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