From f0bc9a75216787dcb6e3809c8853f18a604fbd23 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 29 Dec 2019 21:16:25 +1000 Subject: [PATCH] Make the QC physics match the engine a bit more accurately, fixes some issues with bullet casings and projectiles visibly bouncing before disappearing on impact --- qcsrc/common/mapobjects/trigger/jumppads.qc | 4 +- qcsrc/common/physics/movetypes/movetypes.qc | 85 ++++++++++++--------- qcsrc/common/physics/movetypes/movetypes.qh | 5 ++ qcsrc/common/physics/movetypes/toss.qc | 68 +++++++++++------ qcsrc/common/stats.qh | 8 ++ 5 files changed, 110 insertions(+), 60 deletions(-) diff --git a/qcsrc/common/mapobjects/trigger/jumppads.qc b/qcsrc/common/mapobjects/trigger/jumppads.qc index f438fbf01..f4b3e455a 100644 --- a/qcsrc/common/mapobjects/trigger/jumppads.qc +++ b/qcsrc/common/mapobjects/trigger/jumppads.qc @@ -36,8 +36,8 @@ vector trigger_push_calculatevelocity(vector org, entity tgt, float ht, entity p torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5; grav = PHYS_GRAVITY(NULL); - if(pushed_entity && PHYS_ENTGRAVITY(pushed_entity)) - grav *= PHYS_ENTGRAVITY(pushed_entity); + if(pushed_entity && pushed_entity.gravity) + grav *= pushed_entity.gravity; zdist = torg.z - org.z; sdist = vlen(torg - org - zdist * '0 0 1'); diff --git a/qcsrc/common/physics/movetypes/movetypes.qc b/qcsrc/common/physics/movetypes/movetypes.qc index 8eb2277d5..108782ef9 100644 --- a/qcsrc/common/physics/movetypes/movetypes.qc +++ b/qcsrc/common/physics/movetypes/movetypes.qc @@ -54,7 +54,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno if(applygravity) { this.move_didgravity = 1; - grav = dt * (PHYS_ENTGRAVITY(this) ? PHYS_ENTGRAVITY(this) : 1) * PHYS_GRAVITY(this); + grav = dt * (this.gravity ? this.gravity : 1) * PHYS_GRAVITY(this); if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !IS_ONGROUND(this)) { @@ -324,11 +324,24 @@ void _Movetype_CheckWaterTransition(entity ent) // SV_CheckWaterTransition void _Movetype_Impact(entity this, entity oth) // SV_Impact { - if(gettouch(this)) + if(!this && !oth) + return; + + if(this.solid != SOLID_NOT && gettouch(this)) gettouch(this)(this, oth); - if(gettouch(oth)) + if(oth.solid != SOLID_NOT && gettouch(oth)) + { + trace_endpos = oth.origin; + trace_plane_normal = -trace_plane_normal; + trace_plane_dist = -trace_plane_dist; + trace_ent = this; + trace_dpstartcontents = 0; + trace_dphitcontents = 0; + trace_dphitq3surfaceflags = 0; + trace_dphittexturename = string_null; gettouch(oth)(oth, this); + } } void _Movetype_LinkEdict_TouchAreaGrid(entity this) // SV_LinkEdict_TouchAreaGrid @@ -526,12 +539,10 @@ bool _Movetype_PushEntity(entity this, vector push, bool failonstartsolid, bool vector last_origin = this.origin; - if(dolink) - _Movetype_LinkEdict(this, true); + _Movetype_LinkEdict(this, dolink); - if(trace_fraction < 1) - if(this.solid >= SOLID_TRIGGER && trace_ent && (!IS_ONGROUND(this) || (this.groundentity != trace_ent))) - _Movetype_Impact(this, trace_ent); + if((this.solid >= SOLID_TRIGGER && trace_fraction < 1 && (!IS_ONGROUND(this) || this.groundentity != trace_ent))) + _Movetype_Impact(this, trace_ent); return (this.origin == last_origin); // false if teleported by touch } @@ -657,12 +668,14 @@ void Movetype_Physics_MatchServer(entity this, bool sloppy) Movetype_Physics_MatchTicrate(this, TICRATE, sloppy); } +// saved .move_* .vector tic_origin; .vector tic_velocity; .int tic_flags; .vector tic_avelocity; .vector tic_angles; +// saved .* .vector tic_saved_origin; .vector tic_saved_velocity; .int tic_saved_flags; @@ -670,6 +683,8 @@ void Movetype_Physics_MatchServer(entity this, bool sloppy) .vector tic_saved_angles; void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy) // SV_Physics_Entity { + // this hack exists to contain the physics feature + // (so entities can place themselves in the world and not need to update .tic_* themselves) #define X(s) \ if(this.(s) != this.tic_saved_##s) \ this.tic_##s = this.(s) @@ -681,19 +696,15 @@ void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy) // SV_Ph X(angles); #undef X + this.flags = this.tic_flags; + this.velocity = this.tic_velocity; + setorigin(this, this.tic_origin); + this.avelocity = this.tic_avelocity; + this.angles = this.tic_angles; + if(tr <= 0) { - this.flags = this.tic_flags; - this.velocity = this.tic_velocity; - this.origin = this.tic_origin; - this.avelocity = this.tic_avelocity; - this.angles = this.tic_angles; Movetype_Physics_NoMatchServer(this); - this.tic_origin = this.origin; - this.tic_velocity = this.velocity; - this.tic_avelocity = this.avelocity; - this.tic_angles = this.angles; - this.tic_flags = this.flags; this.tic_saved_flags = this.flags; this.tic_saved_velocity = this.velocity; @@ -712,23 +723,27 @@ void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy) // SV_Ph if(!this.move_didgravity) this.move_didgravity = ((this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS) && !(this.tic_flags & FL_ONGROUND)); - for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) { - this.flags = this.tic_flags; - this.velocity = this.tic_velocity; - setorigin(this, this.tic_origin); - this.avelocity = this.tic_avelocity; - this.angles = this.tic_angles; _Movetype_Physics_Frame(this, tr); - this.tic_origin = this.origin; - this.tic_velocity = this.velocity; - this.tic_avelocity = this.avelocity; - this.tic_angles = this.angles; - this.tic_flags = this.flags; if(wasfreed(this)) return; } + // update the physics fields + this.tic_origin = this.origin; + this.tic_velocity = this.velocity; + this.tic_avelocity = this.avelocity; + this.tic_angles = this.angles; + this.tic_flags = this.flags; + + // restore their actual values + this.flags = this.tic_saved_flags; + this.velocity = this.tic_saved_velocity; + setorigin(this, this.tic_saved_origin); + //this.avelocity = this.tic_saved_avelocity; + this.angles = this.tic_saved_angles; + this.avelocity = this.tic_avelocity; if(dt > 0 && this.move_movetype != MOVETYPE_NONE && !(this.tic_flags & FL_ONGROUND)) @@ -740,7 +755,7 @@ void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy) // SV_Ph { this.velocity_z -= (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1) * dt - * (this.gravity ? this.gravity : 1) + * ((this.gravity) ? this.gravity : 1) * PHYS_GRAVITY(this); } @@ -752,16 +767,16 @@ void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy) // SV_Ph } else { - vector oldorg = this.origin; - this.origin = this.tic_origin; + setorigin(this, this.tic_origin); _Movetype_PushEntityTrace(this, dt * this.velocity); - this.origin = oldorg; if(!trace_startsolid) setorigin(this, trace_endpos); + else + setorigin(this, this.tic_saved_origin); } if(this.move_didgravity > 0 && GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE) - this.velocity_z -= 0.5 * dt * (this.gravity ? this.gravity : 1) * PHYS_GRAVITY(this); + this.velocity_z -= 0.5 * dt * ((this.gravity) ? this.gravity : 1) * PHYS_GRAVITY(this); } else { @@ -770,6 +785,8 @@ void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy) // SV_Ph setorigin(this, this.tic_origin); } + this.flags = this.tic_flags; + this.tic_saved_flags = this.flags; this.tic_saved_velocity = this.velocity; this.tic_saved_origin = this.origin; diff --git a/qcsrc/common/physics/movetypes/movetypes.qh b/qcsrc/common/physics/movetypes/movetypes.qh index 51da5e730..0c8bc6948 100644 --- a/qcsrc/common/physics/movetypes/movetypes.qh +++ b/qcsrc/common/physics/movetypes/movetypes.qh @@ -19,8 +19,13 @@ const int WATERLEVEL_SUBMERGED = 3; #define GAMEPLAYFIX_STEPMULTIPLETIMES(s) STAT(GAMEPLAYFIX_STEPMULTIPLETIMES) #define GAMEPLAYFIX_UNSTICKPLAYERS(s) STAT(GAMEPLAYFIX_UNSTICKPLAYERS) #define GAMEPLAYFIX_WATERTRANSITION(s) STAT(GAMEPLAYFIX_WATERTRANSITION) +#define GAMEPLAYFIX_SLIDEMOVEPROJECTILES(s) STAT(GAMEPLAYFIX_SLIDEMOVEPROJECTILES) +#define GAMEPLAYFIX_GRENADEBOUNCESLOPES(s) STAT(GAMEPLAYFIX_GRENADEBOUNCESLOPES) +#define GAMEPLAYFIX_NOAIRBORNCORPSE(s) STAT(GAMEPLAYFIX_NOAIRBORNCORPSE) +#define NOAIRBORNCORPSE_ALLOWSUSPENDED(s) STAT(NOAIRBORNCORPSE_ALLOWSUSPENDED) #define UPWARD_VELOCITY_CLEARS_ONGROUND(s) STAT(GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND) + #define PHYS_STEPHEIGHT(s) STAT(MOVEVARS_STEPHEIGHT) #define PHYS_NOSTEP(s) STAT(NOSTEP) #define PHYS_JUMPSTEP(s) STAT(MOVEVARS_JUMPSTEP) diff --git a/qcsrc/common/physics/movetypes/toss.qc b/qcsrc/common/physics/movetypes/toss.qc index fc3de0859..772eb1b07 100644 --- a/qcsrc/common/physics/movetypes/toss.qc +++ b/qcsrc/common/physics/movetypes/toss.qc @@ -2,19 +2,26 @@ void _Movetype_Physics_Toss(entity this, float dt) // SV_Physics_Toss { - if (IS_ONGROUND(this)) + if(IS_ONGROUND(this)) { - if (this.velocity.z >= 1 / 32 && UPWARD_VELOCITY_CLEARS_ONGROUND(this)) + if(this.velocity.z >= (1 / 32) && UPWARD_VELOCITY_CLEARS_ONGROUND(this)) { + // don't stick to ground if onground and moving upward UNSET_ONGROUND(this); } - else if (!this.groundentity) + else if(!this.groundentity || !GAMEPLAYFIX_NOAIRBORNCORPSE(this)) { return; } - else if (this.move_suspendedinair && wasfreed(this.groundentity)) + else if(this.move_suspendedinair && wasfreed(this.groundentity)) { this.groundentity = NULL; + if(NOAIRBORNCORPSE_ALLOWSUSPENDED(this)) + return; + } + else if(boxesoverlap(this.absmin, this.absmax, this.groundentity.absmin, this.groundentity.absmax)) + { + // don't slide if still touching the groundentity return; } } @@ -23,35 +30,37 @@ void _Movetype_Physics_Toss(entity this, float dt) // SV_Physics_Toss _Movetype_CheckVelocity(this); - /*if (this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS) + if(this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS) { - this.move_didgravity = 1; + this.move_didgravity = true; this.velocity_z -= (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1) * dt - * (this.gravity ? this.gravity : 1) + * ((this.gravity) ? this.gravity : 1) * PHYS_GRAVITY(this); - }*/ + } - if (this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS) + /*if (this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS) { this.move_didgravity = true; this.velocity_z -= (((this.gravity) ? this.gravity : 1) * PHYS_GRAVITY(this) * dt); - } + }*/ this.angles = this.angles + this.avelocity * dt; float movetime = dt; - for (int bump = 0; bump < MAX_CLIP_PLANES && movetime > 0; ++bump) + for (int bump = 0; bump < MAX_CLIP_PLANES && movetime > 0; bump++) { vector move = this.velocity * movetime; - _Movetype_PushEntity(this, move, true, false); + if(!_Movetype_PushEntity(this, move, true, true)) + return; if (wasfreed(this)) return; if (trace_startsolid) { _Movetype_UnstickEntity(this); - _Movetype_PushEntity(this, move, false, false); + if(!_Movetype_PushEntity(this, move, true, true)) + return; if (wasfreed(this)) return; } @@ -63,28 +72,36 @@ void _Movetype_Physics_Toss(entity this, float dt) // SV_Physics_Toss if (this.move_movetype == MOVETYPE_BOUNCEMISSILE) { - this.velocity = _Movetype_ClipVelocity(this.velocity, trace_plane_normal, 2.0); + float bouncefac = (!this.bouncefactor) ? 1.0 : this.bouncefactor; + this.velocity = _Movetype_ClipVelocity(this.velocity, trace_plane_normal, 1 + bouncefac); UNSET_ONGROUND(this); + if(!GAMEPLAYFIX_SLIDEMOVEPROJECTILES(this)) + movetime = 0; } else if (this.move_movetype == MOVETYPE_BOUNCE) { - float bouncefac = this.bouncefactor; if (!bouncefac) bouncefac = 0.5; - float bstop = this.bouncestop; if (!bstop) bstop = 60 / 800; - bstop *= (this.gravity ? this.gravity : 1) * PHYS_GRAVITY(this); + float bouncefac = (!this.bouncefactor) ? 0.5 : this.bouncefactor; + float bstop = (!this.bouncestop) ? (60 / 800) : this.bouncestop; + float grav = ((this.gravity) ? this.gravity : 1); this.velocity = _Movetype_ClipVelocity(this.velocity, trace_plane_normal, 1 + bouncefac); float d = trace_plane_normal * this.velocity; - if (trace_plane_normal.z > 0.7 && d < bstop && d > -bstop) + if(!GAMEPLAYFIX_GRENADEBOUNCESLOPES(this)) + d = this.velocity.z; + if (trace_plane_normal.z > 0.7 && d < PHYS_GRAVITY(this) * bstop * grav) { SET_ONGROUND(this); this.groundentity = trace_ent; this.velocity = '0 0 0'; this.avelocity = '0 0 0'; + movetime = 0; } else { UNSET_ONGROUND(this); + if(!GAMEPLAYFIX_SLIDEMOVEPROJECTILES(this)) + movetime = 0; } } else @@ -98,24 +115,27 @@ void _Movetype_Physics_Toss(entity this, float dt) // SV_Physics_Toss this.move_suspendedinair = true; this.velocity = '0 0 0'; this.avelocity = '0 0 0'; + movetime = 0; } else { UNSET_ONGROUND(this); + if(!GAMEPLAYFIX_SLIDEMOVEPROJECTILES(this)) + movetime = 0; } } // DP revision 8905 (just, WHY...) - if (this.move_movetype == MOVETYPE_BOUNCEMISSILE) - break; + //if (this.move_movetype == MOVETYPE_BOUNCEMISSILE) + //break; // DP revision 8918 (WHY...) - if (IS_ONGROUND(this)) - break; + //if (IS_ONGROUND(this)) + //break; } - //if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE && this.move_didgravity > 0 && !IS_ONGROUND(this)) - // this.velocity_z -= 0.5 * dt * (this.gravity ? this.gravity : 1) * PHYS_GRAVITY(this); + if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE && this.move_didgravity > 0 && !IS_ONGROUND(this)) + this.velocity_z -= 0.5 * dt * ((this.gravity) ? this.gravity : 1) * PHYS_GRAVITY(this); _Movetype_CheckWaterTransition(this); } diff --git a/qcsrc/common/stats.qh b/qcsrc/common/stats.qh index 488d44220..1a9b35ec0 100644 --- a/qcsrc/common/stats.qh +++ b/qcsrc/common/stats.qh @@ -193,6 +193,10 @@ int autocvar_sv_gameplayfix_stepdown = 2; int autocvar_sv_gameplayfix_stepmultipletimes = 1; int autocvar_sv_gameplayfix_unstickplayers = 1; int autocvar_sv_gameplayfix_fixedcheckwatertransition = 1; +int autocvar_sv_gameplayfix_slidemoveprojectiles = 1; +int autocvar_sv_gameplayfix_grenadebouncedownslopes = 1; +int autocvar_sv_gameplayfix_noairborncorpse = 1; +int autocvar_sv_gameplayfix_noairborncorpse_allowsuspendeditems = 1; #endif REGISTER_STAT(GAMEPLAYFIX_DOWNTRACEONGROUND, int, autocvar_sv_gameplayfix_downtracesupportsongroundflag) REGISTER_STAT(GAMEPLAYFIX_EASIERWATERJUMP, int, autocvar_sv_gameplayfix_easierwaterjump) @@ -201,6 +205,10 @@ REGISTER_STAT(GAMEPLAYFIX_STEPMULTIPLETIMES, int, autocvar_sv_gameplayfix_stepmu REGISTER_STAT(GAMEPLAYFIX_UNSTICKPLAYERS, int, autocvar_sv_gameplayfix_unstickplayers) REGISTER_STAT(GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND, int, autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag) REGISTER_STAT(GAMEPLAYFIX_WATERTRANSITION, int, autocvar_sv_gameplayfix_fixedcheckwatertransition) +REGISTER_STAT(GAMEPLAYFIX_SLIDEMOVEPROJECTILES, int, autocvar_sv_gameplayfix_slidemoveprojectiles) +REGISTER_STAT(GAMEPLAYFIX_GRENADEBOUNCESLOPES, int, autocvar_sv_gameplayfix_grenadebouncedownslopes) +REGISTER_STAT(GAMEPLAYFIX_NOAIRBORNCORPSE, int, autocvar_sv_gameplayfix_noairborncorpse) +REGISTER_STAT(NOAIRBORNCORPSE_ALLOWSUSPENDED, int, autocvar_sv_gameplayfix_noairborncorpse_allowsuspendeditems) REGISTER_STAT(MOVEVARS_JUMPSTEP, int, cvar("sv_jumpstep")) REGISTER_STAT(NOSTEP, int, cvar("sv_nostep")) -- 2.39.2