X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fphysics%2Fmovetypes%2Fmovetypes.qc;h=cbb54cd26e575c8cb6e67740b0b48fa2f02516bf;hb=52575743c833ba5456bddde8738a468e7236a9b4;hp=3fe2808583b94254d580b3c3960b2610c9192e6f;hpb=88e815808cb794930e7a0d6257cfdb8b3456a9a1;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/physics/movetypes/movetypes.qc b/qcsrc/common/physics/movetypes/movetypes.qc index 3fe280858..e20755183 100644 --- a/qcsrc/common/physics/movetypes/movetypes.qc +++ b/qcsrc/common/physics/movetypes/movetypes.qc @@ -4,10 +4,12 @@ void set_movetype(entity this, int mt) { this.move_movetype = mt; - if (mt == MOVETYPE_PHYSICS || mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH) { + if (mt == MOVETYPE_PHYSICS) { this.move_qcphysics = false; } - this.movetype = (this.move_qcphysics) ? MOVETYPE_NONE : mt; + if(!IL_CONTAINS(g_moveables, this)) + IL_PUSH(g_moveables, this); // add it to the moveable entities list (even if it doesn't move!) logic: if an object never sets its movetype, we assume it never does anything notable + this.movetype = (this.move_qcphysics) ? MOVETYPE_QCENTITY : mt; } #elif defined(CSQC) void set_movetype(entity this, int mt) @@ -16,6 +18,89 @@ void set_movetype(entity this, int mt) } #endif +bool _Movetype_NudgeOutOfSolid_PivotIsKnownGood(entity this, vector pivot) // SV_NudgeOutOfSolid_PivotIsKnownGood +{ + vector stuckorigin = this.origin; + vector goodmins = pivot, goodmaxs = pivot; + for(int bump = 0; bump < 6; bump++) + { + int coord = 2 - (bump >> 1); + int dir = (bump & 1); + + for(int subbump = 0; ; ++subbump) + { + vector testorigin = stuckorigin; + if(dir) + { + // pushing maxs + switch(coord) + { + case 0: testorigin.x += this.maxs_x - goodmaxs.x; break; + case 1: testorigin.y += this.maxs_y - goodmaxs.y; break; + case 2: testorigin.z += this.maxs_z - goodmaxs.z; break; + } + } + else + { + // pushing mins + switch(coord) + { + case 0: testorigin.x += this.mins_x - goodmins.x; break; + case 1: testorigin.y += this.mins_y - goodmins.y; break; + case 2: testorigin.z += this.mins_z - goodmins.z; break; + } + } + + tracebox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, this); + if(trace_startsolid && trace_ent.solid == SOLID_BSP) // NOTE: this checks for bmodelstartsolid in the engine + { + // BAD BAD, can't fix that + return false; + } + + if(trace_fraction >= 1) + break; // it WORKS! + + if(subbump >= 10) + { + // BAD BAD, can't fix that + return false; + } + + // we hit something... let's move out of it + vector move = trace_endpos - testorigin; + float nudge = (trace_plane_normal * move) + 0.03125; // FIXME cvar this constant + stuckorigin = stuckorigin + nudge * trace_plane_normal; + } + + if(dir) + { + // pushing maxs + switch(coord) + { + case 0: goodmaxs.x = this.maxs_x; break; + case 1: goodmaxs.y = this.maxs_y; break; + case 2: goodmaxs.z = this.maxs_z; break; + } + } + else + { + // pushing mins + switch(coord) + { + case 0: goodmins.x = this.mins_x; break; + case 1: goodmins.y = this.mins_y; break; + case 2: goodmins.z = this.mins_z; break; + } + } + } + + // WE WIN + this.origin = stuckorigin; + + return true; +} + void _Movetype_WallFriction(entity this, vector stepnormal) // SV_WallFriction { /*float d, i; @@ -34,13 +119,19 @@ void _Movetype_WallFriction(entity this, vector stepnormal) // SV_WallFriction } vector planes[MAX_CLIP_PLANES]; -int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnormal, float stepheight) // SV_FlyMove +int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepnormal, float stepheight) // SV_FlyMove { - int blocked = 0; + move_stepnormal = '0 0 0'; + + if(dt <= 0) + return 0; + + int blockedflag = 0; int i, j, numplanes = 0; float time_left = dt, grav = 0; vector push; - vector primal_velocity, original_velocity, restore_velocity; + vector primal_velocity, original_velocity; + vector restore_velocity = this.velocity; for(i = 0; i < MAX_CLIP_PLANES; ++i) planes[i] = '0 0 0'; @@ -48,7 +139,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma 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)) { @@ -59,7 +150,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma } } - original_velocity = primal_velocity = restore_velocity = this.velocity; + original_velocity = primal_velocity = this.velocity; for(int bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++) { @@ -67,12 +158,11 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma break; push = this.velocity * time_left; - _Movetype_PushEntity(this, push, true); - if(trace_startsolid) + if(!_Movetype_PushEntity(this, push, true, false)) { // we got teleported by a touch function // let's abort the move - blocked |= 8; + blockedflag |= 8; break; } @@ -95,7 +185,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma if(trace_plane_normal.z > 0.7) { // floor - blocked |= 1; + blockedflag |= 1; if(!trace_ent) { @@ -113,24 +203,21 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma vector org = this.origin; vector steppush = '0 0 1' * stepheight; - _Movetype_PushEntity(this, steppush, true); - if(trace_startsolid) + if(!_Movetype_PushEntity(this, steppush, true, false)) { - blocked |= 8; + blockedflag |= 8; break; } - _Movetype_PushEntity(this, push, true); - if(trace_startsolid) + if(!_Movetype_PushEntity(this, push, true, false)) { - blocked |= 8; + blockedflag |= 8; break; } float trace2_fraction = trace_fraction; - steppush = '0 0 1' * (org.z - this.origin_z); - _Movetype_PushEntity(this, steppush, true); - if(trace_startsolid) + steppush = vec3(0, 0, org.z - this.origin_z); + if(!_Movetype_PushEntity(this, steppush, true, false)) { - blocked |= 8; + blockedflag |= 8; break; } @@ -148,10 +235,10 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma else { // step - return it to caller - blocked |= 2; + blockedflag |= 2; // save the trace for player extrafriction - if(stepnormal) - stepnormal = trace_plane_normal; + if(applystepnormal) + move_stepnormal = trace_plane_normal; } if(my_trace_fraction >= 0.001) @@ -168,7 +255,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma { // this shouldn't really happen this.velocity = '0 0 0'; - blocked = 3; + blockedflag = 3; break; } @@ -204,7 +291,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma if(numplanes != 2) { this.velocity = '0 0 0'; - blocked = 7; + blockedflag = 7; break; } vector dir = cross(planes[0], planes[1]); @@ -229,7 +316,10 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma } // LordHavoc: this came from QW and allows you to get out of water more easily - if(GAMEPLAYFIX_EASIERWATERJUMP(this) && (this.flags & FL_WATERJUMP) && !(blocked & 8)) + if(GAMEPLAYFIX_EASIERWATERJUMP(this) && (this.flags & FL_WATERJUMP) && !(blockedflag & 8)) + this.velocity = primal_velocity; + + if(PHYS_WALLCLIP(this) && this.pm_time && !(this.flags & FL_WATERJUMP) && !(blockedflag & 8)) this.velocity = primal_velocity; if(applygravity) @@ -241,7 +331,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma } } - return blocked; + return blockedflag; } void _Movetype_CheckVelocity(entity this) // SV_CheckVelocity @@ -319,10 +409,13 @@ 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)) gettouch(oth)(oth, this); } @@ -331,7 +424,7 @@ void _Movetype_LinkEdict_TouchAreaGrid(entity this) // SV_LinkEdict_TouchAreaGr if(this.solid == SOLID_NOT) return; - FOREACH_ENTITY_RADIUS(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin), true, { + FOREACH_ENTITY_RADIUS_ORDERED(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin), true, { if (it.solid == SOLID_TRIGGER && it != this) if (it.move_nomonsters != MOVE_NOMONSTERS && it.move_nomonsters != MOVE_WORLDONLY) if (gettouch(it) && boxesoverlap(it.absmin, it.absmax, this.absmin, this.absmax)) @@ -345,96 +438,171 @@ void _Movetype_LinkEdict_TouchAreaGrid(entity this) // SV_LinkEdict_TouchAreaGr trace_plane_normal = '0 0 1'; trace_plane_dist = 0; trace_ent = this; + trace_dpstartcontents = 0; + trace_dphitcontents = 0; + trace_dphitq3surfaceflags = 0; + trace_dphittexturename = string_null; gettouch(it)(it, this); } }); } +bool autocvar__movetype_debug = false; void _Movetype_LinkEdict(entity this, bool touch_triggers) // SV_LinkEdict { - vector mi, ma; - if(this.solid == SOLID_BSP) + if(autocvar__movetype_debug) { - // TODO set the absolute bbox - mi = this.mins; - ma = this.maxs; - } - else - { - mi = this.mins; - ma = this.maxs; - } - mi += this.origin; - ma += this.origin; + vector mi, ma; + if(this.solid == SOLID_BSP) + { + // TODO set the absolute bbox + mi = this.mins; + ma = this.maxs; + } + else + { + mi = this.mins; + ma = this.maxs; + } + mi += this.origin; + ma += this.origin; - if(this.flags & FL_ITEM) - { - mi -= '15 15 1'; - ma += '15 15 1'; + if(this.flags & FL_ITEM) + { + mi -= '15 15 1'; + ma += '15 15 1'; + } + else + { + mi -= '1 1 1'; + ma += '1 1 1'; + } + + this.absmin = mi; + this.absmax = ma; } else { - mi -= '1 1 1'; - ma += '1 1 1'; + setorigin(this, this.origin); // calls SV_LinkEdict + #ifdef CSQC + // NOTE: CSQC's version of setorigin doesn't expand + this.absmin -= '1 1 1'; + this.absmax += '1 1 1'; + #endif } - this.absmin = mi; - this.absmax = ma; - if(touch_triggers) _Movetype_LinkEdict_TouchAreaGrid(this); } +int _Movetype_ContentsMask(entity this) // SV_GenericHitSuperContentsMask +{ + if(this) + { + if(this.dphitcontentsmask) + return this.dphitcontentsmask; + else if(this.solid == SOLID_SLIDEBOX) + { + if(this.flags & FL_MONSTER) + return DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_MONSTERCLIP; + else + return DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP; + } + else if(this.solid == SOLID_CORPSE) + return DPCONTENTS_SOLID | DPCONTENTS_BODY; + else if(this.solid == SOLID_TRIGGER) + return DPCONTENTS_SOLID | DPCONTENTS_BODY; + else + return DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; + } + else + return DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; +} + entity _Movetype_TestEntityPosition_ent; bool _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition { entity this = _Movetype_TestEntityPosition_ent; -// vector org = this.origin + ofs; - - int cont = this.dphitcontentsmask; - this.dphitcontentsmask = DPCONTENTS_SOLID; - tracebox(this.origin, this.mins, this.maxs, this.origin, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this); - this.dphitcontentsmask = cont; + vector org = this.origin + ofs; - if(trace_startsolid) + //int cont = this.dphitcontentsmask; + //this.dphitcontentsmask = DPCONTENTS_SOLID; + tracebox(org, this.mins, this.maxs, this.origin, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this); + //this.dphitcontentsmask = cont; + if(trace_dpstartcontents & _Movetype_ContentsMask(this)) return true; - if(vdist(trace_endpos - this.origin, >, 0.0001)) - this.origin = trace_endpos; + if(vlen2(trace_endpos - this.origin) >= 0.0001) + { + tracebox(trace_endpos, this.mins, this.maxs, trace_endpos, MOVE_NOMONSTERS, this); + if(!trace_startsolid) + this.origin = trace_endpos; + } return false; } -bool _Movetype_UnstickEntity(entity this) // SV_UnstickEntity +bool _Movetype_TestEntityPosition_Offset(int offset) +{ + // NOTE: expects _Movetype_TestEntityPosition_ent to be set to the correct entity + // returns true if stuck + + // start at 2, since the first position has already been checked + for(int j = 2; j <= offset; ++j) + { + if(!_Movetype_TestEntityPosition('0 0 -1' * j)) + return false; + if(!_Movetype_TestEntityPosition('0 0 1' * j)) + return false; + } + + return true; +} + +int _Movetype_UnstickEntity(entity this) // SV_UnstickEntity { _Movetype_TestEntityPosition_ent = this; if (!_Movetype_TestEntityPosition(' 0 0 0')) { - return true; + return UNSTICK_FINE; } #define X(v) if (_Movetype_TestEntityPosition(v)) + X('0 0 -1') X(' 0 0 1') X('-1 0 0') X(' 1 0 0') X(' 0 -1 0') X(' 0 1 0') X('-1 -1 0') X(' 1 -1 0') X('-1 1 0') X(' 1 1 0') #undef X { - #define X(i) \ - if (_Movetype_TestEntityPosition('0 0 -1' * i)) \ - if (_Movetype_TestEntityPosition('0 0 1' * i)) - X(01) X(02) X(03) X(04) X(05) X(06) X(07) X(08) - X(09) X(10) X(11) X(12) X(13) X(14) X(15) X(16) - X(17) - #undef X + if(_Movetype_TestEntityPosition_Offset(rint((this.maxs.z - this.mins.z) * 0.36))) { LOG_DEBUGF("Can't unstick an entity (edict: %d, classname: %s, origin: %s)", etof(this), this.classname, vtos(this.origin)); - return false; + return UNSTICK_STUCK; } } LOG_DEBUGF("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)", etof(this), this.classname, vtos(this.origin)); - _Movetype_LinkEdict(this, true); - return true; + _Movetype_LinkEdict(this, false); + return UNSTICK_FIXED; +} + +void _Movetype_CheckStuck(entity this) // SV_CheckStuck +{ + int unstick = _Movetype_UnstickEntity(this); // sets test position entity + switch(unstick) + { + case UNSTICK_FINE: + this.oldorigin = this.origin; + break; + case UNSTICK_FIXED: + break; // already sorted + case UNSTICK_STUCK: + vector offset = this.oldorigin - this.origin; + if(!_Movetype_TestEntityPosition(offset)) + _Movetype_LinkEdict(this, false); + // couldn't unstick, should we warn about this? + break; + } } vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // SV_ClipVelocity @@ -466,25 +634,32 @@ void _Movetype_PushEntityTrace(entity this, vector push) tracebox(this.origin, this.mins, this.maxs, end, type, this); } -float _Movetype_PushEntity(entity this, vector push, bool failonstartsolid) // SV_PushEntity +bool _Movetype_PushEntity(entity this, vector push, bool failonstartsolid, bool dolink) // SV_PushEntity { _Movetype_PushEntityTrace(this, push); + // NOTE: this is a workaround for the QC's lack of a worldstartsolid trace parameter if(trace_startsolid && failonstartsolid) - return trace_fraction; + { + int oldtype = this.move_nomonsters; + this.move_nomonsters = MOVE_WORLDONLY; + _Movetype_PushEntityTrace(this, push); + this.move_nomonsters = oldtype; + if(trace_startsolid) + return true; + } this.origin = trace_endpos; - if(trace_fraction < 1) - if(this.solid >= SOLID_TRIGGER && (!IS_ONGROUND(this) || (this.groundentity != trace_ent))) - _Movetype_Impact(this, trace_ent); + vector last_origin = this.origin; - return trace_fraction; -} + _Movetype_LinkEdict(this, dolink); + if((this.solid >= SOLID_TRIGGER && trace_fraction < 1 && (!IS_ONGROUND(this) || this.groundentity != trace_ent))) + _Movetype_Impact(this, trace_ent); -.float ltime; -.void() blocked; + return (this.origin == last_origin); // false if teleported by touch +} void _Movetype_Physics_Frame(entity this, float movedt) { @@ -493,7 +668,7 @@ void _Movetype_Physics_Frame(entity this, float movedt) { case MOVETYPE_PUSH: case MOVETYPE_FAKEPUSH: - LOG_DEBUGF("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!"); + _Movetype_Physics_Push(this, movedt); break; case MOVETYPE_NONE: break; @@ -519,6 +694,8 @@ void _Movetype_Physics_Frame(entity this, float movedt) case MOVETYPE_FLY: case MOVETYPE_FLY_WORLDONLY: _Movetype_Physics_Toss(this, movedt); + if(wasfreed(this)) + return; _Movetype_LinkEdict(this, true); break; case MOVETYPE_PHYSICS: @@ -533,7 +710,7 @@ void _Movetype_Physics_ClientFrame(entity this, float movedt) { case MOVETYPE_PUSH: case MOVETYPE_FAKEPUSH: - LOG_DEBUGF("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!"); + LOG_DEBUG("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!"); break; case MOVETYPE_NONE: break; @@ -546,17 +723,23 @@ void _Movetype_Physics_ClientFrame(entity this, float movedt) this.angles = this.angles + movedt * this.avelocity; break; case MOVETYPE_STEP: + if (GAMEPLAYFIX_UNSTICKPLAYERS(this) == 2) + _Movetype_CheckStuck(this); _Movetype_Physics_Step(this, movedt); break; case MOVETYPE_WALK: case MOVETYPE_FLY: case MOVETYPE_FLY_WORLDONLY: + if (movedt > 0 && GAMEPLAYFIX_UNSTICKPLAYERS(this) == 2) + _Movetype_CheckStuck(this); _Movetype_Physics_Walk(this, movedt); break; case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: case MOVETYPE_BOUNCEMISSILE: case MOVETYPE_FLYMISSILE: + if (GAMEPLAYFIX_UNSTICKPLAYERS(this) == 2) + _Movetype_CheckStuck(this); _Movetype_Physics_Toss(this, movedt); break; case MOVETYPE_PHYSICS: @@ -572,12 +755,24 @@ void _Movetype_Physics_ClientFrame(entity this, float movedt) void Movetype_Physics_NoMatchTicrate(entity this, float movedt, bool isclient) // to be run every move frame { + bool didmove = (this.move_time != 0); this.move_time = time; if(isclient) _Movetype_Physics_ClientFrame(this, movedt); else + { + // this doesn't apply to clients, and only applies to unmatched entities + // don't run think/move on newly spawned projectiles as it messes up + // movement interpolation and rocket trails, and is inconsistent with + // respect to entities spawned in the same frame + // (if an ent spawns a higher numbered ent, it moves in the same frame, + // but if it spawns a lower numbered ent, it doesn't - this never moves + // ents in the first frame regardless) + if(!didmove && GAMEPLAYFIX_DELAYPROJECTILES(this) > 0) + return; _Movetype_Physics_Frame(this, movedt); + } if(wasfreed(this)) return; @@ -601,12 +796,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; @@ -614,6 +811,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) @@ -625,54 +824,54 @@ 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; - this.tic_saved_origin = this.origin; - this.tic_saved_avelocity = this.avelocity; - this.tic_saved_angles = this.angles; + + this.tic_saved_flags = this.tic_flags = this.flags; + this.tic_saved_velocity = this.tic_velocity = this.velocity; + this.tic_saved_origin = this.tic_origin = this.origin; + this.tic_saved_avelocity = this.tic_avelocity = this.avelocity; + this.tic_saved_angles = this.tic_angles = this.angles; return; } float dt = time - this.move_time; - int n = max(0, floor(dt / tr)); + int n = bound(0, floor(dt / tr), 32); // limit the number of frames to 32 (CL_MAX_USERCMDS, using DP_SMALLMEMORY value for consideration of QC's limitations) dt -= n * tr; this.move_time += n * tr; 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)) @@ -684,7 +883,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); } @@ -696,16 +895,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 { @@ -714,6 +913,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;