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;
}