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