3 //string autocvar_g_nix;
4 int autocvar_g_balance_nix_ammo_cells;
5 int autocvar_g_balance_nix_ammo_plasma;
6 int autocvar_g_balance_nix_ammo_fuel;
7 int autocvar_g_balance_nix_ammo_nails;
8 int autocvar_g_balance_nix_ammo_rockets;
9 int autocvar_g_balance_nix_ammo_shells;
10 int autocvar_g_balance_nix_ammoincr_cells;
11 int autocvar_g_balance_nix_ammoincr_plasma;
12 int autocvar_g_balance_nix_ammoincr_fuel;
13 int autocvar_g_balance_nix_ammoincr_nails;
14 int autocvar_g_balance_nix_ammoincr_rockets;
15 int autocvar_g_balance_nix_ammoincr_shells;
16 float autocvar_g_balance_nix_incrtime;
17 float autocvar_g_balance_nix_roundtime;
18 bool autocvar_g_nix_with_healtharmor;
19 bool autocvar_g_nix_with_blaster;
20 bool autocvar_g_nix_with_powerups;
21 int autocvar_g_pickup_cells_max;
22 int autocvar_g_pickup_plasma_max;
23 int autocvar_g_pickup_fuel_max;
24 int autocvar_g_pickup_nails_max;
25 int autocvar_g_pickup_rockets_max;
26 int autocvar_g_pickup_shells_max;
28 float g_nix_with_blaster;
33 .float nix_lastchange_id;
34 .float nix_lastinfotime;
37 bool NIX_CanChooseWeapon(int wpn);
39 REGISTER_MUTATOR(nix, expr_evaluate(cvar_string("g_nix")) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok))
43 g_nix_with_blaster = autocvar_g_nix_with_blaster;
48 FOREACH(Weapons, it != WEP_Null && NIX_CanChooseWeapon(it.m_id), { it.wr_init(it); });
51 MUTATOR_ONROLLBACK_OR_REMOVE
53 // nothing to roll back
58 // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
59 FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
60 SetResource(it, RES_SHELLS, start_ammo_shells);
61 SetResource(it, RES_BULLETS, start_ammo_nails);
62 SetResource(it, RES_ROCKETS, start_ammo_rockets);
63 SetResource(it, RES_CELLS, start_ammo_cells);
64 SetResource(it, RES_PLASMA, start_ammo_plasma);
65 SetResource(it, RES_FUEL, start_ammo_fuel);
66 STAT(WEAPONS, it) = start_weapons;
67 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
69 .entity weaponentity = weaponentities[slot];
70 if(it.(weaponentity).m_weapon == WEP_Null && slot != 0)
72 if(!client_hasweapon(it, it.(weaponentity).m_weapon, weaponentity, true, false))
73 it.(weaponentity).m_switchweapon = w_getbestweapon(it, weaponentity);
81 bool NIX_CanChooseWeapon(int wpn)
83 entity e = REGISTRY_GET(Weapons, wpn);
84 if (e == WEP_Null) return false; // skip dummies
87 if(!(g_weaponarena_weapons & e.m_wepset))
92 if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
94 if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
96 if (!(e.spawnflags & WEP_FLAG_NORMAL))
101 void NIX_ChooseNextWeapon()
103 RandomSelection_Init();
104 FOREACH(Weapons, it != WEP_Null, {
105 if(NIX_CanChooseWeapon(it.m_id))
106 RandomSelection_AddFloat(it.m_id, 1, (it.m_id != nix_weapon));
108 nix_nextweapon = RandomSelection_chosen_float;
111 void NIX_GiveCurrentWeapon(entity this)
116 NIX_ChooseNextWeapon();
118 dt = ceil(nix_nextchange - time);
122 nix_weapon = nix_nextweapon;
124 if (!nix_nextchange) // no round played yet?
125 nix_nextchange = time; // start the first round now!
127 nix_nextchange = time + autocvar_g_balance_nix_roundtime;
128 // Weapon w = REGISTRY_GET(Weapons, nix_weapon);
129 // w.wr_init(w); // forget it, too slow
133 entity wpn = REGISTRY_GET(Weapons, nix_weapon);
135 if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
137 SetResource(this, RES_SHELLS, 0);
138 SetResource(this, RES_BULLETS, 0);
139 SetResource(this, RES_ROCKETS, 0);
140 SetResource(this, RES_CELLS, 0);
141 SetResource(this, RES_PLASMA, 0);
142 SetResource(this, RES_FUEL, 0);
143 if(this.items & IT_UNLIMITED_AMMO)
145 switch (wpn.ammo_type)
147 case RES_SHELLS: SetResource(this, RES_SHELLS, autocvar_g_pickup_shells_max); break;
148 case RES_BULLETS: SetResource(this, RES_BULLETS, autocvar_g_pickup_nails_max); break;
149 case RES_ROCKETS: SetResource(this, RES_ROCKETS, autocvar_g_pickup_rockets_max); break;
150 case RES_CELLS: SetResource(this, RES_CELLS, autocvar_g_pickup_cells_max); break;
151 case RES_PLASMA: SetResource(this, RES_PLASMA, autocvar_g_pickup_plasma_max); break;
152 case RES_FUEL: SetResource(this, RES_FUEL, autocvar_g_pickup_fuel_max); break;
157 switch (wpn.ammo_type)
159 case RES_SHELLS: SetResource(this, RES_SHELLS, autocvar_g_balance_nix_ammo_shells); break;
160 case RES_BULLETS: SetResource(this, RES_BULLETS, autocvar_g_balance_nix_ammo_nails); break;
161 case RES_ROCKETS: SetResource(this, RES_ROCKETS, autocvar_g_balance_nix_ammo_rockets); break;
162 case RES_CELLS: SetResource(this, RES_CELLS, autocvar_g_balance_nix_ammo_cells); break;
163 case RES_PLASMA: SetResource(this, RES_PLASMA, autocvar_g_balance_nix_ammo_plasma); break;
164 case RES_FUEL: SetResource(this, RES_FUEL, autocvar_g_balance_nix_ammo_fuel); break;
168 this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
169 if(dt >= 1 && dt <= 5)
170 this.nix_lastinfotime = -42;
172 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
174 wpn.wr_resetplayer(wpn, this);
176 // all weapons must be fully loaded when we spawn
177 if (wpn.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
179 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
181 .entity weaponentity = weaponentities[slot];
182 this.(weaponentity).(weapon_load[nix_weapon]) = wpn.reloading_ammo;
186 // set last change info
187 this.nix_lastchange_id = nix_nextchange;
189 if(this.nix_lastinfotime != dt)
191 this.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
192 if(dt >= 1 && dt <= 5)
193 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
196 if(!(this.items & IT_UNLIMITED_AMMO) && time > this.nix_nextincr)
198 switch (wpn.ammo_type)
200 case RES_SHELLS: GiveResource(this, RES_SHELLS, autocvar_g_balance_nix_ammoincr_shells); break;
201 case RES_BULLETS: GiveResource(this, RES_BULLETS, autocvar_g_balance_nix_ammoincr_nails); break;
202 case RES_ROCKETS: GiveResource(this, RES_ROCKETS, autocvar_g_balance_nix_ammoincr_rockets); break;
203 case RES_CELLS: GiveResource(this, RES_CELLS, autocvar_g_balance_nix_ammoincr_cells); break;
204 case RES_PLASMA: GiveResource(this, RES_PLASMA, autocvar_g_balance_nix_ammoincr_plasma); break;
205 case RES_FUEL: GiveResource(this, RES_FUEL, autocvar_g_balance_nix_ammoincr_fuel); break;
208 this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
211 STAT(WEAPONS, this) = '0 0 0';
212 if(g_nix_with_blaster)
213 STAT(WEAPONS, this) |= WEPSET(BLASTER);
214 STAT(WEAPONS, this) |= wpn.m_wepset;
216 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
218 .entity weaponentity = weaponentities[slot];
219 if (this.(weaponentity).m_weapon == WEP_Null && slot != 0)
222 if (this.(weaponentity).m_switchweapon != wpn)
223 if (!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
225 if (client_hasweapon(this, wpn, weaponentity, true, false))
226 W_SwitchWeapon(this, wpn, weaponentity);
231 MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
233 return true; // no throwing in NIX
236 MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
238 M_ARGV(0, string) = strcat(M_ARGV(0, string), ":NIX");
241 MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
243 M_ARGV(0, string) = strcat(M_ARGV(0, string), ", NIX");
246 MUTATOR_HOOKFUNCTION(nix, FilterItemDefinition)
248 entity definition = M_ARGV(0, entity);
250 if (definition.instanceOfHealth || definition.instanceOfArmor)
252 return !autocvar_g_nix_with_healtharmor;
254 else if (definition.instanceOfPowerup)
256 return !autocvar_g_nix_with_powerups;
259 return true; // delete all other items
262 MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
264 entity ent = M_ARGV(0, entity);
266 if(ent.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
270 MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
272 entity player = M_ARGV(0, entity);
276 if(IS_PLAYER(player))
277 NIX_GiveCurrentWeapon(player);
280 MUTATOR_HOOKFUNCTION(nix, ForbidRandomStartWeapons)
285 MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
287 entity player = M_ARGV(0, entity);
289 player.nix_lastchange_id = -1;
290 NIX_GiveCurrentWeapon(player); // overrides the weapons you got when spawning
291 player.items |= IT_UNLIMITED_SUPERWEAPONS;
294 MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
296 M_ARGV(0, string) = "NIX";