2 #include "round_handler.qh"
4 #include "weapons/throwing.qh"
5 #include "command/common.qh"
8 #include "clientkill.qh"
9 #include "weapons/selection.qh"
10 #include "weapons/tracing.qh"
11 #include "weapons/weaponsystem.qh"
13 #include <common/gamemodes/_mod.qh>
15 #include <common/state.qh>
17 #include "../common/minigames/sv_minigames.qh"
19 #include <common/weapons/_all.qh>
20 #include "../common/vehicles/sv_vehicles.qh"
22 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
26 #define IMPULSE(id) _IMPULSE(IMP_##id)
27 #define _IMPULSE(id) \
28 void id##_handle(entity this); \
29 STATIC_INIT_LATE(id) \
31 id.impulse_handle = id##_handle; \
33 void id##_handle(entity this)
38 * 0 reserved (no input)
45 * 143: emergency teleport
46 * 148: unfairly eliminate
49 * 200 to 209: prev weapon shortcuts
50 * 210 to 219: best weapon shortcuts
51 * 220 to 229: next weapon shortcuts
52 * 230 to 253: individual weapons (up to 24)
55 // weapon switching impulses
58 IMPULSE(weapon_group_##i) \
62 this.impulse = IMP_weapon_group_##i.impulse; \
65 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
67 .entity weaponentity = weaponentities[slot]; \
68 W_NextWeaponOnImpulse(this, i, weaponentity); \
69 if(autocvar_g_weaponswitch_debug != 1) \
85 // custom order weapon cycling
88 IMPULSE(weapon_priority_##i##_##dir) \
90 if (this.vehicle) return; \
93 this.impulse = IMP_weapon_priority_##i##_##dir.impulse; \
96 noref int prev = -1; \
98 noref int next = +1; \
99 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
101 .entity weaponentity = weaponentities[slot]; \
102 W_CycleWeapon(this, CS(this).cvar_cl_weaponpriorities[i], dir, weaponentity); \
103 if(autocvar_g_weaponswitch_debug != 1) \
144 IMPULSE(weapon_byid_##i) \
146 if (this.vehicle) return; \
149 this.impulse = IMP_weapon_byid_##i.impulse; \
152 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
154 .entity weaponentity = weaponentities[slot]; \
155 W_SwitchWeapon_TryOthers(this, REGISTRY_GET(Weapons, WEP_FIRST + i), weaponentity); \
156 if(autocvar_g_weaponswitch_debug != 1) \
186 IMPULSE(weapon_next_byid)
188 if (this.vehicle) return;
191 this.impulse = IMP_weapon_next_byid.impulse;
194 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
196 .entity weaponentity = weaponentities[slot];
197 W_NextWeapon(this, 0, weaponentity);
199 if(autocvar_g_weaponswitch_debug != 1)
204 IMPULSE(weapon_prev_byid)
206 if (this.vehicle) return;
209 this.impulse = IMP_weapon_prev_byid.impulse;
212 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
214 .entity weaponentity = weaponentities[slot];
215 W_PreviousWeapon(this, 0, weaponentity);
217 if(autocvar_g_weaponswitch_debug != 1)
222 IMPULSE(weapon_next_bygroup)
224 if (this.vehicle) return;
227 this.impulse = IMP_weapon_next_bygroup.impulse;
230 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
232 .entity weaponentity = weaponentities[slot];
233 W_NextWeapon(this, 1, weaponentity);
235 if(autocvar_g_weaponswitch_debug != 1)
240 IMPULSE(weapon_prev_bygroup)
242 if (this.vehicle) return;
245 this.impulse = IMP_weapon_prev_bygroup.impulse;
248 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
250 .entity weaponentity = weaponentities[slot];
251 W_PreviousWeapon(this, 1, weaponentity);
253 if(autocvar_g_weaponswitch_debug != 1)
258 IMPULSE(weapon_next_bypriority)
260 if (this.vehicle) return;
263 this.impulse = IMP_weapon_next_bypriority.impulse;
266 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
268 .entity weaponentity = weaponentities[slot];
269 W_NextWeapon(this, 2, weaponentity);
271 if(autocvar_g_weaponswitch_debug != 1)
276 IMPULSE(weapon_prev_bypriority)
278 if (this.vehicle) return;
281 this.impulse = IMP_weapon_prev_bypriority.impulse;
284 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
286 .entity weaponentity = weaponentities[slot];
287 W_PreviousWeapon(this, 2, weaponentity);
289 if(autocvar_g_weaponswitch_debug != 1)
296 if (this.vehicle) return;
297 if (IS_DEAD(this)) return;
298 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
300 .entity weaponentity = weaponentities[slot];
301 W_LastWeapon(this, weaponentity);
303 if(autocvar_g_weaponswitch_debug != 1)
310 if (this.vehicle) return;
311 if (IS_DEAD(this)) return;
312 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
314 .entity weaponentity = weaponentities[slot];
315 W_SwitchWeapon(this, w_getbestweapon(this, weaponentity), weaponentity);
317 if(autocvar_g_weaponswitch_debug != 1)
324 if (this.vehicle) return;
325 if (IS_DEAD(this)) return;
326 bool is_dualwielding = W_DualWielding(this);
327 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
329 .entity weaponentity = weaponentities[slot];
330 vector md = this.(weaponentity).movedir;
331 vector vecs = ((md.x > 0) ? md : '0 0 0');
332 vector dv = v_right * -vecs.y;
334 dv = '0 0 0'; // don't override!
335 W_ThrowWeapon(this, weaponentity, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), dv, true);
337 if(autocvar_g_weaponswitch_debug == 2)
338 break; // in this mode, the off-hand weapon is selected based on the primary weapon, don't drop it twice!
342 IMPULSE(weapon_reload)
344 if (this.vehicle) return;
345 if (IS_DEAD(this)) return;
346 if (weaponLocked(this)) return;
348 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
350 .entity weaponentity = weaponentities[slot];
351 Weapon w = this.(weaponentity).m_weapon;
352 w.wr_reload(w, actor, weaponentity);
354 // allow reloading all active slots?
355 //if(autocvar_g_weaponswitch_debug != 1)
360 void ImpulseCommands(entity this)
362 if (game_stopped) return;
364 int imp = CS(this).impulse;
366 CS(this).impulse = 0;
368 if (MinigameImpulse(this, imp)) return;
370 if (timeout_status == TIMEOUT_ACTIVE) return; // don't allow any impulses while the game is paused
372 // allow only weapon change impulses when not in round time
373 if (round_handler_IsActive() && !round_handler_IsRoundStarted())
375 #define X(id) case IMP_##id.impulse:
390 X(weapon_next_bygroup)
391 X(weapon_prev_bygroup)
392 X(weapon_next_bypriority)
393 X(weapon_prev_bypriority)
397 X(weapon_priority_0_prev)
398 X(weapon_priority_1_prev)
399 X(weapon_priority_2_prev)
400 X(weapon_priority_3_prev)
401 X(weapon_priority_4_prev)
402 X(weapon_priority_5_prev)
403 X(weapon_priority_6_prev)
404 X(weapon_priority_7_prev)
405 X(weapon_priority_8_prev)
406 X(weapon_priority_9_prev)
407 X(weapon_priority_0_next)
408 X(weapon_priority_1_next)
409 X(weapon_priority_2_next)
410 X(weapon_priority_3_next)
411 X(weapon_priority_4_next)
412 X(weapon_priority_5_next)
413 X(weapon_priority_6_next)
414 X(weapon_priority_7_next)
415 X(weapon_priority_8_next)
416 X(weapon_priority_9_next)
417 X(weapon_priority_0_best)
418 X(weapon_priority_1_best)
419 X(weapon_priority_2_best)
420 X(weapon_priority_3_best)
421 X(weapon_priority_4_best)
422 X(weapon_priority_5_best)
423 X(weapon_priority_6_best)
424 X(weapon_priority_7_best)
425 X(weapon_priority_8_best)
426 X(weapon_priority_9_best)
457 if (vehicle_impulse(this, imp)) return;
459 if (CheatImpulse(this, imp)) return;
461 FOREACH(IMPULSES, it.impulse == imp, {
462 void(entity) f = it.impulse_handle;
474 IMPULSE(waypoint_personal_here)
476 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.origin, RADARICON_WAYPOINT);
477 if (wp) WaypointSprite_Ping(wp);
478 sprint(this, "personal waypoint spawned at location\n");
481 IMPULSE(waypoint_personal_crosshair)
483 WarpZone_crosshair_trace(this);
484 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, trace_endpos, RADARICON_WAYPOINT);
485 if (wp) WaypointSprite_Ping(wp);
486 sprint(this, "personal waypoint spawned at crosshair\n");
489 IMPULSE(waypoint_personal_death)
491 if (!this.death_origin) return;
492 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.death_origin, RADARICON_WAYPOINT);
493 if (wp) WaypointSprite_Ping(wp);
494 sprint(this, "personal waypoint spawned at death location\n");
497 IMPULSE(waypoint_here_follow)
499 if (!teamplay) return;
500 if (IS_DEAD(this)) return;
501 if (!MUTATOR_CALLHOOK(HelpMePing, this))
503 entity wp = WaypointSprite_Attach(WP_Helpme, this, true, RADARICON_HELPME);
504 if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
505 else WaypointSprite_Ping(wp);
507 sprint(this, "HELP ME attached\n");
510 IMPULSE(waypoint_here_here)
512 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.origin, RADARICON_HERE);
513 if (wp) WaypointSprite_Ping(wp);
514 sprint(this, "HERE spawned at location\n");
517 IMPULSE(waypoint_here_crosshair)
519 WarpZone_crosshair_trace_plusvisibletriggers(this);
520 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
521 if (wp) WaypointSprite_Ping(wp);
522 sprint(this, "HERE spawned at crosshair\n");
525 IMPULSE(waypoint_here_death)
527 if (!this.death_origin) return;
528 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.death_origin, RADARICON_HERE);
529 if (wp) WaypointSprite_Ping(wp);
530 sprint(this, "HERE spawned at death location\n");
533 IMPULSE(waypoint_danger_here)
535 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.origin, RADARICON_DANGER);
536 if (wp) WaypointSprite_Ping(wp);
537 sprint(this, "DANGER spawned at location\n");
540 IMPULSE(waypoint_danger_crosshair)
542 WarpZone_crosshair_trace(this);
543 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, trace_endpos, RADARICON_DANGER);
544 if (wp) WaypointSprite_Ping(wp);
545 sprint(this, "DANGER spawned at crosshair\n");
548 IMPULSE(waypoint_danger_death)
550 if (!this.death_origin) return;
551 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.death_origin, RADARICON_DANGER);
552 if (wp) WaypointSprite_Ping(wp);
553 sprint(this, "DANGER spawned at death location\n");
556 IMPULSE(waypoint_clear_personal)
558 WaypointSprite_ClearPersonal(this);
561 delete(this.personal);
562 this.personal = NULL;
564 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
567 sprint(this, "personal waypoint cleared\n");
570 IMPULSE(waypoint_clear)
572 WaypointSprite_ClearOwned(this);
575 delete(this.personal);
576 this.personal = NULL;
577 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
580 sprint(this, "all waypoints cleared\n");