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/state.qh>
14 #include "../common/minigames/sv_minigames.qh"
16 #include <common/weapons/_all.qh>
17 #include "../common/vehicles/sv_vehicles.qh"
19 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
23 #define IMPULSE(id) _IMPULSE(IMP_##id)
24 #define _IMPULSE(id) \
25 void id##_handle(entity this); \
26 STATIC_INIT_LATE(id) \
28 id.impulse_handle = id##_handle; \
30 void id##_handle(entity this)
35 * 0 reserved (no input)
42 * 143: emergency teleport
43 * 148: unfairly eliminate
46 * 200 to 209: prev weapon shortcuts
47 * 210 to 219: best weapon shortcuts
48 * 220 to 229: next weapon shortcuts
49 * 230 to 253: individual weapons (up to 24)
52 // weapon switching impulses
55 IMPULSE(weapon_group_##slot) \
59 this.impulse = IMP_weapon_group_##slot.impulse; \
62 for(int wepslot = 0; wepslot < MAX_WEAPONSLOTS; ++wepslot) \
64 .entity weaponentity = weaponentities[wepslot]; \
65 W_NextWeaponOnImpulse(this, slot, weaponentity); \
66 if(wepslot == 0 && autocvar_g_weaponswitch_debug != 1) \
82 // custom order weapon cycling
84 #define X(slot, dir) \
85 IMPULSE(weapon_priority_##slot##_##dir) \
87 if (this.vehicle) return; \
90 this.impulse = IMP_weapon_priority_##slot##_##dir.impulse; \
93 noref int prev = -1; \
95 noref int next = +1; \
96 for(int wepslot = 0; wepslot < MAX_WEAPONSLOTS; ++wepslot) \
98 .entity weaponentity = weaponentities[wepslot]; \
99 W_CycleWeapon(this, CS(this).cvar_cl_weaponpriorities[slot], dir, weaponentity); \
100 if(wepslot == 0 && autocvar_g_weaponswitch_debug != 1) \
141 IMPULSE(weapon_byid_##i) \
143 if (this.vehicle) return; \
146 this.impulse = IMP_weapon_byid_##i.impulse; \
149 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
151 .entity weaponentity = weaponentities[slot]; \
152 W_SwitchWeapon(this, Weapons_from(WEP_FIRST + i), weaponentity); \
153 if(slot == 0 && autocvar_g_weaponswitch_debug != 1) \
183 IMPULSE(weapon_next_byid)
185 if (this.vehicle) return;
188 this.impulse = IMP_weapon_next_byid.impulse;
191 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
193 .entity weaponentity = weaponentities[slot];
194 W_NextWeapon(this, 0, weaponentity);
196 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
201 IMPULSE(weapon_prev_byid)
203 if (this.vehicle) return;
206 this.impulse = IMP_weapon_prev_byid.impulse;
209 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
211 .entity weaponentity = weaponentities[slot];
212 W_PreviousWeapon(this, 0, weaponentity);
214 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
219 IMPULSE(weapon_next_bygroup)
221 if (this.vehicle) return;
224 this.impulse = IMP_weapon_next_bygroup.impulse;
227 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
229 .entity weaponentity = weaponentities[slot];
230 W_NextWeapon(this, 1, weaponentity);
232 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
237 IMPULSE(weapon_prev_bygroup)
239 if (this.vehicle) return;
242 this.impulse = IMP_weapon_prev_bygroup.impulse;
245 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
247 .entity weaponentity = weaponentities[slot];
248 W_PreviousWeapon(this, 1, weaponentity);
250 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
255 IMPULSE(weapon_next_bypriority)
257 if (this.vehicle) return;
260 this.impulse = IMP_weapon_next_bypriority.impulse;
263 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
265 .entity weaponentity = weaponentities[slot];
266 W_NextWeapon(this, 2, weaponentity);
268 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
273 IMPULSE(weapon_prev_bypriority)
275 if (this.vehicle) return;
278 this.impulse = IMP_weapon_prev_bypriority.impulse;
281 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
283 .entity weaponentity = weaponentities[slot];
284 W_PreviousWeapon(this, 2, weaponentity);
286 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
293 if (this.vehicle) return;
294 if (IS_DEAD(this)) return;
295 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
297 .entity weaponentity = weaponentities[slot];
298 W_LastWeapon(this, weaponentity);
300 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
307 if (this.vehicle) return;
308 if (IS_DEAD(this)) return;
309 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
311 .entity weaponentity = weaponentities[slot];
312 W_SwitchWeapon(this, w_getbestweapon(this, weaponentity), weaponentity);
314 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
321 if (this.vehicle) return;
322 if (IS_DEAD(this)) return;
323 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
325 .entity weaponentity = weaponentities[slot];
326 W_ThrowWeapon(this, weaponentity, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), '0 0 0', true);
328 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
333 IMPULSE(weapon_reload)
335 if (this.vehicle) return;
336 if (IS_DEAD(this)) return;
337 if (forbidWeaponUse(this)) return;
339 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
341 .entity weaponentity = weaponentities[slot];
342 Weapon w = this.(weaponentity).m_weapon;
343 w.wr_reload(w, actor, weaponentity);
345 // allow reloading all active slots?
346 //if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
351 void ImpulseCommands(entity this)
353 if (game_stopped) return;
355 int imp = CS(this).impulse;
357 CS(this).impulse = 0;
359 if (MinigameImpulse(this, imp)) return;
361 if (timeout_status == TIMEOUT_ACTIVE) return; // don't allow any impulses while the game is paused
363 // allow only weapon change impulses when not in round time
364 if (round_handler_IsActive() && !round_handler_IsRoundStarted())
366 #define X(id) case IMP_##id.impulse:
381 X(weapon_next_bygroup)
382 X(weapon_prev_bygroup)
383 X(weapon_next_bypriority)
384 X(weapon_prev_bypriority)
388 X(weapon_priority_0_prev)
389 X(weapon_priority_1_prev)
390 X(weapon_priority_2_prev)
391 X(weapon_priority_3_prev)
392 X(weapon_priority_4_prev)
393 X(weapon_priority_5_prev)
394 X(weapon_priority_6_prev)
395 X(weapon_priority_7_prev)
396 X(weapon_priority_8_prev)
397 X(weapon_priority_9_prev)
398 X(weapon_priority_0_next)
399 X(weapon_priority_1_next)
400 X(weapon_priority_2_next)
401 X(weapon_priority_3_next)
402 X(weapon_priority_4_next)
403 X(weapon_priority_5_next)
404 X(weapon_priority_6_next)
405 X(weapon_priority_7_next)
406 X(weapon_priority_8_next)
407 X(weapon_priority_9_next)
408 X(weapon_priority_0_best)
409 X(weapon_priority_1_best)
410 X(weapon_priority_2_best)
411 X(weapon_priority_3_best)
412 X(weapon_priority_4_best)
413 X(weapon_priority_5_best)
414 X(weapon_priority_6_best)
415 X(weapon_priority_7_best)
416 X(weapon_priority_8_best)
417 X(weapon_priority_9_best)
448 if (vehicle_impulse(this, imp)) return;
450 if (CheatImpulse(this, imp)) return;
452 FOREACH(IMPULSES, it.impulse == imp, {
453 void(entity) f = it.impulse_handle;
465 IMPULSE(waypoint_personal_here)
467 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.origin, RADARICON_WAYPOINT);
468 if (wp) WaypointSprite_Ping(wp);
469 sprint(this, "personal waypoint spawned at location\n");
472 IMPULSE(waypoint_personal_crosshair)
474 WarpZone_crosshair_trace(this);
475 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, trace_endpos, RADARICON_WAYPOINT);
476 if (wp) WaypointSprite_Ping(wp);
477 sprint(this, "personal waypoint spawned at crosshair\n");
480 IMPULSE(waypoint_personal_death)
482 if (!this.death_origin) return;
483 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.death_origin, RADARICON_WAYPOINT);
484 if (wp) WaypointSprite_Ping(wp);
485 sprint(this, "personal waypoint spawned at death location\n");
488 IMPULSE(waypoint_here_follow)
490 if (!teamplay) return;
491 if (IS_DEAD(this)) return;
492 if (!MUTATOR_CALLHOOK(HelpMePing, this))
494 entity wp = WaypointSprite_Attach(WP_Helpme, this, true, RADARICON_HELPME);
495 if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
496 else WaypointSprite_Ping(wp);
498 sprint(this, "HELP ME attached\n");
501 IMPULSE(waypoint_here_here)
503 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.origin, RADARICON_HERE);
504 if (wp) WaypointSprite_Ping(wp);
505 sprint(this, "HERE spawned at location\n");
508 IMPULSE(waypoint_here_crosshair)
510 WarpZone_crosshair_trace(this);
511 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
512 if (wp) WaypointSprite_Ping(wp);
513 sprint(this, "HERE spawned at crosshair\n");
516 IMPULSE(waypoint_here_death)
518 if (!this.death_origin) return;
519 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.death_origin, RADARICON_HERE);
520 if (wp) WaypointSprite_Ping(wp);
521 sprint(this, "HERE spawned at death location\n");
524 IMPULSE(waypoint_danger_here)
526 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.origin, RADARICON_DANGER);
527 if (wp) WaypointSprite_Ping(wp);
528 sprint(this, "DANGER spawned at location\n");
531 IMPULSE(waypoint_danger_crosshair)
533 WarpZone_crosshair_trace(this);
534 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, trace_endpos, RADARICON_DANGER);
535 if (wp) WaypointSprite_Ping(wp);
536 sprint(this, "DANGER spawned at crosshair\n");
539 IMPULSE(waypoint_danger_death)
541 if (!this.death_origin) return;
542 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.death_origin, RADARICON_DANGER);
543 if (wp) WaypointSprite_Ping(wp);
544 sprint(this, "DANGER spawned at death location\n");
547 IMPULSE(waypoint_clear_personal)
549 WaypointSprite_ClearPersonal(this);
552 delete(this.personal);
553 this.personal = NULL;
555 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
558 sprint(this, "personal waypoint cleared\n");
561 IMPULSE(waypoint_clear)
563 WaypointSprite_ClearOwned(this);
566 delete(this.personal);
567 this.personal = NULL;
568 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
571 sprint(this, "all waypoints cleared\n");