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
59 void weapon_group_handle(entity this, int number, int imp)
66 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
68 .entity weaponentity = weaponentities[slot];
69 W_NextWeaponOnImpulse(this, number, weaponentity);
70 if(autocvar_g_weaponswitch_debug != 1)
76 IMPULSE(weapon_group_##i) \
78 weapon_group_handle(this, i, IMP_weapon_group_##i.impulse); \
92 // custom order weapon cycling
94 void weapon_priority_handle(entity this, int dir, int number, int imp)
96 if (this.vehicle) return;
102 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
104 .entity weaponentity = weaponentities[slot];
105 W_CycleWeapon(this, CS(this).cvar_cl_weaponpriorities[number], dir, weaponentity);
106 if(autocvar_g_weaponswitch_debug != 1)
112 IMPULSE(weapon_priority_##i##_##dir) \
114 noref int prev = -1; \
115 noref int best = 0; \
116 noref int next = +1; \
117 weapon_priority_handle(this, dir, i, IMP_weapon_priority_##i##_##dir.impulse); \
155 void weapon_byid_handle(entity this, int number, int imp)
157 if (this.vehicle) return;
163 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
165 .entity weaponentity = weaponentities[slot];
166 W_SwitchWeapon_TryOthers(this, REGISTRY_GET(Weapons, WEP_FIRST + number), weaponentity);
167 if(autocvar_g_weaponswitch_debug != 1)
173 IMPULSE(weapon_byid_##i) \
175 weapon_byid_handle(this, i, IMP_weapon_byid_##i.impulse); \
203 IMPULSE(weapon_next_byid)
205 if (this.vehicle) return;
208 this.impulse = IMP_weapon_next_byid.impulse;
211 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
213 .entity weaponentity = weaponentities[slot];
214 W_NextWeapon(this, 0, weaponentity);
216 if(autocvar_g_weaponswitch_debug != 1)
221 IMPULSE(weapon_prev_byid)
223 if (this.vehicle) return;
226 this.impulse = IMP_weapon_prev_byid.impulse;
229 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
231 .entity weaponentity = weaponentities[slot];
232 W_PreviousWeapon(this, 0, weaponentity);
234 if(autocvar_g_weaponswitch_debug != 1)
239 IMPULSE(weapon_next_bygroup)
241 if (this.vehicle) return;
244 this.impulse = IMP_weapon_next_bygroup.impulse;
247 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
249 .entity weaponentity = weaponentities[slot];
250 W_NextWeapon(this, 1, weaponentity);
252 if(autocvar_g_weaponswitch_debug != 1)
257 IMPULSE(weapon_prev_bygroup)
259 if (this.vehicle) return;
262 this.impulse = IMP_weapon_prev_bygroup.impulse;
265 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
267 .entity weaponentity = weaponentities[slot];
268 W_PreviousWeapon(this, 1, weaponentity);
270 if(autocvar_g_weaponswitch_debug != 1)
275 IMPULSE(weapon_next_bypriority)
277 if (this.vehicle) return;
280 this.impulse = IMP_weapon_next_bypriority.impulse;
283 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
285 .entity weaponentity = weaponentities[slot];
286 W_NextWeapon(this, 2, weaponentity);
288 if(autocvar_g_weaponswitch_debug != 1)
293 IMPULSE(weapon_prev_bypriority)
295 if (this.vehicle) return;
298 this.impulse = IMP_weapon_prev_bypriority.impulse;
301 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
303 .entity weaponentity = weaponentities[slot];
304 W_PreviousWeapon(this, 2, weaponentity);
306 if(autocvar_g_weaponswitch_debug != 1)
313 if (this.vehicle) return;
314 if (IS_DEAD(this)) return;
315 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
317 .entity weaponentity = weaponentities[slot];
318 W_LastWeapon(this, weaponentity);
320 if(autocvar_g_weaponswitch_debug != 1)
327 if (this.vehicle) return;
328 if (IS_DEAD(this)) return;
329 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
331 .entity weaponentity = weaponentities[slot];
332 W_SwitchWeapon(this, w_getbestweapon(this, weaponentity), weaponentity);
334 if(autocvar_g_weaponswitch_debug != 1)
341 if (this.vehicle) return;
342 if (IS_DEAD(this)) return;
343 bool is_dualwielding = W_DualWielding(this);
344 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
346 .entity weaponentity = weaponentities[slot];
347 vector md = this.(weaponentity).movedir;
348 vector vecs = ((md.x > 0) ? md : '0 0 0');
349 vector dv = v_right * -vecs.y;
351 dv = '0 0 0'; // don't override!
352 W_ThrowWeapon(this, weaponentity, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), dv, true);
354 if(autocvar_g_weaponswitch_debug == 2)
355 break; // in this mode, the off-hand weapon is selected based on the primary weapon, don't drop it twice!
359 IMPULSE(weapon_reload)
361 if (this.vehicle) return;
362 if (IS_DEAD(this)) return;
363 if (weaponLocked(this)) return;
365 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
367 .entity weaponentity = weaponentities[slot];
368 Weapon w = this.(weaponentity).m_weapon;
369 w.wr_reload(w, actor, weaponentity);
371 // allow reloading all active slots?
372 //if(autocvar_g_weaponswitch_debug != 1)
377 void ImpulseCommands(entity this)
379 if (game_stopped) return;
381 int imp = CS(this).impulse;
383 CS(this).impulse = 0;
385 if (MinigameImpulse(this, imp)) return;
387 if (timeout_status == TIMEOUT_ACTIVE) return; // don't allow any impulses while the game is paused
389 // allow only weapon change impulses when not in round time
390 if (round_handler_IsActive() && !round_handler_IsRoundStarted())
392 #define X(id) case IMP_##id.impulse:
407 X(weapon_next_bygroup)
408 X(weapon_prev_bygroup)
409 X(weapon_next_bypriority)
410 X(weapon_prev_bypriority)
414 X(weapon_priority_0_prev)
415 X(weapon_priority_1_prev)
416 X(weapon_priority_2_prev)
417 X(weapon_priority_3_prev)
418 X(weapon_priority_4_prev)
419 X(weapon_priority_5_prev)
420 X(weapon_priority_6_prev)
421 X(weapon_priority_7_prev)
422 X(weapon_priority_8_prev)
423 X(weapon_priority_9_prev)
424 X(weapon_priority_0_next)
425 X(weapon_priority_1_next)
426 X(weapon_priority_2_next)
427 X(weapon_priority_3_next)
428 X(weapon_priority_4_next)
429 X(weapon_priority_5_next)
430 X(weapon_priority_6_next)
431 X(weapon_priority_7_next)
432 X(weapon_priority_8_next)
433 X(weapon_priority_9_next)
434 X(weapon_priority_0_best)
435 X(weapon_priority_1_best)
436 X(weapon_priority_2_best)
437 X(weapon_priority_3_best)
438 X(weapon_priority_4_best)
439 X(weapon_priority_5_best)
440 X(weapon_priority_6_best)
441 X(weapon_priority_7_best)
442 X(weapon_priority_8_best)
443 X(weapon_priority_9_best)
474 if (vehicle_impulse(this, imp)) return;
476 if (CheatImpulse(this, imp)) return;
478 FOREACH(IMPULSES, it.impulse == imp, {
479 void(entity) f = it.impulse_handle;
491 IMPULSE(waypoint_personal_here)
493 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.origin, RADARICON_WAYPOINT);
494 if (wp) WaypointSprite_Ping(wp);
495 sprint(this, "personal waypoint spawned at location\n");
498 IMPULSE(waypoint_personal_crosshair)
500 WarpZone_crosshair_trace(this);
501 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, trace_endpos, RADARICON_WAYPOINT);
502 if (wp) WaypointSprite_Ping(wp);
503 sprint(this, "personal waypoint spawned at crosshair\n");
506 IMPULSE(waypoint_personal_death)
508 if (!this.death_origin) return;
509 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.death_origin, RADARICON_WAYPOINT);
510 if (wp) WaypointSprite_Ping(wp);
511 sprint(this, "personal waypoint spawned at death location\n");
514 IMPULSE(waypoint_here_follow)
516 if (!teamplay) return;
517 if (IS_DEAD(this)) return;
518 if (!MUTATOR_CALLHOOK(HelpMePing, this))
520 entity wp = WaypointSprite_Attach(WP_Helpme, this, true, RADARICON_HELPME);
521 if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
522 else WaypointSprite_Ping(wp);
524 sprint(this, "HELP ME attached\n");
527 IMPULSE(waypoint_here_here)
529 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.origin, RADARICON_HERE);
530 if (wp) WaypointSprite_Ping(wp);
531 sprint(this, "HERE spawned at location\n");
534 IMPULSE(waypoint_here_crosshair)
536 WarpZone_crosshair_trace_plusvisibletriggers(this);
537 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
538 if (wp) WaypointSprite_Ping(wp);
539 sprint(this, "HERE spawned at crosshair\n");
542 IMPULSE(waypoint_here_death)
544 if (!this.death_origin) return;
545 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.death_origin, RADARICON_HERE);
546 if (wp) WaypointSprite_Ping(wp);
547 sprint(this, "HERE spawned at death location\n");
550 IMPULSE(waypoint_danger_here)
552 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.origin, RADARICON_DANGER);
553 if (wp) WaypointSprite_Ping(wp);
554 sprint(this, "DANGER spawned at location\n");
557 IMPULSE(waypoint_danger_crosshair)
559 WarpZone_crosshair_trace(this);
560 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, trace_endpos, RADARICON_DANGER);
561 if (wp) WaypointSprite_Ping(wp);
562 sprint(this, "DANGER spawned at crosshair\n");
565 IMPULSE(waypoint_danger_death)
567 if (!this.death_origin) return;
568 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.death_origin, RADARICON_DANGER);
569 if (wp) WaypointSprite_Ping(wp);
570 sprint(this, "DANGER spawned at death location\n");
573 IMPULSE(waypoint_clear_personal)
575 WaypointSprite_ClearPersonal(this);
578 delete(this.personal);
579 this.personal = NULL;
581 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
584 sprint(this, "personal waypoint cleared\n");
587 IMPULSE(waypoint_clear)
589 WaypointSprite_ClearOwned(this);
592 delete(this.personal);
593 this.personal = NULL;
594 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
597 sprint(this, "all waypoints cleared\n");