]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
Merge branch 'amade/small-fixes' into 'master'
[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))
124         if( !forbidWeaponUse(player)
125                 || (round_handler_IsActive() && !round_handler_IsRoundStarted()) )
126         if(time >= player.jump_interval)
127         {
128                 player.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor(player);
129                 makevectors(player.v_angle);
130
131                 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
132                 {
133                         .entity weaponentity = weaponentities[slot];
134
135                         if(player.(weaponentity).m_weapon == WEP_Null && slot != 0)
136                                 continue;
137
138                         Weapon oldwep = player.(weaponentity).m_weapon;
139                         player.(weaponentity).m_weapon = WEP_BLASTER;
140                         W_Blaster_Attack(
141                                 player,
142                                 weaponentity,
143                                 WEP_BLASTER.m_id | HITTYPE_SECONDARY,
144                                 WEP_CVAR_SEC(vaporizer, shotangle),
145                                 WEP_CVAR_SEC(vaporizer, damage),
146                                 WEP_CVAR_SEC(vaporizer, edgedamage),
147                                 WEP_CVAR_SEC(vaporizer, radius),
148                                 WEP_CVAR_SEC(vaporizer, force),
149                                 WEP_CVAR_SEC(vaporizer, speed),
150                                 WEP_CVAR_SEC(vaporizer, spread),
151                                 WEP_CVAR_SEC(vaporizer, delay),
152                                 WEP_CVAR_SEC(vaporizer, lifetime)
153                         );
154                         player.(weaponentity).m_weapon = oldwep;
155                 }
156         }
157
158         PHYS_INPUT_BUTTON_ATCK2(player) = false;
159 }
160
161 MUTATOR_HOOKFUNCTION(ok, PlayerWeaponSelect)
162 {
163         entity player = M_ARGV(0, entity);
164
165         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
166         {
167                 .entity weaponentity = weaponentities[slot];
168                 entity thiswep = player.(weaponentity);
169
170                 if(player.ok_lastwep[slot] && player.ok_lastwep[slot] != WEP_Null)
171                 {
172                         Weapon newwep = player.ok_lastwep[slot];
173                         if(player.ok_lastwep[slot] == WEP_HMG)
174                                 newwep = WEP_MACHINEGUN;
175                         if(player.ok_lastwep[slot] == WEP_RPC)
176                                 newwep = WEP_VORTEX;
177                         thiswep.m_switchweapon = newwep;
178                         player.ok_lastwep[slot] = WEP_Null;
179                 }
180         }
181 }
182
183 void self_spawnfunc_weapon_hmg(entity this) { spawnfunc_weapon_hmg(this); }
184 void self_spawnfunc_weapon_rpc(entity this) { spawnfunc_weapon_rpc(this); }
185
186 MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
187 {
188         entity ent = M_ARGV(0, entity);
189
190         if(autocvar_g_powerups)
191         if(autocvar_g_overkill_powerups_replace)
192         {
193                 if(ent.classname == "item_strength")
194                 {
195                         entity wep = new(weapon_hmg);
196                         setorigin(wep, ent.origin);
197                         setmodel(wep, MDL_OK_HMG);
198                         wep.ok_item = true;
199                         wep.noalign = ent.noalign;
200                         wep.cnt = ent.cnt;
201                         wep.team = ent.team;
202                         wep.respawntime = g_pickup_respawntime_superweapon;
203                         wep.pickup_anyway = true;
204                         wep.spawnfunc_checked = true;
205                         setthink(wep, self_spawnfunc_weapon_hmg);
206                         wep.nextthink = time + 0.1;
207                         return true;
208                 }
209                 else if(ent.classname == "item_invincible")
210                 {
211                         entity wep = new(weapon_rpc);
212                         setorigin(wep, ent.origin);
213                         setmodel(wep, MDL_OK_RPC);
214                         wep.ok_item = true;
215                         wep.noalign = ent.noalign;
216                         wep.cnt = ent.cnt;
217                         wep.team = ent.team;
218                         wep.respawntime = g_pickup_respawntime_superweapon;
219                         wep.pickup_anyway = true;
220                         wep.spawnfunc_checked = true;
221                         setthink(wep, self_spawnfunc_weapon_rpc);
222                         wep.nextthink = time + 0.1;
223                         return true;
224                 }
225         }
226 }
227
228 bool ok_HandleItemWaypoints(entity e)
229 {
230         if(!autocvar_g_overkill_itemwaypoints)
231                 return false; // don't handle it
232
233         switch(e.itemdef)
234         {
235                 case ITEM_HealthMega: return true;
236                 case ITEM_ArmorMedium: return true;
237                 case ITEM_ArmorBig: return true;
238                 case ITEM_ArmorMega: return true;
239         }
240
241         return false;
242 }
243
244 MUTATOR_HOOKFUNCTION(ok, Item_RespawnCountdown)
245 {
246         entity item = M_ARGV(0, entity);
247         return ok_HandleItemWaypoints(item);
248 }
249
250 MUTATOR_HOOKFUNCTION(ok, Item_ScheduleRespawn)
251 {
252         entity item = M_ARGV(0, entity);
253         return ok_HandleItemWaypoints(item);
254 }
255
256 MUTATOR_HOOKFUNCTION(ok, FilterItem)
257 {
258         entity item = M_ARGV(0, entity);
259
260         if(item.ok_item)
261                 return false;
262
263         switch(item.itemdef)
264         {
265                 case ITEM_HealthMega: return autocvar_g_overkill_filter_healthmega;
266                 case ITEM_ArmorMedium: return autocvar_g_overkill_filter_armormedium;
267                 case ITEM_ArmorBig: return autocvar_g_overkill_filter_armorbig;
268                 case ITEM_ArmorMega: return autocvar_g_overkill_filter_armormega;
269         }
270
271         return true;
272 }
273
274 MUTATOR_HOOKFUNCTION(ok, SetStartItems, CBC_ORDER_LAST)
275 {
276         WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
277
278         if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
279         if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
280
281         start_items |= IT_UNLIMITED_WEAPON_AMMO;
282         start_weapons = warmup_start_weapons = ok_start_items;
283 }
284
285 MUTATOR_HOOKFUNCTION(ok, SetWeaponArena)
286 {
287         // turn weapon arena off
288         M_ARGV(0, string) = "off";
289 }
290
291 MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
292 {
293         M_ARGV(0, string) = strcat(M_ARGV(0, string), ":OK");
294 }
295
296 MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
297 {
298         M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Overkill");
299 }
300
301 MUTATOR_HOOKFUNCTION(ok, SetModname)
302 {
303         M_ARGV(0, string) = "Overkill";
304         return true;
305 }
306
307 void ok_SetCvars()
308 {
309         // hack to force overkill playermodels
310         cvar_settemp("sv_defaultcharacter", "1");
311         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");
312         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");
313         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");
314 }
315
316 void ok_Initialize()
317 {
318         ok_SetCvars();
319
320         precache_all_playermodels("models/ok_player/*.dpm");
321
322         WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
323         WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
324
325         WEP_SHOTGUN.mdl = "ok_shotgun";
326         WEP_MACHINEGUN.mdl = "ok_mg";
327         WEP_VORTEX.mdl = "ok_sniper";
328 }