alias sv_hook_gamestart_ka
alias sv_hook_gamestart_ft
alias sv_hook_gamestart_inv
+alias sv_hook_gamestart_gg
alias sv_hook_gamerestart
alias sv_hook_gameend
alias sv_vote_gametype_hook_dm
alias sv_vote_gametype_hook_dom
alias sv_vote_gametype_hook_ft
+alias sv_vote_gametype_hook_gg
alias sv_vote_gametype_hook_inv
alias sv_vote_gametype_hook_ka
alias sv_vote_gametype_hook_kh
set g_inv_respawn_delay_max 0
set g_inv_respawn_waves 0
set g_inv_weapon_stay 0
+set g_gg_respawn_delay_small 0
+set g_gg_respawn_delay_small_count 0
+set g_gg_respawn_delay_large 0
+set g_gg_respawn_delay_large_count 0
+set g_gg_respawn_delay_max 0
+set g_gg_respawn_waves 0
+set g_gg_weapon_stay 0
// =========
set g_invasion_teams 0 "number of teams in invasion (note: use mapinfo to set this)"
set g_invasion_team_spawns 1 "use team spawns in teamplay invasion mode"
set g_invasion_type 0 "type of invasion mode - 0: round-based, 1: hunting, 2: complete the stage (note: use mapinfo to set this)"
+
+// =========
+// gungame
+// =========
+set g_gg 0 "GunGame: Kill players with all weapons"
+set g_gg_weapons "vortex mortar machinegun hagar arc electro devastator crylink shotgun blaster"
--- /dev/null
+/// \file
+/// \brief Source file that contains implementation of the GunGame gamemode.
+/// \author Lyberta
+/// \copyright GNU GPLv3 or any later version.
+
+#include "gamemode_gungame.qh"
+
+//============================ Constants ======================================
+
+const string GUNGAME_WEAPONS = "g_gg_weapons";
+
+//======================= Global variables ====================================
+
+.int gungame_leading_weapon_stat = _STAT(GUNGAME_LEADING_WEAPON);
+
+int gungame_maxlevel; ///< Player who reaches this level wins.
+string gungame_weapons; ///< Holds weapons corresponding to levels.
+
+entity gungame_leading_player; ///< Holds the leading player.
+int gungame_leading_level; ///< Holds the leading level.
+entity gungame_leading_weapon; ///< Holds the leading weapon.
+
+//====================== Forward declarations =================================
+
+/// \brief Resets the state to initial one.
+/// \return No return.
+void GunGame_Reset();
+
+/// \brief Returns the weapon that corresponds to the given level.
+/// \param[in] level Level of the weapon.
+/// \return Weapon corresponding to the given level.
+entity GunGame_GetWeapon(int level);
+
+/// \brief Updates stats of all players.
+/// \return No return.
+void GunGame_UpdateStats();
+
+//========================= Free functions ====================================
+
+void GunGame_Initialize()
+{
+ GunGame_Reset();
+}
+
+void GunGame_Reset()
+{
+ if (gungame_weapons)
+ {
+ strunzone(gungame_weapons);
+ }
+ gungame_weapons = strzone(cvar_string(GUNGAME_WEAPONS));
+ gungame_maxlevel = tokenize_console(gungame_weapons);
+ if (gungame_maxlevel == 0)
+ {
+ error("GunGame: Invalid weapon configuration.");
+ }
+ GameRules_limit_score(gungame_maxlevel);
+ gungame_leading_player = NULL;
+ gungame_leading_level = 0;
+ gungame_leading_weapon = GunGame_GetWeapon(0);
+ GunGame_UpdateStats();
+}
+
+entity GunGame_GetWeapon(int level)
+{
+ if (level >= gungame_maxlevel)
+ {
+ return NULL;
+ }
+ tokenize_console(gungame_weapons);
+ string weapon = argv(level);
+ FOREACH(Weapons, it != WEP_Null,
+ {
+ if (it.netname == weapon)
+ {
+ return it;
+ }
+ });
+ error("GunGame_GetWeapon: Invalid level or weapon name");
+ return NULL;
+}
+
+/// \brief Returns the player level.
+/// \param[in] player Player to check.
+/// \return Level of the player.
+int GunGame_GetPlayerLevel(entity player)
+{
+ return PlayerScore_Get(player, SP_SCORE);
+}
+
+/// \brief Updates the information about the leading player.
+/// \return No return.
+void GunGame_UpdateLeadingPlayer()
+{
+ entity previous_leader = gungame_leading_player;
+ FOREACH_CLIENT(true,
+ {
+ if (gungame_leading_player == NULL)
+ {
+ gungame_leading_player = it;
+ continue;
+ }
+ if (GunGame_GetPlayerLevel(it) > GunGame_GetPlayerLevel(
+ gungame_leading_player))
+ {
+ gungame_leading_player = it;
+ }
+ });
+ if (gungame_leading_player == NULL)
+ {
+ return;
+ }
+ if ((gungame_leading_player == previous_leader) &&
+ (GunGame_GetPlayerLevel(gungame_leading_player) ==
+ gungame_leading_level))
+ {
+ return;
+ }
+ gungame_leading_level = GunGame_GetPlayerLevel(gungame_leading_player);
+ gungame_leading_weapon = GunGame_GetWeapon(gungame_leading_level);
+ GunGame_UpdateStats();
+ //PrintToChatAll(strcat(gungame_leading_player.netname,
+ // " is leading with level ", ftos(gungame_leading_level)));
+}
+
+void GunGame_UpdateStats()
+{
+ FOREACH_CLIENT(IS_REAL_CLIENT(it),
+ {
+ it.gungame_leading_weapon_stat = gungame_leading_weapon.m_id;
+ });
+}
+
+/// \brief Gives the player a weapon that corresponds to their level.
+/// \param[in,out] player Player to give weapon to.
+/// \return No return.
+void GunGame_GivePlayerWeapon(entity player)
+{
+ int level = GunGame_GetPlayerLevel(player);
+ if (level >= gungame_maxlevel)
+ {
+ return;
+ }
+ entity weapon = GunGame_GetWeapon(level);
+ player.weapons |= weapon.m_wepset;
+ centerprint(player, strcat("^3Level ", ftos(level + 1), ": ^2",
+ weapon.m_name));
+}
+
+//============================= Hooks ========================================
+
+/// \brief Hook that is called to determine if there is a weapon arena.
+MUTATOR_HOOKFUNCTION(gg, SetWeaponArena)
+{
+ //PrintToChatAll("SetWeaponArena");
+ M_ARGV(0, string) = "off";
+}
+
+/// \brief Hook that is called to determine start items of all players.
+MUTATOR_HOOKFUNCTION(gg, SetStartItems)
+{
+ //PrintToChatAll("SetStartItems");
+ start_weapons = WEPSET(Null);
+ warmup_start_weapons = WEPSET(Null);
+}
+
+/// \brief Hook that is called when an item is about to spawn.
+MUTATOR_HOOKFUNCTION(gg, FilterItem)
+{
+ //PrintToChatAll("FilterItem");
+ entity item = M_ARGV(0, entity);
+ if (item.itemdef.instanceOfWeaponPickup)
+ {
+ // Block weapons from spawning.
+ return true;
+ }
+}
+
+/// \brief Hook that is called when player connects to the server.
+MUTATOR_HOOKFUNCTION(gg, ClientConnect)
+{
+ entity player = M_ARGV(0, entity);
+ if (!IS_REAL_CLIENT(player))
+ {
+ return true;
+ }
+ player.gungame_leading_weapon_stat = gungame_leading_weapon.m_id;
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(gg, reset_map_global)
+{
+ GunGame_Reset();
+}
+
+/// \brief Hook that is called when player spawns.
+MUTATOR_HOOKFUNCTION(gg, PlayerSpawn, CBC_ORDER_LAST)
+{
+ entity player = M_ARGV(0, entity);
+ player.weapons = WEPSET(Null);
+ GunGame_GivePlayerWeapon(player);
+ player.items |= IT_UNLIMITED_AMMO;
+}
+
+/// \brief Hook which is called when the player tries to throw their weapon.
+MUTATOR_HOOKFUNCTION(gg, ForbidThrowCurrentWeapon)
+{
+ return true;
+}
+
+/// \brief Hook that is called when player dies.
+MUTATOR_HOOKFUNCTION(gg, PlayerDies)
+{
+ GunGame_UpdateLeadingPlayer();
+ entity attacker = M_ARGV(1, entity);
+ if (!IS_PLAYER(attacker) || IS_DEAD(attacker) || (GunGame_GetPlayerLevel(
+ attacker) >= gungame_maxlevel))
+ {
+ return;
+ }
+ attacker.weapons = WEPSET(Null);
+ GunGame_GivePlayerWeapon(attacker);
+}
+
+/// \brief Hook that determines whether remaining frags are announced.
+MUTATOR_HOOKFUNCTION(gg, Scores_CountFragsRemaining)
+{
+ // announce remaining frags
+ return true;
+}