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