Add weaponentity parameter to ammo checking
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / nix / sv_nix.qc
1 #include "sv_nix.qh"
2
3 int autocvar_g_balance_nix_ammo_cells;
4 int autocvar_g_balance_nix_ammo_plasma;
5 int autocvar_g_balance_nix_ammo_fuel;
6 int autocvar_g_balance_nix_ammo_nails;
7 int autocvar_g_balance_nix_ammo_rockets;
8 int autocvar_g_balance_nix_ammo_shells;
9 int autocvar_g_balance_nix_ammoincr_cells;
10 int autocvar_g_balance_nix_ammoincr_plasma;
11 int autocvar_g_balance_nix_ammoincr_fuel;
12 int autocvar_g_balance_nix_ammoincr_nails;
13 int autocvar_g_balance_nix_ammoincr_rockets;
14 int autocvar_g_balance_nix_ammoincr_shells;
15 float autocvar_g_balance_nix_incrtime;
16 float autocvar_g_balance_nix_roundtime;
17 bool autocvar_g_nix_with_healtharmor;
18 bool autocvar_g_nix_with_blaster;
19 bool autocvar_g_nix_with_powerups;
20 int autocvar_g_pickup_cells_max;
21 int autocvar_g_pickup_plasma_max;
22 int autocvar_g_pickup_fuel_max;
23 int autocvar_g_pickup_nails_max;
24 int autocvar_g_pickup_rockets_max;
25 int autocvar_g_pickup_shells_max;
26
27 float g_nix_with_blaster;
28 // WEAPONTODO
29 int nix_weapon;
30 float nix_nextchange;
31 float nix_nextweapon;
32 .float nix_lastchange_id;
33 .float nix_lastinfotime;
34 .float nix_nextincr;
35
36 bool NIX_CanChooseWeapon(int wpn);
37
38 REGISTER_MUTATOR(nix, cvar("g_nix") && !cvar("g_instagib") && !cvar("g_overkill"))
39 {
40         MUTATOR_ONADD
41         {
42                 g_nix_with_blaster = autocvar_g_nix_with_blaster;
43
44                 nix_nextchange = 0;
45                 nix_nextweapon = 0;
46
47                 FOREACH(Weapons, it != WEP_Null && NIX_CanChooseWeapon(it.m_id), LAMBDA(it.wr_init(it)));
48         }
49
50         MUTATOR_ONROLLBACK_OR_REMOVE
51         {
52                 // nothing to roll back
53         }
54
55         MUTATOR_ONREMOVE
56         {
57                 // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
58                 FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
59                         it.ammo_cells = start_ammo_cells;
60                         it.ammo_plasma = start_ammo_plasma;
61                         it.ammo_shells = start_ammo_shells;
62                         it.ammo_nails = start_ammo_nails;
63                         it.ammo_rockets = start_ammo_rockets;
64                         it.ammo_fuel = start_ammo_fuel;
65                         it.weapons = start_weapons;
66                         .entity weaponentity = weaponentities[0]; // TODO: unhardcode
67                         if(!client_hasweapon(it, it.(weaponentity).m_weapon, weaponentity, true, false))
68                                 it.(weaponentity).m_switchweapon = w_getbestweapon(it);
69                 });
70         }
71
72         return false;
73 }
74
75 bool NIX_CanChooseWeapon(int wpn)
76 {
77         entity e = Weapons_from(wpn);
78         if (e == WEP_Null) return false; // skip dummies
79         if(g_weaponarena)
80         {
81                 if(!(g_weaponarena_weapons & e.m_wepset))
82                         return false;
83         }
84         else
85         {
86                 if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
87                         return false;
88                 if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
89                         return false;
90                 if (!(e.spawnflags & WEP_FLAG_NORMAL))
91                         return false;
92         }
93         return true;
94 }
95 void NIX_ChooseNextWeapon()
96 {
97         RandomSelection_Init();
98         FOREACH(Weapons, it != WEP_Null, LAMBDA(
99                 if(NIX_CanChooseWeapon(it.m_id))
100                         RandomSelection_Add(NULL, it.m_id, string_null, 1, (it.m_id != nix_weapon));
101         ));
102         nix_nextweapon = RandomSelection_chosen_float;
103 }
104
105 void NIX_GiveCurrentWeapon(entity this)
106 {
107         float dt;
108
109         if(!nix_nextweapon)
110                 NIX_ChooseNextWeapon();
111
112         dt = ceil(nix_nextchange - time);
113
114         if(dt <= 0)
115         {
116                 nix_weapon = nix_nextweapon;
117                 nix_nextweapon = 0;
118                 if (!nix_nextchange) // no round played yet?
119                         nix_nextchange = time; // start the first round now!
120                 else
121                         nix_nextchange = time + autocvar_g_balance_nix_roundtime;
122                 // Weapon w = Weapons_from(nix_weapon);
123                 // w.wr_init(w); // forget it, too slow
124         }
125
126         // get weapon info
127         entity e = Weapons_from(nix_weapon);
128
129         if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
130         {
131                 this.ammo_shells = this.ammo_nails = this.ammo_rockets = this.ammo_cells = this.ammo_plasma = this.ammo_fuel = 0;
132
133                 if(this.items & IT_UNLIMITED_WEAPON_AMMO)
134                 {
135                         switch(e.ammo_field)
136                         {
137                                 case ammo_shells:  this.ammo_shells  = autocvar_g_pickup_shells_max;  break;
138                                 case ammo_nails:   this.ammo_nails   = autocvar_g_pickup_nails_max;   break;
139                                 case ammo_rockets: this.ammo_rockets = autocvar_g_pickup_rockets_max; break;
140                                 case ammo_cells:   this.ammo_cells   = autocvar_g_pickup_cells_max;   break;
141                                 case ammo_plasma:  this.ammo_plasma  = autocvar_g_pickup_plasma_max;   break;
142                                 case ammo_fuel:    this.ammo_fuel    = autocvar_g_pickup_fuel_max;    break;
143                         }
144                 }
145                 else
146                 {
147                         switch(e.ammo_field)
148                         {
149                                 case ammo_shells:  this.ammo_shells  = autocvar_g_balance_nix_ammo_shells;  break;
150                                 case ammo_nails:   this.ammo_nails   = autocvar_g_balance_nix_ammo_nails;   break;
151                                 case ammo_rockets: this.ammo_rockets = autocvar_g_balance_nix_ammo_rockets; break;
152                                 case ammo_cells:   this.ammo_cells   = autocvar_g_balance_nix_ammo_cells;   break;
153                                 case ammo_plasma:  this.ammo_plasma  = autocvar_g_balance_nix_ammo_plasma;   break;
154                                 case ammo_fuel:    this.ammo_fuel    = autocvar_g_balance_nix_ammo_fuel;    break;
155                         }
156                 }
157
158                 this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
159                 if(dt >= 1 && dt <= 5)
160                         this.nix_lastinfotime = -42;
161                 else
162                         Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
163
164                 e.wr_resetplayer(e, this);
165
166                 // all weapons must be fully loaded when we spawn
167                 if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
168                         this.(weapon_load[nix_weapon]) = e.reloading_ammo;
169
170                 // vortex too
171                 if(WEP_CVAR(vortex, charge))
172                 {
173                         if(WEP_CVAR_SEC(vortex, chargepool))
174                                 this.vortex_chargepool_ammo = 1;
175                         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
176                         {
177                                 .entity weaponentity = weaponentities[slot];
178                                 this.(weaponentity).vortex_charge = WEP_CVAR(vortex, charge_start);
179                         }
180                 }
181
182                 // set last change info
183                 this.nix_lastchange_id = nix_nextchange;
184         }
185         if(this.nix_lastinfotime != dt)
186         {
187                 this.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
188                 if(dt >= 1 && dt <= 5)
189                         Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
190         }
191
192         if(!(this.items & IT_UNLIMITED_WEAPON_AMMO) && time > this.nix_nextincr)
193         {
194                 switch(e.ammo_field)
195                 {
196                         case ammo_shells:  this.ammo_shells  += autocvar_g_balance_nix_ammoincr_shells;  break;
197                         case ammo_nails:   this.ammo_nails   += autocvar_g_balance_nix_ammoincr_nails;   break;
198                         case ammo_rockets: this.ammo_rockets += autocvar_g_balance_nix_ammoincr_rockets; break;
199                         case ammo_cells:   this.ammo_cells   += autocvar_g_balance_nix_ammoincr_cells;   break;
200                         case ammo_plasma:  this.ammo_plasma  += autocvar_g_balance_nix_ammoincr_plasma;   break;
201                         case ammo_fuel:    this.ammo_fuel    += autocvar_g_balance_nix_ammoincr_fuel;    break;
202                 }
203
204                 this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
205         }
206
207         this.weapons = '0 0 0';
208         if(g_nix_with_blaster)
209                 this.weapons |= WEPSET(BLASTER);
210         this.weapons |= e.m_wepset;
211
212         .entity weaponentity = weaponentities[0]; // TODO: unhardcode
213     Weapon w = Weapons_from(nix_weapon);
214         if(this.(weaponentity).m_switchweapon != w)
215                 if(!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
216                 {
217                         if(client_hasweapon(this, w, weaponentity, true, false))
218                                 W_SwitchWeapon(this, w, weaponentity);
219                 }
220 }
221
222 MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
223 {
224         return true; // no throwing in NIX
225 }
226
227 MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
228 {
229         M_ARGV(0, string) = strcat(M_ARGV(0, string), ":NIX");
230 }
231
232 MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
233 {
234         M_ARGV(0, string) = strcat(M_ARGV(0, string), ", NIX");
235 }
236
237 MUTATOR_HOOKFUNCTION(nix, FilterItem)
238 {
239         entity item = M_ARGV(0, entity);
240
241         switch (item.items)
242         {
243                 case ITEM_HealthSmall.m_itemid:
244                 case ITEM_HealthMedium.m_itemid:
245                 case ITEM_HealthLarge.m_itemid:
246                 case ITEM_HealthMega.m_itemid:
247                 case ITEM_ArmorSmall.m_itemid:
248                 case ITEM_ArmorMedium.m_itemid:
249                 case ITEM_ArmorLarge.m_itemid:
250                 case ITEM_ArmorMega.m_itemid:
251                         if (autocvar_g_nix_with_healtharmor)
252                                 return false;
253                         break;
254                 case ITEM_Strength.m_itemid:
255                 case ITEM_Shield.m_itemid:
256                         if (autocvar_g_nix_with_powerups)
257                                 return false;
258                         break;
259         }
260
261         return true; // delete all other items
262 }
263
264 MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
265 {
266         entity ent = M_ARGV(0, entity);
267
268         if(ent.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
269                 return true;
270 }
271
272 MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
273 {
274         entity player = M_ARGV(0, entity);
275
276         if(!intermission_running)
277         if(!IS_DEAD(player))
278         if(IS_PLAYER(player))
279                 NIX_GiveCurrentWeapon(player);
280 }
281
282 MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
283 {
284         entity player = M_ARGV(0, entity);
285
286         player.nix_lastchange_id = -1;
287         NIX_GiveCurrentWeapon(player); // overrides the weapons you got when spawning
288         player.items |= IT_UNLIMITED_SUPERWEAPONS;
289 }
290
291 MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
292 {
293         M_ARGV(0, string) = "NIX";
294 }