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