static float onground_lasttime = 0;
static bool onslick_last = false;
-
if(onground)
{
if(PHYS_FRICTION(strafeplayer) == 0)
else
movespeed = min(movespeed, maxspeed);
- float dt = DetectFrameTime();
-
// determine whether the player is pressing forwards or backwards keys
int keys_fwd;
if(islocal) // if entity is local player
}
}
+ float dt = DetectFrameTime();
+
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;
float frictionspeed; // speed lost from friction
float strafespeed; // speed minus friction
- if((speed > 0) && onground)
+ if(moving && onground)
{
float strafefriction = onslick ? PHYS_FRICTION_SLICK(strafeplayer) : PHYS_FRICTION(strafeplayer);
strafespeed = speed;
}
- float minspeed = autocvar_hud_panel_strafehud_switch_minspeed;
- if(minspeed < 0)
- minspeed = bestspeed + frictionspeed;
-
// get current strafing angle ranging from -180° to +180°
float angle;
bool fwd;
- bool straight_overturn = false;
- float antiflicker_angle = bound(0, autocvar_hud_panel_strafehud_antiflicker_angle, 180);
if(!autocvar__hud_configure)
{
- if(speed > 0)
+ 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);
else
angle -= 180;
}
-
- // do not make the angle indicator switch side too much at ±180° if anti flicker is turned on
- if(angle > (180 - antiflicker_angle) || angle < (-180 + antiflicker_angle))
- straight_overturn = true;
}
else
{
float absolute_bestangle = bestangle;
float absolute_prebestangle = prebestangle;
+ float antiflicker_angle = bound(0, autocvar_hud_panel_strafehud_antiflicker_angle, 180);
float direction = StrafeHUD_determineDirection(angle, wishangle, antiflicker_angle);
if(direction == STRAFEHUD_DIRECTION_LEFT) // the angle becomes negative in case we strafe left
// best strafe acceleration angle
float changeangle = -bestangle;
- float bestangle_width = max(panel_size.x * autocvar_hud_panel_strafehud_switch_width, 1);
bool opposite_direction = false;
float opposite_changeangle = 0;
opposite_changeangle = opposite_bestangle + bestangle * 2;
}
- bool immobile = speed <= 0;
-
- float currentangle = angle;
- if(mode == STRAFEHUD_MODE_VELOCITY_CENTERED)
- currentangle = bound(-hudangle / 2, currentangle, hudangle / 2);
-
// shift hud if operating in view angle centered mode
float shift_angle = 0;
if(mode == STRAFEHUD_MODE_VIEW_CENTERED)
{
- shift_angle = -currentangle;
+ shift_angle = -angle;
bestangle += shift_angle;
changeangle += shift_angle;
opposite_bestangle += shift_angle;
opposite_changeangle += shift_angle;
}
- if(mode == STRAFEHUD_MODE_VIEW_CENTERED || straight_overturn)
- currentangle = 0;
-
- currentangle = StrafeHUD_projectAngle(currentangle, hudangle, false);
-
StrafeHUD_DrawStrafeMeter(
- speed, minspeed, shift_angle, wishangle, currentangle, changeangle, bestangle,
- bestangle_width, absolute_bestangle, absolute_prebestangle,
- opposite_bestangle, opposite_changeangle, immobile,
- opposite_direction, direction, hudangle);
+ speed, bestspeed, frictionspeed, shift_angle, wishangle, changeangle, bestangle,
+ absolute_bestangle, absolute_prebestangle, opposite_bestangle, opposite_changeangle,
+ moving, opposite_direction, direction, hudangle);
float text_offset_top;
float text_offset_bottom;
StrafeHUD_DrawDirectionIndicator(direction, opposite_direction, fwd);
vector angle_indicator_info = StrafeHUD_DrawAngleIndicator(
- angle, wishangle, currentangle, bestangle, absolute_bestangle,
- absolute_prebestangle, opposite_bestangle, immobile,
- opposite_direction, direction, hudangle);
+ angle, wishangle, bestangle, absolute_bestangle,
+ absolute_prebestangle, opposite_bestangle, antiflicker_angle,
+ moving, opposite_direction, direction, mode, hudangle);
// unpack return value from vector
float strafe_ratio = angle_indicator_info.x;
int autocvar_hud_panel_strafehud = 3;
bool autocvar__hud_panel_strafehud_demo = false;
-bool autocvar_hud_panel_strafehud_dynamichud = true;
+bool autocvar_hud_panel_strafehud_dynamichud = true;
int autocvar_hud_panel_strafehud_mode = 0;
float autocvar_hud_panel_strafehud_range = 90;
int autocvar_hud_panel_strafehud_style = 2;
#include <client/draw.qh>
void StrafeHUD_DrawStrafeMeter(
- float speed, float minspeed, float shift_angle, float wishangle,
- float currentangle, float changeangle, float bestangle, float bestangle_width,
- float absolute_bestangle, float absolute_prebestangle,
- float opposite_bestangle, float opposite_changeangle,
- bool immobile, bool opposite_direction, int direction, float hudangle)
+ float speed, float bestspeed, float frictionspeed, float shift_angle, float wishangle,
+ float changeangle, float bestangle, float absolute_bestangle,
+ float absolute_prebestangle, float opposite_bestangle,
+ float opposite_changeangle, bool moving, bool opposite_direction,
+ int direction, float hudangle)
{
// the neutral zone fills the whole strafe bar
- if(immobile)
+ if(!moving)
{
// draw neutral zone
- if(panel_size.x > 0 && panel_size.y > 0 && autocvar_hud_panel_strafehud_bar_neutral_alpha * panel_fg_alpha > 0)
+ if(panel_size.x > 0 && panel_size.y > 0 && autocvar_hud_panel_strafehud_bar_neutral_alpha > 0)
{
switch(autocvar_hud_panel_strafehud_style)
{
}
else
{
+ // calculate various zones of the strafe-o-meter
float accelzone_left_startangle;
float accelzone_right_startangle;
- float accelzone_offsetangle;
float preaccelzone_left_startangle;
float preaccelzone_right_startangle;
- float preaccelzone_offsetangle;
+ float neutral_startangle;
float overturn_startangle;
- // calculate various zones of the strafe-o-meter
- if(autocvar_hud_panel_strafehud_bar_preaccel)
- preaccelzone_offsetangle = absolute_bestangle - absolute_prebestangle;
- else
+ float accelzone_offsetangle = 90 - absolute_bestangle;
+ float preaccelzone_offsetangle = absolute_bestangle - absolute_prebestangle;
+ float neutral_offsetangle = 360;
+ float overturn_offsetangle = 180;
+
+ if(!autocvar_hud_panel_strafehud_bar_preaccel)
preaccelzone_offsetangle = 0;
- accelzone_offsetangle = 90 - absolute_bestangle;
+ // assign starting angles and shift the current offset for every element
+ float current_startangle = 0;
- float overturn_offsetangle = 180;
- float neutral_offsetangle = 360 - accelzone_offsetangle * 2 - preaccelzone_offsetangle * 2 - overturn_offsetangle;
- float neutral_startangle;
+ preaccelzone_right_startangle = current_startangle;
+ current_startangle += preaccelzone_offsetangle;
- {
- float current_offsetangle = 0;
- preaccelzone_right_startangle = current_offsetangle;
- current_offsetangle += preaccelzone_offsetangle;
-
- accelzone_right_startangle = current_offsetangle;
- current_offsetangle += accelzone_offsetangle;
+ accelzone_right_startangle = current_startangle;
+ current_startangle += accelzone_offsetangle;
- overturn_startangle = current_offsetangle;
- current_offsetangle += overturn_offsetangle;
+ overturn_startangle = current_startangle;
+ current_startangle += overturn_offsetangle;
- accelzone_left_startangle = current_offsetangle;
- current_offsetangle += accelzone_offsetangle;
+ accelzone_left_startangle = current_startangle;
+ current_startangle += accelzone_offsetangle;
- preaccelzone_left_startangle = current_offsetangle;
- current_offsetangle += preaccelzone_offsetangle;
+ preaccelzone_left_startangle = current_startangle;
+ current_startangle += preaccelzone_offsetangle;
- neutral_startangle = current_offsetangle;
- }
+ neutral_startangle = current_startangle;
+ neutral_offsetangle = 360 - current_startangle;
// calculate how far off-center the strafe zones currently are
shift_angle += neutral_offsetangle / 2 - wishangle;
autocvar_hud_panel_strafehud_style, STRAFEHUD_GRADIENT_NONE,
true, hudangle);
+ float minspeed = autocvar_hud_panel_strafehud_switch_minspeed;
+ if(minspeed < 0)
+ minspeed = bestspeed + frictionspeed;
+
// only draw indicators if minspeed is reached
- if(autocvar_hud_panel_strafehud_switch && speed >= minspeed && bestangle_width > 0 && autocvar_hud_panel_strafehud_switch_alpha > 0)
+ if(autocvar_hud_panel_strafehud_switch && speed >= minspeed && autocvar_hud_panel_strafehud_switch_alpha > 0)
{
// draw the change indicator(s)
- float offsetangle = !opposite_direction ? changeangle : opposite_changeangle;
- float opposite_offsetangle = !opposite_direction ? bestangle : opposite_bestangle;
+ float offsetangle = opposite_direction ? opposite_changeangle : changeangle;
+ float opposite_offsetangle = opposite_direction ? opposite_bestangle : bestangle;
- offsetangle = StrafeHUD_projectAngle(offsetangle, hudangle, false);
- opposite_offsetangle = StrafeHUD_projectAngle(opposite_offsetangle, hudangle, false);
+ float bestangle_width = max(panel_size.x * autocvar_hud_panel_strafehud_switch_width, 1);
// remove change indicator width from offset
if(direction == STRAFEHUD_DIRECTION_LEFT)
}
// draw the actual strafe angle
-vector StrafeHUD_DrawAngleIndicator(float angle, float wishangle, float currentangle,
+// TODO: break this apart so that each angle indicator is drawn in an individual function call
+vector StrafeHUD_DrawAngleIndicator(float angle, float wishangle,
float bestangle, float absolute_bestangle, float absolute_prebestangle,
- float opposite_bestangle, bool immobile, bool opposite_direction, int direction,
- float hudangle)
+ float opposite_bestangle, float antiflicker_angle, bool moving, bool opposite_direction, int direction,
+ int mode, float hudangle)
{
+ float currentangle = 0;
+ if(mode == STRAFEHUD_MODE_VELOCITY_CENTERED)
+ {
+ // avoid switching side too much at ±180° if within anti flicker is triggered
+ if(fabs(angle) <= (180 - antiflicker_angle))
+ // bound to HUD area
+ currentangle = bound(-hudangle / 2, angle, hudangle / 2);
+ currentangle = StrafeHUD_projectAngle(currentangle, hudangle, false);
+ }
+
vector currentangle_color = autocvar_hud_panel_strafehud_angle_neutral_color;
float strafe_ratio = 0;
- if(!immobile)
+ if(moving)
{
float moveangle = fabs(angle + wishangle);
}
// draw the arrows on the angle indicator
+// TODO: break this apart so that each angle indicator is drawn in an individual function call
vector StrafeHUD_DrawAngleIndicatorArrow(float currentangle, vector currentangle_size,
vector currentangle_color, float ghost_angle, float angleheight_offset,
int direction, float hudangle)
if(autocvar_hud_panel_strafehud_direction &&
direction != STRAFEHUD_DIRECTION_NONE &&
direction_size_vertical.x > 0 &&
- autocvar_hud_panel_strafehud_direction_alpha * panel_fg_alpha > 0)
+ autocvar_hud_panel_strafehud_direction_alpha > 0)
{
bool indicator_direction = direction == STRAFEHUD_DIRECTION_LEFT;
+
// invert left/right when strafing backwards or when strafing towards the opposite side indicated by the direction variable
// if both conditions are true then it's inverted twice hence not inverted at all
if(!fwd != opposite_direction)
#include "../strafehud.qh"
vector StrafeHUD_DrawAngleIndicatorArrow(
- float, vector, vector, float, float, int, float);
+ float, vector, vector, float, float, int, float);
vector StrafeHUD_DrawAngleIndicator(
- float, float, float, float, float, float,
- float, bool, bool, int, float);
+ float, float, float, float, float,
+ float, float, bool, bool, int, int, float);
void StrafeHUD_DrawDirectionIndicator(int, bool, bool);
void StrafeHUD_DrawStrafeMeter(
- float, float, float, float, float, float,
- float, float, float, float, float, float,
- bool, bool, int, float);
+ float, float, float, float, float, float, float,
+ float, float, float, float, bool, bool, int, float);
#include <client/draw.qh>
// functions to make hud elements align perfectly in the hud area
-void StrafeHUD_drawStrafeHUD(float startangle, float offsetangle, vector color, float alpha, int type, int gradientType, bool doProject, float range)
+void StrafeHUD_drawStrafeHUD(float startangle, float offsetangle, vector color, float alpha, int type, int gradientType, bool projectWidth, float range)
{
float offset = StrafeHUD_angleToOffset(startangle % 360, range);
float width = StrafeHUD_angleToWidth(offsetangle, range);
+ float mirror_offset;
+ float mirror_width;
- float mirror_offset, mirror_width;
- vector size = panel_size;
- vector mirror_size = panel_size;
- float overflow_width = 0, overflow_mirror_width = 0;
- float original_width = width; // required for gradient
-
- if(type == STRAFEHUD_STYLE_GRADIENT && gradientType == STRAFEHUD_GRADIENT_NONE)
- type = STRAFEHUD_STYLE_DRAWFILL;
+ if(type == STRAFEHUD_STYLE_GRADIENT)
+ {
+ projectWidth = true; // must be fully projected for gradients
+ if(gradientType == STRAFEHUD_GRADIENT_NONE)
+ type = STRAFEHUD_STYLE_DRAWFILL;
+ }
if(alpha <= 0 && type != STRAFEHUD_STYLE_GRADIENT || width <= 0)
return;
// how much is hidden by the current hud angle
float hidden_width = (360 - range) / range * panel_size.x;
+ float original_width = width; // required for gradient
if(offset < 0)
{
mirror_offset = max(offset - panel_size.x - hidden_width, 0);
}
+ float overflow_width = 0;
width = max(width, 0);
if((offset + width) > panel_size.x)
{
overflow_width = (offset + width) - panel_size.x;
width = panel_size.x - offset;
}
+ vector size = panel_size;
size.x = width;
float original_offset = offset;
- if(doProject)
- {
- if(size.x > 0) size.x = StrafeHUD_projectWidth(offset, size.x, range);
- offset = StrafeHUD_projectOffset(offset, range, false);
- }
+ if(projectWidth && size.x > 0)
+ size.x = StrafeHUD_projectWidth(offset, size.x, range);
+
+ offset = StrafeHUD_projectOffset(offset, range, false);
if(mirror_offset < 0)
{
mirror_offset = 0;
}
+ float overflow_mirror_width = 0;
mirror_width = max(mirror_width, 0);
if((mirror_offset + mirror_width) > panel_size.x)
{
overflow_mirror_width = (mirror_offset + mirror_width) - panel_size.x;
mirror_width = panel_size.x - mirror_offset;
}
+ vector mirror_size = panel_size;
mirror_size.x = mirror_width;
float original_mirror_offset = mirror_offset;
- if(doProject)
- {
- if(mirror_size.x > 0) mirror_size.x = StrafeHUD_projectWidth(mirror_offset, mirror_size.x, range);
- mirror_offset = StrafeHUD_projectOffset(mirror_offset, range, false);
- }
+ if(projectWidth && mirror_size.x > 0)
+ mirror_size.x = StrafeHUD_projectWidth(mirror_offset, mirror_size.x, range);
+
+ mirror_offset = StrafeHUD_projectOffset(mirror_offset, range, false);
switch(type)
{
StrafeHUD_drawGradient(
color, autocvar_hud_panel_strafehud_bar_neutral_color,
mirror_size, original_width, mirror_offset, original_mirror_offset,
- alpha, gradient_mirror_offset, gradientType, doProject, range);
+ alpha, gradient_mirror_offset, gradientType, range);
StrafeHUD_drawGradient(
color, autocvar_hud_panel_strafehud_bar_neutral_color,
size, original_width, offset, original_offset,
- alpha, gradient_offset, gradientType, doProject, range);
+ alpha, gradient_offset, gradientType, range);
}
}
return mixedColor;
}
-void StrafeHUD_drawGradient(vector color1, vector color2, vector size, float original_width, float offset, float original_offset, float alpha, float gradientOffset, int gradientType, bool doProject, float range)
+// FIXME: this is very bad for performance, there should be a better way to draw gradients
+void StrafeHUD_drawGradient(vector color1, vector color2, vector size, float original_width, float offset, float original_offset, float alpha, float gradientOffset, int gradientType, float range)
{
float color_ratio, alpha1, alpha2;
vector segment_size = size;
segment_size.x = min(size.x - i, 1); // each gradient segment is 1 unit wide except if there is less than 1 unit of gradient remaining
segment_offset = offset + i;
ratio_offset = segment_offset + segment_size.x / 2;
- if(doProject)
- ratio_offset = StrafeHUD_projectOffset(ratio_offset, range, true);
+ ratio_offset = StrafeHUD_projectOffset(ratio_offset, range, true);
ratio_offset += gradientOffset;
ratio = (ratio_offset - original_offset) / original_width * (gradientType == STRAFEHUD_GRADIENT_BOTH ? 2 : 1);
if(ratio > 1) ratio = 2 - ratio;
#include "../strafehud.qh"
void StrafeHUD_drawStrafeHUD(float, float, vector, float, int, int, bool, float);
-void StrafeHUD_drawGradient(vector, vector, vector, float, float, float, float, float, int, bool, float);
+void StrafeHUD_drawGradient(vector, vector, vector, float, float, float, float, float, int, float);
void StrafeHUD_drawStrafeArrow(vector, float, vector, float, bool, float);
bool StrafeHUD_drawTextIndicator(string, float, vector, float, float, float, int);
vector StrafeHUD_mixColors(vector, vector, float);
#include <lib/csqcmodel/common.qh> // for IS_PLAYER() macro
#include <common/resources/cl_resources.qh> // IS_DEAD() macro
+// slick detector
float StrafeHUD_DrawSlickDetector(entity e, bool onslick)
{
- // slick detector
float slickdetector_height = bound(0, autocvar_hud_panel_strafehud_slickdetector_height, 1);
slickdetector_height *= panel_size.y;
if(autocvar_hud_panel_strafehud_slickdetector &&
slickdetected = onslick; // do not need to traceline if already touching slick
- // traceline into every direction
+ // traceline downwards into every direction
trace_dphitq3surfaceflags = 0;
vector traceorigin = e.origin + eZ * e.mins.z;
for(float i = 0; i < 90 && !slickdetected; i += slicksteps)
return dt;
}
+// determine player wishdir
float DetectWishAngle(vector movement, int keys, bool islocal)
{
- // determine player wishdir
float wishangle;
if(islocal) // if entity is local player
{