2 #include "round_handler.qh"
4 #include "weapons/throwing.qh"
5 #include "command/common.qh"
7 #include "clientkill.qh"
8 #include "weapons/selection.qh"
9 #include "weapons/tracing.qh"
10 #include "weapons/weaponsystem.qh"
12 #include <common/gamemodes/_mod.qh>
14 #include <common/state.qh>
16 #include "../common/minigames/sv_minigames.qh"
18 #include <common/weapons/_all.qh>
19 #include "../common/vehicles/sv_vehicles.qh"
21 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
25 #define IMPULSE(id) _IMPULSE(IMP_##id)
26 #define _IMPULSE(id) \
27 void id##_handle(entity this); \
28 STATIC_INIT_LATE(id) \
30 id.impulse_handle = id##_handle; \
32 void id##_handle(entity this)
37 * 0 reserved (no input)
44 * 143: emergency teleport
45 * 148: unfairly eliminate
48 * 200 to 209: prev weapon shortcuts
49 * 210 to 219: best weapon shortcuts
50 * 220 to 229: next weapon shortcuts
51 * 230 to 253: individual weapons (up to 24)
54 // weapon switching impulses
57 IMPULSE(weapon_group_##i) \
61 this.impulse = IMP_weapon_group_##i.impulse; \
64 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
66 .entity weaponentity = weaponentities[slot]; \
67 W_NextWeaponOnImpulse(this, i, weaponentity); \
68 if(autocvar_g_weaponswitch_debug != 1) \
84 // custom order weapon cycling
87 IMPULSE(weapon_priority_##i##_##dir) \
89 if (this.vehicle) return; \
92 this.impulse = IMP_weapon_priority_##i##_##dir.impulse; \
95 noref int prev = -1; \
97 noref int next = +1; \
98 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
100 .entity weaponentity = weaponentities[slot]; \
101 W_CycleWeapon(this, CS(this).cvar_cl_weaponpriorities[i], dir, weaponentity); \
102 if(autocvar_g_weaponswitch_debug != 1) \
143 IMPULSE(weapon_byid_##i) \
145 if (this.vehicle) return; \
148 this.impulse = IMP_weapon_byid_##i.impulse; \
151 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
153 .entity weaponentity = weaponentities[slot]; \
154 W_SwitchWeapon_TryOthers(this, REGISTRY_GET(Weapons, WEP_FIRST + i), weaponentity); \
155 if(autocvar_g_weaponswitch_debug != 1) \
185 IMPULSE(weapon_next_byid)
187 if (this.vehicle) return;
190 this.impulse = IMP_weapon_next_byid.impulse;
193 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
195 .entity weaponentity = weaponentities[slot];
196 W_NextWeapon(this, 0, weaponentity);
198 if(autocvar_g_weaponswitch_debug != 1)
203 IMPULSE(weapon_prev_byid)
205 if (this.vehicle) return;
208 this.impulse = IMP_weapon_prev_byid.impulse;
211 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
213 .entity weaponentity = weaponentities[slot];
214 W_PreviousWeapon(this, 0, weaponentity);
216 if(autocvar_g_weaponswitch_debug != 1)
221 IMPULSE(weapon_next_bygroup)
223 if (this.vehicle) return;
226 this.impulse = IMP_weapon_next_bygroup.impulse;
229 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
231 .entity weaponentity = weaponentities[slot];
232 W_NextWeapon(this, 1, weaponentity);
234 if(autocvar_g_weaponswitch_debug != 1)
239 IMPULSE(weapon_prev_bygroup)
241 if (this.vehicle) return;
244 this.impulse = IMP_weapon_prev_bygroup.impulse;
247 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
249 .entity weaponentity = weaponentities[slot];
250 W_PreviousWeapon(this, 1, weaponentity);
252 if(autocvar_g_weaponswitch_debug != 1)
257 IMPULSE(weapon_next_bypriority)
259 if (this.vehicle) return;
262 this.impulse = IMP_weapon_next_bypriority.impulse;
265 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
267 .entity weaponentity = weaponentities[slot];
268 W_NextWeapon(this, 2, weaponentity);
270 if(autocvar_g_weaponswitch_debug != 1)
275 IMPULSE(weapon_prev_bypriority)
277 if (this.vehicle) return;
280 this.impulse = IMP_weapon_prev_bypriority.impulse;
283 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
285 .entity weaponentity = weaponentities[slot];
286 W_PreviousWeapon(this, 2, weaponentity);
288 if(autocvar_g_weaponswitch_debug != 1)
295 if (this.vehicle) return;
296 if (IS_DEAD(this)) return;
297 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
299 .entity weaponentity = weaponentities[slot];
300 W_LastWeapon(this, weaponentity);
302 if(autocvar_g_weaponswitch_debug != 1)
309 if (this.vehicle) return;
310 if (IS_DEAD(this)) return;
311 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
313 .entity weaponentity = weaponentities[slot];
314 W_SwitchWeapon(this, w_getbestweapon(this, weaponentity), weaponentity);
316 if(autocvar_g_weaponswitch_debug != 1)
323 if (this.vehicle) return;
324 if (IS_DEAD(this)) return;
325 bool is_dualwielding = W_DualWielding(this);
326 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
328 .entity weaponentity = weaponentities[slot];
329 vector md = this.(weaponentity).movedir;
330 vector vecs = ((md.x > 0) ? md : '0 0 0');
331 vector dv = v_right * -vecs.y;
333 dv = '0 0 0'; // don't override!
334 W_ThrowWeapon(this, weaponentity, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), dv, true);
336 if(autocvar_g_weaponswitch_debug == 2)
337 break; // in this mode, the off-hand weapon is selected based on the primary weapon, don't drop it twice!
341 IMPULSE(weapon_reload)
343 if (this.vehicle) return;
344 if (IS_DEAD(this)) return;
345 if (weaponLocked(this)) return;
347 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
349 .entity weaponentity = weaponentities[slot];
350 Weapon w = this.(weaponentity).m_weapon;
351 w.wr_reload(w, actor, weaponentity);
353 // allow reloading all active slots?
354 //if(autocvar_g_weaponswitch_debug != 1)
359 void ImpulseCommands(entity this)
361 if (game_stopped) return;
363 int imp = CS(this).impulse;
365 CS(this).impulse = 0;
367 if (MinigameImpulse(this, imp)) return;
369 if (timeout_status == TIMEOUT_ACTIVE) return; // don't allow any impulses while the game is paused
371 // allow only weapon change impulses when not in round time
372 if (round_handler_IsActive() && !round_handler_IsRoundStarted())
374 #define X(id) case IMP_##id.impulse:
389 X(weapon_next_bygroup)
390 X(weapon_prev_bygroup)
391 X(weapon_next_bypriority)
392 X(weapon_prev_bypriority)
396 X(weapon_priority_0_prev)
397 X(weapon_priority_1_prev)
398 X(weapon_priority_2_prev)
399 X(weapon_priority_3_prev)
400 X(weapon_priority_4_prev)
401 X(weapon_priority_5_prev)
402 X(weapon_priority_6_prev)
403 X(weapon_priority_7_prev)
404 X(weapon_priority_8_prev)
405 X(weapon_priority_9_prev)
406 X(weapon_priority_0_next)
407 X(weapon_priority_1_next)
408 X(weapon_priority_2_next)
409 X(weapon_priority_3_next)
410 X(weapon_priority_4_next)
411 X(weapon_priority_5_next)
412 X(weapon_priority_6_next)
413 X(weapon_priority_7_next)
414 X(weapon_priority_8_next)
415 X(weapon_priority_9_next)
416 X(weapon_priority_0_best)
417 X(weapon_priority_1_best)
418 X(weapon_priority_2_best)
419 X(weapon_priority_3_best)
420 X(weapon_priority_4_best)
421 X(weapon_priority_5_best)
422 X(weapon_priority_6_best)
423 X(weapon_priority_7_best)
424 X(weapon_priority_8_best)
425 X(weapon_priority_9_best)
456 if (vehicle_impulse(this, imp)) return;
458 if (CheatImpulse(this, imp)) return;
460 FOREACH(IMPULSES, it.impulse == imp, {
461 void(entity) f = it.impulse_handle;
473 IMPULSE(waypoint_personal_here)
475 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.origin, RADARICON_WAYPOINT);
476 if (wp) WaypointSprite_Ping(wp);
477 sprint(this, "personal waypoint spawned at location\n");
480 IMPULSE(waypoint_personal_crosshair)
482 WarpZone_crosshair_trace(this);
483 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, trace_endpos, RADARICON_WAYPOINT);
484 if (wp) WaypointSprite_Ping(wp);
485 sprint(this, "personal waypoint spawned at crosshair\n");
488 IMPULSE(waypoint_personal_death)
490 if (!this.death_origin) return;
491 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.death_origin, RADARICON_WAYPOINT);
492 if (wp) WaypointSprite_Ping(wp);
493 sprint(this, "personal waypoint spawned at death location\n");
496 IMPULSE(waypoint_here_follow)
498 if (!teamplay) return;
499 if (IS_DEAD(this)) return;
500 if (!MUTATOR_CALLHOOK(HelpMePing, this))
502 entity wp = WaypointSprite_Attach(WP_Helpme, this, true, RADARICON_HELPME);
503 if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
504 else WaypointSprite_Ping(wp);
506 sprint(this, "HELP ME attached\n");
509 IMPULSE(waypoint_here_here)
511 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.origin, RADARICON_HERE);
512 if (wp) WaypointSprite_Ping(wp);
513 sprint(this, "HERE spawned at location\n");
516 IMPULSE(waypoint_here_crosshair)
518 WarpZone_crosshair_trace_plusvisibletriggers(this);
519 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
520 if (wp) WaypointSprite_Ping(wp);
521 sprint(this, "HERE spawned at crosshair\n");
524 IMPULSE(waypoint_here_death)
526 if (!this.death_origin) return;
527 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.death_origin, RADARICON_HERE);
528 if (wp) WaypointSprite_Ping(wp);
529 sprint(this, "HERE spawned at death location\n");
532 IMPULSE(waypoint_danger_here)
534 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.origin, RADARICON_DANGER);
535 if (wp) WaypointSprite_Ping(wp);
536 sprint(this, "DANGER spawned at location\n");
539 IMPULSE(waypoint_danger_crosshair)
541 WarpZone_crosshair_trace(this);
542 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, trace_endpos, RADARICON_DANGER);
543 if (wp) WaypointSprite_Ping(wp);
544 sprint(this, "DANGER spawned at crosshair\n");
547 IMPULSE(waypoint_danger_death)
549 if (!this.death_origin) return;
550 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.death_origin, RADARICON_DANGER);
551 if (wp) WaypointSprite_Ping(wp);
552 sprint(this, "DANGER spawned at death location\n");
555 IMPULSE(waypoint_clear_personal)
557 WaypointSprite_ClearPersonal(this);
560 delete(this.personal);
561 this.personal = NULL;
563 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
566 sprint(this, "personal waypoint cleared\n");
569 IMPULSE(waypoint_clear)
571 WaypointSprite_ClearOwned(this);
574 delete(this.personal);
575 this.personal = NULL;
576 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
579 sprint(this, "all waypoints cleared\n");