X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=sv_phys.c;h=abd6005532fa9c6255b0d4b9a6f00627582e1950;hb=67f791e9dfd457941c7b73607fdeec2262020154;hp=591c2baf933c6e367e3a82d27f82857e09a6f07a;hpb=79534d3ffe3463f7f8bd6d45cb5a2146382190ba;p=xonotic%2Fdarkplaces.git diff --git a/sv_phys.c b/sv_phys.c index 591c2baf..abd60055 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -82,15 +82,24 @@ int SV_GenericHitSuperContentsMask(const prvm_edict_t *passedict) SV_Move ================== */ +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +#if COLLISIONPARANOID >= 1 +trace_t SV_Move_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +#else +trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +#endif +#else #if COLLISIONPARANOID >= 1 trace_t SV_Move_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask) #else trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask) #endif +#endif { vec3_t hullmins, hullmaxs; int i, bodysupercontents; int passedictprog; + float pitchsign = 1; qboolean pointtrace; prvm_edict_t *traceowner, *touch; trace_t trace; @@ -111,6 +120,20 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const // list of entities to test for collisions int numtouchedicts; prvm_edict_t *touchedicts[MAX_EDICTS]; +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + vec3_t end; + vec_t len = 0; + + if(!VectorCompare(start, pEnd)) + { + // TRICK: make the trace 1 qu longer! + VectorSubtract(pEnd, start, end); + len = VectorNormalizeLength(end); + VectorAdd(pEnd, end, end); + } + else + VectorCopy(pEnd, end); +#endif VectorCopy(start, clipstart); VectorCopy(end, clipend); @@ -128,7 +151,7 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const if (cliptrace.startsolid || cliptrace.fraction < 1) cliptrace.ent = prog->edicts; if (type == MOVE_WORLDONLY) - return cliptrace; + goto finished; if (type == MOVE_MISSILE) { @@ -218,9 +241,22 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const // if the modelindex is 0, it shouldn't be SOLID_BSP! if (modelindex > 0 && modelindex < MAX_MODELS) model = sv.models[(int)touch->fields.server->modelindex]; + //pitchsign = 1; + if ( + ((modelindex = (int)touch->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS && (model = sv.models[(int)touch->fields.server->modelindex])) + ? + model->type == mod_alias + : + ( + (((unsigned char)PRVM_EDICTFIELDVALUE(touch, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC) + || + ((gamemode == GAME_TENEBRAE) && ((unsigned int)touch->fields.server->effects & (16 | 32))) + ) + ) + pitchsign = -1; } if (model) - Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1); + Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1); else Matrix4x4_CreateTranslate(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2]); Matrix4x4_Invert_Simple(&imatrix, &matrix); @@ -232,6 +268,11 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.server->solid == SOLID_BSP); } +finished: +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + if(!VectorCompare(start, pEnd)) + Collision_ShortenTrace(&cliptrace, len / (len + 1), pEnd); +#endif return cliptrace; } @@ -392,7 +433,7 @@ void SV_LinkEdict (prvm_edict_t *ent, qboolean touch_triggers) if (ent->fields.server->solid == SOLID_BSP) { int modelindex = (int)ent->fields.server->modelindex; - if (modelindex < 0 || modelindex > MAX_MODELS) + if (modelindex < 0 || modelindex >= MAX_MODELS) { Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent)); modelindex = 0; @@ -484,11 +525,13 @@ returns true if the entity is in solid currently */ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset) { + int contents; vec3_t org; trace_t trace; + contents = SV_GenericHitSuperContentsMask(ent); VectorAdd(ent->fields.server->origin, offset, org); - trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent, SUPERCONTENTS_SOLID); - if (trace.startsupercontents & SUPERCONTENTS_SOLID) + trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent, contents); + if (trace.startsupercontents & contents) return true; else { @@ -512,14 +555,27 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset) v[0] = (i & 1) ? m2[0] : m1[0]; v[1] = (i & 2) ? m2[1] : m1[1]; v[2] = (i & 4) ? m2[2] : m1[2]; - if (SV_PointSuperContents(v) & SUPERCONTENTS_SOLID) + if (SV_PointSuperContents(v) & contents) return true; } } } // if the trace found a better position for the entity, move it there if (VectorDistance2(trace.endpos, ent->fields.server->origin) >= 0.0001) + { +#if 0 + // please switch back to this code when trace.endpos sometimes being in solid bug is fixed VectorCopy(trace.endpos, ent->fields.server->origin); +#else + // verify if the endpos is REALLY outside solid + VectorCopy(trace.endpos, org); + trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, org, MOVE_NOMONSTERS, ent, contents); + if(trace.startsolid) + Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n"); + else + VectorCopy(org, ent->fields.server->origin); +#endif + } return false; } @@ -671,14 +727,16 @@ qboolean SV_RunThink (prvm_edict_t *ent) SV_Impact Two entities have touched, so run their touch functions +returns true if the impact kept the origin of the touching entity intact ================== */ extern void VM_SetTraceGlobals(const trace_t *trace); extern sizebuf_t vm_tempstringsbuf; -void SV_Impact (prvm_edict_t *e1, trace_t *trace) +qboolean SV_Impact (prvm_edict_t *e1, trace_t *trace) { int restorevm_tempstringsbuf_cursize; int old_self, old_other; + vec3_t org; prvm_edict_t *e2 = (prvm_edict_t *)trace->ent; prvm_eval_t *val; @@ -686,6 +744,8 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace) old_other = prog->globals.server->other; restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; + VectorCopy(e1->fields.server->origin, org); + VM_SetTraceGlobals(trace); prog->globals.server->time = sv.time; @@ -718,6 +778,8 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace) prog->globals.server->self = old_self; prog->globals.server->other = old_other; vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + + return VectorCompare(e1->fields.server->origin, org); } @@ -753,18 +815,23 @@ Returns the clipflags if the velocity was modified (hit something solid) 1 = floor 2 = wall / step 4 = dead stop +8 = teleported by touch method If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored ============ */ static float SV_Gravity (prvm_edict_t *ent); +static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink); // LordHavoc: increased from 5 to 32 #define MAX_CLIP_PLANES 32 static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask) { int blocked, bumpcount; - int i, j, impact, numplanes; + int i, j, numplanes; float d, time_left, gravity; - vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity; + vec3_t dir, push, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity; +#if 0 + vec3_t end; +#endif trace_t trace; if (time <= 0) return 0; @@ -792,8 +859,18 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo if (!ent->fields.server->velocity[0] && !ent->fields.server->velocity[1] && !ent->fields.server->velocity[2]) break; - VectorMA(ent->fields.server->origin, time_left, ent->fields.server->velocity, end); - trace = SV_Move(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, hitsupercontentsmask); + VectorScale(ent->fields.server->velocity, time_left, push); +#if 0 + VectorAdd(ent->fields.server->origin, push, end); +#endif + if(!SV_PushEntity(&trace, ent, push, false, false)) + { + // we got teleported by a touch function + // let's abort the move + blocked |= 8; + break; + } + #if 0 //if (trace.fraction < 0.002) { @@ -852,27 +929,21 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo } #endif - // break if it moved the entire distance if (trace.fraction == 1) - { - VectorCopy(trace.endpos, ent->fields.server->origin); break; - } - - if (!trace.ent) - { - Con_Printf ("SV_FlyMove: !trace.ent"); - trace.ent = prog->edicts; - } - - impact = !((int) ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace.ent); - if (trace.plane.normal[2]) { if (trace.plane.normal[2] > 0.7) { // floor blocked |= 1; + + if (!trace.ent) + { + Con_Printf ("SV_FlyMove: !trace.ent"); + trace.ent = prog->edicts; + } + ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND; ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent); } @@ -885,25 +956,13 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo if (stepnormal) VectorCopy(trace.plane.normal, stepnormal); } - if (trace.fraction >= 0.001) { // actually covered some distance - VectorCopy(trace.endpos, ent->fields.server->origin); VectorCopy(ent->fields.server->velocity, original_velocity); numplanes = 0; } - // run the impact function - if (impact) - { - SV_Impact(ent, &trace); - - // break if removed by the impact function - if (ent->priv.server->free) - break; - } - time_left *= 1 - trace.fraction; // clipped to another plane @@ -993,7 +1052,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo */ // LordHavoc: this came from QW and allows you to get out of water more easily - if (sv_gameplayfix_easierwaterjump.integer && ((int)ent->fields.server->flags & FL_WATERJUMP)) + if (sv_gameplayfix_easierwaterjump.integer && ((int)ent->fields.server->flags & FL_WATERJUMP) && !(blocked & 8)) VectorCopy(primal_velocity, ent->fields.server->velocity); if (applygravity && !((int)ent->fields.server->flags & FL_ONGROUND)) ent->fields.server->velocity[2] -= gravity; @@ -1033,13 +1092,15 @@ PUSHMOVE SV_PushEntity Does not change the entities velocity at all +The trace struct is filled with the trace that has been done. +Returns true if the push did not result in the entity being teleported by QC code. ============ */ -static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid) +static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink) { int type; - trace_t trace; vec3_t end; + qboolean impact; VectorAdd (ent->fields.server->origin, push, end); @@ -1050,16 +1111,31 @@ static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmo else type = MOVE_NORMAL; - trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent)); - if (trace.bmodelstartsolid && failonbmodelstartsolid) - return trace; + *trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent)); + if (trace->bmodelstartsolid && failonbmodelstartsolid) + return true; + + VectorCopy (trace->endpos, ent->fields.server->origin); - VectorCopy (trace.endpos, ent->fields.server->origin); - SV_LinkEdict (ent, true); +#if 0 + if(!trace->startsolid) + if(SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, type, ent, SV_GenericHitSuperContentsMask(ent)).startsolid) + { + Con_Printf("something eeeeevil happened\n"); + } +#endif - if (ent->fields.server->solid >= SOLID_TRIGGER && trace.ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace.ent))) - SV_Impact (ent, &trace); - return trace; + impact = (ent->fields.server->solid >= SOLID_TRIGGER && trace->ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace->ent))); + + if(impact) + { + SV_LinkEdict (ent, dolink); + return SV_Impact (ent, trace); + } + else if(dolink) + SV_LinkEdict (ent, true); + + return true; } @@ -1081,7 +1157,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) int numcheckentities; static prvm_edict_t *checkentities[MAX_EDICTS]; dp_model_t *pushermodel; - trace_t trace; + trace_t trace, trace2; matrix4x4_t pusherfinalmatrix, pusherfinalimatrix; unsigned short moved_edicts[MAX_EDICTS]; @@ -1262,7 +1338,13 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) // try moving the contacted entity pusher->fields.server->solid = SOLID_NOT; - trace = SV_PushEntity (check, move, true); + if(!SV_PushEntity (&trace, check, move, true, true)) + { + // entity "check" got teleported + check->fields.server->angles[1] += trace.fraction * moveangle[1]; + pusher->fields.server->solid = savesolid; // was SOLID_BSP + continue; // pushed enough + } // FIXME: turn players specially check->fields.server->angles[1] += trace.fraction * moveangle[1]; pusher->fields.server->solid = savesolid; // was SOLID_BSP @@ -1284,7 +1366,11 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) VectorScale(move, 1.1, move2); VectorCopy (check->priv.server->moved_from, check->fields.server->origin); VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); - SV_PushEntity (check, move2, true); + if(!SV_PushEntity (&trace2, check, move2, true, true)) + { + // entity "check" got teleported + continue; + } pusher->fields.server->solid = savesolid; Collision_ClipToGenericEntity(&trace, pushermodel, (int) pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents); if (trace.startsolid) @@ -1294,7 +1380,11 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) VectorScale(move, 0.9, move2); VectorCopy (check->priv.server->moved_from, check->fields.server->origin); VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); - SV_PushEntity (check, move2, true); + if(!SV_PushEntity (&trace2, check, move2, true, true)) + { + // entity "check" got teleported + continue; + } pusher->fields.server->solid = savesolid; Collision_ClipToGenericEntity(&trace, pushermodel, (int) pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents); if (trace.startsolid) @@ -1390,111 +1480,123 @@ CLIENT MOVEMENT static float unstickoffsets[] = { + // poutting -/+z changes first as they are least weird + 0, 0, -1, + 0, 0, 1, + // x or y changes -1, 0, 0, 1, 0, 0, 0, -1, 0, 0, 1, 0, + // x and y changes -1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0, - 0, 0, -1, - 0, 0, 1, - 0, 0, -2, - 0, 0, 2, - 0, 0, -3, - 0, 0, 3, - 0, 0, -4, - 0, 0, 4, - 0, 0, -5, - 0, 0, 5, - 0, 0, -6, - 0, 0, 6, - 0, 0, -7, - 0, 0, 7, - 0, 0, -8, - 0, 0, 8, - 0, 0, -9, - 0, 0, 9, - 0, 0, -10, - 0, 0, 10, - 0, 0, -11, - 0, 0, 11, - 0, 0, -12, - 0, 0, 12, - 0, 0, -13, - 0, 0, 13, - 0, 0, -14, - 0, 0, 14, - 0, 0, -15, - 0, 0, 15, - 0, 0, -16, - 0, 0, 16, - 0, 0, -17, - 0, 0, 17, }; -/* -============= -SV_CheckStuck +typedef enum unstickresult_e +{ + UNSTICK_STUCK = 0, + UNSTICK_GOOD = 1, + UNSTICK_UNSTUCK = 2 +} +unstickresult_t; -This is a big hack to try and fix the rare case of getting stuck in the world -clipping hull. -============= -*/ -void SV_CheckStuck (prvm_edict_t *ent) +unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset) { - int i; - vec3_t offset; + int i, maxunstick; + // if not stuck in a bmodel, just return if (!SV_TestEntityPosition(ent, vec3_origin)) - { - VectorCopy (ent->fields.server->origin, ent->fields.server->oldorigin); - return; - } + return UNSTICK_GOOD; for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3) { if (!SV_TestEntityPosition(ent, unstickoffsets + i)) { - Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2]); + VectorCopy(unstickoffsets + i, offset); SV_LinkEdict (ent, true); - return; + return UNSTICK_UNSTUCK; } } - VectorSubtract(ent->fields.server->oldorigin, ent->fields.server->origin, offset); - if (!SV_TestEntityPosition(ent, offset)) + maxunstick = (int) ((ent->fields.server->maxs[2] - ent->fields.server->mins[2]) * 0.36); + // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox + + for(i = 2; i <= maxunstick; ++i) { - Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); - SV_LinkEdict (ent, true); - return; + VectorClear(offset); + offset[2] = -i; + if (!SV_TestEntityPosition(ent, offset)) + { + SV_LinkEdict (ent, true); + return UNSTICK_UNSTUCK; + } + offset[2] = i; + if (!SV_TestEntityPosition(ent, offset)) + { + SV_LinkEdict (ent, true); + return UNSTICK_UNSTUCK; + } } - Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); + return UNSTICK_STUCK; } qboolean SV_UnstickEntity (prvm_edict_t *ent) { - int i; - - // if not stuck in a bmodel, just return - if (!SV_TestEntityPosition(ent, vec3_origin)) - return true; - - for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3) + vec3_t offset; + switch(SV_UnstickEntityReturnOffset(ent, offset)) { - if (!SV_TestEntityPosition(ent, unstickoffsets + i)) - { - Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2]); - SV_LinkEdict (ent, true); + case UNSTICK_GOOD: return true; - } + case UNSTICK_UNSTUCK: + Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), offset[0], offset[1], offset[2]); + return true; + case UNSTICK_STUCK: + if (developer.integer >= 100) + Con_Printf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); + return false; + default: + Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n"); + return false; } +} - if (developer.integer >= 100) - Con_Printf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); - return false; +/* +============= +SV_CheckStuck + +This is a big hack to try and fix the rare case of getting stuck in the world +clipping hull. +============= +*/ +void SV_CheckStuck (prvm_edict_t *ent) +{ + vec3_t offset; + + switch(SV_UnstickEntityReturnOffset(ent, offset)) + { + case UNSTICK_GOOD: + VectorCopy (ent->fields.server->origin, ent->fields.server->oldorigin); + break; + case UNSTICK_UNSTUCK: + Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), offset[0], offset[1], offset[2]); + break; + case UNSTICK_STUCK: + VectorSubtract(ent->fields.server->oldorigin, ent->fields.server->origin, offset); + if (!SV_TestEntityPosition(ent, offset)) + { + Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); + SV_LinkEdict (ent, true); + } + else + Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); + break; + default: + Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n"); + } } @@ -1607,7 +1709,7 @@ int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel) case 7: dir[0] = -2; dir[1] = -2; break; } - SV_PushEntity (ent, dir, false); + SV_PushEntity (&trace, ent, dir, false, true); // retry the original move ent->fields.server->velocity[0] = oldvel[0]; @@ -1644,7 +1746,7 @@ void SV_WalkMove (prvm_edict_t *ent) { int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity, hitsupercontentsmask; vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity; - trace_t downtrace; + trace_t downtrace, trace; qboolean applygravity; // if frametime is 0 (due to client sending the same timestamp twice), @@ -1675,11 +1777,8 @@ void SV_WalkMove (prvm_edict_t *ent) SV_CheckVelocity(ent); SV_LinkEdict (ent, true); - VectorCopy(ent->fields.server->origin, originalmove_origin); - VectorCopy(ent->fields.server->velocity, originalmove_velocity); - originalmove_clip = clip; - originalmove_flags = (int)ent->fields.server->flags; - originalmove_groundentity = ent->fields.server->groundentity; + if(clip & 8) // teleport + return; if ((int)ent->fields.server->flags & FL_WATERJUMP) return; @@ -1687,6 +1786,12 @@ void SV_WalkMove (prvm_edict_t *ent) if (sv_nostep.integer) return; + VectorCopy(ent->fields.server->origin, originalmove_origin); + VectorCopy(ent->fields.server->velocity, originalmove_velocity); + originalmove_clip = clip; + originalmove_flags = (int)ent->fields.server->flags; + originalmove_groundentity = ent->fields.server->groundentity; + // if move didn't block on a step, return if (clip & 2) { @@ -1714,13 +1819,22 @@ void SV_WalkMove (prvm_edict_t *ent) // move up VectorClear (upmove); upmove[2] = sv_stepheight.value; - // FIXME: don't link? - SV_PushEntity(ent, upmove, false); + if(!SV_PushEntity(&trace, ent, upmove, false, true)) + { + // we got teleported when upstepping... must abort the move + return; + } // move forward ent->fields.server->velocity[2] = 0; clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask); ent->fields.server->velocity[2] += start_velocity[2]; + if(clip & 8) + { + // we got teleported when upstepping... must abort the move + // note that z velocity handling may not be what QC expects here, but we cannot help it + return; + } SV_CheckVelocity(ent); SV_LinkEdict (ent, true); @@ -1756,8 +1870,11 @@ void SV_WalkMove (prvm_edict_t *ent) // move down VectorClear (downmove); downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime; - // FIXME: don't link? - downtrace = SV_PushEntity (ent, downmove, false); + if(!SV_PushEntity (&downtrace, ent, downmove, false, true)) + { + // we got teleported when downstepping... must abort the move + return; + } if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7) { @@ -1937,14 +2054,16 @@ void SV_Physics_Toss (prvm_edict_t *ent) { // move origin VectorScale (ent->fields.server->velocity, movetime, move); - trace = SV_PushEntity (ent, move, true); + if(!SV_PushEntity (&trace, ent, move, true, true)) + return; // teleported if (ent->priv.server->free) return; if (trace.bmodelstartsolid) { // try to unstick the entity SV_UnstickEntity(ent); - trace = SV_PushEntity (ent, move, false); + if(!SV_PushEntity (&trace, ent, move, false, true)) + return; // teleported if (ent->priv.server->free) return; } @@ -1960,7 +2079,18 @@ void SV_Physics_Toss (prvm_edict_t *ent) { float d, ent_gravity; prvm_eval_t *val; - ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1.5); + float bouncefactor = 0.5f; + float bouncestop = 60.0f / 800.0f; + + val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.bouncefactor); + if (val!=0 && val->_float) + bouncefactor = val->_float; + + val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.bouncestop); + if (val!=0 && val->_float) + bouncestop = val->_float; + + ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1 + bouncefactor); // LordHavoc: fixed grenades not bouncing when fired down a slope val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.gravity); if (val!=0 && val->_float) @@ -1970,7 +2100,7 @@ void SV_Physics_Toss (prvm_edict_t *ent) if (sv_gameplayfix_grenadebouncedownslopes.integer) { d = DotProduct(trace.plane.normal, ent->fields.server->velocity); - if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * (60.0 / 800.0) * ent_gravity) + if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * bouncestop * ent_gravity) { ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND; ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent); @@ -1982,7 +2112,7 @@ void SV_Physics_Toss (prvm_edict_t *ent) } else { - if (trace.plane.normal[2] > 0.7 && ent->fields.server->velocity[2] < sv_gravity.value * (60.0 / 800.0) * ent_gravity) + if (trace.plane.normal[2] > 0.7 && ent->fields.server->velocity[2] < sv_gravity.value * bouncestop * ent_gravity) { ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND; ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent); @@ -2008,7 +2138,7 @@ void SV_Physics_Toss (prvm_edict_t *ent) else ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND; } - if (!sv_gameplayfix_slidemoveprojectiles.integer) + if (!sv_gameplayfix_slidemoveprojectiles.integer || (ent->fields.server->movetype != MOVETYPE_BOUNCE && ent->fields.server->movetype == MOVETYPE_BOUNCEMISSILE) || ((int)ent->fields.server->flags & FL_ONGROUND)) break; } @@ -2374,7 +2504,7 @@ void SV_Physics (void) } // decrement prog->num_edicts if the highest number entities died - for (;PRVM_EDICT_NUM(prog->num_edicts - 1)->priv.server->free;prog->num_edicts--); + for (;PRVM_ED_CanAlloc(PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--); if (!sv_freezenonclients.integer) sv.time += sv.frametime;