]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/mutator_nix.qc
NIX mutator: remove the on-remove erorr, and handle it gracefully
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator_nix.qc
1 float g_nix, g_nix_with_laser;
2
3 float nix_weapon;
4 float nix_weapon_ammo;
5 float nix_nextchange;
6 float nix_nextweapon;
7 float nix_nextweapon_ammo;
8 .float nix_lastchange_id;
9 .float nix_lastinfotime;
10 .float nix_nextincr;
11
12 float NIX_CanChooseWeapon(float wpn)
13 {
14         entity e;
15         e = get_weaponinfo(wpn);
16         if(!e.weapons) // skip dummies
17                 return FALSE;
18         if(g_weaponarena)
19         {
20                 if not(g_weaponarena & e.weapons)
21                         return FALSE;
22         }
23         else
24         {
25                 if(wpn == WEP_LASER && g_nix_with_laser)
26                         return FALSE;
27                 if not(e.spawnflags & WEP_FLAG_NORMAL)
28                         return FALSE;
29         }
30         return TRUE;
31 }
32 void NIX_ChooseNextWeapon()
33 {
34         float j;
35         RandomSelection_Init();
36         for(j = WEP_FIRST; j <= WEP_LAST; ++j)
37                 if(NIX_CanChooseWeapon(j))
38                         RandomSelection_Add(world, j, string_null, 1, (j != nix_weapon));
39         nix_nextweapon = RandomSelection_chosen_float;
40         nix_nextweapon_ammo = W_AmmoItemCode(nix_nextweapon);
41 }
42
43 void NIX_GiveCurrentWeapon()
44 {
45         float dt;
46
47         if(!nix_nextweapon)
48                 NIX_ChooseNextWeapon();
49
50         dt = ceil(nix_nextchange - time);
51
52         if(dt <= 0)
53         {
54                 nix_weapon = nix_nextweapon;
55                 nix_weapon_ammo = nix_nextweapon_ammo;
56                 nix_nextweapon = 0;
57                 nix_nextchange = time + cvar("g_balance_nix_roundtime");
58                 //weapon_action(nix_weapon, WR_PRECACHE); // forget it, too slow
59         }
60         
61         if(nix_nextchange != self.nix_lastchange_id) // this shall only be called once per round!
62         {
63                 self.nix_lastchange_id = nix_nextchange;
64                 if (self.items & IT_UNLIMITED_WEAPON_AMMO)
65                 {
66                         self.ammo_shells = (nix_weapon_ammo & IT_SHELLS) ?
67                                 cvar("g_pickup_shells_max") : 0;
68                         self.ammo_nails = (nix_weapon_ammo & IT_NAILS) ?
69                                 cvar("g_pickup_nails_max") : 0;
70                         self.ammo_rockets = (nix_weapon_ammo & IT_ROCKETS) ?
71                                 cvar("g_pickup_rockets_max") : 0;
72                         self.ammo_cells = (nix_weapon_ammo & IT_CELLS) ?
73                                 cvar("g_pickup_cells_max") : 0;
74                         self.ammo_fuel = (nix_weapon_ammo & IT_FUEL) ?
75                                 cvar("g_pickup_fuel_max") : 0;
76                 }
77                 else
78                 {
79                         self.ammo_shells = (nix_weapon_ammo & IT_SHELLS) ?
80                                 cvar("g_balance_nix_ammo_shells") : 0;
81                         self.ammo_nails = (nix_weapon_ammo & IT_NAILS) ?
82                                 cvar("g_balance_nix_ammo_nails") : 0;
83                         self.ammo_rockets = (nix_weapon_ammo & IT_ROCKETS) ?
84                                 cvar("g_balance_nix_ammo_rockets") : 0;
85                         self.ammo_cells = (nix_weapon_ammo & IT_CELLS) ?
86                                 cvar("g_balance_nix_ammo_cells") : 0;
87                         self.ammo_fuel = (nix_weapon_ammo & IT_FUEL) ?
88                                 cvar("g_balance_nix_ammo_fuel") : 0;
89                 }
90                 self.nix_nextincr = time + cvar("g_balance_nix_incrtime");
91                 if(dt >= 1 && dt <= 5)
92                         self.nix_lastinfotime = -42;
93                 else
94                         centerprint(self, strcat("\n\n^2Active weapon: ^3", W_Name(nix_weapon)));
95         }
96         if(self.nix_lastinfotime != dt)
97         {
98                 self.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
99                 if(dt >= 1 && dt <= 5)
100                         centerprint(self, strcat("^3", ftos(dt), "^2 seconds until weapon change...\n\nNext weapon: ^3", W_Name(nix_nextweapon), "\n"));
101         }
102
103         if(!(self.items & IT_UNLIMITED_WEAPON_AMMO) && time > self.nix_nextincr)
104         {
105                 if (nix_weapon_ammo & IT_SHELLS)
106                         self.ammo_shells = self.ammo_shells + cvar("g_balance_nix_ammoincr_shells");
107                 else if (nix_weapon_ammo & IT_NAILS)
108                         self.ammo_nails = self.ammo_nails + cvar("g_balance_nix_ammoincr_nails");
109                 else if (nix_weapon_ammo & IT_ROCKETS)
110                         self.ammo_rockets = self.ammo_rockets + cvar("g_balance_nix_ammoincr_rockets");
111                 else if (nix_weapon_ammo & IT_CELLS)
112                         self.ammo_cells = self.ammo_cells + cvar("g_balance_nix_ammoincr_cells");
113                 if (nix_weapon_ammo & IT_FUEL) // hook uses cells and fuel
114                         self.ammo_fuel = self.ammo_fuel + cvar("g_balance_nix_ammoincr_fuel");
115                 self.nix_nextincr = time + cvar("g_balance_nix_incrtime");
116         }
117
118         self.weapons = 0;
119         if(g_nix_with_laser)
120                 self.weapons = self.weapons | WEPBIT_LASER;
121         self.weapons = self.weapons | W_WeaponBit(nix_weapon);
122
123         if(self.switchweapon != nix_weapon)
124                 if(!client_hasweapon(self, self.switchweapon, TRUE, FALSE))
125                         if(client_hasweapon(self, nix_weapon, TRUE, FALSE))
126                                 W_SwitchWeapon(nix_weapon);
127 }
128
129 void NIX_precache()
130 {
131         float i;
132         for (i = WEP_FIRST; i <= WEP_LAST; ++i)
133                 if (NIX_CanChooseWeapon(i))
134                         weapon_action(i, WR_PRECACHE);
135 }
136
137 MUTATOR_HOOKFUNCTION(nix_ForbidThrowCurrentWeapon)
138 {
139         return 1; // no throwing in NIX
140 }
141
142 MUTATOR_HOOKFUNCTION(nix_SetStartItems)
143 {
144         NIX_precache();
145         // we do NOT change the start weapons any more, so we can later turn off the mutator!
146         //   start_weapons = 0; // will be done later, when player spawns
147         //   warmup_start_weapons = 0; // will be done later, when player spawns
148         return 0;
149 }
150
151 MUTATOR_HOOKFUNCTION(nix_BuildMutatorsString)
152 {
153         ret_string = strcat(ret_string, ":NIX");
154         return 0;
155 }
156
157 MUTATOR_HOOKFUNCTION(nix_BuildMutatorsPrettyString)
158 {
159         ret_string = strcat(ret_string, ", NIX");
160         return 0;
161 }
162
163 MUTATOR_HOOKFUNCTION(nix_FilterItem)
164 {
165         switch (self.items)
166         {
167                 case IT_HEALTH:
168                 case IT_5HP:
169                 case IT_25HP:
170                 case IT_ARMOR:
171                 case IT_ARMOR_SHARD:
172                         if (cvar("g_nix_with_healtharmor"))
173                                 return 0;
174                         break;
175                 case IT_STRENGTH:
176                 case IT_INVINCIBLE:
177                         if (cvar("g_nix_with_powerups"))
178                                 return 0;
179                         break;
180         }
181
182         return 1; // delete all other items
183 }
184
185 MUTATOR_HOOKFUNCTION(nix_OnEntityPreSpawn)
186 {
187         if(self.classname == "target_items") // items triggers cannot work in nixnex (as they change weapons/ammo)
188                 return 1;
189         return 0;
190 }
191
192 MUTATOR_HOOKFUNCTION(nix_PlayerPreThink)
193 {
194         if(!intermission_running)
195         if(self.deadflag == DEAD_NO)
196         if(self.classname == "player")
197                 NIX_GiveCurrentWeapon();
198         return 0;
199 }
200
201 MUTATOR_HOOKFUNCTION(nix_PlayerSpawn)
202 {
203         self.nix_lastchange_id = -1;
204         NIX_GiveCurrentWeapon(); // overrides the weapons you got when spawning
205         return 0;
206 }
207
208 MUTATOR_DEFINITION(mutator_nix)
209 {
210         MUTATOR_HOOK(ForbidThrowCurrentWeapon, nix_ForbidThrowCurrentWeapon, CBC_ORDER_ANY);
211         MUTATOR_HOOK(SetStartItems, nix_SetStartItems, CBC_ORDER_EXCLUSIVE);
212         MUTATOR_HOOK(BuildMutatorsString, nix_BuildMutatorsString, CBC_ORDER_ANY);
213         MUTATOR_HOOK(BuildMutatorsPrettyString, nix_BuildMutatorsPrettyString, CBC_ORDER_ANY);
214         MUTATOR_HOOK(FilterItem, nix_FilterItem, CBC_ORDER_ANY);
215         MUTATOR_HOOK(OnEntityPreSpawn, nix_OnEntityPreSpawn, CBC_ORDER_ANY);
216         MUTATOR_HOOK(PlayerPreThink, nix_PlayerPreThink, CBC_ORDER_ANY);
217         MUTATOR_HOOK(PlayerSpawn, nix_PlayerSpawn, CBC_ORDER_ANY);
218
219         MUTATOR_ONADD
220         {
221                 g_nix = 1;
222                 g_nix_with_laser = cvar("g_nix_with_laser");
223
224                 nix_nextchange = time;
225                 nix_nextweapon = 0;
226
227                 NIX_precache();
228         }
229
230         MUTATOR_ONREMOVE
231         {
232                 g_nix = 0;
233                 // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
234         }
235
236         return 0;
237 }