]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/impulse.qc
Don't make use of impulses to trigger waypoint editor commands
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / impulse.qc
1 #include "impulse.qh"
2 #include "round_handler.qh"
3
4 #include "weapons/throwing.qh"
5 #include "command/common.qh"
6 #include "cheats.qh"
7 #include "weapons/selection.qh"
8 #include "weapons/tracing.qh"
9 #include "weapons/weaponsystem.qh"
10
11 #include <common/state.qh>
12
13 #include "../common/minigames/sv_minigames.qh"
14
15 #include <common/weapons/_all.qh>
16 #include "../common/vehicles/sv_vehicles.qh"
17
18 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
19
20 .entity vehicle;
21
22 #define IMPULSE(id) _IMPULSE(IMP_##id)
23 #define _IMPULSE(id) \
24         void id##_handle(entity this); \
25         STATIC_INIT_LATE(id) \
26         { \
27                 id.impulse_handle = id##_handle; \
28         } \
29         void id##_handle(entity this)
30
31 /**
32  * Impulse map:
33  *
34  * 0 reserved (no input)
35  *
36  * 99: loaded
37  *
38  * 140: moving clone
39  * 141: ctf speedrun
40  * 142: fixed clone
41  * 143: emergency teleport
42  * 148: unfairly eliminate
43  *
44  * TODO:
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)
49  */
50
51 // weapon switching impulses
52
53 #define X(slot) \
54         IMPULSE(weapon_group_##slot) \
55         { \
56                 if (IS_DEAD(this)) \
57                 { \
58                         this.impulse = IMP_weapon_group_##slot.impulse; \
59                         return; \
60                 } \
61                 for(int wepslot = 0; wepslot < MAX_WEAPONSLOTS; ++wepslot) \
62                 { \
63                         .entity weaponentity = weaponentities[wepslot]; \
64                         W_NextWeaponOnImpulse(this, slot, weaponentity); \
65                         if(wepslot == 0 && autocvar_g_weaponswitch_debug != 1) \
66                                 break; \
67                 } \
68         }
69 X(1)
70 X(2)
71 X(3)
72 X(4)
73 X(5)
74 X(6)
75 X(7)
76 X(8)
77 X(9)
78 X(0)
79 #undef X
80
81 // custom order weapon cycling
82
83 #define X(slot, dir) \
84         IMPULSE(weapon_priority_##slot##_##dir) \
85         { \
86                 if (this.vehicle) return; \
87                 if (IS_DEAD(this)) \
88                 { \
89                         this.impulse = IMP_weapon_priority_##slot##_##dir.impulse; \
90                         return; \
91                 } \
92                 noref int prev = -1; \
93                 noref int best =  0; \
94                 noref int next = +1; \
95                 for(int wepslot = 0; wepslot < MAX_WEAPONSLOTS; ++wepslot) \
96                 { \
97                         .entity weaponentity = weaponentities[wepslot]; \
98                         W_CycleWeapon(this, CS(this).cvar_cl_weaponpriorities[slot], dir, weaponentity); \
99                         if(wepslot == 0 && autocvar_g_weaponswitch_debug != 1) \
100                                 break; \
101                 } \
102         }
103 X(0, prev)
104 X(1, prev)
105 X(2, prev)
106 X(3, prev)
107 X(4, prev)
108 X(5, prev)
109 X(6, prev)
110 X(7, prev)
111 X(8, prev)
112 X(9, prev)
113
114 X(0, best)
115 X(1, best)
116 X(2, best)
117 X(3, best)
118 X(4, best)
119 X(5, best)
120 X(6, best)
121 X(7, best)
122 X(8, best)
123 X(9, best)
124
125 X(0, next)
126 X(1, next)
127 X(2, next)
128 X(3, next)
129 X(4, next)
130 X(5, next)
131 X(6, next)
132 X(7, next)
133 X(8, next)
134 X(9, next)
135 #undef X
136
137 // direct weapons
138
139 #define X(i) \
140         IMPULSE(weapon_byid_##i) \
141         { \
142                 if (this.vehicle) return; \
143                 if (IS_DEAD(this)) \
144                 { \
145                         this.impulse = IMP_weapon_byid_##i.impulse; \
146                         return; \
147                 } \
148                 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
149                 { \
150                         .entity weaponentity = weaponentities[slot]; \
151                         W_SwitchWeapon(this, Weapons_from(WEP_FIRST + i), weaponentity); \
152                         if(slot == 0 && autocvar_g_weaponswitch_debug != 1) \
153                                 break; \
154                 } \
155         }
156 X(0)
157 X(1)
158 X(2)
159 X(3)
160 X(4)
161 X(5)
162 X(6)
163 X(7)
164 X(8)
165 X(9)
166 X(10)
167 X(11)
168 X(12)
169 X(13)
170 X(14)
171 X(15)
172 X(16)
173 X(17)
174 X(18)
175 X(19)
176 X(20)
177 X(21)
178 X(22)
179 X(23)
180 #undef X
181
182 IMPULSE(weapon_next_byid)
183 {
184         if (this.vehicle) return;
185         if (IS_DEAD(this))
186         {
187                 this.impulse = IMP_weapon_next_byid.impulse;
188                 return;
189         }
190         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
191         {
192                 .entity weaponentity = weaponentities[slot];
193                 W_NextWeapon(this, 0, weaponentity);
194
195                 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
196                         break;
197         }
198 }
199
200 IMPULSE(weapon_prev_byid)
201 {
202         if (this.vehicle) return;
203         if (IS_DEAD(this))
204         {
205                 this.impulse = IMP_weapon_prev_byid.impulse;
206                 return;
207         }
208         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
209         {
210                 .entity weaponentity = weaponentities[slot];
211                 W_PreviousWeapon(this, 0, weaponentity);
212
213                 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
214                         break;
215         }
216 }
217
218 IMPULSE(weapon_next_bygroup)
219 {
220         if (this.vehicle) return;
221         if (IS_DEAD(this))
222         {
223                 this.impulse = IMP_weapon_next_bygroup.impulse;
224                 return;
225         }
226         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
227         {
228                 .entity weaponentity = weaponentities[slot];
229                 W_NextWeapon(this, 1, weaponentity);
230
231                 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
232                         break;
233         }
234 }
235
236 IMPULSE(weapon_prev_bygroup)
237 {
238         if (this.vehicle) return;
239         if (IS_DEAD(this))
240         {
241                 this.impulse = IMP_weapon_prev_bygroup.impulse;
242                 return;
243         }
244         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
245         {
246                 .entity weaponentity = weaponentities[slot];
247                 W_PreviousWeapon(this, 1, weaponentity);
248
249                 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
250                         break;
251         }
252 }
253
254 IMPULSE(weapon_next_bypriority)
255 {
256         if (this.vehicle) return;
257         if (IS_DEAD(this))
258         {
259                 this.impulse = IMP_weapon_next_bypriority.impulse;
260                 return;
261         }
262         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
263         {
264                 .entity weaponentity = weaponentities[slot];
265                 W_NextWeapon(this, 2, weaponentity);
266
267                 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
268                         break;
269         }
270 }
271
272 IMPULSE(weapon_prev_bypriority)
273 {
274         if (this.vehicle) return;
275         if (IS_DEAD(this))
276         {
277                 this.impulse = IMP_weapon_prev_bypriority.impulse;
278                 return;
279         }
280         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
281         {
282                 .entity weaponentity = weaponentities[slot];
283                 W_PreviousWeapon(this, 2, weaponentity);
284
285                 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
286                         break;
287         }
288 }
289
290 IMPULSE(weapon_last)
291 {
292         if (this.vehicle) return;
293         if (IS_DEAD(this)) return;
294         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
295         {
296                 .entity weaponentity = weaponentities[slot];
297                 W_LastWeapon(this, weaponentity);
298
299                 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
300                         break;
301         }
302 }
303
304 IMPULSE(weapon_best)
305 {
306         if (this.vehicle) return;
307         if (IS_DEAD(this)) return;
308         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
309         {
310                 .entity weaponentity = weaponentities[slot];
311                 W_SwitchWeapon(this, w_getbestweapon(this, weaponentity), weaponentity);
312
313                 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
314                         break;
315         }
316 }
317
318 IMPULSE(weapon_drop)
319 {
320         if (this.vehicle) return;
321         if (IS_DEAD(this)) return;
322         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
323         {
324                 .entity weaponentity = weaponentities[slot];
325                 W_ThrowWeapon(this, weaponentity, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), '0 0 0', true);
326
327                 if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
328                         break;
329         }
330 }
331
332 IMPULSE(weapon_reload)
333 {
334         if (this.vehicle) return;
335         if (IS_DEAD(this)) return;
336         if (forbidWeaponUse(this)) return;
337         entity actor = this;
338         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
339         {
340                 .entity weaponentity = weaponentities[slot];
341                 Weapon w = this.(weaponentity).m_weapon;
342                 w.wr_reload(w, actor, weaponentity);
343
344                 // allow reloading all active slots?
345                 //if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
346                         //break;
347         }
348 }
349
350 void ImpulseCommands(entity this)
351 {
352         if (game_stopped) return;
353
354         int imp = CS(this).impulse;
355         if (!imp) return;
356         CS(this).impulse = 0;
357
358         if (MinigameImpulse(this, imp)) return;
359
360         if (timeout_status == TIMEOUT_ACTIVE) return;  // don't allow any impulses while the game is paused
361
362         // allow only weapon change impulses when not in round time
363         if (round_handler_IsActive() && !round_handler_IsRoundStarted())
364         {
365                 #define X(id) case IMP_##id.impulse:
366                 switch (imp)
367                 {
368                         X(weapon_group_0)
369                         X(weapon_group_1)
370                         X(weapon_group_2)
371                         X(weapon_group_3)
372                         X(weapon_group_4)
373                         X(weapon_group_5)
374                         X(weapon_group_6)
375                         X(weapon_group_7)
376                         X(weapon_group_8)
377                         X(weapon_group_9)
378                         X(weapon_next_byid)
379                         X(weapon_prev_byid)
380                         X(weapon_next_bygroup)
381                         X(weapon_prev_bygroup)
382                         X(weapon_next_bypriority)
383                         X(weapon_prev_bypriority)
384                         X(weapon_last)
385                         X(weapon_best)
386                         X(weapon_reload)
387                         X(weapon_priority_0_prev)
388             X(weapon_priority_1_prev)
389             X(weapon_priority_2_prev)
390             X(weapon_priority_3_prev)
391             X(weapon_priority_4_prev)
392             X(weapon_priority_5_prev)
393             X(weapon_priority_6_prev)
394             X(weapon_priority_7_prev)
395             X(weapon_priority_8_prev)
396             X(weapon_priority_9_prev)
397             X(weapon_priority_0_next)
398                         X(weapon_priority_1_next)
399                         X(weapon_priority_2_next)
400                         X(weapon_priority_3_next)
401                         X(weapon_priority_4_next)
402                         X(weapon_priority_5_next)
403                         X(weapon_priority_6_next)
404                         X(weapon_priority_7_next)
405                         X(weapon_priority_8_next)
406                         X(weapon_priority_9_next)
407                         X(weapon_priority_0_best)
408             X(weapon_priority_1_best)
409             X(weapon_priority_2_best)
410             X(weapon_priority_3_best)
411             X(weapon_priority_4_best)
412             X(weapon_priority_5_best)
413             X(weapon_priority_6_best)
414             X(weapon_priority_7_best)
415             X(weapon_priority_8_best)
416             X(weapon_priority_9_best)
417             X(weapon_byid_0)
418             X(weapon_byid_1)
419             X(weapon_byid_2)
420             X(weapon_byid_3)
421             X(weapon_byid_4)
422             X(weapon_byid_5)
423             X(weapon_byid_6)
424             X(weapon_byid_7)
425             X(weapon_byid_8)
426             X(weapon_byid_9)
427             X(weapon_byid_10)
428             X(weapon_byid_11)
429             X(weapon_byid_12)
430             X(weapon_byid_13)
431             X(weapon_byid_14)
432             X(weapon_byid_15)
433             X(weapon_byid_16)
434             X(weapon_byid_17)
435             X(weapon_byid_18)
436             X(weapon_byid_19)
437             X(weapon_byid_20)
438             X(weapon_byid_21)
439             X(weapon_byid_22)
440             X(weapon_byid_23)
441                         break;
442                         default: return;
443                 }
444 #undef X
445         }
446
447         if (vehicle_impulse(this, imp)) return;
448
449         if (CheatImpulse(this, imp)) return;
450
451         FOREACH(IMPULSES, it.impulse == imp, {
452                 void(entity) f = it.impulse_handle;
453                 if (!f) continue;
454                 f(this);
455                 return;
456         });
457 }
458
459 IMPULSE(use)
460 {
461         PlayerUseKey(this);
462 }
463
464 IMPULSE(waypoint_personal_here)
465 {
466         entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.origin, RADARICON_WAYPOINT);
467         if (wp) WaypointSprite_Ping(wp);
468         sprint(this, "personal waypoint spawned at location\n");
469 }
470
471 IMPULSE(waypoint_personal_crosshair)
472 {
473         WarpZone_crosshair_trace(this);
474         entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, trace_endpos, RADARICON_WAYPOINT);
475         if (wp) WaypointSprite_Ping(wp);
476         sprint(this, "personal waypoint spawned at crosshair\n");
477 }
478
479 IMPULSE(waypoint_personal_death)
480 {
481         if (!this.death_origin) return;
482         entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.death_origin, RADARICON_WAYPOINT);
483         if (wp) WaypointSprite_Ping(wp);
484         sprint(this, "personal waypoint spawned at death location\n");
485 }
486
487 IMPULSE(waypoint_here_follow)
488 {
489         if (!teamplay) return;
490         if (IS_DEAD(this)) return;
491         if (!MUTATOR_CALLHOOK(HelpMePing, this))
492         {
493                 entity wp = WaypointSprite_Attach(WP_Helpme, this, true, RADARICON_HELPME);
494                 if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
495                 else WaypointSprite_Ping(wp);
496         }
497         sprint(this, "HELP ME attached\n");
498 }
499
500 IMPULSE(waypoint_here_here)
501 {
502         entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.origin, RADARICON_HERE);
503         if (wp) WaypointSprite_Ping(wp);
504         sprint(this, "HERE spawned at location\n");
505 }
506
507 IMPULSE(waypoint_here_crosshair)
508 {
509         WarpZone_crosshair_trace(this);
510         entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
511         if (wp) WaypointSprite_Ping(wp);
512         sprint(this, "HERE spawned at crosshair\n");
513 }
514
515 IMPULSE(waypoint_here_death)
516 {
517         if (!this.death_origin) return;
518         entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.death_origin, RADARICON_HERE);
519         if (wp) WaypointSprite_Ping(wp);
520         sprint(this, "HERE spawned at death location\n");
521 }
522
523 IMPULSE(waypoint_danger_here)
524 {
525         entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.origin, RADARICON_DANGER);
526         if (wp) WaypointSprite_Ping(wp);
527         sprint(this, "DANGER spawned at location\n");
528 }
529
530 IMPULSE(waypoint_danger_crosshair)
531 {
532         WarpZone_crosshair_trace(this);
533         entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, trace_endpos, RADARICON_DANGER);
534         if (wp) WaypointSprite_Ping(wp);
535         sprint(this, "DANGER spawned at crosshair\n");
536 }
537
538 IMPULSE(waypoint_danger_death)
539 {
540         if (!this.death_origin) return;
541         entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.death_origin, RADARICON_DANGER);
542         if (wp) WaypointSprite_Ping(wp);
543         sprint(this, "DANGER spawned at death location\n");
544 }
545
546 IMPULSE(waypoint_clear_personal)
547 {
548         WaypointSprite_ClearPersonal(this);
549         if (this.personal)
550         {
551                 delete(this.personal);
552                 this.personal = NULL;
553
554                 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
555                         ClientKill(this);
556         }
557         sprint(this, "personal waypoint cleared\n");
558 }
559
560 IMPULSE(waypoint_clear)
561 {
562         WaypointSprite_ClearOwned(this);
563         if (this.personal)
564         {
565                 delete(this.personal);
566                 this.personal = NULL;
567                 if((g_cts || g_race) && autocvar_g_allow_checkpoints)
568                         ClientKill(this);
569         }
570         sprint(this, "all waypoints cleared\n");
571 }