22{
23 static float hud_lasttime = 0;
24
25
27 {
31 {
33 return;
34 }
35 }
36
38
41 else
43
45
47 {
50 }
51
54
56 {
58 return;
59 }
60
61
62
63 int keys =
STAT(PRESSED_KEYS);
65
66
68
69
70 bool real_onslick = false;
71
72
73 bool onground = real_onground && !jumpheld;
74 bool onslick = real_onslick;
75
76
79
80 static float onground_lasttime = 0;
81 static bool onslick_last = false;
82 if (onground)
83 {
85
86 onground_lasttime =
time;
87 onslick_last = onslick;
88 }
89 else if (jumpheld || swimming)
90 onground_lasttime = 0;
91
92 bool onground_expired;
93 if (onground_lasttime == 0)
94 onground_expired = true;
95 else
97
98
104
105 if (!onground && !onground_expired)
106 {
107 onground = true;
108 onslick = onslick_last;
109
111 {
114 }
115 }
116 else if (onslick)
117 {
120 }
121
122
124
125 float movespeed;
126 if (is_local)
127 {
129
130
131 if (movespeed == 0)
132 movespeed = maxspeed;
133 }
134 else
135 {
136
137
138
139 movespeed = maxspeed;
140 }
141
142
145 float absolute_wishangle =
fabs(wishangle);
146 bool strafekeys =
fabs(wishangle) > 45;
147
148
149 static bool turn = false;
150 float strafity = 0;
152 turn = false;
153 else
154 {
155 static float turn_lasttime = 0;
156 static float turnangle;
158
159 if (strafekeys)
160 turn = true;
161 else if (turn_expired)
162 turn = false;
163
164 if (turn)
165 {
166 if (strafekeys)
167 {
168 turn_lasttime =
time;
169 turnangle = wishangle;
170 }
171 else
172 wishangle = turnangle;
173
174
175 strafity = 1 - (90 -
fabs(wishangle)) / 45;
176
179
180 movespeed =
min(movespeed, maxspeed);
181
184 }
185 }
186
188
189 maxaccel *= dt * movespeed;
190 float bestspeed =
max(movespeed - maxaccel, 0);
191
192
194
196 bool moving =
speed > 0;
197
198 float frictionspeed;
199 float strafespeed;
200
201 if (moving && onground)
202 {
204
205 if (strafefriction > 0)
206 {
208
209
211
212
213
214 {
215 float independent_geometric = (1 - strafefriction * dt_r) ** (dt / dt_r);
216 if (S <
speed &&
speed < S / independent_geometric)
217 strafespeed = S - S * strafefriction * (dt - (dt_r *
log(S /
speed)) /
log(1 - strafefriction * dt_r));
219 strafespeed =
speed * independent_geometric;
220 else
221 strafespeed =
speed - strafefriction * dt * S;
222 strafespeed =
max(0, strafespeed);
223 }
224 }
225 else
227 frictionspeed =
speed - strafespeed;
228 }
229 else
230 {
231 frictionspeed = 0;
233 }
234
235
237 bool fwd;
238
240 {
241 if (moving)
242 {
243
245 if (vel_angle > 180)
246 vel_angle -= 360;
248
249
250 angle = vel_angle - view_angle;
251
252
255 else if (
angle < -180)
257
258
259
260 if (
fabs(wishangle) != 90)
261 {
263 fwd = true;
265 fwd = false;
266 else
268 }
269
270 else
271 {
272 if (wishangle < 0)
273 fwd =
angle <= -wishangle;
274 else
275 fwd =
angle >= -wishangle;
276 }
277
278
279 if (!fwd)
280 {
283 else
285 }
286 }
287 else
288 {
290 fwd = true;
291 }
292 }
293 else
294 {
295 const float demo_maxangle = 55;
296 const float demo_turnspeed = 40;
297 static float demo_position = -37 / demo_maxangle;
298
300 {
301 float demo_dt =
time - hud_lasttime;
302 float demo_step = (demo_turnspeed / demo_maxangle) * demo_dt;
303 demo_position = ((demo_position + demo_step) % 4 + 4) % 4;
304 }
305
306
307 if (demo_position > 3)
308 angle = -1 + (demo_position - 3);
309 else if (demo_position > 1)
310 angle = +1 - (demo_position - 1);
311 else
312 angle = demo_position;
313 angle *= demo_maxangle;
314
315 fwd = true;
316 wishangle = 45;
318 wishangle *= -1;
319 }
320
321
322 if (!fwd)
323 wishangle *= -1;
324
325
327 {
329 wishangle *= -1;
330 }
331
333 if (airstopaccel == 0 || turn)
334 airstopaccel = 1;
335
336
337
338 float bestangle;
339 float prebestangle;
340 float overturnangle;
341 if (!moving)
342 {
343
344 prebestangle = bestangle = 0;
345 overturnangle = 180;
346 }
348 {
349
350 {
351
352 bestangle = strafespeed > bestspeed
353 ? acos(bestspeed / strafespeed) *
RAD2DEG
354 : 0;
355
356 }
357 {
358
359
360 float prebestangle_sqrt = movespeed * movespeed + strafespeed * strafespeed -
speed *
speed;
361
362 prebestangle = (prebestangle_sqrt > 0 && strafespeed >
sqrt(prebestangle_sqrt))
363 ? acos(
sqrt(prebestangle_sqrt) / strafespeed) *
RAD2DEG
364 : (prebestangle_sqrt > 0 ? 0 : 90);
365
366 }
367 {
368 float overturn_numer =
speed *
speed - strafespeed * strafespeed - maxaccel * maxaccel;
369 float overturn_denom = 2 * maxaccel * strafespeed;
370
371 overturnangle = overturn_denom >
fabs(overturn_numer)
372 ? acos(overturn_numer / overturn_denom) *
RAD2DEG
373 : (overturn_numer < 0 ? 180 : 0);
374
375 }
376 if (overturnangle < bestangle || bestangle < prebestangle)
377 {
378
380 {
381
382
383 prebestangle = bestangle = 0;
384 overturnangle = 0;
385 }
387 {
388
389
390
391
392
393
394
395 overturnangle = bestangle;
396 prebestangle = bestangle;
397 }
398 else
399 {
400
401
405 ? acos(-(airstopaccel * maxaccel * 0.5) /
speed) *
RAD2DEG
406 : acos(-maxaccel / (2 *
speed - (airstopaccel - 1) * maxaccel)) *
RAD2DEG;
407 }
408 }
409 }
410 else
411 {
412
413 bestangle =
speed > bestspeed
415 : 0;
416 prebestangle =
speed > movespeed
418 : 0;
419
420
421 overturnangle =
speed > airstopaccel * maxaccel * 0.5
423 ? acos(-(airstopaccel * maxaccel * 0.5) /
speed) *
RAD2DEG
424 : acos(-maxaccel / (2 *
speed - (airstopaccel - 1) * maxaccel)) *
RAD2DEG)
425 : 180;
426 }
427
428 float absolute_bestangle = bestangle;
429 float absolute_prebestangle = prebestangle;
430 float absolute_overturnangle = overturnangle;
431
436 bool is_aircontrol_direction = fwd || (aircontrol_flags &
BIT(0));
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454 bool wturning = (wishangle == 0) && !onground && is_aircontrol_keys;
455 bool wturn_valid = false;
456 float wturn_bestangle = 0;
460 {
462 if (wturn_power == 2)
463 {
464 float wturn_a = 32 *
fabs(aircontrol) * dt;
465 if (aircontrol_flags &
BIT(2))
466 wturn_a *= maxspeed / maxspeed_phys;
467 float wturn_V = 1 - (wturn_a * wturn_a) / (
speed *
speed);
469 wturn_bestangle = acos(-
speed / wturn_a * (
cos((acos(wturn_V) +
M_PI * 2) / 3) * 2 + 1)) *
RAD2DEG;
470 else
472 wturn_valid = true;
473 }
475 {
476 wturn_bestangle = acos(
sqrt(wturn_power / (wturn_power + 1))) *
RAD2DEG;
477 wturn_valid = true;
478 }
479 }
480 float absolute_wturn_bestangle = wturn_bestangle;
481
482
483 float n_bestangle = 0;
484 float absolute_n_prebestangle = 0;
487 if (draw_normal || wturn_valid)
488 {
489
491 float n_movespeed = n_maxspeed;
493 float n_bestspeed =
max(n_movespeed - n_maxaccel, 0);
494 n_bestangle =
speed > n_bestspeed
496 : -45;
497 absolute_n_prebestangle =
speed > n_movespeed
499 : 0;
500 }
501
503
506
508 {
509 n_bestangle *= -1;
510 bestangle *= -1;
511 prebestangle *= -1;
512 overturnangle *= -1;
513 }
514 float opposite_bestangle = -bestangle;
515 float n_opposite_bestangle = -n_bestangle;
516
517 bestangle -= wishangle;
518 opposite_bestangle -= wishangle;
519 n_opposite_bestangle -= wishangle;
520 prebestangle -= wishangle;
521 overturnangle -= wishangle;
522
523 int mode;
526 else
528
529
530 float changeangle = -bestangle;
531 float n_changeangle = -n_bestangle;
532 float n_opposite_changeangle = n_opposite_bestangle + n_bestangle * 2;
533
534
536 if (minspeed < 0)
537 minspeed = bestspeed + frictionspeed;
538
539 bool opposite_direction = false;
540 float opposite_changeangle = 0;
543 {
544 opposite_direction = true;
545 opposite_changeangle = opposite_bestangle + bestangle * 2;
546 }
547
548
549 float wturn_left_bestangle = wturn_bestangle;
550 float wturn_right_bestangle = -wturn_bestangle;
551
552
553 float shiftangle = 0;
555 {
557 bestangle += shiftangle;
558 changeangle += shiftangle;
559 opposite_bestangle += shiftangle;
560 opposite_changeangle += shiftangle;
561 n_bestangle += shiftangle;
562 n_changeangle += shiftangle;
563 n_opposite_bestangle += shiftangle;
564 n_opposite_changeangle += shiftangle;
565 wturn_left_bestangle += shiftangle;
566 wturn_right_bestangle += shiftangle;
567 }
568
569 StrafeHUD_DrawStrafeMeter(shiftangle, wishangle, absolute_bestangle, absolute_prebestangle, absolute_overturnangle, moving, hudangle);
570
571 float text_offset_top;
572 float text_offset_bottom;
575
578
579
581 float strafe_ratio = 0;
582 if (moving)
583 {
584 float moveangle =
fabs(
angle + wishangle);
585 if (moveangle > 180) moveangle = 360 - moveangle;
586
587
588 if (moveangle >= absolute_overturnangle)
589 {
590 if (moveangle == absolute_overturnangle && absolute_overturnangle == 180)
591 {}
592 else
593 {
595 strafe_ratio = (moveangle - absolute_overturnangle) / (180 - absolute_overturnangle);
596
597 strafe_ratio *= -1;
598 }
599 }
600
601 else if (moveangle >= absolute_bestangle)
602 {
604 strafe_ratio = (absolute_overturnangle - moveangle) / (absolute_overturnangle - absolute_bestangle);
605
606 }
607 else if (moveangle >= absolute_prebestangle)
608 {
611 strafe_ratio = (moveangle - absolute_prebestangle) / (absolute_bestangle - absolute_prebestangle);
612 }
613
617 currentangle_color,
fabs(strafe_ratio));
618 }
619
620 float currentangle = 0;
622 {
623
624 if (
fabs(
angle) <= 180 - antiflicker_angle)
625 currentangle =
angle;
626 }
627
628 float max_line_height = 0;
629 float max_top_arrow_size = 0;
630 float max_bottom_arrow_size = 0;
631
632
634 {
635
639 indicator_size.z = 0;
640
644
645
647
648 if (num_dashes > 0)
649 max_line_height =
max(max_line_height, indicator_size.y);
650 if (has_top_arrow)
651 max_top_arrow_size =
max(max_top_arrow_size, arrow_size);
652 if (has_bottom_arrow)
653 max_bottom_arrow_size =
max(max_bottom_arrow_size, arrow_size);
654
655
656 float current_changeangle = draw_normal
657 ? (opposite_direction ? n_opposite_changeangle : n_changeangle)
658 : (opposite_direction ? opposite_changeangle : changeangle);
659 float opposite_changeangle = draw_normal
660 ? (opposite_direction ? n_opposite_bestangle : n_bestangle)
661 : (opposite_direction ? opposite_bestangle : bestangle);
662
664 current_changeangle, indicator_size, arrow_size, num_dashes,
667
670 opposite_changeangle, indicator_size, arrow_size, num_dashes,
673 }
674
677 {
678
682 indicator_size.z = 0;
683
687
688
690
691 if (num_dashes > 0)
692 max_line_height =
max(max_line_height, indicator_size.y);
693 if (has_top_arrow)
694 max_top_arrow_size =
max(max_top_arrow_size, arrow_size);
695 if (has_bottom_arrow)
696 max_bottom_arrow_size =
max(max_bottom_arrow_size, arrow_size);
697
698 float ghostangle = opposite_direction ? opposite_bestangle : bestangle;
699
701 ghostangle, indicator_size, arrow_size, num_dashes,
704 }
705
706
707 if (wturn_valid && !onground && is_aircontrol_direction
709 && absolute_wturn_bestangle < absolute_n_prebestangle
713 {
714
718 indicator_size.z = 0;
719
723
724
726
727 if (num_dashes > 0)
728 max_line_height =
max(max_line_height, indicator_size.y);
729 if (has_top_arrow)
730 max_top_arrow_size =
max(max_top_arrow_size, arrow_size);
731 if (has_bottom_arrow)
732 max_bottom_arrow_size =
max(max_bottom_arrow_size, arrow_size);
733
734
736 wturn_left_bestangle, indicator_size, arrow_size, num_dashes,
740 wturn_right_bestangle, indicator_size, arrow_size, num_dashes,
743 }
744
746 {
747
751 indicator_size.z = 0;
752
756
757
759
760 if (num_dashes > 0)
761 max_line_height =
max(max_line_height, indicator_size.y);
762 if (has_top_arrow)
763 max_top_arrow_size =
max(max_top_arrow_size, arrow_size);
764 if (has_bottom_arrow)
765 max_bottom_arrow_size =
max(max_bottom_arrow_size, arrow_size);
766
768 currentangle, indicator_size, arrow_size, num_dashes,
769 has_top_arrow, has_bottom_arrow, currentangle_color,
771 }
772
773
774 {
775 float line_height_offset = max_line_height;
776
777
778 line_height_offset = (line_height_offset -
panel_size.y) / 2;
779
780
781 float angle_offset_top;
782 angle_offset_top = line_height_offset + max_top_arrow_size;
783
784
785 float angle_offset_bottom;
786 angle_offset_bottom = line_height_offset + max_bottom_arrow_size;
787
788
789 text_offset_top =
max(angle_offset_top, text_offset_top);
790 text_offset_bottom =
max(angle_offset_bottom, text_offset_bottom);
791 }
792
794
800
802
804}
#define MUTATOR_CALLHOOK(id,...)
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define draw_beginBoldFont()
#define draw_endBoldFont()
bool StrafeHUD_IsGradient(int style)
entity StrafeHUD_GetStrafeplayer(bool is_local)
float StrafeHUD_DetermineDirection(float angle, float wishangle, float antiflicker_angle)
bool StrafeHUD_DetermineOnSlick(entity e)
float StrafeHUD_DetermineWishAngle(vector movement, int keys, bool is_local)
int StrafeHUD_DetermineForwardKeys(vector movement, int keys, bool is_local)
float StrafeHUD_DetermineFrameTime()
bool StrafeHUD_DetermineJumpHeld(entity e, int keys, bool is_local)
float StrafeHUD_DetermineWaterLevel(entity e)
bool StrafeHUD_DetermineOnGround(entity e, bool is_local)
float StrafeHUD_DetermineHudAngle(float absolute_wishangle, float absolute_overturnangle, float strafity)
vector StrafeHUD_MixColors(vector color1, vector color2, float ratio)
int spectatee_status
the -1 disables HUD panels before CSQC receives necessary data
float GeomLerp(float a, float _lerp, float b)
#define PHYS_FRICTION_SLICK(s)
#define PHYS_MAXAIRSTRAFESPEED(s)
#define PHYS_AIRCONTROL_PENALTY(s)
#define PHYS_AIRACCELERATE(s)
#define PHYS_STOPSPEED(s)
#define PHYS_MAXAIRSPEED(s)
#define PHYS_INPUT_ANGLES(s)
#define PHYS_AIRACCEL_QW(s)
#define PHYS_AIRSTRAFEACCELERATE(s)
#define PHYS_SLICKACCELERATE(s)
#define PHYS_ACCELERATE(s)
#define PHYS_AIRSTOPACCELERATE_FULL(s)
#define PHYS_FRICTION_REPLICA_DT
#define PHYS_AIRCONTROL_FLAGS(s)
#define PHYS_AIRSTOPACCELERATE(s)
#define PHYS_AIRCONTROL_POWER(s)
#define PHYS_AIRCONTROL(s)
#define PHYS_INPUT_MOVEVALUES(s)
void StrafeHUD_DrawStrafeMeter(float shiftangle, float wishangle, float absolute_bestangle, float absolute_prebestangle, float absolute_overturnangle, bool moving, float hudangle)
void StrafeHUD_DrawDirectionIndicator(int direction, bool opposite_direction, bool fwd)
void StrafeHUD_DrawAngleIndicator(float angle, vector line_size, float arrow_size, int num_dashes, bool has_top_arrow, bool has_bottom_arrow, vector color, float alpha, float hudangle)
void HUD_Panel_LoadCvars()
#define HUD_Panel_DrawBg()
bool autocvar__hud_configure
const int WATERLEVEL_SWIMMING
const int STRAFEHUD_WTURN_SIDESTRAFE
vector autocvar_hud_panel_strafehud_wturn_color
int autocvar_hud_panel_strafehud_wturn
float autocvar_hud_panel_strafehud_wturn_line_height
int autocvar_hud_panel_strafehud_onground_mode
int autocvar_hud_panel_strafehud
float autocvar_hud_panel_strafehud_timeout_turn
vector autocvar_hud_panel_strafehud_angle_preaccel_color
float autocvar_hud_panel_strafehud_switch_alpha
int autocvar_hud_panel_strafehud_switch_arrow
const int STRAFEHUD_DIRECTION_RIGHT
bool autocvar__hud_panel_strafehud_demo
bool autocvar_hud_panel_strafehud_onground_friction
float autocvar_hud_panel_strafehud_bestangle_line_width
int autocvar_hud_panel_strafehud_bestangle_arrow
float autocvar_hud_panel_strafehud_angle_alpha
bool autocvar_hud_panel_strafehud_dynamichud
float autocvar_hud_panel_strafehud_switch_line_height
float autocvar_hud_panel_strafehud_wturn_line_width
const int STRAFEHUD_KEYS_FORWARD
const int STRAFEHUD_MODE_VELOCITY_CENTERED
float autocvar_hud_panel_strafehud_angle_line_height
int autocvar_hud_panel_strafehud_switch_line
float autocvar_hud_panel_strafehud_bestangle_line_height
float autocvar_hud_panel_strafehud_antiflicker_angle
const int STRAFEHUD_SWITCH_SIDESTRAFE
const int STRAFEHUD_ONGROUND_OVERTURN
int autocvar_hud_panel_strafehud_wturn_line
const int STRAFEHUD_SWITCH_NORMAL
const int STRAFEHUD_MODE_VIEW_CENTERED
vector autocvar_hud_panel_strafehud_switch_color
const int STRAFEHUD_WTURN_NORMAL
int autocvar_hud_panel_strafehud_mode
float autocvar_hud_panel_strafehud_angle_line_width
float autocvar_hud_panel_strafehud_wturn_arrow_size
const int STRAFEHUD_KEYS_BACKWARD
float autocvar_hud_panel_strafehud_bestangle_arrow_size
int autocvar_hud_panel_strafehud_bestangle_line
vector autocvar_hud_panel_strafehud_bestangle_color
float autocvar_hud_panel_strafehud_switch_arrow_size
int autocvar_hud_panel_strafehud_switch
int autocvar_hud_panel_strafehud_angle_line
bool autocvar_hud_panel_strafehud_wturn_proper
float autocvar_hud_panel_strafehud_bestangle_alpha
vector autocvar_hud_panel_strafehud_angle_neutral_color
int autocvar_hud_panel_strafehud_wturn_arrow
float autocvar_hud_panel_strafehud_wturn_alpha
int autocvar_hud_panel_strafehud_style
const int STRAFEHUD_ONGROUND_GROUND
float autocvar_hud_panel_strafehud_timeout_ground
bool autocvar_hud_panel_strafehud_bar_preaccel
vector autocvar_hud_panel_strafehud_angle_accel_color
float autocvar_hud_panel_strafehud_switch_minspeed
vector autocvar_hud_panel_strafehud_angle_overturn_color
int autocvar_hud_panel_strafehud_angle_arrow
const float ACOS_SQRT2_3_DEG
float autocvar_hud_panel_strafehud_angle_arrow_size
const int STRAFEHUD_DIRECTION_LEFT
bool autocvar_hud_panel_strafehud_wturn_unrestricted
const int STRAFEHUD_DIRECTION_NONE
float autocvar_hud_panel_strafehud_switch_line_width
int autocvar_hud_panel_strafehud_bestangle
bool autocvar_hud_panel_strafehud_direction