X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=sv_phys.c;h=12f9b303e6b67cffd382faf006cd873d6ef69061;hb=c3dd86794da69f70df630f9f68df695faad49f08;hp=0e37ed3b6dfad40eef7abebd7edf606f15e879cf;hpb=a9d901739e22f3bb631ff5cd3001992cae51c669;p=xonotic%2Fdarkplaces.git diff --git a/sv_phys.c b/sv_phys.c index 0e37ed3b..12f9b303 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -39,17 +39,20 @@ solid_edge items only clip against bsp models. */ -cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4"}; -cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100"}; -cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800"}; -cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000"}; -cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0"}; -cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18"}; -cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "1"}; -cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1"}; -cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "0"}; -cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0"}; -cvar_t sv_playerphysicsqc = {CVAR_NOTIFY, "sv_playerphysicsqc", "1"}; +cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4", "how fast you slow down"}; +cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100", "how fast you come to a complete stop"}; +cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"}; +cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000", "universal speed limit on all entities"}; +cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0", "prevents MOVETYPE_STEP entities (monsters) from moving"}; +cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18", "how high you can step up (TW_SV_STEPCONTROL extension)"}; +cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "0", "whether you can step up while jumping (sv_gameplayfix_stepwhilejumping must also be 1)"}; +cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"}; +cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "0", "enables simpler/buggier player physics (not recommended)"}; +cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0", "freezes time, except for players, allowing you to walk around and take screenshots of explosions"}; +cvar_t sv_playerphysicsqc = {CVAR_NOTIFY, "sv_playerphysicsqc", "1", "enables QuakeC function to override player physics"}; + +cvar_t sv_sound_watersplash = {0, "sv_sound_watersplash", "misc/h2ohit1.wav", "sound to play when MOVETYPE_FLY/TOSS/BOUNCE/STEP entity enters or leaves water (empty cvar disables the sound)"}; +cvar_t sv_sound_land = {0, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"}; #define MOVE_EPSILON 0.01 @@ -64,6 +67,21 @@ void SV_Phys_Init (void) Cvar_RegisterVariable(&sv_freezenonclients); Cvar_RegisterVariable(&sv_playerphysicsqc); + + Cvar_RegisterVariable(&sv_sound_watersplash); + Cvar_RegisterVariable(&sv_sound_land); +} + +/* +============ +SV_TestEntityPosition + +returns true if the entity is in solid currently +============ +*/ +static int SV_TestEntityPosition (prvm_edict_t *ent, int movemode) +{ + return SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, movemode, ent).startsolid; } /* @@ -88,7 +106,7 @@ void SV_CheckAllEnts (void) || check->fields.server->movetype == MOVETYPE_NOCLIP) continue; - if (SV_TestEntityPosition (check)) + if (SV_TestEntityPosition (check, MOVE_NORMAL)) Con_Print("entity in invalid position\n"); } } @@ -359,7 +377,7 @@ int SV_FlyMove (prvm_edict_t *ent, float time, float *stepnormal) // run the impact function if (impact) { - SV_Impact(ent, trace.ent); + SV_Impact(ent, (prvm_edict_t *)trace.ent); // break if removed by the impact function if (ent->priv.server->free) @@ -512,7 +530,7 @@ trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push) SV_LinkEdict (ent, true); if (trace.ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace.ent))) - SV_Impact (ent, trace.ent); + SV_Impact (ent, (prvm_edict_t *)trace.ent); return trace; } @@ -523,13 +541,11 @@ SV_PushMove ============ */ -trace_t SV_ClipMoveToEntity (prvm_edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); void SV_PushMove (prvm_edict_t *pusher, float movetime) { int i, e, index; - prvm_edict_t *check, *ed; float savesolid, movetime2, pushltime; - vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2; + vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org; int num_moved; int numcheckentities; static prvm_edict_t *checkentities[MAX_EDICTS]; @@ -632,7 +648,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) VectorCopy (pusher->fields.server->angles, pushang); pushltime = pusher->fields.server->ltime; -// move the pusher to it's final position +// move the pusher to its final position VectorMA (pusher->fields.server->origin, movetime, pusher->fields.server->velocity, pusher->fields.server->origin); VectorMA (pusher->fields.server->angles, movetime, pusher->fields.server->avelocity, pusher->fields.server->angles); @@ -647,9 +663,9 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities); for (e = 0;e < numcheckentities;e++) { - check = checkentities[e]; - if (check->fields.server->movetype == MOVETYPE_PUSH - || check->fields.server->movetype == MOVETYPE_NONE + prvm_edict_t *check = checkentities[e]; + if (check->fields.server->movetype == MOVETYPE_NONE + || check->fields.server->movetype == MOVETYPE_PUSH || check->fields.server->movetype == MOVETYPE_FOLLOW || check->fields.server->movetype == MOVETYPE_NOCLIP || check->fields.server->movetype == MOVETYPE_FAKEPUSH) @@ -657,11 +673,19 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) // if the entity is standing on the pusher, it will definitely be moved if (!(((int)check->fields.server->flags & FL_ONGROUND) && PRVM_PROG_TO_EDICT(check->fields.server->groundentity) == pusher)) - if (!SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin).startsolid) + { + // if the entity is not inside the pusher's final position, leave it alone + if (!SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID).startsolid) continue; + // remove the onground flag for non-players + if (check->fields.server->movetype != MOVETYPE_WALK) + check->fields.server->flags = (int)check->fields.server->flags & ~FL_ONGROUND; + } + if (forward[0] != 1 || left[1] != 1) // quick way to check if any rotation is used { + vec3_t org2; VectorSubtract (check->fields.server->origin, pusher->fields.server->origin, org); org2[0] = DotProduct (org, forward); org2[1] = DotProduct (org, left); @@ -672,10 +696,6 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) else VectorCopy (move1, move); - // remove the onground flag for non-players - if (check->fields.server->movetype != MOVETYPE_WALK) - check->fields.server->flags = (int)check->fields.server->flags & ~FL_ONGROUND; - VectorCopy (check->fields.server->origin, check->priv.server->moved_from); VectorCopy (check->fields.server->angles, check->priv.server->moved_fromangles); sv.moved_edicts[num_moved++] = check; @@ -688,50 +708,63 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) pusher->fields.server->solid = savesolid; // was SOLID_BSP // if it is still inside the pusher, block - if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin).startsolid) + if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID).startsolid) { // try moving the contacted entity a tiny bit further to account for precision errors + vec3_t move2; pusher->fields.server->solid = SOLID_NOT; - VectorScale(move, 0.1, move); - SV_PushEntity (check, move); + VectorScale(move, 1.1, move2); + VectorCopy (check->priv.server->moved_from, check->fields.server->origin); + VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); + SV_PushEntity (check, move2); pusher->fields.server->solid = savesolid; - if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin).startsolid) + if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID).startsolid) { - // still inside pusher, so it's really blocked - - // fail the move - if (check->fields.server->mins[0] == check->fields.server->maxs[0]) - continue; - if (check->fields.server->solid == SOLID_NOT || check->fields.server->solid == SOLID_TRIGGER) + // try moving the contacted entity a tiny bit less to account for precision errors + pusher->fields.server->solid = SOLID_NOT; + VectorScale(move, 0.9, move2); + VectorCopy (check->priv.server->moved_from, check->fields.server->origin); + VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); + SV_PushEntity (check, move2); + pusher->fields.server->solid = savesolid; + if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID).startsolid) { - // corpse - check->fields.server->mins[0] = check->fields.server->mins[1] = 0; - VectorCopy (check->fields.server->mins, check->fields.server->maxs); - continue; - } + // still inside pusher, so it's really blocked - VectorCopy (pushorig, pusher->fields.server->origin); - VectorCopy (pushang, pusher->fields.server->angles); - pusher->fields.server->ltime = pushltime; - SV_LinkEdict (pusher, false); + // fail the move + if (check->fields.server->mins[0] == check->fields.server->maxs[0]) + continue; + if (check->fields.server->solid == SOLID_NOT || check->fields.server->solid == SOLID_TRIGGER) + { + // corpse + check->fields.server->mins[0] = check->fields.server->mins[1] = 0; + VectorCopy (check->fields.server->mins, check->fields.server->maxs); + continue; + } - // move back any entities we already moved - for (i = 0;i < num_moved;i++) - { - ed = sv.moved_edicts[i]; - VectorCopy (ed->priv.server->moved_from, ed->fields.server->origin); - VectorCopy (ed->priv.server->moved_fromangles, ed->fields.server->angles); - SV_LinkEdict (ed, false); - } + VectorCopy (pushorig, pusher->fields.server->origin); + VectorCopy (pushang, pusher->fields.server->angles); + pusher->fields.server->ltime = pushltime; + SV_LinkEdict (pusher, false); - // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone - if (pusher->fields.server->blocked) - { - prog->globals.server->self = PRVM_EDICT_TO_PROG(pusher); - prog->globals.server->other = PRVM_EDICT_TO_PROG(check); - PRVM_ExecuteProgram (pusher->fields.server->blocked, "QC function self.blocked is missing"); + // move back any entities we already moved + for (i = 0;i < num_moved;i++) + { + prvm_edict_t *ed = sv.moved_edicts[i]; + VectorCopy (ed->priv.server->moved_from, ed->fields.server->origin); + VectorCopy (ed->priv.server->moved_fromangles, ed->fields.server->angles); + SV_LinkEdict (ed, false); + } + + // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone + if (pusher->fields.server->blocked) + { + prog->globals.server->self = PRVM_EDICT_TO_PROG(pusher); + prog->globals.server->other = PRVM_EDICT_TO_PROG(check); + PRVM_ExecuteProgram (pusher->fields.server->blocked, "QC function self.blocked is missing"); + } + break; } - break; } } } @@ -798,7 +831,7 @@ void SV_CheckStuck (prvm_edict_t *ent) int i, j, z; vec3_t org; - if (!SV_TestEntityPosition(ent)) + if (!SV_TestEntityPosition(ent, MOVE_NORMAL)) { VectorCopy (ent->fields.server->origin, ent->fields.server->oldorigin); return; @@ -806,9 +839,9 @@ void SV_CheckStuck (prvm_edict_t *ent) VectorCopy (ent->fields.server->origin, org); VectorCopy (ent->fields.server->oldorigin, ent->fields.server->origin); - if (!SV_TestEntityPosition(ent)) + if (!SV_TestEntityPosition(ent, MOVE_NORMAL)) { - Con_DPrint("Unstuck.\n"); + Con_DPrintf("Unstuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); SV_LinkEdict (ent, true); return; } @@ -820,16 +853,46 @@ void SV_CheckStuck (prvm_edict_t *ent) ent->fields.server->origin[0] = org[0] + i; ent->fields.server->origin[1] = org[1] + j; ent->fields.server->origin[2] = org[2] + z; - if (!SV_TestEntityPosition(ent)) + if (!SV_TestEntityPosition(ent, MOVE_NORMAL)) + { + Con_DPrintf("Unstuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); + SV_LinkEdict (ent, true); + return; + } + } + + VectorCopy (org, ent->fields.server->origin); + Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); +} + +static void SV_UnstickEntity (prvm_edict_t *ent) +{ + int i, j, z; + vec3_t org; + + // if not stuck in a bmodel, just return + if (!SV_TestEntityPosition(ent, MOVE_NOMONSTERS)) + return; + + VectorCopy (ent->fields.server->origin, org); + + for (z=0 ; z< 18 ; z += 6) + for (i=-1 ; i <= 1 ; i++) + for (j=-1 ; j <= 1 ; j++) + { + ent->fields.server->origin[0] = org[0] + i; + ent->fields.server->origin[1] = org[1] + j; + ent->fields.server->origin[2] = org[2] + z; + if (!SV_TestEntityPosition(ent, MOVE_NOMONSTERS)) { - Con_DPrint("Unstuck.\n"); + Con_DPrintf("Unstuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); SV_LinkEdict (ent, true); return; } } VectorCopy (org, ent->fields.server->origin); - Con_DPrint("player is stuck.\n"); + Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); } @@ -1061,6 +1124,9 @@ void SV_WalkMove (prvm_edict_t *ent) if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7) { + // this has been disabled so that you can't jump when you are stepping + // up while already jumping (also known as the Quake2 stair jump bug) +#if 0 // LordHavoc: disabled this check so you can walk on monsters/players //if (ent->fields.server->solid == SOLID_BSP) { @@ -1068,6 +1134,7 @@ void SV_WalkMove (prvm_edict_t *ent) ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND; ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(downtrace.ent); } +#endif } else { @@ -1148,7 +1215,7 @@ SV_CheckWaterTransition void SV_CheckWaterTransition (prvm_edict_t *ent) { int cont; - cont = SV_PointQ1Contents(ent->fields.server->origin); + cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(ent->fields.server->origin)); if (!ent->fields.server->watertype) { // just spawned here @@ -1158,8 +1225,8 @@ void SV_CheckWaterTransition (prvm_edict_t *ent) } // check if the entity crossed into or out of water - if (gamemode != GAME_NEXUIZ && ((ent->fields.server->watertype == CONTENTS_WATER || ent->fields.server->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))) - SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); + if (sv_sound_watersplash.string && ((ent->fields.server->watertype == CONTENTS_WATER || ent->fields.server->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))) + SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1); if (cont <= CONTENTS_WATER) { @@ -1185,22 +1252,25 @@ void SV_Physics_Toss (prvm_edict_t *ent) trace_t trace; vec3_t move; - // don't stick to ground if onground and moving upward - if (ent->fields.server->velocity[2] >= (1.0 / 32.0) && ((int)ent->fields.server->flags & FL_ONGROUND)) - ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND; - // if onground, return without moving if ((int)ent->fields.server->flags & FL_ONGROUND) { - if (ent->fields.server->groundentity == 0 || sv_gameplayfix_noairborncorpse.integer) - return; - // if ent was supported by a brush model on previous frame, - // and groundentity is now freed, set groundentity to 0 (floating) - if (ent->priv.server->suspendedinairflag && PRVM_PROG_TO_EDICT(ent->fields.server->groundentity)->priv.server->free) + // don't stick to ground if onground and moving upward + if (ent->fields.server->velocity[2] >= (1.0 / 32.0)) + ent->fields.server->flags -= FL_ONGROUND; + else { - // leave it suspended in the air - ent->fields.server->groundentity = 0; - return; + prvm_edict_t *ground = PRVM_PROG_TO_EDICT(ent->fields.server->groundentity); + if (ground->fields.server->solid == SOLID_BSP || !sv_gameplayfix_noairborncorpse.integer) + return; + // if ent was supported by a brush model on previous frame, + // and groundentity is now freed, set groundentity to 0 (floating) + if (ent->priv.server->suspendedinairflag && ground->priv.server->free) + { + // leave it suspended in the air + ent->fields.server->groundentity = 0; + return; + } } } ent->priv.server->suspendedinairflag = false; @@ -1219,6 +1289,14 @@ void SV_Physics_Toss (prvm_edict_t *ent) trace = SV_PushEntity (ent, move); if (ent->priv.server->free) return; + if (trace.startsolid) + { + // try to unstick the entity + SV_UnstickEntity(ent); + trace = SV_PushEntity (ent, move); + if (ent->priv.server->free) + return; + } if (trace.fraction < 1) { @@ -1300,23 +1378,38 @@ will fall if the floor is pulled out from under them. */ void SV_Physics_Step (prvm_edict_t *ent) { - // don't stick to ground if onground and moving upward - if (ent->fields.server->velocity[2] >= (1.0 / 32.0) && ((int)ent->fields.server->flags & FL_ONGROUND)) - ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND; - - // freefall if not onground/fly/swim - if (!((int)ent->fields.server->flags & (FL_ONGROUND | FL_FLY | FL_SWIM))) + int flags = (int)ent->fields.server->flags; + // don't fall at all if fly/swim + if (!(flags & (FL_FLY | FL_SWIM))) { - int hitsound = ent->fields.server->velocity[2] < sv_gravity.value * -0.1; + if (flags & FL_ONGROUND) + { + // freefall if onground and moving upward + // freefall if not standing on a world surface (it may be a lift) + prvm_edict_t *ground = PRVM_PROG_TO_EDICT(ent->fields.server->groundentity); + if (ent->fields.server->velocity[2] >= (1.0 / 32.0) || (ground->fields.server->solid != SOLID_BSP && sv_gameplayfix_noairborncorpse.integer)) + { + ent->fields.server->flags -= FL_ONGROUND; + SV_AddGravity(ent); + SV_CheckVelocity(ent); + SV_FlyMove(ent, sv.frametime, NULL); + SV_LinkEdict(ent, true); + } + } + else + { + // freefall if not onground + int hitsound = ent->fields.server->velocity[2] < sv_gravity.value * -0.1; - SV_AddGravity(ent); - SV_CheckVelocity(ent); - SV_FlyMove(ent, sv.frametime, NULL); - SV_LinkEdict(ent, true); + SV_AddGravity(ent); + SV_CheckVelocity(ent); + SV_FlyMove(ent, sv.frametime, NULL); + SV_LinkEdict(ent, true); - // just hit ground - if (hitsound && (int)ent->fields.server->flags & FL_ONGROUND && gamemode != GAME_NEXUIZ) - SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1); + // just hit ground + if (hitsound && (int)ent->fields.server->flags & FL_ONGROUND && sv_sound_land.string) + SV_StartSound(ent, 0, sv_sound_land.string, 255, 1); + } } // regular thinking @@ -1327,38 +1420,92 @@ void SV_Physics_Step (prvm_edict_t *ent) //============================================================================ -void SV_Physics_Entity (prvm_edict_t *ent, qboolean runmove) +static void SV_Physics_Entity (prvm_edict_t *ent) { - int i = ent - prog->edicts; - if (i >= 1 && i <= svs.maxclients) + // don't run a move on newly spawned projectiles as it messes up movement + // interpolation and rocket trails + qboolean runmove = ent->priv.server->move; + ent->priv.server->move = true; + switch ((int) ent->fields.server->movetype) { - // make sure the velocity is sane (not a NaN) - SV_CheckVelocity(ent); - // LordHavoc: QuakeC replacement for SV_ClientThink (player movement) - if (SV_PlayerPhysicsQC && sv_playerphysicsqc.integer) + case MOVETYPE_PUSH: + case MOVETYPE_FAKEPUSH: + SV_Physics_Pusher (ent); + break; + case MOVETYPE_NONE: + // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects + if (ent->fields.server->nextthink > 0 && ent->fields.server->nextthink <= sv.time + sv.frametime) + SV_RunThink (ent); + break; + case MOVETYPE_FOLLOW: + SV_Physics_Follow (ent); + break; + case MOVETYPE_NOCLIP: + if (SV_RunThink(ent)) { - prog->globals.server->time = sv.time; - prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); - PRVM_ExecuteProgram ((func_t)(SV_PlayerPhysicsQC - prog->functions), "QC function SV_PlayerPhysics is missing"); + SV_CheckWater(ent); + VectorMA(ent->fields.server->origin, sv.frametime, ent->fields.server->velocity, ent->fields.server->origin); + VectorMA(ent->fields.server->angles, sv.frametime, ent->fields.server->avelocity, ent->fields.server->angles); } - else - SV_ClientThink (); - // make sure the velocity is sane (not a NaN) - SV_CheckVelocity(ent); - // LordHavoc: a hack to ensure that the (rather silly) id1 quakec - // player_run/player_stand1 does not horribly malfunction if the - // velocity becomes a number that is both == 0 and != 0 - // (sounds to me like NaN but to be absolutely safe...) - if (DotProduct(ent->fields.server->velocity, ent->fields.server->velocity) < 0.0001) - VectorClear(ent->fields.server->velocity); - // call standard client pre-think + SV_LinkEdict(ent, false); + break; + case MOVETYPE_STEP: + SV_Physics_Step (ent); + break; + case MOVETYPE_WALK: + if (SV_RunThink (ent)) + { + if (!SV_CheckWater (ent) && ! ((int)ent->fields.server->flags & FL_WATERJUMP) ) + SV_AddGravity (ent); + SV_CheckStuck (ent); + SV_WalkMove (ent); + SV_LinkEdict (ent, true); + } + break; + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + case MOVETYPE_BOUNCEMISSILE: + case MOVETYPE_FLYMISSILE: + case MOVETYPE_FLY: + // regular thinking + if (SV_RunThink (ent) && runmove) + SV_Physics_Toss (ent); + break; + default: + Con_Printf ("SV_Physics: bad movetype %i\n", (int)ent->fields.server->movetype); + break; + } +} + +void SV_ApplyClientMove (void); +void SV_Physics_ClientEntity (prvm_edict_t *ent) +{ + SV_ApplyClientMove(); + // make sure the velocity is sane (not a NaN) + SV_CheckVelocity(ent); + // LordHavoc: QuakeC replacement for SV_ClientThink (player movement) + if (SV_PlayerPhysicsQC && sv_playerphysicsqc.integer) + { prog->globals.server->time = sv.time; prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); - PRVM_ExecuteProgram (prog->globals.server->PlayerPreThink, "QC function PlayerPreThink is missing"); - SV_CheckVelocity (ent); + PRVM_ExecuteProgram ((func_t)(SV_PlayerPhysicsQC - prog->functions), "QC function SV_PlayerPhysics is missing"); } + else + SV_ClientThink (); + // make sure the velocity is sane (not a NaN) + SV_CheckVelocity(ent); + // LordHavoc: a hack to ensure that the (rather silly) id1 quakec + // player_run/player_stand1 does not horribly malfunction if the + // velocity becomes a number that is both == 0 and != 0 + // (sounds to me like NaN but to be absolutely safe...) + if (DotProduct(ent->fields.server->velocity, ent->fields.server->velocity) < 0.0001) + VectorClear(ent->fields.server->velocity); + // call standard client pre-think + prog->globals.server->time = sv.time; + prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); + PRVM_ExecuteProgram (prog->globals.server->PlayerPreThink, "QC function PlayerPreThink is missing"); + SV_CheckVelocity (ent); - // LordHavoc: merged client and normal entity physics switch ((int) ent->fields.server->movetype) { case MOVETYPE_PUSH: @@ -1380,9 +1527,6 @@ void SV_Physics_Entity (prvm_edict_t *ent, qboolean runmove) VectorMA(ent->fields.server->origin, sv.frametime, ent->fields.server->velocity, ent->fields.server->origin); VectorMA(ent->fields.server->angles, sv.frametime, ent->fields.server->avelocity, ent->fields.server->angles); } - // relink normal entities here, players always get relinked so don't relink twice - if (!(i > 0 && i <= svs.maxclients)) - SV_LinkEdict(ent, false); break; case MOVETYPE_STEP: SV_Physics_Step (ent); @@ -1394,9 +1538,6 @@ void SV_Physics_Entity (prvm_edict_t *ent, qboolean runmove) SV_AddGravity (ent); SV_CheckStuck (ent); SV_WalkMove (ent); - // relink normal entities here, players always get relinked so don't relink twice - if (!(i > 0 && i <= svs.maxclients)) - SV_LinkEdict (ent, true); } break; case MOVETYPE_TOSS: @@ -1404,42 +1545,33 @@ void SV_Physics_Entity (prvm_edict_t *ent, qboolean runmove) case MOVETYPE_BOUNCEMISSILE: case MOVETYPE_FLYMISSILE: // regular thinking - if (SV_RunThink (ent) && runmove) + if (SV_RunThink (ent)) SV_Physics_Toss (ent); break; case MOVETYPE_FLY: - if (SV_RunThink (ent) && runmove) + if (SV_RunThink (ent)) { - if (i > 0 && i <= svs.maxclients) - { - SV_CheckWater (ent); - SV_WalkMove (ent); - } - else - SV_Physics_Toss (ent); + SV_CheckWater (ent); + SV_WalkMove (ent); } break; default: - Con_Printf ("SV_Physics: bad movetype %i", (int)ent->fields.server->movetype); + Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)ent->fields.server->movetype); break; } - if (i >= 1 && i <= svs.maxclients) - { - SV_CheckVelocity (ent); + SV_CheckVelocity (ent); - // call standard player post-think - SV_LinkEdict (ent, true); + // call standard player post-think + SV_LinkEdict (ent, true); - SV_CheckVelocity (ent); + SV_CheckVelocity (ent); - prog->globals.server->time = sv.time; - prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); - PRVM_ExecuteProgram (prog->globals.server->PlayerPostThink, "QC function PlayerPostThink is missing"); - } + prog->globals.server->time = sv.time; + prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); + PRVM_ExecuteProgram (prog->globals.server->PlayerPostThink, "QC function PlayerPostThink is missing"); } - /* ================ SV_Physics @@ -1448,9 +1580,8 @@ SV_Physics */ void SV_Physics (void) { - int i, newnum_edicts; + int i; prvm_edict_t *ent; - qbyte runmove[MAX_EDICTS]; // let the progs know that a new frame has started prog->globals.server->self = PRVM_EDICT_TO_PROG(prog->edicts); @@ -1459,43 +1590,36 @@ void SV_Physics (void) prog->globals.server->frametime = sv.frametime; PRVM_ExecuteProgram (prog->globals.server->StartFrame, "QC function StartFrame is missing"); - newnum_edicts = 0; - for (i = 0, ent = prog->edicts;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) - if ((runmove[i] = !ent->priv.server->free)) - newnum_edicts = i + 1; - prog->num_edicts = max(svs.maxclients + 1, newnum_edicts); - // // treat each object in turn // - for (i = 0, ent = prog->edicts;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) - { - if (ent->priv.server->free) - continue; - - if (prog->globals.server->force_retouch) - SV_LinkEdict (ent, true); // force retouch even for stationary + // if force_retouch, relink all the entities + if (prog->globals.server->force_retouch > 0) + for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + if (!ent->priv.server->free) + SV_LinkEdict (ent, true); // force retouch even for stationary - if (i >= 1 && i <= svs.maxclients) + // run physics on the client entities + for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++) + { + if (!ent->priv.server->free) { - host_client = svs.clients + i - 1; // don't do physics on disconnected clients, FrikBot relies on this if (!host_client->spawned) - { memset(&host_client->cmd, 0, sizeof(host_client->cmd)); - continue; - } - // connected slot - if (host_client->movesequence) - continue; // return if running asynchronously + // don't run physics here if running asynchronously + else if (!host_client->movesequence) + SV_Physics_ClientEntity(ent); } - else if (sv_freezenonclients.integer) - continue; - - SV_Physics_Entity(ent, runmove[i]); } + // run physics on all the non-client entities + if (!sv_freezenonclients.integer) + for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + if (!ent->priv.server->free) + SV_Physics_Entity(ent); + if (prog->globals.server->force_retouch > 0) prog->globals.server->force_retouch = max(0, prog->globals.server->force_retouch - 1); @@ -1508,6 +1632,9 @@ void SV_Physics (void) PRVM_ExecuteProgram ((func_t)(EndFrameQC - prog->functions), "QC function EndFrame is missing"); } + // decrement prog->num_edicts if the highest number entities died + for (;PRVM_EDICT_NUM(prog->num_edicts - 1)->priv.server->free;prog->num_edicts--); + if (!sv_freezenonclients.integer) sv.time += sv.frametime; }