d2a7308dedf04267af31ea7b599a4abd447ca08f
[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
8 bool autocvar_g_overkill_itemwaypoints = true;
9
10 bool autocvar_g_overkill_filter_healthmega;
11 bool autocvar_g_overkill_filter_armormedium;
12 bool autocvar_g_overkill_filter_armorbig;
13 bool autocvar_g_overkill_filter_armormega;
14
15 .float ok_item;
16
17 .Weapon ok_lastwep[MAX_WEAPONSLOTS];
18
19 void ok_Initialize();
20
21 REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
22 {
23         MUTATOR_ONADD
24         {
25                 ok_Initialize();
26         }
27
28         MUTATOR_ONREMOVE
29         {
30                 WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
31                 WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
32         }
33 }
34
35 void W_Blaster_Attack(entity, .entity, float, float, float, float, float, float, float, float, float, float);
36 spawnfunc(weapon_hmg);
37 spawnfunc(weapon_rpc);
38
39 MUTATOR_HOOKFUNCTION(ok, Damage_Calculate, CBC_ORDER_LAST)
40 {
41         entity frag_attacker = M_ARGV(1, entity);
42         entity frag_target = M_ARGV(2, entity);
43         float frag_deathtype = M_ARGV(3, float);
44
45         if(IS_PLAYER(frag_attacker) && (IS_PLAYER(frag_target) || IS_VEHICLE(frag_target) || IS_TURRET(frag_target)))
46         if(DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
47         {
48                 if(frag_attacker != frag_target)
49                 if(!STAT(FROZEN, frag_target))
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'; // force
54                 }
55
56                 M_ARGV(4, float) = 0; // damage
57         }
58 }
59
60 void ok_DropItem(entity this, entity targ)
61 {
62         entity e = new(droppedweapon); // hax
63         e.ok_item = true;
64         e.noalign = true;
65         e.pickup_anyway = true;
66         e.spawnfunc_checked = true;
67         spawnfunc_item_armor_small(e);
68         if (!wasfreed(e)) { // might have been blocked by a mutator
69         set_movetype(e, MOVETYPE_TOSS);
70         e.gravity = 1;
71         e.reset = SUB_Remove;
72         setorigin(e, this.origin + '0 0 32');
73         e.velocity = '0 0 200' + normalize(targ.origin - this.origin) * 500;
74         SUB_SetFade(e, time + 5, 1);
75         }
76 }
77
78 MUTATOR_HOOKFUNCTION(ok, PlayerDies)
79 {
80         entity frag_attacker = M_ARGV(1, entity);
81         entity frag_target = M_ARGV(2, entity);
82
83         entity targ = ((frag_attacker) ? frag_attacker : frag_target);
84
85         ok_DropItem(frag_target, targ);
86
87         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
88         {
89                 .entity weaponentity = weaponentities[slot];
90
91                 frag_target.ok_lastwep[slot] = frag_target.(weaponentity).m_switchweapon;
92         }
93 }
94
95 MUTATOR_HOOKFUNCTION(ok, MonsterDropItem)
96 {
97         entity mon = M_ARGV(0, entity);
98         entity olditem = M_ARGV(1, entity);
99         entity frag_attacker = M_ARGV(2, entity);
100
101         delete(olditem);
102
103         M_ARGV(1, entity) = NULL;
104
105         ok_DropItem(mon, frag_attacker);
106 }
107
108 MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
109 {
110         return true;
111 }
112
113 MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
114 {
115         if(game_stopped)
116                 return;
117
118         entity player = M_ARGV(0, entity);
119
120         if(IS_DEAD(player) || !IS_PLAYER(player) || STAT(FROZEN, player))
121                 return;
122
123         if(PHYS_INPUT_BUTTON_ATCK2(player) && time >= player.jump_interval)
124         if( !forbidWeaponUse(player)
125                 || (round_handler_IsActive() && !round_handler_IsRoundStarted()) )
126         {
127                 player.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor(player);
128                 makevectors(player.v_angle);
129
130                 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
131                 {
132                         .entity weaponentity = weaponentities[slot];
133
134                         if(player.(weaponentity).m_weapon == WEP_Null && slot != 0)
135                                 continue;
136
137                         Weapon oldwep = player.(weaponentity).m_weapon;
138                         player.(weaponentity).m_weapon = WEP_BLASTER;
139                         W_Blaster_Attack(
140                                 player,
141                                 weaponentity,
142                                 WEP_BLASTER.m_id | HITTYPE_SECONDARY,
143                                 WEP_CVAR_SEC(vaporizer, shotangle),
144                                 WEP_CVAR_SEC(vaporizer, damage),
145                                 WEP_CVAR_SEC(vaporizer, edgedamage),
146                                 WEP_CVAR_SEC(vaporizer, radius),
147                                 WEP_CVAR_SEC(vaporizer, force),
148                                 WEP_CVAR_SEC(vaporizer, speed),
149                                 WEP_CVAR_SEC(vaporizer, spread),
150                                 WEP_CVAR_SEC(vaporizer, delay),
151                                 WEP_CVAR_SEC(vaporizer, lifetime)
152                         );
153                         player.(weaponentity).m_weapon = oldwep;
154                 }
155         }
156
157         PHYS_INPUT_BUTTON_ATCK2(player) = false;
158 }
159
160 MUTATOR_HOOKFUNCTION(ok, PlayerWeaponSelect)
161 {
162         entity player = M_ARGV(0, entity);
163
164         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
165         {
166                 .entity weaponentity = weaponentities[slot];
167                 entity thiswep = player.(weaponentity);
168
169                 if(player.ok_lastwep[slot] && player.ok_lastwep[slot] != WEP_Null)
170                 {
171                         Weapon newwep = player.ok_lastwep[slot];
172                         if(player.ok_lastwep[slot] == WEP_HMG)
173                                 newwep = WEP_MACHINEGUN;
174                         if(player.ok_lastwep[slot] == WEP_RPC)
175                                 newwep = WEP_VORTEX;
176                         thiswep.m_switchweapon = newwep;
177                         player.ok_lastwep[slot] = WEP_Null;
178                 }
179         }
180 }
181
182 void self_spawnfunc_weapon_hmg(entity this) { spawnfunc_weapon_hmg(this); }
183 void self_spawnfunc_weapon_rpc(entity this) { spawnfunc_weapon_rpc(this); }
184
185 MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
186 {
187         entity ent = M_ARGV(0, entity);
188
189         if(autocvar_g_powerups)
190         if(autocvar_g_overkill_powerups_replace)
191         {
192                 if(ent.classname == "item_strength")
193                 {
194                         entity wep = new(weapon_hmg);
195                         setorigin(wep, ent.origin);
196                         setmodel(wep, MDL_OK_HMG);
197                         wep.ok_item = true;
198                         wep.noalign = ent.noalign;
199                         wep.cnt = ent.cnt;
200                         wep.team = ent.team;
201                         wep.respawntime = g_pickup_respawntime_superweapon;
202                         wep.pickup_anyway = true;
203                         wep.spawnfunc_checked = true;
204                         setthink(wep, self_spawnfunc_weapon_hmg);
205                         wep.nextthink = time + 0.1;
206                         return true;
207                 }
208                 else if(ent.classname == "item_invincible")
209                 {
210                         entity wep = new(weapon_rpc);
211                         setorigin(wep, ent.origin);
212                         setmodel(wep, MDL_OK_RPC);
213                         wep.ok_item = true;
214                         wep.noalign = ent.noalign;
215                         wep.cnt = ent.cnt;
216                         wep.team = ent.team;
217                         wep.respawntime = g_pickup_respawntime_superweapon;
218                         wep.pickup_anyway = true;
219                         wep.spawnfunc_checked = true;
220                         setthink(wep, self_spawnfunc_weapon_rpc);
221                         wep.nextthink = time + 0.1;
222                         return true;
223                 }
224         }
225 }
226
227 bool ok_HandleItemWaypoints(entity e)
228 {
229         if(!autocvar_g_overkill_itemwaypoints)
230                 return false; // don't handle it
231
232         switch(e.itemdef)
233         {
234                 case ITEM_HealthMega: return true;
235                 case ITEM_ArmorMedium: return true;
236                 case ITEM_ArmorBig: return true;
237                 case ITEM_ArmorMega: return true;
238         }
239
240         return false;
241 }
242
243 MUTATOR_HOOKFUNCTION(ok, Item_RespawnCountdown)
244 {
245         entity item = M_ARGV(0, entity);
246         return ok_HandleItemWaypoints(item);
247 }
248
249 MUTATOR_HOOKFUNCTION(ok, Item_ScheduleRespawn)
250 {
251         entity item = M_ARGV(0, entity);
252         return ok_HandleItemWaypoints(item);
253 }
254
255 MUTATOR_HOOKFUNCTION(ok, FilterItem)
256 {
257         entity item = M_ARGV(0, entity);
258
259         if(item.ok_item)
260                 return false;
261
262         switch(item.itemdef)
263         {
264                 case ITEM_HealthMega: return autocvar_g_overkill_filter_healthmega;
265                 case ITEM_ArmorMedium: return autocvar_g_overkill_filter_armormedium;
266                 case ITEM_ArmorBig: return autocvar_g_overkill_filter_armorbig;
267                 case ITEM_ArmorMega: return autocvar_g_overkill_filter_armormega;
268         }
269
270         return true;
271 }
272
273 MUTATOR_HOOKFUNCTION(ok, SetStartItems, CBC_ORDER_LAST)
274 {
275         WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
276
277         if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
278         if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
279
280         start_items |= IT_UNLIMITED_WEAPON_AMMO;
281         start_weapons = warmup_start_weapons = ok_start_items;
282 }
283
284 MUTATOR_HOOKFUNCTION(ok, SetWeaponArena)
285 {
286         // turn weapon arena off
287         M_ARGV(0, string) = "off";
288 }
289
290 MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
291 {
292         M_ARGV(0, string) = strcat(M_ARGV(0, string), ":OK");
293 }
294
295 MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
296 {
297         M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Overkill");
298 }
299
300 MUTATOR_HOOKFUNCTION(ok, SetModname)
301 {
302         M_ARGV(0, string) = "Overkill";
303         return true;
304 }
305
306 void ok_Initialize()
307 {
308         precache_all_playermodels("models/ok_player/*.dpm");
309
310         WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
311         WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
312
313         WEP_SHOTGUN.mdl = "ok_shotgun";
314         WEP_MACHINEGUN.mdl = "ok_mg";
315         WEP_VORTEX.mdl = "ok_sniper";
316 }