X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=sv_phys.c;h=ffc4123f6f6ed70b09d29f90f1876e2719de46a0;hb=2cda7ccb571b41372e2ee91edf1bf59ad6452c07;hp=6c2d933b6660540ac84a916dc09a8abb2ccea8bb;hpb=01349d19335a49f7d474c4e233705e85c222ec31;p=xonotic%2Fdarkplaces.git diff --git a/sv_phys.c b/sv_phys.c index 6c2d933b..ffc4123f 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -39,44 +39,10 @@ solid_edge items only clip against bsp models. */ -cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4", "how fast you slow down"}; -cvar_t sv_waterfriction = {CVAR_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"}; -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_debugmove = {CVAR_NOTIFY, "sv_debugmove", "0", "disables collision detection optimizations for debugging purposes"}; - -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)"}; - -// TODO: move this extern to server.h -extern cvar_t sv_clmovement_waitforinput; - #define MOVE_EPSILON 0.01 void SV_Physics_Toss (prvm_edict_t *ent); -void SV_Phys_Init (void) -{ - Cvar_RegisterVariable(&sv_stepheight); - Cvar_RegisterVariable(&sv_jumpstep); - Cvar_RegisterVariable(&sv_wallfriction); - Cvar_RegisterVariable(&sv_newflymove); - Cvar_RegisterVariable(&sv_freezenonclients); - Cvar_RegisterVariable(&sv_playerphysicsqc); - Cvar_RegisterVariable(&sv_debugmove); - - Cvar_RegisterVariable(&sv_sound_watersplash); - Cvar_RegisterVariable(&sv_sound_land); -} - /* =============================================================================== @@ -141,14 +107,11 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const // matrices to transform into/out of other entity's space matrix4x4_t matrix, imatrix; // model of other entity - model_t *model; + dp_model_t *model; // list of entities to test for collisions int numtouchedicts; prvm_edict_t *touchedicts[MAX_EDICTS]; - // Get Allow Touch with Owner - int nAllowTouchWithOwner = PRVM_EDICTFIELDVALUE(passedict, prog->fieldoffsets.allowtouchwithowner)->_int; - VectorCopy(start, clipstart); VectorCopy(end, clipend); VectorCopy(mins, clipmins); @@ -235,10 +198,10 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const if (passedict == touch) continue; // don't clip owned entities against owner - if (!nAllowTouchWithOwner && traceowner == touch) + if (traceowner == touch) continue; // don't clip owner against owned entities - if (!nAllowTouchWithOwner && passedictprog == touch->fields.server->owner) + if (passedictprog == touch->fields.server->owner) continue; // don't clip points against points (they can't collide) if (pointtrace && VectorCompare(touch->fields.server->mins, touch->fields.server->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.server->flags & FL_MONSTER))) @@ -292,6 +255,63 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const } #endif +int SV_PointSuperContents(const vec3_t point) +{ + int supercontents = 0; + int i; + prvm_edict_t *touch; + vec3_t transformed; + // matrices to transform into/out of other entity's space + matrix4x4_t matrix, imatrix; + // model of other entity + dp_model_t *model; + unsigned int modelindex; + int frame; + // list of entities to test for collisions + int numtouchedicts; + prvm_edict_t *touchedicts[MAX_EDICTS]; + + // get world supercontents at this point + if (sv.worldmodel && sv.worldmodel->PointSuperContents) + supercontents = sv.worldmodel->PointSuperContents(sv.worldmodel, 0, point); + + // if sv_gameplayfix_swiminbmodels is off we're done + if (!sv_gameplayfix_swiminbmodels.integer) + return supercontents; + + // get list of entities at this point + numtouchedicts = World_EntitiesInBox(&sv.world, point, point, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + + // we only care about SOLID_BSP for pointcontents + if (touch->fields.server->solid != SOLID_BSP) + continue; + + // might interact, so do an exact clip + modelindex = (unsigned int)touch->fields.server->modelindex; + if (modelindex >= MAX_MODELS) + continue; + model = sv.models[(int)touch->fields.server->modelindex]; + if (!model || !model->PointSuperContents) + continue; + Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + Matrix4x4_Transform(&imatrix, point, transformed); + frame = (int)touch->fields.server->frame; + supercontents |= model->PointSuperContents(model, bound(0, frame, (model->numframes - 1)), transformed); + } + + return supercontents; +} + /* =============================================================================== @@ -306,7 +326,7 @@ void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent) prvm_edict_t *touch, *touchedicts[MAX_EDICTS]; // build a list of edicts to touch, because the link loop can be corrupted - // by SV_IncreaseEdicts called during touch functions + // by IncreaseEdicts called during touch functions numtouchedicts = World_EntitiesInBox(&sv.world, ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts); if (numtouchedicts > MAX_EDICTS) { @@ -358,7 +378,7 @@ SV_LinkEdict */ void SV_LinkEdict (prvm_edict_t *ent, qboolean touch_triggers) { - model_t *model; + dp_model_t *model; vec3_t mins, maxs; if (ent == prog->edicts) @@ -380,7 +400,7 @@ void SV_LinkEdict (prvm_edict_t *ent, qboolean touch_triggers) model = sv.models[modelindex]; if (model != NULL) { - if (!model->TraceBox) + if (!model->TraceBox && developer.integer >= 1) Con_Printf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent)); if (ent->fields.server->angles[0] || ent->fields.server->angles[2] || ent->fields.server->avelocity[0] || ent->fields.server->avelocity[2]) @@ -560,6 +580,8 @@ int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents) PRVM_G_FLOAT(OFS_PARM0) = ent->fields.server->watertype; // New Contents PRVM_G_FLOAT(OFS_PARM1) = nContents; + // Assign Self + prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); // Execute VM Function PRVM_ExecuteProgram(contentstransition->function, "contentstransition: NULL function"); } @@ -587,12 +609,12 @@ void SV_CheckVelocity (prvm_edict_t *ent) { if (IS_NAN(ent->fields.server->velocity[i])) { - Con_Printf("Got a NaN velocity on %s\n", PRVM_GetString(ent->fields.server->classname)); + Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(ent->fields.server->classname)); ent->fields.server->velocity[i] = 0; } if (IS_NAN(ent->fields.server->origin[i])) { - Con_Printf("Got a NaN origin on %s\n", PRVM_GetString(ent->fields.server->classname)); + Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(ent->fields.server->classname)); ent->fields.server->origin[i] = 0; } } @@ -620,22 +642,27 @@ Returns false if the entity removed itself. */ qboolean SV_RunThink (prvm_edict_t *ent) { - float thinktime; - - thinktime = ent->fields.server->nextthink; - if (thinktime <= 0 || thinktime > sv.time + sv.frametime) - return true; + int iterations; // don't let things stay in the past. // it is possible to start that way by a trigger with a local time. - if (thinktime < sv.time) - thinktime = sv.time; + if (ent->fields.server->nextthink <= 0 || ent->fields.server->nextthink > sv.time + sv.frametime) + return true; - ent->fields.server->nextthink = 0; - prog->globals.server->time = thinktime; - prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); - prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts); - PRVM_ExecuteProgram (ent->fields.server->think, "QC function self.think is missing"); + for (iterations = 0;iterations < 128 && !ent->priv.server->free;iterations++) + { + prog->globals.server->time = max(sv.time, ent->fields.server->nextthink); + ent->fields.server->nextthink = 0; + prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); + prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts); + PRVM_ExecuteProgram (ent->fields.server->think, "QC function self.think is missing"); + // mods often set nextthink to time to cause a think every frame, + // we don't want to loop in that case, so exit if the new nextthink is + // <= the time the qc was told, also exit if it is past the end of the + // frame + if (ent->fields.server->nextthink <= prog->globals.server->time || ent->fields.server->nextthink > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer) + break; + } return !ent->priv.server->free; } @@ -647,14 +674,17 @@ Two entities have touched, so run their touch functions ================== */ extern void VM_SetTraceGlobals(const trace_t *trace); +extern sizebuf_t vm_tempstringsbuf; void SV_Impact (prvm_edict_t *e1, trace_t *trace) { + int restorevm_tempstringsbuf_cursize; int old_self, old_other; prvm_edict_t *e2 = (prvm_edict_t *)trace->ent; prvm_eval_t *val; old_self = prog->globals.server->self; old_other = prog->globals.server->other; + restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; VM_SetTraceGlobals(trace); @@ -687,6 +717,7 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace) prog->globals.server->self = old_self; prog->globals.server->other = old_other; + vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; } @@ -947,7 +978,7 @@ int SV_FlyMove (prvm_edict_t *ent, float time, float *stepnormal, int hitsuperco */ // LordHavoc: this came from QW and allows you to get out of water more easily - if (sv_gameplayfix_qwplayerphysics.integer && ((int)ent->fields.server->flags & FL_WATERJUMP)) + if (sv_gameplayfix_easierwaterjump.integer && ((int)ent->fields.server->flags & FL_WATERJUMP)) VectorCopy(primal_velocity, ent->fields.server->velocity); return blocked; } @@ -1024,14 +1055,17 @@ SV_PushMove void SV_PushMove (prvm_edict_t *pusher, float movetime) { int i, e, index; + int checkcontents; + qboolean rotated; float savesolid, movetime2, pushltime; 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]; - model_t *pushermodel; + dp_model_t *pushermodel; trace_t trace; matrix4x4_t pusherfinalmatrix, pusherfinalimatrix; + unsigned short moved_edicts[MAX_EDICTS]; if (!pusher->fields.server->velocity[0] && !pusher->fields.server->velocity[1] && !pusher->fields.server->velocity[2] && !pusher->fields.server->avelocity[0] && !pusher->fields.server->avelocity[1] && !pusher->fields.server->avelocity[2]) { @@ -1070,6 +1104,8 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) } pushermodel = sv.models[index]; + rotated = VectorLength2(pusher->fields.server->angles) + VectorLength2(pusher->fields.server->avelocity) > 0; + movetime2 = movetime; VectorScale(pusher->fields.server->velocity, movetime2, move1); VectorScale(pusher->fields.server->avelocity, movetime2, moveangle); @@ -1158,18 +1194,28 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) || check->fields.server->movetype == MOVETYPE_FAKEPUSH) continue; + //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(check->fields.server->classname)); + + // tell any MOVETYPE_STEP entity that it may need to check for water transitions + check->priv.server->waterposition_forceupdate = true; + + checkcontents = SV_GenericHitSuperContentsMask(check); + // if the entity is standing on the pusher, it will definitely be moved // if the entity is not standing on the pusher, but is in the pusher's // final position, move it if (!((int)check->fields.server->flags & FL_ONGROUND) || PRVM_PROG_TO_EDICT(check->fields.server->groundentity) != pusher) { - Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY); + Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents); + //trace = SV_Move(check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, MOVE_NOMONSTERS, check, checkcontents); if (!trace.startsolid) + { + //Con_Printf("- not in solid\n"); continue; + } } - - if (forward[0] != 1 || left[1] != 1) // quick way to check if any rotation is used + if (rotated) { vec3_t org2; VectorSubtract (check->fields.server->origin, pusher->fields.server->origin, org); @@ -1182,9 +1228,11 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) else VectorCopy (move1, move); + //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]); + 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; + moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check); // try moving the contacted entity pusher->fields.server->solid = SOLID_NOT; @@ -1201,7 +1249,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) check->fields.server->flags = (int)check->fields.server->flags & ~FL_ONGROUND; // if it is still inside the pusher, block - Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY); + Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents); if (trace.startsolid) { // try moving the contacted entity a tiny bit further to account for precision errors @@ -1212,7 +1260,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); SV_PushEntity (check, move2, true); pusher->fields.server->solid = savesolid; - Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY); + Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents); if (trace.startsolid) { // try moving the contacted entity a tiny bit less to account for precision errors @@ -1222,7 +1270,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); SV_PushEntity (check, move2, true); pusher->fields.server->solid = savesolid; - Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY); + Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents); if (trace.startsolid) { // still inside pusher, so it's really blocked @@ -1246,7 +1294,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) // move back any entities we already moved for (i = 0;i < num_moved;i++) { - prvm_edict_t *ed = sv.moved_edicts[i]; + prvm_edict_t *ed = PRVM_EDICT_NUM(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); @@ -1326,21 +1374,37 @@ static float unstickoffsets[] = 1, 1, 0, 0, 0, -1, 0, 0, 1, + 0, 0, -2, 0, 0, 2, + 0, 0, -3, 0, 0, 3, + 0, 0, -4, 0, 0, 4, + 0, 0, -5, 0, 0, 5, + 0, 0, -6, 0, 0, 6, + 0, 0, -7, 0, 0, 7, + 0, 0, -8, 0, 0, 8, + 0, 0, -9, 0, 0, 9, + 0, 0, -10, 0, 0, 10, + 0, 0, -11, 0, 0, 11, + 0, 0, -12, 0, 0, 12, + 0, 0, -13, 0, 0, 13, + 0, 0, -14, 0, 0, 14, + 0, 0, -15, 0, 0, 15, + 0, 0, -16, 0, 0, 16, + 0, 0, -17, 0, 0, 17, }; @@ -1384,13 +1448,13 @@ void SV_CheckStuck (prvm_edict_t *ent) Con_DPrintf("Stuck player 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) +qboolean SV_UnstickEntity (prvm_edict_t *ent) { int i; // if not stuck in a bmodel, just return if (!SV_TestEntityPosition(ent, vec3_origin)) - return; + return true; for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3) { @@ -1398,12 +1462,13 @@ static void SV_UnstickEntity (prvm_edict_t *ent) { Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2]); SV_LinkEdict (ent, true); - return; + return true; } } if (developer.integer >= 100) Con_Printf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); + return false; } @@ -1926,6 +1991,13 @@ will fall if the floor is pulled out from under them. void SV_Physics_Step (prvm_edict_t *ent) { int flags = (int)ent->fields.server->flags; + + // DRESK + // Backup Velocity in the event that movetypesteplandevent is called, + // to provide a parameter with the entity's velocity at impact. + prvm_eval_t *movetypesteplandevent; + vec3_t backupVelocity; + VectorCopy(ent->fields.server->velocity, backupVelocity); // don't fall at all if fly/swim if (!(flags & (FL_FLY | FL_SWIM))) { @@ -1940,6 +2012,7 @@ void SV_Physics_Step (prvm_edict_t *ent) SV_CheckVelocity(ent); SV_FlyMove(ent, sv.frametime, NULL, SV_GenericHitSuperContentsMask(ent)); SV_LinkEdict(ent, true); + ent->priv.server->waterposition_forceupdate = true; } } else @@ -1953,15 +2026,42 @@ void SV_Physics_Step (prvm_edict_t *ent) SV_LinkEdict(ent, true); // 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); + if (hitsound && (int)ent->fields.server->flags & FL_ONGROUND) + { + // DRESK - Check for Entity Land Event Function + movetypesteplandevent = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.movetypesteplandevent); + + if(movetypesteplandevent->function) + { // Valid Function; Execute + // Prepare Parameters + // Assign Velocity at Impact + PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0]; + PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1]; + PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2]; + // Assign Self + prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); + // Execute VM Function + PRVM_ExecuteProgram(movetypesteplandevent->function, "movetypesteplandevent: NULL function"); + } + else + // Check for Engine Landing Sound + if(sv_sound_land.string) + SV_StartSound(ent, 0, sv_sound_land.string, 255, 1); + } + ent->priv.server->waterposition_forceupdate = true; } } // regular thinking - SV_RunThink(ent); + if (!SV_RunThink(ent)) + return; - SV_CheckWaterTransition(ent); + if (ent->priv.server->waterposition_forceupdate || !VectorCompare(ent->fields.server->origin, ent->priv.server->waterposition_origin)) + { + ent->priv.server->waterposition_forceupdate = false; + VectorCopy(ent->fields.server->origin, ent->priv.server->waterposition_origin); + SV_CheckWaterTransition(ent); + } } //============================================================================ @@ -2014,7 +2114,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent) case MOVETYPE_FLYMISSILE: case MOVETYPE_FLY: // regular thinking - if (SV_RunThink (ent) && runmove) + if (SV_RunThink (ent) && (runmove || !sv_gameplayfix_delayprojectiles.integer)) SV_Physics_Toss (ent); break; default: @@ -2090,7 +2190,10 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent) // don't run physics here if running asynchronously if (host_client->clmovement_skipphysicsframes <= 0) + { SV_ClientThink(); + //host_client->cmd.time = max(host_client->cmd.time, sv.time); + } // make sure the velocity is sane (not a NaN) SV_CheckVelocity(ent);