--- /dev/null
+#include "common_physics.qh"
+
+#include <lib/csqcmodel/cl_player.qh>
+#include <common/physics/player.qh>
+#include <common/physics/movetypes/movetypes.qh>
+
+// non-local players
+#include <common/animdecide.qh> // anim_implicit_state
+#include <common/ent_cs.qh> // CSQCModel_server2csqc()
+
+void HUD_Physics_Init()
+{
+ // find out whether the local csqcmodel entity is valid
+ if(spectatee_status > 0 || isdemo())
+ {
+ islocal = false;
+ strafeplayer = CSQCModel_server2csqc(player_localentnum - 1);
+ }
+ else
+ {
+ islocal = true;
+ strafeplayer = csqcplayer;
+ }
+
+ if(csqcplayer && strafeplayer)
+ csqc_and_strafe_player = true;
+ else
+ {
+ csqc_and_strafe_player = false;
+ // Since both huds return (essentially) when this is false, no variables beyond this point need to be computed
+ return;
+ }
+
+ predicted = csqcplayer_status == CSQCPLAYERSTATUS_PREDICTED;
+
+ // check the player waterlevel without affecting the player entity, this way we can fetch waterlevel even if client prediction is disabled
+ {
+ // store old values
+ void old_contentstransition(int, int) = strafeplayer.contentstransition;
+ float old_watertype = strafeplayer.watertype;
+ float old_waterlevel = strafeplayer.waterlevel;
+
+ strafeplayer.contentstransition = func_null; // unset the contentstransition function if present
+ _Movetype_CheckWater(strafeplayer);
+ strafe_waterlevel = strafeplayer.waterlevel; // store the player waterlevel
+
+ // restore old values
+ strafeplayer.contentstransition = old_contentstransition;
+ strafeplayer.watertype = old_watertype;
+ strafeplayer.waterlevel = old_waterlevel;
+ }
+
+ movement_phys = PHYS_INPUT_MOVEVALUES(strafeplayer);
+ keys = STAT(PRESSED_KEYS);
+ // try to ignore if track_canjump is enabled, doesn't work in spectator mode if spectated player uses +jetpack or cl_movement_track_canjump
+ jumpheld = false;
+ if(islocal)
+ {
+ if((PHYS_INPUT_BUTTON_JUMP(strafeplayer) || PHYS_INPUT_BUTTON_JETPACK(strafeplayer)) && !PHYS_CL_TRACK_CANJUMP(strafeplayer))
+ jumpheld = true;
+ }
+ else
+ {
+ if((keys & KEY_JUMP) && !PHYS_TRACK_CANJUMP(strafeplayer))
+ jumpheld = true;
+ }
+
+ // doesn't get changed by ground timeout and isn't affected by jump input
+ real_onground = islocal ? IS_ONGROUND(strafeplayer) : !(strafeplayer.anim_implicit_state & ANIMIMPLICITSTATE_INAIR);
+ // doesn't get changed by ground timeout
+ real_onslick = false;
+ // if jump is held assume we are in air, avoids flickering of the hud when hitting the ground
+ onground = (real_onground && !jumpheld);
+ onslick = real_onslick;
+ // the hud will not work well while swimming
+ swimming = strafe_waterlevel >= WATERLEVEL_SWIMMING;
+ // use local csqcmodel entity for this even when spectating, flickers too much otherwise
+ vel_phys = csqcplayer.velocity;
+ speed_phys = vlen(vec2(vel_phys));
+ speed3d_phys = vlen(vel_phys);
+ immobile = speed_phys <= 0;
+
+ maxspeed_ground = PHYS_MAXSPEED(strafeplayer);
+ maxspeed_air = PHYS_MAXAIRSPEED(strafeplayer);
+ maxspeed_airstrafe = PHYS_MAXAIRSTRAFESPEED(strafeplayer);
+ maxaccel_ground = PHYS_ACCELERATE(strafeplayer);
+ maxaccel_air = PHYS_AIRACCELERATE(strafeplayer);
+ maxaccel_airstrafe = PHYS_AIRSTRAFEACCELERATE(strafeplayer);
+ // only the local csqcplayer entity contains this information even when spectating
+ maxspeed_mod = IS_DUCKED(csqcplayer) ? .5 : 1;
+ maxspeed_phys = onground ? maxspeed_ground : maxspeed_air;
+ maxspeed = maxspeed_phys * maxspeed_mod;
+ maxaccel_phys = onground ? maxaccel_ground : maxaccel_air;
+ maxaccel = maxaccel_phys;
+ stopspeed = PHYS_STOPSPEED(strafeplayer);
+ airstopaccel = PHYS_AIRSTOPACCELERATE(strafeplayer);
+ aircontrol = PHYS_AIRCONTROL(strafeplayer);
+ aircontrol_backwards = PHYS_AIRCONTROL_BACKWARDS(strafeplayer) == 1;
+ aircontrol_power = PHYS_AIRCONTROL_POWER(strafeplayer);
+ aircontrol_penalty = PHYS_AIRCONTROL_PENALTY(strafeplayer);
+ airaccel_qw = PHYS_AIRACCEL_QW(strafeplayer) == 1;
+ friction_phys = PHYS_FRICTION(strafeplayer);
+
+ // change the range from 0° - 360° to -180° - 180° to match how view_angle represents angles
+ vel_angle = vectoangles(strafeplayer.velocity).y - (vectoangles(strafeplayer.velocity).y > 180 ? 360 : 0);
+ view_angle = PHYS_INPUT_ANGLES(strafeplayer).y;
+
+ if(onground)
+ {
+ if(friction_phys == 0)
+ {
+ onslick = true;
+ }
+ else // don't 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;
+
+ onground_lasttime = time;
+ onslick_last = onslick;
+ }
+ else if(jumpheld || swimming)
+ {
+ onground_lasttime = 0;
+ }
+
+ strafefriction = onslick ? PHYS_FRICTION_SLICK(strafeplayer) : friction_phys;
+ alive_player = (!IS_DEAD(strafeplayer) && IS_PLAYER(strafeplayer));
+}
#include "physics.qh"
+#include <client/hud/common_physics.qh>
#include <client/draw.qh>
-#include <lib/csqcmodel/cl_player.qh>
-#include <common/physics/player.qh>
-#include <common/physics/movetypes/movetypes.qh>
// Physics (#15)
HUD_Write_Cvar("hud_panel_physics_text_scale");
}
-vector acc_prevspeed;
+vector acc_prev_vel;
float acc_prevtime, acc_avg, top_speed, top_speed_time, jump_speed, jump_speed_time, prev_vel_z = 0;
float physics_update_time, discrete_speed, discrete_acceleration;
void HUD_Physics()
panel_size -= '2 2 0' * panel_bg_padding;
}
- draw_beginBoldFont();
+ if(!csqc_and_strafe_player)
+ return;
- bool onslick = false;
- if(IS_ONGROUND(csqcplayer))
- {
- if(PHYS_FRICTION(csqcplayer) == 0)
- onslick = true;
- else // don't use IS_ONSLICK(), it only works for the local player and only if client prediction is enabled
- {
- trace_dphitq3surfaceflags = 0;
- tracebox(csqcplayer.origin, csqcplayer.mins, csqcplayer.maxs, csqcplayer.origin - '0 0 1', MOVE_NOMONSTERS, csqcplayer);
- onslick = trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK;
- }
- }
+ draw_beginBoldFont();
float acceleration_progressbar_scale = 0;
if(autocvar_hud_panel_physics_progressbar && autocvar_hud_panel_physics_acceleration_progressbar_scale > 1)
//compute speed
float speed, conversion_factor = GetSpeedUnitFactor(autocvar_hud_speed_unit);
- vector vel = (csqcplayer ? csqcplayer.velocity : pmove_vel);
-
float max_speed = floor( autocvar_hud_panel_physics_speed_max * conversion_factor + 0.5 );
if (autocvar__hud_configure)
+ {
speed = floor( max_speed * 0.65 + 0.5 );
+ immobile = speed <= 0;
+ }
else if(autocvar_hud_panel_physics_speed_vertical)
- speed = floor( vlen(vel) * conversion_factor + 0.5 );
+ speed = floor( speed3d_phys * conversion_factor + 0.5 );
else
- speed = floor( vlen(vel - vel.z * '0 0 1') * conversion_factor + 0.5 );
+ speed = floor( speed_phys * conversion_factor + 0.5 );
//compute acceleration
float acceleration, f;
acceleration = 0.45; //use a hardcoded value so that the hud responds to hud_panel_physics_acceleration_max changing
else
{
- // 1 m/s = 0.0254 qu/s; 1 g = 9.80665 m/s^2
f = time - acc_prevtime;
if(autocvar_hud_panel_physics_acceleration_vertical)
- acceleration = (vlen(vel) - vlen(acc_prevspeed));
+ acceleration = (speed3d_phys - vlen(acc_prev_vel));
else
- acceleration = (vlen(vel - '0 0 1' * vel.z) - vlen(acc_prevspeed - '0 0 1' * acc_prevspeed.z));
+ acceleration = (speed_phys - vlen(vec2(acc_prev_vel)));
- acceleration = acceleration * (1 / max(0.0001, f)) * (0.0254 / 9.80665);
+ acceleration = acceleration * (1 / max(0.0001, f)) * ACCEL2GRAV;
- acc_prevspeed = vel;
+ acc_prev_vel = vel_phys;
acc_prevtime = time;
if(autocvar_hud_panel_physics_acceleration_movingaverage)
{
if (autocvar__hud_configure)
{
- top_speed = floor( max_speed * speed_size * 0.9 + 0.5 ); // slightly less than top speed text
+ top_speed = floor( max_speed * speed_size * 0.9 + 0.5 ); //slightly less than top speed text
f = 1;
}
else
{
- if(vel.z > prev_vel_z && !IS_DEAD(csqcplayer) && IS_PLAYER(csqcplayer))
+ if(vel_phys.z > prev_vel_z && jumpheld && !onground && !swimming && alive_player)
{
- // FIXME: this includes some situations where the player doesn't explicitly jump (e.g. bouncing on ramp, jumppad)
- // maybe these can be left in?
+ //NOTE: this includes some situations where the player doesn't explicitly jump (e.g. jumppad, weapon kb)
+ //excluding them would be difficult. maybe they can be left in?
jump_speed = speed;
jump_speed_time = time;
}
f = max(1, autocvar_hud_panel_physics_jumpspeed_time);
// divide by f to make it start from 1
f = cos( ((time - jump_speed_time) / f) * PI/2 );
- prev_vel_z = vel.z;
+ prev_vel_z = vel_phys.z;
}
if (f > 0)
{
}
//draw speed
- if(speed)
+ if(!immobile)
if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
HUD_Panel_DrawProgressBar(panel_pos + speed_offset, panel_size, "progressbar", speed/max_speed, 0, speed_baralign, autocvar_hud_progressbar_speed_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
// Author: Juhu
#include "strafehud.qh"
+#include <client/hud/common_physics.qh>
#include <client/draw.qh>
-#include <lib/csqcmodel/cl_player.qh>
-#include <common/physics/player.qh>
-#include <common/physics/movetypes/movetypes.qh>
// non-essential
#include <client/view.qh> // for v_flipped state
-// non-local players
-#include <common/animdecide.qh> // anim_implicit_state
-#include <common/ent_cs.qh> // CSQCModel_server2csqc()
-
// start speed
#include <client/hud/panel/racetimer.qh> // checkpoint information (race_*)
+// GeomLerp
+#include <common/physics/player.qh>
+
// StrafeHUD (#25)
void HUD_StrafeHUD_Export(int fh)
// allow saving cvars that aesthetically change the panel into hud skin files
}
-float GeomLerp(float a, float _lerp, float b); // declare GeomLerp here since there's no header file for it
-
void HUD_StrafeHUD()
{
static float hud_lasttime = 0;
- entity strafeplayer;
- bool islocal;
// generic hud routines
if(!autocvar__hud_configure)
panel_size -= '2 2 0' * panel_bg_padding;
}
- // find out whether the local csqcmodel entity is valid
- if(spectatee_status > 0 || isdemo())
- {
- islocal = false;
- strafeplayer = CSQCModel_server2csqc(player_localentnum - 1);
- }
- else
- {
- islocal = true;
- strafeplayer = csqcplayer;
- }
-
// draw strafehud
- if(csqcplayer && strafeplayer)
+ if(csqc_and_strafe_player)
{
- float strafe_waterlevel;
-
- // check the player waterlevel without affecting the player entity, this way we can fetch waterlevel even if client prediction is disabled
- {
- // store old values
- void old_contentstransition(int, int) = strafeplayer.contentstransition;
- float old_watertype = strafeplayer.watertype;
- float old_waterlevel = strafeplayer.waterlevel;
-
- strafeplayer.contentstransition = func_null; // unset the contentstransition function if present
- _Movetype_CheckWater(strafeplayer);
- strafe_waterlevel = strafeplayer.waterlevel; // store the player waterlevel
-
- // restore old values
- strafeplayer.contentstransition = old_contentstransition;
- strafeplayer.watertype = old_watertype;
- strafeplayer.waterlevel = old_waterlevel;
- }
+ float friction = friction_phys;
+ float speed = speed_phys;
+ vector movement = movement_phys;
- int keys = STAT(PRESSED_KEYS);
- // try to ignore if track_canjump is enabled, doesn't work in spectator mode if spectated player uses +jetpack or cl_movement_track_canjump
- bool jumpheld = false;
- if(islocal)
+ if(autocvar__hud_configure)
{
- if((PHYS_INPUT_BUTTON_JUMP(strafeplayer) || PHYS_INPUT_BUTTON_JETPACK(strafeplayer)) && !PHYS_CL_TRACK_CANJUMP(strafeplayer))
- jumpheld = true;
- }
- else
- {
- if((keys & KEY_JUMP) && !PHYS_TRACK_CANJUMP(strafeplayer))
- jumpheld = true;
+ speed = 1337;
+ immobile = false;
+ maxspeed = 320;
+ maxaccel = 1;
}
// persistent
- static float onground_lasttime = 0;
- static bool onslick_last = false;
- static float turn_lasttime = 0;
- static bool turn = false;
+ static float turn_lasttime = 0;
+ static bool turn = false;
static float turnangle;
- static float dt_update = 0;
- static int dt_time = 0;
- static float dt_sum = 0;
- static float dt = 0;
+ static float dt_update = 0;
+ static int dt_time = 0;
+ static float dt_sum = 0;
+ static float dt = 0;
// physics
- // doesn't get changed by ground timeout and isn't affected by jump input
- bool real_onground = islocal ? IS_ONGROUND(strafeplayer) : !(strafeplayer.anim_implicit_state & ANIMIMPLICITSTATE_INAIR);
- // doesn't get changed by ground timeout
- bool real_onslick = false;
- // 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;
bool onground_expired;
bool strafekeys;
- // the hud will not work well while swimming
- bool swimming = strafe_waterlevel >= WATERLEVEL_SWIMMING;
- // use local csqcmodel entity for this even when spectating, flickers too much otherwise
- float speed = !autocvar__hud_configure ? vlen(vec2(csqcplayer.velocity)) : 1337;
- // 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 movespeed;
float bestspeed;
- float maxaccel_phys = onground ? PHYS_ACCELERATE(strafeplayer) : PHYS_AIRACCELERATE(strafeplayer);
- float maxaccel = !autocvar__hud_configure ? maxaccel_phys : 1;
- float airstopaccel = PHYS_AIRSTOPACCELERATE(strafeplayer);
- float aircontrol = PHYS_AIRCONTROL(strafeplayer);
- bool aircontrol_backwards = PHYS_AIRCONTROL_BACKWARDS(strafeplayer) == 1;
- bool airaccel_qw = PHYS_AIRACCEL_QW(strafeplayer) == 1;
- // 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;
float angle;
- vector movement = PHYS_INPUT_MOVEVALUES(strafeplayer);
bool fwd; // left & right variables are flipped when !fwd
int keys_fwd;
float wishangle;
int direction;
- float strafity = 0;
+ float strafity = 0;
// HUD
int mode;
- float speed_conversion_factor = GetSpeedUnitFactor(autocvar_hud_speed_unit);
- float length_conversion_factor = GetLengthUnitFactor(autocvar_hud_speed_unit);
+ float speed_conversion_factor = GetSpeedUnitFactor(autocvar_hud_speed_unit);
+ float length_conversion_factor = GetLengthUnitFactor(autocvar_hud_speed_unit);
// use more decimals when displaying km or miles
- int length_decimals = autocvar_hud_speed_unit >= 3 && autocvar_hud_speed_unit <= 5 ? 6 : 2;
- float antiflicker_angle = bound(0, autocvar_hud_panel_strafehud_antiflicker_angle, 180);
+ int length_decimals = autocvar_hud_speed_unit >= 3 && autocvar_hud_speed_unit <= 5 ? 6 : 2;
+ float antiflicker_angle = bound(0, autocvar_hud_panel_strafehud_antiflicker_angle, 180);
float minspeed;
- float shift_offset = 0;
- bool straight_overturn = false;
- bool immobile = speed <= 0;
+ float shift_offset = 0;
+ bool straight_overturn = false;
float hudangle;
float hidden_width;
float neutral_offset;
float neutral_width;
- vector currentangle_color = autocvar_hud_panel_strafehud_angle_neutral_color;
+ vector currentangle_color = autocvar_hud_panel_strafehud_angle_neutral_color;
float currentangle_offset;
vector currentangle_size;
float bestangle;
float prebestangle;
float overturn_angle;
float odd_bestangle;
- float bestangle_offset = 0;
- float switch_bestangle_offset = 0;
- bool odd_angles = false;
- float odd_bestangle_offset = 0;
- float switch_odd_bestangle_offset = 0;
- float switch_bestangle_width = 0;
- float wturn_bestangle = 0;
- float wturn_left_bestangle_offset = 0;
- float wturn_right_bestangle_offset = 0;
- float wturn_bestangle_width = 0;
+ float bestangle_offset = 0;
+ float switch_bestangle_offset = 0;
+ bool odd_angles = false;
+ float odd_bestangle_offset = 0;
+ float switch_odd_bestangle_offset = 0;
+ float switch_bestangle_width = 0;
+ float wturn_bestangle = 0;
+ float wturn_left_bestangle_offset = 0;
+ float wturn_right_bestangle_offset = 0;
+ float wturn_bestangle_width = 0;
float accelzone_left_offset;
float accelzone_right_offset;
float accelzone_width;
float overturn_offset;
float overturn_width;
float slickdetector_height;
- vector direction_size_vertical = '0 0 0';
- vector direction_size_horizontal = '0 0 0';
+ vector direction_size_vertical = '0 0 0';
+ vector direction_size_horizontal = '0 0 0';
float range_minangle;
- float text_offset_top = 0;
- float text_offset_bottom = 0;
+ float text_offset_top = 0;
+ float text_offset_bottom = 0;
// real_* variables which are always positive with no wishangle offset
float real_bestangle;
float real_prebestangle;
float real_overturn_angle;
- float real_wturn_bestangle = 0;
+ float real_wturn_bestangle = 0;
if(autocvar_hud_panel_strafehud_mode >= 0 && autocvar_hud_panel_strafehud_mode <= 1)
mode = autocvar_hud_panel_strafehud_mode;
// 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), 0);
- if(onground)
- {
- if(PHYS_FRICTION(strafeplayer) == 0)
- {
- onslick = true;
- }
- else // don't 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;
-
- onground_lasttime = time;
- onslick_last = onslick;
- }
- else if(jumpheld || swimming)
- {
- onground_lasttime = 0;
- }
-
if(onground_lasttime == 0)
onground_expired = true;
else
if(!autocvar__hud_configure)
{
- maxspeed = PHYS_MAXSPEED(strafeplayer) * maxspeed_mod;
- maxaccel = PHYS_ACCELERATE(strafeplayer);
+ maxspeed = maxspeed_ground * maxspeed_mod;
+ maxaccel = maxaccel_ground;
}
}
arrow_size = max(arrow_size, 1);
// determine frametime
- if((csqcplayer_status == CSQCPLAYERSTATUS_PREDICTED) && (input_timelength > 0))
+ if(predicted && (input_timelength > 0))
{
float dt_client = input_timelength;
// calculate the maximum air strafe speed and acceleration
strafity = 1 - (90 - fabs(wishangle)) / 45;
- if(PHYS_MAXAIRSTRAFESPEED(strafeplayer) != 0)
- maxspeed = min(maxspeed, GeomLerp(PHYS_MAXAIRSPEED(strafeplayer), strafity, PHYS_MAXAIRSTRAFESPEED(strafeplayer)));
+ if(maxspeed_airstrafe != 0)
+ maxspeed = min(maxspeed, GeomLerp(maxspeed_air, strafity, maxspeed_airstrafe));
movespeed = min(movespeed, maxspeed);
- if(PHYS_AIRSTRAFEACCELERATE(strafeplayer) != 0)
- maxaccel = GeomLerp(PHYS_AIRACCELERATE(strafeplayer), strafity, PHYS_AIRSTRAFEACCELERATE(strafeplayer));
+ if(maxaccel_airstrafe != 0)
+ maxaccel = GeomLerp(maxaccel_air, strafity, maxaccel_airstrafe);
}
}
if((speed > 0) && onground)
{
- float strafefriction = onslick ? PHYS_FRICTION_SLICK(strafeplayer) : PHYS_FRICTION(strafeplayer);
-
- frictionspeed = speed * dt * strafefriction * max(PHYS_STOPSPEED(strafeplayer) / speed, 1);
+ frictionspeed = speed * dt * strafefriction * max(stopspeed / speed, 1);
strafespeed = max(speed - frictionspeed, 0);
}
else
* this doesn't have support for sv_aircontrol_sideways == 1
*/
bool wturning = !onground && wishangle == 0 && (keys_fwd == STRAFEHUD_KEYS_FORWARD || (aircontrol_backwards && keys_fwd == STRAFEHUD_KEYS_BACKWARD));
- bool wturn_valid = aircontrol && PHYS_AIRCONTROL_PENALTY(strafeplayer) == 0 && (airaccel_qw || autocvar_hud_panel_strafehud_wturn_unrestricted == 1);
+ bool wturn_valid = aircontrol && aircontrol_penalty == 0 && (airaccel_qw || autocvar_hud_panel_strafehud_wturn_unrestricted == 1);
bool wturn_check = autocvar_hud_panel_strafehud_wturn && !immobile && wturn_valid;
if(wturn_check)
{
- float wturn_power = PHYS_AIRCONTROL_POWER(strafeplayer);
+ float wturn_power = aircontrol_power;
if(wturn_power == 2)
{
float wturn_a = 32 * aircontrol * dt;
if(draw_normal)
{
// recalculate bestangle as if strafing normally
- float n_maxspeed = PHYS_MAXAIRSPEED(strafeplayer) * maxspeed_mod;
+ float n_maxspeed = maxspeed_air * maxspeed_mod;
float n_movespeed = n_maxspeed;
- float n_maxaccel = PHYS_AIRACCELERATE(strafeplayer) * dt * n_movespeed;
+ float n_maxaccel = maxaccel_air * dt * n_movespeed;
float n_bestspeed = max(n_movespeed - n_maxaccel, 0);
n_bestangle = speed > n_bestspeed
? acos(n_bestspeed / speed) * RAD2DEG - 45
slickoffset.y = cos(j) * slickrotate;
traceline(traceorigin, traceorigin + slickoffset, MOVE_NOMONSTERS, strafeplayer);
- if((PHYS_FRICTION(strafeplayer) == 0 && trace_fraction < 1)
+ if((friction == 0 && trace_fraction < 1)
|| (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK))
slickdetected = true;
if(i == 0)
static float jumpheight = 0, jumptime = 0; // displayed value and timestamp for fade out
// tries to catch kill and spectate but those are not reliable
- if((strafeplayer.velocity.z <= 0) || real_onground || swimming || IS_DEAD(strafeplayer) || !IS_PLAYER(strafeplayer))
+ if((strafeplayer.velocity.z <= 0) || real_onground || swimming || !alive_player)
{
height_min = height_max = strafeplayer.origin.z;
}