]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/mutator_nix.qc
NIX: reset weapon load on forced weapon switch
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator_nix.qc
1 float g_nix_with_laser;
2
3 float nix_weapon;
4 float nix_weapon_ammo;
5 float nix_nextchange;
6 float nix_nextweapon;
7 float nix_nextweapon_ammo;
8 .float nix_lastchange_id;
9 .float nix_lastinfotime;
10 .float nix_nextincr;
11
12 .float nix_save_cells;
13 .float nix_save_shells;
14 .float nix_save_nails;
15 .float nix_save_rockets;
16 .float nix_save_fuel;
17 .float nix_save_weapons;
18
19 float NIX_CanChooseWeapon(float wpn)
20 {
21         entity e;
22         e = get_weaponinfo(wpn);
23         if(!e.weapons) // skip dummies
24                 return FALSE;
25         if(g_weaponarena)
26         {
27                 if not(g_weaponarena & e.weapons)
28                         return FALSE;
29         }
30         else
31         {
32                 if(wpn == WEP_LASER && g_nix_with_laser)
33                         return FALSE;
34                 if not(e.spawnflags & WEP_FLAG_NORMAL)
35                         return FALSE;
36         }
37         return TRUE;
38 }
39 void NIX_ChooseNextWeapon()
40 {
41         float j;
42         RandomSelection_Init();
43         for(j = WEP_FIRST; j <= WEP_LAST; ++j)
44                 if(NIX_CanChooseWeapon(j))
45                         RandomSelection_Add(world, j, string_null, 1, (j != nix_weapon));
46         nix_nextweapon = RandomSelection_chosen_float;
47         nix_nextweapon_ammo = W_AmmoItemCode(nix_nextweapon);
48 }
49
50 void NIX_GiveCurrentWeapon()
51 {
52         float dt;
53
54         if(!nix_nextweapon)
55                 NIX_ChooseNextWeapon();
56
57         dt = ceil(nix_nextchange - time);
58
59         if(dt <= 0)
60         {
61                 nix_weapon = nix_nextweapon;
62                 nix_weapon_ammo = nix_nextweapon_ammo;
63                 nix_nextweapon = 0;
64                 if (!nix_nextchange) // no round played yet?
65                         nix_nextchange = time; // start the first round now!
66                 else
67                         nix_nextchange = time + autocvar_g_balance_nix_roundtime;
68                 //weapon_action(nix_weapon, WR_PRECACHE); // forget it, too slow
69         }
70
71         if(nix_nextchange != self.nix_lastchange_id) // this shall only be called once per round!
72         {
73                 self.nix_lastchange_id = nix_nextchange;
74                 if (self.items & IT_UNLIMITED_WEAPON_AMMO)
75                 {
76                         self.ammo_shells = (nix_weapon_ammo & IT_SHELLS) ?
77                                 autocvar_g_pickup_shells_max : 0;
78                         self.ammo_nails = (nix_weapon_ammo & IT_NAILS) ?
79                                 autocvar_g_pickup_nails_max : 0;
80                         self.ammo_rockets = (nix_weapon_ammo & IT_ROCKETS) ?
81                                 autocvar_g_pickup_rockets_max : 0;
82                         self.ammo_cells = (nix_weapon_ammo & IT_CELLS) ?
83                                 autocvar_g_pickup_cells_max : 0;
84                         self.ammo_fuel = (nix_weapon_ammo & IT_FUEL) ?
85                                 autocvar_g_pickup_fuel_max : 0;
86                 }
87                 else
88                 {
89                         self.ammo_shells = (nix_weapon_ammo & IT_SHELLS) ?
90                                 autocvar_g_balance_nix_ammo_shells : 0;
91                         self.ammo_nails = (nix_weapon_ammo & IT_NAILS) ?
92                                 autocvar_g_balance_nix_ammo_nails : 0;
93                         self.ammo_rockets = (nix_weapon_ammo & IT_ROCKETS) ?
94                                 autocvar_g_balance_nix_ammo_rockets : 0;
95                         self.ammo_cells = (nix_weapon_ammo & IT_CELLS) ?
96                                 autocvar_g_balance_nix_ammo_cells : 0;
97                         self.ammo_fuel = (nix_weapon_ammo & IT_FUEL) ?
98                                 autocvar_g_balance_nix_ammo_fuel : 0;
99                 }
100                 self.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
101                 if(dt >= 1 && dt <= 5)
102                         self.nix_lastinfotime = -42;
103                 else
104                         Send_CSQC_Centerprint_Generic(self, CPID_NIX_WPNCHANGE, strcat("^2Active weapon: ^3", W_Name(nix_weapon)), 0, 0);
105
106                 weapon_action(nix_weapon, WR_RESETPLAYER);
107                 // all weapons must be fully loaded when we spawn
108                 entity e;
109                 e = get_weaponinfo(nix_weapon);
110                 if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
111                         self.weapon_load[nix_weapon] = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
112         }
113         if(self.nix_lastinfotime != dt)
114         {
115                 self.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
116                 if(dt >= 1 && dt <= 5)
117                         Send_CSQC_Centerprint_Generic(self, CPID_NIX_WPNCHANGE, strcat("^3%d^2 seconds until weapon change...\n\nNext weapon: ^3", W_Name(nix_nextweapon)), 1, dt);
118         }
119
120         if(!(self.items & IT_UNLIMITED_WEAPON_AMMO) && time > self.nix_nextincr)
121         {
122                 if (nix_weapon_ammo & IT_SHELLS)
123                         self.ammo_shells = self.ammo_shells + autocvar_g_balance_nix_ammoincr_shells;
124                 else if (nix_weapon_ammo & IT_NAILS)
125                         self.ammo_nails = self.ammo_nails + autocvar_g_balance_nix_ammoincr_nails;
126                 else if (nix_weapon_ammo & IT_ROCKETS)
127                         self.ammo_rockets = self.ammo_rockets + autocvar_g_balance_nix_ammoincr_rockets;
128                 else if (nix_weapon_ammo & IT_CELLS)
129                         self.ammo_cells = self.ammo_cells + autocvar_g_balance_nix_ammoincr_cells;
130                 if (nix_weapon_ammo & IT_FUEL) // hook uses cells and fuel
131                         self.ammo_fuel = self.ammo_fuel + autocvar_g_balance_nix_ammoincr_fuel;
132                 self.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
133         }
134
135         self.weapons = 0;
136         if(g_nix_with_laser)
137                 self.weapons = self.weapons | WEPBIT_LASER;
138         self.weapons = self.weapons | W_WeaponBit(nix_weapon);
139
140         if(self.switchweapon != nix_weapon)
141                 if(!client_hasweapon(self, self.switchweapon, TRUE, FALSE))
142                         if(client_hasweapon(self, nix_weapon, TRUE, FALSE))
143                                 W_SwitchWeapon(nix_weapon);
144 }
145
146 void NIX_precache()
147 {
148         float i;
149         for (i = WEP_FIRST; i <= WEP_LAST; ++i)
150                 if (NIX_CanChooseWeapon(i))
151                         weapon_action(i, WR_PRECACHE);
152 }
153
154 MUTATOR_HOOKFUNCTION(nix_ForbidThrowCurrentWeapon)
155 {
156         return 1; // no throwing in NIX
157 }
158
159 MUTATOR_HOOKFUNCTION(nix_SetStartItems)
160 {
161         NIX_precache();
162         // we do NOT change the start weapons any more, so we can later turn off the mutator!
163         //   start_weapons = 0; // will be done later, when player spawns
164         //   warmup_start_weapons = 0; // will be done later, when player spawns
165         return 0;
166 }
167
168 MUTATOR_HOOKFUNCTION(nix_BuildMutatorsString)
169 {
170         ret_string = strcat(ret_string, ":NIX");
171         return 0;
172 }
173
174 MUTATOR_HOOKFUNCTION(nix_BuildMutatorsPrettyString)
175 {
176         ret_string = strcat(ret_string, ", NIX");
177         return 0;
178 }
179
180 MUTATOR_HOOKFUNCTION(nix_FilterItem)
181 {
182         switch (self.items)
183         {
184                 case IT_HEALTH:
185                 case IT_5HP:
186                 case IT_25HP:
187                 case IT_ARMOR:
188                 case IT_ARMOR_SHARD:
189                         if (autocvar_g_nix_with_healtharmor)
190                                 return 0;
191                         break;
192                 case IT_STRENGTH:
193                 case IT_INVINCIBLE:
194                         if (autocvar_g_nix_with_powerups)
195                                 return 0;
196                         break;
197         }
198
199         return 1; // delete all other items
200 }
201
202 MUTATOR_HOOKFUNCTION(nix_OnEntityPreSpawn)
203 {
204         if(self.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
205                 return 1;
206         return 0;
207 }
208
209 MUTATOR_HOOKFUNCTION(nix_PlayerPreThink)
210 {
211         if(!intermission_running)
212         if(self.deadflag == DEAD_NO)
213         if(self.classname == "player")
214                 NIX_GiveCurrentWeapon();
215         return 0;
216 }
217
218 MUTATOR_HOOKFUNCTION(nix_PlayerSpawn)
219 {
220         self.nix_lastchange_id = -1;
221         NIX_GiveCurrentWeapon(); // overrides the weapons you got when spawning
222         return 0;
223 }
224
225 MUTATOR_DEFINITION(mutator_nix)
226 {
227         entity e;
228
229         MUTATOR_HOOK(ForbidThrowCurrentWeapon, nix_ForbidThrowCurrentWeapon, CBC_ORDER_ANY);
230         MUTATOR_HOOK(SetStartItems, nix_SetStartItems, CBC_ORDER_EXCLUSIVE);
231         MUTATOR_HOOK(BuildMutatorsString, nix_BuildMutatorsString, CBC_ORDER_ANY);
232         MUTATOR_HOOK(BuildMutatorsPrettyString, nix_BuildMutatorsPrettyString, CBC_ORDER_ANY);
233         MUTATOR_HOOK(FilterItem, nix_FilterItem, CBC_ORDER_ANY);
234         MUTATOR_HOOK(OnEntityPreSpawn, nix_OnEntityPreSpawn, CBC_ORDER_ANY);
235         MUTATOR_HOOK(PlayerPreThink, nix_PlayerPreThink, CBC_ORDER_ANY);
236         MUTATOR_HOOK(PlayerSpawn, nix_PlayerSpawn, CBC_ORDER_ANY);
237
238         MUTATOR_ONADD
239         {
240                 g_nix_with_laser = autocvar_g_nix_with_laser;
241
242                 nix_nextchange = 0;
243                 nix_nextweapon = 0;
244
245                 NIX_precache();
246
247                 FOR_EACH_PLAYER(e)
248                 {
249                         if(e.deadflag == DEAD_NO)
250                         {
251                                 e.nix_save_cells = e.ammo_cells;
252                                 e.nix_save_shells = e.ammo_shells;
253                                 e.nix_save_nails = e.ammo_nails;
254                                 e.nix_save_rockets = e.ammo_rockets;
255                                 e.nix_save_fuel = e.ammo_fuel;
256                                 e.nix_save_weapons = e.weapons;
257                         }
258                         else
259                         {
260                                 e.nix_save_cells = 0;
261                                 e.nix_save_shells = 0;
262                                 e.nix_save_nails = 0;
263                                 e.nix_save_rockets = 0;
264                                 e.nix_save_fuel = 0;
265                                 e.nix_save_weapons = 0;
266                         }
267                 }
268         }
269
270         MUTATOR_ONREMOVE
271         {
272                 // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
273
274                 FOR_EACH_PLAYER(e) if(e.deadflag == DEAD_NO)
275                 {
276                         e.ammo_cells = max(start_ammo_cells, e.nix_save_cells);
277                         e.ammo_shells = max(start_ammo_shells, e.nix_save_shells);
278                         e.ammo_nails = max(start_ammo_nails, e.nix_save_nails);
279                         e.ammo_rockets = max(start_ammo_rockets, e.nix_save_rockets);
280                         e.ammo_fuel = max(start_ammo_fuel, e.nix_save_fuel);
281                         e.weapons = (start_weapons | e.nix_save_weapons);
282                         if(!client_hasweapon(e, e.weapon, TRUE, FALSE))
283                                 e.switchweapon = w_getbestweapon(self);
284                 }
285         }
286
287         return 0;
288 }