22{
23 static float hud_lasttime = 0;
24
25
26 if (!should_draw)
27 return;
29 {
33 {
35 return;
36 }
37 }
38
40
43 else
45
47
49 {
52 }
53
56
58 {
60 return;
61 }
62
63
64
65 int keys =
STAT(PRESSED_KEYS);
67
68
70
71
72 bool real_onslick = false;
73
74
75 bool onground = real_onground && !jumpheld;
76 bool onslick = real_onslick;
77
78
81
82 static float onground_lasttime = 0;
83 static bool onslick_last = false;
84 if (onground)
85 {
87
88 onground_lasttime =
time;
89 onslick_last = onslick;
90 }
91 else if (jumpheld || swimming)
92 onground_lasttime = 0;
93
94 bool onground_expired;
95 if (onground_lasttime == 0)
96 onground_expired = true;
97 else
99
100
106
107 if (!onground && !onground_expired)
108 {
109 onground = true;
110 onslick = onslick_last;
111
113 {
116 }
117 }
118 else if (onslick)
119 {
122 }
123
124
126
127 float movespeed;
128 if (is_local)
129 {
131
132
133 if (movespeed == 0)
134 movespeed = maxspeed;
135 }
136 else
137 {
138
139
140
141 movespeed = maxspeed;
142 }
143
144
147 float absolute_wishangle =
fabs(wishangle);
148 bool strafekeys =
fabs(wishangle) > 45;
149
150
151 static bool turn = false;
152 float strafity = 0;
154 turn = false;
155 else
156 {
157 static float turn_lasttime = 0;
158 static float turnangle;
160
161 if (strafekeys)
162 turn = true;
163 else if (turn_expired)
164 turn = false;
165
166 if (turn)
167 {
168 if (strafekeys)
169 {
170 turn_lasttime =
time;
171 turnangle = wishangle;
172 }
173 else
174 wishangle = turnangle;
175
176
177 strafity = 1 - (90 -
fabs(wishangle)) / 45;
178
181
182 movespeed =
min(movespeed, maxspeed);
183
186 }
187 }
188
190
191 maxaccel *= dt * movespeed;
192 float bestspeed =
max(movespeed - maxaccel, 0);
193
194
196
198 bool moving =
speed > 0;
199
200 float frictionspeed;
201 float strafespeed;
202
203 if (moving && onground)
204 {
206
207 if (strafefriction > 0)
208 {
210
211
213
214
215
216 {
217 float independent_geometric = (1 - strafefriction * dt_r) ** (dt / dt_r);
218 if (S <
speed &&
speed < S / independent_geometric)
219 strafespeed = S - S * strafefriction * (dt - (dt_r *
log(S /
speed)) /
log(1 - strafefriction * dt_r));
221 strafespeed =
speed * independent_geometric;
222 else
223 strafespeed =
speed - strafefriction * dt * S;
224 strafespeed =
max(0, strafespeed);
225 }
226 }
227 else
229 frictionspeed =
speed - strafespeed;
230 }
231 else
232 {
233 frictionspeed = 0;
235 }
236
237
239 bool fwd;
240
242 {
243 if (moving)
244 {
245
247 if (vel_angle > 180)
248 vel_angle -= 360;
250
251
252 angle = vel_angle - view_angle;
253
254
257 else if (
angle < -180)
259
260
261
262 if (
fabs(wishangle) != 90)
263 {
265 fwd = true;
267 fwd = false;
268 else
270 }
271
272 else
273 {
274 if (wishangle < 0)
275 fwd =
angle <= -wishangle;
276 else
277 fwd =
angle >= -wishangle;
278 }
279
280
281 if (!fwd)
282 {
285 else
287 }
288 }
289 else
290 {
292 fwd = true;
293 }
294 }
295 else
296 {
297 const float demo_maxangle = 55;
298 const float demo_turnspeed = 40;
299 static float demo_position = -37 / demo_maxangle;
300
302 {
303 float demo_dt =
time - hud_lasttime;
304 float demo_step = (demo_turnspeed / demo_maxangle) * demo_dt;
305 demo_position = ((demo_position + demo_step) % 4 + 4) % 4;
306 }
307
308
309 if (demo_position > 3)
310 angle = -1 + (demo_position - 3);
311 else if (demo_position > 1)
312 angle = +1 - (demo_position - 1);
313 else
314 angle = demo_position;
315 angle *= demo_maxangle;
316
317 fwd = true;
318 wishangle = 45;
320 wishangle *= -1;
321 }
322
323
324 if (!fwd)
325 wishangle *= -1;
326
327
329 {
331 wishangle *= -1;
332 }
333
335 if (airstopaccel == 0 || turn)
336 airstopaccel = 1;
337
338
339
340 float bestangle;
341 float prebestangle;
342 float overturnangle;
343 if (!moving)
344 {
345
346 prebestangle = bestangle = 0;
347 overturnangle = 180;
348 }
350 {
351
352 {
353
354 bestangle = strafespeed > bestspeed
355 ? acos(bestspeed / strafespeed) *
RAD2DEG
356 : 0;
357
358 }
359 {
360
361
362 float prebestangle_sqrt = movespeed * movespeed + strafespeed * strafespeed -
speed *
speed;
363
364 prebestangle = (prebestangle_sqrt > 0 && strafespeed >
sqrt(prebestangle_sqrt))
365 ? acos(
sqrt(prebestangle_sqrt) / strafespeed) *
RAD2DEG
366 : (prebestangle_sqrt > 0 ? 0 : 90);
367
368 }
369 {
370 float overturn_numer =
speed *
speed - strafespeed * strafespeed - maxaccel * maxaccel;
371 float overturn_denom = 2 * maxaccel * strafespeed;
372
373 overturnangle = overturn_denom >
fabs(overturn_numer)
374 ? acos(overturn_numer / overturn_denom) *
RAD2DEG
375 : (overturn_numer < 0 ? 180 : 0);
376
377 }
378 if (overturnangle < bestangle || bestangle < prebestangle)
379 {
380
382 {
383
384
385 prebestangle = bestangle = 0;
386 overturnangle = 0;
387 }
389 {
390
391
392
393
394
395
396
397 overturnangle = bestangle;
398 prebestangle = bestangle;
399 }
400 else
401 {
402
403
407 ? acos(-(airstopaccel * maxaccel * 0.5) /
speed) *
RAD2DEG
408 : acos(-maxaccel / (2 *
speed - (airstopaccel - 1) * maxaccel)) *
RAD2DEG;
409 }
410 }
411 }
412 else
413 {
414
415 bestangle =
speed > bestspeed
417 : 0;
418 prebestangle =
speed > movespeed
420 : 0;
421
422
423 overturnangle =
speed > airstopaccel * maxaccel * 0.5
425 ? acos(-(airstopaccel * maxaccel * 0.5) /
speed) *
RAD2DEG
426 : acos(-maxaccel / (2 *
speed - (airstopaccel - 1) * maxaccel)) *
RAD2DEG)
427 : 180;
428 }
429
430 float absolute_bestangle = bestangle;
431 float absolute_prebestangle = prebestangle;
432 float absolute_overturnangle = overturnangle;
433
438 bool is_aircontrol_direction = fwd || (aircontrol_flags &
BIT(0));
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456 bool wturning = (wishangle == 0) && !onground && is_aircontrol_keys;
457 bool wturn_valid = false;
458 float wturn_bestangle = 0;
462 {
464 if (wturn_power == 2)
465 {
466 float wturn_a = 32 *
fabs(aircontrol) * dt;
467 if (aircontrol_flags &
BIT(2))
468 wturn_a *= maxspeed / maxspeed_phys;
469 float wturn_V = 1 - (wturn_a * wturn_a) / (
speed *
speed);
471 wturn_bestangle = acos(-
speed / wturn_a * (
cos((acos(wturn_V) +
M_PI * 2) / 3) * 2 + 1)) *
RAD2DEG;
472 else
474 wturn_valid = true;
475 }
477 {
478 wturn_bestangle = acos(
sqrt(wturn_power / (wturn_power + 1))) *
RAD2DEG;
479 wturn_valid = true;
480 }
481 }
482 float absolute_wturn_bestangle = wturn_bestangle;
483
484
485 float n_bestangle = 0;
486 float absolute_n_prebestangle = 0;
489 if (draw_normal || wturn_valid)
490 {
491
493 float n_movespeed = n_maxspeed;
495 float n_bestspeed =
max(n_movespeed - n_maxaccel, 0);
496 n_bestangle =
speed > n_bestspeed
498 : -45;
499 absolute_n_prebestangle =
speed > n_movespeed
501 : 0;
502 }
503
505
508
510 {
511 n_bestangle *= -1;
512 bestangle *= -1;
513 prebestangle *= -1;
514 overturnangle *= -1;
515 }
516 float opposite_bestangle = -bestangle;
517 float n_opposite_bestangle = -n_bestangle;
518
519 bestangle -= wishangle;
520 opposite_bestangle -= wishangle;
521 n_opposite_bestangle -= wishangle;
522 prebestangle -= wishangle;
523 overturnangle -= wishangle;
524
525 int mode;
528 else
530
531
532 float changeangle = -bestangle;
533 float n_changeangle = -n_bestangle;
534 float n_opposite_changeangle = n_opposite_bestangle + n_bestangle * 2;
535
536
538 if (minspeed < 0)
539 minspeed = bestspeed + frictionspeed;
540
541 bool opposite_direction = false;
542 float opposite_changeangle = 0;
545 {
546 opposite_direction = true;
547 opposite_changeangle = opposite_bestangle + bestangle * 2;
548 }
549
550
551 float wturn_left_bestangle = wturn_bestangle;
552 float wturn_right_bestangle = -wturn_bestangle;
553
554
555 float shiftangle = 0;
557 {
559 bestangle += shiftangle;
560 changeangle += shiftangle;
561 opposite_bestangle += shiftangle;
562 opposite_changeangle += shiftangle;
563 n_bestangle += shiftangle;
564 n_changeangle += shiftangle;
565 n_opposite_bestangle += shiftangle;
566 n_opposite_changeangle += shiftangle;
567 wturn_left_bestangle += shiftangle;
568 wturn_right_bestangle += shiftangle;
569 }
570
571 StrafeHUD_DrawStrafeMeter(shiftangle, wishangle, absolute_bestangle, absolute_prebestangle, absolute_overturnangle, moving, hudangle);
572
573 float text_offset_top;
574 float text_offset_bottom;
577
580
581
583 float strafe_ratio = 0;
584 if (moving)
585 {
586 float moveangle =
fabs(
angle + wishangle);
587 if (moveangle > 180) moveangle = 360 - moveangle;
588
589
590 if (moveangle >= absolute_overturnangle)
591 {
592 if (moveangle == absolute_overturnangle && absolute_overturnangle == 180)
593 {}
594 else
595 {
597 strafe_ratio = (moveangle - absolute_overturnangle) / (180 - absolute_overturnangle);
598
599 strafe_ratio *= -1;
600 }
601 }
602
603 else if (moveangle >= absolute_bestangle)
604 {
606 strafe_ratio = (absolute_overturnangle - moveangle) / (absolute_overturnangle - absolute_bestangle);
607
608 }
609 else if (moveangle >= absolute_prebestangle)
610 {
613 strafe_ratio = (moveangle - absolute_prebestangle) / (absolute_bestangle - absolute_prebestangle);
614 }
615
619 currentangle_color,
fabs(strafe_ratio));
620 }
621
622 float currentangle = 0;
624 {
625
626 if (
fabs(
angle) <= 180 - antiflicker_angle)
627 currentangle =
angle;
628 }
629
630 float max_line_height = 0;
631 float max_top_arrow_size = 0;
632 float max_bottom_arrow_size = 0;
633
634
636 {
637
641 indicator_size.z = 0;
642
646
647
649
650 if (num_dashes > 0)
651 max_line_height =
max(max_line_height, indicator_size.y);
652 if (has_top_arrow)
653 max_top_arrow_size =
max(max_top_arrow_size, arrow_size);
654 if (has_bottom_arrow)
655 max_bottom_arrow_size =
max(max_bottom_arrow_size, arrow_size);
656
657
658 float current_changeangle = draw_normal
659 ? (opposite_direction ? n_opposite_changeangle : n_changeangle)
660 : (opposite_direction ? opposite_changeangle : changeangle);
661 float opposite_changeangle = draw_normal
662 ? (opposite_direction ? n_opposite_bestangle : n_bestangle)
663 : (opposite_direction ? opposite_bestangle : bestangle);
664
666 current_changeangle, indicator_size, arrow_size, num_dashes,
669
672 opposite_changeangle, indicator_size, arrow_size, num_dashes,
675 }
676
679 {
680
684 indicator_size.z = 0;
685
689
690
692
693 if (num_dashes > 0)
694 max_line_height =
max(max_line_height, indicator_size.y);
695 if (has_top_arrow)
696 max_top_arrow_size =
max(max_top_arrow_size, arrow_size);
697 if (has_bottom_arrow)
698 max_bottom_arrow_size =
max(max_bottom_arrow_size, arrow_size);
699
700 float ghostangle = opposite_direction ? opposite_bestangle : bestangle;
701
703 ghostangle, indicator_size, arrow_size, num_dashes,
706 }
707
708
709 if (wturn_valid && !onground && is_aircontrol_direction
711 && absolute_wturn_bestangle < absolute_n_prebestangle
715 {
716
720 indicator_size.z = 0;
721
725
726
728
729 if (num_dashes > 0)
730 max_line_height =
max(max_line_height, indicator_size.y);
731 if (has_top_arrow)
732 max_top_arrow_size =
max(max_top_arrow_size, arrow_size);
733 if (has_bottom_arrow)
734 max_bottom_arrow_size =
max(max_bottom_arrow_size, arrow_size);
735
736
738 wturn_left_bestangle, indicator_size, arrow_size, num_dashes,
742 wturn_right_bestangle, indicator_size, arrow_size, num_dashes,
745 }
746
748 {
749
753 indicator_size.z = 0;
754
758
759
761
762 if (num_dashes > 0)
763 max_line_height =
max(max_line_height, indicator_size.y);
764 if (has_top_arrow)
765 max_top_arrow_size =
max(max_top_arrow_size, arrow_size);
766 if (has_bottom_arrow)
767 max_bottom_arrow_size =
max(max_bottom_arrow_size, arrow_size);
768
770 currentangle, indicator_size, arrow_size, num_dashes,
771 has_top_arrow, has_bottom_arrow, currentangle_color,
773 }
774
775
776 {
777 float line_height_offset = max_line_height;
778
779
780 line_height_offset = (line_height_offset -
panel_size.y) / 2;
781
782
783 float angle_offset_top = line_height_offset + max_top_arrow_size;
784
785
786 float 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