]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/nix/sv_nix.qc
Merge branch 'Lyberta/URS2' into 'master'
[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), { 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                         SetResourceAmount(it, RESOURCE_SHELLS, start_ammo_shells);
60                         SetResourceAmount(it, RESOURCE_BULLETS, start_ammo_nails);
61                         SetResourceAmount(it, RESOURCE_ROCKETS, start_ammo_rockets);
62                         SetResourceAmount(it, RESOURCE_CELLS, start_ammo_cells);
63                         SetResourceAmount(it, RESOURCE_PLASMA, start_ammo_plasma);
64                         SetResourceAmount(it, RESOURCE_FUEL, start_ammo_fuel);
65                         it.weapons = start_weapons;
66                         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
67                         {
68                                 .entity weaponentity = weaponentities[slot];
69                                 if(it.(weaponentity).m_weapon == WEP_Null && slot != 0)
70                                         continue;
71                                 if(!client_hasweapon(it, it.(weaponentity).m_weapon, weaponentity, true, false))
72                                         it.(weaponentity).m_switchweapon = w_getbestweapon(it, weaponentity);
73                         }
74                 });
75         }
76
77         return false;
78 }
79
80 bool NIX_CanChooseWeapon(int wpn)
81 {
82         entity e = Weapons_from(wpn);
83         if (e == WEP_Null) return false; // skip dummies
84         if(g_weaponarena)
85         {
86                 if(!(g_weaponarena_weapons & e.m_wepset))
87                         return false;
88         }
89         else
90         {
91                 if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
92                         return false;
93                 if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
94                         return false;
95                 if (!(e.spawnflags & WEP_FLAG_NORMAL))
96                         return false;
97         }
98         return true;
99 }
100 void NIX_ChooseNextWeapon()
101 {
102         RandomSelection_Init();
103         FOREACH(Weapons, it != WEP_Null, {
104                 if(NIX_CanChooseWeapon(it.m_id))
105                         RandomSelection_AddFloat(it.m_id, 1, (it.m_id != nix_weapon));
106         });
107         nix_nextweapon = RandomSelection_chosen_float;
108 }
109
110 void NIX_GiveCurrentWeapon(entity this)
111 {
112         float dt;
113
114         if(!nix_nextweapon)
115                 NIX_ChooseNextWeapon();
116
117         dt = ceil(nix_nextchange - time);
118
119         if(dt <= 0)
120         {
121                 nix_weapon = nix_nextweapon;
122                 nix_nextweapon = 0;
123                 if (!nix_nextchange) // no round played yet?
124                         nix_nextchange = time; // start the first round now!
125                 else
126                         nix_nextchange = time + autocvar_g_balance_nix_roundtime;
127                 // Weapon w = Weapons_from(nix_weapon);
128                 // w.wr_init(w); // forget it, too slow
129         }
130
131         // get weapon info
132         entity e = Weapons_from(nix_weapon);
133
134         if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
135         {
136                 SetResourceAmount(this, RESOURCE_SHELLS, 0);
137                 SetResourceAmount(this, RESOURCE_BULLETS, 0);
138                 SetResourceAmount(this, RESOURCE_ROCKETS, 0);
139                 SetResourceAmount(this, RESOURCE_CELLS, 0);
140                 SetResourceAmount(this, RESOURCE_PLASMA, 0);
141                 SetResourceAmount(this, RESOURCE_FUEL, 0);
142                 if(this.items & IT_UNLIMITED_WEAPON_AMMO)
143                 {
144                         switch(e.ammo_field)
145                         {
146                                 case ammo_shells:  SetResourceAmount(this, RESOURCE_SHELLS, autocvar_g_pickup_shells_max);  break;
147                                 case ammo_nails:   SetResourceAmount(this, RESOURCE_BULLETS, autocvar_g_pickup_nails_max);   break;
148                                 case ammo_rockets: SetResourceAmount(this, RESOURCE_ROCKETS, autocvar_g_pickup_rockets_max); break;
149                                 case ammo_cells:   SetResourceAmount(this, RESOURCE_CELLS, autocvar_g_pickup_cells_max);   break;
150                                 case ammo_plasma:  SetResourceAmount(this, RESOURCE_PLASMA, autocvar_g_pickup_plasma_max);   break;
151                                 case ammo_fuel:    SetResourceAmount(this, RESOURCE_FUEL, autocvar_g_pickup_fuel_max);    break;
152                         }
153                 }
154                 else
155                 {
156                         switch(e.ammo_field)
157                         {
158                                 case ammo_shells:  SetResourceAmount(this, RESOURCE_SHELLS, autocvar_g_balance_nix_ammo_shells);  break;
159                                 case ammo_nails:   SetResourceAmount(this, RESOURCE_BULLETS, autocvar_g_balance_nix_ammo_nails);   break;
160                                 case ammo_rockets: SetResourceAmount(this, RESOURCE_ROCKETS, autocvar_g_balance_nix_ammo_rockets); break;
161                                 case ammo_cells:   SetResourceAmount(this, RESOURCE_CELLS, autocvar_g_balance_nix_ammo_cells);   break;
162                                 case ammo_plasma:  SetResourceAmount(this, RESOURCE_PLASMA, autocvar_g_balance_nix_ammo_plasma);   break;
163                                 case ammo_fuel:    SetResourceAmount(this, RESOURCE_FUEL, autocvar_g_balance_nix_ammo_fuel);    break;
164                         }
165                 }
166
167                 this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
168                 if(dt >= 1 && dt <= 5)
169                         this.nix_lastinfotime = -42;
170                 else
171                         Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
172
173                 e.wr_resetplayer(e, this);
174
175                 // all weapons must be fully loaded when we spawn
176                 if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
177                 {
178                         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
179                         {
180                                 .entity weaponentity = weaponentities[slot];
181                                 this.(weaponentity).(weapon_load[nix_weapon]) = e.reloading_ammo;
182                         }
183                 }
184
185                 // vortex too
186                 if(WEP_CVAR(vortex, charge))
187                 {
188                         if(WEP_CVAR_SEC(vortex, chargepool))
189                                 this.vortex_chargepool_ammo = 1;
190                         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
191                         {
192                                 .entity weaponentity = weaponentities[slot];
193                                 this.(weaponentity).vortex_charge = WEP_CVAR(vortex, charge_start);
194                         }
195                 }
196
197                 // set last change info
198                 this.nix_lastchange_id = nix_nextchange;
199         }
200         if(this.nix_lastinfotime != dt)
201         {
202                 this.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
203                 if(dt >= 1 && dt <= 5)
204                         Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
205         }
206
207         if(!(this.items & IT_UNLIMITED_WEAPON_AMMO) && time > this.nix_nextincr)
208         {
209                 switch(e.ammo_field)
210                 {
211                         case ammo_shells:  GiveResource(this, RESOURCE_SHELLS, autocvar_g_balance_nix_ammoincr_shells);  break;
212                         case ammo_nails:   GiveResource(this, RESOURCE_BULLETS, autocvar_g_balance_nix_ammoincr_nails);   break;
213                         case ammo_rockets: GiveResource(this, RESOURCE_ROCKETS, autocvar_g_balance_nix_ammoincr_rockets); break;
214                         case ammo_cells:   GiveResource(this, RESOURCE_CELLS, autocvar_g_balance_nix_ammoincr_cells);   break;
215                         case ammo_plasma:  GiveResource(this, RESOURCE_PLASMA, autocvar_g_balance_nix_ammoincr_plasma);   break;
216                         case ammo_fuel:    GiveResource(this, RESOURCE_FUEL, autocvar_g_balance_nix_ammoincr_fuel);    break;
217                 }
218
219                 this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
220         }
221
222         this.weapons = '0 0 0';
223         if(g_nix_with_blaster)
224                 this.weapons |= WEPSET(BLASTER);
225         this.weapons |= e.m_wepset;
226
227     Weapon w = Weapons_from(nix_weapon);
228     for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
229     {
230         .entity weaponentity = weaponentities[slot];
231         if(this.(weaponentity).m_weapon == WEP_Null && slot != 0)
232                 continue;
233
234                 if(this.(weaponentity).m_switchweapon != w)
235                 if(!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
236                 {
237                         if(client_hasweapon(this, w, weaponentity, true, false))
238                                 W_SwitchWeapon(this, w, weaponentity);
239                 }
240         }
241 }
242
243 MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
244 {
245         return true; // no throwing in NIX
246 }
247
248 MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
249 {
250         M_ARGV(0, string) = strcat(M_ARGV(0, string), ":NIX");
251 }
252
253 MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
254 {
255         M_ARGV(0, string) = strcat(M_ARGV(0, string), ", NIX");
256 }
257
258 MUTATOR_HOOKFUNCTION(nix, FilterItem)
259 {
260         entity item = M_ARGV(0, entity);
261
262         if(item.itemdef.instanceOfHealth || item.itemdef.instanceOfArmor)
263         {
264                 return !autocvar_g_nix_with_healtharmor;
265         }
266         else if(item.itemdef.instanceOfPowerup)
267         {
268                 return !autocvar_g_nix_with_powerups;
269         }
270
271         return true; // delete all other items
272 }
273
274 MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
275 {
276         entity ent = M_ARGV(0, entity);
277
278         if(ent.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
279                 return true;
280 }
281
282 MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
283 {
284         entity player = M_ARGV(0, entity);
285
286         if(!game_stopped)
287         if(!IS_DEAD(player))
288         if(IS_PLAYER(player))
289                 NIX_GiveCurrentWeapon(player);
290 }
291
292 MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
293 {
294         entity player = M_ARGV(0, entity);
295
296         player.nix_lastchange_id = -1;
297         NIX_GiveCurrentWeapon(player); // overrides the weapons you got when spawning
298         player.items |= IT_UNLIMITED_SUPERWEAPONS;
299 }
300
301 MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
302 {
303         M_ARGV(0, string) = "NIX";
304 }