3 #include <common/gamemodes/_mod.qh>
4 #include <common/minigames/sv_minigames.qh>
5 #include <common/mutators/mutator/waypoints/waypointsprites.qh>
6 #include <common/state.qh>
7 #include <common/vehicles/sv_vehicles.qh>
8 #include <common/weapons/_all.qh>
9 #include <server/cheats.qh>
10 #include <server/client.qh>
11 #include <server/clientkill.qh>
12 #include <server/command/common.qh>
13 #include <server/damage.qh>
14 #include <server/mutators/_mod.qh>
15 #include <server/round_handler.qh>
16 #include <server/weapons/selection.qh>
17 #include <server/weapons/throwing.qh>
18 #include <server/weapons/tracing.qh>
19 #include <server/weapons/weaponsystem.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
54 void weapon_group_handle(entity this, int number, int imp)
61 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
63 .entity weaponentity = weaponentities[slot];
64 W_NextWeaponOnImpulse(this, number, weaponentity);
65 if(autocvar_g_weaponswitch_debug != 1)
71 IMPULSE(weapon_group_##i) \
73 weapon_group_handle(this, i, IMP_weapon_group_##i.impulse); \
87 // custom order weapon cycling
89 void weapon_priority_handle(entity this, int dir, int number, int imp)
91 if (this.vehicle) return;
97 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
99 .entity weaponentity = weaponentities[slot];
100 W_CycleWeapon(this, CS(this).cvar_cl_weaponpriorities[number], dir, weaponentity);
101 if(autocvar_g_weaponswitch_debug != 1)
107 IMPULSE(weapon_priority_##i##_##dir) \
109 noref int prev = -1; \
110 noref int best = 0; \
111 noref int next = +1; \
112 weapon_priority_handle(this, dir, i, IMP_weapon_priority_##i##_##dir.impulse); \
150 void weapon_byid_handle(entity this, int number, int imp)
152 if (this.vehicle) return;
158 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
160 .entity weaponentity = weaponentities[slot];
161 W_SwitchWeapon_TryOthers(this, REGISTRY_GET(Weapons, WEP_FIRST + number), weaponentity);
162 if(autocvar_g_weaponswitch_debug != 1)
168 IMPULSE(weapon_byid_##i) \
170 weapon_byid_handle(this, i, IMP_weapon_byid_##i.impulse); \
198 IMPULSE(weapon_next_byid)
200 if (this.vehicle) return;
203 this.impulse = IMP_weapon_next_byid.impulse;
206 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
208 .entity weaponentity = weaponentities[slot];
209 W_NextWeapon(this, 0, weaponentity);
211 if(autocvar_g_weaponswitch_debug != 1)
216 IMPULSE(weapon_prev_byid)
218 if (this.vehicle) return;
221 this.impulse = IMP_weapon_prev_byid.impulse;
224 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
226 .entity weaponentity = weaponentities[slot];
227 W_PreviousWeapon(this, 0, weaponentity);
229 if(autocvar_g_weaponswitch_debug != 1)
234 IMPULSE(weapon_next_bygroup)
236 if (this.vehicle) return;
239 this.impulse = IMP_weapon_next_bygroup.impulse;
242 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
244 .entity weaponentity = weaponentities[slot];
245 W_NextWeapon(this, 1, weaponentity);
247 if(autocvar_g_weaponswitch_debug != 1)
252 IMPULSE(weapon_prev_bygroup)
254 if (this.vehicle) return;
257 this.impulse = IMP_weapon_prev_bygroup.impulse;
260 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
262 .entity weaponentity = weaponentities[slot];
263 W_PreviousWeapon(this, 1, weaponentity);
265 if(autocvar_g_weaponswitch_debug != 1)
270 IMPULSE(weapon_next_bypriority)
272 if (this.vehicle) return;
275 this.impulse = IMP_weapon_next_bypriority.impulse;
278 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
280 .entity weaponentity = weaponentities[slot];
281 W_NextWeapon(this, 2, weaponentity);
283 if(autocvar_g_weaponswitch_debug != 1)
288 IMPULSE(weapon_prev_bypriority)
290 if (this.vehicle) return;
293 this.impulse = IMP_weapon_prev_bypriority.impulse;
296 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
298 .entity weaponentity = weaponentities[slot];
299 W_PreviousWeapon(this, 2, weaponentity);
301 if(autocvar_g_weaponswitch_debug != 1)
308 if (this.vehicle) return;
309 if (IS_DEAD(this)) return;
310 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
312 .entity weaponentity = weaponentities[slot];
313 W_LastWeapon(this, weaponentity);
315 if(autocvar_g_weaponswitch_debug != 1)
322 if (this.vehicle) return;
323 if (IS_DEAD(this)) return;
324 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
326 .entity weaponentity = weaponentities[slot];
327 W_SwitchWeapon(this, w_getbestweapon(this, weaponentity), weaponentity);
329 if(autocvar_g_weaponswitch_debug != 1)
336 if (this.vehicle) return;
337 if (IS_DEAD(this)) return;
338 bool is_dualwielding = W_DualWielding(this);
339 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
341 .entity weaponentity = weaponentities[slot];
342 vector md = this.(weaponentity).movedir;
343 vector vecs = ((md.x > 0) ? md : '0 0 0');
344 vector dv = v_right * -vecs.y;
346 dv = '0 0 0'; // don't override!
347 W_ThrowWeapon(this, weaponentity, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), dv, true);
349 if(autocvar_g_weaponswitch_debug == 2)
350 break; // in this mode, the off-hand weapon is selected based on the primary weapon, don't drop it twice!
354 IMPULSE(weapon_reload)
356 if (this.vehicle) return;
357 if (IS_DEAD(this)) return;
358 if (weaponLocked(this)) return;
360 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
362 .entity weaponentity = weaponentities[slot];
363 Weapon w = this.(weaponentity).m_weapon;
364 w.wr_reload(w, actor, weaponentity);
366 // allow reloading all active slots?
367 //if(autocvar_g_weaponswitch_debug != 1)
372 void ImpulseCommands(entity this)
374 if (game_stopped) return;
376 int imp = CS(this).impulse;
378 CS(this).impulse = 0;
380 if (MinigameImpulse(this, imp)) return;
382 if (timeout_status == TIMEOUT_ACTIVE) return; // don't allow any impulses while the game is paused
384 // allow only weapon change impulses when not in round time
385 if (round_handler_IsActive() && !round_handler_IsRoundStarted())
387 #define X(id) case IMP_##id.impulse:
402 X(weapon_next_bygroup)
403 X(weapon_prev_bygroup)
404 X(weapon_next_bypriority)
405 X(weapon_prev_bypriority)
409 X(weapon_priority_0_prev)
410 X(weapon_priority_1_prev)
411 X(weapon_priority_2_prev)
412 X(weapon_priority_3_prev)
413 X(weapon_priority_4_prev)
414 X(weapon_priority_5_prev)
415 X(weapon_priority_6_prev)
416 X(weapon_priority_7_prev)
417 X(weapon_priority_8_prev)
418 X(weapon_priority_9_prev)
419 X(weapon_priority_0_next)
420 X(weapon_priority_1_next)
421 X(weapon_priority_2_next)
422 X(weapon_priority_3_next)
423 X(weapon_priority_4_next)
424 X(weapon_priority_5_next)
425 X(weapon_priority_6_next)
426 X(weapon_priority_7_next)
427 X(weapon_priority_8_next)
428 X(weapon_priority_9_next)
429 X(weapon_priority_0_best)
430 X(weapon_priority_1_best)
431 X(weapon_priority_2_best)
432 X(weapon_priority_3_best)
433 X(weapon_priority_4_best)
434 X(weapon_priority_5_best)
435 X(weapon_priority_6_best)
436 X(weapon_priority_7_best)
437 X(weapon_priority_8_best)
438 X(weapon_priority_9_best)
469 if (vehicle_impulse(this, imp)) return;
471 if (CheatImpulse(this, imp)) return;
473 FOREACH(IMPULSES, it.impulse == imp, {
474 void(entity) f = it.impulse_handle;
486 IMPULSE(waypoint_personal_here)
488 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.origin, RADARICON_WAYPOINT);
489 if (wp) WaypointSprite_Ping(wp);
490 sprint(this, "personal waypoint spawned at location\n");
493 IMPULSE(waypoint_personal_crosshair)
495 WarpZone_crosshair_trace(this);
496 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, trace_endpos, RADARICON_WAYPOINT);
497 if (wp) WaypointSprite_Ping(wp);
498 sprint(this, "personal waypoint spawned at crosshair\n");
501 IMPULSE(waypoint_personal_death)
503 if (!this.death_origin) return;
504 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.death_origin, RADARICON_WAYPOINT);
505 if (wp) WaypointSprite_Ping(wp);
506 sprint(this, "personal waypoint spawned at death location\n");
509 IMPULSE(waypoint_here_follow)
511 if (!teamplay) return;
512 if (IS_DEAD(this)) return;
513 if (!MUTATOR_CALLHOOK(HelpMePing, this))
515 entity wp = WaypointSprite_Attach(WP_Helpme, this, true, RADARICON_HELPME);
516 if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
517 else WaypointSprite_Ping(wp);
519 sprint(this, "HELP ME attached\n");
522 IMPULSE(waypoint_here_here)
524 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.origin, RADARICON_HERE);
525 if (wp) WaypointSprite_Ping(wp);
526 sprint(this, "HERE spawned at location\n");
529 IMPULSE(waypoint_here_crosshair)
531 WarpZone_crosshair_trace_plusvisibletriggers(this);
532 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
533 if (wp) WaypointSprite_Ping(wp);
534 sprint(this, "HERE spawned at crosshair\n");
537 IMPULSE(waypoint_here_death)
539 if (!this.death_origin) return;
540 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.death_origin, RADARICON_HERE);
541 if (wp) WaypointSprite_Ping(wp);
542 sprint(this, "HERE spawned at death location\n");
545 IMPULSE(waypoint_danger_here)
547 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.origin, RADARICON_DANGER);
548 if (wp) WaypointSprite_Ping(wp);
549 sprint(this, "DANGER spawned at location\n");
552 IMPULSE(waypoint_danger_crosshair)
554 WarpZone_crosshair_trace(this);
555 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, trace_endpos, RADARICON_DANGER);
556 if (wp) WaypointSprite_Ping(wp);
557 sprint(this, "DANGER spawned at crosshair\n");
560 IMPULSE(waypoint_danger_death)
562 if (!this.death_origin) return;
563 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.death_origin, RADARICON_DANGER);
564 if (wp) WaypointSprite_Ping(wp);
565 sprint(this, "DANGER spawned at death location\n");
568 IMPULSE(waypoint_clear_personal)
570 WaypointSprite_ClearPersonal(this);
573 delete(this.personal);
574 this.personal = NULL;
576 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
579 sprint(this, "personal waypoint cleared\n");
582 IMPULSE(waypoint_clear)
584 WaypointSprite_ClearOwned(this);
587 delete(this.personal);
588 this.personal = NULL;
589 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
592 sprint(this, "all waypoints cleared\n");