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