3 #include <server/weapons/selection.qh>
4 #include <server/world.qh>
6 //string autocvar_g_nix;
7 int autocvar_g_balance_nix_ammo_cells;
8 int autocvar_g_balance_nix_ammo_plasma;
9 int autocvar_g_balance_nix_ammo_fuel;
10 int autocvar_g_balance_nix_ammo_nails;
11 int autocvar_g_balance_nix_ammo_rockets;
12 int autocvar_g_balance_nix_ammo_shells;
13 int autocvar_g_balance_nix_ammoincr_cells;
14 int autocvar_g_balance_nix_ammoincr_plasma;
15 int autocvar_g_balance_nix_ammoincr_fuel;
16 int autocvar_g_balance_nix_ammoincr_nails;
17 int autocvar_g_balance_nix_ammoincr_rockets;
18 int autocvar_g_balance_nix_ammoincr_shells;
19 float autocvar_g_balance_nix_incrtime;
20 float autocvar_g_balance_nix_roundtime;
21 bool autocvar_g_nix_with_healtharmor;
22 bool autocvar_g_nix_with_blaster;
23 bool autocvar_g_nix_with_powerups;
24 int autocvar_g_pickup_cells_max;
25 int autocvar_g_pickup_plasma_max;
26 int autocvar_g_pickup_fuel_max;
27 int autocvar_g_pickup_nails_max;
28 int autocvar_g_pickup_rockets_max;
29 int autocvar_g_pickup_shells_max;
31 float g_nix_with_blaster;
36 .float nix_lastchange_id;
37 .float nix_lastinfotime;
40 bool NIX_CanChooseWeapon(int wpn);
42 REGISTER_MUTATOR(nix, expr_evaluate(cvar_string("g_nix")) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok) && !MapInfo_LoadedGametype.m_weaponarena)
46 g_nix_with_blaster = autocvar_g_nix_with_blaster;
51 FOREACH(Weapons, it != WEP_Null && NIX_CanChooseWeapon(it.m_id), { it.wr_init(it); });
54 MUTATOR_ONROLLBACK_OR_REMOVE
56 // nothing to roll back
61 // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
62 FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
63 SetResource(it, RES_SHELLS, start_ammo_shells);
64 SetResource(it, RES_BULLETS, start_ammo_nails);
65 SetResource(it, RES_ROCKETS, start_ammo_rockets);
66 SetResource(it, RES_CELLS, start_ammo_cells);
67 SetResource(it, RES_PLASMA, start_ammo_plasma);
68 SetResource(it, RES_FUEL, start_ammo_fuel);
69 STAT(WEAPONS, it) = start_weapons;
70 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
72 .entity weaponentity = weaponentities[slot];
73 if(it.(weaponentity).m_weapon == WEP_Null && slot != 0)
75 if(!client_hasweapon(it, it.(weaponentity).m_weapon, weaponentity, true, false))
76 it.(weaponentity).m_switchweapon = w_getbestweapon(it, weaponentity);
84 bool NIX_CanChooseWeapon(int wpn)
86 entity e = REGISTRY_GET(Weapons, wpn);
87 if (e == WEP_Null) return false; // skip dummies
90 if(!(g_weaponarena_weapons & e.m_wepset))
95 if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
97 if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
99 if (!(e.spawnflags & WEP_FLAG_NORMAL))
104 void NIX_ChooseNextWeapon()
106 RandomSelection_Init();
107 FOREACH(Weapons, it != WEP_Null, {
108 if(NIX_CanChooseWeapon(it.m_id))
109 RandomSelection_AddFloat(it.m_id, 1, (it.m_id != nix_weapon));
111 nix_nextweapon = RandomSelection_chosen_float;
114 void NIX_GiveCurrentWeapon(entity this)
119 NIX_ChooseNextWeapon();
121 dt = ceil(nix_nextchange - time);
125 nix_weapon = nix_nextweapon;
127 if (!nix_nextchange) // no round played yet?
128 nix_nextchange = time; // start the first round now!
130 nix_nextchange = time + autocvar_g_balance_nix_roundtime;
131 // Weapon w = REGISTRY_GET(Weapons, nix_weapon);
132 // w.wr_init(w); // forget it, too slow
136 entity wpn = REGISTRY_GET(Weapons, nix_weapon);
138 if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
140 SetResource(this, RES_SHELLS, 0);
141 SetResource(this, RES_BULLETS, 0);
142 SetResource(this, RES_ROCKETS, 0);
143 SetResource(this, RES_CELLS, 0);
144 SetResource(this, RES_PLASMA, 0);
145 SetResource(this, RES_FUEL, 0);
146 if(this.items & IT_UNLIMITED_AMMO)
148 switch (wpn.ammo_type)
150 case RES_SHELLS: SetResource(this, RES_SHELLS, autocvar_g_pickup_shells_max); break;
151 case RES_BULLETS: SetResource(this, RES_BULLETS, autocvar_g_pickup_nails_max); break;
152 case RES_ROCKETS: SetResource(this, RES_ROCKETS, autocvar_g_pickup_rockets_max); break;
153 case RES_CELLS: SetResource(this, RES_CELLS, autocvar_g_pickup_cells_max); break;
154 case RES_PLASMA: SetResource(this, RES_PLASMA, autocvar_g_pickup_plasma_max); break;
155 case RES_FUEL: SetResource(this, RES_FUEL, autocvar_g_pickup_fuel_max); break;
160 switch (wpn.ammo_type)
162 case RES_SHELLS: SetResource(this, RES_SHELLS, autocvar_g_balance_nix_ammo_shells); break;
163 case RES_BULLETS: SetResource(this, RES_BULLETS, autocvar_g_balance_nix_ammo_nails); break;
164 case RES_ROCKETS: SetResource(this, RES_ROCKETS, autocvar_g_balance_nix_ammo_rockets); break;
165 case RES_CELLS: SetResource(this, RES_CELLS, autocvar_g_balance_nix_ammo_cells); break;
166 case RES_PLASMA: SetResource(this, RES_PLASMA, autocvar_g_balance_nix_ammo_plasma); break;
167 case RES_FUEL: SetResource(this, RES_FUEL, autocvar_g_balance_nix_ammo_fuel); break;
171 this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
172 if(dt >= 1 && dt <= 5)
173 this.nix_lastinfotime = -42;
175 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
177 wpn.wr_resetplayer(wpn, this);
179 // all weapons must be fully loaded when we spawn
180 if (wpn.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
182 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
184 .entity weaponentity = weaponentities[slot];
185 this.(weaponentity).(weapon_load[nix_weapon]) = wpn.reloading_ammo;
189 // set last change info
190 this.nix_lastchange_id = nix_nextchange;
192 if(this.nix_lastinfotime != dt)
194 this.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
195 if(dt >= 1 && dt <= 5)
196 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
199 if(!(this.items & IT_UNLIMITED_AMMO) && time > this.nix_nextincr)
201 switch (wpn.ammo_type)
203 case RES_SHELLS: GiveResource(this, RES_SHELLS, autocvar_g_balance_nix_ammoincr_shells); break;
204 case RES_BULLETS: GiveResource(this, RES_BULLETS, autocvar_g_balance_nix_ammoincr_nails); break;
205 case RES_ROCKETS: GiveResource(this, RES_ROCKETS, autocvar_g_balance_nix_ammoincr_rockets); break;
206 case RES_CELLS: GiveResource(this, RES_CELLS, autocvar_g_balance_nix_ammoincr_cells); break;
207 case RES_PLASMA: GiveResource(this, RES_PLASMA, autocvar_g_balance_nix_ammoincr_plasma); break;
208 case RES_FUEL: GiveResource(this, RES_FUEL, autocvar_g_balance_nix_ammoincr_fuel); break;
211 this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
214 STAT(WEAPONS, this) = '0 0 0';
215 if(g_nix_with_blaster)
216 STAT(WEAPONS, this) |= WEPSET(BLASTER);
217 STAT(WEAPONS, this) |= wpn.m_wepset;
219 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
221 .entity weaponentity = weaponentities[slot];
222 if (this.(weaponentity).m_weapon == WEP_Null && slot != 0)
225 if (this.(weaponentity).m_switchweapon != wpn)
226 if (!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
228 if (client_hasweapon(this, wpn, weaponentity, true, false))
229 W_SwitchWeapon(this, wpn, weaponentity);
234 MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
236 return true; // no throwing in NIX
239 MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
241 M_ARGV(0, string) = strcat(M_ARGV(0, string), ":NIX");
244 MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
246 M_ARGV(0, string) = strcat(M_ARGV(0, string), ", NIX");
249 MUTATOR_HOOKFUNCTION(nix, FilterItemDefinition)
251 entity definition = M_ARGV(0, entity);
253 if (definition.instanceOfHealth || definition.instanceOfArmor)
255 return !autocvar_g_nix_with_healtharmor;
257 else if (definition.instanceOfPowerup)
259 return !autocvar_g_nix_with_powerups;
262 return true; // delete all other items
265 MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
267 entity ent = M_ARGV(0, entity);
269 if(ent.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
273 MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
275 entity player = M_ARGV(0, entity);
279 if(IS_PLAYER(player))
280 NIX_GiveCurrentWeapon(player);
283 MUTATOR_HOOKFUNCTION(nix, ForbidRandomStartWeapons)
288 MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
290 entity player = M_ARGV(0, entity);
292 player.nix_lastchange_id = -1;
293 NIX_GiveCurrentWeapon(player); // overrides the weapons you got when spawning
294 player.items |= IT_UNLIMITED_SUPERWEAPONS;
297 MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
299 M_ARGV(0, string) = "NIX";