]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/hud/panel/strafehud.qc
further improve strafehud drawing code (fixes visual inconsistencies with certain...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud / panel / strafehud.qc
1 // Name:   StrafeHUD
2 // Author: Juhu
3
4 #include "strafehud.qh"
5
6 #include <client/autocvars.qh>
7 #include <client/miscfunctions.qh>
8 #include <common/animdecide.qh>
9 #include <common/ent_cs.qh>
10 #include <common/mapinfo.qh>
11 #include <common/mapobjects/trigger/swamp.qh>
12 #include <common/physics/movetypes/movetypes.qh>
13 #include <common/physics/player.qh>
14 #include <lib/csqcmodel/cl_player.qh>
15
16 bool strafehud_fwd = true;
17 float strafehud_demo_angle = -37;
18 float strafehud_demo_direction = 1;
19 float strafehud_demo_time = 0;
20 float strafehud_state_onground_time = 0;
21 float strafehud_state_strafekeys_time = 0;
22 bool strafehud_state_onground = true;
23 bool strafehud_state_strafekeys = false;
24 bool strafehud_turn = false;
25 float strafehud_turnangle;
26
27 void HUD_StrafeHUD()
28 {
29     entity strafeplayer;
30
31     if(!autocvar__hud_configure)
32     {
33         if(!autocvar_hud_panel_strafehud) return;
34         if(spectatee_status == -1 && (autocvar_hud_panel_strafehud == 1 || autocvar_hud_panel_strafehud == 3)) return;
35         if(autocvar_hud_panel_strafehud == 3 && !(ISGAMETYPE(RACE) || ISGAMETYPE(CTS))) return;
36     }
37
38     HUD_Panel_LoadCvars();
39
40     if (autocvar_hud_panel_strafehud_dynamichud)
41         HUD_Scale_Enable();
42     else
43         HUD_Scale_Disable();
44     HUD_Panel_DrawBg();
45     if(panel_bg_padding)
46     {
47         panel_pos  += '1 1 0' * panel_bg_padding;
48         panel_size -= '2 2 0' * panel_bg_padding;
49     }
50
51     if(spectatee_status > 0)
52     {
53         strafeplayer = CSQCModel_server2csqc(player_localentnum - 1);
54     }
55     else
56     {
57         strafeplayer = csqcplayer;
58     }
59
60     // draw strafehud
61     if(csqcplayer && strafeplayer)
62     {
63         // autocvars
64         float strafehud_bar_alpha                  = autocvar_hud_panel_strafehud_bar_alpha;
65         vector strafehud_bar_color                 = autocvar_hud_panel_strafehud_bar_color;
66         vector strafehud_bestangle_color           = autocvar_hud_panel_strafehud_indicator_color;
67         vector strafehud_bestangle_opposite_color  = autocvar_hud_panel_strafehud_indicator_switch_color;
68         vector strafehud_good_color                = autocvar_hud_panel_strafehud_good_color;
69         vector strafehud_warning_color             = autocvar_hud_panel_strafehud_warning_color;
70         vector strafehud_alert_color               = autocvar_hud_panel_strafehud_alert_color;
71         vector strafehud_direction_color           = autocvar_hud_panel_strafehud_direction_color;
72         float strafehud_timeout_air                = autocvar_hud_panel_strafehud_timeout_air;    // timeout for slick ramps
73         float strafehud_timeout_ground             = autocvar_hud_panel_strafehud_timeout_ground; // timeout for strafe jumping in general
74         float strafehud_timeout_strafe             = autocvar_hud_panel_strafehud_timeout_strafe; // timeout for jumping with strafe keys only
75         float strafehud_indicator_minspeed         = autocvar_hud_panel_strafehud_indicator_minspeed;
76
77         // physics
78         float  strafehud_onground                  = strafeplayer == csqcplayer ? IS_ONGROUND(strafeplayer) : !(strafeplayer.anim_implicit_state & ANIMIMPLICITSTATE_INAIR);
79         float  strafehud_speed                     = !autocvar__hud_configure ? vlen(vec2(csqcplayer.velocity)) : 1337; // use local csqcmodel entity for this even when spectating, flickers too much otherwise
80         float  strafehud_maxspeed_crouch_mod       = IS_DUCKED(strafeplayer) ? .5 : 1;
81         float  strafehud_maxspeed_swamp_mod        = strafeplayer.in_swamp ? strafeplayer.swamp_slowdown : 1;
82         float  strafehud_maxspeed_phys             = strafehud_onground ? PHYS_MAXSPEED(strafeplayer) : PHYS_MAXAIRSPEED(strafeplayer);
83         float  strafehud_maxspeed                  = !autocvar__hud_configure ? (strafehud_maxspeed_phys * strafehud_maxspeed_crouch_mod * strafehud_maxspeed_swamp_mod) : 320;
84         float  strafehud_vel_angle                 = vectoangles(strafeplayer.velocity).y;
85         float  strafehud_view_angle                = view_angles.y + 180;
86         float  strafehud_angle;
87         float  strafehud_direction;
88         vector strafehud_movement                  = PHYS_INPUT_MOVEVALUES(strafeplayer);
89         int    strafehud_keys                      = STAT(PRESSED_KEYS);
90         float  strafehud_wishangle;
91         float  strafehud_moveangle;
92
93         // HUD
94         float  strafehud_hudangle;
95         float  strafehud_bar_offset;
96         vector strafehud_bar_size                  = panel_size;
97         vector strafehud_currentangle_color        = strafehud_warning_color;
98         float  strafehud_currentangle_offset;
99         vector strafehud_currentangle_size         = '0 0 0';
100         float  strafehud_bestangle                 = 0;
101         bool   strafehud_bestangle_anywhere        = false;
102         float  strafehud_bestangle_offset;
103         float  strafehud_bestangle_opposite_offset;
104         vector strafehud_bestangle_size            = '0 0 0';
105         float  strafehud_accelzone_offset;
106         vector strafehud_accelzone_size            = panel_size;
107         float  strafehud_overturn_offset;
108         vector strafehud_overturn_size             = panel_size;
109         float  strafehud_mirrorangle;
110         float  strafehud_mirror_overturn_offset    = 0;
111         vector strafehud_mirror_overturn_size      = panel_size;
112         vector strafehud_direction_size_vertical   = '0 0 0';
113         vector strafehud_direction_size_horizontal = '0 0 0';
114         float  strafehud_maxangle;
115         float  strafehud_range_minangle;
116
117         // determine whether the player is strafing forwards or backwards
118         if(strafeplayer == csqcplayer) // if entity is local player
119         {
120             if(strafehud_movement_x > 0)
121             {
122                 strafehud_fwd = true;
123             }
124             else if(strafehud_movement_x < 0)
125             {
126                 strafehud_fwd = false;
127             }
128         }
129         else // alternatively determine direction by querying pressed keys
130         {
131             if((strafehud_keys & KEY_FORWARD) && !(strafehud_keys & KEY_BACKWARD))
132             {
133                 strafehud_fwd = true;
134             }
135             else if(!(strafehud_keys & KEY_FORWARD) && (strafehud_keys & KEY_BACKWARD))
136             {
137                 strafehud_fwd = false;
138             }
139         }
140
141         // determine player wishdir
142         if(strafeplayer == csqcplayer) // if entity is local player
143         {
144             if(strafehud_movement_x == 0)
145             {
146                 if(strafehud_movement_y < 0)
147                 {
148                     strafehud_wishangle = -90;
149                 }
150                 else if(strafehud_movement_y > 0)
151                 {
152                     strafehud_wishangle = 90;
153                 }
154                 else
155                 {
156                     strafehud_wishangle = 0;
157                 }
158             }
159             else
160             {
161                 if(strafehud_movement_y == 0)
162                 {
163                     strafehud_wishangle = 0;
164                 }
165                 else
166                 {
167                     strafehud_wishangle = RAD2DEG * atan2(strafehud_movement_y, strafehud_movement_x);
168                 }
169             }
170         }
171         else // alternatively calculate wishdir by querying pressed keys
172         {
173             if(strafehud_keys & KEY_FORWARD)
174             {
175                 strafehud_wishangle = 45;
176             }
177             else if(strafehud_keys & KEY_BACKWARD)
178             {
179                 strafehud_wishangle = 135;
180             }
181             else
182             {
183                 strafehud_wishangle = 90;
184             }
185             if(strafehud_keys & KEY_LEFT)
186             {
187                 strafehud_wishangle *= -1;
188             }
189             else if(!(strafehud_keys & KEY_RIGHT))
190             {
191                 strafehud_wishangle = 0;
192             }
193         }
194
195         // determine minimum required angle to display full strafe range
196         strafehud_range_minangle = fabs(strafehud_wishangle) % 90; // maximum range is 90 degree
197         if(strafehud_range_minangle > 45) // minimum angle range is 45
198         {
199             strafehud_range_minangle = 45 - fabs(strafehud_wishangle) % 45;
200         }
201         strafehud_range_minangle = 90 - strafehud_range_minangle; // calculate value which is never >90 or <45
202
203         if(autocvar_hud_panel_strafehud_angle == 0)
204         {
205             if(autocvar__hud_configure)
206             {
207                 strafehud_hudangle = 45;
208             }
209             else
210             {
211                 strafehud_hudangle = strafehud_range_minangle; // use minimum angle required if dynamically setting hud angle
212             }
213         }
214         else
215         {
216             strafehud_hudangle = bound(1, fabs(autocvar_hud_panel_strafehud_angle), 360) / 2; // limit HUD range to 360 degrees, higher values don't make sense and break the code
217         }
218
219         // detecting strafe turning
220         if(!autocvar__hud_configure)
221         {
222             if(strafehud_onground != strafehud_state_onground)
223             {
224                 strafehud_state_onground_time = time;
225             }
226             strafehud_state_onground = strafehud_onground;
227             if((fabs(strafehud_wishangle) == 90) != strafehud_state_strafekeys)
228             {
229                 strafehud_state_strafekeys_time = time;
230             }
231             strafehud_state_strafekeys = fabs(strafehud_wishangle) == 90;
232             if((strafehud_keys & KEY_FORWARD) || (strafehud_keys & KEY_BACKWARD))
233             {
234                 strafehud_turn = false;
235             }
236             else if(strafehud_onground)
237             {
238                 if((time - strafehud_state_onground_time) >= strafehud_timeout_ground)
239                 {
240                     strafehud_turn = false;
241                 }
242             }
243             else // air strafe only
244             {
245                 if(fabs(strafehud_wishangle) == 90)
246                 {
247                     if((time - strafehud_state_onground_time) >= strafehud_timeout_air)
248                     {
249                         strafehud_turn = true; // CPMA turning
250                         strafehud_turnangle = strafehud_wishangle;
251                     }
252                 }
253                 else if((time - strafehud_state_strafekeys_time) >= strafehud_timeout_strafe)
254                 {
255                     strafehud_turn = false;
256                 }
257             }
258             if(strafehud_turn)
259             {
260                 strafehud_maxspeed = PHYS_MAXAIRSTRAFESPEED(strafeplayer) * strafehud_maxspeed_swamp_mod; // no crouching here because it doesn't affect air strafing
261                 strafehud_wishangle = strafehud_turnangle;
262             }
263         }
264
265         strafehud_indicator_minspeed = strafehud_indicator_minspeed < 0 ? strafehud_maxspeed + .1 : strafehud_indicator_minspeed;
266
267         // get current strafing angle ranging from -180° to +180°
268         if(!autocvar__hud_configure)
269         {
270             if(!strafehud_fwd) strafehud_wishangle += strafehud_wishangle < 0 ? 180 : strafehud_wishangle > 0 ? -180 : 0;
271             if(strafehud_speed > 0)
272             {
273                 if(!strafehud_fwd) strafehud_view_angle += strafehud_view_angle < 0 ? 180 : strafehud_view_angle > 0 ? -180 : 0;
274                 strafehud_angle = strafehud_view_angle - strafehud_vel_angle;
275
276                 if     (strafehud_angle >  180) strafehud_angle = -360 + strafehud_angle;
277                 else if(strafehud_angle < -180) strafehud_angle =  360 + strafehud_angle;
278
279                 strafehud_angle = 180 - strafehud_angle;
280                 if(strafehud_angle > 180)
281                 {
282                     strafehud_angle = -fabs(360 - strafehud_angle);
283                 }
284
285                 // making the hud less flickery in case of rounding errors
286                 if(strafehud_angle > 179.9 || strafehud_angle < -179.9)
287                 {
288                     strafehud_currentangle_color = strafehud_alert_color;
289                     strafehud_angle = 0;
290                 }
291                 if(strafehud_angle < .1 && strafehud_angle > -.1)
292                 {
293                     strafehud_angle = 0;
294                 }
295             }
296             else
297             {
298                 strafehud_angle = 0;
299             }
300         }
301         else // simulate turning for HUD setup
302         {
303             if(autocvar__hud_panel_strafehud_center)
304             {
305                 strafehud_angle = strafehud_demo_angle = 0;
306                 strafehud_demo_time = 0;
307                 strafehud_wishangle = 0;
308             }
309             else
310             {
311                 if(autocvar__hud_panel_strafehud_demo && ((time - strafehud_demo_time) >= .025))
312                 {
313                     strafehud_demo_time = time;
314                     strafehud_demo_angle += strafehud_demo_direction;
315                     if(fabs(strafehud_demo_angle) >= 55)
316                     {
317                         strafehud_demo_direction = -strafehud_demo_direction;
318                     }
319                 }
320                 strafehud_angle = strafehud_demo_angle;
321                 strafehud_wishangle = 45 * (strafehud_demo_angle > 0 ? 1 : -1);
322             }
323         }
324
325         if (autocvar_v_flipped)
326         {
327             strafehud_angle = -strafehud_angle;
328             strafehud_wishangle = -strafehud_wishangle;
329         }
330
331         strafehud_moveangle = strafehud_angle + strafehud_wishangle;
332
333         if(strafehud_wishangle != 0)
334         {
335             strafehud_direction = strafehud_wishangle > 0 ? 1 : -1;
336         }
337         else
338         {
339             strafehud_direction = strafehud_moveangle > 0 ? 1 : strafehud_moveangle < 0 ? -1 : 0;
340         }
341
342         // decelerating at this angle
343         strafehud_maxangle = 90 - fabs(strafehud_wishangle);
344         // best angle to strafe at
345         strafehud_bestangle = (strafehud_speed > strafehud_maxspeed ? acos(strafehud_maxspeed / strafehud_speed) : 0) * RAD2DEG * (strafehud_direction < 0 ? -1 : 1) - strafehud_wishangle;
346         // various offsets and size calculations of hud indicators elements
347         // best strafe acceleration angle
348         strafehud_bestangle_offset          = floor( strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5);
349         strafehud_bestangle_opposite_offset = floor(-strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5);
350         strafehud_bestangle_size.x = floor(panel_size.x * .01 + .5);
351         strafehud_bestangle_size.y = panel_size.y;
352         // current angle
353         strafehud_currentangle_offset = floor(bound(-strafehud_hudangle, strafehud_angle, strafehud_hudangle)/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5);
354         strafehud_currentangle_size.x = floor(panel_size.x * .005 + .5);
355         strafehud_currentangle_size.y = floor(panel_size.y * 1.5 + .5);
356         // direction indicator
357         strafehud_direction_size_vertical.x = floor(panel_size.x * .0075 + .5);
358         strafehud_direction_size_vertical.y = panel_size.y;
359         strafehud_direction_size_horizontal.x = floor(strafehud_direction_size_vertical.x * 3 + .5);
360         strafehud_direction_size_horizontal.y = strafehud_direction_size_vertical.x;
361         // overturn
362         strafehud_mirrorangle = strafehud_maxangle + strafehud_hudangle - 180; // how many degrees of overturn area are on the opposite side of the hud
363         strafehud_overturn_size.x = floor((panel_size.x * (strafehud_hudangle - strafehud_maxangle) / strafehud_hudangle) / 2 + .5);
364         strafehud_mirror_overturn_size.x = floor(panel_size.x * strafehud_mirrorangle / (strafehud_hudangle * 2) + .5);
365
366         // if the strafe bar fills the whole hud panel
367         if(!(strafehud_speed >= strafehud_indicator_minspeed) || !(fabs(strafehud_bestangle) <= strafehud_hudangle) || !(strafehud_direction != 0))
368         {
369             // add a background to the strafe-o-meter
370             if(panel_size.x > 0 && panel_size.y > 0)
371             {
372                 HUD_Panel_DrawProgressBar(panel_pos, panel_size, "progressbar", 1, 0, 0, strafehud_bar_color, strafehud_bar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
373             }
374         }
375
376         // mark the ideal strafe angle
377         if(strafehud_speed >= strafehud_indicator_minspeed) // draw indicators if strafing is required to gain speed
378         {
379             if (fabs(strafehud_bestangle) <= strafehud_hudangle) // don't draw angle indicator and acceleration zones if outside of hud range
380             {
381                 if (strafehud_direction != 0) // only draw acceleration zones if strafe direction can be determined
382                 {
383                     // calculate zone in which strafe acceleration happens
384                     if(strafehud_direction < 0) // turning left
385                     {
386                         strafehud_accelzone_offset = 0;
387                         strafehud_accelzone_size.x = strafehud_bestangle_offset - strafehud_bestangle_size.x;
388                     }
389                     else // turning right
390                     {
391                         strafehud_accelzone_offset = strafehud_bestangle_offset + strafehud_bestangle_size.x;
392                         strafehud_accelzone_size.x = panel_size.x - strafehud_accelzone_offset;
393                     }
394
395                     if(strafehud_hudangle > strafehud_maxangle) // draw overturn area and move acceleration zone
396                     {
397                         if(strafehud_direction < 0) // turning left
398                         {
399                             // calculate offset of overturn area
400                             strafehud_overturn_offset = 0;
401                             // move/adjust acceleration zone
402                             strafehud_accelzone_offset += strafehud_overturn_size.x;
403                             strafehud_accelzone_size.x -= strafehud_overturn_size.x;
404                             // calculate the remainder of the overturn zone on the opposite side
405                             strafehud_mirror_overturn_offset = panel_size.x - strafehud_mirror_overturn_size.x;
406                         }
407                         else // turning right
408                         {
409                             // calculate offset of overturn area
410                             strafehud_overturn_offset = panel_size.x - strafehud_overturn_size.x;
411                             // adjust acceleration zone
412                             strafehud_accelzone_size.x -= strafehud_overturn_size.x;
413                             // calculate the remainder of the overturn zone on the opposite side
414                             strafehud_mirror_overturn_offset = 0;
415                         }
416                         // draw overturn area
417                         if(strafehud_overturn_size.x > 0 && strafehud_overturn_size.y > 0)
418                         {
419                             HUD_Panel_DrawProgressBar(panel_pos + eX * strafehud_overturn_offset, strafehud_overturn_size, "progressbar", 1, 0, 0, strafehud_alert_color, strafehud_bar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
420                         }
421                         // draw remaining overturn area on the opposite side if there is any (180 degree in total)
422                         if(strafehud_mirrorangle > 0 && strafehud_mirror_overturn_size.x > 0 && strafehud_mirror_overturn_size.y > 0)
423                         {
424                             HUD_Panel_DrawProgressBar(panel_pos + eX * strafehud_mirror_overturn_offset, strafehud_mirror_overturn_size, "progressbar", 1, 0, 0, strafehud_alert_color, strafehud_bar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
425                         }
426                     }
427
428                     // draw acceleration zone
429                     if(strafehud_accelzone_size.x > 0 && strafehud_accelzone_size.y > 0)
430                     {
431                         HUD_Panel_DrawProgressBar(panel_pos + eX * strafehud_accelzone_offset, strafehud_accelzone_size, "progressbar", 1, 0, 0, strafehud_bestangle_color, strafehud_bar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
432                     }
433
434                     // add a background to the strafe-o-meter
435                     if(strafehud_direction < 0) // turning left
436                     {
437                         strafehud_bar_offset = strafehud_accelzone_offset + strafehud_accelzone_size.x + strafehud_bestangle_size.x;
438                         strafehud_bar_size.x = panel_size.x - strafehud_bar_offset - (panel_size.x - (strafehud_mirrorangle > 0 ? strafehud_mirror_overturn_offset : panel_size.x));
439                     }
440                     else // turning right
441                     {
442                         strafehud_bar_offset = strafehud_mirrorangle > 0 ? strafehud_mirror_overturn_size.x : 0;
443                         strafehud_bar_size.x = panel_size.x - strafehud_bar_offset - (panel_size.x - strafehud_accelzone_offset) - strafehud_bestangle_size.x;
444                     }
445                     if(strafehud_bar_size.x > 0 && strafehud_bar_size.y > 0)
446                     {
447                         HUD_Panel_DrawProgressBar(panel_pos + eX * strafehud_bar_offset, strafehud_bar_size, "progressbar", 1, 0, 0, strafehud_bar_color, strafehud_bar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
448                     }
449
450                     // draw the direction indicator caps at the sides of the hud
451                     // vertical line
452                     drawfill(panel_pos + eX * (strafehud_direction < 0 ? -strafehud_direction_size_vertical.x : panel_size.x), strafehud_direction_size_vertical, strafehud_direction_color, panel_fg_alpha, DRAWFLAG_NORMAL);
453                     // top horizontal line
454                     drawfill(panel_pos + eX * (strafehud_direction < 0 ? -strafehud_direction_size_vertical.x : panel_size.x - strafehud_direction_size_horizontal.x + strafehud_direction_size_vertical.x) - eY * strafehud_direction_size_horizontal.y, strafehud_direction_size_horizontal, strafehud_direction_color, panel_fg_alpha, DRAWFLAG_NORMAL);
455                     // bottom horizontal line
456                     drawfill(panel_pos + eX * (strafehud_direction < 0 ? -strafehud_direction_size_vertical.x : panel_size.x - strafehud_direction_size_horizontal.x + strafehud_direction_size_vertical.x) + eY * panel_size.y, strafehud_direction_size_horizontal, strafehud_direction_color, panel_fg_alpha, DRAWFLAG_NORMAL);
457
458                     // draw opposite best strafe angle
459                     drawfill(panel_pos + eX * (strafehud_bestangle_opposite_offset - (-strafehud_direction < 0 ? strafehud_bestangle_size.x : 0)), strafehud_bestangle_size, strafehud_bestangle_opposite_color, panel_fg_alpha, DRAWFLAG_NORMAL);
460                     // draw current best strafe angle
461                     drawfill(panel_pos + eX * (strafehud_bestangle_offset - (strafehud_direction < 0 ? strafehud_bestangle_size.x : 0)), strafehud_bestangle_size, strafehud_bestangle_color, panel_fg_alpha, DRAWFLAG_NORMAL);
462                 }
463                 else
464                 {
465                     // draw best angles for acceleration
466                     drawfill(panel_pos + eX * (strafehud_bestangle_opposite_offset - strafehud_bestangle_size.x), strafehud_bestangle_size, strafehud_bestangle_opposite_color, panel_fg_alpha, DRAWFLAG_NORMAL);
467                     drawfill(panel_pos + eX * (strafehud_bestangle_offset), strafehud_bestangle_size, strafehud_bestangle_opposite_color, panel_fg_alpha, DRAWFLAG_NORMAL);
468                 }
469             }
470         }
471         else
472         {
473             strafehud_bestangle_anywhere = true; // no indicators, moving forward should suffice to gain speed
474         }
475
476         // draw the actual strafe angle
477         if (!strafehud_bestangle_anywhere) // player gains speed with strafing
478         {
479             if ((strafehud_direction > 0 && strafehud_angle >= strafehud_bestangle) ||
480                 (strafehud_direction < 0 && strafehud_angle <= strafehud_bestangle))
481             strafehud_currentangle_color = strafehud_good_color;
482         }
483
484         if (fabs(strafehud_moveangle) > 89.9) // player is overturning
485         {
486             strafehud_currentangle_color = strafehud_alert_color;
487         }
488
489         if (strafehud_speed <= (strafehud_maxspeed + .1) && strafehud_currentangle_color != strafehud_alert_color) // player gains speed without strafing
490         {
491             strafehud_currentangle_color = strafehud_good_color;
492         }
493
494         drawfill(panel_pos - '0 1 0'*floor(panel_size.y * .25 + .5) + eX * (strafehud_currentangle_offset - strafehud_currentangle_size.x/2), strafehud_currentangle_size, strafehud_currentangle_color, autocvar_hud_panel_strafehud_angle_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
495     }
496 }