0c698e6b0dd3d29ef67fdb1c922a82ed94286856
[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, PlayerWeaponSelect)
114 {
115         entity player = M_ARGV(0, entity);
116
117         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
118         {
119                 .entity weaponentity = weaponentities[slot];
120                 entity thiswep = player.(weaponentity);
121
122                 if(player.ok_lastwep[slot] && player.ok_lastwep[slot] != WEP_Null)
123                 {
124                         Weapon newwep = player.ok_lastwep[slot];
125                         if(player.ok_lastwep[slot] == WEP_HMG)
126                                 newwep = WEP_MACHINEGUN;
127                         if(player.ok_lastwep[slot] == WEP_RPC)
128                                 newwep = WEP_VORTEX;
129                         thiswep.m_switchweapon = newwep;
130                         player.ok_lastwep[slot] = WEP_Null;
131                 }
132         }
133 }
134
135 void self_spawnfunc_weapon_hmg(entity this) { spawnfunc_weapon_hmg(this); }
136 void self_spawnfunc_weapon_rpc(entity this) { spawnfunc_weapon_rpc(this); }
137
138 MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
139 {
140         entity ent = M_ARGV(0, entity);
141
142         if(autocvar_g_powerups)
143         if(autocvar_g_overkill_powerups_replace)
144         {
145                 if(ent.classname == "item_strength")
146                 {
147                         entity wep = new(weapon_hmg);
148                         setorigin(wep, ent.origin);
149                         setmodel(wep, MDL_OK_HMG);
150                         wep.ok_item = true;
151                         wep.noalign = ent.noalign;
152                         wep.cnt = ent.cnt;
153                         wep.team = ent.team;
154                         wep.respawntime = g_pickup_respawntime_superweapon;
155                         wep.pickup_anyway = true;
156                         wep.spawnfunc_checked = true;
157                         setthink(wep, self_spawnfunc_weapon_hmg);
158                         wep.nextthink = time + 0.1;
159                         return true;
160                 }
161                 else if(ent.classname == "item_invincible")
162                 {
163                         entity wep = new(weapon_rpc);
164                         setorigin(wep, ent.origin);
165                         setmodel(wep, MDL_OK_RPC);
166                         wep.ok_item = true;
167                         wep.noalign = ent.noalign;
168                         wep.cnt = ent.cnt;
169                         wep.team = ent.team;
170                         wep.respawntime = g_pickup_respawntime_superweapon;
171                         wep.pickup_anyway = true;
172                         wep.spawnfunc_checked = true;
173                         setthink(wep, self_spawnfunc_weapon_rpc);
174                         wep.nextthink = time + 0.1;
175                         return true;
176                 }
177         }
178 }
179
180 bool ok_HandleItemWaypoints(entity e)
181 {
182         if(!autocvar_g_overkill_itemwaypoints)
183                 return false; // don't handle it
184
185         switch(e.itemdef)
186         {
187                 case ITEM_HealthMega: return true;
188                 case ITEM_ArmorMedium: return true;
189                 case ITEM_ArmorBig: return true;
190                 case ITEM_ArmorMega: return true;
191         }
192
193         return false;
194 }
195
196 MUTATOR_HOOKFUNCTION(ok, Item_RespawnCountdown)
197 {
198         entity item = M_ARGV(0, entity);
199         return ok_HandleItemWaypoints(item);
200 }
201
202 MUTATOR_HOOKFUNCTION(ok, Item_ScheduleRespawn)
203 {
204         entity item = M_ARGV(0, entity);
205         return ok_HandleItemWaypoints(item);
206 }
207
208 MUTATOR_HOOKFUNCTION(ok, FilterItem)
209 {
210         entity item = M_ARGV(0, entity);
211
212         if(item.ok_item)
213                 return false;
214
215         switch(item.itemdef)
216         {
217                 case ITEM_HealthMega: return autocvar_g_overkill_filter_healthmega;
218                 case ITEM_ArmorMedium: return autocvar_g_overkill_filter_armormedium;
219                 case ITEM_ArmorBig: return autocvar_g_overkill_filter_armorbig;
220                 case ITEM_ArmorMega: return autocvar_g_overkill_filter_armormega;
221         }
222
223         return true;
224 }
225
226 MUTATOR_HOOKFUNCTION(ok, SetStartItems, CBC_ORDER_LAST)
227 {
228         WepSet ok_start_items = (WEPSET(OVERKILL_MACHINEGUN) | WEPSET(OVERKILL_VORTEX) | WEPSET(OVERKILL_SHOTGUN));
229
230         if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
231         if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
232
233         start_items |= IT_UNLIMITED_WEAPON_AMMO;
234         start_weapons = warmup_start_weapons = ok_start_items;
235 }
236
237 MUTATOR_HOOKFUNCTION(ok, SetWeaponArena)
238 {
239         // turn weapon arena off
240         M_ARGV(0, string) = "off";
241 }
242
243 MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
244 {
245         M_ARGV(0, string) = strcat(M_ARGV(0, string), ":OK");
246 }
247
248 MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
249 {
250         M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Overkill");
251 }
252
253 MUTATOR_HOOKFUNCTION(ok, SetModname)
254 {
255         M_ARGV(0, string) = "Overkill";
256         return true;
257 }
258
259 void ok_Initialize()
260 {
261         precache_all_playermodels("models/ok_player/*.dpm");
262
263         WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
264         WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
265
266         //WEP_SHOTGUN.mdl = "ok_shotgun";
267         //WEP_MACHINEGUN.mdl = "ok_mg";
268         //WEP_VORTEX.mdl = "ok_sniper";
269 }