]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/nix/sv_nix.qc
Merge branch 'master' into terencehill/glowmod_color_fix
[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))
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         if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
139         {
140                 SetResource(this, RES_SHELLS, 0);
141                 SetResource(this, RES_BULLETS, 0);
142                 SetResource(this, RES_ROCKETS, 0);
143                 SetResource(this, RES_CELLS, 0);
144                 SetResource(this, RES_PLASMA, 0);
145                 SetResource(this, RES_FUEL, 0);
146                 if(this.items & IT_UNLIMITED_AMMO)
147                 {
148                         switch (wpn.ammo_type)
149                         {
150                                 case RES_SHELLS:  SetResource(this, RES_SHELLS, autocvar_g_pickup_shells_max);  break;
151                                 case RES_BULLETS: SetResource(this, RES_BULLETS, autocvar_g_pickup_nails_max);   break;
152                                 case RES_ROCKETS: SetResource(this, RES_ROCKETS, autocvar_g_pickup_rockets_max); break;
153                                 case RES_CELLS:   SetResource(this, RES_CELLS, autocvar_g_pickup_cells_max);   break;
154                                 case RES_PLASMA:  SetResource(this, RES_PLASMA, autocvar_g_pickup_plasma_max);   break;
155                                 case RES_FUEL:    SetResource(this, RES_FUEL, autocvar_g_pickup_fuel_max);    break;
156                         }
157                 }
158                 else
159                 {
160                         switch (wpn.ammo_type)
161                         {
162                                 case RES_SHELLS:  SetResource(this, RES_SHELLS, autocvar_g_balance_nix_ammo_shells);  break;
163                                 case RES_BULLETS: SetResource(this, RES_BULLETS, autocvar_g_balance_nix_ammo_nails);   break;
164                                 case RES_ROCKETS: SetResource(this, RES_ROCKETS, autocvar_g_balance_nix_ammo_rockets); break;
165                                 case RES_CELLS:   SetResource(this, RES_CELLS, autocvar_g_balance_nix_ammo_cells);   break;
166                                 case RES_PLASMA:  SetResource(this, RES_PLASMA, autocvar_g_balance_nix_ammo_plasma);   break;
167                                 case RES_FUEL:    SetResource(this, RES_FUEL, autocvar_g_balance_nix_ammo_fuel);    break;
168                         }
169                 }
170
171                 this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
172                 if(dt >= 1 && dt <= 5)
173                         this.nix_lastinfotime = -42;
174                 else
175                         Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
176
177                 wpn.wr_resetplayer(wpn, this);
178
179                 // all weapons must be fully loaded when we spawn
180                 if (wpn.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
181                 {
182                         for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
183                         {
184                                 .entity weaponentity = weaponentities[slot];
185                                 this.(weaponentity).(weapon_load[nix_weapon]) = wpn.reloading_ammo;
186                         }
187                 }
188
189                 // set last change info
190                 this.nix_lastchange_id = nix_nextchange;
191         }
192         if(this.nix_lastinfotime != dt)
193         {
194                 this.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
195                 if(dt >= 1 && dt <= 5)
196                         Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
197         }
198
199         if(!(this.items & IT_UNLIMITED_AMMO) && time > this.nix_nextincr)
200         {
201                 switch (wpn.ammo_type)
202                 {
203                         case RES_SHELLS:  GiveResource(this, RES_SHELLS, autocvar_g_balance_nix_ammoincr_shells);  break;
204                         case RES_BULLETS: GiveResource(this, RES_BULLETS, autocvar_g_balance_nix_ammoincr_nails);   break;
205                         case RES_ROCKETS: GiveResource(this, RES_ROCKETS, autocvar_g_balance_nix_ammoincr_rockets); break;
206                         case RES_CELLS:   GiveResource(this, RES_CELLS, autocvar_g_balance_nix_ammoincr_cells);   break;
207                         case RES_PLASMA:  GiveResource(this, RES_PLASMA, autocvar_g_balance_nix_ammoincr_plasma);   break;
208                         case RES_FUEL:    GiveResource(this, RES_FUEL, autocvar_g_balance_nix_ammoincr_fuel);    break;
209                 }
210
211                 this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
212         }
213
214         STAT(WEAPONS, this) = '0 0 0';
215         if(g_nix_with_blaster)
216                 STAT(WEAPONS, this) |= WEPSET(BLASTER);
217         STAT(WEAPONS, this) |= wpn.m_wepset;
218
219         for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
220         {
221                 .entity weaponentity = weaponentities[slot];
222                 if (this.(weaponentity).m_weapon == WEP_Null && slot != 0)
223                         continue;
224
225                 if (this.(weaponentity).m_switchweapon != wpn)
226                 if (!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
227                 {
228                         if (client_hasweapon(this, wpn, weaponentity, true, false))
229                                 W_SwitchWeapon(this, wpn, weaponentity);
230                 }
231         }
232 }
233
234 MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
235 {
236         return true; // no throwing in NIX
237 }
238
239 MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
240 {
241         M_ARGV(0, string) = strcat(M_ARGV(0, string), ":NIX");
242 }
243
244 MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
245 {
246         M_ARGV(0, string) = strcat(M_ARGV(0, string), ", NIX");
247 }
248
249 MUTATOR_HOOKFUNCTION(nix, FilterItemDefinition)
250 {
251         entity definition = M_ARGV(0, entity);
252
253         if (definition.instanceOfHealth || definition.instanceOfArmor)
254         {
255                 return !autocvar_g_nix_with_healtharmor;
256         }
257         else if (definition.instanceOfPowerup)
258         {
259                 return !autocvar_g_nix_with_powerups;
260         }
261
262         return true; // delete all other items
263 }
264
265 MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
266 {
267         entity ent = M_ARGV(0, entity);
268
269         if(ent.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
270                 return true;
271 }
272
273 MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
274 {
275         entity player = M_ARGV(0, entity);
276
277         if(!game_stopped)
278         if(!IS_DEAD(player))
279         if(IS_PLAYER(player))
280                 NIX_GiveCurrentWeapon(player);
281 }
282
283 MUTATOR_HOOKFUNCTION(nix, ForbidRandomStartWeapons)
284 {
285         return true;
286 }
287
288 MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
289 {
290         entity player = M_ARGV(0, entity);
291
292         player.nix_lastchange_id = -1;
293         NIX_GiveCurrentWeapon(player); // overrides the weapons you got when spawning
294         player.items |= IT_UNLIMITED_SUPERWEAPONS;
295 }
296
297 MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
298 {
299         M_ARGV(0, string) = "NIX";
300 }