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)
}
#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;
if(dt <= 0)
return 0;
- int blocked = 0;
+ int blockedflag = 0;
int i, j, numplanes = 0;
float time_left = dt, grav = 0;
vector push;
{
// we got teleported by a touch function
// let's abort the move
- blocked |= 8;
+ blockedflag |= 8;
break;
}
if(trace_plane_normal.z > 0.7)
{
// floor
- blocked |= 1;
+ blockedflag |= 1;
if(!trace_ent)
{
if(!_Movetype_PushEntity(this, steppush, true, false))
{
- blocked |= 8;
+ blockedflag |= 8;
break;
}
if(!_Movetype_PushEntity(this, push, true, false))
{
- blocked |= 8;
+ blockedflag |= 8;
break;
}
float trace2_fraction = trace_fraction;
steppush = vec3(0, 0, org.z - this.origin_z);
if(!_Movetype_PushEntity(this, steppush, true, false))
{
- blocked |= 8;
+ blockedflag |= 8;
break;
}
else
{
// step - return it to caller
- blocked |= 2;
+ blockedflag |= 2;
// save the trace for player extrafriction
if(applystepnormal)
move_stepnormal = trace_plane_normal;
{
// this shouldn't really happen
this.velocity = '0 0 0';
- blocked = 3;
+ blockedflag = 3;
break;
}
if(numplanes != 2)
{
this.velocity = '0 0 0';
- blocked = 7;
+ blockedflag = 7;
break;
}
vector dir = cross(planes[0], planes[1]);
}
// 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) && !(blocked & 8))
+ if(PHYS_WALLCLIP(this) && this.pm_time && !(this.flags & FL_WATERJUMP) && !(blockedflag & 8))
this.velocity = primal_velocity;
if(applygravity)
}
}
- return blocked;
+ return blockedflag;
}
void _Movetype_CheckVelocity(entity this) // SV_CheckVelocity
gettouch(this)(this, 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
_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 & 32) // TODO: 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(org, this.mins, this.maxs, org, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this);
- this.dphitcontentsmask = cont;
-
- 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_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;
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(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8)
- X(9) 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));
}
LOG_DEBUGF("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)",
etof(this), this.classname, vtos(this.origin));
- _Movetype_LinkEdict(this, true);
+ _Movetype_LinkEdict(this, false);
return UNSTICK_FIXED;
}
return (this.origin == last_origin); // false if teleported by touch
}
-
-.float ltime;
-.void() blocked;
-
void _Movetype_Physics_Frame(entity this, float movedt)
{
this.move_didgravity = -1;
{
case MOVETYPE_PUSH:
case MOVETYPE_FAKEPUSH:
- LOG_DEBUG("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!");
+ _Movetype_Physics_Push(this, movedt);
break;
case MOVETYPE_NONE:
break;
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:
{
Movetype_Physics_NoMatchServer(this);
- 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;