#include "physics.qh"
#include "triggers/trigger/swamp.qh"
#include "triggers/trigger/jumppads.qh"
+#include "viewloc.qh"
#ifdef SVQC
#include "../server/miscfunctions.qh"
+#include "triggers/trigger/viewloc.qh"
+
+// client side physics
+bool Physics_Valid(string thecvar)
+{
+ if(!autocvar_g_physics_clientselect) { return false; }
+
+ string l = strcat(" ", autocvar_g_physics_clientselect_options, " ");
+
+ if(strstrofs(l, strcat(" ", thecvar, " "), 0) >= 0)
+ return true;
+
+ return false;
+}
+
+float Physics_ClientOption(entity pl, string option)
+{
+ if(Physics_Valid(pl.cvar_cl_physics))
+ {
+ string var = sprintf("g_physics_%s_%s", pl.cvar_cl_physics, option);
+ if(cvar_type(var) & CVAR_TYPEFLAG_EXISTS)
+ return cvar(var);
+ }
+ if(autocvar_g_physics_clientselect && autocvar_g_physics_clientselect_default)
+ {
+ string var = sprintf("g_physics_%s_%s", autocvar_g_physics_clientselect_default, option);
+ if(cvar_type(var) & CVAR_TYPEFLAG_EXISTS)
+ return cvar(var);
+ }
+ return cvar(strcat("sv_", option));
+}
void Physics_AddStats()
{
addstat(STAT_DOUBLEJUMP, AS_INT, stat_doublejump);
// jump speed caps
- addstat(STAT_MOVEVARS_JUMPSPEEDCAP_MIN, AS_FLOAT, stat_jumpspeedcap_min);
- addstat(STAT_MOVEVARS_JUMPSPEEDCAP_MIN, AS_FLOAT, stat_jumpspeedcap_min);
addstat(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS, AS_INT, stat_jumpspeedcap_disable_onramps);
// hacks
addstat(STAT_MOVEVARS_FRICTION_SLICK, AS_FLOAT, stat_sv_friction_slick);
addstat(STAT_GAMEPLAYFIX_EASIERWATERJUMP, AS_INT, stat_gameplayfix_easierwaterjump);
+ // new properties
+ addstat(STAT_MOVEVARS_JUMPVELOCITY, AS_FLOAT, stat_sv_jumpvelocity);
+ addstat(STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, AS_FLOAT, stat_sv_airaccel_qw_stretchfactor);
+ addstat(STAT_MOVEVARS_MAXAIRSTRAFESPEED, AS_FLOAT, stat_sv_maxairstrafespeed);
+ addstat(STAT_MOVEVARS_MAXAIRSPEED, AS_FLOAT, stat_sv_maxairspeed);
+ addstat(STAT_MOVEVARS_AIRSTRAFEACCELERATE, AS_FLOAT, stat_sv_airstrafeaccelerate);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL, AS_FLOAT, stat_sv_warsowbunny_turnaccel);
+ addstat(STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, AS_FLOAT, stat_sv_airaccel_sideways_friction);
+ addstat(STAT_MOVEVARS_AIRCONTROL, AS_FLOAT, stat_sv_aircontrol);
+ addstat(STAT_MOVEVARS_AIRCONTROL_POWER, AS_FLOAT, stat_sv_aircontrol_power);
+ addstat(STAT_MOVEVARS_AIRCONTROL_PENALTY, AS_FLOAT, stat_sv_aircontrol_penalty);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, AS_FLOAT, stat_sv_warsowbunny_airforwardaccel);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED, AS_FLOAT, stat_sv_warsowbunny_topspeed);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_ACCEL, AS_FLOAT, stat_sv_warsowbunny_accel);
+ addstat(STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, AS_FLOAT, stat_sv_warsowbunny_backtosideratio);
+ addstat(STAT_MOVEVARS_FRICTION, AS_FLOAT, stat_sv_friction);
+ addstat(STAT_MOVEVARS_ACCELERATE, AS_FLOAT, stat_sv_accelerate);
+ addstat(STAT_MOVEVARS_STOPSPEED, AS_FLOAT, stat_sv_stopspeed);
+ addstat(STAT_MOVEVARS_AIRACCELERATE, AS_FLOAT, stat_sv_airaccelerate);
+ addstat(STAT_MOVEVARS_AIRSTOPACCELERATE, AS_FLOAT, stat_sv_airstopaccelerate);
+
addstat(STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND, AS_INT, stat_gameplayfix_upvelocityclearsonground);
}
self.stat_pl_crouch_min = PL_CROUCH_MIN;
self.stat_pl_crouch_max = PL_CROUCH_MAX;
- self.stat_sv_airaccel_qw = AdjustAirAccelQW(autocvar_sv_airaccel_qw, maxspd_mod);
- if (autocvar_sv_airstrafeaccel_qw)
- self.stat_sv_airstrafeaccel_qw = AdjustAirAccelQW(autocvar_sv_airstrafeaccel_qw, maxspd_mod);
+
+ self.stat_sv_airaccel_qw = AdjustAirAccelQW(Physics_ClientOption(self, "airaccel_qw"), maxspd_mod);
+ if(Physics_ClientOption(self, "airstrafeaccel_qw"))
+ self.stat_sv_airstrafeaccel_qw = AdjustAirAccelQW(Physics_ClientOption(self, "airstrafeaccel_qw"), maxspd_mod);
else
self.stat_sv_airstrafeaccel_qw = 0;
- self.stat_sv_airspeedlimit_nonqw = autocvar_sv_airspeedlimit_nonqw * maxspd_mod;
- self.stat_sv_maxspeed = autocvar_sv_maxspeed * maxspd_mod; // also slow walking
+ self.stat_sv_airspeedlimit_nonqw = Physics_ClientOption(self, "airspeedlimit_nonqw") * maxspd_mod;
+ self.stat_sv_maxspeed = Physics_ClientOption(self, "maxspeed") * maxspd_mod; // also slow walking
self.stat_movement_highspeed = PHYS_HIGHSPEED; // TODO: remove this!
self.stat_doublejump = PHYS_DOUBLEJUMP;
self.stat_jetpack_maxspeed_up = PHYS_JETPACK_MAXSPEED_UP;
self.stat_jetpack_fuel = PHYS_JETPACK_FUEL;
- self.stat_jumpspeedcap_min = PHYS_JUMPSPEEDCAP_MIN;
- self.stat_jumpspeedcap_max = PHYS_JUMPSPEEDCAP_MAX;
self.stat_jumpspeedcap_disable_onramps = PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS;
self.stat_sv_friction_on_land = PHYS_FRICTION_ONLAND;
self.stat_gameplayfix_easierwaterjump = GAMEPLAYFIX_EASIERWATERJUMP;
+
+ // old stats
+ // fix some new settings
+ self.stat_sv_airaccel_qw_stretchfactor = Physics_ClientOption(self, "airaccel_qw_stretchfactor");
+ self.stat_sv_maxairstrafespeed = Physics_ClientOption(self, "maxairstrafespeed");
+ self.stat_sv_maxairspeed = Physics_ClientOption(self, "maxairspeed");
+ self.stat_sv_airstrafeaccelerate = Physics_ClientOption(self, "airstrafeaccelerate");
+ self.stat_sv_warsowbunny_turnaccel = Physics_ClientOption(self, "warsowbunny_turnaccel");
+ self.stat_sv_airaccel_sideways_friction = Physics_ClientOption(self, "airaccel_sideways_friction");
+ self.stat_sv_aircontrol = Physics_ClientOption(self, "aircontrol");
+ self.stat_sv_aircontrol_power = Physics_ClientOption(self, "aircontrol_power");
+ self.stat_sv_aircontrol_penalty = Physics_ClientOption(self, "aircontrol_penalty");
+ self.stat_sv_warsowbunny_airforwardaccel = Physics_ClientOption(self, "warsowbunny_airforwardaccel");
+ self.stat_sv_warsowbunny_topspeed = Physics_ClientOption(self, "warsowbunny_topspeed");
+ self.stat_sv_warsowbunny_accel = Physics_ClientOption(self, "warsowbunny_accel");
+ self.stat_sv_warsowbunny_backtosideratio = Physics_ClientOption(self, "warsowbunny_backtosideratio");
+ self.stat_sv_friction = Physics_ClientOption(self, "friction");
+ self.stat_sv_accelerate = Physics_ClientOption(self, "accelerate");
+ self.stat_sv_stopspeed = Physics_ClientOption(self, "stopspeed");
+ self.stat_sv_airaccelerate = Physics_ClientOption(self, "airaccelerate");
+ self.stat_sv_airstopaccelerate = Physics_ClientOption(self, "airstopaccelerate");
+ self.stat_sv_jumpvelocity = Physics_ClientOption(self, "jumpvelocity");
+
self.stat_gameplayfix_upvelocityclearsonground = UPWARD_VELOCITY_CLEARS_ONGROUND;
}
#endif
if (k <= 0)
return;
- k *= bound(0, wishspeed / PHYS_MAXAIRSPEED, 1);
+ k *= bound(0, wishspeed / PHYS_MAXAIRSPEED(self), 1);
float zspeed = self.velocity_z;
self.velocity_z = 0;
bool doublejump = false;
float mjumpheight = PHYS_JUMPVELOCITY;
- player_multijump = doublejump;
- player_jumpheight = mjumpheight;
#ifdef SVQC
- if (MUTATOR_CALLHOOK(PlayerJump))
+ if (MUTATOR_CALLHOOK(PlayerJump, doublejump, mjumpheight))
#elif defined(CSQC)
- if(PM_multijump_checkjump())
+ player_multijump = doublejump;
+ player_jumpheight = mjumpheight;
+ if (PM_multijump_checkjump())
#endif
return true;
// velocity bounds. Final velocity is bound between (jumpheight *
// min + jumpheight) and (jumpheight * max + jumpheight);
- if(PHYS_JUMPSPEEDCAP_MIN)
+ if(PHYS_JUMPSPEEDCAP_MIN != "")
{
- float minjumpspeed = mjumpheight * PHYS_JUMPSPEEDCAP_MIN;
+ float minjumpspeed = mjumpheight * stof(PHYS_JUMPSPEEDCAP_MIN);
if (self.velocity_z < minjumpspeed)
mjumpheight += minjumpspeed - self.velocity_z;
}
- if(PHYS_JUMPSPEEDCAP_MAX)
+ if(PHYS_JUMPSPEEDCAP_MAX != "")
{
// don't do jump speedcaps on ramps to preserve old xonotic ramjump style
tracebox(self.origin + '0 0 0.01', self.mins, self.maxs, self.origin - '0 0 0.01', MOVE_NORMAL, self);
if (!(trace_fraction < 1 && trace_plane_normal_z < 0.98 && PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS))
{
- float maxjumpspeed = mjumpheight * PHYS_JUMPSPEEDCAP_MAX;
+ float maxjumpspeed = mjumpheight * stof(PHYS_JUMPSPEEDCAP_MAX);
if (self.velocity_z > maxjumpspeed)
mjumpheight -= self.velocity_z - maxjumpspeed;
void CheckPlayerJump()
{
#ifdef SVQC
- float was_flying = ITEMS(self) & IT_USING_JETPACK;
+ float was_flying = ITEMS_STAT(self) & IT_USING_JETPACK;
#endif
if (JETPACK_JUMP(self) < 2)
- ITEMS(self) &= ~IT_USING_JETPACK;
+ ITEMS_STAT(self) &= ~IT_USING_JETPACK;
if(PHYS_INPUT_BUTTON_JUMP(self) || PHYS_INPUT_BUTTON_JETPACK(self))
{
float air_jump = !PlayerJump() || self.multijump_count > 0; // PlayerJump() has important side effects
float activate = JETPACK_JUMP(self) && air_jump && PHYS_INPUT_BUTTON_JUMP(self) || PHYS_INPUT_BUTTON_JETPACK(self);
- float has_fuel = !PHYS_JETPACK_FUEL || PHYS_AMMO_FUEL(self) || ITEMS(self) & IT_UNLIMITED_WEAPON_AMMO;
+ float has_fuel = !PHYS_JETPACK_FUEL || PHYS_AMMO_FUEL(self) || ITEMS_STAT(self) & IT_UNLIMITED_WEAPON_AMMO;
- if (!(ITEMS(self) & IT_JETPACK)) { }
+ if (!(ITEMS_STAT(self) & ITEM_Jetpack.m_itemid)) { }
else if (self.jetpack_stopped) { }
else if (!has_fuel)
{
Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL);
#endif
self.jetpack_stopped = true;
- ITEMS(self) &= ~IT_USING_JETPACK;
+ ITEMS_STAT(self) &= ~IT_USING_JETPACK;
}
else if (activate && !PHYS_FROZEN(self))
- ITEMS(self) |= IT_USING_JETPACK;
+ ITEMS_STAT(self) |= IT_USING_JETPACK;
}
else
{
self.jetpack_stopped = false;
- ITEMS(self) &= ~IT_USING_JETPACK;
+ ITEMS_STAT(self) &= ~IT_USING_JETPACK;
}
if (!PHYS_INPUT_BUTTON_JUMP(self))
UNSET_JUMP_HELD(self);
if (time >= self.spider_slowness)
return;
PHYS_MAXSPEED(self) *= 0.5; // half speed while slow from spider
- self.stat_sv_airspeedlimit_nonqw *= 0.5;
+ PHYS_MAXAIRSPEED(self) *= 0.5;
+ PHYS_AIRSPEEDLIMIT_NONQW(self) *= 0.5;
+ PHYS_AIRSTRAFEACCELERATE(self) *= 0.5;
#endif
}
#ifdef SVQC
// WEAPONTODO
float xyspeed = vlen(vec2(self.velocity));
- if (self.weapon == WEP_VORTEX && WEP_CVAR(vortex, charge) && WEP_CVAR(vortex, charge_velocity_rate) && xyspeed > WEP_CVAR(vortex, charge_minspeed))
+ if (self.weapon == WEP_VORTEX.m_id && WEP_CVAR(vortex, charge) && WEP_CVAR(vortex, charge_velocity_rate) && xyspeed > WEP_CVAR(vortex, charge_minspeed))
{
// add a maximum of charge_velocity_rate when going fast (f = 1), gradually increasing from minspeed (f = 0) to maxspeed
xyspeed = min(xyspeed, WEP_CVAR(vortex, charge_maxspeed));
vector wishvel = v_forward * self.movement_x
+ v_right * self.movement_y;
// add remaining speed as Z component
- float maxairspd = PHYS_MAXAIRSPEED * max(1, maxspd_mod);
+ float maxairspd = PHYS_MAXAIRSPEED(self) * max(1, maxspd_mod);
// fix speedhacks :P
wishvel = normalize(wishvel) * min(1, vlen(wishvel) / maxairspd);
// add the unused velocity as up component
wishvel_z = (wishvel_z - PHYS_GRAVITY) * fz + PHYS_GRAVITY;
fvel = min(1, vlen(wishvel) / best);
- if (PHYS_JETPACK_FUEL && !(ITEMS(self) & IT_UNLIMITED_WEAPON_AMMO))
+ if (PHYS_JETPACK_FUEL && !(ITEMS_STAT(self) & IT_UNLIMITED_WEAPON_AMMO))
f = min(1, PHYS_AMMO_FUEL(self) / (PHYS_JETPACK_FUEL * PHYS_INPUT_TIMELENGTH * fvel));
else
f = 1;
UNSET_ONGROUND(self);
#ifdef SVQC
- if (!(ITEMS(self) & IT_UNLIMITED_WEAPON_AMMO))
+ if (!(ITEMS_STAT(self) & IT_UNLIMITED_WEAPON_AMMO))
self.ammo_fuel -= PHYS_JETPACK_FUEL * PHYS_INPUT_TIMELENGTH * fvel * f;
- ITEMS(self) |= IT_USING_JETPACK;
+ ITEMS_STAT(self) |= IT_USING_JETPACK;
// jetpack also inhibits health regeneration, but only for 1 second
self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_pause_fuel_regen);
if (pmove_waterjumptime <= 0)
#endif
{
- float maxairspd = PHYS_MAXAIRSPEED * min(maxspd_mod, 1);
+ float maxairspd = PHYS_MAXAIRSPEED(self) * min(maxspd_mod, 1);
// apply air speed limit
float airaccelqw = PHYS_AIRACCEL_QW(self);
// log dv/dt = logaccel + logmaxspeed + log(1 - accelqw) (when fast)
float strafity = IsMoveInDirection(self.movement, -90) + IsMoveInDirection(self.movement, +90); // if one is nonzero, other is always zero
if (PHYS_MAXAIRSTRAFESPEED)
- wishspeed = min(wishspeed, GeomLerp(PHYS_MAXAIRSPEED*maxspd_mod, strafity, PHYS_MAXAIRSTRAFESPEED*maxspd_mod));
- if (PHYS_AIRSTRAFEACCELERATE)
- airaccel = GeomLerp(airaccel, strafity, PHYS_AIRSTRAFEACCELERATE*maxspd_mod);
+ wishspeed = min(wishspeed, GeomLerp(PHYS_MAXAIRSPEED(self)*maxspd_mod, strafity, PHYS_MAXAIRSTRAFESPEED*maxspd_mod));
+ if (PHYS_AIRSTRAFEACCELERATE(self))
+ airaccel = GeomLerp(airaccel, strafity, PHYS_AIRSTRAFEACCELERATE(self)*maxspd_mod);
if (PHYS_AIRSTRAFEACCEL_QW(self))
airaccelqw =
(((strafity > 0.5 ? PHYS_AIRSTRAFEACCEL_QW(self) : PHYS_AIRACCEL_QW(self)) >= 0) ? +1 : -1)
self.movement = PHYS_INPUT_MOVEVALUES(self);
vector oldv_angle = self.v_angle;
- vector oldangles = self.angles; // we need to save these as they're abused by other code
+ vector oldangles = self.angles; // we need to save these, as they're abused by other code
self.v_angle = PHYS_INPUT_ANGLES(self);
self.angles = PHYS_WORLD_ANGLES(self);
self.disableclientprediction = 0;
#endif
+ viewloc_PlayerPhysics();
+
PM_check_spider();
PM_check_frozen();
maxspeed_mod = self.spectatorspeed;
}
- float spd = max(PHYS_MAXSPEED(self), PHYS_MAXAIRSPEED) * maxspeed_mod;
+ float spd = max(PHYS_MAXSPEED(self), PHYS_MAXAIRSPEED(self)) * maxspeed_mod;
if(self.speed != spd)
{
self.speed = spd;
stuffcmd(self, strcat("cl_sidespeed ", temps, "\n"));
stuffcmd(self, strcat("cl_upspeed ", temps, "\n"));
}
+
+ if(self.stat_jumpspeedcap_min != PHYS_JUMPSPEEDCAP_MIN)
+ {
+ self.stat_jumpspeedcap_min = PHYS_JUMPSPEEDCAP_MIN;
+ stuffcmd(self, strcat("cl_jumpspeedcap_min ", PHYS_JUMPSPEEDCAP_MIN, "\n"));
+ }
+ if(self.stat_jumpspeedcap_max != PHYS_JUMPSPEEDCAP_MAX)
+ {
+ self.stat_jumpspeedcap_min = PHYS_JUMPSPEEDCAP_MAX;
+ stuffcmd(self, strcat("cl_jumpspeedcap_max ", PHYS_JUMPSPEEDCAP_MAX, "\n"));
+ }
#endif
if(PHYS_DEAD(self))
+ {
+ // handle water here
+ vector midpoint = ((self.absmin + self.absmax) * 0.5);
+ if(pointcontents(midpoint) == CONTENT_WATER)
+ {
+ self.velocity = self.velocity * 0.5;
+
+ // do we want this?
+ //if(pointcontents(midpoint + '0 0 2') == CONTENT_WATER)
+ //{ self.velocity_z = 70; }
+ }
goto end;
+ }
#ifdef SVQC
if (!self.fixangle && !g_bugrigs)
RaceCarPhysics();
#endif
- else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY || (BUFFS(self) & BUFF_FLIGHT))
+ else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY || (BUFFS_STAT(self) & BUFF_FLIGHT.m_itemid))
PM_fly(maxspeed_mod);
else if (self.waterlevel >= WATERLEVEL_SWIMMING)
else if (time < self.ladder_time)
PM_ladder(maxspeed_mod);
- else if (ITEMS(self) & IT_USING_JETPACK)
+ else if (ITEMS_STAT(self) & IT_USING_JETPACK)
PM_jetpack(maxspeed_mod);
else if (IS_ONGROUND(self))