2 #include "round_handler.qh"
4 #include "weapons/throwing.qh"
5 #include "command/common.qh"
8 #include "clientkill.qh"
10 #include <server/mutators/_mod.qh>
11 #include "weapons/selection.qh"
12 #include "weapons/tracing.qh"
13 #include "weapons/weaponsystem.qh"
15 #include <common/gamemodes/_mod.qh>
17 #include <common/state.qh>
19 #include "../common/minigames/sv_minigames.qh"
21 #include <common/weapons/_all.qh>
22 #include "../common/vehicles/sv_vehicles.qh"
24 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
28 #define IMPULSE(id) _IMPULSE(IMP_##id)
29 #define _IMPULSE(id) \
30 void id##_handle(entity this); \
31 STATIC_INIT_LATE(id) \
33 id.impulse_handle = id##_handle; \
35 void id##_handle(entity this)
40 * 0 reserved (no input)
47 * 143: emergency teleport
48 * 148: unfairly eliminate
51 * 200 to 209: prev weapon shortcuts
52 * 210 to 219: best weapon shortcuts
53 * 220 to 229: next weapon shortcuts
54 * 230 to 253: individual weapons (up to 24)
57 // weapon switching impulses
60 IMPULSE(weapon_group_##i) \
64 this.impulse = IMP_weapon_group_##i.impulse; \
67 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
69 .entity weaponentity = weaponentities[slot]; \
70 W_NextWeaponOnImpulse(this, i, weaponentity); \
71 if(autocvar_g_weaponswitch_debug != 1) \
87 // custom order weapon cycling
90 IMPULSE(weapon_priority_##i##_##dir) \
92 if (this.vehicle) return; \
95 this.impulse = IMP_weapon_priority_##i##_##dir.impulse; \
98 noref int prev = -1; \
100 noref int next = +1; \
101 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
103 .entity weaponentity = weaponentities[slot]; \
104 W_CycleWeapon(this, CS(this).cvar_cl_weaponpriorities[i], dir, weaponentity); \
105 if(autocvar_g_weaponswitch_debug != 1) \
146 IMPULSE(weapon_byid_##i) \
148 if (this.vehicle) return; \
151 this.impulse = IMP_weapon_byid_##i.impulse; \
154 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
156 .entity weaponentity = weaponentities[slot]; \
157 W_SwitchWeapon_TryOthers(this, REGISTRY_GET(Weapons, WEP_FIRST + i), weaponentity); \
158 if(autocvar_g_weaponswitch_debug != 1) \
188 IMPULSE(weapon_next_byid)
190 if (this.vehicle) return;
193 this.impulse = IMP_weapon_next_byid.impulse;
196 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
198 .entity weaponentity = weaponentities[slot];
199 W_NextWeapon(this, 0, weaponentity);
201 if(autocvar_g_weaponswitch_debug != 1)
206 IMPULSE(weapon_prev_byid)
208 if (this.vehicle) return;
211 this.impulse = IMP_weapon_prev_byid.impulse;
214 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
216 .entity weaponentity = weaponentities[slot];
217 W_PreviousWeapon(this, 0, weaponentity);
219 if(autocvar_g_weaponswitch_debug != 1)
224 IMPULSE(weapon_next_bygroup)
226 if (this.vehicle) return;
229 this.impulse = IMP_weapon_next_bygroup.impulse;
232 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
234 .entity weaponentity = weaponentities[slot];
235 W_NextWeapon(this, 1, weaponentity);
237 if(autocvar_g_weaponswitch_debug != 1)
242 IMPULSE(weapon_prev_bygroup)
244 if (this.vehicle) return;
247 this.impulse = IMP_weapon_prev_bygroup.impulse;
250 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
252 .entity weaponentity = weaponentities[slot];
253 W_PreviousWeapon(this, 1, weaponentity);
255 if(autocvar_g_weaponswitch_debug != 1)
260 IMPULSE(weapon_next_bypriority)
262 if (this.vehicle) return;
265 this.impulse = IMP_weapon_next_bypriority.impulse;
268 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
270 .entity weaponentity = weaponentities[slot];
271 W_NextWeapon(this, 2, weaponentity);
273 if(autocvar_g_weaponswitch_debug != 1)
278 IMPULSE(weapon_prev_bypriority)
280 if (this.vehicle) return;
283 this.impulse = IMP_weapon_prev_bypriority.impulse;
286 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
288 .entity weaponentity = weaponentities[slot];
289 W_PreviousWeapon(this, 2, weaponentity);
291 if(autocvar_g_weaponswitch_debug != 1)
298 if (this.vehicle) return;
299 if (IS_DEAD(this)) return;
300 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
302 .entity weaponentity = weaponentities[slot];
303 W_LastWeapon(this, weaponentity);
305 if(autocvar_g_weaponswitch_debug != 1)
312 if (this.vehicle) return;
313 if (IS_DEAD(this)) return;
314 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
316 .entity weaponentity = weaponentities[slot];
317 W_SwitchWeapon(this, w_getbestweapon(this, weaponentity), weaponentity);
319 if(autocvar_g_weaponswitch_debug != 1)
326 if (this.vehicle) return;
327 if (IS_DEAD(this)) return;
328 bool is_dualwielding = W_DualWielding(this);
329 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
331 .entity weaponentity = weaponentities[slot];
332 vector md = this.(weaponentity).movedir;
333 vector vecs = ((md.x > 0) ? md : '0 0 0');
334 vector dv = v_right * -vecs.y;
336 dv = '0 0 0'; // don't override!
337 W_ThrowWeapon(this, weaponentity, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), dv, true);
339 if(autocvar_g_weaponswitch_debug == 2)
340 break; // in this mode, the off-hand weapon is selected based on the primary weapon, don't drop it twice!
344 IMPULSE(weapon_reload)
346 if (this.vehicle) return;
347 if (IS_DEAD(this)) return;
348 if (weaponLocked(this)) return;
350 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
352 .entity weaponentity = weaponentities[slot];
353 Weapon w = this.(weaponentity).m_weapon;
354 w.wr_reload(w, actor, weaponentity);
356 // allow reloading all active slots?
357 //if(autocvar_g_weaponswitch_debug != 1)
362 void ImpulseCommands(entity this)
364 if (game_stopped) return;
366 int imp = CS(this).impulse;
368 CS(this).impulse = 0;
370 if (MinigameImpulse(this, imp)) return;
372 if (timeout_status == TIMEOUT_ACTIVE) return; // don't allow any impulses while the game is paused
374 // allow only weapon change impulses when not in round time
375 if (round_handler_IsActive() && !round_handler_IsRoundStarted())
377 #define X(id) case IMP_##id.impulse:
392 X(weapon_next_bygroup)
393 X(weapon_prev_bygroup)
394 X(weapon_next_bypriority)
395 X(weapon_prev_bypriority)
399 X(weapon_priority_0_prev)
400 X(weapon_priority_1_prev)
401 X(weapon_priority_2_prev)
402 X(weapon_priority_3_prev)
403 X(weapon_priority_4_prev)
404 X(weapon_priority_5_prev)
405 X(weapon_priority_6_prev)
406 X(weapon_priority_7_prev)
407 X(weapon_priority_8_prev)
408 X(weapon_priority_9_prev)
409 X(weapon_priority_0_next)
410 X(weapon_priority_1_next)
411 X(weapon_priority_2_next)
412 X(weapon_priority_3_next)
413 X(weapon_priority_4_next)
414 X(weapon_priority_5_next)
415 X(weapon_priority_6_next)
416 X(weapon_priority_7_next)
417 X(weapon_priority_8_next)
418 X(weapon_priority_9_next)
419 X(weapon_priority_0_best)
420 X(weapon_priority_1_best)
421 X(weapon_priority_2_best)
422 X(weapon_priority_3_best)
423 X(weapon_priority_4_best)
424 X(weapon_priority_5_best)
425 X(weapon_priority_6_best)
426 X(weapon_priority_7_best)
427 X(weapon_priority_8_best)
428 X(weapon_priority_9_best)
459 if (vehicle_impulse(this, imp)) return;
461 if (CheatImpulse(this, imp)) return;
463 FOREACH(IMPULSES, it.impulse == imp, {
464 void(entity) f = it.impulse_handle;
476 IMPULSE(waypoint_personal_here)
478 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.origin, RADARICON_WAYPOINT);
479 if (wp) WaypointSprite_Ping(wp);
480 sprint(this, "personal waypoint spawned at location\n");
483 IMPULSE(waypoint_personal_crosshair)
485 WarpZone_crosshair_trace(this);
486 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, trace_endpos, RADARICON_WAYPOINT);
487 if (wp) WaypointSprite_Ping(wp);
488 sprint(this, "personal waypoint spawned at crosshair\n");
491 IMPULSE(waypoint_personal_death)
493 if (!this.death_origin) return;
494 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.death_origin, RADARICON_WAYPOINT);
495 if (wp) WaypointSprite_Ping(wp);
496 sprint(this, "personal waypoint spawned at death location\n");
499 IMPULSE(waypoint_here_follow)
501 if (!teamplay) return;
502 if (IS_DEAD(this)) return;
503 if (!MUTATOR_CALLHOOK(HelpMePing, this))
505 entity wp = WaypointSprite_Attach(WP_Helpme, this, true, RADARICON_HELPME);
506 if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
507 else WaypointSprite_Ping(wp);
509 sprint(this, "HELP ME attached\n");
512 IMPULSE(waypoint_here_here)
514 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.origin, RADARICON_HERE);
515 if (wp) WaypointSprite_Ping(wp);
516 sprint(this, "HERE spawned at location\n");
519 IMPULSE(waypoint_here_crosshair)
521 WarpZone_crosshair_trace_plusvisibletriggers(this);
522 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
523 if (wp) WaypointSprite_Ping(wp);
524 sprint(this, "HERE spawned at crosshair\n");
527 IMPULSE(waypoint_here_death)
529 if (!this.death_origin) return;
530 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.death_origin, RADARICON_HERE);
531 if (wp) WaypointSprite_Ping(wp);
532 sprint(this, "HERE spawned at death location\n");
535 IMPULSE(waypoint_danger_here)
537 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.origin, RADARICON_DANGER);
538 if (wp) WaypointSprite_Ping(wp);
539 sprint(this, "DANGER spawned at location\n");
542 IMPULSE(waypoint_danger_crosshair)
544 WarpZone_crosshair_trace(this);
545 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, trace_endpos, RADARICON_DANGER);
546 if (wp) WaypointSprite_Ping(wp);
547 sprint(this, "DANGER spawned at crosshair\n");
550 IMPULSE(waypoint_danger_death)
552 if (!this.death_origin) return;
553 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.death_origin, RADARICON_DANGER);
554 if (wp) WaypointSprite_Ping(wp);
555 sprint(this, "DANGER spawned at death location\n");
558 IMPULSE(waypoint_clear_personal)
560 WaypointSprite_ClearPersonal(this);
563 delete(this.personal);
564 this.personal = NULL;
566 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
569 sprint(this, "personal waypoint cleared\n");
572 IMPULSE(waypoint_clear)
574 WaypointSprite_ClearOwned(this);
577 delete(this.personal);
578 this.personal = NULL;
579 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
582 sprint(this, "all waypoints cleared\n");