/** * 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. FIXME: is this * true? */ public static void SV_Physics_Step(edict_t ent) { bool wasonground; var hitsound = false; float[] vel; float speed, newspeed, control; float friction; edict_t groundentity; int mask; // airborn monsters should always check for ground if (ent.groundentity == null) { M.M_CheckGround(ent); } groundentity = ent.groundentity; SV.SV_CheckVelocity(ent); if (groundentity != null) { wasonground = true; } else { wasonground = false; } if (ent.avelocity[0] != 0 || ent.avelocity[1] != 0 || ent.avelocity[2] != 0) { SV.SV_AddRotationalFriction(ent); } // add gravity except: // flying monsters // swimming monsters who are in the water if (!wasonground) { if (0 == (ent.flags & Defines.FL_FLY)) { if (!((ent.flags & Defines.FL_SWIM) != 0 && ent.waterlevel > 2)) { if (ent.velocity[2] < GameBase.sv_gravity.value * -0.1) { hitsound = true; } if (ent.waterlevel == 0) { SV.SV_AddGravity(ent); } } } } // friction for flying monsters that have been given vertical velocity if ((ent.flags & Defines.FL_FLY) != 0 && ent.velocity[2] != 0) { speed = Math.Abs(ent.velocity[2]); control = speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; friction = Defines.sv_friction / 3; newspeed = speed - Defines.FRAMETIME * control * friction; if (newspeed < 0) { newspeed = 0; } newspeed /= speed; ent.velocity[2] *= newspeed; } // friction for flying monsters that have been given vertical velocity if ((ent.flags & Defines.FL_SWIM) != 0 && ent.velocity[2] != 0) { speed = Math.Abs(ent.velocity[2]); control = speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; newspeed = speed - Defines.FRAMETIME * control * Defines.sv_waterfriction * ent.waterlevel; if (newspeed < 0) { newspeed = 0; } newspeed /= speed; ent.velocity[2] *= newspeed; } if (ent.velocity[2] != 0 || ent.velocity[1] != 0 || ent.velocity[0] != 0) { // apply friction // let dead monsters who aren't completely onground slide if (wasonground || 0 != (ent.flags & (Defines.FL_SWIM | Defines.FL_FLY))) { if (!(ent.health <= 0.0 && !M.M_CheckBottom(ent))) { vel = ent.velocity; speed = (float)Math.Sqrt(vel[0] * vel[0] + vel[1] * vel[1]); if (speed != 0) { friction = Defines.sv_friction; control = speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; newspeed = speed - Defines.FRAMETIME * control * friction; if (newspeed < 0) { newspeed = 0; } newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } } if ((ent.svflags & Defines.SVF_MONSTER) != 0) { mask = Defines.MASK_MONSTERSOLID; } else { mask = Defines.MASK_SOLID; } SV.SV_FlyMove(ent, Defines.FRAMETIME, mask); GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); if (!ent.inuse) { return; } if (ent.groundentity != null) { if (!wasonground) { if (hitsound) { GameBase.gi.sound(ent, 0, GameBase.gi.soundindex("world/land.wav"), 1, 1, 0); } } } } // regular thinking SV.SV_RunThink(ent); }
/** * Toss, bounce, and fly movement. When onground, do nothing. */ public static void SV_Physics_Toss(edict_t ent) { trace_t trace; float[] move = { 0, 0, 0 }; float backoff; edict_t slave; bool wasinwater; bool isinwater; float[] old_origin = { 0, 0, 0 }; // regular thinking SV.SV_RunThink(ent); // if not a team captain, so movement will be handled elsewhere if ((ent.flags & Defines.FL_TEAMSLAVE) != 0) { return; } if (ent.velocity[2] > 0) { ent.groundentity = null; } // check for the groundentity going away if (ent.groundentity != null) { if (!ent.groundentity.inuse) { ent.groundentity = null; } } // if onground, return without moving if (ent.groundentity != null) { return; } Math3D.VectorCopy(ent.s.origin, old_origin); SV.SV_CheckVelocity(ent); // add gravity if (ent.movetype != Defines.MOVETYPE_FLY && ent.movetype != Defines.MOVETYPE_FLYMISSILE) { SV.SV_AddGravity(ent); } // move angles Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, ent.s.angles); // move origin Math3D.VectorScale(ent.velocity, Defines.FRAMETIME, move); trace = SV.SV_PushEntity(ent, move); if (!ent.inuse) { return; } if (trace.fraction < 1) { if (ent.movetype == Defines.MOVETYPE_BOUNCE) { backoff = 1.5f; } else { backoff = 1; } GameBase.ClipVelocity(ent.velocity, trace.plane.normal, ent.velocity, backoff); // stop if on ground if (trace.plane.normal[2] > 0.7) { if (ent.velocity[2] < 60 || ent.movetype != Defines.MOVETYPE_BOUNCE) { ent.groundentity = trace.ent; ent.groundentity_linkcount = trace.ent.linkcount; Math3D.VectorCopy(Globals.vec3_origin, ent.velocity); Math3D.VectorCopy(Globals.vec3_origin, ent.avelocity); } } // if (ent.touch) // ent.touch (ent, trace.ent, &trace.plane, trace.surface); } // check for water transition wasinwater = (ent.watertype & Defines.MASK_WATER) != 0; ent.watertype = GameBase.gi.pointcontents(ent.s.origin); isinwater = (ent.watertype & Defines.MASK_WATER) != 0; if (isinwater) { ent.waterlevel = 1; } else { ent.waterlevel = 0; } if (!wasinwater && isinwater) { GameBase.gi.positioned_sound(old_origin, ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); } else if (wasinwater && !isinwater) { GameBase.gi.positioned_sound(ent.s.origin, ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); } // move teamslaves for (slave = ent.teamchain; slave != null; slave = slave.teamchain) { Math3D.VectorCopy(ent.s.origin, slave.s.origin); GameBase.gi.linkentity(slave); } }