]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
Unhardcode a few more 0 slot cases
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / overkill / sv_overkill.qc
1 #include "sv_overkill.qh"
2
3 #include "hmg.qh"
4 #include "rpc.qh"
5
6 bool autocvar_g_overkill_powerups_replace;
7 float autocvar_g_overkill_superguns_respawn_time;
8 bool autocvar_g_overkill_100h_anyway;
9 bool autocvar_g_overkill_100a_anyway;
10
11 .vector ok_deathloc;
12 .float ok_spawnsys_timer;
13 .Weapon ok_lastwep[MAX_WEAPONSLOTS];
14 .float ok_item;
15
16 .float ok_pauseregen_finished;
17
18 void ok_Initialize();
19
20 REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
21 {
22         MUTATOR_ONADD
23         {
24                 ok_Initialize();
25         }
26
27         MUTATOR_ONREMOVE
28         {
29                 WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
30                 WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
31         }
32 }
33
34 void W_Blaster_Attack(entity, .entity, float, float, float, float, float, float, float, float, float, float);
35 spawnfunc(weapon_hmg);
36 spawnfunc(weapon_rpc);
37
38 MUTATOR_HOOKFUNCTION(ok, PlayerDamage_Calculate, CBC_ORDER_LAST)
39 {
40         entity frag_attacker = M_ARGV(1, entity);
41         entity frag_target = M_ARGV(2, entity);
42         float frag_deathtype = M_ARGV(3, float);
43
44         if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target))
45         if(DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
46         {
47                 if(frag_attacker != frag_target)
48                 if(frag_target.health > 0)
49                 if(STAT(FROZEN, frag_target) == 0)
50                 if(!IS_DEAD(frag_target))
51                 {
52                         Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE);
53                         M_ARGV(6, vector) = '0 0 0';
54                 }
55
56                 M_ARGV(4, float) = 0;
57         }
58 }
59
60 MUTATOR_HOOKFUNCTION(ok, PlayerDamage_SplitHealthArmor)
61 {
62         entity frag_target = M_ARGV(2, entity);
63         float damage_take = M_ARGV(4, float);
64
65         if(damage_take)
66                 frag_target.ok_pauseregen_finished = max(frag_target.ok_pauseregen_finished, time + 2);
67 }
68
69 void ok_DropItem(entity this, entity targ)
70 {
71         entity e = new(droppedweapon); // hax
72         e.ok_item = true;
73         e.noalign = true;
74         e.pickup_anyway = true;
75         e.spawnfunc_checked = true;
76         spawnfunc_item_armor_small(e);
77         if (!wasfreed(e)) { // might have been blocked by a mutator
78         set_movetype(e, MOVETYPE_TOSS);
79         e.gravity = 1;
80         e.reset = SUB_Remove;
81         setorigin(e, this.origin + '0 0 32');
82         e.velocity = '0 0 200' + normalize(targ.origin - this.origin) * 500;
83         SUB_SetFade(e, time + 5, 1);
84         }
85 }
86
87 MUTATOR_HOOKFUNCTION(ok, PlayerDies)
88 {
89         entity frag_attacker = M_ARGV(1, entity);
90         entity frag_target = M_ARGV(2, entity);
91
92         entity targ = ((frag_attacker) ? frag_attacker : frag_target);
93
94         ok_DropItem(frag_target, targ);
95
96         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
97         {
98                 .entity weaponentity = weaponentities[slot];
99
100                 frag_target.ok_lastwep[slot] = frag_target.(weaponentity).m_switchweapon;
101         }
102 }
103
104 MUTATOR_HOOKFUNCTION(ok, MonsterDropItem)
105 {
106         entity mon = M_ARGV(0, entity);
107         entity olditem = M_ARGV(1, entity);
108         entity frag_attacker = M_ARGV(2, entity);
109
110         delete(olditem);
111
112         M_ARGV(1, entity) = NULL;
113
114         ok_DropItem(mon, frag_attacker);
115 }
116
117 MUTATOR_HOOKFUNCTION(ok, PlayerRegen)
118 {
119         entity player = M_ARGV(0, entity);
120
121         // overkill's values are different, so use custom regen
122         if(!STAT(FROZEN, player))
123         {
124                 player.armorvalue = CalcRotRegen(player.armorvalue, autocvar_g_balance_armor_regenstable, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear,
125                         1 * frametime * (time > player.ok_pauseregen_finished), 0, 0, 1, 1 * frametime * (time > player.pauserotarmor_finished), autocvar_g_balance_armor_limit);
126                 player.health = CalcRotRegen(player.health, autocvar_g_balance_health_regenstable, 0, 100, 1 * frametime * (time > player.ok_pauseregen_finished), 200, 0,
127                         autocvar_g_balance_health_rotlinear, 1 * frametime * (time > player.pauserothealth_finished), autocvar_g_balance_health_limit);
128
129                 float minf, maxf, limitf;
130
131                 maxf = autocvar_g_balance_fuel_rotstable;
132                 minf = autocvar_g_balance_fuel_regenstable;
133                 limitf = autocvar_g_balance_fuel_limit;
134
135                 player.ammo_fuel = CalcRotRegen(player.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear,
136                         frametime * (time > player.pauseregen_finished) * ((player.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > player.pauserotfuel_finished), limitf);
137         }
138         return true; // return true anyway, as frozen uses no regen
139 }
140
141 MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
142 {
143         return true;
144 }
145
146 MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
147 {
148         if(intermission_running || gameover)
149                 return;
150
151         entity player = M_ARGV(0, entity);
152
153         if(IS_DEAD(player) || !IS_PLAYER(player) || STAT(FROZEN, player))
154                 return;
155
156         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
157         {
158                 .entity weaponentity = weaponentities[slot];
159                 entity thiswep = player.(weaponentity);
160
161                 if(player.ok_lastwep[slot] && player.ok_lastwep[slot] != WEP_Null)
162                 {
163                         Weapon newwep = player.ok_lastwep[slot];
164                         if(player.ok_lastwep[slot] == WEP_HMG)
165                                 newwep = WEP_MACHINEGUN;
166                         if(player.ok_lastwep[slot] == WEP_RPC)
167                                 newwep = WEP_VORTEX;
168                         thiswep.m_switchweapon = newwep;
169                         player.ok_lastwep[slot] = WEP_Null;
170                 }
171         }
172
173         if(PHYS_INPUT_BUTTON_ATCK2(player))
174         if(!forbidWeaponUse(player) || player.weapon_blocked) // allow if weapon is blocked
175         if(time >= player.jump_interval)
176         {
177                 player.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor(player);
178                 makevectors(player.v_angle);
179
180                 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
181                 {
182                         .entity weaponentity = weaponentities[slot];
183
184                         if(player.(weaponentity).m_weapon == WEP_Null && slot != 0)
185                                 continue;
186
187                         Weapon oldwep = player.(weaponentity).m_weapon;
188                         player.(weaponentity).m_weapon = WEP_BLASTER;
189                         W_Blaster_Attack(
190                                 player,
191                                 weaponentity,
192                                 WEP_BLASTER.m_id | HITTYPE_SECONDARY,
193                                 WEP_CVAR_SEC(vaporizer, shotangle),
194                                 WEP_CVAR_SEC(vaporizer, damage),
195                                 WEP_CVAR_SEC(vaporizer, edgedamage),
196                                 WEP_CVAR_SEC(vaporizer, radius),
197                                 WEP_CVAR_SEC(vaporizer, force),
198                                 WEP_CVAR_SEC(vaporizer, speed),
199                                 WEP_CVAR_SEC(vaporizer, spread),
200                                 WEP_CVAR_SEC(vaporizer, delay),
201                                 WEP_CVAR_SEC(vaporizer, lifetime)
202                         );
203                         player.(weaponentity).m_weapon = oldwep;
204                 }
205         }
206
207         PHYS_INPUT_BUTTON_ATCK2(player) = false;
208 }
209
210 MUTATOR_HOOKFUNCTION(ok, PlayerSpawn)
211 {
212         entity player = M_ARGV(0, entity);
213
214         // if player changed their weapon while dead, don't switch to their death weapon
215         if(player.impulse)
216         {
217                 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
218                 {
219                         player.ok_lastwep[slot] = WEP_Null;
220                 }
221         }
222
223         player.ok_pauseregen_finished = time + 2;
224 }
225
226 void self_spawnfunc_weapon_hmg(entity this) { spawnfunc_weapon_hmg(this); }
227 void self_spawnfunc_weapon_rpc(entity this) { spawnfunc_weapon_rpc(this); }
228
229 MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
230 {
231         entity ent = M_ARGV(0, entity);
232
233         if(autocvar_g_powerups)
234         if(autocvar_g_overkill_powerups_replace)
235         {
236                 if(ent.classname == "item_strength")
237                 {
238                         entity wep = new(weapon_hmg);
239                         setorigin(wep, ent.origin);
240                         setmodel(wep, MDL_OK_HMG);
241                         wep.ok_item = true;
242                         wep.noalign = ent.noalign;
243                         wep.cnt = ent.cnt;
244                         wep.team = ent.team;
245                         wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
246                         wep.pickup_anyway = true;
247                         wep.spawnfunc_checked = true;
248                         setthink(wep, self_spawnfunc_weapon_hmg);
249                         wep.nextthink = time + 0.1;
250                         return true;
251                 }
252
253                 if(ent.classname == "item_invincible")
254                 {
255                         entity wep = new(weapon_rpc);
256                         setorigin(wep, ent.origin);
257                         setmodel(wep, MDL_OK_RPC);
258                         wep.ok_item = true;
259                         wep.noalign = ent.noalign;
260                         wep.cnt = ent.cnt;
261                         wep.team = ent.team;
262                         wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
263                         wep.pickup_anyway = true;
264                         wep.spawnfunc_checked = true;
265                         setthink(wep, self_spawnfunc_weapon_rpc);
266                         wep.nextthink = time + 0.1;
267                         return true;
268                 }
269         }
270 }
271
272 MUTATOR_HOOKFUNCTION(ok, FilterItem)
273 {
274         entity item = M_ARGV(0, entity);
275
276         if(item.ok_item)
277                 return;
278
279         switch(item.items)
280         {
281                 case ITEM_HealthMega.m_itemid: return !(autocvar_g_overkill_100h_anyway);
282                 case ITEM_ArmorMega.m_itemid: return !(autocvar_g_overkill_100a_anyway);
283         }
284
285         return true;
286 }
287
288 MUTATOR_HOOKFUNCTION(ok, SetStartItems)
289 {
290         WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
291
292         if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
293         if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
294
295         start_items |= IT_UNLIMITED_WEAPON_AMMO;
296         start_weapons = warmup_start_weapons = ok_start_items;
297 }
298
299 MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
300 {
301         M_ARGV(0, string) = strcat(M_ARGV(0, string), ":OK");
302 }
303
304 MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
305 {
306         M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Overkill");
307 }
308
309 MUTATOR_HOOKFUNCTION(ok, SetModname)
310 {
311         M_ARGV(0, string) = "Overkill";
312         return true;
313 }
314
315 void ok_SetCvars()
316 {
317         // hack to force overkill playermodels
318         cvar_settemp("sv_defaultcharacter", "1");
319         cvar_settemp("sv_defaultplayermodel", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
320         cvar_settemp("sv_defaultplayermodel_red", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm");
321         cvar_settemp("sv_defaultplayermodel_blue", "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
322 }
323
324 void ok_Initialize()
325 {
326         ok_SetCvars();
327
328         precache_all_playermodels("models/ok_player/*.dpm");
329
330         WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
331         WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
332
333         WEP_SHOTGUN.mdl = "ok_shotgun";
334         WEP_MACHINEGUN.mdl = "ok_mg";
335         WEP_VORTEX.mdl = "ok_sniper";
336 }