2 /// \brief Source file that contains implementation of the GunGame gamemode.
4 /// \copyright GNU GPLv2 or any later version.
6 #include "sv_gungame.qh"
8 //============================ Constants ======================================
10 const string GUNGAME_WEAPONS = "g_gg_weapons";
12 //======================= Global variables ====================================
14 /// \brief Number of kills needed to advance to the next weapon.
15 int autocvar_g_gg_kills_per_weapon;
17 int gungame_maxlevel; ///< Player who reaches this level wins.
18 string gungame_weapons; ///< Holds weapons corresponding to levels.
20 entity gungame_leading_player; ///< Holds the leading player.
21 int gungame_leading_level; ///< Holds the leading level.
22 entity gungame_leading_weapon; ///< Holds the leading weapon.
24 //====================== Forward declarations =================================
26 /// \brief Resets the state to initial one.
27 /// \return No return.
30 /// \brief Returns the weapon that corresponds to the given level.
31 /// \param[in] level Level of the weapon.
32 /// \return Weapon corresponding to the given level.
33 entity GunGame_GetWeapon(int level);
35 /// \brief Updates stats of all players.
36 /// \return No return.
37 void GunGame_UpdateStats();
39 //========================= Free functions ====================================
41 void GunGame_Initialize()
50 strunzone(gungame_weapons);
52 gungame_weapons = strzone(cvar_string(GUNGAME_WEAPONS));
53 gungame_maxlevel = tokenize_console(gungame_weapons) *
54 autocvar_g_gg_kills_per_weapon;
55 if (gungame_maxlevel == 0)
57 error("GunGame: Invalid weapon configuration.");
59 GameRules_limit_score(gungame_maxlevel);
60 gungame_leading_player = NULL;
61 gungame_leading_level = 0;
62 gungame_leading_weapon = GunGame_GetWeapon(0);
63 GunGame_UpdateStats();
66 entity GunGame_GetWeapon(int level)
68 if (level >= gungame_maxlevel)
72 tokenize_console(gungame_weapons);
73 string weapon = argv(floor(level / autocvar_g_gg_kills_per_weapon));
74 FOREACH(Weapons, it != WEP_Null,
76 if (it.netname == weapon)
81 error("GunGame_GetWeapon: Invalid level or weapon name");
85 /// \brief Returns the player level.
86 /// \param[in] player Player to check.
87 /// \return Level of the player.
88 int GunGame_GetPlayerLevel(entity player)
90 return PlayerScore_Get(player, SP_SCORE);
93 /// \brief Updates the information about the leading player.
94 /// \return No return.
95 void GunGame_UpdateLeadingPlayer()
97 entity previous_leader = gungame_leading_player;
100 if (gungame_leading_player == NULL)
102 gungame_leading_player = it;
105 if (GunGame_GetPlayerLevel(it) > GunGame_GetPlayerLevel(
106 gungame_leading_player))
108 gungame_leading_player = it;
111 if (gungame_leading_player == NULL)
115 if ((gungame_leading_player == previous_leader) &&
116 (GunGame_GetPlayerLevel(gungame_leading_player) ==
117 gungame_leading_level))
121 gungame_leading_level = GunGame_GetPlayerLevel(gungame_leading_player);
122 gungame_leading_weapon = GunGame_GetWeapon(gungame_leading_level);
123 GunGame_UpdateStats();
124 //PrintToChatAll(strcat(gungame_leading_player.netname,
125 // " is leading with level ", ftos(gungame_leading_level)));
128 void GunGame_UpdateStats()
130 FOREACH_CLIENT(IS_REAL_CLIENT(it),
132 STAT(GUNGAME_LEADING_WEAPON, it) = gungame_leading_weapon.m_id;
136 /// \brief Gives the player a weapon that corresponds to their level.
137 /// \param[in,out] player Player to give weapon to.
138 /// \return No return.
139 void GunGame_GivePlayerWeapon(entity player)
141 int level = GunGame_GetPlayerLevel(player);
142 if (level >= gungame_maxlevel)
146 entity weapon = GunGame_GetWeapon(level);
147 player.weapons |= weapon.m_wepset;
148 centerprint(player, strcat("^3Level ", ftos(level + 1), ": ^2",
152 //============================= Hooks ========================================
154 /// \brief Hook that is called to determine if there is a weapon arena.
155 MUTATOR_HOOKFUNCTION(gg, SetWeaponArena)
157 //PrintToChatAll("SetWeaponArena");
158 M_ARGV(0, string) = "off";
161 /// \brief Hook that is called to determine start items of all players.
162 MUTATOR_HOOKFUNCTION(gg, SetStartItems)
164 //PrintToChatAll("SetStartItems");
165 start_weapons = WEPSET(Null);
166 warmup_start_weapons = WEPSET(Null);
169 /// \brief Hook that is called when an item is about to spawn.
170 MUTATOR_HOOKFUNCTION(gg, FilterItem)
172 //PrintToChatAll("FilterItem");
173 entity item = M_ARGV(0, entity);
174 if (item.itemdef.instanceOfWeaponPickup)
176 // Block weapons from spawning.
181 /// \brief Hook that is called when player connects to the server.
182 MUTATOR_HOOKFUNCTION(gg, ClientConnect)
184 entity player = M_ARGV(0, entity);
185 if (!IS_REAL_CLIENT(player))
189 STAT(GUNGAME_LEADING_WEAPON, player) = gungame_leading_weapon.m_id;
193 MUTATOR_HOOKFUNCTION(gg, reset_map_global)
198 /// \brief Hook that is called when player spawns.
199 MUTATOR_HOOKFUNCTION(gg, PlayerSpawn, CBC_ORDER_LAST)
201 entity player = M_ARGV(0, entity);
202 player.weapons = WEPSET(Null);
203 GunGame_GivePlayerWeapon(player);
204 player.items |= IT_UNLIMITED_AMMO;
207 /// \brief Hook which is called when the player tries to throw their weapon.
208 MUTATOR_HOOKFUNCTION(gg, ForbidThrowCurrentWeapon)
213 /// \brief Hook that is called when player dies.
214 MUTATOR_HOOKFUNCTION(gg, PlayerDies)
216 GunGame_UpdateLeadingPlayer();
217 entity attacker = M_ARGV(1, entity);
218 if (!IS_PLAYER(attacker) || IS_DEAD(attacker) || (GunGame_GetPlayerLevel(
219 attacker) >= gungame_maxlevel))
223 attacker.weapons = WEPSET(Null);
224 GunGame_GivePlayerWeapon(attacker);
227 /// \brief Hook that determines whether remaining frags are announced.
228 MUTATOR_HOOKFUNCTION(gg, Scores_CountFragsRemaining)
230 // announce remaining frags