1 #include "round_handler.qh"
3 #include "bot/waypoints.qh"
5 #include "weapons/throwing.qh"
6 #include "command/common.qh"
8 #include "bot/navigation.qh"
9 #include "weapons/selection.qh"
10 #include "weapons/tracing.qh"
11 #include "weapons/weaponsystem.qh"
13 #include "../common/minigames/sv_minigames.qh"
15 #include "../common/weapons/all.qh"
16 #include "../common/vehicles/sv_vehicles.qh"
18 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
22 #define IMPULSE(id) _IMPULSE(IMP_##id)
23 #define _IMPULSE(id) \
24 void id##_handle(entity this); \
25 STATIC_INIT_LATE(id) \
27 id.impulse_handle = id##_handle; \
29 void id##_handle(entity this)
34 * 0 reserved (no input)
41 * 143: emergency teleport
42 * 148: unfairly eliminate
45 * 200 to 209: prev weapon shortcuts
46 * 210 to 219: best weapon shortcuts
47 * 220 to 229: next weapon shortcuts
48 * 230 to 253: individual weapons (up to 24)
51 // weapon switching impulses
54 IMPULSE(weapon_group_##slot) \
56 if (this.deadflag != DEAD_NO) return; \
57 W_NextWeaponOnImpulse(slot); \
71 // custom order weapon cycling
73 #define X(slot, dir) \
74 IMPULSE(weapon_priority_##slot##_##dir) \
76 if (this.vehicle) return; \
77 if (this.deadflag != DEAD_NO) return; \
78 noref int prev = -1; \
80 noref int next = +1; \
81 W_CycleWeapon(this.cvar_cl_weaponpriorities[slot], dir); \
120 IMPULSE(weapon_byid_##i) \
122 if (this.vehicle) return; \
123 if (this.deadflag != DEAD_NO) return; \
124 W_SwitchWeapon(Weapons_from(WEP_FIRST + i)); \
152 IMPULSE(weapon_next_byid)
154 if (this.vehicle) return;
155 if (this.deadflag != DEAD_NO) return;
159 IMPULSE(weapon_prev_byid)
161 if (this.vehicle) return;
162 if (this.deadflag != DEAD_NO) return;
166 IMPULSE(weapon_next_bygroup)
168 if (this.vehicle) return;
169 if (this.deadflag != DEAD_NO) return;
173 IMPULSE(weapon_prev_bygroup)
175 if (this.vehicle) return;
176 if (this.deadflag != DEAD_NO) return;
180 IMPULSE(weapon_next_bypriority)
182 if (this.vehicle) return;
183 if (this.deadflag != DEAD_NO) return;
187 IMPULSE(weapon_prev_bypriority)
189 if (this.vehicle) return;
190 if (this.deadflag != DEAD_NO) return;
196 if (this.vehicle) return;
197 if (this.deadflag != DEAD_NO) return;
203 if (this.vehicle) return;
204 if (this.deadflag != DEAD_NO) return;
205 W_SwitchWeapon(w_getbestweapon(this));
210 if (this.vehicle) return;
211 if (this.deadflag != DEAD_NO) return;
212 W_ThrowWeapon(W_CalculateProjectileVelocity(this.velocity, v_forward * 750, false), '0 0 0', true);
215 IMPULSE(weapon_reload)
217 if (this.vehicle) return;
218 if (this.deadflag != DEAD_NO) return;
219 if (forbidWeaponUse(this)) return;
220 Weapon w = Weapons_from(this.weapon);
224 void ImpulseCommands(entity this)
226 if (gameover) return;
228 int imp = this.impulse;
232 if (MinigameImpulse(this, imp)) return;
234 if (timeout_status == TIMEOUT_ACTIVE) return; // don't allow any impulses while the game is paused
236 // allow only weapon change impulses when not in round time
237 if (round_handler_IsActive() && !round_handler_IsRoundStarted())
239 #define X(id) case IMP_##id.impulse:
254 X(weapon_next_bygroup)
255 X(weapon_prev_bygroup)
256 X(weapon_next_bypriority)
257 X(weapon_prev_bypriority)
261 X(weapon_priority_0_prev)
262 X(weapon_priority_1_prev)
263 X(weapon_priority_2_prev)
264 X(weapon_priority_3_prev)
265 X(weapon_priority_4_prev)
266 X(weapon_priority_5_prev)
267 X(weapon_priority_6_prev)
268 X(weapon_priority_7_prev)
269 X(weapon_priority_8_prev)
270 X(weapon_priority_9_prev)
271 X(weapon_priority_0_next)
272 X(weapon_priority_1_next)
273 X(weapon_priority_2_next)
274 X(weapon_priority_3_next)
275 X(weapon_priority_4_next)
276 X(weapon_priority_5_next)
277 X(weapon_priority_6_next)
278 X(weapon_priority_7_next)
279 X(weapon_priority_8_next)
280 X(weapon_priority_9_next)
281 X(weapon_priority_0_best)
282 X(weapon_priority_1_best)
283 X(weapon_priority_2_best)
284 X(weapon_priority_3_best)
285 X(weapon_priority_4_best)
286 X(weapon_priority_5_best)
287 X(weapon_priority_6_best)
288 X(weapon_priority_7_best)
289 X(weapon_priority_8_best)
290 X(weapon_priority_9_best)
321 if (vehicle_impulse(this, imp)) return;
323 if (CheatImpulse(imp)) return;
325 FOREACH(IMPULSES, it.impulse == imp, {
326 void(entity) f = it.impulse_handle;
338 IMPULSE(waypoint_personal_here)
340 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this.origin, RADARICON_WAYPOINT);
341 if (wp) WaypointSprite_Ping(wp);
342 sprint(this, "personal waypoint spawned at location\n");
345 IMPULSE(waypoint_personal_crosshair)
347 WarpZone_crosshair_trace(this);
348 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, trace_endpos, RADARICON_WAYPOINT);
349 if (wp) WaypointSprite_Ping(wp);
350 sprint(this, "personal waypoint spawned at crosshair\n");
353 IMPULSE(waypoint_personal_death)
355 if (!this.death_origin) return;
356 entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this.death_origin, RADARICON_WAYPOINT);
357 if (wp) WaypointSprite_Ping(wp);
358 sprint(this, "personal waypoint spawned at death location\n");
361 IMPULSE(waypoint_here_follow)
363 if (!teamplay) return;
364 if (this.deadflag != DEAD_NO) return;
365 if (!MUTATOR_CALLHOOK(HelpMePing, this))
367 entity wp = WaypointSprite_Attach(WP_Helpme, true, RADARICON_HELPME);
368 if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
369 else WaypointSprite_Ping(wp);
371 sprint(this, "HELP ME attached\n");
374 IMPULSE(waypoint_here_here)
376 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this.origin, RADARICON_HERE);
377 if (wp) WaypointSprite_Ping(wp);
378 sprint(this, "HERE spawned at location\n");
381 IMPULSE(waypoint_here_crosshair)
383 WarpZone_crosshair_trace(this);
384 entity wp = WaypointSprite_DeployFixed(WP_Here, false, trace_endpos, RADARICON_HERE);
385 if (wp) WaypointSprite_Ping(wp);
386 sprint(this, "HERE spawned at crosshair\n");
389 IMPULSE(waypoint_here_death)
391 if (!this.death_origin) return;
392 entity wp = WaypointSprite_DeployFixed(WP_Here, false, this.death_origin, RADARICON_HERE);
393 if (wp) WaypointSprite_Ping(wp);
394 sprint(this, "HERE spawned at death location\n");
397 IMPULSE(waypoint_danger_here)
399 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this.origin, RADARICON_DANGER);
400 if (wp) WaypointSprite_Ping(wp);
401 sprint(this, "DANGER spawned at location\n");
404 IMPULSE(waypoint_danger_crosshair)
406 WarpZone_crosshair_trace(this);
407 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, trace_endpos, RADARICON_DANGER);
408 if (wp) WaypointSprite_Ping(wp);
409 sprint(this, "DANGER spawned at crosshair\n");
412 IMPULSE(waypoint_danger_death)
414 if (!this.death_origin) return;
415 entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this.death_origin, RADARICON_DANGER);
416 if (wp) WaypointSprite_Ping(wp);
417 sprint(this, "DANGER spawned at death location\n");
420 IMPULSE(waypoint_clear_personal)
422 WaypointSprite_ClearPersonal();
425 remove(this.personal);
426 this.personal = NULL;
428 sprint(this, "personal waypoint cleared\n");
431 IMPULSE(waypoint_clear)
433 WaypointSprite_ClearOwned();
436 remove(this.personal);
437 this.personal = NULL;
439 sprint(this, "all waypoints cleared\n");
442 IMPULSE(navwaypoint_spawn)
444 if (!autocvar_g_waypointeditor) return;
445 waypoint_schedulerelink(waypoint_spawn(this.origin, this.origin, 0));
446 bprint(strcat("Waypoint spawned at ", vtos(this.origin), "\n"));
449 IMPULSE(navwaypoint_remove)
451 if (!autocvar_g_waypointeditor) return;
452 entity e = navigation_findnearestwaypoint(this, false);
454 if (e.wpflags & WAYPOINTFLAG_GENERATED) return;
455 bprint(strcat("Waypoint removed at ", vtos(e.origin), "\n"));
459 IMPULSE(navwaypoint_relink)
461 if (!autocvar_g_waypointeditor) return;
462 waypoint_schedulerelinkall();
465 IMPULSE(navwaypoint_save)
467 if (!autocvar_g_waypointeditor) return;
471 IMPULSE(navwaypoint_unreachable)
473 if (!autocvar_g_waypointeditor) return;
474 for (entity e = findchain(classname, "waypoint"); e; e = e.chain)
476 e.colormod = '0.5 0.5 0.5';
477 e.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
479 entity e2 = navigation_findnearestwaypoint(this, false);
480 navigation_markroutes(e2);
486 for (entity e = findchain(classname, "waypoint"); e; e = e.chain)
488 if (e.wpcost < 10000000) continue;
489 LOG_INFO("unreachable: ", etos(e), " ", vtos(e.origin), "\n");
491 e.effects |= EF_NODEPTHTEST | EF_BLUE;
495 if (i) LOG_INFOF("%d waypoints cannot be reached from here in any way (marked with blue light)\n", i);
496 navigation_markroutes_inverted(e2);
499 for (entity e = findchain(classname, "waypoint"); e; e = e.chain)
501 if (e.wpcost < 10000000) continue;
502 LOG_INFO("cannot reach me: ", etos(e), " ", vtos(e.origin), "\n");
504 if (!(e.effects & EF_NODEPTHTEST)) // not already reported before
506 e.effects |= EF_NODEPTHTEST | EF_RED;
509 if (i) LOG_INFOF("%d waypoints cannot walk to here in any way (marked with red light)\n", i);
510 if (m) LOG_INFOF("%d waypoints have been marked total\n", m);
513 for (entity e = findchain(classname, "info_player_deathmatch"); e; e = e.chain)
515 vector org = e.origin;
516 tracebox(e.origin, PL_MIN, PL_MAX, e.origin - '0 0 512', MOVE_NOMONSTERS, world);
517 setorigin(e, trace_endpos);
518 if (navigation_findnearestwaypoint(e, false))
521 e.effects &= ~EF_NODEPTHTEST;
527 LOG_INFO("spawn without waypoint: ", etos(e), " ", vtos(e.origin), "\n");
528 e.effects |= EF_NODEPTHTEST;
529 _setmodel(e, this.model);
530 e.frame = this.frame;
532 e.colormod = '8 0.5 8';
533 setsize(e, '0 0 0', '0 0 0');
537 if (i) LOG_INFOF("%d spawnpoints have no nearest waypoint (marked by player model)\n", i);
540 entity start = findchainflags(flags, FL_ITEM);
541 for (entity e = start; e; e = e.chain)
543 e.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
544 e.colormod = '0.5 0.5 0.5';
546 for (entity e = start; e; e = e.chain)
548 if (navigation_findnearestwaypoint(e, false)) continue;
549 LOG_INFO("item without waypoint: ", etos(e), " ", vtos(e.origin), "\n");
550 e.effects |= EF_NODEPTHTEST | EF_RED;
554 if (i) LOG_INFOF("%d items have no nearest waypoint and cannot be walked away from (marked with red light)\n", i);
557 for (entity e = start; e; e = e.chain)
559 if (navigation_findnearestwaypoint(e, true)) continue;
560 LOG_INFO("item without waypoint: ", etos(e), " ", vtos(e.origin), "\n");
561 e.effects |= EF_NODEPTHTEST | EF_BLUE;
565 if (i) LOG_INFOF("%d items have no nearest waypoint and cannot be walked to (marked with blue light)\n", i);