X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fphysics%2Fmovetypes%2Fmovetypes.qc;h=93cf2a4d31cd0f4951d81913191fca1d52d6e6fc;hb=e32294da8b1c948ac56c25a2aac9072e5376ee83;hp=68d4c366016f922f0374e54a69a8b34ac1c9dfdd;hpb=4217ea623aa4a6c6eb6b59728e5872b7fb9d0702;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/physics/movetypes/movetypes.qc b/qcsrc/common/physics/movetypes/movetypes.qc index 68d4c3660..93cf2a4d3 100644 --- a/qcsrc/common/physics/movetypes/movetypes.qc +++ b/qcsrc/common/physics/movetypes/movetypes.qc @@ -4,12 +4,14 @@ 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; + } else if (autocvar_sv_qcphysics == 2) { + this.move_qcphysics = true; } 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_NONE : mt; + this.movetype = (this.move_qcphysics) ? MOVETYPE_QCENTITY : mt; } #elif defined(CSQC) void set_movetype(entity this, int mt) @@ -18,6 +20,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; @@ -43,7 +128,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno if(dt <= 0) return 0; - int blocked = 0; + int blockedflag = 0; int i, j, numplanes = 0; float time_left = dt, grav = 0; vector push; @@ -79,7 +164,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno { // we got teleported by a touch function // let's abort the move - blocked |= 8; + blockedflag |= 8; break; } @@ -94,6 +179,8 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno if(trace_fraction == 1) break; + time_left *= 1 - trace_fraction; + float my_trace_fraction = trace_fraction; vector my_trace_plane_normal = trace_plane_normal; @@ -102,7 +189,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno if(trace_plane_normal.z > 0.7) { // floor - blocked |= 1; + blockedflag |= 1; if(!trace_ent) { @@ -119,27 +206,29 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno // step - handle it immediately vector org = this.origin; vector steppush = '0 0 1' * stepheight; + push = this.velocity * time_left; 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; } // accept the new position if it made some progress... - if(fabs(this.origin_x - org.x) >= 0.03125 || fabs(this.origin_y - org.y) >= 0.03125) + // previously this checked if absolute distance >= 0.03125 which made stepping up unreliable + if(this.origin_x - org.x || this.origin_y - org.y) { trace_endpos = this.origin; time_left *= 1 - trace2_fraction; @@ -152,7 +241,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno else { // step - return it to caller - blocked |= 2; + blockedflag |= 2; // save the trace for player extrafriction if(applystepnormal) move_stepnormal = trace_plane_normal; @@ -165,14 +254,12 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno numplanes = 0; } - time_left *= 1 - my_trace_fraction; - // clipped to another plane if(numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen this.velocity = '0 0 0'; - blocked = 3; + blockedflag = 3; break; } @@ -208,7 +295,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno if(numplanes != 2) { this.velocity = '0 0 0'; - blocked = 7; + blockedflag = 7; break; } vector dir = cross(planes[0], planes[1]); @@ -233,10 +320,10 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno } // 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) @@ -248,7 +335,7 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepno } } - return blocked; + return blockedflag; } void _Movetype_CheckVelocity(entity this) // SV_CheckVelocity @@ -329,11 +416,40 @@ void _Movetype_Impact(entity this, entity oth) // SV_Impact if(!this && !oth) return; + // due to a lack of pointers in QC, we must save the trace values and restore them for other functions + bool save_trace_allsolid = trace_allsolid; + bool save_trace_startsolid = trace_startsolid; + float save_trace_fraction = trace_fraction; + bool save_trace_inwater = trace_inwater; + bool save_trace_inopen = trace_inopen; + vector save_trace_endpos = trace_endpos; + vector save_trace_plane_normal = trace_plane_normal; + float save_trace_plane_dist = trace_plane_dist; + entity save_trace_ent = trace_ent; + int save_trace_dpstartcontents = trace_dpstartcontents; + int save_trace_dphitcontents = trace_dphitcontents; + int save_trace_dphitq3surfaceflags = trace_dphitq3surfaceflags; + string save_trace_dphittexturename = trace_dphittexturename; + if(this.solid != SOLID_NOT && gettouch(this)) gettouch(this)(this, oth); if(oth.solid != SOLID_NOT && gettouch(oth)) gettouch(oth)(oth, this); + + trace_allsolid = save_trace_allsolid; + trace_startsolid = save_trace_startsolid; + trace_fraction = save_trace_fraction; + trace_inwater = save_trace_inwater; + trace_inopen = save_trace_inopen; + trace_endpos = save_trace_endpos; + trace_plane_normal = save_trace_plane_normal; + trace_plane_dist = save_trace_plane_dist; + trace_ent = save_trace_ent; + trace_dpstartcontents = save_trace_dpstartcontents; + trace_dphitcontents = save_trace_dphitcontents; + trace_dphitq3surfaceflags = save_trace_dphitq3surfaceflags; + trace_dphittexturename = save_trace_dphittexturename; } void _Movetype_LinkEdict_TouchAreaGrid(entity this) // SV_LinkEdict_TouchAreaGrid @@ -341,7 +457,22 @@ 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, { + // due to a lack of pointers in QC, we must save the trace values and restore them for other functions + bool save_trace_allsolid = trace_allsolid; + bool save_trace_startsolid = trace_startsolid; + float save_trace_fraction = trace_fraction; + bool save_trace_inwater = trace_inwater; + bool save_trace_inopen = trace_inopen; + vector save_trace_endpos = trace_endpos; + vector save_trace_plane_normal = trace_plane_normal; + float save_trace_plane_dist = trace_plane_dist; + entity save_trace_ent = trace_ent; + int save_trace_dpstartcontents = trace_dpstartcontents; + int save_trace_dphitcontents = trace_dphitcontents; + int save_trace_dphitq3surfaceflags = trace_dphitq3surfaceflags; + string save_trace_dphittexturename = trace_dphittexturename; + + 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)) @@ -363,6 +494,20 @@ void _Movetype_LinkEdict_TouchAreaGrid(entity this) // SV_LinkEdict_TouchAreaGr gettouch(it)(it, this); } }); + + trace_allsolid = save_trace_allsolid; + trace_startsolid = save_trace_startsolid; + trace_fraction = save_trace_fraction; + trace_inwater = save_trace_inwater; + trace_inopen = save_trace_inopen; + trace_endpos = save_trace_endpos; + trace_plane_normal = save_trace_plane_normal; + trace_plane_dist = save_trace_plane_dist; + trace_ent = save_trace_ent; + trace_dpstartcontents = save_trace_dpstartcontents; + trace_dphitcontents = save_trace_dphitcontents; + trace_dphitq3surfaceflags = save_trace_dphitq3surfaceflags; + trace_dphittexturename = save_trace_dphittexturename; } bool autocvar__movetype_debug = false; @@ -413,6 +558,30 @@ void _Movetype_LinkEdict(entity this, bool touch_triggers) // SV_LinkEdict _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 { @@ -421,13 +590,12 @@ bool _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition //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); + tracebox(org, this.mins, this.maxs, this.origin, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this); //this.dphitcontentsmask = cont; - - if(trace_startsolid) + if(trace_dpstartcontents & _Movetype_ContentsMask(this)) return true; - if(vdist(trace_endpos - this.origin, >, 0.0001)) + if(vlen2(trace_endpos - this.origin) >= 0.0001) { tracebox(trace_endpos, this.mins, this.maxs, trace_endpos, MOVE_NOMONSTERS, this); if(!trace_startsolid) @@ -436,6 +604,23 @@ bool _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition 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; @@ -450,13 +635,7 @@ int _Movetype_UnstickEntity(entity this) // SV_UnstickEntity 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(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)); @@ -488,7 +667,7 @@ void _Movetype_CheckStuck(entity this) // SV_CheckStuck } } -vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // SV_ClipVelocity +vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // ClipVelocity { vel -= ((vel * norm) * norm) * f; @@ -544,10 +723,6 @@ bool _Movetype_PushEntity(entity this, vector push, bool failonstartsolid, bool 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; @@ -555,7 +730,7 @@ void _Movetype_Physics_Frame(entity this, float movedt) { 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; @@ -581,9 +756,6 @@ 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: break; @@ -621,6 +793,8 @@ void _Movetype_Physics_ClientFrame(entity this, float movedt) 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: @@ -636,12 +810,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; @@ -713,7 +899,7 @@ void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy) // SV_Ph 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;