#include "player.qh"
-#include "../triggers/include.qh"
+#include "../mapobjects/_mod.qh"
#include "../viewloc.qh"
#ifdef SVQC
#include <server/miscfunctions.qh>
-#include "../triggers/trigger/viewloc.qh"
+#include "../mapobjects/trigger/viewloc.qh"
// client side physics
bool Physics_Valid(string thecvar)
{
- return autocvar_g_physics_clientselect && strhasword(autocvar_g_physics_clientselect_options, thecvar);
+ return autocvar_g_physics_clientselect && thecvar != "" && thecvar && thecvar != "default" && strhasword(autocvar_g_physics_clientselect_options, thecvar);
}
float Physics_ClientOption(entity this, string option, float defaultval)
{
- if(Physics_Valid(this.cvar_cl_physics))
+ if(IS_REAL_CLIENT(this) && Physics_Valid(CS(this).cvar_cl_physics))
{
- string s = sprintf("g_physics_%s_%s", this.cvar_cl_physics, option);
+ string s = strcat("g_physics_", CS(this).cvar_cl_physics, "_", option);
if(cvar_type(s) & CVAR_TYPEFLAG_EXISTS)
return cvar(s);
}
- if(autocvar_g_physics_clientselect && autocvar_g_physics_clientselect_default)
+ if(autocvar_g_physics_clientselect && autocvar_g_physics_clientselect_default && autocvar_g_physics_clientselect_default != "")
{
- string s = sprintf("g_physics_%s_%s", autocvar_g_physics_clientselect_default, option);
+ string s = strcat("g_physics_", autocvar_g_physics_clientselect_default, "_", option);
if(cvar_type(s) & CVAR_TYPEFLAG_EXISTS)
return cvar(s);
}
return defaultval;
}
-void Physics_UpdateStats(entity this, float maxspd_mod)
+void Physics_UpdateStats(entity this)
{
+ // update this first, as it's used on all stats (wouldn't want to update them all manually from a mutator hook now, would we?)
+ STAT(MOVEVARS_HIGHSPEED, this) = autocvar_g_movement_highspeed;
+
+ MUTATOR_CALLHOOK(PlayerPhysics_UpdateStats, this);
+ float maxspd_mod = PHYS_HIGHSPEED(this);
+
STAT(MOVEVARS_AIRACCEL_QW, this) = AdjustAirAccelQW(Physics_ClientOption(this, "airaccel_qw", autocvar_sv_airaccel_qw), maxspd_mod);
STAT(MOVEVARS_AIRSTRAFEACCEL_QW, this) = (Physics_ClientOption(this, "airstrafeaccel_qw", autocvar_sv_airstrafeaccel_qw))
? AdjustAirAccelQW(Physics_ClientOption(this, "airstrafeaccel_qw", autocvar_sv_airstrafeaccel_qw), maxspd_mod)
STAT(MOVEVARS_AIRCONTROL, this) = Physics_ClientOption(this, "aircontrol", autocvar_sv_aircontrol);
STAT(MOVEVARS_AIRCONTROL_POWER, this) = Physics_ClientOption(this, "aircontrol_power", autocvar_sv_aircontrol_power);
STAT(MOVEVARS_AIRCONTROL_BACKWARDS, this) = Physics_ClientOption(this, "aircontrol_backwards", autocvar_sv_aircontrol_backwards);
+ STAT(MOVEVARS_AIRCONTROL_SIDEWARDS, this) = Physics_ClientOption(this, "aircontrol_sidewards", autocvar_sv_aircontrol_sidewards);
STAT(MOVEVARS_AIRCONTROL_PENALTY, this) = Physics_ClientOption(this, "aircontrol_penalty", autocvar_sv_aircontrol_penalty);
STAT(MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, this) = Physics_ClientOption(this, "warsowbunny_airforwardaccel", autocvar_sv_warsowbunny_airforwardaccel);
STAT(MOVEVARS_WARSOWBUNNY_TOPSPEED, this) = Physics_ClientOption(this, "warsowbunny_topspeed", autocvar_sv_warsowbunny_topspeed);
STAT(MOVEVARS_AIRACCELERATE, this) = Physics_ClientOption(this, "airaccelerate", autocvar_sv_airaccelerate);
STAT(MOVEVARS_AIRSTOPACCELERATE, this) = Physics_ClientOption(this, "airstopaccelerate", autocvar_sv_airstopaccelerate);
STAT(MOVEVARS_JUMPVELOCITY, this) = Physics_ClientOption(this, "jumpvelocity", autocvar_sv_jumpvelocity);
+ STAT(MOVEVARS_JUMPVELOCITY_CROUCH, this) = Physics_ClientOption(this, "jumpvelocity_crouch", autocvar_sv_jumpvelocity_crouch);
STAT(MOVEVARS_TRACK_CANJUMP, this) = Physics_ClientOption(this, "track_canjump", autocvar_sv_track_canjump);
+
+ MUTATOR_CALLHOOK(PlayerPhysics_PostUpdateStats, this, maxspd_mod);
}
#endif
{
return a == 0 ? (_lerp < 1 ? 0 : b)
: b == 0 ? (_lerp > 0 ? 0 : a)
- : a * pow(fabs(b / a), _lerp);
+ : a * (fabs(b / a) ** _lerp);
}
void PM_ClientMovement_UpdateStatus(entity this)
{
-#ifdef CSQC
if(!IS_PLAYER(this))
return;
- // set crouched
- bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
+ bool have_hook = false;
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
- entity wep = viewmodels[slot];
- if(wep.hook && !wasfreed(wep.hook))
+ #if defined(CSQC)
+ entity wepent = viewmodels[slot];
+ #elif defined(SVQC)
+ .entity weaponentity = weaponentities[slot];
+ entity wepent = this.(weaponentity);
+ #endif
+ if(wepent.hook && !wasfreed(wepent.hook))
{
- do_crouch = false;
- break; // don't bother checking the others
+ have_hook = true;
+ break;
}
}
- if(this.waterlevel >= WATERLEVEL_SWIMMING)
+ bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
+ if (have_hook) {
do_crouch = false;
- if(hud != HUD_NORMAL)
+ //} else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
+ //do_crouch = false;
+ } else if (PHYS_INVEHICLE(this)) {
do_crouch = false;
- if(STAT(FROZEN, this))
+ } else if (STAT(FROZEN, this)) {
do_crouch = false;
+ }
- if (do_crouch)
- {
- // wants to crouch, this always works
- if (!IS_DUCKED(this)) SET_DUCKED(this);
- }
- else
- {
- // wants to stand, if currently crouching we need to check for a low ceiling first
- if (IS_DUCKED(this))
- {
- tracebox(this.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), this.origin, MOVE_NORMAL, this);
- if (!trace_startsolid) UNSET_DUCKED(this);
+ if (do_crouch) {
+ if (!IS_DUCKED(this)) {
+ SET_DUCKED(this);
+ this.view_ofs = STAT(PL_CROUCH_VIEW_OFS, this);
+ setsize(this, STAT(PL_CROUCH_MIN, this), STAT(PL_CROUCH_MAX, this));
+ // setanim(this, this.anim_duck, false, true, true); // this anim is BROKEN anyway
}
+ } else if (IS_DUCKED(this)) {
+ tracebox(this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), this.origin, false, this);
+ if (!trace_startsolid) {
+ UNSET_DUCKED(this);
+ this.view_ofs = STAT(PL_VIEW_OFS, this);
+ setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
+ }
}
+#ifdef CSQC
if (IS_ONGROUND(this) || this.velocity.z <= 0 || PHYS_WATERJUMP_TIME(this) <= 0)
PHYS_WATERJUMP_TIME(this) = 0;
void CPM_PM_Aircontrol(entity this, float dt, vector wishdir, float wishspeed)
{
- float movity = IsMoveInDirection(this.movement, 0);
+ float movity = IsMoveInDirection(PHYS_CS(this).movement, 0);
if(PHYS_AIRCONTROL_BACKWARDS(this))
- movity += IsMoveInDirection(this.movement, 180);
+ movity += IsMoveInDirection(PHYS_CS(this).movement, 180);
+ if(PHYS_AIRCONTROL_SIDEWARDS(this))
+ {
+ movity += IsMoveInDirection(PHYS_CS(this).movement, 90);
+ movity += IsMoveInDirection(PHYS_CS(this).movement, -90);
+ }
float k = 32 * (2 * movity - 1);
if (k <= 0)
if (dot > 0) // we can't change direction while slowing down
{
- k *= pow(dot, PHYS_AIRCONTROL_POWER(this)) * dt;
+ k *= (dot ** PHYS_AIRCONTROL_POWER(this)) * dt;
xyspeed = max(0, xyspeed - PHYS_AIRCONTROL_PENALTY(this) * sqrt(max(0, 1 - dot*dot)) * k/32);
k *= PHYS_AIRCONTROL(this);
this.velocity = normalize(this.velocity * xyspeed + wishdir * k);
#endif
bool doublejump = false;
- float mjumpheight = PHYS_JUMPVELOCITY(this);
+ float mjumpheight = ((PHYS_JUMPVELOCITY_CROUCH(this) && IS_DUCKED(this)) ? PHYS_JUMPVELOCITY_CROUCH(this) : PHYS_JUMPVELOCITY(this));
+ bool track_jump = PHYS_CL_TRACK_CANJUMP(this);
if (MUTATOR_CALLHOOK(PlayerJump, this, mjumpheight, doublejump))
return true;
{
doublejump = true;
mjumpheight *= 0.7;
+ track_jump = true;
}
else
{
if (!IS_ONGROUND(this) && !IS_ONSLICK(this))
return IS_JUMP_HELD(this);
- bool track_jump = PHYS_CL_TRACK_CANJUMP(this);
if(PHYS_TRACK_CANJUMP(this))
track_jump = true;
#ifdef SVQC
- #define JETPACK_JUMP(s) s.cvar_cl_jetpack_jump
+ #define JETPACK_JUMP(s) CS(s).cvar_cl_jetpack_jump
#elif defined(CSQC)
float autocvar_cl_jetpack_jump;
#define JETPACK_JUMP(s) autocvar_cl_jetpack_jump
CheckWaterJump(this);
}
-float racecar_angle(float forward, float down)
+#ifdef SVQC
+string specialcommand = "xwxwxsxsxaxdxaxdx1x ";
+.float specialcommand_pos;
+void SpecialCommand(entity this)
{
- if (forward < 0)
+ if(autocvar_sv_cheats || this.maycheat)
{
- forward = -forward;
- down = -down;
+ if (!CheatImpulse(this, CHIMPULSE_GIVE_ALL.impulse))
+ LOG_INFO("A hollow voice says \"Plugh\".");
}
-
- float ret = vectoyaw('0 1 0' * down + '1 0 0' * forward);
-
- float angle_mult = forward / (800 + forward);
-
- if (ret > 180)
- return ret * angle_mult + 360 * (1 - angle_mult);
else
- return ret * angle_mult;
+ STAT(MOVEVARS_SPECIALCOMMAND, this) = true;
}
-
-string specialcommand = "xwxwxsxsxaxdxaxdx1x ";
-.float specialcommand_pos;
-void SpecialCommand(entity this)
-{
-#ifdef SVQC
- if (!CheatImpulse(this, CHIMPULSE_GIVE_ALL.impulse))
- LOG_INFO("A hollow voice says \"Plugh\".\n");
#endif
-}
bool PM_check_specialcommand(entity this, int buttons)
{
else
c = "?";
- if (c == substring(specialcommand, this.specialcommand_pos, 1))
+ if (c == substring(specialcommand, CS(this).specialcommand_pos, 1))
{
- this.specialcommand_pos += 1;
- if (this.specialcommand_pos >= strlen(specialcommand))
+ CS(this).specialcommand_pos += 1;
+ if (CS(this).specialcommand_pos >= strlen(specialcommand))
{
- this.specialcommand_pos = 0;
+ CS(this).specialcommand_pos = 0;
SpecialCommand(this);
return true;
}
}
- else if (this.specialcommand_pos && (c != substring(specialcommand, this.specialcommand_pos - 1, 1)))
- this.specialcommand_pos = 0;
+ else if (CS(this).specialcommand_pos && (c != substring(specialcommand, CS(this).specialcommand_pos - 1, 1)))
+ CS(this).specialcommand_pos = 0;
#endif
return false;
}
if (this.nickspamcount >= autocvar_g_nick_flood_penalty_yellow)
{
// slight annoyance for nick change scripts
- this.movement = -1 * this.movement;
+ PHYS_CS(this).movement = -1 * PHYS_CS(this).movement;
PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_JUMP(this) = PHYS_INPUT_BUTTON_ATCK2(this) = PHYS_INPUT_BUTTON_ZOOM(this) = PHYS_INPUT_BUTTON_CROUCH(this) = PHYS_INPUT_BUTTON_HOOK(this) = PHYS_INPUT_BUTTON_USE(this) = false;
if (this.nickspamcount >= autocvar_g_nick_flood_penalty_red) // if you are persistent and the slight annoyance above does not stop you, I'll show you!
#endif
)
{
- this.movement_x = bound(-5, this.movement.x, 5);
- this.movement_y = bound(-5, this.movement.y, 5);
- this.movement_z = bound(-5, this.movement.z, 5);
+ PHYS_CS(this).movement_x = bound(-5, PHYS_CS(this).movement.x, 5);
+ PHYS_CS(this).movement_y = bound(-5, PHYS_CS(this).movement.y, 5);
+ PHYS_CS(this).movement_z = bound(-5, PHYS_CS(this).movement.z, 5);
}
else
- this.movement = '0 0 0';
+ PHYS_CS(this).movement = '0 0 0';
vector midpoint = ((this.absmin + this.absmax) * 0.5);
if (pointcontents(midpoint) == CONTENT_WATER)
#ifdef SVQC
if (!this.player_blocked)
return;
- this.movement = '0 0 0';
+ PHYS_CS(this).movement = '0 0 0';
this.disableclientprediction = 1;
#endif
}
{
//makevectors(this.v_angle.y * '0 1 0');
makevectors(this.v_angle);
- vector wishvel = v_forward * this.movement_x
- + v_right * this.movement_y;
+ vector wishvel = v_forward * PHYS_CS(this).movement_x
+ + v_right * PHYS_CS(this).movement_y;
// add remaining speed as Z component
float maxairspd = PHYS_MAXAIRSPEED(this) * max(1, maxspd_mod);
// fix speedhacks :P
float a_up = PHYS_JETPACK_ACCEL_UP(this);
float a_add = PHYS_JETPACK_ANTIGRAVITY(this) * PHYS_GRAVITY(this);
- if(PHYS_JETPACK_REVERSE_THRUST(this) && PHYS_INPUT_BUTTON_CROUCH(self)) { a_up = PHYS_JETPACK_REVERSE_THRUST(this); }
+ if(PHYS_JETPACK_REVERSE_THRUST(this) && PHYS_INPUT_BUTTON_CROUCH(this)) { a_up = PHYS_JETPACK_REVERSE_THRUST(this); }
wishvel_x *= a_side;
wishvel_y *= a_side;
wishvel_z *= a_up;
wishvel_z += a_add;
- if(PHYS_JETPACK_REVERSE_THRUST(this) && PHYS_INPUT_BUTTON_CROUCH(self)) { wishvel_z *= -1; }
+ if(PHYS_JETPACK_REVERSE_THRUST(this) && PHYS_INPUT_BUTTON_CROUCH(this)) { wishvel_z *= -1; }
float best = 0;
//////////////////////////////////////////////////////////////////////////////////////
#ifdef SVQC
if (!(ITEMS_STAT(this) & IT_UNLIMITED_WEAPON_AMMO))
- this.ammo_fuel -= PHYS_JETPACK_FUEL(this) * dt * fvel * f;
+ SetResourceAmountExplicit(this, RESOURCE_FUEL, GetResourceAmount(this, RESOURCE_FUEL) - PHYS_JETPACK_FUEL(this) * dt * fvel * f);
ITEMS_STAT(this) |= IT_USING_JETPACK;
void CSQC_ClientMovement_PlayerMove_Frame(entity this)
#endif
{
+#ifdef SVQC
+ // needs to be called before physics are run!
+ if(IS_REAL_CLIENT(this))
+ PM_UpdateButtons(this, CS(this));
+#endif
+
sys_phys_update(this, PHYS_INPUT_TIMELENGTH);
#ifdef SVQC
- this.pm_frametime = frametime;
+ CS(this).pm_frametime = frametime;
+#elif defined(CSQC)
+ if((ITEMS_STAT(this) & IT_USING_JETPACK) && !IS_DEAD(this) && !intermission)
+ this.csqcmodel_modelflags |= MF_ROCKET;
+ else
+ this.csqcmodel_modelflags &= ~MF_ROCKET;
#endif
}