2 #include "round_handler.qh"
4 #include "weapons/throwing.qh"
5 #include "command/common.qh"
8 #include "clientkill.qh"
10 #include "weapons/selection.qh"
11 #include "weapons/tracing.qh"
12 #include "weapons/weaponsystem.qh"
14 #include <common/gamemodes/_mod.qh>
16 #include <common/state.qh>
18 #include "../common/minigames/sv_minigames.qh"
20 #include <common/weapons/_all.qh>
21 #include "../common/vehicles/sv_vehicles.qh"
23 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
27 #define IMPULSE(id) _IMPULSE(IMP_##id)
28 #define _IMPULSE(id) \
29 void id##_handle(entity this); \
30 STATIC_INIT_LATE(id) \
32 id.impulse_handle = id##_handle; \
34 void id##_handle(entity this)
39 * 0 reserved (no input)
46 * 143: emergency teleport
47 * 148: unfairly eliminate
50 * 200 to 209: prev weapon shortcuts
51 * 210 to 219: best weapon shortcuts
52 * 220 to 229: next weapon shortcuts
53 * 230 to 253: individual weapons (up to 24)
56 // weapon switching impulses
59 IMPULSE(weapon_group_##i) \
63 this.impulse = IMP_weapon_group_##i.impulse; \
66 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
68 .entity weaponentity = weaponentities[slot]; \
69 W_NextWeaponOnImpulse(this, i, weaponentity); \
70 if(autocvar_g_weaponswitch_debug != 1) \
86 // custom order weapon cycling
89 IMPULSE(weapon_priority_##i##_##dir) \
91 if (this.vehicle) return; \
94 this.impulse = IMP_weapon_priority_##i##_##dir.impulse; \
97 noref int prev = -1; \
99 noref int next = +1; \
100 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
102 .entity weaponentity = weaponentities[slot]; \
103 W_CycleWeapon(this, CS(this).cvar_cl_weaponpriorities[i], dir, weaponentity); \
104 if(autocvar_g_weaponswitch_debug != 1) \
145 IMPULSE(weapon_byid_##i) \
147 if (this.vehicle) return; \
150 this.impulse = IMP_weapon_byid_##i.impulse; \
153 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
155 .entity weaponentity = weaponentities[slot]; \
156 W_SwitchWeapon_TryOthers(this, REGISTRY_GET(Weapons, WEP_FIRST + i), weaponentity); \
157 if(autocvar_g_weaponswitch_debug != 1) \
187 IMPULSE(weapon_next_byid)
189 if (this.vehicle) return;
192 this.impulse = IMP_weapon_next_byid.impulse;
195 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
197 .entity weaponentity = weaponentities[slot];
198 W_NextWeapon(this, 0, weaponentity);
200 if(autocvar_g_weaponswitch_debug != 1)
205 IMPULSE(weapon_prev_byid)
207 if (this.vehicle) return;
210 this.impulse = IMP_weapon_prev_byid.impulse;
213 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
215 .entity weaponentity = weaponentities[slot];
216 W_PreviousWeapon(this, 0, weaponentity);
218 if(autocvar_g_weaponswitch_debug != 1)
223 IMPULSE(weapon_next_bygroup)
225 if (this.vehicle) return;
228 this.impulse = IMP_weapon_next_bygroup.impulse;
231 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
233 .entity weaponentity = weaponentities[slot];
234 W_NextWeapon(this, 1, weaponentity);
236 if(autocvar_g_weaponswitch_debug != 1)
241 IMPULSE(weapon_prev_bygroup)
243 if (this.vehicle) return;
246 this.impulse = IMP_weapon_prev_bygroup.impulse;
249 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
251 .entity weaponentity = weaponentities[slot];
252 W_PreviousWeapon(this, 1, weaponentity);
254 if(autocvar_g_weaponswitch_debug != 1)
259 IMPULSE(weapon_next_bypriority)
261 if (this.vehicle) return;
264 this.impulse = IMP_weapon_next_bypriority.impulse;
267 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
269 .entity weaponentity = weaponentities[slot];
270 W_NextWeapon(this, 2, weaponentity);
272 if(autocvar_g_weaponswitch_debug != 1)
277 IMPULSE(weapon_prev_bypriority)
279 if (this.vehicle) return;
282 this.impulse = IMP_weapon_prev_bypriority.impulse;
285 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
287 .entity weaponentity = weaponentities[slot];
288 W_PreviousWeapon(this, 2, weaponentity);
290 if(autocvar_g_weaponswitch_debug != 1)
297 if (this.vehicle) return;
298 if (IS_DEAD(this)) return;
299 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
301 .entity weaponentity = weaponentities[slot];
302 W_LastWeapon(this, weaponentity);
304 if(autocvar_g_weaponswitch_debug != 1)
311 if (this.vehicle) return;
312 if (IS_DEAD(this)) return;
313 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
315 .entity weaponentity = weaponentities[slot];
316 W_SwitchWeapon(this, w_getbestweapon(this, weaponentity), weaponentity);
318 if(autocvar_g_weaponswitch_debug != 1)
325 if (this.vehicle) return;
326 if (IS_DEAD(this)) return;
327 bool is_dualwielding = W_DualWielding(this);
328 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
330 .entity weaponentity = weaponentities[slot];
331 vector md = this.(weaponentity).movedir;
332 vector vecs = ((md.x > 0) ? md : '0 0 0');
333 vector dv = v_right * -vecs.y;
335 dv = '0 0 0'; // don't override!
336 W_ThrowWeapon(this, weaponentity, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), dv, true);
338 if(autocvar_g_weaponswitch_debug == 2)
339 break; // in this mode, the off-hand weapon is selected based on the primary weapon, don't drop it twice!
343 IMPULSE(weapon_reload)
345 if (this.vehicle) return;
346 if (IS_DEAD(this)) return;
347 if (weaponLocked(this)) return;
349 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
351 .entity weaponentity = weaponentities[slot];
352 Weapon w = this.(weaponentity).m_weapon;
353 w.wr_reload(w, actor, weaponentity);
355 // allow reloading all active slots?
356 //if(autocvar_g_weaponswitch_debug != 1)
361 void ImpulseCommands(entity this)
363 if (game_stopped) return;
365 int imp = CS(this).impulse;
367 CS(this).impulse = 0;
369 if (MinigameImpulse(this, imp)) return;
371 if (timeout_status == TIMEOUT_ACTIVE) return; // don't allow any impulses while the game is paused
373 // allow only weapon change impulses when not in round time
374 if (round_handler_IsActive() && !round_handler_IsRoundStarted())
376 #define X(id) case IMP_##id.impulse:
391 X(weapon_next_bygroup)
392 X(weapon_prev_bygroup)
393 X(weapon_next_bypriority)
394 X(weapon_prev_bypriority)
398 X(weapon_priority_0_prev)
399 X(weapon_priority_1_prev)
400 X(weapon_priority_2_prev)
401 X(weapon_priority_3_prev)
402 X(weapon_priority_4_prev)
403 X(weapon_priority_5_prev)
404 X(weapon_priority_6_prev)
405 X(weapon_priority_7_prev)
406 X(weapon_priority_8_prev)
407 X(weapon_priority_9_prev)
408 X(weapon_priority_0_next)
409 X(weapon_priority_1_next)
410 X(weapon_priority_2_next)
411 X(weapon_priority_3_next)
412 X(weapon_priority_4_next)
413 X(weapon_priority_5_next)
414 X(weapon_priority_6_next)
415 X(weapon_priority_7_next)
416 X(weapon_priority_8_next)
417 X(weapon_priority_9_next)
418 X(weapon_priority_0_best)
419 X(weapon_priority_1_best)
420 X(weapon_priority_2_best)
421 X(weapon_priority_3_best)
422 X(weapon_priority_4_best)
423 X(weapon_priority_5_best)
424 X(weapon_priority_6_best)
425 X(weapon_priority_7_best)
426 X(weapon_priority_8_best)
427 X(weapon_priority_9_best)
458 if (vehicle_impulse(this, imp)) return;
460 if (CheatImpulse(this, imp)) return;
462 FOREACH(IMPULSES, it.impulse == imp, {
463 void(entity) f = it.impulse_handle;
475 IMPULSE(waypoint_personal_here)
477 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.origin, RADARICON_WAYPOINT);
478 if (wp) WaypointSprite_Ping(wp);
479 sprint(this, "personal waypoint spawned at location\n");
482 IMPULSE(waypoint_personal_crosshair)
484 WarpZone_crosshair_trace(this);
485 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, trace_endpos, RADARICON_WAYPOINT);
486 if (wp) WaypointSprite_Ping(wp);
487 sprint(this, "personal waypoint spawned at crosshair\n");
490 IMPULSE(waypoint_personal_death)
492 if (!this.death_origin) return;
493 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.death_origin, RADARICON_WAYPOINT);
494 if (wp) WaypointSprite_Ping(wp);
495 sprint(this, "personal waypoint spawned at death location\n");
498 IMPULSE(waypoint_here_follow)
500 if (!teamplay) return;
501 if (IS_DEAD(this)) return;
502 if (!MUTATOR_CALLHOOK(HelpMePing, this))
504 entity wp = WaypointSprite_Attach(WP_Helpme, this, true, RADARICON_HELPME);
505 if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
506 else WaypointSprite_Ping(wp);
508 sprint(this, "HELP ME attached\n");
511 IMPULSE(waypoint_here_here)
513 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.origin, RADARICON_HERE);
514 if (wp) WaypointSprite_Ping(wp);
515 sprint(this, "HERE spawned at location\n");
518 IMPULSE(waypoint_here_crosshair)
520 WarpZone_crosshair_trace_plusvisibletriggers(this);
521 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
522 if (wp) WaypointSprite_Ping(wp);
523 sprint(this, "HERE spawned at crosshair\n");
526 IMPULSE(waypoint_here_death)
528 if (!this.death_origin) return;
529 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.death_origin, RADARICON_HERE);
530 if (wp) WaypointSprite_Ping(wp);
531 sprint(this, "HERE spawned at death location\n");
534 IMPULSE(waypoint_danger_here)
536 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.origin, RADARICON_DANGER);
537 if (wp) WaypointSprite_Ping(wp);
538 sprint(this, "DANGER spawned at location\n");
541 IMPULSE(waypoint_danger_crosshair)
543 WarpZone_crosshair_trace(this);
544 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, trace_endpos, RADARICON_DANGER);
545 if (wp) WaypointSprite_Ping(wp);
546 sprint(this, "DANGER spawned at crosshair\n");
549 IMPULSE(waypoint_danger_death)
551 if (!this.death_origin) return;
552 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.death_origin, RADARICON_DANGER);
553 if (wp) WaypointSprite_Ping(wp);
554 sprint(this, "DANGER spawned at death location\n");
557 IMPULSE(waypoint_clear_personal)
559 WaypointSprite_ClearPersonal(this);
562 delete(this.personal);
563 this.personal = NULL;
565 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
568 sprint(this, "personal waypoint cleared\n");
571 IMPULSE(waypoint_clear)
573 WaypointSprite_ClearOwned(this);
576 delete(this.personal);
577 this.personal = NULL;
578 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
581 sprint(this, "all waypoints cleared\n");