From 4fad5255ba7e0ee9d9ba6ca7864ad5a27f3de2ca Mon Sep 17 00:00:00 2001 From: s1lent Date: Sat, 9 Dec 2017 12:21:09 +0700 Subject: [PATCH] Refactoring world.cpp, sv_phys.cpp, sv_move.cpp --- .gitignore | 11 +- rehlds/engine/mathlib.cpp | 17 +- rehlds/engine/mathlib_e.h | 99 +- rehlds/engine/net.h | 14 + rehlds/engine/net_ws.cpp | 2 +- rehlds/engine/pmovetst.cpp | 2 +- rehlds/engine/pr_cmds.cpp | 15 +- rehlds/engine/r_studio.cpp | 2 +- rehlds/engine/sv_main.cpp | 10 +- rehlds/engine/sv_move.cpp | 593 ++++++----- rehlds/engine/sv_move.h | 14 +- rehlds/engine/sv_phys.cpp | 1374 +++++++++++++------------- rehlds/engine/sv_phys.h | 6 +- rehlds/engine/sv_user.cpp | 99 +- rehlds/engine/textures.cpp | 4 +- rehlds/engine/world.cpp | 1456 ++++++++++++++-------------- rehlds/engine/world.h | 20 +- rehlds/hookers/engine/hooklist.cpp | 6 +- rehlds/public/rehlds/progs.h | 2 +- 19 files changed, 1970 insertions(+), 1776 deletions(-) diff --git a/.gitignore b/.gitignore index 63383d8..574a0f2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,22 +2,23 @@ **/.gradle .idea *.iml +*.bat +*.log +*.lnk **/msvc/Debug* **/msvc/Release* **/msvc/Tests **/msvc/Test Fixes -**/msvc/.vs -**/msvc/*.db -**/msvc/*.opendb **/msvc/*.sdf **/msvc/*.opensdf **/msvc/*.user **/msvc/*.suo **/msvc/*.db **/msvc/*.opendb -**/msvc/PublishPath*.txt -**/msvc/ipch +**/msvc/*.txt +**/msvc/*.amplxeproj **/msvc/.vs +**/msvc/ipch rehlds/version/appversion.h rehlds/_rehldsTestImg diff --git a/rehlds/engine/mathlib.cpp b/rehlds/engine/mathlib.cpp index 107c3cd..8b81108 100644 --- a/rehlds/engine/mathlib.cpp +++ b/rehlds/engine/mathlib.cpp @@ -558,11 +558,11 @@ NOBODY void InterpolateAngles(float *start, float *end, float *output, float fra // NormalizeAngles(float *angles); // 453 //} -void VectorTransform(const vec_t *in1, float *in2, vec_t *out) +void VectorTransform(const vec_t *in1, float (*in2)[4], vec_t *out) { - out[0] = _DotProduct(in1, in2 + 0) + in2[3]; - out[1] = _DotProduct(in1, in2 + 4) + in2[7]; - out[2] = _DotProduct(in1, in2 + 8) + in2[11]; + out[0] = _DotProduct(in1, in2[0]) + in2[0][3]; + out[1] = _DotProduct(in1, in2[1]) + in2[1][3]; + out[2] = _DotProduct(in1, in2[2]) + in2[2][3]; } int VectorCompare(const vec_t *v1, const vec_t *v2) @@ -595,7 +595,7 @@ void VectorMA(const vec_t *veca, float scale, const vec_t *vecm, vec_t *out) #endif #ifndef REHLDS_FIXES -long double _DotProduct(const vec_t *v1, const vec_t *v2) +real_t _DotProduct(const vec_t *v1, const vec_t *v2) { return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; } @@ -689,13 +689,6 @@ NOBODY void VectorInverse(vec_t *v); //{ //} -void VectorScale(const vec_t *in, float scale, vec_t *out) -{ - out[0] = scale * in[0]; - out[1] = scale * in[1]; - out[2] = scale * in[2]; -} - NOBODY int Q_log2(int val); //{ // int answer; // 568 diff --git a/rehlds/engine/mathlib_e.h b/rehlds/engine/mathlib_e.h index ff9c89f..7bfcb2a 100644 --- a/rehlds/engine/mathlib_e.h +++ b/rehlds/engine/mathlib_e.h @@ -31,6 +31,16 @@ #include "maintypes.h" #include "model.h" +#ifndef REHLDS_FIXES +// NOTE: In some cases we need high precision of floating-point, +// so use double instead of float, otherwise unittest will fail +typedef double real_t; +#else +typedef float real_t; +#endif + +typedef real_t real3_t[3]; + enum { PITCH = 0, // up / down @@ -45,6 +55,22 @@ enum #define vec3_origin (*pvec3_origin) #endif // HOOK_ENGINE +#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ + (((p)->type < 3) ? \ + ( \ + ((p)->dist <= (emins)[(p)->type]) ? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type]) ? \ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSide((emins), (emaxs), (p))) + extern vec3_t vec3_origin; static const int nanmask = 0x7F800000; @@ -104,6 +130,71 @@ inline T M_clamp(T a, T min, T max) { return clamp(a, min, max); } +inline void VectorAdd(const vec_t *veca, const vec_t *vecb, vec_t *out) +{ + out[0] = veca[0] + vecb[0]; + out[1] = veca[1] + vecb[1]; + out[2] = veca[2] + vecb[2]; +} + +template +inline void VectorSubtract(const vec_t *veca, const vec_t *vecb, T *out) +{ + out[0] = veca[0] - vecb[0]; + out[1] = veca[1] - vecb[1]; + out[2] = veca[2] - vecb[2]; +} + +#ifndef REHLDS_FIXES +template +inline void VectorMA(const vec_t *veca, float scale, const T *vecm, vec_t *out) +{ + out[0] = scale * vecm[0] + veca[0]; + out[1] = scale * vecm[1] + veca[1]; + out[2] = scale * vecm[2] + veca[2]; +} +#endif + +inline void VectorScale(const vec_t *in, float scale, vec_t *out) +{ + out[0] = scale * in[0]; + out[1] = scale * in[1]; + out[2] = scale * in[2]; +} + +inline void VectorClear(vec_t *in) +{ + in[0] = 0.0f; + in[1] = 0.0f; + in[2] = 0.0f; +} + +inline void VectorCopy(const vec_t *in, vec_t *out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +inline void VectorNegate(const vec_t *in, vec_t *out) +{ + out[0] = -in[0]; + out[1] = -in[1]; + out[2] = -in[2]; +} + +inline void VectorAverage(const vec_t *veca, const vec_t *vecb, vec_t *out) +{ + out[0] = (veca[0] + vecb[0]) * 0.5f; + out[1] = (veca[1] + vecb[1]) * 0.5f; + out[2] = (veca[2] + vecb[2]) * 0.5f; +} + +inline bool VectorIsZero(const vec_t *in) +{ + return (in[0] == 0.0f && in[1] == 0.0f && in[2] == 0.0f); +} + float anglemod(float a); void BOPS_Error(void); @@ -116,14 +207,10 @@ void AngleMatrix(const vec_t *angles, float(*matrix)[4]); NOBODY void AngleIMatrix(const vec_t *angles, float *matrix); NOBODY void NormalizeAngles(float *angles); NOBODY void InterpolateAngles(float *start, float *end, float *output, float frac); -void VectorTransform(const vec_t *in1, float *in2, vec_t *out); +void VectorTransform(const vec_t *in1, float (*in2)[4], vec_t *out); int VectorCompare(const vec_t *v1, const vec_t *v2); void VectorMA(const vec_t *veca, float scale, const vec_t *vecm, vec_t *out); -#ifdef REHLDS_FIXES -float _DotProduct(const vec_t *v1, const vec_t *v2); // with sse support -#else // REHLDS_FIXES -long double _DotProduct(const vec_t *v1, const vec_t *v2); // precise -#endif // REHLDS_FIXES +real_t _DotProduct(const vec_t *v1, const vec_t *v2); NOBODY void _VectorSubtract(vec_t *veca, vec_t *vecb, vec_t *out); void _VectorAdd(vec_t *veca, vec_t *vecb, vec_t *out); NOBODY void _VectorCopy(vec_t *in, vec_t *out); diff --git a/rehlds/engine/net.h b/rehlds/engine/net.h index c21e305..9f3fa98 100644 --- a/rehlds/engine/net.h +++ b/rehlds/engine/net.h @@ -54,6 +54,17 @@ const char S2C_CONNECTION = 'B'; // HLMaster rejected a server's connection because the server needs to be updated const char M2S_REQUESTRESTART = 'O'; +// Response details about each player on the server +const char S2A_PLAYERS = 'D'; + +// Response as multi-packeted the rules the server is using +const char S2A_RULES = 'E'; + +// info request +const char S2A_INFO = 'C'; // deprecated goldsrc response + +const char S2A_INFO_DETAILED = 'm'; // New Query protocol, returns dedicated or not, + other performance info. + // send a log event as key value const char S2A_LOGSTRING = 'R'; @@ -78,6 +89,9 @@ const char A2A_PING = 'i'; // respond with an A2A_ACK // Generic Ack const char A2A_ACK = 'j'; // general acknowledgement without info +// Print to client console +const char A2A_PRINT = 'l'; // print a message on client + // Challenge response from master const char M2A_CHALLENGE = 's'; // + challenge value diff --git a/rehlds/engine/net_ws.cpp b/rehlds/engine/net_ws.cpp index 265a683..a18b641 100644 --- a/rehlds/engine/net_ws.cpp +++ b/rehlds/engine/net_ws.cpp @@ -1273,7 +1273,7 @@ qboolean NET_GetPacket(netsrc_t sock) { Q_memcpy(net_message.data, in_message.data, in_message.cursize); net_message.cursize = in_message.cursize; - Q_memcpy(&net_from, &in_from, 0x14u); + Q_memcpy(&net_from, &in_from, sizeof(netadr_t)); NET_ThreadUnlock(); return bret; } diff --git a/rehlds/engine/pmovetst.cpp b/rehlds/engine/pmovetst.cpp index a2c6480..0b36057 100644 --- a/rehlds/engine/pmovetst.cpp +++ b/rehlds/engine/pmovetst.cpp @@ -501,7 +501,7 @@ pmtrace_t _PM_PlayerTrace(vec_t *start, vec_t *end, int traceFlags, int numphyse closest = 0; for (int j = 0; j < pNumHulls; j++) { - Q_memset(&testtrace, 0, 0x44u); + Q_memset(&testtrace, 0, sizeof(testtrace)); testtrace.endpos[0] = end[0]; testtrace.endpos[1] = end[1]; testtrace.endpos[2] = end[2]; diff --git a/rehlds/engine/pr_cmds.cpp b/rehlds/engine/pr_cmds.cpp index e9d13ab..f7ab9a8 100644 --- a/rehlds/engine/pr_cmds.cpp +++ b/rehlds/engine/pr_cmds.cpp @@ -339,7 +339,7 @@ void EXT_FUNC PF_traceline_Shared(const float *v1, const float *v2, int nomonste #ifdef REHLDS_OPT_PEDANTIC trace_t trace = SV_Move_Point(v1, v2, nomonsters, ent); #else // REHLDS_OPT_PEDANTIC - trace_t trace = SV_Move(v1, vec3_origin, vec3_origin, v2, nomonsters, ent, 0); + trace_t trace = SV_Move(v1, vec3_origin, vec3_origin, v2, nomonsters, ent, FALSE); #endif // REHLDS_OPT_PEDANTIC gGlobalVariables.trace_flags = 0; @@ -370,7 +370,8 @@ void EXT_FUNC TraceHull(const float *v1, const float *v2, int fNoMonsters, int h hullNumber = hullNumber; if (hullNumber < 0 || hullNumber > 3) hullNumber = 0; - trace_t trace = SV_Move(v1, gHullMins[hullNumber], gHullMaxs[hullNumber], v2, fNoMonsters, pentToSkip, 0); + + trace_t trace = SV_Move(v1, gHullMins[hullNumber], gHullMaxs[hullNumber], v2, fNoMonsters, pentToSkip, FALSE); ptr->fAllSolid = trace.allsolid; ptr->fStartSolid = trace.startsolid; @@ -608,7 +609,7 @@ void EXT_FUNC PF_TraceToss_DLL(edict_t *pent, edict_t *pentToIgnore, TraceResult int EXT_FUNC TraceMonsterHull(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr) { - qboolean monsterClip = (pEdict->v.flags & FL_MONSTERCLIP) ? 1 : 0; + qboolean monsterClip = (pEdict->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE; trace_t trace = SV_Move(v1, pEdict->v.mins, pEdict->v.maxs, v2, fNoMonsters, pentToSkip, monsterClip); if (ptr) { @@ -1676,12 +1677,12 @@ int EXT_FUNC PF_droptofloor_I(edict_t *ent) { vec3_t end; trace_t trace; - qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0; + qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE; end[0] = ent->v.origin[0]; end[1] = ent->v.origin[1]; end[2] = ent->v.origin[2] - 256.0; - trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, 0, ent, monsterClip); + trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, monsterClip); if (trace.allsolid) return -1; @@ -1772,7 +1773,7 @@ void EXT_FUNC PF_aim_I(edict_t *ent, float speed, float *rgflReturn) start[1] += ent->v.view_ofs[1]; start[2] += ent->v.view_ofs[2]; VectorMA(start, 2048.0, dir, end); - tr = SV_Move(start, vec3_origin, vec3_origin, end, 0, ent, 0); + tr = SV_Move(start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, FALSE); if (tr.ent && tr.ent->v.takedamage == 2.0f && (ent->v.team <= 0 || ent->v.team != tr.ent->v.team)) { @@ -1811,7 +1812,7 @@ void EXT_FUNC PF_aim_I(edict_t *ent, float speed, float *rgflReturn) if (dist >= bestdist) { - tr = SV_Move(start, vec3_origin, vec3_origin, end, 0, ent, 0); + tr = SV_Move(start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, FALSE); if (tr.ent == check) { bestdist = dist; diff --git a/rehlds/engine/r_studio.cpp b/rehlds/engine/r_studio.cpp index 7a692a8..e9b5be0 100644 --- a/rehlds/engine/r_studio.cpp +++ b/rehlds/engine/r_studio.cpp @@ -950,7 +950,7 @@ void EXT_FUNC GetAttachment(const edict_t *pEdict, int iAttachment, float *rgflO ); if (rgflOrigin) - VectorTransform(pattachment->org, (float *)bonetransform[pattachment->bone], rgflOrigin); + VectorTransform(pattachment->org, bonetransform[pattachment->bone], rgflOrigin); } int ModelFrameCount(model_t *model) diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index 085ad3f..30bb71c 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -2832,7 +2832,7 @@ NOXREF void ReplyServerChallenge(netadr_t *adr) buf.flags = SIZEBUF_ALLOW_OVERFLOW; MSG_WriteLong(&buf, 0xffffffff); - MSG_WriteByte(&buf, 65); + MSG_WriteByte(&buf, S2C_CHALLENGE); MSG_WriteLong(&buf, GetChallengeNr(adr)); NET_SendPacket(NS_SERVER, buf.cursize, (char *)buf.data, *adr); } @@ -3000,7 +3000,7 @@ NOXREF void SVC_Info(qboolean bDetailed) } MSG_WriteLong(&buf, 0xffffffff); - MSG_WriteByte(&buf, bDetailed ? 109 : 67); + MSG_WriteByte(&buf, bDetailed ? S2A_INFO_DETAILED : S2A_INFO); if (noip) { @@ -3102,7 +3102,7 @@ NOXREF void SVC_PlayerInfo(void) buf.flags = SIZEBUF_ALLOW_OVERFLOW; MSG_WriteLong(&buf, 0xffffffff); - MSG_WriteByte(&buf, 68); + MSG_WriteByte(&buf, S2A_PLAYERS); for (i = 0; i < g_psvs.maxclients; i++) { @@ -3154,7 +3154,7 @@ NOXREF void SVC_RuleInfo(void) return; MSG_WriteLong(&buf, 0xffffffff); - MSG_WriteByte(&buf, 69); + MSG_WriteByte(&buf, S2A_RULES); MSG_WriteShort(&buf, nNumRules); var = cvar_vars; @@ -3216,7 +3216,7 @@ void SV_FlushRedirect(void) buf.flags = SIZEBUF_ALLOW_OVERFLOW; MSG_WriteLong(&buf, -1); - MSG_WriteByte(&buf, 0x6Cu); + MSG_WriteByte(&buf, A2A_PRINT); MSG_WriteString(&buf, outputbuf); MSG_WriteByte(&buf, 0); NET_SendPacket(NS_SERVER, buf.cursize, buf.data, sv_redirectto); diff --git a/rehlds/engine/sv_move.cpp b/rehlds/engine/sv_move.cpp index 7d1a91a..472a135 100644 --- a/rehlds/engine/sv_move.cpp +++ b/rehlds/engine/sv_move.cpp @@ -28,21 +28,7 @@ #include "precompiled.h" -/* -* Local initialization -*/ -#ifndef HOOK_ENGINE - -static int c_yes = 0; -static int c_no = 0; - -#else // HOOK_ENGINE - -int c_yes; -int c_no; - -#endif // HOOK_ENGINE - +// Returns false if any part of the bottom of the entity is off an edge that is not a staircase. qboolean SV_CheckBottom(edict_t *ent) { vec3_t mins; @@ -54,12 +40,17 @@ qboolean SV_CheckBottom(edict_t *ent) int y; float mid; float bottom; - qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0; - _VectorAdd(ent->v.origin, ent->v.mins, mins); - _VectorAdd(ent->v.origin, ent->v.maxs, maxs); + qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE; + + VectorAdd(ent->v.origin, ent->v.mins, mins); + VectorAdd(ent->v.origin, ent->v.maxs, maxs); + + // if all of the points under the corners are solid world, don't bother + // with the tougher checks + // the corners must be within 16 of the midpoint + start[2] = mins[2] - 1.0f; - start[2] = mins[2] - 1; for (x = 0; x <= 1; x++) { for (y = 0; y <= 1; y++) @@ -73,23 +64,28 @@ qboolean SV_CheckBottom(edict_t *ent) goto realcheck; } } - ++c_yes; - return 1; + + // we got out easy + return TRUE; realcheck: - ++c_no; + + // check it for real... start[2] = mins[2]; + // the midpoint must be within 16 of the bottom start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f; start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f; - stop[2] = start[2] - 2 * sv_stepsize.value; - trace = SV_Move(start, vec3_origin, vec3_origin, stop, 1, ent, monsterClip); + + stop[2] = start[2] - 2.0f * sv_stepsize.value; + trace = SV_Move(start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, monsterClip); if (trace.fraction == 1.0f) - return 0; + return FALSE; mid = bottom = trace.endpos[2]; + // the corners must be within 16 of the midpoint for (x = 0; x <= 1; x++) { for (y = 0; y <= 1; y++) @@ -97,18 +93,23 @@ realcheck: start[0] = stop[0] = x ? maxs[0] : mins[0]; start[1] = stop[1] = y ? maxs[1] : mins[1]; - trace = SV_Move(start, vec3_origin, vec3_origin, stop, 1, ent, monsterClip); + trace = SV_Move(start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, monsterClip); if (trace.fraction != 1.0f && trace.endpos[2] > bottom) bottom = trace.endpos[2]; + if (trace.fraction == 1.0f || mid - trace.endpos[2] > sv_stepsize.value) - return 0; + return FALSE; } } - return 1; + return TRUE; } +// Called by monster program code. +// The move will be adjusted for slopes and stairs, but if the move isn't +// possible, no move is done, false is returned, and +// pr_global_struct->trace_normal is set to the normal of the blocking wall qboolean SV_movetest(edict_t *ent, vec_t *move, qboolean relink) { vec3_t oldorg; @@ -116,223 +117,255 @@ qboolean SV_movetest(edict_t *ent, vec_t *move, qboolean relink) vec3_t end; trace_t trace; - oldorg[0] = ent->v.origin[0]; - oldorg[1] = ent->v.origin[1]; - oldorg[2] = ent->v.origin[2]; - - neworg[0] = ent->v.origin[0] + move[0]; - neworg[1] = ent->v.origin[1] + move[1]; - neworg[2] = ent->v.origin[2] + move[2]; - end[0] = neworg[0]; - end[1] = neworg[1]; + // try the move + VectorCopy(ent->v.origin, oldorg); + VectorAdd(ent->v.origin, move, neworg); + // push down from a step height above the wished position neworg[2] += sv_stepsize.value; - end[2] = neworg[2] - (2 * sv_stepsize.value); - trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, 0, ent); + VectorCopy(neworg, end); + end[2] -= sv_stepsize.value * 2.0f; + + trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); + if (trace.allsolid) - return 0; + return FALSE; if (trace.startsolid) { neworg[2] -= sv_stepsize.value; - trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, 0, ent); + trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); + if (trace.allsolid || trace.startsolid) - return 0; + return FALSE; } + if (trace.fraction == 1.0f) { + // if monster had the ground pulled out, go ahead and fall if (ent->v.flags & FL_PARTIALGROUND) { - ent->v.origin[0] = *move + ent->v.origin[0]; - ent->v.origin[1] = ent->v.origin[1] + move[1]; - ent->v.origin[2] = ent->v.origin[2] + move[2]; - if (relink) - SV_LinkEdict(ent, TRUE); + VectorAdd(ent->v.origin, move, ent->v.origin); + if (relink) + { + SV_LinkEdict(ent, TRUE); + } + + // fall down ent->v.flags &= ~FL_ONGROUND; - return 1; + return TRUE; } - return 0; + + // walked off an edge + return FALSE; } - ent->v.origin[0] = trace.endpos[0]; - ent->v.origin[1] = trace.endpos[1]; - ent->v.origin[2] = trace.endpos[2]; - if (SV_CheckBottom(ent) == 0) + // check point traces down for dangling corners + VectorCopy(trace.endpos, ent->v.origin); + + if (!SV_CheckBottom(ent)) { if (!(ent->v.flags & FL_PARTIALGROUND)) { - ent->v.origin[0] = oldorg[0]; - ent->v.origin[1] = oldorg[1]; - ent->v.origin[2] = oldorg[2]; - return 0; + VectorCopy(oldorg, ent->v.origin); + return FALSE; } + + // entity had floor mostly pulled out from underneath it + // and is trying to correct } else { if (ent->v.flags & FL_PARTIALGROUND) { + // back on ground ent->v.flags &= ~FL_PARTIALGROUND; } + ent->v.groundentity = trace.ent; } + // the move is ok if (relink) + { SV_LinkEdict(ent, TRUE); + } - return 1; + return TRUE; } +// Called by monster program code. +// The move will be adjusted for slopes and stairs, but if the move isn't +// possible, no move is done, false is returned, and +// pr_global_struct->trace_normal is set to the normal of the blocking wall qboolean SV_movestep(edict_t *ent, vec_t *move, qboolean relink) { trace_t trace; - vec3_t end; - vec3_t oldorg; - float dz; - qboolean monsterClipBrush; - vec3_t start; + vec3_t neworg, oldorg, end; - oldorg[0] = ent->v.origin[0]; - oldorg[1] = ent->v.origin[1]; - oldorg[2] = ent->v.origin[2]; + // try the move + VectorCopy(ent->v.origin, oldorg); + VectorAdd(ent->v.origin, move, neworg); - start[0] = ent->v.origin[0] + move[0]; - start[1] = ent->v.origin[1] + move[1]; - start[2] = ent->v.origin[2] + move[2]; - monsterClipBrush = (ent->v.flags & FL_MONSTERCLIP) != 0; + qboolean monsterClipBrush = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE; + + // flying monsters don't step up if (ent->v.flags & (FL_FLY | FL_SWIM)) { - int i = 0; - while (i < 2) + // try one move with vertical motion, then one without + for (int i = 0; i < 2; i++) { - start[0] = ent->v.origin[0] + move[0]; - start[1] = ent->v.origin[1] + move[1]; - start[2] = ent->v.origin[2] + move[2]; - edict_t* enemy = ent->v.enemy; - + VectorAdd(ent->v.origin, move, neworg); + edict_t *enemy = ent->v.enemy; if (i == 0 && enemy) { - dz = ent->v.origin[2] - enemy->v.origin[2]; - if (dz > 40.0) - start[2] = start[2] - 8.0; - if (dz < 30.0) - start[2] = start[2] + 8.0; + float dz = ent->v.origin[2] - enemy->v.origin[2]; + + if (dz > 40.0f) + neworg[2] -= 8.0f; + else if (dz < 30.0f) + neworg[2] += 8.0f; } - trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, start, 0, ent, monsterClipBrush); + + trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent, monsterClipBrush); + if (trace.fraction == 1.0f) - break; + { + g_groupmask = ent->v.groupinfo; + + if ((ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY) + { + // swim monster left water + return FALSE; + } + + VectorCopy(trace.endpos, ent->v.origin); + + if (relink) + { + SV_LinkEdict(ent, TRUE); + } + + return TRUE; + } if (!enemy) - return 0; - - if (i == 1) - return 0; - - i++; + { + break; + } } - g_groupmask = ent->v.groupinfo; - if ((ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == -1) - return 0; - - ent->v.origin[0] = trace.endpos[0]; - ent->v.origin[1] = trace.endpos[1]; - ent->v.origin[2] = trace.endpos[2]; - if (relink) - SV_LinkEdict(ent, TRUE); - - return 1; + return FALSE; } - start[2] += sv_stepsize.value; - end[0] = start[0]; - end[1] = start[1]; - end[2] = start[2] - (2 * sv_stepsize.value); - trace = SV_Move(start, ent->v.mins, ent->v.maxs, end, 0, ent, (ent->v.flags & FL_MONSTERCLIP) != 0); + // push down from a step height above the wished position + neworg[2] += sv_stepsize.value; + VectorCopy(neworg, end); + end[2] -= sv_stepsize.value * 2.0f; + + trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, monsterClipBrush); + if (trace.allsolid) - return 0; + return FALSE; if (trace.startsolid) { - start[2] = start[2] - sv_stepsize.value; - trace = SV_Move(start, ent->v.mins, ent->v.maxs, end, 0, ent, monsterClipBrush); + neworg[2] = neworg[2] - sv_stepsize.value; + trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, monsterClipBrush); + if (trace.allsolid || trace.startsolid) - return 0; + return FALSE; } - if (trace.fraction != 1.0f) + if (trace.fraction == 1.0f) { - ent->v.origin[0] = trace.endpos[0]; - ent->v.origin[1] = trace.endpos[1]; - ent->v.origin[2] = trace.endpos[2]; - if (SV_CheckBottom(ent) == 0) + // if monster had the ground pulled out, go ahead and fall + if (ent->v.flags & FL_PARTIALGROUND) { - if (!(ent->v.flags & FL_PARTIALGROUND)) + VectorAdd(ent->v.origin, move, ent->v.origin); + + if (relink) { - ent->v.origin[0] = oldorg[0]; - ent->v.origin[1] = oldorg[1]; - ent->v.origin[2] = oldorg[2]; - return 0; + SV_LinkEdict(ent, TRUE); } - } - else - { - if (ent->v.flags & FL_PARTIALGROUND) - ent->v.flags &= ~FL_PARTIALGROUND; - ent->v.groundentity = trace.ent; + // fall down + ent->v.flags &= ~FL_ONGROUND; + return TRUE; } - if (relink) - SV_LinkEdict(ent, TRUE); - - return 1; + // walked off an edge + return FALSE; } - if (!(ent->v.flags & FL_PARTIALGROUND)) - return 0; + // check point traces down for dangling corners + VectorCopy(trace.endpos, ent->v.origin); - ent->v.origin[0] += move[0]; - ent->v.origin[1] += move[1]; - ent->v.origin[2] += move[2]; + if (!SV_CheckBottom(ent)) + { + if (!(ent->v.flags & FL_PARTIALGROUND)) + { + VectorCopy(oldorg, ent->v.origin); + return FALSE; + } + + // entity had floor mostly pulled out from underneath it + // and is trying to correct + } + else + { + if (ent->v.flags & FL_PARTIALGROUND) + { + // back on ground + ent->v.flags &= ~FL_PARTIALGROUND; + } + + ent->v.groundentity = trace.ent; + } + + // the move is ok if (relink) + { SV_LinkEdict(ent, TRUE); + } - ent->v.flags &= ~FL_ONGROUND; - return 1; + return TRUE; } +// Turns to the movement direction, and walks the current distance if facing it. qboolean SV_StepDirection(edict_t *ent, float yaw, float dist) { vec3_t move; - move[0] = cos(yaw * (2 * M_PI) / 360.0) * dist; - move[1] = sin(yaw * (2 * M_PI) / 360.0) * dist; - move[2] = 0; - if (SV_movestep(ent, move, 0)) + yaw = yaw * (M_PI * 2.0f) / 360.0f; + + move[0] = cos(yaw) * dist; + move[1] = sin(yaw) * dist; + move[2] = 0.0f; + + if (SV_movestep(ent, move, FALSE)) { SV_LinkEdict(ent, TRUE); - return 1; - } - else - { - SV_LinkEdict(ent, TRUE); - return 0; + return TRUE; } + + SV_LinkEdict(ent, TRUE); + return FALSE; } qboolean SV_FlyDirection(edict_t *ent, vec_t *direction) { - if (SV_movestep(ent, direction, 0)) + if (SV_movestep(ent, direction, FALSE)) { SV_LinkEdict(ent, TRUE); - return 1; + return TRUE; } else { SV_LinkEdict(ent, TRUE); - return 0; + return FALSE; } } @@ -341,51 +374,91 @@ void SV_FixCheckBottom(edict_t *ent) ent->v.flags |= FL_PARTIALGROUND; } +const int DI_NODIR = -1; + NOXREF void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist) { NOXREFCHECK; - float deltax; - float deltay; - float d[3]; - float tdir; - float olddir; - float turnaround; - olddir = anglemod(45.0 * (int)(actor->v.ideal_yaw / 45.0)); - turnaround = anglemod(olddir - 180.0); + SV_NewChaseDir2(actor, enemy->v.origin, dist); +} - deltax = enemy->v.origin[0] - actor->v.origin[0]; - deltay = enemy->v.origin[1] - actor->v.origin[1]; +NOXREF qboolean SV_CloseEnough(edict_t *ent, edict_t *goal, float dist) +{ + NOXREFCHECK; - if (deltax > 10.0) - d[1] = 0.0; - else if (deltax <- 10.0) - d[1]= 180.0; + for (int i = 0; i < 3; i++) + { + if (goal->v.absmin[i] > ent->v.absmax[i] + dist) + return FALSE; + + if (goal->v.absmax[i] < ent->v.absmin[i] - dist) + return FALSE; + } + + return TRUE; +} + +NOXREF qboolean SV_ReachedGoal(edict_t *ent, vec_t *vecGoal, float flDist) +{ + NOXREFCHECK; + + for (int i = 0; i < 3; i++) + { + if (vecGoal[i] > ent->v.absmax[i] + flDist) + return FALSE; + + if (vecGoal[i] < ent->v.absmin[i] - flDist) + return FALSE; + } + + return TRUE; +} + +void SV_NewChaseDir2(edict_t *actor, vec_t *vecGoal, float dist) +{ + vec3_t d; + float deltax, deltay; + float tempdir, olddir, turnaround; + + olddir = anglemod(45.0f * (int)(actor->v.ideal_yaw / 45.0f)); + turnaround = anglemod(olddir - 180.0f); + + deltax = vecGoal[0] - actor->v.origin[0]; + deltay = vecGoal[1] - actor->v.origin[1]; + + if (deltax > 10.0f) + d[1] = 0.0f; + else if (deltax < -10.0f) + d[1] = 180.0f; else - d[1]= DI_NODIR; - if (deltay < -10.0) - d[2] = 270.0; - else if (deltay > 10.0) - d[2] = 90.0; - else - d[2]= DI_NODIR; + d[1] = DI_NODIR; + if (deltay < -10.0f) + d[2] = 270.0f; + else if (deltay > 10.0f) + d[2] = 90.0f; + else + d[2] = DI_NODIR; + + // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { - if (d[1] == 0.0) - tdir = d[2] == 90.0 ? 45.0 : 315.0; + if (d[1] == 0.0f) + tempdir = d[2] == 90.0f ? 45.0f : 315.0f; else - tdir = d[2] == 90.0 ? 135.0 : 215.0; + tempdir = d[2] == 90.0f ? 135.0f : 215.0f; - if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + if (tempdir != turnaround && SV_StepDirection(actor, tempdir, dist)) return; } - if (RandomLong(0, 1) || abs(deltay) > abs(deltax)) + // try other directions + if (RandomLong(0, 1) || abs(deltay) > abs(deltax)) { - tdir = d[1]; + tempdir = d[1]; d[1] = d[2]; - d[2] = tdir; + d[2] = tempdir; } if (d[1] != DI_NODIR && d[1] != turnaround && SV_StepDirection(actor, d[1], dist)) @@ -394,168 +467,68 @@ NOXREF void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist) if (d[2] != DI_NODIR && d[2] != turnaround && SV_StepDirection(actor, d[2], dist)) return; + // there is no direct path to the player, so pick another direction if (olddir != DI_NODIR && SV_StepDirection(actor, olddir, dist)) return; + // randomly determine direction of search if (RandomLong(0, 1)) { - for (tdir = 0.0; tdir <= 315.0; tdir += 45.0) - if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) - return; + for (tempdir = 0.0f; tempdir <= 315.0f; tempdir += 45.0f) + { + if (tempdir != turnaround && SV_StepDirection(actor, tempdir, dist)) + return; + } } else { - for (tdir = 315.0 ; tdir >= 0.0; tdir -= 45.0) - if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) - return; + for (tempdir = 315.0f; tempdir >= 0.0f; tempdir -= 45.0f) + { + if (tempdir != turnaround && SV_StepDirection(actor, tempdir, dist)) + return; + } } + // we tried. run backwards. that ought to work... if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist)) return; + // can't move, we're stuck somehow actor->v.ideal_yaw = olddir; + // if a bridge was pulled out from underneath a monster, it may not have + // a valid standing position at all if (!SV_CheckBottom(actor)) + { SV_FixCheckBottom(actor); -} - -NOXREF qboolean SV_CloseEnough(edict_t *ent, edict_t *goal, float dist) -{ - NOXREFCHECK; - int i; - for (i = 0; i < 3; i++) - { - if (goal->v.absmin[i] > ent->v.absmax[i] + dist) - return FALSE; - if (goal->v.absmax[i] < ent->v.absmin[i] - dist) - return FALSE; - } - return TRUE; -} - -NOXREF qboolean SV_ReachedGoal(edict_t *ent, vec_t *vecGoal, float flDist) -{ - NOXREFCHECK; - int i; - for (i = 0; i < 3; i++) - { - if (vecGoal[i] > ent->v.absmax[i] + flDist) - return FALSE; - if (vecGoal[i] < ent->v.absmin[i] - flDist) - return FALSE; - } - return TRUE; -} - -void SV_NewChaseDir2(edict_t *actor, vec_t *vecGoal, float dist) -{ - float deltax; - float deltay; - float d_1, d_2; - float tdir; - float olddir; - float turnaround; - - olddir = anglemod(45 * (int)(actor->v.ideal_yaw / 45.0)); - turnaround = anglemod(olddir - 180.0); - deltax = vecGoal[0] - actor->v.origin[0]; - deltay = vecGoal[1] - actor->v.origin[1]; - - if (deltax > 10) - d_1 = 0; - else if (deltax < -10) - d_1 = 180; - else - d_1 = DI_NODIR; - - if (deltay < -10) - d_2 = 270; - else if (deltay > 10) - d_2 = 90; - else - d_2 = DI_NODIR; - - if (d_1 != DI_NODIR && d_2 != DI_NODIR) - { - if (d_1 == 0.0) - tdir = d_2 == 90 ? 45 : 315; - else - tdir = d_2 == 90 ? 135 : 215; - - if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) - return; - } - - if (RandomLong(0, 1) || abs(deltay) > abs(deltax)) - { - tdir = d_1; - d_1 = d_2; - d_2 = tdir; - } - - if (d_1 != DI_NODIR && d_1 != turnaround - && SV_StepDirection(actor, d_1, dist)) - return; - - if (d_2 != DI_NODIR && d_2 != turnaround - && SV_StepDirection(actor, d_2, dist)) - return; - - if (olddir != DI_NODIR && SV_StepDirection(actor, olddir, dist)) - return; - - if (RandomLong(0, 1)) - { - for (tdir = 0; tdir <= 315; tdir += 45) - { - if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) - return; - } - } - else - { - for (tdir = 315; tdir >= 0; tdir -= 45) - { - if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) - return; - } - } - - if (turnaround == DI_NODIR || !SV_StepDirection(actor, turnaround, dist)) - { - actor->v.ideal_yaw = olddir; - if (!SV_CheckBottom(actor)) - SV_FixCheckBottom(actor); } } -void EXT_FUNC SV_MoveToOrigin_I(edict_t *ent, const float *pflGoal, float dist, int iStrafe) +void EXT_FUNC SV_MoveToOrigin_I(edict_t *ent, const float *pflGoal, float dist, int iMoveType) { vec3_t vecGoal; - vec3_t vecDir; + VectorCopy(pflGoal, vecGoal); - vecGoal[0] = pflGoal[0]; - vecGoal[1] = pflGoal[1]; - vecGoal[2] = pflGoal[2]; - - if (ent->v.flags & (FL_ONGROUND | FL_SWIM | FL_FLY)) + if (ent->v.flags & (FL_FLY | FL_SWIM | FL_ONGROUND)) { - if (iStrafe) + if (iMoveType == MOVE_NORMAL) { - vecDir[0] = vecGoal[0] - ent->v.origin[0]; - vecDir[1] = vecGoal[1] - ent->v.origin[1]; - vecDir[2] = vecGoal[2] - ent->v.origin[2]; + if (!SV_StepDirection(ent, ent->v.ideal_yaw, dist)) + { + SV_NewChaseDir2(ent, vecGoal, dist); + } + } + else + { + vec3_t vecDir; + VectorSubtract(vecGoal, ent->v.origin, vecDir); + if (!(ent->v.flags & (FL_SWIM | FL_FLY))) - vecDir[2] = 0; + vecDir[2] = 0.0f; VectorNormalize(vecDir); VectorScale(vecDir, dist, vecDir); SV_FlyDirection(ent, vecDir); } - else - { - if (!SV_StepDirection(ent, ent->v.ideal_yaw, dist)) - SV_NewChaseDir2(ent, vecGoal, dist); - } } } diff --git a/rehlds/engine/sv_move.h b/rehlds/engine/sv_move.h index d53cd58..29a3829 100644 --- a/rehlds/engine/sv_move.h +++ b/rehlds/engine/sv_move.h @@ -31,18 +31,6 @@ #include "maintypes.h" #include "server.h" -const int DI_NODIR = -1; - -#ifdef HOOK_ENGINE - -#define c_yes (*pc_yes) -#define c_no (*pc_no) - -extern int c_yes; -extern int c_no; - -#endif // HOOK_ENGINE - qboolean SV_CheckBottom(edict_t *ent); qboolean SV_movetest(edict_t *ent, vec_t *move, qboolean relink); qboolean SV_movestep(edict_t *ent, vec_t *move, qboolean relink); @@ -53,4 +41,4 @@ NOXREF void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist); NOXREF qboolean SV_CloseEnough(edict_t *ent, edict_t *goal, float dist); NOXREF qboolean SV_ReachedGoal(edict_t *ent, vec_t *vecGoal, float flDist); void SV_NewChaseDir2(edict_t *actor, vec_t *vecGoal, float dist); -void SV_MoveToOrigin_I(edict_t *ent, const float *pflGoal, float dist, int iStrafe); +void SV_MoveToOrigin_I(edict_t *ent, const float *pflGoal, float dist, int iMoveType); diff --git a/rehlds/engine/sv_phys.cpp b/rehlds/engine/sv_phys.cpp index b922566..fe14441 100644 --- a/rehlds/engine/sv_phys.cpp +++ b/rehlds/engine/sv_phys.cpp @@ -28,8 +28,22 @@ #include "precompiled.h" -vec3_t* g_moved_from; -edict_t** g_moved_edict; +// Pushmove objects do not obey gravity, and do not interact with each other or trigger fields, +// but block normal movement and push normal objects when they move. +// +// onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects +// +// doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH +// bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS +// corpses are SOLID_NOT and MOVETYPE_TOSS +// crates are SOLID_BBOX and MOVETYPE_TOSS +// walking monsters are SOLID_BBOX and MOVETYPE_STEP +// flying/floating monsters are SOLID_BBOX and MOVETYPE_FLY +// +// solid_edge items only clip against bsp models. + +vec3_t *g_moved_from; +edict_t **g_moved_edict; /* * Globals initialization @@ -54,12 +68,13 @@ cvar_t sv_stopspeed; #endif // HOOK_ENGINE -NOXREF void SV_CheckAllEnts(void) +NOXREF void SV_CheckAllEnts() { NOXREFCHECK; int e; edict_t *check; + // see if any solid entities are inside the final position for (e = 1; e < g_psv.num_edicts; e++) { check = &g_psv.edicts[e]; @@ -67,22 +82,20 @@ NOXREF void SV_CheckAllEnts(void) if (check->free) continue; - int movetype = check->v.movetype; - if (check->v.movetype == MOVETYPE_NONE) - continue; + if (check->v.movetype == MOVETYPE_NONE + || check->v.movetype == MOVETYPE_PUSH + || check->v.movetype == MOVETYPE_NOCLIP + || check->v.movetype == MOVETYPE_FOLLOW) + continue; - if (movetype != MOVETYPE_PUSH - && movetype != MOVETYPE_NOCLIP - && movetype != MOVETYPE_FOLLOW) - { - if (SV_TestEntityPosition(check) != NULL) - Con_Printf("entity in invalid position\n"); - } + if (SV_TestEntityPosition(check) != NULL) + Con_Printf("entity in invalid position\n"); } } void SV_CheckVelocity(edict_t *ent) { + // bound velocity for (int i = 0; i < 3; i++) { if (IS_NAN(ent->v.velocity[i])) @@ -90,6 +103,7 @@ void SV_CheckVelocity(edict_t *ent) Con_Printf("Got a NaN velocity on %s\n", &pr_strings[ent->v.classname]); ent->v.velocity[i] = 0; } + if (IS_NAN(ent->v.origin[i])) { Con_Printf("Got a NaN origin on %s\n", &pr_strings[ent->v.classname]); @@ -121,16 +135,14 @@ qboolean SV_RunThink(edict_t *ent) { thinktime = ent->v.nextthink; if (thinktime <= 0.0 || thinktime > g_psv.time + host_frametime) - { return TRUE; - } + if (thinktime < g_psv.time) - { - thinktime = (float) g_psv.time; // don't let things stay in the past. - // it is possible to start that way - // by a trigger with a local time. - } - ent->v.nextthink = 0.0; + thinktime = g_psv.time; // don't let things stay in the past. + // it is possible to start that way + // by a trigger with a local time. + + ent->v.nextthink = 0.0f; gGlobalVariables.time = thinktime; gEntityInterface.pfnThink(ent); } @@ -143,9 +155,11 @@ qboolean SV_RunThink(edict_t *ent) return !ent->free; } +// Two entities have touched, so run their touch functions void SV_Impact(edict_t *e1, edict_t *e2, trace_t *ptrace) { - gGlobalVariables.time = (float) g_psv.time; + gGlobalVariables.time = g_psv.time; + if ((e1->v.flags & FL_KILLME) || (e2->v.flags & FL_KILLME)) return; @@ -163,7 +177,7 @@ void SV_Impact(edict_t *e1, edict_t *e2, trace_t *ptrace) } } - if (e1->v.solid) + if (e1->v.solid != SOLID_NOT) { SV_SetGlobalTrace(ptrace); gEntityInterface.pfnTouch(e1, e2); @@ -173,176 +187,145 @@ void SV_Impact(edict_t *e1, edict_t *e2, trace_t *ptrace) return; #endif // REHLDS_FIXES } - if (e2->v.solid) + + if (e2->v.solid != SOLID_NOT) { SV_SetGlobalTrace(ptrace); gEntityInterface.pfnTouch(e2, e1); } } +const float STOP_EPSILON = 0.1f; + +// Slide off of the impacting object int ClipVelocity(vec_t *in, vec_t *normal, vec_t *out, float overbounce) { int blocked = 0; - if (normal[2] > 0.0) - blocked = 1; - if (normal[2] == 0.0) - blocked |= 2u; + if (normal[2] > 0.0f) + blocked = 1; // floor + if (normal[2] == 0.0f) + blocked |= 2; // step + float change; float backoff = _DotProduct(in, normal) * overbounce; + for (int i = 0; i < 3; i++) { - float tmp = normal[i] * backoff; - float change = in[i] - tmp; - out[i] = (change > -0.1f && change < 0.1f) ? 0.0f : change; + change = normal[i] * backoff; + out[i] = in[i] - change; + + if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) + out[i] = 0.0f; } return blocked; } +#define MAX_CLIP_PLANES 5 + +// The basic solid body movement clip that slides along multiple planes +// steptrace - if not NULL, the trace results of any vertical wall hit will be stored +// Returns the clipflags if the velocity was modified (hit something solid) +// 1 = floor +// 2 = wall / step +// 4 = dead stop int SV_FlyMove(edict_t *ent, float time, trace_t *steptrace) { - vec_t planes[5][3]; - int numplanes = 0; - - vec3_t primal_velocity; - primal_velocity[0] = ent->v.velocity[0]; - primal_velocity[1] = ent->v.velocity[1]; - primal_velocity[2] = ent->v.velocity[2]; - - vec3_t original_velocity; - original_velocity[0] = ent->v.velocity[0]; - original_velocity[1] = ent->v.velocity[1]; - original_velocity[2] = ent->v.velocity[2]; - - vec3_t new_velocity; - - qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0; int blocked = 0; - for (int bumpcount = 0; bumpcount < 4; bumpcount++) + int numplanes = 0; + float time_left = time; + + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity, original_velocity, new_velocity; + + VectorCopy(ent->v.velocity, original_velocity); + VectorCopy(ent->v.velocity, primal_velocity); + + qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE; + for (int bumpcount = 0; bumpcount < MAX_CLIP_PLANES - 1; bumpcount++) { - if (ent->v.velocity[0] == 0.0f && ent->v.velocity[1] == 0.0f && ent->v.velocity[2] == 0.0f) + if (VectorIsZero(ent->v.velocity)) break; vec3_t end; - for (int i = 0; i < 3; i++) - VectorMA(ent->v.origin, time, ent->v.velocity, end); + VectorMA(ent->v.origin, time_left, ent->v.velocity, end); - trace_t trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, 0, ent, monsterClip); + trace_t trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, monsterClip); if (trace.allsolid) { - ent->v.velocity[0] = vec3_origin[0]; - ent->v.velocity[1] = vec3_origin[1]; - ent->v.velocity[2] = vec3_origin[2]; - return 4; + // entity is trapped in another solid + VectorClear(ent->v.velocity); + return 4; // dead end } if (trace.fraction > 0.0f) { - trace_t test = SV_Move(trace.endpos, ent->v.mins, ent->v.maxs, trace.endpos, 0, ent, monsterClip); - if (test.allsolid != 1) + trace_t test = SV_Move(trace.endpos, ent->v.mins, ent->v.maxs, trace.endpos, MOVE_NORMAL, ent, monsterClip); + if (!test.allsolid) { - ent->v.origin[0] = trace.endpos[0]; - ent->v.origin[1] = trace.endpos[1]; - ent->v.origin[2] = trace.endpos[2]; - primal_velocity[0] = ent->v.velocity[0]; - primal_velocity[1] = ent->v.velocity[1]; - primal_velocity[2] = ent->v.velocity[2]; + // actually covered some distance + VectorCopy(trace.endpos, ent->v.origin); + VectorCopy(ent->v.velocity, original_velocity); numplanes = 0; } } + // moved the entire distance if (trace.fraction == 1.0f) break; if (!trace.ent) Sys_Error("%s: !trace.ent", __func__); - if (trace.plane.normal[2] > 0.7) + if (trace.plane.normal[2] > 0.7f) { - blocked |= 1u; + blocked |= 1; // floor + if (trace.ent->v.solid == SOLID_BSP - || trace.ent->v.movetype == MOVETYPE_PUSHSTEP || trace.ent->v.solid == SOLID_SLIDEBOX - || ent->v.flags & FL_CLIENT) + || trace.ent->v.movetype == MOVETYPE_PUSHSTEP + || (ent->v.flags & FL_CLIENT)) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; } } - if (trace.plane.normal[2] == 0.0) + if (trace.plane.normal[2] == 0.0f) { - blocked |= 2u; + blocked |= 2; // step + if (steptrace) - Q_memcpy(steptrace, &trace, 0x38u); + { + // save for player extrafriction + Q_memcpy(steptrace, &trace, sizeof(trace_t)); + } } + // run the impact function SV_Impact(ent, trace.ent, &trace); + + // break if removed by the impact function if (ent->free) break; - time = time - trace.fraction * time; - if (numplanes >= 5) + time_left -= time_left * trace.fraction; + + // clipped to another plane + if (numplanes >= MAX_CLIP_PLANES) { - ent->v.velocity[0] = vec3_origin[0]; - ent->v.velocity[1] = vec3_origin[1]; - ent->v.velocity[2] = vec3_origin[2]; - return blocked; + // this shouldn't really happen + VectorClear(ent->v.velocity); + break; } - planes[numplanes][0] = trace.plane.normal[0]; - planes[numplanes][1] = trace.plane.normal[1]; - planes[numplanes][2] = trace.plane.normal[2]; - ++numplanes; - if (numplanes != 1 - || ent->v.movetype != MOVETYPE_WALK - || ((ent->v.flags & FL_ONGROUND) && ent->v.friction == 1.0f)) - { - int i = 0; - for (; i < numplanes; i++) - { - ClipVelocity(primal_velocity, planes[i], new_velocity, 1.0); - int j = 0; - for (; j < numplanes; j++) - { - if (j == i) - continue; + VectorCopy(trace.plane.normal, planes[numplanes]); + numplanes++; - if (_DotProduct(new_velocity, planes[j]) < 0.0f) - break; - } - if (j == numplanes) - break; - } - if (i == numplanes) - { - if (numplanes != 2) - return blocked; - - vec3_t dir; - CrossProduct(planes[0], planes[1], dir); - float vscale = _DotProduct(dir, ent->v.velocity); - VectorScale(dir, vscale, ent->v.velocity); - } - else - { - ent->v.velocity[1] = new_velocity[1]; - ent->v.velocity[2] = new_velocity[2]; - ent->v.velocity[0] = new_velocity[0]; - } - - if (_DotProduct(original_velocity, ent->v.velocity) <= 0.0f) - { - ent->v.velocity[0] = vec3_origin[0]; - ent->v.velocity[1] = vec3_origin[1]; - ent->v.velocity[2] = vec3_origin[2]; - return blocked; - } - } - else + if (numplanes == 1 && ent->v.movetype == MOVETYPE_WALK && (!(ent->v.flags & FL_ONGROUND) || ent->v.friction != 1.0f)) { float d; - if (planes[0][2] <= 0.7) + if (planes[0][2] <= 0.7f) { d = (1.0f - ent->v.friction) * sv_bounce.value + 1.0f; } @@ -350,13 +333,61 @@ int SV_FlyMove(edict_t *ent, float time, trace_t *steptrace) { d = 1.0f; } - ClipVelocity(primal_velocity, planes[0], new_velocity, d); - ent->v.velocity[0] = new_velocity[0]; - ent->v.velocity[1] = new_velocity[1]; - ent->v.velocity[2] = new_velocity[2]; - primal_velocity[0] = new_velocity[0]; - primal_velocity[1] = new_velocity[1]; - primal_velocity[2] = new_velocity[2]; + + ClipVelocity(original_velocity, planes[0], new_velocity, d); + + VectorCopy(new_velocity, ent->v.velocity); + VectorCopy(new_velocity, original_velocity); + } + else + { + int i, j; + + // modify original_velocity so it parallels all of the clip planes + for (i = 0; i < numplanes; i++) + { + ClipVelocity(original_velocity, planes[i], new_velocity, 1.0f); + + for (j = 0; j < numplanes; j++) + { + if (j != i) + { + if (_DotProduct(new_velocity, planes[j]) < 0.0f) + break; // not ok + } + } + + if (j == numplanes) + break; + } + + if (i != numplanes) + { + // go along this plane + VectorCopy(new_velocity, ent->v.velocity); + } + else + { + // go along the crease + if (numplanes != 2) + { + //VectorClear(ent->v.velocity); + break; + } + + vec3_t dir; + CrossProduct(planes[0], planes[1], dir); + float d = _DotProduct(dir, ent->v.velocity); + VectorScale(dir, d, ent->v.velocity); + } + + // if current velocity is against the original velocity, + // stop dead to avoid tiny occilations in sloping corners + if (_DotProduct(ent->v.velocity, primal_velocity) <= 0.0f) + { + VectorClear(ent->v.velocity); + break; + } } } @@ -366,36 +397,42 @@ int SV_FlyMove(edict_t *ent, float time, trace_t *steptrace) void SV_AddGravity(edict_t *ent) { float ent_gravity; - if (ent->v.gravity == 0.0) - ent_gravity = 1.0; - else + if (ent->v.gravity) ent_gravity = ent->v.gravity; - ent_gravity = (float)(ent->v.velocity[2] - sv_gravity.value * ent_gravity * host_frametime); - ent->v.velocity[2] = (float)(ent_gravity + ent->v.basevelocity[2] * host_frametime); - ent->v.basevelocity[2] = 0; + else + ent_gravity = 1.0f; + + ent->v.velocity[2] -= (ent_gravity * sv_gravity.value * host_frametime); + ent->v.velocity[2] += (ent->v.basevelocity[2] * host_frametime); + ent->v.basevelocity[2] = 0.0f; + SV_CheckVelocity(ent); } NOXREF void SV_AddCorrectGravity(edict_t *ent) { NOXREFCHECK; - float ent_gravity = 1.0f; - if (ent->v.gravity != 0.0f) + float ent_gravity; + if (ent->v.gravity) ent_gravity = ent->v.gravity; + else + ent_gravity = 1.0f; ent->v.velocity[2] -= (ent_gravity * sv_gravity.value * 0.5f * host_frametime); - ent->v.velocity[2] += ent->v.basevelocity[2] * host_frametime; + ent->v.velocity[2] += (ent->v.basevelocity[2] * host_frametime); + ent->v.basevelocity[2] = 0.0f; - pmove->basevelocity[2] = 0.0f; SV_CheckVelocity(ent); } NOXREF void SV_FixupGravityVelocity(edict_t *ent) { NOXREFCHECK; - float ent_gravity = 1.0f; - if (ent->v.gravity != 0.0f) + float ent_gravity; + if (ent->v.gravity) ent_gravity = ent->v.gravity; + else + ent_gravity = 1.0f; ent->v.velocity[2] -= (ent_gravity * sv_gravity.value * 0.5f * host_frametime); SV_CheckVelocity(ent); @@ -403,145 +440,152 @@ NOXREF void SV_FixupGravityVelocity(edict_t *ent) trace_t SV_PushEntity(edict_t *ent, vec_t *push) { - trace_t trace; vec3_t end; + VectorAdd(push, ent->v.origin, end); + int moveType; - - end[0] = push[0] + ent->v.origin[0]; - end[1] = push[1] + ent->v.origin[1]; - end[2] = push[2] + ent->v.origin[2]; - if (ent->v.movetype == MOVETYPE_FLYMISSILE) - moveType = 2; + moveType = MOVE_MISSILE; + else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) + moveType = MOVE_NOMONSTERS; // only clip against bmodels else - moveType = (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) ? 1 : 0; + moveType = MOVE_NORMAL; - qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0; - trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, moveType, ent, monsterClip); - if (trace.fraction != 0.0) + qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE; + trace_t trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, moveType, ent, monsterClip); + + if (trace.fraction != 0.0f) { - ent->v.origin[0] = trace.endpos[0]; - ent->v.origin[1] = trace.endpos[1]; - ent->v.origin[2] = trace.endpos[2]; +#ifdef REHLDS_FIXES + // don't move in the direction, since this is a dead end + if (!trace.startsolid && !trace.allsolid) +#endif + { + VectorCopy(trace.endpos, ent->v.origin); + } } SV_LinkEdict(ent, TRUE); + if (trace.ent) + { SV_Impact(ent, trace.ent, &trace); + } return trace; } void SV_PushMove(edict_t *pusher, float movetime) { - vec3_t mins; - vec3_t maxs; - vec3_t move; - vec3_t pushorig; - - if (pusher->v.velocity[0] == 0.0f && pusher->v.velocity[1] == 0.0f && pusher->v.velocity[2] == 0.0f) + if (VectorIsZero(pusher->v.velocity)) { pusher->v.ltime = movetime + pusher->v.ltime; return; } - pushorig[0] = pusher->v.origin[0]; - pushorig[1] = pusher->v.origin[1]; - pushorig[2] = pusher->v.origin[2]; + vec3_t move; + vec3_t mins, maxs; for (int i = 0; i < 3; i++) { - float movedist = movetime * pusher->v.velocity[i]; - move[i] = movedist; - mins[i] = movedist + pusher->v.absmin[i]; - maxs[i] = movedist + pusher->v.absmax[i]; - pusher->v.origin[i] = movedist + pusher->v.origin[i]; + move[i] = pusher->v.velocity[i] * movetime; + mins[i] = pusher->v.absmin[i] + move[i]; + maxs[i] = pusher->v.absmax[i] + move[i]; } - pusher->v.ltime = movetime + pusher->v.ltime; + vec3_t pushorig; + VectorCopy(pusher->v.origin, pushorig); + + // move the pusher to it's final position + VectorAdd(pusher->v.origin, move, pusher->v.origin); + pusher->v.ltime += movetime; SV_LinkEdict(pusher, FALSE); if (pusher->v.solid == SOLID_NOT) return; + // see if any solid entities are inside the final position int num_moved = 0; for (int i = 1; i < g_psv.num_edicts; i++) { - edict_t* check = &g_psv.edicts[i]; + edict_t *check = &g_psv.edicts[i]; if (check->free) continue; - if (check->v.movetype == MOVETYPE_PUSH) - continue; - - if (check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_FOLLOW || check->v.movetype == MOVETYPE_NOCLIP) - continue; - - if (((check->v.flags & FL_ONGROUND) && check->v.groundentity == pusher) - || (check->v.absmin[0] < maxs[0] - && check->v.absmin[1] < maxs[1] - && check->v.absmin[2] < maxs[2] - && check->v.absmax[0] > mins[0] - && check->v.absmax[1] > mins[1] - && check->v.absmax[2] > mins[2] - && SV_TestEntityPosition(check))) - { - if (check->v.movetype != MOVETYPE_WALK) - check->v.flags &= ~FL_ONGROUND; - - vec3_t entorigin; - entorigin[0] = check->v.origin[0]; - entorigin[1] = check->v.origin[1]; - entorigin[2] = check->v.origin[2]; - - pusher->v.solid = SOLID_NOT; - g_moved_from[num_moved][0] = check->v.origin[0]; - g_moved_from[num_moved][1] = check->v.origin[1]; - g_moved_from[num_moved][2] = check->v.origin[2]; - g_moved_edict[num_moved] = check; - ++num_moved; - - SV_PushEntity(check, move); - - pusher->v.solid = SOLID_BSP; - if (!SV_TestEntityPosition(check)) + if (check->v.movetype == MOVETYPE_PUSH + || check->v.movetype == MOVETYPE_NONE + || check->v.movetype == MOVETYPE_FOLLOW + || check->v.movetype == MOVETYPE_NOCLIP) continue; + // if the entity is standing on the pusher, it will definately be moved + if (!(check->v.flags & FL_ONGROUND) || check->v.groundentity != pusher) + { + if (check->v.absmin[0] >= maxs[0] + || check->v.absmin[1] >= maxs[1] + || check->v.absmin[2] >= maxs[2] + || check->v.absmax[0] <= mins[0] + || check->v.absmax[1] <= mins[1] + || check->v.absmax[2] <= mins[2]) + continue; + + // see if the ent's bbox is inside the pusher's final position + if (!SV_TestEntityPosition(check)) + continue; + } + + // remove the onground flag for non-players + if (check->v.movetype != MOVETYPE_WALK) + check->v.flags &= ~FL_ONGROUND; + + vec3_t entorig; + VectorCopy(check->v.origin, entorig); + VectorCopy(check->v.origin, g_moved_from[num_moved]); + g_moved_edict[num_moved] = check; + num_moved++; + + // try moving the contacted entity + pusher->v.solid = SOLID_NOT; + SV_PushEntity(check, move); + pusher->v.solid = SOLID_BSP; + + // if it is still inside the pusher, block + if (SV_TestEntityPosition(check)) + { + // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) { - check->v.mins[1] = 0; + // corpse check->v.mins[0] = 0; + check->v.mins[1] = 0; + check->v.maxs[0] = 0; check->v.maxs[1] = 0; check->v.maxs[2] = check->v.mins[2]; + continue; } - check->v.origin[0] = entorigin[0]; - check->v.origin[1] = entorigin[1]; - check->v.origin[2] = entorigin[2]; + VectorCopy(entorig, check->v.origin); SV_LinkEdict(check, TRUE); - pusher->v.origin[0] = pushorig[0]; - pusher->v.origin[1] = pushorig[1]; - pusher->v.origin[2] = pushorig[2]; + VectorCopy(pushorig, pusher->v.origin); SV_LinkEdict(pusher, FALSE); - pusher->v.ltime = pusher->v.ltime - movetime; + pusher->v.ltime -= movetime; gEntityInterface.pfnBlocked(pusher, check); + // move back any entities we already moved for (int e = 0; e < num_moved; e++) { - g_moved_edict[e]->v.origin[0] = g_moved_from[e][0]; - g_moved_edict[e]->v.origin[1] = g_moved_from[e][1]; - g_moved_edict[e]->v.origin[2] = g_moved_from[e][2]; - + VectorCopy(g_moved_from[e], g_moved_edict[e]->v.origin); SV_LinkEdict(g_moved_edict[e], FALSE); } + return; } } @@ -549,159 +593,154 @@ void SV_PushMove(edict_t *pusher, float movetime) int SV_PushRotate(edict_t *pusher, float movetime) { - vec3_t amove; - vec3_t pushorig; - vec3_t forward; - vec3_t right; - vec3_t up; - vec3_t forwardNow; - vec3_t rightNow; - vec3_t upNow; + vec3_t amove, pushorig; + vec3_t forward, right, up; + vec3_t forwardNow, rightNow, upNow; - if (pusher->v.avelocity[0] == 0.0 && pusher->v.avelocity[1] == 0.0 && pusher->v.avelocity[2] == 0.0) + if (VectorIsZero(pusher->v.avelocity)) { - pusher->v.ltime = movetime + pusher->v.ltime; + pusher->v.ltime += movetime; return 1; } - for (int i = 0; i < 3; i++) - amove[i] = movetime * pusher->v.avelocity[i]; - + VectorScale(pusher->v.avelocity, movetime, amove); AngleVectors(pusher->v.angles, forward, right, up); - pushorig[0] = pusher->v.angles[0]; - pushorig[1] = pusher->v.angles[1]; - pushorig[2] = pusher->v.angles[2]; + VectorCopy(pusher->v.angles, pushorig); - pusher->v.angles[0] = amove[0] + pusher->v.angles[0]; - pusher->v.angles[1] = amove[1] + pusher->v.angles[1]; - pusher->v.angles[2] = amove[2] + pusher->v.angles[2]; + // move the pusher to it's final position + VectorAdd(pusher->v.angles, amove, pusher->v.angles); AngleVectorsTranspose(pusher->v.angles, forwardNow, rightNow, upNow); - pusher->v.ltime = movetime + pusher->v.ltime; - + pusher->v.ltime += movetime; SV_LinkEdict(pusher, FALSE); + + // non-solid pushers can't push anything if (pusher->v.solid == SOLID_NOT) return 1; + // see if any solid entities are inside the final position int num_moved = 0; for (int i = 1; i < g_psv.num_edicts; i++) { - edict_t* check = &g_psv.edicts[i]; + edict_t *check = &g_psv.edicts[i]; + if (check->free) continue; - if (check->v.movetype == MOVETYPE_PUSH) - continue; + if (check->v.movetype == MOVETYPE_PUSH + || check->v.movetype == MOVETYPE_NONE + || check->v.movetype == MOVETYPE_FOLLOW + || check->v.movetype == MOVETYPE_NOCLIP) + continue; - if (check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_FOLLOW || check->v.movetype == MOVETYPE_NOCLIP) - continue; - - if (((check->v.flags & FL_ONGROUND) && check->v.groundentity == pusher) - || (check->v.absmin[0] < pusher->v.absmax[0] - && check->v.absmin[1] < pusher->v.absmax[1] - && check->v.absmin[2] < pusher->v.absmax[2] - && check->v.absmax[0] > pusher->v.absmin[0] - && check->v.absmax[1] > pusher->v.absmin[1] - && check->v.absmax[2] > pusher->v.absmin[2] - && SV_TestEntityPosition(check))) + // if the entity is standing on the pusher, it will definately be moved + if (!(check->v.flags & FL_ONGROUND) || check->v.groundentity != pusher) { - if (check->v.movetype != MOVETYPE_WALK) - check->v.flags &= ~FL_ONGROUND; + if (check->v.absmin[0] >= pusher->v.absmax[0] + || check->v.absmin[1] >= pusher->v.absmax[1] + || check->v.absmin[2] >= pusher->v.absmax[2] + || check->v.absmax[0] <= pusher->v.absmin[0] + || check->v.absmax[1] <= pusher->v.absmin[1] + || check->v.absmax[2] <= pusher->v.absmin[2]) + continue; - vec3_t entorig; - entorig[0] = check->v.origin[0]; - entorig[1] = check->v.origin[1]; - entorig[2] = check->v.origin[2]; + // see if the ent's bbox is inside the pusher's final position + if (!SV_TestEntityPosition(check)) + continue; + } - g_moved_from[num_moved][0] = check->v.origin[0]; - g_moved_from[num_moved][1] = check->v.origin[1]; - g_moved_from[num_moved][2] = check->v.origin[2]; - g_moved_edict[num_moved] = check; - ++num_moved; + // remove the onground flag for non-players + if (check->v.movetype != MOVETYPE_WALK) + check->v.flags &= ~FL_ONGROUND; - if (num_moved >= g_psv.max_edicts) - Sys_Error("%s: Out of edicts in simulator!\n", __func__); + vec3_t entorig; + VectorCopy(check->v.origin, entorig); + VectorCopy(check->v.origin, g_moved_from[num_moved]); + g_moved_edict[num_moved] = check; + num_moved++; - vec3_t start, end, push, move; + if (num_moved >= g_psv.max_edicts) + Sys_Error("%s: Out of edicts in simulator!\n", __func__); - if (check->v.movetype == MOVETYPE_PUSHSTEP) + vec3_t start, end, push, move; + + if (check->v.movetype == MOVETYPE_PUSHSTEP) + { + vec3_t org; + VectorAverage(check->v.absmax, check->v.absmin, org); + VectorSubtract(org, pusher->v.origin, start); + } + else + { + VectorSubtract(check->v.origin, pusher->v.origin, start); + } + + // calculate destination position + move[0] = _DotProduct(forward, start); + move[1] = -_DotProduct(right, start); + move[2] = _DotProduct(up, start); + + end[0] = _DotProduct(forwardNow, move); + end[1] = _DotProduct(rightNow, move); + end[2] = _DotProduct(upNow, move); + + VectorSubtract(end, start, push); + + // try moving the contacted entity + pusher->v.solid = SOLID_NOT; + SV_PushEntity(check, push); + pusher->v.solid = SOLID_BSP; + + if (check->v.movetype != MOVETYPE_PUSHSTEP) + { + if (check->v.flags & FL_CLIENT) { - vec3_t org; - org[0] = (check->v.absmax[0] + check->v.absmin[0]) * 0.5f; - org[1] = (check->v.absmax[1] + check->v.absmin[1]) * 0.5f; - org[2] = (check->v.absmax[2] + check->v.absmin[2]) * 0.5f; - start[0] = org[0] - pusher->v.origin[0]; - start[1] = org[1] - pusher->v.origin[1]; - start[2] = org[2] - pusher->v.origin[2]; + check->v.fixangle = 2; + check->v.avelocity[1] = check->v.avelocity[1] + amove[1]; } else { - start[0] = check->v.origin[0] - pusher->v.origin[0]; - start[1] = check->v.origin[1] - pusher->v.origin[1]; - start[2] = check->v.origin[2] - pusher->v.origin[2]; + //check->v.angles[0] = check->v.angles[0] + 0.0f; //TODO: The 'check->v.angles[0]' variable is assigned to itself. + check->v.angles[1] = check->v.angles[1] + amove[1]; + //check->v.angles[2] = check->v.angles[2] + 0.0f; //TODO: The 'check->v.angles[2]' variable is assigned to itself. } + } - pusher->v.solid = SOLID_NOT; - - move[0] = _DotProduct(forward, start); - move[1] = -_DotProduct(right, start); - move[2] = _DotProduct(up, start); - end[0] = _DotProduct(forwardNow, move); - end[1] = _DotProduct(rightNow, move); - end[2] = _DotProduct(upNow, move); - push[0] = end[0] - start[0]; - push[1] = end[1] - start[1]; - push[2] = end[2] - start[2]; - SV_PushEntity(check, push); - - pusher->v.solid = SOLID_BSP; - if (check->v.movetype != MOVETYPE_PUSHSTEP) - { - if (check->v.flags & FL_CLIENT) - { - check->v.fixangle = 2; - check->v.avelocity[1] = amove[1] + check->v.avelocity[1]; - } - else - { - //check->v.angles[0] = check->v.angles[0] + 0.0f; //TODO: The 'check->v.angles[0]' variable is assigned to itself. - check->v.angles[1] = amove[1] + check->v.angles[1]; - //check->v.angles[2] = check->v.angles[2] + 0.0f; //TODO: The 'check->v.angles[2]' variable is assigned to itself. - } - } - - if (!SV_TestEntityPosition(check) || check->v.mins[0] == check->v.maxs[0]) + // if it is still inside the pusher, block + if (SV_TestEntityPosition(check)) + { + // fail the move + if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) { - check->v.mins[1] = 0.0f; + // corpse check->v.mins[0] = 0.0f; + check->v.mins[1] = 0.0f; check->v.maxs[0] = 0.0f; check->v.maxs[1] = 0.0f; + check->v.maxs[2] = check->v.mins[2]; continue; } - check->v.origin[0] = entorig[0]; - check->v.origin[1] = entorig[1]; - check->v.origin[2] = entorig[2]; + VectorCopy(entorig, check->v.origin); SV_LinkEdict(check, TRUE); - pusher->v.angles[0] = pushorig[0]; - pusher->v.angles[1] = pushorig[1]; - pusher->v.angles[2] = pushorig[2]; + VectorCopy(pushorig, pusher->v.angles); SV_LinkEdict(pusher, FALSE); - pusher->v.ltime = pusher->v.ltime - movetime; + pusher->v.ltime -= movetime; gEntityInterface.pfnBlocked(pusher, check); + + // move back any entities we already moved for (int e = 0; e < num_moved; e++) { - edict_t* movedEnt = g_moved_edict[e]; - movedEnt->v.origin[0] = g_moved_from[e][0]; - movedEnt->v.origin[1] = g_moved_from[e][1]; - movedEnt->v.origin[2] = g_moved_from[e][2]; + edict_t *movedEnt = g_moved_edict[e]; + VectorCopy(g_moved_from[e], movedEnt->v.origin); + if (movedEnt->v.flags & FL_CLIENT) { movedEnt->v.avelocity[1] = 0.0f; @@ -715,6 +754,7 @@ int SV_PushRotate(edict_t *pusher, float movetime) //movedEnt->v.angles[2] = movedEnt->v.angles[2]; //TODO: V570 The 'movedEnt->v.angles[2]' variable is assigned to itself. } } + SV_LinkEdict(movedEnt, FALSE); } @@ -731,27 +771,30 @@ void SV_Physics_Pusher(edict_t *ent) float oldltime = ent->v.ltime; float movetime; - if (oldltime + host_frametime <= thinktime) + if (thinktime < oldltime + host_frametime) { - movetime = (float) host_frametime; + movetime = thinktime - ent->v.ltime; + + if (movetime < 0.0f) + movetime = 0.0f; } else { - movetime = thinktime - ent->v.ltime; - if (movetime < 0.0) - movetime = 0; + movetime = host_frametime; } - if (movetime != 0.0) + + if (movetime) { - if (ent->v.avelocity[0] != 0.0 || ent->v.avelocity[1] != 0.0 || ent->v.avelocity[2] != 0.0) + if (!VectorIsZero(ent->v.avelocity)) { - if (ent->v.velocity[0] != 0.0 || ent->v.velocity[1] != 0.0 || ent->v.velocity[2] != 0.0) + if (!VectorIsZero(ent->v.velocity)) { if (SV_PushRotate(ent, movetime)) { float savetime = ent->v.ltime; ent->v.ltime = oldltime; SV_PushMove(ent, movetime); + if (ent->v.ltime < savetime) ent->v.ltime = savetime; } @@ -780,7 +823,7 @@ void SV_Physics_Pusher(edict_t *ent) ) { ent->v.nextthink = 0; - gGlobalVariables.time = (float) g_psv.time; + gGlobalVariables.time = g_psv.time; gEntityInterface.pfnThink(ent); } } @@ -788,166 +831,170 @@ void SV_Physics_Pusher(edict_t *ent) qboolean SV_CheckWater(edict_t *ent) { vec3_t point; - - ent->v.waterlevel = 0; - ent->v.watertype = -1; - g_groupmask = ent->v.groupinfo; point[0] = (ent->v.absmax[0] + ent->v.absmin[0]) * 0.5f; point[1] = (ent->v.absmax[1] + ent->v.absmin[1]) * 0.5f; - point[2] = ent->v.absmin[2] + 1.0f; - int cont = SV_PointContents(point); - if (cont > CONTENTS_WATER || cont <= CONTENTS_TRANSLUCENT) - return 0; + point[2] = (ent->v.absmin[2] + 1.0f); - ent->v.watertype = cont; - ent->v.waterlevel = 1; - if (ent->v.absmin[2] == ent->v.absmax[2]) + ent->v.watertype = CONTENTS_EMPTY; + ent->v.waterlevel = 0; + + g_groupmask = ent->v.groupinfo; + + int cont = SV_PointContents(point); + if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT) { - ent->v.waterlevel = 3; - } - else - { - g_groupmask = ent->v.groupinfo; - point[2] = (ent->v.absmax[2] + ent->v.absmin[2]) * 0.5f; - int truecont = SV_PointContents(point); - if (truecont <= CONTENTS_WATER && truecont > CONTENTS_TRANSLUCENT) + ent->v.watertype = cont; + ent->v.waterlevel = 1; + + if (ent->v.absmin[2] == ent->v.absmax[2]) + { + ent->v.waterlevel = 3; + } + else { - ent->v.waterlevel = 2; g_groupmask = ent->v.groupinfo; - point[0] = point[0] + ent->v.view_ofs[0]; - point[1] = point[1] + ent->v.view_ofs[1]; - point[2] = point[2] + ent->v.view_ofs[2]; - truecont = SV_PointContents(point); + point[2] = (ent->v.absmax[2] + ent->v.absmin[2]) * 0.5f; + + int truecont = SV_PointContents(point); if (truecont <= CONTENTS_WATER && truecont > CONTENTS_TRANSLUCENT) - ent->v.waterlevel = 3; + { + ent->v.waterlevel = 2; + g_groupmask = ent->v.groupinfo; + point[0] = point[0] + ent->v.view_ofs[0]; + point[1] = point[1] + ent->v.view_ofs[1]; + point[2] = point[2] + ent->v.view_ofs[2]; + truecont = SV_PointContents(point); + if (truecont <= CONTENTS_WATER && truecont > CONTENTS_TRANSLUCENT) + ent->v.waterlevel = 3; + } + } + + if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) + { + static vec3_t current_table[] = + { + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { -1.0f, 0.0f, 0.0f }, + { 0.0f, -1.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f }, + { 0.0f, 0.0f, -1.0f }, + }; + + VectorMA(ent->v.basevelocity, 150.0f * ent->v.waterlevel / 3.0f, current_table[-(cont - CONTENTS_CURRENT_0)], ent->v.basevelocity); } } - if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) - { - static vec_t current_table[6][3] = - { - { 1.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f }, - { -1.0f, 0.0f, 0.0f }, - { 0.0f, -1.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f }, - { 0.0f, 0.0f, -1.0f } - }; - - VectorMA(ent->v.basevelocity, ent->v.waterlevel * 50.0f, current_table[-(cont - CONTENTS_CURRENT_0)], ent->v.basevelocity); - } - - return (ent->v.waterlevel > 1) ? 1 : 0; + return (ent->v.waterlevel > 1) ? TRUE : FALSE; } -float SV_RecursiveWaterLevel(vec_t *center, float out, float in, int count) +float SV_RecursiveWaterLevel(const vec_t *origin, float mins, float maxs, int depth) { - float offset = (float)((out - in) * 0.5 + in); - if (count + 1 < 6) - { - vec3_t test; - test[0] = center[0]; - test[1] = center[1]; - test[2] = offset + center[2]; - if (SV_PointContents(test) == CONTENTS_WATER) - return SV_RecursiveWaterLevel(center, out, offset, count + 1); - else - return SV_RecursiveWaterLevel(center, offset, in, count + 1); - } - else - { - return offset; - } + float waterlevel = ((mins - maxs) * 0.5f + maxs); + if (++depth > 5) + return waterlevel; + + vec3_t test; + test[0] = origin[0]; + test[1] = origin[1]; + test[2] = origin[2] + waterlevel; + + if (SV_PointContents(test) == CONTENTS_WATER) + return SV_RecursiveWaterLevel(origin, mins, waterlevel, depth); + + return SV_RecursiveWaterLevel(origin, waterlevel, maxs, depth); } float SV_Submerged(edict_t *ent) { - float end; vec3_t center; + VectorAverage(ent->v.absmax, ent->v.absmin, center); - center[0] = (ent->v.absmax[0] + ent->v.absmin[0]) * 0.5f; - center[1] = (ent->v.absmax[1] + ent->v.absmin[1]) * 0.5f; - center[2] = (ent->v.absmin[2] + ent->v.absmax[2]) * 0.5f; - float start = ent->v.absmin[2] - center[2]; - if (ent->v.waterlevel == 1) + float waterlevel = ent->v.absmin[2] - center[2]; + + switch (ent->v.waterlevel) { - return SV_RecursiveWaterLevel(center, 0.0, start, 0) - start; - } - - if (ent->v.waterlevel == 2) - { - end = ent->v.absmax[2] - center[2]; - return SV_RecursiveWaterLevel(center, end, 0.0, 0) - start; - } - - if (ent->v.waterlevel == 3) + case 1: + return SV_RecursiveWaterLevel(center, 0.0f, waterlevel, 0) - waterlevel; + case 2: + return SV_RecursiveWaterLevel(center, ent->v.absmax[2] - center[2], 0.0f, 0) - waterlevel; + case 3: { vec3_t point; point[0] = center[0]; point[1] = center[1]; point[2] = ent->v.absmax[2]; + g_groupmask = ent->v.groupinfo; - if (SV_PointContents(point) == -3) + + if (SV_PointContents(point) == CONTENTS_WATER) + { return ent->v.maxs[2] - ent->v.mins[2]; + } - end = ent->v.absmax[2] - center[2]; - return SV_RecursiveWaterLevel(center, end, 0.0, 0) - start; + return SV_RecursiveWaterLevel(center, ent->v.absmax[2] - center[2], 0.0f, 0) - waterlevel; + } + default: + return 0.0f; } - - return 0; } // Non moving objects can only think. void SV_Physics_None(edict_t *ent) { + // regular thinking SV_RunThink(ent); } +// Just copy angles and origin of parent void SV_Physics_Follow(edict_t *ent) { - if (SV_RunThink(ent)) + // regular thinking + if (!SV_RunThink(ent)) + return; + + edict_t *parent = ent->v.aiment; + if (!ent->v.aiment) { - if (ent->v.aiment) - { - ent->v.angles[0] = ent->v.aiment->v.angles[0]; - ent->v.angles[1] = ent->v.aiment->v.angles[1]; - ent->v.angles[2] = ent->v.aiment->v.angles[2]; - ent->v.origin[0] = ent->v.aiment->v.origin[0] + ent->v.v_angle[0]; - ent->v.origin[1] = ent->v.aiment->v.origin[1] + ent->v.v_angle[1]; - ent->v.origin[2] = ent->v.aiment->v.origin[2] + ent->v.v_angle[2]; - SV_LinkEdict(ent, TRUE); - } - else - { - Con_DPrintf("%s movetype FOLLOW with NULL aiment\n", &pr_strings[ent->v.classname]); - ent->v.movetype = 0; - } + Con_DPrintf("%s movetype FOLLOW with NULL aiment\n", &pr_strings[ent->v.classname]); + ent->v.movetype = MOVETYPE_NONE; + return; } + + VectorAdd(parent->v.origin, ent->v.v_angle, ent->v.origin); + VectorCopy(parent->v.angles, ent->v.angles); + + SV_LinkEdict(ent, TRUE); } +// A moving object that doesn't obey physics void SV_Physics_Noclip(edict_t *ent) { - if (SV_RunThink(ent)) - { - VectorMA(ent->v.angles, (float)host_frametime, ent->v.avelocity, ent->v.angles); - VectorMA(ent->v.origin, (float)host_frametime, ent->v.velocity, ent->v.origin); - SV_LinkEdict(ent, FALSE); - } + // regular thinking + if (!SV_RunThink(ent)) + return; + + VectorMA(ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); + VectorMA(ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); + + // noclip ents never touch triggers + SV_LinkEdict(ent, FALSE); } void SV_CheckWaterTransition(edict_t *ent) { vec3_t point; - g_groupmask = ent->v.groupinfo; point[0] = (ent->v.absmax[0] + ent->v.absmin[0]) * 0.5f; point[1] = (ent->v.absmax[1] + ent->v.absmin[1]) * 0.5f; - point[2] = ent->v.absmin[2] + 1.0f; - int cont = SV_PointContents(point); + point[2] = (ent->v.absmin[2] + 1.0f); + g_groupmask = ent->v.groupinfo; + + int cont = SV_PointContents(point); if (ent->v.watertype == 0) { + // just spawned here ent->v.watertype = cont; ent->v.waterlevel = 1; return; @@ -955,38 +1002,47 @@ void SV_CheckWaterTransition(edict_t *ent) if (cont > CONTENTS_WATER || cont <= CONTENTS_TRANSLUCENT) { - if (ent->v.watertype != -1) - SV_StartSound(0, ent, 0, "player/pl_wade2.wav", 255, 1.0, 0, 100); - ent->v.watertype = -1; + if (ent->v.watertype != CONTENTS_EMPTY) + { + // just crossed into water + SV_StartSound(0, ent, CHAN_AUTO, "player/pl_wade2.wav", 255, 1.0f, 0, PITCH_NORM); + } + + ent->v.watertype = CONTENTS_EMPTY; ent->v.waterlevel = 0; return; } - if (ent->v.watertype == -1) + if (ent->v.watertype == CONTENTS_EMPTY) { - SV_StartSound(0, ent, 0, "player/pl_wade1.wav", 255, 1.0, 0, 100); - ent->v.velocity[2] = ent->v.velocity[2] * 0.5f; + // just crossed into water + SV_StartSound(0, ent, CHAN_AUTO, "player/pl_wade1.wav", 255, 1.0f, 0, PITCH_NORM); + ent->v.velocity[2] *= 0.5f; } ent->v.watertype = cont; ent->v.waterlevel = 1; + if (ent->v.absmin[2] == ent->v.absmax[2]) { + // a point entity ent->v.waterlevel = 3; return; } - g_groupmask = ent->v.groupinfo; point[2] = (ent->v.absmin[2] + ent->v.absmax[2]) * 0.5f; + + g_groupmask = ent->v.groupinfo; cont = SV_PointContents(point); + if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT) { ent->v.waterlevel = 2; + VectorAdd(point, ent->v.view_ofs, point); + g_groupmask = ent->v.groupinfo; - point[0] = point[0] + ent->v.view_ofs[0]; - point[1] = point[1] + ent->v.view_ofs[1]; - point[2] = point[2] + ent->v.view_ofs[2]; cont = SV_PointContents(point); + if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT) { ent->v.waterlevel = 3; @@ -994,50 +1050,61 @@ void SV_CheckWaterTransition(edict_t *ent) } } +// Toss, bounce, and fly movement. When onground, do nothing. void SV_Physics_Toss(edict_t *ent) { SV_CheckWater(ent); + + // regular thinking if (!SV_RunThink(ent)) return; - if (ent->v.velocity[2] > 0.0 || ent->v.groundentity == NULL || ent->v.groundentity->v.flags & (FL_MONSTER | FL_CLIENT)) + if (ent->v.velocity[2] > 0.0f || !ent->v.groundentity || (ent->v.groundentity->v.flags & (FL_MONSTER | FL_CLIENT))) { ent->v.flags &= ~FL_ONGROUND; + } - if ((ent->v.flags & FL_ONGROUND) && VectorCompare(ent->v.velocity, vec_origin)) { - ent->v.avelocity[0] = vec3_origin[0]; - ent->v.avelocity[1] = vec3_origin[1]; - ent->v.avelocity[2] = vec3_origin[2]; - if (VectorCompare(ent->v.basevelocity, vec_origin)) - return; + // if on ground and not moving, return. + if ((ent->v.flags & FL_ONGROUND) && VectorIsZero(ent->v.velocity)) + { + VectorClear(ent->v.avelocity); + + if (VectorIsZero(ent->v.basevelocity)) + return; // at rest } SV_CheckVelocity(ent); - if (ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_BOUNCEMISSILE && ent->v.movetype != MOVETYPE_FLYMISSILE) - SV_AddGravity(ent); - VectorMA(ent->v.angles, (float)host_frametime, ent->v.avelocity, ent->v.angles); - ent->v.velocity[0] = ent->v.basevelocity[0] + ent->v.velocity[0]; - ent->v.velocity[1] = ent->v.basevelocity[1] + ent->v.velocity[1]; - ent->v.velocity[2] = ent->v.basevelocity[2] + ent->v.velocity[2]; + // add gravity + switch (ent->v.movetype) + { + case MOVETYPE_FLY: + case MOVETYPE_FLYMISSILE: + case MOVETYPE_BOUNCEMISSILE: + break; + default: + SV_AddGravity(ent); + break; + } + + // move angles + VectorMA(ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); + + // move origin + VectorAdd(ent->v.velocity, ent->v.basevelocity, ent->v.velocity); SV_CheckVelocity(ent); vec3_t move; - VectorScale(ent->v.velocity, (float)host_frametime, move); - ent->v.velocity[0] = ent->v.velocity[0] - ent->v.basevelocity[0]; - ent->v.velocity[1] = ent->v.velocity[1] - ent->v.basevelocity[1]; - ent->v.velocity[2] = ent->v.velocity[2] - ent->v.basevelocity[2]; + VectorScale(ent->v.velocity, host_frametime, move); + VectorSubtract(ent->v.velocity, ent->v.basevelocity, ent->v.velocity); trace_t trace = SV_PushEntity(ent, move); SV_CheckVelocity(ent); if (trace.allsolid) { - ent->v.velocity[0] = vec3_origin[0]; - ent->v.velocity[1] = vec3_origin[1]; - ent->v.velocity[2] = vec3_origin[2]; - ent->v.avelocity[0] = vec3_origin[0]; - ent->v.avelocity[1] = vec3_origin[1]; - ent->v.avelocity[2] = vec3_origin[2]; + // entity is trapped in another solid + VectorClear(ent->v.avelocity); + VectorClear(ent->v.velocity); return; } @@ -1052,312 +1119,330 @@ void SV_Physics_Toss(edict_t *ent) float backoff; if (ent->v.movetype == MOVETYPE_BOUNCE) - { backoff = 2.0f - ent->v.friction; - } - else - { + else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE) backoff = 2.0f; - if (ent->v.movetype != MOVETYPE_BOUNCEMISSILE) - backoff = 1.0f; - } + else + backoff = 1.0f; + ClipVelocity(ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); - if (trace.plane.normal[2] <= 0.7) + // stop if on ground + if (trace.plane.normal[2] > 0.7f) { - SV_CheckWaterTransition(ent); - return; - } + VectorAdd(ent->v.velocity, ent->v.basevelocity, move); + float vel = _DotProduct(move, move); - move[0] = ent->v.basevelocity[0] + ent->v.velocity[0]; - move[1] = ent->v.basevelocity[1] + ent->v.velocity[1]; - move[2] = ent->v.basevelocity[2] + ent->v.velocity[2]; - if (sv_gravity.value * host_frametime > move[2]) - { - ent->v.flags |= FL_ONGROUND; - ent->v.velocity[2]= 0; - ent->v.groundentity = trace.ent; - } - - if (_DotProduct(move, move) >= 900.0f) - { - if (ent->v.movetype == MOVETYPE_BOUNCE || ent->v.movetype == MOVETYPE_BOUNCEMISSILE) + if (move[2] < sv_gravity.value * host_frametime) { - float scale = (1.0 - trace.fraction) * host_frametime * 0.9f; + // we're rolling on the ground, add static friction + ent->v.flags |= FL_ONGROUND; + ent->v.velocity[2]= 0; + ent->v.groundentity = trace.ent; + } + + if (_DotProduct(move, move) < 900.0f || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE)) + { + ent->v.flags |= FL_ONGROUND; + ent->v.groundentity = trace.ent; + + VectorClear(ent->v.velocity); + VectorClear(ent->v.avelocity); + } + else + { + float scale = (1.0f - trace.fraction) * host_frametime * 0.9f; VectorScale(ent->v.velocity, scale, move); VectorMA(move, scale, ent->v.basevelocity, move); - SV_PushEntity(ent, move); - SV_CheckWaterTransition(ent); - return; + + trace = SV_PushEntity(ent, move); + +#ifdef REHLDS_FIXES + if (ent->free) + return; +#endif } } - ent->v.flags |= FL_ONGROUND; - ent->v.groundentity = trace.ent; - ent->v.velocity[0] = vec3_origin[0]; - ent->v.velocity[1] = vec3_origin[1]; - ent->v.velocity[2] = vec3_origin[2]; - ent->v.avelocity[0] = vec3_origin[0]; - ent->v.avelocity[1] = vec3_origin[1]; - ent->v.avelocity[2] = vec3_origin[2]; + // check for in water SV_CheckWaterTransition(ent); } void PF_WaterMove(edict_t *pSelf) { - int flags; - int waterlevel; - int watertype; - float drownlevel; - if (pSelf->v.movetype == MOVETYPE_NOCLIP) { - pSelf->v.air_finished = (float)(g_psv.time + 12.0f); + pSelf->v.air_finished = g_psv.time + 12.0f; return; } - if (pSelf->v.health < 0.0) + if (pSelf->v.health < 0.0f) return; - drownlevel = pSelf->v.deadflag ? 1.0f : 3.0f; - waterlevel = pSelf->v.waterlevel; - watertype = pSelf->v.watertype; - flags = pSelf->v.flags; + float drownlevel = (pSelf->v.deadflag == DEAD_NO) ? 3.0f : 1.0f; + int waterlevel = pSelf->v.waterlevel; + int watertype = pSelf->v.watertype; + int flags = pSelf->v.flags; + if (!(flags & (FL_IMMUNE_WATER | FL_GODMODE))) { - if (flags & FL_SWIM && (waterlevel < drownlevel) - || (waterlevel >= drownlevel)) + if ((flags & FL_SWIM) && (waterlevel < drownlevel) || (waterlevel >= drownlevel)) { if (pSelf->v.air_finished < g_psv.time && pSelf->v.pain_finished < g_psv.time) { - pSelf->v.dmg += 2.0; - if (pSelf->v.dmg > 15.0) + pSelf->v.dmg += 2.0f; + + if (pSelf->v.dmg > 15.0f) pSelf->v.dmg = 10.0f; - pSelf->v.pain_finished = (float)(g_psv.time + 1.0f); + + pSelf->v.pain_finished = g_psv.time + 1.0f; } } else { pSelf->v.dmg = 2.0f; - pSelf->v.air_finished = (float)(g_psv.time + 12.0); + pSelf->v.air_finished = g_psv.time + 12.0f; } } + if (!waterlevel) { + // play leave water sound if (flags & FL_INWATER) { switch (RandomLong(0, 3)) { case 0: - SV_StartSound(0, pSelf, 4, "player/pl_wade1.wav", 255, 0.8f, 0, 100); + SV_StartSound(0, pSelf, CHAN_BODY, "player/pl_wade1.wav", 255, ATTN_NORM, 0, PITCH_NORM); break; case 1: - SV_StartSound(0, pSelf, 4, "player/pl_wade2.wav", 255, 0.8f, 0, 100); + SV_StartSound(0, pSelf, CHAN_BODY, "player/pl_wade2.wav", 255, ATTN_NORM, 0, PITCH_NORM); break; case 2: - SV_StartSound(0, pSelf, 4, "player/pl_wade3.wav", 255, 0.8f, 0, 100); + SV_StartSound(0, pSelf, CHAN_BODY, "player/pl_wade3.wav", 255, ATTN_NORM, 0, PITCH_NORM); break; case 3: - SV_StartSound(0, pSelf, 4, "player/pl_wade4.wav", 255, 0.8f, 0, 100); + SV_StartSound(0, pSelf, CHAN_BODY, "player/pl_wade4.wav", 255, ATTN_NORM, 0, PITCH_NORM); break; default: break; } + pSelf->v.flags &= ~FL_INWATER; } - pSelf->v.air_finished = (float)(g_psv.time + 12.0); + + pSelf->v.air_finished = g_psv.time + 12.0f; return; } - if (watertype == -5) + if (watertype == CONTENTS_LAVA) { if (!(flags & (FL_IMMUNE_LAVA | FL_GODMODE)) && pSelf->v.dmgtime < g_psv.time) { if (g_psv.time <= pSelf->v.radsuit_finished) - pSelf->v.dmgtime = (float)(g_psv.time + 1.0); + pSelf->v.dmgtime = g_psv.time + 1.0f; else - pSelf->v.dmgtime = (float)(g_psv.time + 0.2); + pSelf->v.dmgtime = g_psv.time + 0.2f; } } - else + else if (watertype == CONTENTS_SLIME) { - if (watertype == -4 - && !(flags & (FL_IMMUNE_SLIME | FL_GODMODE)) - && pSelf->v.dmgtime < g_psv.time - && pSelf->v.radsuit_finished < g_psv.time) + if (!(flags & (FL_IMMUNE_SLIME | FL_GODMODE)) && pSelf->v.dmgtime < g_psv.time) { - pSelf->v.dmgtime = (float)(g_psv.time + 1.0); + if (pSelf->v.radsuit_finished < g_psv.time) + pSelf->v.dmgtime = g_psv.time + 1.0f; } } if (!(flags & FL_INWATER)) { - if (watertype == -3) + // player enter water sound + if (watertype == CONTENTS_WATER) { switch (RandomLong(0, 3)) { case 0: - SV_StartSound(0, pSelf, 4, "player/pl_wade1.wav", 255, 0.8f, 0, 100); + SV_StartSound(0, pSelf, CHAN_BODY, "player/pl_wade1.wav", 255, ATTN_NORM, 0, PITCH_NORM); break; case 1: - SV_StartSound(0, pSelf, 4, "player/pl_wade2.wav", 255, 0.8f, 0, 100); + SV_StartSound(0, pSelf, CHAN_BODY, "player/pl_wade2.wav", 255, ATTN_NORM, 0, PITCH_NORM); break; case 2: - SV_StartSound(0, pSelf, 4, "player/pl_wade3.wav", 255, 0.8f, 0, 100); + SV_StartSound(0, pSelf, CHAN_BODY, "player/pl_wade3.wav", 255, ATTN_NORM, 0, PITCH_NORM); break; case 3: - SV_StartSound(0, pSelf, 4, "player/pl_wade4.wav", 255, 0.8f, 0, 100); + SV_StartSound(0, pSelf, CHAN_BODY, "player/pl_wade4.wav", 255, ATTN_NORM, 0, PITCH_NORM); break; default: break; } } - pSelf->v.dmgtime = 0; - pSelf->v.flags = flags | FL_INWATER; + + pSelf->v.dmgtime = 0.0f; + pSelf->v.flags |= FL_INWATER; } if (!(flags & FL_WATERJUMP)) { - VectorMA(pSelf->v.velocity, (float)(pSelf->v.waterlevel * host_frametime * -0.8), pSelf->v.velocity, pSelf->v.velocity); + VectorMA(pSelf->v.velocity, (-0.8 * pSelf->v.waterlevel * host_frametime), pSelf->v.velocity, pSelf->v.velocity); } } - +// Monsters freefall when they don't have a ground entity, otherwise all movement is done with discrete steps. +// This is also used for objects that have become still on the ground, +// but will fall if the floor is pulled out from under them. void SV_Physics_Step(edict_t *ent) { - vec3_t maxs; - vec3_t mins; - vec3_t point; - PF_WaterMove(ent); SV_CheckVelocity(ent); - qboolean wasonground = (ent->v.flags & FL_ONGROUND) ? 1 : 0; + + qboolean wasonground = (ent->v.flags & FL_ONGROUND) ? TRUE : FALSE; qboolean inwater = SV_CheckWater(ent); - if ((ent->v.flags & FL_FLOAT) && ent->v.waterlevel > 0)// FL_FLOAT + + if ((ent->v.flags & FL_FLOAT) && ent->v.waterlevel > 0) { - float waterLevel = (float)(SV_Submerged(ent) * ent->v.skin * host_frametime); + float buoyancy = SV_Submerged(ent) * ent->v.skin * host_frametime; + SV_AddGravity(ent); - ent->v.velocity[2] += waterLevel; + ent->v.velocity[2] += buoyancy; } - if (!wasonground) + + // add gravity except: + // flying monsters + // swimming monsters who are in the water + if (!wasonground && !(ent->v.flags & FL_FLY) && (!(ent->v.flags & FL_SWIM) || ent->v.waterlevel <= 0)) { - if (!(ent->v.flags & FL_FLY)) - { - if (!(ent->v.flags & FL_SWIM) || ent->v.waterlevel <= 0) - { - if (!inwater) - SV_AddGravity(ent); - } - } + if (!inwater) + SV_AddGravity(ent); } - if (VectorCompare(ent->v.velocity, vec_origin) && VectorCompare(ent->v.basevelocity, vec_origin)) - { - if (gGlobalVariables.force_retouch != 0.0) - { - trace_t trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent, (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0); - if (trace.fraction < 1.0 || trace.startsolid) - { - if (trace.ent) - SV_Impact(ent, trace.ent, &trace); - } - } - } - else + + if (!VectorIsZero(ent->v.velocity) || !VectorIsZero(ent->v.basevelocity)) { ent->v.flags &= ~FL_ONGROUND; - if (wasonground && (ent->v.health > 0.0 || SV_CheckBottom(ent))) + + // apply friction + // let dead monsters who aren't completely onground slide + if (wasonground && (ent->v.health > 0.0f || SV_CheckBottom(ent))) { - float speed = (float)Q_sqrt((long double)(ent->v.velocity[0] * ent->v.velocity[0] + ent->v.velocity[1] * ent->v.velocity[1])); - if (speed != 0.0) + float speed = Q_sqrt((double)(ent->v.velocity[0] * ent->v.velocity[0] + ent->v.velocity[1] * ent->v.velocity[1])); + if (speed) { float friction = sv_friction.value * ent->v.friction; ent->v.friction = 1.0f; - float control = (speed >= sv_stopspeed.value) ? speed : sv_stopspeed.value; - float newspeed = (float)(speed - control * friction * host_frametime); - if (newspeed < 0.0) - newspeed = 0.0; + float control = (speed < sv_stopspeed.value) ? sv_stopspeed.value : speed; + float newspeed = speed - (host_frametime * control * friction); + if (newspeed < 0.0f) + newspeed = 0.0f; + newspeed = newspeed / speed; ent->v.velocity[0] *= newspeed; ent->v.velocity[1] *= newspeed; } } - ent->v.velocity[0] += ent->v.basevelocity[0]; - ent->v.velocity[1] += ent->v.basevelocity[1]; - ent->v.velocity[2] += ent->v.basevelocity[2]; - SV_CheckVelocity(ent); - SV_FlyMove(ent, (float)host_frametime, 0); - SV_CheckVelocity(ent); - ent->v.velocity[0] -= ent->v.basevelocity[0]; - ent->v.velocity[1] -= ent->v.basevelocity[1]; - ent->v.velocity[2] -= ent->v.basevelocity[2]; - SV_CheckVelocity(ent); - mins[0] = ent->v.mins[0] + ent->v.origin[0]; - mins[1] = ent->v.mins[1] + ent->v.origin[1]; - mins[2] = ent->v.mins[2] + ent->v.origin[2]; - maxs[0] = ent->v.maxs[0] + ent->v.origin[0]; - maxs[1] = ent->v.maxs[1] + ent->v.origin[1]; - point[2] = mins[2] - 1.0f; - for (int x = 0; x <= 1; x++) + VectorAdd(ent->v.velocity, ent->v.basevelocity, ent->v.velocity); + SV_CheckVelocity(ent); + + SV_FlyMove(ent, host_frametime, nullptr); + SV_CheckVelocity(ent); + + VectorSubtract(ent->v.velocity, ent->v.basevelocity, ent->v.velocity); + SV_CheckVelocity(ent); + + // determine if it's on solid ground at all { - for (int y = 0; y <= 1; y++) + int x, y; + vec3_t point, mins, maxs; + + VectorAdd(ent->v.origin, ent->v.mins, mins); + VectorAdd(ent->v.origin, ent->v.maxs, maxs); + + point[2] = mins[2] - 1.0f; + + for (x = 0; x <= 1; x++) { - point[0] = x ? (maxs[0]) : (mins[0]); - point[1] = y ? (maxs[1]) : (mins[1]); - g_groupmask = ent->v.groupinfo; - if (SV_PointContents(point) == -2) + for (y = 0; y <= 1; y++) { - ent->v.flags |= FL_ONGROUND; - break; + point[0] = x ? maxs[0] : mins[0]; + point[1] = y ? maxs[1] : mins[1]; + + g_groupmask = ent->v.groupinfo; + + if (SV_PointContents(point) == CONTENTS_SOLID) + { + ent->v.flags |= FL_ONGROUND; + break; + } } } - }; + } + SV_LinkEdict(ent, TRUE); } + else + { + if (gGlobalVariables.force_retouch != 0.0f) + { + trace_t trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent, (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE); + + // hentacle impact code + if ((trace.fraction < 1.0f || trace.startsolid) && trace.ent) + { + SV_Impact(ent, trace.ent, &trace); + } + } + } + + // regular thinking SV_RunThink(ent); SV_CheckWaterTransition(ent); } -void SV_Physics(void) +void SV_Physics() { - gGlobalVariables.time = (float)g_psv.time; + // let the progs know that a new frame has started + gGlobalVariables.time = g_psv.time; gEntityInterface.pfnStartFrame(); + + // treat each object in turn for (int i = 0; i < g_psv.num_edicts; i++) { - edict_t* ent = &g_psv.edicts[i]; + edict_t *ent = &g_psv.edicts[i]; if (ent->free) continue; - if (gGlobalVariables.force_retouch != 0.0) + if (gGlobalVariables.force_retouch != 0.0f) + { + // force retouch even for stationary SV_LinkEdict(ent, TRUE); + } if (i > 0 && i <= g_psvs.maxclients) continue; if (ent->v.flags & FL_ONGROUND) { - edict_t* groundentity = ent->v.groundentity; - if (groundentity) + edict_t *groundentity = ent->v.groundentity; + if (groundentity && (groundentity->v.flags & FL_CONVEYOR)) { - if (groundentity->v.flags & FL_CONVEYOR) - { - if (ent->v.flags & FL_BASEVELOCITY) - VectorMA(ent->v.basevelocity, groundentity->v.speed, groundentity->v.movedir, ent->v.basevelocity); - else - VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity); - ent->v.flags |= FL_BASEVELOCITY; - } + if (ent->v.flags & FL_BASEVELOCITY) + VectorMA(ent->v.basevelocity, groundentity->v.speed, groundentity->v.movedir, ent->v.basevelocity); + else + VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity); + + ent->v.flags |= FL_BASEVELOCITY; } } + if (!(ent->v.flags & FL_BASEVELOCITY)) { - VectorMA(ent->v.velocity, (float)(host_frametime * 0.5 + 1.0), ent->v.basevelocity, ent->v.velocity); - ent->v.basevelocity[0] = vec3_origin[0]; - ent->v.basevelocity[1] = vec3_origin[1]; - ent->v.basevelocity[2] = vec3_origin[2]; + // Apply momentum (add in half of the previous frame of velocity first) + VectorMA(ent->v.velocity, (host_frametime * 0.5f + 1.0f), ent->v.basevelocity, ent->v.velocity); + VectorClear(ent->v.basevelocity); } + ent->v.flags &= ~FL_BASEVELOCITY; switch (ent->v.movetype) @@ -1365,24 +1450,19 @@ void SV_Physics(void) case MOVETYPE_NONE: SV_Physics_None(ent); break; - case MOVETYPE_PUSH: SV_Physics_Pusher(ent); break; - case MOVETYPE_FOLLOW: SV_Physics_Follow(ent); break; - case MOVETYPE_NOCLIP: SV_Physics_Noclip(ent); break; - case MOVETYPE_STEP: case MOVETYPE_PUSHSTEP: SV_Physics_Step(ent); break; - case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: case MOVETYPE_BOUNCEMISSILE: @@ -1390,7 +1470,6 @@ void SV_Physics(void) case MOVETYPE_FLYMISSILE: SV_Physics_Toss(ent); break; - default: Sys_Error("%s: %s bad movetype %d", __func__, &pr_strings[ent->v.classname], ent->v.movetype); } @@ -1405,34 +1484,29 @@ void SV_Physics(void) trace_t SV_Trace_Toss(edict_t *ent, edict_t *ignore) { - edict_t tempent; + edict_t *tent, tempent; trace_t trace; vec3_t move; vec3_t end; double save_frametime; save_frametime = host_frametime; - host_frametime = 5.0; + host_frametime = 5.0f; + Q_memcpy(&tempent, ent, sizeof(tempent)); + tent = &tempent; + do { - do - { - SV_CheckVelocity(&tempent); - SV_AddGravity(&tempent); - VectorMA(tempent.v.angles, (float)host_frametime, tempent.v.avelocity, tempent.v.angles); - VectorScale(tempent.v.velocity, (float)host_frametime, move); - end[0] = tempent.v.origin[0] + move[0]; - end[1] = tempent.v.origin[1] + move[1]; - end[2] = tempent.v.origin[2] + move[2]; - trace = SV_Move(tempent.v.origin, tempent.v.mins, tempent.v.maxs, end, 0, &tempent, 0); - tempent.v.origin[1] = trace.endpos[1]; - tempent.v.origin[0] = trace.endpos[0]; - tempent.v.origin[2] = trace.endpos[2]; - } - while (!trace.ent); + SV_CheckVelocity(tent); + SV_AddGravity(tent); + VectorMA(tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles); + VectorScale(tent->v.velocity, host_frametime, move); + VectorAdd(tent->v.origin, move, end); + trace = SV_Move(tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent, FALSE); + VectorCopy(trace.endpos, tent->v.origin); } - while (trace.ent == ignore); + while (!trace.ent || trace.ent == ignore); host_frametime = save_frametime; return trace; diff --git a/rehlds/engine/sv_phys.h b/rehlds/engine/sv_phys.h index 9ba3a67..4ac0e7f 100644 --- a/rehlds/engine/sv_phys.h +++ b/rehlds/engine/sv_phys.h @@ -32,7 +32,6 @@ #include "model.h" #include "cvar.h" - #ifdef HOOK_ENGINE #define sv_maxvelocity (*psv_maxvelocity) #define sv_gravity (*psv_gravity) @@ -54,8 +53,7 @@ extern cvar_t sv_stopspeed; extern vec3_t *g_moved_from; extern edict_t **g_moved_edict; - -NOXREF void SV_CheckAllEnts(void); +NOXREF void SV_CheckAllEnts(); void SV_CheckVelocity(edict_t *ent); qboolean SV_RunThink(edict_t *ent); void SV_Impact(edict_t *e1, edict_t *e2, trace_t *ptrace); @@ -69,7 +67,7 @@ void SV_PushMove(edict_t *pusher, float movetime); int SV_PushRotate(edict_t *pusher, float movetime); void SV_Physics_Pusher(edict_t *ent); qboolean SV_CheckWater(edict_t *ent); -float SV_RecursiveWaterLevel(vec_t *center, float out, float in, int count); +float SV_RecursiveWaterLevel(const vec_t *origin, float mins, float maxs, int depth); float SV_Submerged(edict_t *ent); void SV_Physics_None(edict_t *ent); void SV_Physics_Follow(edict_t *ent); diff --git a/rehlds/engine/sv_user.cpp b/rehlds/engine/sv_user.cpp index c07197e..18ffa41 100644 --- a/rehlds/engine/sv_user.cpp +++ b/rehlds/engine/sv_user.cpp @@ -396,8 +396,10 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) pe->origin[0] = check->v.origin[0]; pe->origin[1] = check->v.origin[1]; - pe->info = e; pe->origin[2] = check->v.origin[2]; + + pe->info = e; + if (e < 1 || e > g_psvs.maxclients) { pe->player = 0; @@ -411,30 +413,32 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) pe->angles[0] = check->v.angles[0]; pe->angles[1] = check->v.angles[1]; pe->angles[2] = check->v.angles[2]; - pe->studiomodel = 0; + + pe->studiomodel = nullptr; pe->rendermode = check->v.rendermode; + if (check->v.solid == SOLID_BSP) { pe->model = g_psv.models[check->v.modelindex]; - Q_strncpy(pe->name, pe->model->name, 0x20u); - pe->name[31] = 0; + Q_strncpy(pe->name, pe->model->name, sizeof(pe->name) - 1); + pe->name[sizeof(pe->name) - 1] = 0; } else if (check->v.solid == SOLID_NOT) { if (check->v.modelindex) { pe->model = g_psv.models[check->v.modelindex]; - Q_strncpy(pe->name, pe->model->name, 0x20u); - pe->name[31] = 0; + Q_strncpy(pe->name, pe->model->name, sizeof(pe->name) - 1); + pe->name[sizeof(pe->name) - 1] = 0; } else { - pe->model = 0; + pe->model = nullptr; } } else { - pe->model = NULL; + pe->model = nullptr; if (check->v.solid != SOLID_BBOX) { pe->mins[0] = check->v.mins[0]; @@ -443,10 +447,11 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) pe->mins[2] = check->v.mins[2]; pe->maxs[1] = check->v.maxs[1]; pe->maxs[2] = check->v.maxs[2]; + if (check->v.classname) { - Q_strncpy(pe->name, &pr_strings[check->v.classname], 0x20u); - pe->name[31] = 0; + Q_strncpy(pe->name, &pr_strings[check->v.classname], sizeof(pe->name) - 1); + pe->name[sizeof(pe->name) - 1] = 0; } else { @@ -460,13 +465,14 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) pModel = g_psv.models[check->v.modelindex]; if (pModel) { - if (pModel->flags & 0x200) + if (pModel->flags & STUDIO_TRACE_HITBOX) pe->studiomodel = pModel; - Q_strncpy(pe->name, pModel->name, 0x20u); - pe->name[31] = 0; + Q_strncpy(pe->name, pModel->name, sizeof(pe->name) - 1); + pe->name[sizeof(pe->name) - 1] = 0; } } + pe->mins[0] = check->v.mins[0]; pe->mins[1] = check->v.mins[1]; pe->mins[2] = check->v.mins[2]; @@ -475,13 +481,16 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) pe->maxs[2] = check->v.maxs[2]; } } + pe->skin = check->v.skin; pe->frame = check->v.frame; pe->solid = check->v.solid; pe->sequence = check->v.sequence; - Q_memcpy(pe->controller, check->v.controller, 4); - Q_memcpy(pe->blending, check->v.blending, 2); pe->movetype = check->v.movetype; + + Q_memcpy(&pe->controller[0], &check->v.controller[0], 4 * sizeof(byte)); + Q_memcpy(&pe->blending[0], &check->v.blending[0], 2 * sizeof(byte)); + pe->iuser1 = check->v.iuser1; pe->iuser2 = check->v.iuser2; pe->iuser3 = check->v.iuser3; @@ -490,6 +499,7 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) pe->fuser2 = check->v.fuser2; pe->fuser3 = check->v.fuser3; pe->fuser4 = check->v.fuser4; + pe->vuser1[0] = check->v.vuser1[0]; pe->vuser1[1] = check->v.vuser1[1]; pe->vuser1[2] = check->v.vuser1[2]; @@ -499,8 +509,10 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) pe->vuser3[0] = check->v.vuser3[0]; pe->vuser3[1] = check->v.vuser3[1]; pe->vuser3[2] = check->v.vuser3[2]; + pe->takedamage = 0; pe->blooddecal = 0; + pe->vuser4[0] = check->v.vuser4[0]; pe->vuser4[1] = check->v.vuser4[1]; pe->vuser4[2] = check->v.vuser4[2]; @@ -619,8 +631,8 @@ void SV_AddLinksToPM(areanode_t *node, vec_t *origin) pmove->physents[0].model = g_psv.worldmodel; if (g_psv.worldmodel != NULL) { - Q_strncpy(pmove->physents[0].name, g_psv.worldmodel->name, 0x20u); - pmove->physents[0].name[31] = 0; + Q_strncpy(pmove->physents[0].name, g_psv.worldmodel->name, sizeof(pmove->physents[0].name) - 1); + pmove->physents[0].name[sizeof(pmove->physents[0].name) - 1] = 0; } pmove->physents[0].origin[0] = vec3_origin[0]; pmove->physents[0].origin[1] = vec3_origin[1]; @@ -813,50 +825,62 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed) sv_player->v.clbasevelocity[1] = sv_player->v.basevelocity[1]; sv_player->v.clbasevelocity[2] = sv_player->v.basevelocity[2]; } - pmove->server = 1; - pmove->multiplayer = (qboolean)(g_psvs.maxclients > 1); + + pmove->server = TRUE; + pmove->multiplayer = (g_psvs.maxclients > 1) ? TRUE : FALSE; pmove->time = float(1000.0 * host_client->svtimebase); - pmove->usehull = (sv_player->v.flags & 0x4000) != 0; + pmove->usehull = (sv_player->v.flags & FL_DUCKING) == FL_DUCKING; pmove->maxspeed = sv_maxspeed.value; pmove->clientmaxspeed = sv_player->v.maxspeed; - pmove->flDuckTime = (float) sv_player->v.flDuckTime; + pmove->flDuckTime = (float)sv_player->v.flDuckTime; pmove->bInDuck = sv_player->v.bInDuck; pmove->flTimeStepSound = sv_player->v.flTimeStepSound; pmove->iStepLeft = sv_player->v.iStepLeft; pmove->flFallVelocity = sv_player->v.flFallVelocity; pmove->flSwimTime = (float)sv_player->v.flSwimTime; pmove->oldbuttons = sv_player->v.oldbuttons; - Q_strncpy(pmove->physinfo, host_client->physinfo, 0xFFu); - pmove->physinfo[255] = 0; + + Q_strncpy(pmove->physinfo, host_client->physinfo, sizeof(pmove->physinfo) - 1); + pmove->physinfo[sizeof(pmove->physinfo) - 1] = 0; + pmove->velocity[0] = sv_player->v.velocity[0]; pmove->velocity[1] = sv_player->v.velocity[1]; pmove->velocity[2] = sv_player->v.velocity[2]; + pmove->movedir[0] = sv_player->v.movedir[0]; pmove->movedir[1] = sv_player->v.movedir[1]; pmove->movedir[2] = sv_player->v.movedir[2]; + pmove->angles[0] = sv_player->v.v_angle[0]; pmove->angles[1] = sv_player->v.v_angle[1]; pmove->angles[2] = sv_player->v.v_angle[2]; + pmove->basevelocity[0] = sv_player->v.basevelocity[0]; pmove->basevelocity[1] = sv_player->v.basevelocity[1]; pmove->basevelocity[2] = sv_player->v.basevelocity[2]; + pmove->view_ofs[0] = sv_player->v.view_ofs[0]; pmove->view_ofs[1] = sv_player->v.view_ofs[1]; pmove->view_ofs[2] = sv_player->v.view_ofs[2]; + pmove->punchangle[0] = sv_player->v.punchangle[0]; pmove->punchangle[1] = sv_player->v.punchangle[1]; pmove->punchangle[2] = sv_player->v.punchangle[2]; + pmove->deadflag = sv_player->v.deadflag; pmove->effects = sv_player->v.effects; pmove->gravity = sv_player->v.gravity; pmove->friction = sv_player->v.friction; pmove->spectator = 0; pmove->waterjumptime = sv_player->v.teleport_time; + Q_memcpy(&pmove->cmd, &cmd, sizeof(pmove->cmd)); + pmove->dead = sv_player->v.health <= 0.0; pmove->movetype = sv_player->v.movetype; pmove->flags = sv_player->v.flags; pmove->player_index = NUM_FOR_EDICT(sv_player) - 1; + pmove->iuser1 = sv_player->v.iuser1; pmove->iuser2 = sv_player->v.iuser2; pmove->iuser3 = sv_player->v.iuser3; @@ -865,28 +889,37 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed) pmove->fuser2 = sv_player->v.fuser2; pmove->fuser3 = sv_player->v.fuser3; pmove->fuser4 = sv_player->v.fuser4; + pmove->vuser1[0] = sv_player->v.vuser1[0]; pmove->vuser1[1] = sv_player->v.vuser1[1]; pmove->vuser1[2] = sv_player->v.vuser1[2]; + pmove->vuser2[0] = sv_player->v.vuser2[0]; pmove->vuser2[1] = sv_player->v.vuser2[1]; pmove->vuser2[2] = sv_player->v.vuser2[2]; + pmove->vuser3[0] = sv_player->v.vuser3[0]; pmove->vuser3[1] = sv_player->v.vuser3[1]; pmove->vuser3[2] = sv_player->v.vuser3[2]; + pmove->vuser4[0] = sv_player->v.vuser4[0]; pmove->vuser4[1] = sv_player->v.vuser4[1]; pmove->vuser4[2] = sv_player->v.vuser4[2]; + pmove->origin[0] = sv_player->v.origin[0]; pmove->origin[1] = sv_player->v.origin[1]; pmove->origin[2] = sv_player->v.origin[2]; + SV_AddLinksToPM(sv_areanodes, pmove->origin); + pmove->frametime = frametime; - pmove->runfuncs = 1; + pmove->runfuncs = TRUE; pmove->PM_PlaySound = PM_SV_PlaySound; pmove->PM_TraceTexture = PM_SV_TraceTexture; pmove->PM_PlaybackEventFull = PM_SV_PlaybackEventFull; - gEntityInterface.pfnPM_Move(pmove, 1); + + gEntityInterface.pfnPM_Move(pmove, TRUE); + sv_player->v.deadflag = pmove->deadflag; sv_player->v.effects = pmove->effects; sv_player->v.teleport_time = pmove->waterjumptime; @@ -897,15 +930,19 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed) sv_player->v.movetype = pmove->movetype; sv_player->v.maxspeed = pmove->clientmaxspeed; sv_player->v.iStepLeft = pmove->iStepLeft; + sv_player->v.view_ofs[0] = pmove->view_ofs[0]; sv_player->v.view_ofs[1] = pmove->view_ofs[1]; sv_player->v.view_ofs[2] = pmove->view_ofs[2]; + sv_player->v.movedir[0] = pmove->movedir[0]; sv_player->v.movedir[1] = pmove->movedir[1]; sv_player->v.movedir[2] = pmove->movedir[2]; + sv_player->v.punchangle[0] = pmove->punchangle[0]; sv_player->v.punchangle[1] = pmove->punchangle[1]; sv_player->v.punchangle[2] = pmove->punchangle[2]; + if (pmove->onground == -1) { sv_player->v.flags &= ~FL_ONGROUND; @@ -915,15 +952,19 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed) sv_player->v.flags |= FL_ONGROUND; sv_player->v.groundentity = EDICT_NUM(pmove->physents[pmove->onground].info); } + sv_player->v.origin[0] = pmove->origin[0]; sv_player->v.origin[1] = pmove->origin[1]; sv_player->v.origin[2] = pmove->origin[2]; + sv_player->v.velocity[0] = pmove->velocity[0]; sv_player->v.velocity[1] = pmove->velocity[1]; sv_player->v.velocity[2] = pmove->velocity[2]; + sv_player->v.basevelocity[0] = pmove->basevelocity[0]; sv_player->v.basevelocity[1] = pmove->basevelocity[1]; sv_player->v.basevelocity[2] = pmove->basevelocity[2]; + if (!sv_player->v.fixangle) { sv_player->v.v_angle[0] = pmove->angles[0]; @@ -933,12 +974,14 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed) sv_player->v.angles[1] = pmove->angles[1]; sv_player->v.angles[2] = pmove->angles[2]; } + sv_player->v.bInDuck = pmove->bInDuck; sv_player->v.flDuckTime = (int)pmove->flDuckTime; sv_player->v.flTimeStepSound = pmove->flTimeStepSound; sv_player->v.flFallVelocity = pmove->flFallVelocity; sv_player->v.flSwimTime = (int)pmove->flSwimTime; sv_player->v.oldbuttons = pmove->cmd.buttons; + sv_player->v.iuser1 = pmove->iuser1; sv_player->v.iuser2 = pmove->iuser2; sv_player->v.iuser3 = pmove->iuser3; @@ -947,18 +990,23 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed) sv_player->v.fuser2 = pmove->fuser2; sv_player->v.fuser3 = pmove->fuser3; sv_player->v.fuser4 = pmove->fuser4; + sv_player->v.vuser1[0] = pmove->vuser1[0]; sv_player->v.vuser1[1] = pmove->vuser1[1]; sv_player->v.vuser1[2] = pmove->vuser1[2]; + sv_player->v.vuser2[0] = pmove->vuser2[0]; sv_player->v.vuser2[1] = pmove->vuser2[1]; sv_player->v.vuser2[2] = pmove->vuser2[2]; + sv_player->v.vuser3[0] = pmove->vuser3[0]; sv_player->v.vuser3[1] = pmove->vuser3[1]; sv_player->v.vuser3[2] = pmove->vuser3[2]; + sv_player->v.vuser4[0] = pmove->vuser4[0]; sv_player->v.vuser4[1] = pmove->vuser4[1]; sv_player->v.vuser4[2] = pmove->vuser4[2]; + SetMinMaxSize(sv_player, player_mins[pmove->usehull], player_maxs[pmove->usehull], 0); if (host_client->edict->v.solid) { @@ -982,6 +1030,7 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed) sv_player->v.velocity[1] = vel[1]; sv_player->v.velocity[2] = vel[2]; } + gGlobalVariables.time = (float)host_client->svtimebase; gGlobalVariables.frametime = frametime; gEntityInterface.pfnPlayerPostThink(sv_player); diff --git a/rehlds/engine/textures.cpp b/rehlds/engine/textures.cpp index 3c8708d..022e7e3 100644 --- a/rehlds/engine/textures.cpp +++ b/rehlds/engine/textures.cpp @@ -214,8 +214,8 @@ void TEX_AddAnimatingTextures(void) if (miptex[i][0] != '+' && miptex[i][0] != '-') continue; - Q_strncpy(name, miptex[i], 0x1Fu); - name[31] = 0; + Q_strncpy(name, miptex[i], sizeof(name) - 1); + name[sizeof(name) - 1] = 0; for (int j = 0; j < 20; j++) { diff --git a/rehlds/engine/world.cpp b/rehlds/engine/world.cpp index 5ad4eb3..07337c5 100644 --- a/rehlds/engine/world.cpp +++ b/rehlds/engine/world.cpp @@ -30,23 +30,26 @@ hull_t box_hull; hull_t beam_hull; + box_clipnodes_t box_clipnodes; box_planes_t box_planes; beam_planes_t beam_planes; areanode_t sv_areanodes[32]; int sv_numareanodes; + #ifdef REHLDS_FIXES -static link_t *touchLinksNext = NULL; +static link_t *touchLinksNext = nullptr; #endif // REHLDS_FIXES cvar_t sv_force_ent_intersection = { "sv_force_ent_intersection", "0", 0, 0.0f, NULL }; +// ClearLink is used for new headnodes void ClearLink(link_t *l) { - l->next = l; - l->prev = l; + l->next = l->prev = l; } +// Remove link from chain void RemoveLink(link_t *l) { #ifdef REHLDS_FIXES @@ -55,16 +58,19 @@ void RemoveLink(link_t *l) touchLinksNext = l->next; } #endif // REHLDS_FIXES + l->next->prev = l->prev; l->prev->next = l->next; } +// Kept trigger and solid entities seperate void InsertLinkBefore(link_t *l, link_t *before) { l->next = before; l->prev = before->prev; l->next->prev = l; l->prev->next = l; + #ifdef REHLDS_FIXES if (touchLinksNext == before) { @@ -76,6 +82,7 @@ void InsertLinkBefore(link_t *l, link_t *before) NOXREF void InsertLinkAfter(link_t *l, link_t *after) { NOXREFCHECK; + l->prev = after; l->next = after->next; @@ -83,14 +90,17 @@ NOXREF void InsertLinkAfter(link_t *l, link_t *after) l->next->prev = l; } -void SV_InitBoxHull(void) +// Set up the planes and clipnodes so that the six floats of a bounding box +// can just be stored out and get a proper hull_t structure. +void SV_InitBoxHull() { - box_hull.clipnodes = &box_clipnodes[0]; - box_hull.planes = &box_planes[0]; + box_hull.clipnodes = box_clipnodes; + box_hull.planes = box_planes; box_hull.firstclipnode = 0; box_hull.lastclipnode = 5; + Q_memcpy(&beam_hull, &box_hull, sizeof(beam_hull)); - beam_hull.planes = &beam_planes[0]; + beam_hull.planes = beam_planes; for (int i = 0; i < 6; i++) { @@ -98,12 +108,15 @@ void SV_InitBoxHull(void) box_clipnodes[i].planenum = i; box_clipnodes[i].children[side] = CONTENTS_EMPTY; box_clipnodes[i].children[side ^ 1] = (i != 5) ? i + 1 : CONTENTS_SOLID; + box_planes[i].type = i >> 1; - beam_planes[i].type = 5; box_planes[i].normal[i >> 1] = 1.0f; + beam_planes[i].type = 5; } } +// To keep everything totally uniform, bounding boxes are turned into small +// BSP trees instead of being compared directly. hull_t *SV_HullForBox(const vec_t *mins, const vec_t *maxs) { box_planes[0].dist = maxs[0]; @@ -112,6 +125,7 @@ hull_t *SV_HullForBox(const vec_t *mins, const vec_t *maxs) box_planes[3].dist = mins[1]; box_planes[4].dist = maxs[2]; box_planes[5].dist = mins[2]; + return &box_hull; } @@ -120,18 +134,12 @@ NOXREF hull_t *SV_HullForBeam(const vec_t *start, const vec_t *end, const vec_t NOXREFCHECK; vec3_t tmp = { 0, 0, 0 }; - beam_planes[0].normal[0] = end[0] - start[0]; - beam_planes[0].normal[1] = end[1] - start[1]; - beam_planes[0].normal[2] = end[2] - start[2]; - + VectorSubtract(end, start, beam_planes[0].normal); VectorNormalize(beam_planes[0].normal); + VectorCopy(beam_planes[0].normal, beam_planes[1].normal); - beam_planes[1].normal[0] = beam_planes[0].normal[0]; - beam_planes[1].normal[1] = beam_planes[0].normal[1]; - beam_planes[1].normal[2] = beam_planes[0].normal[2]; - - beam_planes[0].dist = _DotProduct((vec_t *)end, beam_planes[0].normal); - beam_planes[1].dist = _DotProduct((vec_t *)start, beam_planes[0].normal); + beam_planes[0].dist = _DotProduct(end, beam_planes[0].normal); + beam_planes[1].dist = _DotProduct(start, beam_planes[0].normal); if (fabs(beam_planes[0].normal[2]) < 0.9f) tmp[2] = 1.0f; @@ -140,89 +148,78 @@ NOXREF hull_t *SV_HullForBeam(const vec_t *start, const vec_t *end, const vec_t CrossProduct(beam_planes[0].normal, tmp, beam_planes[2].normal); VectorNormalize(beam_planes[2].normal); - - beam_planes[3].normal[0] = beam_planes[2].normal[0]; - beam_planes[3].normal[1] = beam_planes[2].normal[1]; - beam_planes[3].normal[2] = beam_planes[2].normal[2]; + VectorCopy(beam_planes[2].normal, beam_planes[3].normal); beam_planes[2].dist = (start[0] + beam_planes[2].normal[0]) * beam_planes[2].normal[0] + (start[1] + beam_planes[2].normal[1]) * beam_planes[2].normal[1] + (start[2] + beam_planes[2].normal[2]) * beam_planes[2].normal[2]; - tmp[0] = start[0] - beam_planes[2].normal[0]; - tmp[1] = start[1] - beam_planes[2].normal[1]; - tmp[2] = start[2] - beam_planes[2].normal[2]; + VectorSubtract(start, beam_planes[2].normal, tmp); beam_planes[3].dist = _DotProduct(tmp, beam_planes[2].normal); CrossProduct(beam_planes[2].normal, beam_planes[0].normal, beam_planes[4].normal); VectorNormalize(beam_planes[4].normal); - beam_planes[5].normal[0] = beam_planes[4].normal[0]; - beam_planes[5].normal[1] = beam_planes[4].normal[1]; - beam_planes[5].normal[2] = beam_planes[4].normal[2]; + VectorCopy(beam_planes[4].normal, beam_planes[5].normal); - beam_planes[4].dist = _DotProduct((vec_t *)start, beam_planes[4].normal); + beam_planes[4].dist = _DotProduct(start, beam_planes[4].normal); beam_planes[5].dist = (start[0] - beam_planes[4].normal[0]) * beam_planes[4].normal[0] + (start[1] - beam_planes[4].normal[1]) * beam_planes[4].normal[1] + (start[2] - beam_planes[4].normal[2]) * beam_planes[4].normal[2]; - beam_planes[0].dist += fabs(beam_planes[0].normal[0] * size[0]) + fabs(beam_planes[0].normal[1] * size[1]) + fabs(beam_planes[0].normal[2] * size[2]); - beam_planes[1].dist -= (fabs(beam_planes[1].normal[0] * size[0]) + fabs(beam_planes[1].normal[1] * size[1]) + fabs(beam_planes[1].normal[2] * size[2])); + beam_planes[0].dist += fabs(beam_planes[0].normal[0] * size[0]) + fabs(beam_planes[0].normal[1] * size[1]) + fabs(beam_planes[0].normal[2] * size[2]); + beam_planes[1].dist -= fabs(beam_planes[1].normal[0] * size[0]) + fabs(beam_planes[1].normal[1] * size[1]) + fabs(beam_planes[1].normal[2] * size[2]); beam_planes[2].dist += fabs(beam_planes[2].normal[0] * size[0]) + fabs(beam_planes[2].normal[1] * size[1]) + fabs(beam_planes[2].normal[2] * size[2]); - beam_planes[3].dist -= (fabs(beam_planes[3].normal[0] * size[0]) + fabs(beam_planes[3].normal[1] * size[1]) + fabs(beam_planes[3].normal[2] * size[2])); + beam_planes[3].dist -= fabs(beam_planes[3].normal[0] * size[0]) + fabs(beam_planes[3].normal[1] * size[1]) + fabs(beam_planes[3].normal[2] * size[2]); beam_planes[4].dist += fabs(beam_planes[4].normal[0] * size[0]) + fabs(beam_planes[4].normal[1] * size[1]) + fabs(beam_planes[4].normal[2] * size[2]); - beam_planes[5].dist -= (fabs(beam_planes[4].normal[0] * size[0]) + fabs(beam_planes[4].normal[1] * size[1]) + fabs(beam_planes[4].normal[2] * size[2])); + beam_planes[5].dist -= fabs(beam_planes[4].normal[0] * size[0]) + fabs(beam_planes[4].normal[1] * size[1]) + fabs(beam_planes[4].normal[2] * size[2]); return &beam_hull; } -struct hull_s *SV_HullForBsp(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset) +// Forcing to select BSP hull +hull_t *SV_HullForBsp(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset) { - model_t *model; hull_t *hull; + model_t *model; + vec3_t size; model = Mod_Handle(ent->v.modelindex); if (!model || model->type != mod_brush) - Sys_Error("%s: Hit a %s with no model (%s)", __func__, &pr_strings[ent->v.classname], &pr_strings[ent->v.model]); - - float xSize = maxs[0] - mins[0]; - if (xSize > 8.0f) { - if (xSize > 36.0f) - { - hull = &model->hulls[2]; - } - else - { - float zSize = maxs[2] - mins[2]; - if (zSize > 36.0f) - hull = &model->hulls[1]; - else - hull = &model->hulls[3]; - } -#ifdef REHLDS_FIXES - if (sv_rehlds_hull_centering.value && mins[0] + maxs[0] == 0.0f) - offset[0] = 0.0f; - else - offset[0] = hull->clip_mins[0] - mins[0]; + Sys_Error("%s: Hit a %s with no model (%s)", __func__, &pr_strings[ent->v.classname], &pr_strings[ent->v.model]); + } - if (sv_rehlds_hull_centering.value && mins[1] + maxs[1] == 0.0f) - offset[1] = 0.0f; - else - offset[1] = hull->clip_mins[1] - mins[1]; -#else // REHLDS_FIXES - offset[0] = hull->clip_mins[0] - mins[0]; - offset[1] = hull->clip_mins[1] - mins[1]; -#endif // REHLDS_FIXES - offset[2] = hull->clip_mins[2] - mins[2]; + VectorSubtract(maxs, mins, size); + + if (size[0] <= 8.0f) + { + hull = &model->hulls[0]; + VectorCopy(hull->clip_mins, offset); } else { - hull = &model->hulls[0]; - offset[0] = model->hulls[0].clip_mins[0]; - offset[1] = model->hulls[0].clip_mins[1]; - offset[2] = model->hulls[0].clip_mins[2]; + if (size[0] <= 36.0f) + { + if (size[2] <= 36.0f) + hull = &model->hulls[3]; + else + hull = &model->hulls[1]; + } + else + { + hull = &model->hulls[2]; + } + + // calculate an offset value to center the origin + VectorSubtract(hull->clip_mins, mins, offset); + +#ifdef REHLDS_FIXES + if (sv_rehlds_hull_centering.value && (mins[0] + maxs[0]) == 0.0f) + offset[0] = 0.0f; + + if (sv_rehlds_hull_centering.value && (mins[1] + maxs[1]) == 0.0f) + offset[1] = 0.0f; +#endif } - offset[0] = ent->v.origin[0] + offset[0]; - offset[1] = ent->v.origin[1] + offset[1]; - offset[2] = ent->v.origin[2] + offset[2]; + VectorAdd(offset, ent->v.origin, offset); return hull; } @@ -231,110 +228,111 @@ hull_t *SV_HullForEntity(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec vec3_t hullmins; vec3_t hullmaxs; + // decide which clipping hull to use, based on the size if (ent->v.solid == SOLID_BSP) { + // explicit hulls in the BSP model if (ent->v.movetype != MOVETYPE_PUSH && ent->v.movetype != MOVETYPE_PUSHSTEP) + { Sys_Error("%s: SOLID_BSP without MOVETYPE_PUSH", __func__); + } return SV_HullForBsp(ent, mins, maxs, offset); } - hullmins[0] = ent->v.mins[0] - maxs[0]; - hullmins[1] = ent->v.mins[1] - maxs[1]; - hullmins[2] = ent->v.mins[2] - maxs[2]; - hullmaxs[0] = ent->v.maxs[0] - mins[0]; - hullmaxs[1] = ent->v.maxs[1] - mins[1]; - hullmaxs[2] = ent->v.maxs[2] - mins[2]; - offset[0] = ent->v.origin[0]; - offset[1] = ent->v.origin[1]; - offset[2] = ent->v.origin[2]; + // create a temp hull from bounding box sizes + VectorSubtract(ent->v.mins, maxs, hullmins); + VectorSubtract(ent->v.maxs, mins, hullmaxs); + VectorCopy(ent->v.origin, offset); + return SV_HullForBox(hullmins, hullmaxs); } +// Builds a uniformly subdivided tree for the given world size areanode_t *SV_CreateAreaNode(int depth, vec_t *mins, vec_t *maxs) { areanode_t *anode; - vec3_t mins1; - vec3_t maxs2; vec3_t size; - vec3_t maxs1; - vec3_t mins2; - float fmid; + vec3_t mins1, maxs2, maxs1, mins2; anode = &sv_areanodes[sv_numareanodes++]; + ClearLink(&anode->trigger_edicts); ClearLink(&anode->solid_edicts); - if (depth == 4) + + if (depth == AREA_DEPTH) { anode->axis = -1; - anode->children[0] = NULL; - anode->children[1] = NULL; + anode->children[0] = anode->children[1] = nullptr; return anode; } - size[0] = maxs[0] - mins[0]; - size[1] = maxs[1] - mins[1]; - anode->axis = (size[0] <= size[1]) ? 1 : 0; - mins1[0] = mins[0]; - mins1[1] = mins[1]; - mins1[2] = mins[2]; + VectorSubtract(maxs, mins, size); - mins2[0] = mins[0]; - mins2[1] = mins[1]; - mins2[2] = mins[2]; + if (size[0] > size[1]) + anode->axis = 0; + else + anode->axis = 1; - maxs1[0] = maxs[0]; - maxs1[1] = maxs[1]; - maxs1[2] = maxs[2]; + anode->dist = 0.5f * (maxs[anode->axis] + mins[anode->axis]); - maxs2[0] = maxs[0]; - maxs2[1] = maxs[1]; - maxs2[2] = maxs[2]; + VectorCopy(mins, mins1); + VectorCopy(mins, mins2); + VectorCopy(maxs, maxs1); + VectorCopy(maxs, maxs2); - fmid = 0.5f * (mins[anode->axis] + maxs[anode->axis]); - mins2[anode->axis] = fmid; - maxs1[anode->axis] = fmid; + maxs1[anode->axis] = mins2[anode->axis] = anode->dist; - anode->dist = fmid; anode->children[0] = SV_CreateAreaNode(depth + 1, mins2, maxs2); anode->children[1] = SV_CreateAreaNode(depth + 1, mins1, maxs1); return anode; } -void SV_ClearWorld(void) +// called after the world model has been loaded, before linking any entities +void SV_ClearWorld() { SV_InitBoxHull(); + Q_memset(sv_areanodes, 0, sizeof(sv_areanodes)); sv_numareanodes = 0; SV_CreateAreaNode(0, g_psv.worldmodel->mins, g_psv.worldmodel->maxs); } +// call before removing an entity, and before trying to move one, +// so it doesn't clip against itself +// flags ent->v.modified void SV_UnlinkEdict(edict_t *ent) { - if (ent->area.prev) + if (!ent->area.prev) { - RemoveLink(&ent->area); - ent->area.next = NULL; - ent->area.prev = NULL; + // not linked in anywhere + return; } + + RemoveLink(&ent->area); + ent->area.prev = ent->area.next = nullptr; } void SV_TouchLinks(edict_t *ent, areanode_t *node) { + vec3_t localPosition, offset; edict_t *touch; + #ifndef REHLDS_FIXES link_t *touchLinksNext; #endif // REHLDS_FIXES + // touch linked edicts for (link_t *l = node->trigger_edicts.next; l != &node->trigger_edicts; l = touchLinksNext) { touchLinksNext = l->next; - touch = (edict_t *)((char *)l - offsetof(edict_t, area)); + touch = EDICT_FROM_AREA(l); + if (touch == ent) continue; - if (ent->v.groupinfo != 0 && touch->v.groupinfo != 0) + if (ent->v.groupinfo && touch->v.groupinfo) { if (g_groupop) { @@ -353,203 +351,169 @@ void SV_TouchLinks(edict_t *ent, areanode_t *node) continue; #endif // REHLDS_FIXES - if (touch->v.solid == SOLID_TRIGGER - && ent->v.absmin[0] <= touch->v.absmax[0] - && ent->v.absmin[1] <= touch->v.absmax[1] - && ent->v.absmin[2] <= touch->v.absmax[2] - && ent->v.absmax[0] >= touch->v.absmin[0] - && ent->v.absmax[1] >= touch->v.absmin[1] - && ent->v.absmax[2] >= touch->v.absmin[2]) + if (touch->v.solid != SOLID_TRIGGER) + continue; + + if (ent->v.absmin[0] > touch->v.absmax[0] + || ent->v.absmin[1] > touch->v.absmax[1] + || ent->v.absmin[2] > touch->v.absmax[2] + || ent->v.absmax[0] < touch->v.absmin[0] + || ent->v.absmax[1] < touch->v.absmin[1] + || ent->v.absmax[2] < touch->v.absmin[2]) + continue; + + // check brush triggers accuracy + if (Mod_GetType(touch->v.modelindex) == mod_brush) { - if (Mod_GetType(touch->v.modelindex) == mod_brush) - { - vec3_t offset; - hull_t *hull = SV_HullForBsp(touch, ent->v.mins, ent->v.maxs, offset); + // force to select bsp-hull + hull_t *hull = SV_HullForBsp(touch, ent->v.mins, ent->v.maxs, offset); - vec3_t localPosition; - localPosition[0] = ent->v.origin[0] - offset[0]; - localPosition[1] = ent->v.origin[1] - offset[1]; - localPosition[2] = ent->v.origin[2] - offset[2]; + // offset the test point appropriately for this hull + VectorSubtract(ent->v.origin, offset, localPosition); - int contents = SV_HullPointContents(hull, hull->firstclipnode, localPosition); - if (contents != CONTENTS_SOLID) - continue; - } - - gGlobalVariables.time = (float)g_psv.time; - gEntityInterface.pfnTouch(touch, ent); + // test hull for intersection with this model + if (SV_HullPointContents(hull, hull->firstclipnode, localPosition) != CONTENTS_SOLID) + continue; } + + gGlobalVariables.time = g_psv.time; + gEntityInterface.pfnTouch(touch, ent); } + #ifdef REHLDS_FIXES - touchLinksNext = NULL; + touchLinksNext = nullptr; #endif // REHLDS_FIXES - if (node->axis != -1) - { - if (ent->v.absmax[node->axis] > node->dist) - SV_TouchLinks(ent, node->children[0]); + // recurse down both sides + if(node->axis == -1) + return; - if (node->dist > ent->v.absmin[node->axis]) - SV_TouchLinks(ent, node->children[1]); - } + if (ent->v.absmax[node->axis] > node->dist) + SV_TouchLinks(ent, node->children[0]); + + if (node->dist > ent->v.absmin[node->axis]) + SV_TouchLinks(ent, node->children[1]); } #ifndef REHLDS_OPT_PEDANTIC + void SV_FindTouchedLeafs(edict_t *ent, mnode_t *node, int *topnode) { - mplane_t *splitplane; - int sides; - if (node->contents == CONTENTS_SOLID) return; + // add an efrag if the node is a leaf if (node->contents < 0) { - if (ent->num_leafs < MAX_ENT_LEAFS) + if (ent->num_leafs > (MAX_ENT_LEAFS - 1)) + { + // continue counting leafs, + // so we know how many it's overrun + ent->num_leafs = (MAX_ENT_LEAFS + 1); + } + else { mleaf_t *leaf = (mleaf_t *)node; int leafnum = leaf - g_psv.worldmodel->leafs - 1; ent->leafnums[ent->num_leafs] = leafnum; ent->num_leafs++; } - else - { - ent->num_leafs = MAX_ENT_LEAFS + 1; - } return; } - splitplane = node->plane; - if (splitplane->type >= 3) + // NODE_MIXED + mplane_t *splitplane = node->plane; + int sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane); + + if (sides == 3 && *topnode == -1) { - sides = BoxOnPlaneSide(ent->v.absmin, ent->v.absmax, splitplane); - } - else - { - if (splitplane->dist > ent->v.absmin[splitplane->type]) - { - if (splitplane->dist < ent->v.absmax[splitplane->type]) - { - sides = 3; - } - else - { - sides = 2; - } - } - else - { - sides = 1; - } + *topnode = node - g_psv.worldmodel->nodes; } - if (sides == 3) - { - if (*topnode == -1) - *topnode = node - g_psv.worldmodel->nodes; - } - - if (sides & 1) - SV_FindTouchedLeafs(ent, node->children[0], topnode); - - if (sides & 2) - SV_FindTouchedLeafs(ent, node->children[1], topnode); + if (sides & 1) SV_FindTouchedLeafs(ent, node->children[0], topnode); + if (sides & 2) SV_FindTouchedLeafs(ent, node->children[1], topnode); } + #else // REHLDS_OPT_PEDANTIC + // unrolled some tail recursion void SV_FindTouchedLeafs(edict_t *ent, mnode_t *node, int *topnode) { - mplane_t *splitplane; - int sides; - - while (1) + while (true) { + // if no collision model + if (!node) + return; + if (node->contents == CONTENTS_SOLID) return; + // add an efrag if the node is a leaf if (node->contents < 0) { - if (ent->num_leafs < MAX_ENT_LEAFS) + if (ent->num_leafs > (MAX_ENT_LEAFS - 1)) + { + // continue counting leafs, + // so we know how many it's overrun + ent->num_leafs = (MAX_ENT_LEAFS + 1); + } + else { mleaf_t *leaf = (mleaf_t *)node; int leafnum = leaf - g_psv.worldmodel->leafs - 1; ent->leafnums[ent->num_leafs] = leafnum; ent->num_leafs++; } - else - { - ent->num_leafs = MAX_ENT_LEAFS + 1; - } + return; } - splitplane = node->plane; - if (splitplane->type >= 3) + // NODE_MIXED + mplane_t *splitplane = node->plane; + int sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane); + + switch (sides) { - sides = BoxOnPlaneSide(ent->v.absmin, ent->v.absmax, splitplane); - - if (sides == 3) - { - if (*topnode == -1) - *topnode = node - g_psv.worldmodel->nodes; - } - - if (sides & 1) - SV_FindTouchedLeafs(ent, node->children[0], topnode); - - if (sides & 2) - SV_FindTouchedLeafs(ent, node->children[1], topnode); - } - else + case 1: node = node->children[0]; break; // do only SV_FindTouchedLeafs(ent, node->children[0], topnode); + case 2: node = node->children[1]; break; // do only SV_FindTouchedLeafs(ent, node->children[1], topnode); + case 3: { - if (splitplane->dist > ent->v.absmin[splitplane->type]) - { - if (splitplane->dist < ent->v.absmax[splitplane->type]) - { - // sides = 3; - // do both children nodes - if (*topnode == -1) - *topnode = node - g_psv.worldmodel->nodes; + if (*topnode == -1) + *topnode = node - g_psv.worldmodel->nodes; - SV_FindTouchedLeafs(ent, node->children[0], topnode); - node = node->children[1]; - continue; - } - else - { - // sides = 2; - // do only SV_FindTouchedLeafs(ent, node->children[1], topnode); - node = node->children[1]; - continue; - } - } - else - { - // sides = 1; - // do only SV_FindTouchedLeafs(ent, node->children[0], topnode); - node = node->children[0]; - continue; - } + // do both children nodes + SV_FindTouchedLeafs(ent, node->children[0], topnode); + node = node->children[1]; + break; + } + default: + return; } - - break; } } + #endif // REHLDS_OPT_PEDANTIC +// Needs to be called any time an entity changes origin, mins, maxs, or solid +// flags ent->v.modified +// sets ent->v.absmin and ent->v.absmax +// if touchtriggers, calls prog functions for the intersected triggers void SV_LinkEdict(edict_t *ent, qboolean touch_triggers) { - static int iTouchLinkSemaphore = 0; + static int iTouchLinkSemaphore = 0; // prevent recursion when SV_TouchLinks is active areanode_t *node; - int topnode; + // unlink from old position if (ent->area.prev) SV_UnlinkEdict(ent); + // don't add the world or free ents if (ent == &g_psv.edicts[0] || ent->free) return; + // set the abs box gEntityInterface.pfnSetAbsBox(ent); + if (ent->v.movetype == MOVETYPE_FOLLOW && ent->v.aiment) { ent->headnode = ent->v.aiment->headnode; @@ -558,20 +522,25 @@ void SV_LinkEdict(edict_t *ent, qboolean touch_triggers) } else { + int topnode = -1; + + // link to PVS leafs ent->num_leafs = 0; ent->headnode = -1; - topnode = -1; + if (ent->v.modelindex) SV_FindTouchedLeafs(ent, g_psv.worldmodel->nodes, &topnode); if (ent->num_leafs > MAX_ENT_LEAFS) { - ent->num_leafs = 0; - ent->headnode = (int)topnode; Q_memset(ent->leafnums, -1, sizeof(ent->leafnums)); + + ent->num_leafs = 0; // so we use headnode instead + ent->headnode = topnode; } } + // ignore non-solid bodies if (ent->v.solid == SOLID_NOT && ent->v.skin >= -1) return; @@ -581,67 +550,67 @@ void SV_LinkEdict(edict_t *ent, qboolean touch_triggers) return; } + // find the first node that the ent's box crosses node = sv_areanodes; while (true) { if (node->axis == -1) break; - if (ent->v.absmin[node->axis] <= node->dist) - { - if (ent->v.absmax[node->axis] >= node->dist) - break; - node = node->children[1]; - } - else - { + if (ent->v.absmin[node->axis] > node->dist) node = node->children[0]; - } + else if (ent->v.absmax[node->axis] < node->dist) + node = node->children[1]; + else break; // crosses the node } - InsertLinkBefore(&ent->area, (ent->v.solid == SOLID_TRIGGER) ? &node->trigger_edicts : &node->solid_edicts); - if (touch_triggers) + // link it in + if (ent->v.solid == SOLID_TRIGGER) + InsertLinkBefore(&ent->area, &node->trigger_edicts); + else + InsertLinkBefore(&ent->area, &node->solid_edicts); + + if (touch_triggers && !iTouchLinkSemaphore) { - if (!iTouchLinkSemaphore) - { - iTouchLinkSemaphore = 1; - SV_TouchLinks(ent, sv_areanodes); - iTouchLinkSemaphore = 0; - } + iTouchLinkSemaphore = 1; + SV_TouchLinks(ent, sv_areanodes); + iTouchLinkSemaphore = 0; } } int SV_HullPointContents(hull_t *hull, int num, const vec_t *p) { + float d; dclipnode_t *node; mplane_t *plane; - float d; - int i = num; - while (i >= 0) + while (num >= 0) { - if (hull->firstclipnode > i || hull->lastclipnode < i) + if (num < hull->firstclipnode || num > hull->lastclipnode) Sys_Error("%s: bad node number", __func__); - node = &hull->clipnodes[i]; + + node = &hull->clipnodes[num]; plane = &hull->planes[node->planenum]; - if (plane->type > 2) - d = _DotProduct(plane->normal, p) - plane->dist; - else + + if (plane->type < 3) d = p[plane->type] - plane->dist; - i = node->children[(d >= 0.0f) ? 0 : 1]; + else + d = _DotProduct(plane->normal, p) - plane->dist; + + if (d < 0) + num = node->children[1]; + else + num = node->children[0]; } - return i; + return num; } int SV_LinkContents(areanode_t *node, const vec_t *pos) { - link_t *l; - link_t *next; + vec3_t localPosition, offset; + link_t *next, *l; edict_t *touch; - hull_t *hull; - vec3_t localPosition; - vec3_t offset; #ifdef REHLDS_OPT_PEDANTIC // unroll tail recursion @@ -650,43 +619,50 @@ int SV_LinkContents(areanode_t *node, const vec_t *pos) { for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) { + touch = EDICT_FROM_AREA(l); next = l->next; - touch = (edict_t *)((char *)l - offsetof(edict_t, area)); - if (!touch->v.solid) - { - if (touch->v.groupinfo) - { - if (g_groupop) - { - if (g_groupop == GROUP_OP_NAND && (touch->v.groupinfo & g_groupmask)) - continue; - } - else - { - if (!(touch->v.groupinfo & g_groupmask)) - continue; - } - } - if (Mod_GetType(touch->v.modelindex) == mod_brush - && pos[0] <= (double)touch->v.absmax[0] - && pos[1] <= (double)touch->v.absmax[1] - && pos[2] <= (double)touch->v.absmax[2] - && pos[0] >= (double)touch->v.absmin[0] - && pos[1] >= (double)touch->v.absmin[1] - && pos[2] >= (double)touch->v.absmin[2]) + if (touch->v.solid != SOLID_NOT) + continue; + + if (touch->v.groupinfo) + { + if (g_groupop) { - int contents = touch->v.skin; - if (contents < -100 || contents > 100) - Con_DPrintf("Invalid contents on trigger field: %s\n", &pr_strings[touch->v.classname]); - hull = SV_HullForBsp(touch, vec3_origin, vec3_origin, offset); - localPosition[0] = pos[0] - offset[0]; - localPosition[1] = pos[1] - offset[1]; - localPosition[2] = pos[2] - offset[2]; - if (SV_HullPointContents(hull, hull->firstclipnode, localPosition) != CONTENTS_EMPTY) - return contents; + if (g_groupop == GROUP_OP_NAND && (touch->v.groupinfo & g_groupmask)) + continue; + } + else + { + if (!(touch->v.groupinfo & g_groupmask)) + continue; } } + + if (Mod_GetType(touch->v.modelindex) != mod_brush) + continue; + + if (pos[0] > touch->v.absmax[0] + || pos[1] > touch->v.absmax[1] + || pos[2] > touch->v.absmax[2] + || pos[0] < touch->v.absmin[0] + || pos[1] < touch->v.absmin[1] + || pos[2] < touch->v.absmin[2]) + continue; + + int contents = touch->v.skin; + if (contents < -100 || contents > 100) + Con_DPrintf("Invalid contents on trigger field: %s\n", &pr_strings[touch->v.classname]); + + // force to select bsp-hull + hull_t *hull = SV_HullForBsp(touch, vec3_origin, vec3_origin, offset); + + // offset the test point appropriately for this hull + VectorSubtract(pos, offset, localPosition); + + // test hull for intersection with this model + if (SV_HullPointContents(hull, hull->firstclipnode, localPosition) != CONTENTS_EMPTY) + return contents; } if (node->axis == -1) @@ -696,16 +672,17 @@ int SV_LinkContents(areanode_t *node, const vec_t *pos) if (pos[node->axis] > node->dist) return SV_LinkContents(node->children[0], pos); - if (pos[node->axis] < node->dist) + else if (pos[node->axis] < node->dist) return SV_LinkContents(node->children[1], pos); + #else // REHLDS_OPT_PEDANTIC + if (pos[node->axis] > node->dist) { node = node->children[0]; continue; } - - if (pos[node->axis] < node->dist) + else if (pos[node->axis] < node->dist) { node = node->children[1]; continue; @@ -718,12 +695,11 @@ int SV_LinkContents(areanode_t *node, const vec_t *pos) return CONTENTS_EMPTY; } +// Returns the CONTENTS_* value from the world at the given point. +// does not check any entities at all int SV_PointContents(const vec_t *p) { - int cont; - int entityContents; - - cont = SV_HullPointContents(g_psv.worldmodel->hulls, 0, p); + int cont = SV_HullPointContents(g_psv.worldmodel->hulls, 0, p); if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) { cont = CONTENTS_WATER; @@ -734,178 +710,178 @@ int SV_PointContents(const vec_t *p) return CONTENTS_SOLID; } - entityContents = SV_LinkContents(&sv_areanodes[0], p); + int entityContents = SV_LinkContents(&sv_areanodes[0], p); return (entityContents != CONTENTS_EMPTY) ? entityContents : cont; } +// Returns true if the entity is in solid currently edict_t *SV_TestEntityPosition(edict_t *ent) { - trace_t trace; - qboolean monsterClip; + qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE; + trace_t trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent, monsterClip); - monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE; - trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent, monsterClip); if (trace.startsolid) { SV_SetGlobalTrace(&trace); return trace.ent; } - return NULL; + return nullptr; } +const float DIST_EPSILON = 0.03125f; + #ifndef REHLDS_OPT_PEDANTIC qboolean SV_RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, const vec_t *p1, const vec_t *p2, trace_t *trace) { dclipnode_t *node; mplane_t *plane; - float t2; + float t1, t2; + float frac, midf, pointf; vec3_t mid; - float frac; - float t1; - signed int side; - float midf; + int side; float pdif = p2f - p1f; - float DIST_EPSILON = 0.03125f; - - if (num >= 0) + if (num < 0) { - if (num < hull->firstclipnode || num > hull->lastclipnode || !hull->planes) - Sys_Error("%s: bad node number", __func__); - - node = &hull->clipnodes[num]; - plane = &hull->planes[hull->clipnodes[num].planenum]; - if (plane->type >= 3) + if (num != CONTENTS_SOLID) { - t1 = _DotProduct(p1, plane->normal) - plane->dist; - t2 = _DotProduct(p2, plane->normal) - plane->dist; + trace->allsolid = FALSE; + + if (num == CONTENTS_EMPTY) + trace->inopen = TRUE; + + else if (num != CONTENTS_TRANSLUCENT) + trace->inwater = TRUE; } else { - t1 = p1[plane->type] - plane->dist; - t2 = p2[plane->type] - plane->dist; - } - if (t1 >= 0.0f && t2 >= 0.0f) - return SV_RecursiveHullCheck(hull, node->children[0], p1f, p2f, p1, p2, trace); - - if (t1 >= 0.0f) - { - midf = t1 - DIST_EPSILON; - } - else - { - if (t2 < 0.0f) - return SV_RecursiveHullCheck(hull, node->children[1], p1f, p2f, p1, p2, trace); - - midf = t1 + DIST_EPSILON; + trace->startsolid = TRUE; } - midf = midf / (t1 - t2); - if (midf >= 0.0f) - { - if (midf > 1.0f) - midf = 1.0f; - } - else - { - midf = 0.0f; - } - if (!IS_NAN(midf)) // not a number - { - frac = pdif * midf + p1f; - mid[0] = (p2[0] - p1[0]) * midf + p1[0]; - mid[1] = (p2[1] - p1[1]) * midf + p1[1]; - mid[2] = (p2[2] - p1[2]) * midf + p1[2]; - side = (t1 < 0.0f) ? 1 : 0; - if (SV_RecursiveHullCheck(hull, node->children[side], p1f, frac, p1, mid, trace)) - { - if (SV_HullPointContents(hull, node->children[side ^ 1], mid) != CONTENTS_SOLID) - return SV_RecursiveHullCheck(hull, node->children[side ^ 1], frac, p2f, mid, p2, trace); - - if (!trace->allsolid) - { - if (side) - { - trace->plane.normal[0] = vec3_origin[0] - plane->normal[0]; - trace->plane.normal[1] = vec3_origin[1] - plane->normal[1]; - trace->plane.normal[2] = vec3_origin[2] - plane->normal[2]; - trace->plane.dist = -plane->dist; - } - else - { - trace->plane.normal[0] = plane->normal[0]; - trace->plane.normal[1] = plane->normal[1]; - trace->plane.normal[2] = plane->normal[2]; - trace->plane.dist = plane->dist; - } - - while (1) - { - if (SV_HullPointContents(hull, hull->firstclipnode, mid) != CONTENTS_SOLID) - { - trace->fraction = frac; - trace->endpos[0] = mid[0]; - trace->endpos[1] = mid[1]; - trace->endpos[2] = mid[2]; - return FALSE; - } - midf -= 0.1f; - if (midf < 0.0f) - break; - frac = pdif * midf + p1f; - mid[0] = (p2[0] - p1[0]) * midf + p1[0]; - mid[1] = (p2[1] - p1[1]) * midf + p1[1]; - mid[2] = (p2[2] - p1[2]) * midf + p1[2]; - } - trace->fraction = frac; - trace->endpos[0] = mid[0]; - trace->endpos[1] = mid[1]; - trace->endpos[2] = mid[2]; - Con_DPrintf("backup past 0\n"); - return FALSE; - } - } - } - return FALSE; + // empty + return TRUE; } - if (num == CONTENTS_SOLID) + if (num < hull->firstclipnode || num > hull->lastclipnode || !hull->planes) + Sys_Error("%s: bad node number", __func__); + + // find the point distances + node = &hull->clipnodes[num]; + plane = &hull->planes[hull->clipnodes[num].planenum]; + + if (plane->type < 3) { - trace->startsolid = TRUE; + t1 = p1[plane->type] - plane->dist; + t2 = p2[plane->type] - plane->dist; } else { - trace->allsolid = FALSE; - if (num == CONTENTS_EMPTY) - { - trace->inopen = TRUE; - return TRUE; - } - if (num != CONTENTS_TRANSLUCENT) - { - trace->inwater = TRUE; - return TRUE; - } + t1 = _DotProduct(plane->normal, p1) - plane->dist; + t2 = _DotProduct(plane->normal, p2) - plane->dist; } - return TRUE; + + if (t1 >= 0.0f && t2 >= 0.0f) + return SV_RecursiveHullCheck(hull, node->children[0], p1f, p2f, p1, p2, trace); + + if (t1 < 0.0f && t2 < 0.0f) + return SV_RecursiveHullCheck(hull, node->children[1], p1f, p2f, p1, p2, trace); + + // put the crosspoint DIST_EPSILON pixels on the near side + if (t1 < 0.0f) + { + frac = (t1 + DIST_EPSILON) / (t1 - t2); + } + else + { + frac = (t1 - DIST_EPSILON) / (t1 - t2); + } + + if (frac < 0.0f) + frac = 0.0f; + + else if (frac > 1.0f) + frac = 1.0f; + + if (IS_NAN(frac)) + { + // not a number + return FALSE; + } + + midf = p1f + pdif * frac; + + real3_t point; + VectorSubtract(p2, p1, point); + VectorMA(p1, frac, point, mid); + + side = (t1 < 0.0f) ? 1 : 0; + + // move up to the node + if (!SV_RecursiveHullCheck(hull, node->children[side], p1f, midf, p1, mid, trace)) + return FALSE; + + if (SV_HullPointContents(hull, node->children[side ^ 1], mid) != CONTENTS_SOLID) + { + // go past the node + return SV_RecursiveHullCheck(hull, node->children[side ^ 1], midf, p2f, mid, p2, trace); + } + + if (trace->allsolid) + { + // never got out of the solid area + return FALSE; + } + + // the other side of the node is solid, this is the impact point + if (!side) + { + VectorCopy(plane->normal, trace->plane.normal); + trace->plane.dist = plane->dist; + } + else + { + VectorNegate(plane->normal, trace->plane.normal); + trace->plane.dist = -plane->dist; + } + + while (SV_HullPointContents(hull, hull->firstclipnode, mid) == CONTENTS_SOLID) + { + // shouldn't really happen, but does occasionally + frac -= 0.1f; + if (frac < 0.0f) + { + trace->fraction = midf; + VectorCopy(mid, trace->endpos); + Con_DPrintf("backup past 0\n"); + return FALSE; + } + + midf = p1f + pdif * frac; + + real3_t point; + VectorSubtract(p2, p1, point); + VectorMA(p1, frac, point, mid); + } + + trace->fraction = midf; + VectorCopy(mid, trace->endpos); + + return FALSE; } + #else // REHLDS_OPT_PEDANTIC + // version with unrolled tail recursion qboolean SV_RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, const vec_t *p1, const vec_t *p2, trace_t *trace) { dclipnode_t *node; mplane_t *plane; - float t2; - vec3_t mid; - float frac; - float t1; - signed int side; - float midf; + float t1, t2; + float frac, midf; + vec3_t mid, custom_p1; // for holding custom p1 value + int side; float pdif; - vec3_t custom_p1; // for holding custom p1 value - - float DIST_EPSILON = 0.03125f; while (num >= 0) { @@ -914,134 +890,135 @@ qboolean SV_RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, cons if (num < hull->firstclipnode || num > hull->lastclipnode || !hull->planes) Sys_Error("%s: bad node number", __func__); + // find the point distances node = &hull->clipnodes[num]; plane = &hull->planes[hull->clipnodes[num].planenum]; - if (plane->type >= 3) - { - t1 = _DotProduct(p1, plane->normal) - plane->dist; - t2 = _DotProduct(p2, plane->normal) - plane->dist; - } - else + + if (plane->type < 3) { t1 = p1[plane->type] - plane->dist; t2 = p2[plane->type] - plane->dist; } + else + { + t1 = _DotProduct(plane->normal, p1) - plane->dist; + t2 = _DotProduct(plane->normal, p2) - plane->dist; + } + if (t1 >= 0.0f && t2 >= 0.0f) { num = node->children[0]; continue; } - if (t1 >= 0.0f) + if (t1 < 0.0f && t2 < 0.0f) { - midf = t1 - DIST_EPSILON; + num = node->children[1]; + continue; + } + + // put the crosspoint DIST_EPSILON pixels on the near side + if (t1 < 0.0f) + { + frac = (t1 + DIST_EPSILON) / (t1 - t2); } else { - if (t2 < 0.0f) - { - num = node->children[1]; - continue; - } - - midf = t1 + DIST_EPSILON; + frac = (t1 - DIST_EPSILON) / (t1 - t2); } - midf = midf / (t1 - t2); - if (midf >= 0.0f) + if (frac < 0.0f) + frac = 0.0f; + + else if (frac > 1.0f) + frac = 1.0f; + + if (IS_NAN(frac)) { - if (midf > 1.0f) - midf = 1.0f; + // not a number + return FALSE; + } + + midf = p1f + pdif * frac; + + real3_t point; + VectorSubtract(p2, p1, point); + VectorMA(p1, frac, point, mid); + + side = (t1 < 0.0f) ? 1 : 0; + + // move up to the node + if (!SV_RecursiveHullCheck(hull, node->children[side], p1f, midf, p1, mid, trace)) + return FALSE; + + if (SV_HullPointContents(hull, node->children[side ^ 1], mid) != CONTENTS_SOLID) + { + // go past the node + num = node->children[side ^ 1]; + p1f = midf; + p1 = custom_p1; + VectorCopy(mid, custom_p1); + continue; + } + + if (trace->allsolid) + { + // never got out of the solid area + return FALSE; + } + + // the other side of the node is solid, this is the impact point + if (!side) + { + VectorCopy(plane->normal, trace->plane.normal); + trace->plane.dist = plane->dist; } else { - midf = 0.0f; + VectorNegate(plane->normal, trace->plane.normal); + trace->plane.dist = -plane->dist; } - if (!IS_NAN(midf)) // not a number + + while (SV_HullPointContents(hull, hull->firstclipnode, mid) == CONTENTS_SOLID) { - frac = pdif * midf + p1f; - mid[0] = (p2[0] - p1[0]) * midf + p1[0]; - mid[1] = (p2[1] - p1[1]) * midf + p1[1]; - mid[2] = (p2[2] - p1[2]) * midf + p1[2]; - side = (t1 < 0.0f) ? 1 : 0; - if (SV_RecursiveHullCheck(hull, node->children[side], p1f, frac, p1, mid, trace)) + // shouldn't really happen, but does occasionally + frac -= 0.1f; + if (frac < 0.0f) { - if (SV_HullPointContents(hull, node->children[side ^ 1], mid) != CONTENTS_SOLID) - { - num = node->children[side ^ 1]; - p1f = frac; - p1 = custom_p1; - custom_p1[0] = mid[0]; - custom_p1[1] = mid[1]; - custom_p1[2] = mid[2]; - continue; - } - - if (!trace->allsolid) - { - if (side) - { - trace->plane.normal[0] = vec3_origin[0] - plane->normal[0]; - trace->plane.normal[1] = vec3_origin[1] - plane->normal[1]; - trace->plane.normal[2] = vec3_origin[2] - plane->normal[2]; - trace->plane.dist = -plane->dist; - } - else - { - trace->plane.normal[0] = plane->normal[0]; - trace->plane.normal[1] = plane->normal[1]; - trace->plane.normal[2] = plane->normal[2]; - trace->plane.dist = plane->dist; - } - - while (1) - { - if (SV_HullPointContents(hull, hull->firstclipnode, mid) != CONTENTS_SOLID) - { - trace->fraction = frac; - trace->endpos[0] = mid[0]; - trace->endpos[1] = mid[1]; - trace->endpos[2] = mid[2]; - return FALSE; - } - midf -= 0.1f; - if (midf < 0.0f) - break; - frac = pdif * midf + p1f; - mid[0] = (p2[0] - p1[0]) * midf + p1[0]; - mid[1] = (p2[1] - p1[1]) * midf + p1[1]; - mid[2] = (p2[2] - p1[2]) * midf + p1[2]; - } - trace->fraction = frac; - trace->endpos[0] = mid[0]; - trace->endpos[1] = mid[1]; - trace->endpos[2] = mid[2]; - Con_DPrintf("backup past 0\n"); - return FALSE; - } + trace->fraction = midf; + VectorCopy(mid, trace->endpos); + Con_DPrintf("backup past 0\n"); + return FALSE; } + + midf = p1f + pdif * frac; + + real3_t point; + VectorSubtract(p2, p1, point); + VectorMA(p1, frac, point, mid); } + + trace->fraction = midf; + VectorCopy(mid, trace->endpos); return FALSE; } - if (num == CONTENTS_SOLID) + if (num != CONTENTS_SOLID) { - trace->startsolid = TRUE; + trace->allsolid = FALSE; + + if (num == CONTENTS_EMPTY) + trace->inopen = TRUE; + + else if (num != CONTENTS_TRANSLUCENT) + trace->inwater = TRUE; } else { - trace->allsolid = FALSE; - if (num == CONTENTS_EMPTY) - { - trace->inopen = TRUE; - return TRUE; - } - if (num != CONTENTS_TRANSLUCENT) - { - trace->inwater = TRUE; - return TRUE; - } + trace->startsolid = TRUE; } + + // empty return TRUE; } #endif // REHLDS_OPT_PEDANTIC @@ -1049,20 +1026,17 @@ qboolean SV_RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, cons void SV_SingleClipMoveToEntity(edict_t *ent, const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, trace_t *trace) { hull_t *hull; - trace_t testtrace; vec3_t offset; - int rotated; - int closest; + bool rotated; vec3_t end_l; vec3_t start_l; int numhulls; + // fill in a default trace Q_memset(trace, 0, sizeof(trace_t)); + VectorCopy(end, trace->endpos); trace->fraction = 1.0f; trace->allsolid = TRUE; - trace->endpos[0] = end[0]; - trace->endpos[1] = end[1]; - trace->endpos[2] = end[2]; #ifdef REHLDS_FIXES if (Mod_GetType(ent->v.modelindex) == mod_studio) @@ -1070,119 +1044,127 @@ void SV_SingleClipMoveToEntity(edict_t *ent, const vec_t *start, const vec_t *mi if (g_psv.models[ent->v.modelindex]->type == mod_studio) #endif // REHLDS_FIXES { + // get the clipping hull from studio model hull = SV_HullForStudioModel(ent, mins, maxs, offset, &numhulls); } else { + // get the clipping hull hull = SV_HullForEntity(ent, mins, maxs, offset); numhulls = 1; } - start_l[0] = start[0] - offset[0]; - start_l[1] = start[1] - offset[1]; - start_l[2] = start[2] - offset[2]; - end_l[0] = end[0] - offset[0]; - end_l[1] = end[1] - offset[1]; - end_l[2] = end[2] - offset[2]; - if (ent->v.solid == SOLID_BSP && (ent->v.angles[0] != 0.0f || ent->v.angles[1] != 0.0f || ent->v.angles[2] != 0.0f)) + + VectorSubtract(start, offset, start_l); + VectorSubtract(end, offset, end_l); + + // rotate start and end into the models frame of reference + if (ent->v.solid == SOLID_BSP && !VectorIsZero(ent->v.angles)) { - vec3_t right; - vec3_t forward; - vec3_t up; + vec3_t forward, right, up; vec3_t temp; AngleVectors(ent->v.angles, forward, right, up); - temp[0] = start_l[0]; temp[1] = start_l[1]; temp[2] = start_l[2]; - start_l[0] = _DotProduct(forward, temp); - start_l[1] = -_DotProduct(right, temp); - start_l[2] = _DotProduct(up, temp); + VectorCopy(start_l, temp); + start_l[0] = _DotProduct(temp, forward); + start_l[1] = -_DotProduct(temp, right); + start_l[2] = _DotProduct(temp, up); - temp[0] = end_l[0]; temp[1] = end_l[1]; temp[2] = end_l[2]; - end_l[0] = _DotProduct(forward, temp); - end_l[1] = -_DotProduct(right, temp); - end_l[2] = _DotProduct(up, temp); + VectorCopy(end_l, temp); + end_l[0] = _DotProduct(temp, forward); + end_l[1] = -_DotProduct(temp, right); + end_l[2] = _DotProduct(temp, up); - rotated = 1; + rotated = true; } else { - rotated = 0; + rotated = false; } + // trace a line through the appropriate clipping hull if (numhulls == 1) { SV_RecursiveHullCheck(hull, hull->firstclipnode, 0.0f, 1.0f, start_l, end_l, trace); } else { - closest = 0; + int last_hitgroup = 0; for (int i = 0; i < numhulls; i++) { - Q_memset(&testtrace, 0, sizeof(trace_t)); - testtrace.endpos[0] = end[0]; - testtrace.endpos[1] = end[1]; - testtrace.endpos[2] = end[2]; - testtrace.fraction = 1.0f; - testtrace.allsolid = TRUE; - SV_RecursiveHullCheck(&hull[i], hull[i].firstclipnode, 0.0f, 1.0f, start_l, end_l, &testtrace); - if (i == 0 || testtrace.allsolid || testtrace.startsolid || testtrace.fraction < trace->fraction) + // fill in a default trace + trace_t trace_hitbox; + Q_memset(&trace_hitbox, 0, sizeof(trace_hitbox)); + VectorCopy(end, trace_hitbox.endpos); + trace_hitbox.fraction = 1.0f; + trace_hitbox.allsolid = TRUE; + + SV_RecursiveHullCheck(&hull[i], hull[i].firstclipnode, 0.0f, 1.0f, start_l, end_l, &trace_hitbox); + + if (i == 0 || trace_hitbox.allsolid || trace_hitbox.startsolid || trace_hitbox.fraction < trace->fraction) { - int isSolid = trace->startsolid; - Q_memcpy(trace, &testtrace, sizeof(trace_t)); - if (isSolid) + if (trace->startsolid) + { + *trace = trace_hitbox; trace->startsolid = TRUE; - closest = i; + } + else + { + *trace = trace_hitbox; + } + + last_hitgroup = i; } } - trace->hitgroup = SV_HitgroupForStudioHull(closest); + trace->hitgroup = SV_HitgroupForStudioHull(last_hitgroup); } if (trace->fraction != 1.0f) { if (rotated) { - vec3_t right; - vec3_t up; - vec3_t forward; + vec3_t forward, right, up; vec3_t temp; AngleVectorsTranspose(ent->v.angles, forward, right, up); - temp[0] = trace->plane.normal[0]; - temp[1] = trace->plane.normal[1]; - temp[2] = trace->plane.normal[2]; + VectorCopy(trace->plane.normal, temp); - trace->plane.normal[0] = _DotProduct(forward, temp); - trace->plane.normal[1] = _DotProduct(right, temp); - trace->plane.normal[2] = _DotProduct(up, temp); + trace->plane.normal[0] = _DotProduct(temp, forward); + trace->plane.normal[1] = _DotProduct(temp, right); + trace->plane.normal[2] = _DotProduct(temp, up); } - trace->endpos[0] = (end[0] - start[0]) * trace->fraction + start[0]; - trace->endpos[1] = (end[1] - start[1]) * trace->fraction + start[1]; - trace->endpos[2] = (end[2] - start[2]) * trace->fraction + start[2]; + real3_t point; + VectorSubtract(end, start, point); + VectorMA(start, trace->fraction, point, trace->endpos); } + // did we clip the move? if (trace->fraction < 1.0f || trace->startsolid) trace->ent = ent; } +// Handles selection or creation of a clipping hull, and offseting (and eventually rotation) of the end points trace_t SV_ClipMoveToEntity(edict_t *ent, const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end) { - trace_t goodtrace; - SV_SingleClipMoveToEntity(ent, start, mins, maxs, end, &goodtrace); - - return goodtrace; + trace_t trace; + SV_SingleClipMoveToEntity(ent, start, mins, maxs, end, &trace); + return trace; } +// Mins and maxs enclose the entire area swept by the move void SV_ClipToLinks(areanode_t *node, moveclip_t *clip) { - link_t *l; - link_t *next; + link_t *next, *l; + edict_t *touch; + // touch linked edicts for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) { next = l->next; - edict_t *touch = (edict_t *)((char *)l - offsetof(edict_t, area)); + touch = EDICT_FROM_AREA(l); + if (touch->v.groupinfo && clip->passedict && clip->passedict->v.groupinfo) { if (g_groupop) @@ -1197,10 +1179,7 @@ void SV_ClipToLinks(areanode_t *node, moveclip_t *clip) } } - if (touch->v.solid == SOLID_NOT) - continue; - - if (touch == clip->passedict) + if (touch->v.solid == SOLID_NOT || touch == clip->passedict) continue; if (touch->v.solid == SOLID_TRIGGER) @@ -1214,6 +1193,7 @@ void SV_ClipToLinks(areanode_t *node, moveclip_t *clip) return; #endif + // monsterclip filter if (touch->v.solid == SOLID_BSP) { if ((touch->v.flags & FL_MONSTERCLIP) && !clip->monsterClipBrush) @@ -1221,67 +1201,84 @@ void SV_ClipToLinks(areanode_t *node, moveclip_t *clip) } else { - if (clip->type == 1 && touch->v.movetype != MOVETYPE_PUSHSTEP) + // ignore all monsters but pushables + if (clip->type == MOVE_NOMONSTERS && touch->v.movetype != MOVETYPE_PUSHSTEP) continue; } - if ((!clip->ignoretrans || !touch->v.rendermode || (touch->v.flags & FL_WORLDBRUSH)) - && clip->boxmins[0] <= touch->v.absmax[0] - && clip->boxmins[1] <= touch->v.absmax[1] - && clip->boxmins[2] <= touch->v.absmax[2] - && clip->boxmaxs[0] >= touch->v.absmin[0] - && clip->boxmaxs[1] >= touch->v.absmin[1] - && clip->boxmaxs[2] >= touch->v.absmin[2] -#ifdef REHLDS_FIXES - && ((touch->v.solid == SOLID_SLIDEBOX && sv_force_ent_intersection.string[0] == '0') -#else // REHLDS_FIXES - && (touch->v.solid == SOLID_SLIDEBOX -#endif // REHLDS_FIXES - || SV_CheckSphereIntersection(touch, clip->start, clip->end)) - && (!clip->passedict || clip->passedict->v.size[0] == 0.0f || touch->v.size[0] != 0.0f)) + if (clip->ignoretrans && touch->v.rendermode != kRenderNormal && !(touch->v.flags & FL_WORLDBRUSH)) + continue; + + if (clip->boxmins[0] > touch->v.absmax[0] + || clip->boxmins[1] > touch->v.absmax[1] + || clip->boxmins[2] > touch->v.absmax[2] + || clip->boxmaxs[0] < touch->v.absmin[0] + || clip->boxmaxs[1] < touch->v.absmin[1] + || clip->boxmaxs[2] < touch->v.absmin[2]) + continue; + + if (touch->v.solid != SOLID_SLIDEBOX && !SV_CheckSphereIntersection(touch, clip->start, clip->end)) + continue; + + if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0]) + continue; // points never interact + + // might intersect, so do an exact clip + if (clip->trace.allsolid) + return; + + if (clip->passedict) { - if (clip->trace.allsolid) - return; + if (touch->v.owner == clip->passedict) + continue; // don't clip against own missiles - if (clip->passedict && (touch->v.owner == clip->passedict || clip->passedict->v.owner == touch)) - continue; + if (clip->passedict->v.owner == touch) + continue; // don't clip against owner + } - trace_t trace; - if (touch->v.flags & FL_MONSTER) - trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins2, clip->maxs2, clip->end); - else - trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins, clip->maxs, clip->end); + trace_t trace; + if (touch->v.flags & FL_MONSTER) + trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins2, clip->maxs2, clip->end); + else + trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins, clip->maxs, clip->end); - if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) + if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) + { + trace.ent = touch; + if (clip->trace.startsolid) + { + clip->trace = trace; + clip->trace.startsolid = TRUE; + } + else { - qboolean oldStartSolid = clip->trace.startsolid; - trace.ent = touch; clip->trace = trace; - if (oldStartSolid) - clip->trace.startsolid = TRUE; } } } - if (node->axis != -1) - { - if (clip->boxmaxs[node->axis] > node->dist) - SV_ClipToLinks(node->children[0], clip); + // recurse down both sides + if (node->axis == -1) + return; - if (node->dist > clip->boxmins[node->axis]) - SV_ClipToLinks(node->children[1], clip); - } + if (clip->boxmaxs[node->axis] > node->dist) + SV_ClipToLinks(node->children[0], clip); + + if (node->dist > clip->boxmins[node->axis]) + SV_ClipToLinks(node->children[1], clip); } +// Mins and maxs enclose the entire area swept by the move void SV_ClipToWorldbrush(areanode_t *node, moveclip_t *clip) { link_t *l; link_t *next; + edict_t *touch; for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) { next = l->next; - edict_t *touch = (edict_t *)((char *)l - offsetof(edict_t, area)); + touch = EDICT_FROM_AREA(l); if (touch->v.solid != SOLID_BSP) continue; @@ -1289,36 +1286,42 @@ void SV_ClipToWorldbrush(areanode_t *node, moveclip_t *clip) if (!(touch->v.flags & FL_WORLDBRUSH)) continue; - if (clip->boxmins[0] <= touch->v.absmax[0] - && clip->boxmins[1] <= touch->v.absmax[1] - && clip->boxmins[2] <= touch->v.absmax[2] - && clip->boxmaxs[0] >= touch->v.absmin[0] - && clip->boxmaxs[1] >= touch->v.absmin[1] - && clip->boxmaxs[2] >= touch->v.absmin[2]) - { - if (clip->trace.allsolid) - return; + if (clip->boxmins[0] > touch->v.absmax[0] + || clip->boxmins[1] > touch->v.absmax[1] + || clip->boxmins[2] > touch->v.absmax[2] + || clip->boxmaxs[0] < touch->v.absmin[0] + || clip->boxmaxs[1] < touch->v.absmin[1] + || clip->boxmaxs[2] < touch->v.absmin[2]) + continue; - trace_t trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins, clip->maxs, clip->end); - if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) + if (clip->trace.allsolid) + return; + + trace_t trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins, clip->maxs, clip->end); + if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) + { + trace.ent = touch; + if (clip->trace.startsolid) + { + clip->trace = trace; + clip->trace.startsolid = TRUE; + } + else { - int oldSolid = clip->trace.startsolid; - trace.ent = touch; clip->trace = trace; - if (oldSolid) - clip->trace.startsolid = TRUE; } } } - if (node->axis != -1) - { - if (clip->boxmaxs[node->axis] > node->dist) - SV_ClipToWorldbrush(node->children[0], clip); + // recurse down both sides + if (node->axis == -1) + return; - if (node->dist > clip->boxmins[node->axis]) - SV_ClipToWorldbrush(node->children[1], clip); - } + if (clip->boxmaxs[node->axis] > node->dist) + SV_ClipToWorldbrush(node->children[0], clip); + + if (node->dist > clip->boxmins[node->axis]) + SV_ClipToWorldbrush(node->children[1], clip); } void SV_MoveBounds(const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, vec_t *boxmins, vec_t *boxmaxs) @@ -1341,71 +1344,77 @@ void SV_MoveBounds(const vec_t *start, const vec_t *mins, const vec_t *maxs, con trace_t SV_MoveNoEnts(const vec_t *start, vec_t *mins, vec_t *maxs, const vec_t *end, int type, edict_t *passedict) { moveclip_t clip; - vec3_t worldEndPoint; - float worldFraction; + vec3_t trace_endpos; + float trace_fraction; Q_memset(&clip, 0, sizeof(clip)); clip.trace = SV_ClipMoveToEntity(g_psv.edicts, start, mins, maxs, end); + if (clip.trace.fraction != 0.0f) { - worldEndPoint[0] = clip.trace.endpos[0]; - worldEndPoint[2] = clip.trace.endpos[2]; - worldEndPoint[1] = clip.trace.endpos[1]; - clip.end = worldEndPoint; + VectorCopy(clip.trace.endpos, trace_endpos); - clip.ignoretrans = type >> 8; - worldFraction = clip.trace.fraction; - clip.type = type; - clip.passedict = passedict; - - clip.mins2[0] = mins[0]; - clip.mins2[1] = mins[1]; - clip.mins2[2] = mins[2]; - clip.maxs2[0] = maxs[0]; - clip.maxs2[1] = maxs[1]; - clip.maxs2[2] = maxs[2]; + trace_fraction = clip.trace.fraction; clip.trace.fraction = 1.0f; clip.start = start; - clip.mins = mins; - clip.maxs = maxs; + clip.end = trace_endpos; + + clip.type = (type & 0xff); + clip.ignoretrans = (type >> 8); + clip.passedict = passedict; clip.monsterClipBrush = FALSE; - SV_MoveBounds(start, clip.mins2, clip.maxs2, worldEndPoint, clip.boxmins, clip.boxmaxs); + clip.mins = mins; + clip.maxs = maxs; + + VectorCopy(mins, clip.mins2); + VectorCopy(maxs, clip.maxs2); + + SV_MoveBounds(start, clip.mins2, clip.maxs2, trace_endpos, clip.boxmins, clip.boxmaxs); SV_ClipToWorldbrush(sv_areanodes, &clip); + clip.trace.fraction *= trace_fraction; gGlobalVariables.trace_ent = clip.trace.ent; - clip.trace.fraction = worldFraction * clip.trace.fraction; } return clip.trace; } +// mins and maxs are reletive +// if the entire move stays in a solid volume, trace.allsolid will be set +// if the starting point is in a solid, it will be allowed to move out to an open area +// nomonsters is used for line of sight or edge testing, +// where mosnters shouldn't be considered solid objects +// passedict is explicitly excluded from clipping checks (normally NULL) trace_t SV_Move(const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, int type, edict_t *passedict, qboolean monsterClipBrush) { moveclip_t clip; - vec3_t worldEndPoint; - float worldFraction; + vec3_t trace_endpos; + float trace_fraction; Q_memset(&clip, 0, sizeof(clip)); clip.trace = SV_ClipMoveToEntity(g_psv.edicts, start, mins, maxs, end); + if (clip.trace.fraction != 0.0f) { - worldEndPoint[0] = clip.trace.endpos[0]; - worldEndPoint[1] = clip.trace.endpos[1]; - worldEndPoint[2] = clip.trace.endpos[2]; - clip.end = worldEndPoint; - worldFraction = clip.trace.fraction; + VectorCopy(clip.trace.endpos, trace_endpos); + + trace_fraction = clip.trace.fraction; - clip.type = type & 0xFF; - clip.ignoretrans = type >> 8; clip.trace.fraction = 1.0f; clip.start = start; - clip.mins = mins; - clip.maxs = maxs; + clip.end = trace_endpos; + + clip.type = (type & 0xff); + clip.ignoretrans = (type >> 8); clip.passedict = passedict; clip.monsterClipBrush = monsterClipBrush; - if (type == 2) + + clip.mins = mins; + clip.maxs = maxs; + + if (type == MOVE_MISSILE) { for (int i = 0; i < 3; i++) { @@ -1415,36 +1424,31 @@ trace_t SV_Move(const vec_t *start, const vec_t *mins, const vec_t *maxs, const } else { - clip.mins2[0] = mins[0]; - clip.mins2[1] = mins[1]; - clip.mins2[2] = mins[2]; - clip.maxs2[0] = maxs[0]; - clip.maxs2[1] = maxs[1]; - clip.maxs2[2] = maxs[2]; + VectorCopy(mins, clip.mins2); + VectorCopy(maxs, clip.maxs2); } - SV_MoveBounds(start, clip.mins2, clip.maxs2, worldEndPoint, clip.boxmins, clip.boxmaxs); + + SV_MoveBounds(start, clip.mins2, clip.maxs2, trace_endpos, clip.boxmins, clip.boxmaxs); SV_ClipToLinks(sv_areanodes, &clip); + + clip.trace.fraction *= trace_fraction; gGlobalVariables.trace_ent = clip.trace.ent; - clip.trace.fraction = worldFraction * clip.trace.fraction; } return clip.trace; } #ifdef REHLDS_OPT_PEDANTIC + // Optimized version of SV_Move routines for moving point hull throw world void SV_SingleClipMoveToPoint(const vec_t *start, const vec_t *end, trace_t *trace) { - hull_t *hull; - Q_memset(trace, 0, sizeof(trace_t)); trace->fraction = 1.0f; trace->allsolid = TRUE; - trace->endpos[0] = end[0]; - trace->endpos[1] = end[1]; - trace->endpos[2] = end[2]; + VectorCopy(end, trace->endpos); - hull = &g_psv.models[1]->hulls[0]; // world point hull + hull_t *hull = &g_psv.models[1]->hulls[0]; // world point hull SV_RecursiveHullCheck(hull, hull->firstclipnode, 0.0f, 1.0f, start, end, trace); if (trace->fraction != 1.0f) @@ -1478,30 +1482,31 @@ void SV_MoveBounds_Point(const vec_t *start, const vec_t *end, vec_t *boxmins, v trace_t SV_Move_Point(const vec_t *start, const vec_t *end, int type, edict_t *passedict) { moveclip_t clip; - vec3_t worldEndPoint; - float worldFraction; + vec3_t trace_endpos; + float trace_fraction; Q_memset(&clip, 0, sizeof(clip)); SV_SingleClipMoveToPoint(start, end, &clip.trace); if (clip.trace.fraction != 0.0f) { - worldEndPoint[0] = clip.trace.endpos[0]; - worldEndPoint[1] = clip.trace.endpos[1]; - worldEndPoint[2] = clip.trace.endpos[2]; + VectorCopy(clip.trace.endpos, trace_endpos); - clip.end = worldEndPoint; - worldFraction = clip.trace.fraction; + trace_fraction = clip.trace.fraction; - clip.type = type & 0xFF; - clip.ignoretrans = type >> 8; clip.trace.fraction = 1.0f; clip.start = start; + clip.end = trace_endpos; + + clip.type = (type & 0xff); + clip.ignoretrans = (type >> 8); + clip.passedict = passedict; + clip.monsterClipBrush = FALSE; + clip.mins = vec3_origin; clip.maxs = vec3_origin; - clip.passedict = passedict; - clip.monsterClipBrush = 0; - if (type == 2) + + if (type == MOVE_MISSILE) { for (int i = 0; i < 3; i++) { @@ -1511,19 +1516,18 @@ trace_t SV_Move_Point(const vec_t *start, const vec_t *end, int type, edict_t *p } else { - clip.mins2[0] = 0.0; - clip.mins2[1] = 0.0; - clip.mins2[2] = 0.0; - clip.maxs2[0] = 0.0; - clip.maxs2[1] = 0.0; - clip.maxs2[2] = 0.0; + VectorClear(clip.mins2); + VectorClear(clip.maxs2); } - SV_MoveBounds_Point(start, worldEndPoint, clip.boxmins, clip.boxmaxs); + + SV_MoveBounds_Point(start, trace_endpos, clip.boxmins, clip.boxmaxs); SV_ClipToLinks(sv_areanodes, &clip); + + clip.trace.fraction *= trace_fraction; gGlobalVariables.trace_ent = clip.trace.ent; - clip.trace.fraction = worldFraction * clip.trace.fraction; } return clip.trace; } + #endif // REHLDS_OPT_PEDANTIC diff --git a/rehlds/engine/world.h b/rehlds/engine/world.h index 5b6f1e3..78115ab 100644 --- a/rehlds/engine/world.h +++ b/rehlds/engine/world.h @@ -40,6 +40,9 @@ typedef struct areanode_s link_t solid_edicts; } areanode_t; +const int AREA_DEPTH = 4; +const int AREA_NODES = 32; + typedef struct moveclip_s // TODO: Move it to world.cpp someday { vec3_t boxmins; @@ -57,6 +60,15 @@ typedef struct moveclip_s // TODO: Move it to world.cpp someday qboolean monsterClipBrush; } moveclip_t; +#define CONTENTS_NONE 0 // no custom contents specified + +#define MOVE_NORMAL 0 // normal trace +#define MOVE_NOMONSTERS 1 // ignore monsters (edicts with flags (FL_MONSTER|FL_FAKECLIENT|FL_CLIENT) set) +#define MOVE_MISSILE 2 // extra size for monsters + +#define FMOVE_IGNORE_GLASS 0x100 +#define FMOVE_SIMPLEBOX 0x200 + typedef dclipnode_t box_clipnodes_t[6]; typedef mplane_t box_planes_t[6]; typedef mplane_t beam_planes_t[6]; @@ -78,7 +90,7 @@ extern hull_t beam_hull; extern box_clipnodes_t box_clipnodes; extern box_planes_t box_planes; extern beam_planes_t beam_planes; -extern areanode_t sv_areanodes[32]; +extern areanode_t sv_areanodes[AREA_NODES]; extern int sv_numareanodes; extern cvar_t sv_force_ent_intersection; @@ -87,13 +99,13 @@ void ClearLink(link_t *l); void RemoveLink(link_t *l); void InsertLinkBefore(link_t *l, link_t *before); NOXREF void InsertLinkAfter(link_t *l, link_t *after); -void SV_InitBoxHull(void); +void SV_InitBoxHull(); hull_t *SV_HullForBox(const vec_t *mins, const vec_t *maxs); NOXREF hull_t *SV_HullForBeam(const vec_t *start, const vec_t *end, const vec_t *size); -struct hull_s *SV_HullForBsp(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset); +hull_t *SV_HullForBsp(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset); hull_t *SV_HullForEntity(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset); areanode_t *SV_CreateAreaNode(int depth, vec_t *mins, vec_t *maxs); -void SV_ClearWorld(void); +void SV_ClearWorld(); void SV_UnlinkEdict(edict_t *ent); void SV_TouchLinks(edict_t *ent, areanode_t *node); void SV_FindTouchedLeafs(edict_t *ent, mnode_t *node, int *topnode); diff --git a/rehlds/hookers/engine/hooklist.cpp b/rehlds/hookers/engine/hooklist.cpp index 7ff8e8e..22c435e 100644 --- a/rehlds/hookers/engine/hooklist.cpp +++ b/rehlds/hookers/engine/hooklist.cpp @@ -1381,7 +1381,7 @@ FunctionHook g_FunctionHooks[] = HOOK_DEF(0x01D50460, Length), HOOK_DEF(0x01D504A0, VectorNormalize), //HOOK_DEF(0x, VectorInverse), - HOOK_DEF(0x01D50550, VectorScale), + //HOOK_DEF(0x01D50550, VectorScale), //HOOK_DEF(0x, Q_log2), //HOOK_DEF(0x, VectorMatrix), HOOK_DEF(0x01D50640, VectorAngles), @@ -2371,8 +2371,8 @@ AddressRef g_DataRefs[] = GLOBALVAR_LINK(0x01E48EA0, "sv_stopspeed", psv_stopspeed), GLOBALVAR_LINK(0x021C2B48, "g_moved_from", pg_moved_from), GLOBALVAR_LINK(0x021C2B4C, "sv_numareanodes", pg_moved_edict), - GLOBALVAR_LINK(0x021C2B50, "c_yes", pc_yes), - GLOBALVAR_LINK(0x021C2B54, "c_no", pc_no), + //GLOBALVAR_LINK(0x021C2B50, "c_yes", pc_yes), + //GLOBALVAR_LINK(0x021C2B54, "c_no", pc_no), GLOBALVAR_LINK(0x020042AC, "net_thread_initialized", pnet_thread_initialized), GLOBALVAR_LINK(0x01E3E8DC, "net_address", pnet_address), GLOBALVAR_LINK(0x01E3E900, "ipname", pipname), diff --git a/rehlds/public/rehlds/progs.h b/rehlds/public/rehlds/progs.h index 1d1f885..808ad30 100644 --- a/rehlds/public/rehlds/progs.h +++ b/rehlds/public/rehlds/progs.h @@ -60,7 +60,7 @@ struct event_state_s #include "edict.h" #endif -#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m))) +#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - offsetof(t, m))) #define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area) //============================================================================