]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
strafehud: avoid unnecessary indentation, removed large if block
authorJuhu <5894800-Juhu_@users.noreply.gitlab.com>
Thu, 19 Sep 2024 17:36:48 +0000 (19:36 +0200)
committerJuhu <5894800-Juhu_@users.noreply.gitlab.com>
Thu, 19 Sep 2024 17:36:48 +0000 (19:36 +0200)
qcsrc/client/hud/panel/strafehud.qc

index 2bf08dec2f0a5559955894e4b77696990f8a676e..5bc8e4a9082d9d91d756f91715cc39ace5df84a8 100644 (file)
@@ -64,496 +64,496 @@ void HUD_StrafeHUD()
                strafeplayer = csqcplayer;
        }
 
+       if(!csqcplayer || !strafeplayer) { hud_lasttime = time; return; }
+
        // draw strafehud
-       if(csqcplayer && strafeplayer)
-       {
-               int keys = STAT(PRESSED_KEYS);
-               bool jumpheld = StrafeHUD_DetermineJumpHeld(strafeplayer, keys, islocal);
 
-               // does not get changed by ground timeout and is not affected by jump input
-               bool real_onground = islocal ? IS_ONGROUND(strafeplayer) : !(strafeplayer.anim_implicit_state & ANIMIMPLICITSTATE_INAIR);
+       int keys = STAT(PRESSED_KEYS);
+       bool jumpheld = StrafeHUD_DetermineJumpHeld(strafeplayer, keys, islocal);
 
-               // does not get changed by ground timeout
-               bool real_onslick = false;
+       // does not get changed by ground timeout and is not affected by jump input
+       bool real_onground = islocal ? IS_ONGROUND(strafeplayer) : !(strafeplayer.anim_implicit_state & ANIMIMPLICITSTATE_INAIR);
 
-               // if jump is held assume we are in air, avoids flickering of the hud when hitting the ground
-               bool onground = real_onground && !jumpheld;
-               bool onslick = real_onslick;
+       // does not get changed by ground timeout
+       bool real_onslick = false;
 
-               // the hud will not work well while swimming
-               float strafe_waterlevel = StrafeHUD_DetermineWaterLevel(strafeplayer);
-               bool swimming = strafe_waterlevel >= WATERLEVEL_SWIMMING;
+       // if jump is held assume we are in air, avoids flickering of the hud when hitting the ground
+       bool onground = real_onground && !jumpheld;
+       bool onslick = real_onslick;
 
-               static float onground_lasttime = 0;
-               static bool onslick_last = false;
-               if(onground)
-               {
-                       if(PHYS_FRICTION(strafeplayer) == 0)
-                       {
-                               onslick = true;
-                       }
-                       else // do not use IS_ONSLICK(), it only works for the local player and only if client prediction is enabled
-                       {
-                               trace_dphitq3surfaceflags = 0;
-                               tracebox(strafeplayer.origin, strafeplayer.mins, strafeplayer.maxs, strafeplayer.origin - '0 0 1', MOVE_NOMONSTERS, strafeplayer);
-                               onslick = trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK;
-                       }
-                       real_onslick = onslick;
+       // the hud will not work well while swimming
+       float strafe_waterlevel = StrafeHUD_DetermineWaterLevel(strafeplayer);
+       bool swimming = strafe_waterlevel >= WATERLEVEL_SWIMMING;
 
-                       onground_lasttime = time;
-                       onslick_last = onslick;
+       static float onground_lasttime = 0;
+       static bool onslick_last = false;
+       if(onground)
+       {
+               if(PHYS_FRICTION(strafeplayer) == 0)
+               {
+                       onslick = true;
                }
-               else if(jumpheld || swimming)
+               else // do not use IS_ONSLICK(), it only works for the local player and only if client prediction is enabled
                {
-                       onground_lasttime = 0;
+                       trace_dphitq3surfaceflags = 0;
+                       tracebox(strafeplayer.origin, strafeplayer.mins, strafeplayer.maxs, strafeplayer.origin - '0 0 1', MOVE_NOMONSTERS, strafeplayer);
+                       onslick = trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK;
                }
+               real_onslick = onslick;
 
-               bool onground_expired;
-               if(onground_lasttime == 0)
-                       onground_expired = true;
-               else
-                       onground_expired = (time - onground_lasttime) >= autocvar_hud_panel_strafehud_timeout_ground; // timeout for slick ramps
+               onground_lasttime = time;
+               onslick_last = onslick;
+       }
+       else if(jumpheld || swimming)
+       {
+               onground_lasttime = 0;
+       }
 
-               // only the local csqcplayer entity contains this information even when spectating
-               float maxspeed_mod = IS_DUCKED(csqcplayer) ? .5 : 1;
-               float maxspeed_phys = onground ? PHYS_MAXSPEED(strafeplayer) : PHYS_MAXAIRSPEED(strafeplayer);
-               float maxspeed = !autocvar__hud_configure ? maxspeed_phys * maxspeed_mod : 320;
-               float maxaccel_phys = onground ? PHYS_ACCELERATE(strafeplayer) : PHYS_AIRACCELERATE(strafeplayer);
-               float maxaccel = !autocvar__hud_configure ? maxaccel_phys : 1;
+       bool onground_expired;
+       if(onground_lasttime == 0)
+               onground_expired = true;
+       else
+               onground_expired = (time - onground_lasttime) >= autocvar_hud_panel_strafehud_timeout_ground; // timeout for slick ramps
 
-               if(!onground && !onground_expired) // if ground timeout has not expired yet use ground physics
-               {
-                       onground = true;
-                       onslick = onslick_last;
+       // only the local csqcplayer entity contains this information even when spectating
+       float maxspeed_mod = IS_DUCKED(csqcplayer) ? .5 : 1;
+       float maxspeed_phys = onground ? PHYS_MAXSPEED(strafeplayer) : PHYS_MAXAIRSPEED(strafeplayer);
+       float maxspeed = !autocvar__hud_configure ? maxspeed_phys * maxspeed_mod : 320;
+       float maxaccel_phys = onground ? PHYS_ACCELERATE(strafeplayer) : PHYS_AIRACCELERATE(strafeplayer);
+       float maxaccel = !autocvar__hud_configure ? maxaccel_phys : 1;
 
-                       if(!autocvar__hud_configure)
-                       {
-                               maxspeed = PHYS_MAXSPEED(strafeplayer) * maxspeed_mod;
-                               maxaccel = PHYS_ACCELERATE(strafeplayer);
-                       }
+       if(!onground && !onground_expired) // if ground timeout has not expired yet use ground physics
+       {
+               onground = true;
+               onslick = onslick_last;
+
+               if(!autocvar__hud_configure)
+               {
+                       maxspeed = PHYS_MAXSPEED(strafeplayer) * maxspeed_mod;
+                       maxaccel = PHYS_ACCELERATE(strafeplayer);
                }
+       }
 
-               vector movement = PHYS_INPUT_MOVEVALUES(strafeplayer);
-               float movespeed = vlen(vec2(movement));
-               if(movespeed == 0)
-                       movespeed = maxspeed;
+       vector movement = PHYS_INPUT_MOVEVALUES(strafeplayer);
+       float movespeed = vlen(vec2(movement));
+       if(movespeed == 0)
+               movespeed = maxspeed;
+       else
+               movespeed = min(movespeed, maxspeed);
+
+       // determine whether the player is pressing forwards or backwards keys
+       int keys_fwd;
+       if(islocal) // if entity is local player
+       {
+               if(movement.x > 0)
+                       keys_fwd = STRAFEHUD_KEYS_FORWARD;
+               else if(movement.x < 0)
+                       keys_fwd = STRAFEHUD_KEYS_BACKWARD;
                else
-                       movespeed = min(movespeed, maxspeed);
+                       keys_fwd = STRAFEHUD_KEYS_NONE;
+       }
+       else // alternatively determine direction by querying pressed keys
+       {
+               if((keys & KEY_FORWARD) && !(keys & KEY_BACKWARD))
+                       keys_fwd = STRAFEHUD_KEYS_FORWARD;
+               else if(!(keys & KEY_FORWARD) && (keys & KEY_BACKWARD))
+                       keys_fwd = STRAFEHUD_KEYS_BACKWARD;
+               else
+                       keys_fwd = STRAFEHUD_KEYS_NONE;
+       }
 
-               // determine whether the player is pressing forwards or backwards keys
-               int keys_fwd;
-               if(islocal) // if entity is local player
-               {
-                       if(movement.x > 0)
-                               keys_fwd = STRAFEHUD_KEYS_FORWARD;
-                       else if(movement.x < 0)
-                               keys_fwd = STRAFEHUD_KEYS_BACKWARD;
-                       else
-                               keys_fwd = STRAFEHUD_KEYS_NONE;
-               }
-               else // alternatively determine direction by querying pressed keys
-               {
-                       if((keys & KEY_FORWARD) && !(keys & KEY_BACKWARD))
-                               keys_fwd = STRAFEHUD_KEYS_FORWARD;
-                       else if(!(keys & KEY_FORWARD) && (keys & KEY_BACKWARD))
-                               keys_fwd = STRAFEHUD_KEYS_BACKWARD;
-                       else
-                               keys_fwd = STRAFEHUD_KEYS_NONE;
-               }
+       float wishangle = StrafeHUD_DetermineWishAngle(movement, keys, islocal);
+       bool strafekeys = fabs(wishangle) > 45;
 
-               float wishangle = StrafeHUD_DetermineWishAngle(movement, keys, islocal);
-               bool strafekeys = fabs(wishangle) > 45;
+       float hudangle = StrafeHUD_DetermineHudAngle(wishangle);
 
-               float hudangle = StrafeHUD_DetermineHudAngle(wishangle);
+       // detect air strafe turning
+       static bool turn = false;
+       if((!strafekeys && vlen(vec2(movement)) > 0) || onground || autocvar__hud_configure)
+       {
+               turn = false;
+       }
+       else // air strafe only
+       {
+               static float turn_lasttime = 0;
+               static float turnangle;
+               bool turn_expired = (time - turn_lasttime) >= autocvar_hud_panel_strafehud_timeout_turn; // timeout for jumping with strafe keys only
 
-               // detect air strafe turning
-               static bool turn = false;
-               if((!strafekeys && vlen(vec2(movement)) > 0) || onground || autocvar__hud_configure)
-               {
+               if(strafekeys)
+                       turn = true;
+               else if(turn_expired)
                        turn = false;
-               }
-               else // air strafe only
-               {
-                       static float turn_lasttime = 0;
-                       static float turnangle;
-                       bool turn_expired = (time - turn_lasttime) >= autocvar_hud_panel_strafehud_timeout_turn; // timeout for jumping with strafe keys only
 
+               if(turn) // CPMA turning
+               {
                        if(strafekeys)
-                               turn = true;
-                       else if(turn_expired)
-                               turn = false;
-
-                       if(turn) // CPMA turning
                        {
-                               if(strafekeys)
-                               {
-                                       turn_lasttime = time;
-                                       turnangle = wishangle;
-                               }
-                               else // retain last state until strafe turning times out
-                               {
-                                       wishangle = turnangle;
-                               }
-
-                               // calculate the maximum air strafe speed and acceleration
-                               float strafity = 1 - (90 - fabs(wishangle)) / 45;
-
-                               if(PHYS_MAXAIRSTRAFESPEED(strafeplayer) != 0)
-                                       maxspeed = min(maxspeed, GeomLerp(PHYS_MAXAIRSPEED(strafeplayer), strafity, PHYS_MAXAIRSTRAFESPEED(strafeplayer)));
-
-                               movespeed = min(movespeed, maxspeed);
-
-                               if(PHYS_AIRSTRAFEACCELERATE(strafeplayer) != 0)
-                                       maxaccel = GeomLerp(PHYS_AIRACCELERATE(strafeplayer), strafity, PHYS_AIRSTRAFEACCELERATE(strafeplayer));
+                               turn_lasttime = time;
+                               turnangle = wishangle;
                        }
+                       else // retain last state until strafe turning times out
+                       {
+                               wishangle = turnangle;
+                       }
+
+                       // calculate the maximum air strafe speed and acceleration
+                       float strafity = 1 - (90 - fabs(wishangle)) / 45;
+
+                       if(PHYS_MAXAIRSTRAFESPEED(strafeplayer) != 0)
+                               maxspeed = min(maxspeed, GeomLerp(PHYS_MAXAIRSPEED(strafeplayer), strafity, PHYS_MAXAIRSTRAFESPEED(strafeplayer)));
+
+                       movespeed = min(movespeed, maxspeed);
+
+                       if(PHYS_AIRSTRAFEACCELERATE(strafeplayer) != 0)
+                               maxaccel = GeomLerp(PHYS_AIRACCELERATE(strafeplayer), strafity, PHYS_AIRSTRAFEACCELERATE(strafeplayer));
                }
+       }
 
-               float dt = StrafeHUD_DetermineFrameTime();
+       float dt = StrafeHUD_DetermineFrameTime();
 
-               maxaccel *= dt * movespeed;
-               float bestspeed = max(movespeed - maxaccel, 0); // target speed to gain maximum acceleration
+       maxaccel *= dt * movespeed;
+       float bestspeed = max(movespeed - maxaccel, 0); // target speed to gain maximum acceleration
 
-               // use local csqcmodel entity for this even when spectating, flickers too much otherwise
-               float speed = !autocvar__hud_configure ? vlen(vec2(csqcplayer.velocity)) : 1337;
-               bool moving = speed > 0;
+       // use local csqcmodel entity for this even when spectating, flickers too much otherwise
+       float speed = !autocvar__hud_configure ? vlen(vec2(csqcplayer.velocity)) : 1337;
+       bool moving = speed > 0;
 
-               float frictionspeed; // speed lost from friction
-               float strafespeed; // speed minus friction
+       float frictionspeed; // speed lost from friction
+       float strafespeed; // speed minus friction
 
-               if(moving && onground)
-               {
-                       float strafefriction = onslick ? PHYS_FRICTION_SLICK(strafeplayer) : PHYS_FRICTION(strafeplayer);
+       if(moving && onground)
+       {
+               float strafefriction = onslick ? PHYS_FRICTION_SLICK(strafeplayer) : PHYS_FRICTION(strafeplayer);
 
-                       frictionspeed = speed * dt * strafefriction * max(PHYS_STOPSPEED(strafeplayer) / speed, 1);
-                       strafespeed = max(speed - frictionspeed, 0);
-               }
-               else
-               {
-                       frictionspeed = 0;
-                       strafespeed = speed;
-               }
+               frictionspeed = speed * dt * strafefriction * max(PHYS_STOPSPEED(strafeplayer) / speed, 1);
+               strafespeed = max(speed - frictionspeed, 0);
+       }
+       else
+       {
+               frictionspeed = 0;
+               strafespeed = speed;
+       }
 
-               // get current strafing angle ranging from -180° to +180°
-               float angle;
-               bool fwd;
+       // get current strafing angle ranging from -180° to +180°
+       float angle;
+       bool fwd;
 
-               if(!autocvar__hud_configure)
+       if(!autocvar__hud_configure)
+       {
+               if(moving)
                {
-                       if(moving)
+                       // change the range from 0° - 360° to -180° - 180° to match how view_angle represents angles
+                       float vel_angle = vectoangles(strafeplayer.velocity).y - (vectoangles(strafeplayer.velocity).y > 180 ? 360 : 0);
+                       float view_angle = PHYS_INPUT_ANGLES(strafeplayer).y;
+
+                       // calculate view angle relative to the players current velocity direction
+                       angle = vel_angle - view_angle;
+
+                       // if the angle goes above 180° or below -180° wrap it to the opposite side since we want the interior angle
+                       if(angle > 180)
+                               angle -= 360;
+                       else if(angle < -180)
+                               angle += 360;
+
+                       // determine whether the player is strafing forwards or backwards
+                       // if the player is not strafe turning use forwards/backwards keys to determine direction
+                       if(fabs(wishangle) != 90)
                        {
-                               // change the range from 0° - 360° to -180° - 180° to match how view_angle represents angles
-                               float vel_angle = vectoangles(strafeplayer.velocity).y - (vectoangles(strafeplayer.velocity).y > 180 ? 360 : 0);
-                               float view_angle = PHYS_INPUT_ANGLES(strafeplayer).y;
-
-                               // calculate view angle relative to the players current velocity direction
-                               angle = vel_angle - view_angle;
-
-                               // if the angle goes above 180° or below -180° wrap it to the opposite side since we want the interior angle
-                               if(angle > 180)
-                                       angle -= 360;
-                               else if(angle < -180)
-                                       angle += 360;
-
-                               // determine whether the player is strafing forwards or backwards
-                               // if the player is not strafe turning use forwards/backwards keys to determine direction
-                               if(fabs(wishangle) != 90)
-                               {
-                                       if(keys_fwd == STRAFEHUD_KEYS_FORWARD)
-                                               fwd = true;
-                                       else if(keys_fwd == STRAFEHUD_KEYS_BACKWARD)
-                                               fwd = false;
-                                       else
-                                               fwd = fabs(angle) <= 90;
-                               }
-                               // otherwise determine by examining the strafe angle
+                               if(keys_fwd == STRAFEHUD_KEYS_FORWARD)
+                                       fwd = true;
+                               else if(keys_fwd == STRAFEHUD_KEYS_BACKWARD)
+                                       fwd = false;
                                else
-                               {
-                                       if(wishangle < 0) // detect direction using wishangle since the direction is not yet set
-                                               fwd = angle <= -wishangle;
-                                       else
-                                               fwd = angle >= -wishangle;
-                               }
-
-                               // shift the strafe angle by 180° when strafing backwards
-                               if(!fwd)
-                               {
-                                       if(angle < 0)
-                                               angle += 180;
-                                       else
-                                               angle -= 180;
-                               }
+                                       fwd = fabs(angle) <= 90;
                        }
+                       // otherwise determine by examining the strafe angle
                        else
                        {
-                               angle = 0;
-                               fwd = true;
+                               if(wishangle < 0) // detect direction using wishangle since the direction is not yet set
+                                       fwd = angle <= -wishangle;
+                               else
+                                       fwd = angle >= -wishangle;
                        }
-               }
-               else // simulate turning for HUD setup
-               {
-                       const float demo_maxangle = 55; // maximum angle before changing direction
-                       const float demo_turnspeed = 40; // turning speed in degrees per second
-                       static float demo_position = -37 / demo_maxangle; // current positioning value between -1 and +1
 
-                       if(autocvar__hud_panel_strafehud_demo)
+                       // shift the strafe angle by 180° when strafing backwards
+                       if(!fwd)
                        {
-                               float demo_dt = time - hud_lasttime;
-                               float demo_step = (demo_turnspeed / demo_maxangle) * demo_dt;
-                               demo_position = ((demo_position + demo_step) % 4 + 4) % 4;
+                               if(angle < 0)
+                                       angle += 180;
+                               else
+                                       angle -= 180;
                        }
-
-                       // triangle wave function
-                       if(demo_position > 3)
-                               angle = -1 + (demo_position - 3);
-                       else if(demo_position > 1)
-                               angle = +1 - (demo_position - 1);
-                       else
-                               angle = demo_position;
-                       angle *= demo_maxangle;
-
+               }
+               else
+               {
+                       angle = 0;
                        fwd = true;
-                       wishangle = 45;
-                       if(angle < 0)
-                               wishangle *= -1;
                }
+       }
+       else // simulate turning for HUD setup
+       {
+               const float demo_maxangle = 55; // maximum angle before changing direction
+               const float demo_turnspeed = 40; // turning speed in degrees per second
+               static float demo_position = -37 / demo_maxangle; // current positioning value between -1 and +1
 
-               // invert the wish angle when strafing backwards
-               if(!fwd)
-                       wishangle *= -1;
-
-               // flip angles if v_flipped is enabled
-               if(autocvar_v_flipped)
+               if(autocvar__hud_panel_strafehud_demo)
                {
-                       angle *= -1;
-                       wishangle *= -1;
+                       float demo_dt = time - hud_lasttime;
+                       float demo_step = (demo_turnspeed / demo_maxangle) * demo_dt;
+                       demo_position = ((demo_position + demo_step) % 4 + 4) % 4;
                }
 
-               // best angle to strafe at
-               // in case of ground friction we may decelerate if the acceleration is smaller than the speed loss from friction
-               float bestangle    = (strafespeed > bestspeed ? acos(bestspeed / strafespeed) * RAD2DEG : 0);
-               float prebestangle = (strafespeed > movespeed ? acos(movespeed / strafespeed) * RAD2DEG : 0);
-               float opposite_bestangle = -bestangle;
+               // triangle wave function
+               if(demo_position > 3)
+                       angle = -1 + (demo_position - 3);
+               else if(demo_position > 1)
+                       angle = +1 - (demo_position - 1);
+               else
+                       angle = demo_position;
+               angle *= demo_maxangle;
 
-               // absolute_* variables which are always positive with no wishangle offset
-               float absolute_bestangle = bestangle;
-               float absolute_prebestangle = prebestangle;
+               fwd = true;
+               wishangle = 45;
+               if(angle < 0)
+                       wishangle *= -1;
+       }
 
-               float antiflicker_angle = bound(0, autocvar_hud_panel_strafehud_antiflicker_angle, 180);
-               float direction = StrafeHUD_DetermineDirection(angle, wishangle, antiflicker_angle);
+       // invert the wish angle when strafing backwards
+       if(!fwd)
+               wishangle *= -1;
 
-               if(direction == STRAFEHUD_DIRECTION_LEFT) // the angle becomes negative in case we strafe left
-               {
-                       bestangle *= -1;
-                       opposite_bestangle *= -1;
-                       prebestangle *= -1;
-               }
+       // flip angles if v_flipped is enabled
+       if(autocvar_v_flipped)
+       {
+               angle *= -1;
+               wishangle *= -1;
+       }
 
-               bestangle -= wishangle;
-               opposite_bestangle -= wishangle;
-               prebestangle -= wishangle;
+       // best angle to strafe at
+       // in case of ground friction we may decelerate if the acceleration is smaller than the speed loss from friction
+       float bestangle    = (strafespeed > bestspeed ? acos(bestspeed / strafespeed) * RAD2DEG : 0);
+       float prebestangle = (strafespeed > movespeed ? acos(movespeed / strafespeed) * RAD2DEG : 0);
+       float opposite_bestangle = -bestangle;
 
-               int mode;
-               if(autocvar_hud_panel_strafehud_mode >= 0 && autocvar_hud_panel_strafehud_mode <= 1)
-                       mode = autocvar_hud_panel_strafehud_mode;
-               else
-                       mode = STRAFEHUD_MODE_VIEW_CENTERED;
+       // absolute_* variables which are always positive with no wishangle offset
+       float absolute_bestangle = bestangle;
+       float absolute_prebestangle = prebestangle;
 
-               // best strafe acceleration angle
-               float changeangle = -bestangle;
+       float antiflicker_angle = bound(0, autocvar_hud_panel_strafehud_antiflicker_angle, 180);
+       float direction = StrafeHUD_DetermineDirection(angle, wishangle, antiflicker_angle);
 
-               bool opposite_direction = false;
-               float opposite_changeangle = 0;
-               if((angle > -wishangle && direction == STRAFEHUD_DIRECTION_LEFT) || (angle < -wishangle && direction == STRAFEHUD_DIRECTION_RIGHT))
-               {
-                       opposite_direction = true;
-                       opposite_changeangle = opposite_bestangle + bestangle * 2;
-               }
+       if(direction == STRAFEHUD_DIRECTION_LEFT) // the angle becomes negative in case we strafe left
+       {
+               bestangle *= -1;
+               opposite_bestangle *= -1;
+               prebestangle *= -1;
+       }
 
-               // shift hud if operating in view angle centered mode
-               float shiftangle = 0;
-               if(mode == STRAFEHUD_MODE_VIEW_CENTERED)
-               {
-                       shiftangle = -angle;
-                       bestangle += shiftangle;
-                       changeangle += shiftangle;
-                       opposite_bestangle += shiftangle;
-                       opposite_changeangle += shiftangle;
-               }
+       bestangle -= wishangle;
+       opposite_bestangle -= wishangle;
+       prebestangle -= wishangle;
+
+       int mode;
+       if(autocvar_hud_panel_strafehud_mode >= 0 && autocvar_hud_panel_strafehud_mode <= 1)
+               mode = autocvar_hud_panel_strafehud_mode;
+       else
+               mode = STRAFEHUD_MODE_VIEW_CENTERED;
 
-               StrafeHUD_DrawStrafeMeter(shiftangle, wishangle, absolute_bestangle, absolute_prebestangle, moving, hudangle);
+       // best strafe acceleration angle
+       float changeangle = -bestangle;
 
-               float text_offset_top;
-               float text_offset_bottom;
-               text_offset_top = text_offset_bottom = StrafeHUD_DrawSlickDetector(strafeplayer, real_onslick);
+       bool opposite_direction = false;
+       float opposite_changeangle = 0;
+       if((angle > -wishangle && direction == STRAFEHUD_DIRECTION_LEFT) || (angle < -wishangle && direction == STRAFEHUD_DIRECTION_RIGHT))
+       {
+               opposite_direction = true;
+               opposite_changeangle = opposite_bestangle + bestangle * 2;
+       }
 
-               StrafeHUD_DrawDirectionIndicator(direction, opposite_direction, fwd);
+       // shift hud if operating in view angle centered mode
+       float shiftangle = 0;
+       if(mode == STRAFEHUD_MODE_VIEW_CENTERED)
+       {
+               shiftangle = -angle;
+               bestangle += shiftangle;
+               changeangle += shiftangle;
+               opposite_bestangle += shiftangle;
+               opposite_changeangle += shiftangle;
+       }
 
-               // determine the strafing ratio and the angle indicator color
-               vector currentangle_color = autocvar_hud_panel_strafehud_angle_neutral_color;
-               float strafe_ratio = 0;
-               if(moving)
-               {
-                       float moveangle = fabs(angle + wishangle);
+       StrafeHUD_DrawStrafeMeter(shiftangle, wishangle, absolute_bestangle, absolute_prebestangle, moving, hudangle);
 
-                       // player is overturning
-                       if(moveangle >= 90)
-                       {
-                               currentangle_color = autocvar_hud_panel_strafehud_angle_overturn_color;
-                               strafe_ratio = (moveangle - 90) / 90;
-                               if(strafe_ratio > 1) strafe_ratio = 2 - strafe_ratio;
-                               strafe_ratio *= -1;
-                       }
-                       // player gains speed by strafing
-                       else if(moveangle >= absolute_bestangle)
-                       {
-                               currentangle_color = autocvar_hud_panel_strafehud_angle_accel_color;
-                               strafe_ratio = (90 - moveangle) / (90 - absolute_bestangle);
-                       }
-                       else if(moveangle >= absolute_prebestangle)
-                       {
-                               if(autocvar_hud_panel_strafehud_bar_preaccel)
-                                       currentangle_color = autocvar_hud_panel_strafehud_angle_accel_color;
-                               strafe_ratio = (moveangle - absolute_prebestangle) / (absolute_bestangle - absolute_prebestangle);
-                       }
+       float text_offset_top;
+       float text_offset_bottom;
+       text_offset_top = text_offset_bottom = StrafeHUD_DrawSlickDetector(strafeplayer, real_onslick);
 
-                       if(autocvar_hud_panel_strafehud_style == STRAFEHUD_STYLE_GRADIENT || autocvar_hud_panel_strafehud_style == STRAFEHUD_STYLE_FAST_GRADIENT)
-                               currentangle_color = StrafeHUD_MixColors(
-                                       autocvar_hud_panel_strafehud_angle_neutral_color,
-                                       currentangle_color, fabs(strafe_ratio));
-               }
+       StrafeHUD_DrawDirectionIndicator(direction, opposite_direction, fwd);
 
-               float currentangle = 0;
-               if(mode == STRAFEHUD_MODE_VELOCITY_CENTERED)
+       // determine the strafing ratio and the angle indicator color
+       vector currentangle_color = autocvar_hud_panel_strafehud_angle_neutral_color;
+       float strafe_ratio = 0;
+       if(moving)
+       {
+               float moveangle = fabs(angle + wishangle);
+
+               // player is overturning
+               if(moveangle >= 90)
+               {
+                       currentangle_color = autocvar_hud_panel_strafehud_angle_overturn_color;
+                       strafe_ratio = (moveangle - 90) / 90;
+                       if(strafe_ratio > 1) strafe_ratio = 2 - strafe_ratio;
+                       strafe_ratio *= -1;
+               }
+               // player gains speed by strafing
+               else if(moveangle >= absolute_bestangle)
                {
-                       // avoid switching side too much at ±180° if anti flicker is triggered
-                       if(fabs(angle) <= 180 - antiflicker_angle)
-                               currentangle = angle;
+                       currentangle_color = autocvar_hud_panel_strafehud_angle_accel_color;
+                       strafe_ratio = (90 - moveangle) / (90 - absolute_bestangle);
+               }
+               else if(moveangle >= absolute_prebestangle)
+               {
+                       if(autocvar_hud_panel_strafehud_bar_preaccel)
+                               currentangle_color = autocvar_hud_panel_strafehud_angle_accel_color;
+                       strafe_ratio = (moveangle - absolute_prebestangle) / (absolute_bestangle - absolute_prebestangle);
                }
 
-               // current angle size calculation
-               vector currentangle_size;
-               currentangle_size.x = max(panel_size.x * min(autocvar_hud_panel_strafehud_angle_width, 10), 1);
-               currentangle_size.y = max(panel_size.y * min(autocvar_hud_panel_strafehud_angle_height, 10), 1);
-               currentangle_size.z = 0;
+               if(autocvar_hud_panel_strafehud_style == STRAFEHUD_STYLE_GRADIENT || autocvar_hud_panel_strafehud_style == STRAFEHUD_STYLE_FAST_GRADIENT)
+                       currentangle_color = StrafeHUD_MixColors(
+                               autocvar_hud_panel_strafehud_angle_neutral_color,
+                               currentangle_color, fabs(strafe_ratio));
+       }
 
-               float num_dashes = nearbyint(autocvar_hud_panel_strafehud_angle_dashes);
+       float currentangle = 0;
+       if(mode == STRAFEHUD_MODE_VELOCITY_CENTERED)
+       {
+               // avoid switching side too much at ±180° if anti flicker is triggered
+               if(fabs(angle) <= 180 - antiflicker_angle)
+                       currentangle = angle;
+       }
 
-               // adjust angle indicator line depending on style
-               switch(autocvar_hud_panel_strafehud_angle_style)
-               {
-                       case STRAFEHUD_INDICATOR_DASHED:
-                               break;
-                       case STRAFEHUD_INDICATOR_SOLID:
-                               num_dashes = 1;
-                               break;
-                       case STRAFEHUD_INDICATOR_NONE:
-                       default:
-                               num_dashes = 0;
-                               break;
-               }
+       // current angle size calculation
+       vector currentangle_size;
+       currentangle_size.x = max(panel_size.x * min(autocvar_hud_panel_strafehud_angle_width, 10), 1);
+       currentangle_size.y = max(panel_size.y * min(autocvar_hud_panel_strafehud_angle_height, 10), 1);
+       currentangle_size.z = 0;
 
-               bool has_top_arrow = autocvar_hud_panel_strafehud_angle_arrow == 1 || autocvar_hud_panel_strafehud_angle_arrow >= 3;
-               bool has_bottom_arrow = autocvar_hud_panel_strafehud_angle_arrow >= 2;
+       float num_dashes = nearbyint(autocvar_hud_panel_strafehud_angle_dashes);
 
-               // there's only one size cvar for the arrows, they will always have a 45° angle to ensure proper rendering without antialiasing
-               float arrow_size = max(panel_size.y * min(autocvar_hud_panel_strafehud_angle_arrow_size, 10), 1);
+       // adjust angle indicator line depending on style
+       switch(autocvar_hud_panel_strafehud_angle_style)
+       {
+               case STRAFEHUD_INDICATOR_DASHED:
+                       break;
+               case STRAFEHUD_INDICATOR_SOLID:
+                       num_dashes = 1;
+                       break;
+               case STRAFEHUD_INDICATOR_NONE:
+               default:
+                       num_dashes = 0;
+                       break;
+       }
 
-               if(num_dashes > 0 || has_top_arrow || has_bottom_arrow)
+       bool has_top_arrow = autocvar_hud_panel_strafehud_angle_arrow == 1 || autocvar_hud_panel_strafehud_angle_arrow >= 3;
+       bool has_bottom_arrow = autocvar_hud_panel_strafehud_angle_arrow >= 2;
+
+       // there's only one size cvar for the arrows, they will always have a 45° angle to ensure proper rendering without antialiasing
+       float arrow_size = max(panel_size.y * min(autocvar_hud_panel_strafehud_angle_arrow_size, 10), 1);
+
+       if(num_dashes > 0 || has_top_arrow || has_bottom_arrow)
+       {
+               bool angle_indicator_visible = false;
+
+               // minimum speed for change indicators
+               float minspeed = autocvar_hud_panel_strafehud_switch_minspeed;
+               if(minspeed < 0)
+                       minspeed = bestspeed + frictionspeed;
+
+               // only draw change indicators if minspeed is reached
+               if(autocvar_hud_panel_strafehud_switch && speed >= minspeed)
                {
-                       bool angle_indicator_visible = false;
+                       // draw the change indicator(s)
+                       float current_changeangle = opposite_direction ? opposite_changeangle : changeangle;
+                       float opposite_changeangle = opposite_direction ? opposite_bestangle : bestangle;
 
-                       // minimum speed for change indicators
-                       float minspeed = autocvar_hud_panel_strafehud_switch_minspeed;
-                       if(minspeed < 0)
-                               minspeed = bestspeed + frictionspeed;
+                       StrafeHUD_DrawAngleIndicator(
+                               current_changeangle, currentangle_size, arrow_size, num_dashes,
+                               has_top_arrow, has_bottom_arrow, autocvar_hud_panel_strafehud_switch_color,
+                               autocvar_hud_panel_strafehud_switch_alpha, hudangle);
 
-                       // only draw change indicators if minspeed is reached
-                       if(autocvar_hud_panel_strafehud_switch && speed >= minspeed)
+                       if(direction == STRAFEHUD_DIRECTION_NONE)
                        {
-                               // draw the change indicator(s)
-                               float current_changeangle = opposite_direction ? opposite_changeangle : changeangle;
-                               float opposite_changeangle = opposite_direction ? opposite_bestangle : bestangle;
-
                                StrafeHUD_DrawAngleIndicator(
-                                       current_changeangle, currentangle_size, arrow_size, num_dashes,
+                                       opposite_changeangle, currentangle_size, arrow_size, num_dashes,
                                        has_top_arrow, has_bottom_arrow, autocvar_hud_panel_strafehud_switch_color,
                                        autocvar_hud_panel_strafehud_switch_alpha, hudangle);
-
-                               if(direction == STRAFEHUD_DIRECTION_NONE)
-                               {
-                                       StrafeHUD_DrawAngleIndicator(
-                                               opposite_changeangle, currentangle_size, arrow_size, num_dashes,
-                                               has_top_arrow, has_bottom_arrow, autocvar_hud_panel_strafehud_switch_color,
-                                               autocvar_hud_panel_strafehud_switch_alpha, hudangle);
-                               }
-
-                               if(autocvar_hud_panel_strafehud_switch_alpha > 0)
-                                       angle_indicator_visible = true;
                        }
 
-                       if(autocvar_hud_panel_strafehud_bestangle && direction != STRAFEHUD_DIRECTION_NONE)
-                       {
-                               float ghostangle = opposite_direction ? opposite_bestangle : bestangle;
-
-                               StrafeHUD_DrawAngleIndicator(
-                                       ghostangle, currentangle_size, arrow_size, num_dashes,
-                                       has_top_arrow, has_bottom_arrow, autocvar_hud_panel_strafehud_bestangle_color,
-                                       autocvar_hud_panel_strafehud_bestangle_alpha, hudangle);
+                       if(autocvar_hud_panel_strafehud_switch_alpha > 0)
+                               angle_indicator_visible = true;
+               }
 
-                               if(autocvar_hud_panel_strafehud_bestangle_alpha > 0)
-                                       angle_indicator_visible = true;
-                       }
+               if(autocvar_hud_panel_strafehud_bestangle && direction != STRAFEHUD_DIRECTION_NONE)
+               {
+                       float ghostangle = opposite_direction ? opposite_bestangle : bestangle;
 
                        StrafeHUD_DrawAngleIndicator(
-                               currentangle, currentangle_size, arrow_size, num_dashes,
-                               has_top_arrow, has_bottom_arrow, currentangle_color,
-                               autocvar_hud_panel_strafehud_angle_alpha, hudangle);
+                               ghostangle, currentangle_size, arrow_size, num_dashes,
+                               has_top_arrow, has_bottom_arrow, autocvar_hud_panel_strafehud_bestangle_color,
+                               autocvar_hud_panel_strafehud_bestangle_alpha, hudangle);
 
-                       if(autocvar_hud_panel_strafehud_angle_alpha > 0)
+                       if(autocvar_hud_panel_strafehud_bestangle_alpha > 0)
                                angle_indicator_visible = true;
+               }
 
-                       // offset text by amount the angle indicator extrudes from the strafehud bar
-                       if(angle_indicator_visible)
-                       {
-                               float line_height_offset = currentangle_size.y;
+               StrafeHUD_DrawAngleIndicator(
+                       currentangle, currentangle_size, arrow_size, num_dashes,
+                       has_top_arrow, has_bottom_arrow, currentangle_color,
+                       autocvar_hud_panel_strafehud_angle_alpha, hudangle);
 
-                               // amount line extrudes from the strafehud bar
-                               line_height_offset = (line_height_offset - panel_size.y) / 2;
+               if(autocvar_hud_panel_strafehud_angle_alpha > 0)
+                       angle_indicator_visible = true;
 
-                               // further offset the top text offset if the top arrow is drawn
-                               float angle_offset_top;
-                               if(has_top_arrow)
-                                       angle_offset_top = line_height_offset + arrow_size;
-                               else if(num_dashes > 0)
-                                       angle_offset_top = line_height_offset;
-                               else
-                                       angle_offset_top = 0;
-
-                               // further offset the bottom text offset if the bottom arrow is drawn
-                               float angle_offset_bottom;
-                               if(has_bottom_arrow)
-                                       angle_offset_bottom = line_height_offset + arrow_size;
-                               else if(num_dashes > 0)
-                                       angle_offset_bottom = line_height_offset;
-                               else
-                                       angle_offset_bottom = 0;
+               // offset text by amount the angle indicator extrudes from the strafehud bar
+               if(angle_indicator_visible)
+               {
+                       float line_height_offset = currentangle_size.y;
 
-                               // make sure text does not draw inside the strafehud bar
-                               text_offset_top = max(angle_offset_top, text_offset_top);
-                               text_offset_bottom = max(angle_offset_bottom, text_offset_bottom);
-                       }
+                       // amount line extrudes from the strafehud bar
+                       line_height_offset = (line_height_offset - panel_size.y) / 2;
+
+                       // further offset the top text offset if the top arrow is drawn
+                       float angle_offset_top;
+                       if(has_top_arrow)
+                               angle_offset_top = line_height_offset + arrow_size;
+                       else if(num_dashes > 0)
+                               angle_offset_top = line_height_offset;
+                       else
+                               angle_offset_top = 0;
+
+                       // further offset the bottom text offset if the bottom arrow is drawn
+                       float angle_offset_bottom;
+                       if(has_bottom_arrow)
+                               angle_offset_bottom = line_height_offset + arrow_size;
+                       else if(num_dashes > 0)
+                               angle_offset_bottom = line_height_offset;
+                       else
+                               angle_offset_bottom = 0;
+
+                       // make sure text does not draw inside the strafehud bar
+                       text_offset_top = max(angle_offset_top, text_offset_top);
+                       text_offset_bottom = max(angle_offset_bottom, text_offset_bottom);
                }
+       }
 
-               text_offset_bottom += StrafeHUD_DrawVerticalAngle(text_offset_bottom);
+       text_offset_bottom += StrafeHUD_DrawVerticalAngle(text_offset_bottom);
 
-               draw_beginBoldFont();
-               text_offset_bottom += StrafeHUD_DrawStartSpeed(speed, text_offset_bottom);
-               text_offset_top += StrafeHUD_DrawStrafeEfficiency(strafe_ratio, text_offset_top);
-               text_offset_top += StrafeHUD_DrawJumpHeight(strafeplayer, real_onground, swimming, text_offset_top);
-               draw_endBoldFont();
+       draw_beginBoldFont();
+       text_offset_bottom += StrafeHUD_DrawStartSpeed(speed, text_offset_bottom);
+       text_offset_top += StrafeHUD_DrawStrafeEfficiency(strafe_ratio, text_offset_top);
+       text_offset_top += StrafeHUD_DrawJumpHeight(strafeplayer, real_onground, swimming, text_offset_top);
+       draw_endBoldFont();
 
-               StrafeHUD_Sonar(strafe_ratio, StrafeHUD_UpdateSonarSound());
-       }
+       StrafeHUD_Sonar(strafe_ratio, StrafeHUD_UpdateSonarSound());
 
        hud_lasttime = time;
 }