コード例 #1
0
ファイル: SV.cs プロジェクト: optimus-code/Quake2Sharp
        /**
         * A moving object that doesn't obey physics.
         */
        public static void SV_Physics_Noclip(edict_t ent)
        {
            //	   regular thinking
            if (!SV.SV_RunThink(ent))
            {
                return;
            }

            Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, ent.s.angles);
            Math3D.VectorMA(ent.s.origin, Defines.FRAMETIME, ent.velocity, ent.s.origin);

            GameBase.gi.linkentity(ent);
        }
コード例 #2
0
ファイル: SV.cs プロジェクト: optimus-code/Quake2Sharp
        /**
         * Turns to the movement direction, and walks the current distance if facing
         * it.
         */
        public static bool SV_StepDirection(edict_t ent, float yaw, float dist)
        {
            float[] move      = { 0, 0, 0 };
            float[] oldorigin = { 0, 0, 0 };
            float   delta;

            ent.ideal_yaw = yaw;
            M.M_ChangeYaw(ent);

            yaw     = (float)(yaw * Math.PI * 2 / 360);
            move[0] = (float)Math.Cos(yaw) * dist;
            move[1] = (float)Math.Sin(yaw) * dist;
            move[2] = 0;

            Math3D.VectorCopy(ent.s.origin, oldorigin);

            if (SV.SV_movestep(ent, move, false))
            {
                delta = ent.s.angles[Defines.YAW] - ent.ideal_yaw;

                if (delta > 45 && delta < 315)
                {
                    // not turned far enough, so don't
                    // take the step
                    Math3D.VectorCopy(oldorigin, ent.s.origin);
                }

                GameBase.gi.linkentity(ent);
                GameBase.G_TouchTriggers(ent);

                return(true);
            }

            GameBase.gi.linkentity(ent);
            GameBase.G_TouchTriggers(ent);

            return(false);
        }
コード例 #3
0
ファイル: SV.cs プロジェクト: optimus-code/Quake2Sharp
        /**
         * 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);
        }
コード例 #4
0
ファイル: SV.cs プロジェクト: optimus-code/Quake2Sharp
        /**
         * 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);
            }
        }
コード例 #5
0
ファイル: SV.cs プロジェクト: optimus-code/Quake2Sharp
 /**
  * Non moving objects can only think.
  */
 public static void SV_Physics_None(edict_t ent)
 {
     // regular thinking
     SV.SV_RunThink(ent);
 }
コード例 #6
0
ファイル: SV.cs プロジェクト: optimus-code/Quake2Sharp
        /**
         *
         * Bmodel objects don't interact with each other, but push all box objects.
         */
        public static void SV_Physics_Pusher(edict_t ent)
        {
            float[] move = { 0, 0, 0 };
            float[] amove = { 0, 0, 0 };
            edict_t part, mv;

            // if not a team captain, so movement will be handled elsewhere
            if ((ent.flags & Defines.FL_TEAMSLAVE) != 0)
            {
                return;
            }

            // make sure all team slaves can move before commiting
            // any moves or calling any think functions
            // if the move is blocked, all moved objects will be backed out
            //	  retry:
            GameBase.pushed_p = 0;

            for (part = ent; part != null; part = part.teamchain)
            {
                if (part.velocity[0] != 0 ||
                    part.velocity[1] != 0 ||
                    part.velocity[2] != 0 ||
                    part.avelocity[0] != 0 ||
                    part.avelocity[1] != 0 ||
                    part.avelocity[2] != 0)
                {
                    // object
                    // is
                    // moving
                    Math3D.VectorScale(part.velocity, Defines.FRAMETIME, move);
                    Math3D.VectorScale(part.avelocity, Defines.FRAMETIME, amove);

                    if (!SV.SV_Push(part, move, amove))
                    {
                        break;                         // move was blocked
                    }
                }
            }

            if (GameBase.pushed_p > Defines.MAX_EDICTS)
            {
                SV_GAME.PF_error(Defines.ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
            }

            if (part != null)
            {
                // the move failed, bump all nextthink times and back out moves
                for (mv = ent; mv != null; mv = mv.teamchain)
                {
                    if (mv.nextthink > 0)
                    {
                        mv.nextthink += Defines.FRAMETIME;
                    }
                }

                // if the pusher has a "blocked" function, call it
                // otherwise, just stay in place until the obstacle is gone
                if (part.blocked != null)
                {
                    part.blocked.blocked(part, GameBase.obstacle);
                }
            }
            else
            {
                // the move succeeded, so call all think functions
                for (part = ent; part != null; part = part.teamchain)
                {
                    SV.SV_RunThink(part);
                }
            }
        }
コード例 #7
0
ファイル: SV.cs プロジェクト: optimus-code/Quake2Sharp
        /**
         * Objects need to be moved back on a failed push, otherwise riders would
         * continue to slide.
         */
        public static bool SV_Push(edict_t pusher, float[] move, float[] amove)
        {
            int     i, e;
            edict_t check;

            edict_t[] block;
            float[]   mins = { 0, 0, 0 };
            float[]   maxs = { 0, 0, 0 };
            pushed_t  p;

            float[] org     = { 0, 0, 0 };
            float[] org2    = { 0, 0, 0 };
            float[] move2   = { 0, 0, 0 };
            float[] forward = { 0, 0, 0 };
            float[] right   = { 0, 0, 0 };
            float[] up      = { 0, 0, 0 };

            // clamp the move to 1/8 units, so the position will
            // be accurate for client side prediction
            for (i = 0; i < 3; i++)
            {
                float temp;
                temp = move[i] * 8.0f;

                if (temp > 0.0)
                {
                    temp += 0.5f;
                }
                else
                {
                    temp -= 0.5f;
                }

                move[i] = 0.125f * (int)temp;
            }

            // find the bounding box
            for (i = 0; i < 3; i++)
            {
                mins[i] = pusher.absmin[i] + move[i];
                maxs[i] = pusher.absmax[i] + move[i];
            }

            //	   we need this for pushing things later
            Math3D.VectorSubtract(Globals.vec3_origin, amove, org);
            Math3D.AngleVectors(org, forward, right, up);

            //	   save the pusher's original position
            GameBase.pushed[GameBase.pushed_p].ent = pusher;
            Math3D.VectorCopy(pusher.s.origin, GameBase.pushed[GameBase.pushed_p].origin);
            Math3D.VectorCopy(pusher.s.angles, GameBase.pushed[GameBase.pushed_p].angles);

            if (pusher.client != null)
            {
                GameBase.pushed[GameBase.pushed_p].deltayaw = pusher.client.ps.pmove.delta_angles[Defines.YAW];
            }

            GameBase.pushed_p++;

            //	   move the pusher to it's final position
            Math3D.VectorAdd(pusher.s.origin, move, pusher.s.origin);
            Math3D.VectorAdd(pusher.s.angles, amove, pusher.s.angles);
            GameBase.gi.linkentity(pusher);

            //	   see if any solid entities are inside the final position

            //check= g_edicts + 1;
            for (e = 1; e < GameBase.num_edicts; e++)
            {
                check = GameBase.g_edicts[e];

                if (!check.inuse)
                {
                    continue;
                }

                if (check.movetype == Defines.MOVETYPE_PUSH ||
                    check.movetype == Defines.MOVETYPE_STOP ||
                    check.movetype == Defines.MOVETYPE_NONE ||
                    check.movetype == Defines.MOVETYPE_NOCLIP)
                {
                    continue;
                }

                if (check.area.prev == null)
                {
                    continue;                     // not linked in anywhere
                }
                // if the entity is standing on the pusher, it will definitely be
                // moved
                if (check.groundentity != pusher)
                {
                    // see if the ent needs to be tested
                    if (check.absmin[0] >= maxs[0] ||
                        check.absmin[1] >= maxs[1] ||
                        check.absmin[2] >= maxs[2] ||
                        check.absmax[0] <= mins[0] ||
                        check.absmax[1] <= mins[1] ||
                        check.absmax[2] <= mins[2])
                    {
                        continue;
                    }

                    // see if the ent's bbox is inside the pusher's final position
                    if (SV.SV_TestEntityPosition(check) == null)
                    {
                        continue;
                    }
                }

                if (pusher.movetype == Defines.MOVETYPE_PUSH || check.groundentity == pusher)
                {
                    // move this entity
                    GameBase.pushed[GameBase.pushed_p].ent = check;
                    Math3D.VectorCopy(check.s.origin, GameBase.pushed[GameBase.pushed_p].origin);
                    Math3D.VectorCopy(check.s.angles, GameBase.pushed[GameBase.pushed_p].angles);
                    GameBase.pushed_p++;

                    // try moving the contacted entity
                    Math3D.VectorAdd(check.s.origin, move, check.s.origin);

                    if (check.client != null)
                    {
                        // FIXME: doesn't rotate monsters?
                        check.client.ps.pmove.delta_angles[Defines.YAW] += (short)amove[Defines.YAW];
                    }

                    // figure movement due to the pusher's amove
                    Math3D.VectorSubtract(check.s.origin, pusher.s.origin, org);
                    org2[0] = Math3D.DotProduct(org, forward);
                    org2[1] = -Math3D.DotProduct(org, right);
                    org2[2] = Math3D.DotProduct(org, up);
                    Math3D.VectorSubtract(org2, org, move2);
                    Math3D.VectorAdd(check.s.origin, move2, check.s.origin);

                    // may have pushed them off an edge
                    if (check.groundentity != pusher)
                    {
                        check.groundentity = null;
                    }

                    block = SV.SV_TestEntityPosition(check);

                    if (block == null)
                    {
                        // pushed ok
                        GameBase.gi.linkentity(check);

                        // impact?
                        continue;
                    }

                    // if it is ok to leave in the old position, do it
                    // this is only relevent for riding entities, not pushed
                    // FIXME: this doesn't acount for rotation
                    Math3D.VectorSubtract(check.s.origin, move, check.s.origin);
                    block = SV.SV_TestEntityPosition(check);

                    if (block == null)
                    {
                        GameBase.pushed_p--;

                        continue;
                    }
                }

                // save off the obstacle so we can call the block function
                GameBase.obstacle = check;

                // move back any entities we already moved
                // go backwards, so if the same entity was pushed
                // twice, it goes back to the original position
                for (var ip = GameBase.pushed_p - 1; ip >= 0; ip--)
                {
                    p = GameBase.pushed[ip];
                    Math3D.VectorCopy(p.origin, p.ent.s.origin);
                    Math3D.VectorCopy(p.angles, p.ent.s.angles);

                    if (p.ent.client != null)
                    {
                        p.ent.client.ps.pmove.delta_angles[Defines.YAW] = (short)p.deltayaw;
                    }

                    GameBase.gi.linkentity(p.ent);
                }

                return(false);
            }

            //	  FIXME: is there a better way to handle this?
            // see if anything we moved has touched a trigger
            for (var ip = GameBase.pushed_p - 1; ip >= 0; ip--)
            {
                GameBase.G_TouchTriggers(GameBase.pushed[ip].ent);
            }

            return(true);
        }
コード例 #8
0
ファイル: SV.cs プロジェクト: optimus-code/Quake2Sharp
        public static int SV_FlyMove(edict_t ent, float time, int mask)
        {
            edict_t hit;
            int     bumpcount, numbumps;

            float[] dir = { 0.0f, 0.0f, 0.0f };
            float   d;
            int     numplanes;
            var     planes = new float[SV.MAX_CLIP_PLANES][];

            float[] primal_velocity = { 0.0f, 0.0f, 0.0f };
            float[] original_velocity = { 0.0f, 0.0f, 0.0f };
            float[] new_velocity = { 0.0f, 0.0f, 0.0f };
            int     i, j;
            trace_t trace;

            float[] end = { 0.0f, 0.0f, 0.0f };
            float   time_left;
            int     blocked;

            for (var n = 0; n < planes.Length; n++)
            {
                planes[n] = new float[3];
            }

            numbumps = 4;

            blocked = 0;
            Math3D.VectorCopy(ent.velocity, original_velocity);
            Math3D.VectorCopy(ent.velocity, primal_velocity);
            numplanes = 0;

            time_left = time;

            ent.groundentity = null;

            for (bumpcount = 0; bumpcount < numbumps; bumpcount++)
            {
                for (i = 0; i < 3; i++)
                {
                    end[i] = ent.s.origin[i] + time_left * ent.velocity[i];
                }

                trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end, ent, mask);

                if (trace.allsolid)
                {
                    // entity is trapped in another solid
                    Math3D.VectorCopy(Globals.vec3_origin, ent.velocity);

                    return(3);
                }

                if (trace.fraction > 0)
                {
                    // actually covered some distance
                    Math3D.VectorCopy(trace.endpos, ent.s.origin);
                    Math3D.VectorCopy(ent.velocity, original_velocity);
                    numplanes = 0;
                }

                if (trace.fraction == 1)
                {
                    break;                     // moved the entire distance
                }
                hit = trace.ent;

                if (trace.plane.normal[2] > 0.7)
                {
                    blocked |= 1;                     // floor

                    if (hit.solid == Defines.SOLID_BSP)
                    {
                        ent.groundentity           = hit;
                        ent.groundentity_linkcount = hit.linkcount;
                    }
                }

                if (trace.plane.normal[2] == 0.0f)
                {
                    blocked |= 2;                     // step
                }
                //
                //	   run the impact function
                //
                SV.SV_Impact(ent, trace);

                if (!ent.inuse)
                {
                    break;                     // removed by the impact function
                }
                time_left -= time_left * trace.fraction;

                // cliped to another plane
                if (numplanes >= SV.MAX_CLIP_PLANES)
                {
                    // this shouldn't
                    // really happen
                    Math3D.VectorCopy(Globals.vec3_origin, ent.velocity);

                    return(3);
                }

                Math3D.VectorCopy(trace.plane.normal, planes[numplanes]);
                numplanes++;

                //
                //	   modify original_velocity so it parallels all of the clip planes
                //
                for (i = 0; i < numplanes; i++)
                {
                    GameBase.ClipVelocity(original_velocity, planes[i], new_velocity, 1);

                    for (j = 0; j < numplanes; j++)
                    {
                        if (j != i && !Math3D.VectorEquals(planes[i], planes[j]))
                        {
                            if (Math3D.DotProduct(new_velocity, planes[j]) < 0)
                            {
                                break;                                 // not ok
                            }
                        }
                    }

                    if (j == numplanes)
                    {
                        break;
                    }
                }

                if (i != numplanes)
                {
                    // go along this plane
                    Math3D.VectorCopy(new_velocity, ent.velocity);
                }
                else
                {
                    // go along the crease
                    if (numplanes != 2)
                    {
                        //					gi.dprintf ("clip velocity, numplanes ==
                        // %i\n",numplanes);
                        Math3D.VectorCopy(Globals.vec3_origin, ent.velocity);

                        return(7);
                    }

                    Math3D.CrossProduct(planes[0], planes[1], dir);
                    d = Math3D.DotProduct(dir, ent.velocity);
                    Math3D.VectorScale(dir, d, ent.velocity);
                }

                //
                //	   if original velocity is against the original velocity, stop dead
                //	   to avoid tiny occilations in sloping corners
                //
                if (Math3D.DotProduct(ent.velocity, primal_velocity) <= 0)
                {
                    Math3D.VectorCopy(Globals.vec3_origin, ent.velocity);

                    return(blocked);
                }
            }

            return(blocked);
        }
コード例 #9
0
ファイル: SV.cs プロジェクト: optimus-code/Quake2Sharp
        public static void SV_NewChaseDir(edict_t actor, edict_t enemy, float dist)
        {
            float deltax, deltay;

            float[] d = { 0, 0, 0 };
            float   tdir, olddir, turnaround;

            //FIXME: how did we get here with no enemy
            if (enemy == null)
            {
                Com.DPrintf("SV_NewChaseDir without enemy!\n");

                return;
            }

            olddir     = Math3D.anglemod((int)(actor.ideal_yaw / 45) * 45);
            turnaround = Math3D.anglemod(olddir - 180);

            deltax = enemy.s.origin[0] - actor.s.origin[0];
            deltay = enemy.s.origin[1] - actor.s.origin[1];

            if (deltax > 10)
            {
                d[1] = 0;
            }
            else if (deltax < -10)
            {
                d[1] = 180;
            }
            else
            {
                d[1] = SV.DI_NODIR;
            }

            if (deltay < -10)
            {
                d[2] = 270;
            }
            else if (deltay > 10)
            {
                d[2] = 90;
            }
            else
            {
                d[2] = SV.DI_NODIR;
            }

            //	   try direct route
            if (d[1] != SV.DI_NODIR && d[2] != SV.DI_NODIR)
            {
                if (d[1] == 0)
                {
                    tdir = d[2] == 90 ? 45 : 315;
                }
                else
                {
                    tdir = d[2] == 90 ? 135 : 215;
                }

                if (tdir != turnaround && SV.SV_StepDirection(actor, tdir, dist))
                {
                    return;
                }
            }

            //	   try other directions
            if ((Lib.rand() & 3 & 1) != 0 || Math.Abs(deltay) > Math.Abs(deltax))
            {
                tdir = d[1];
                d[1] = d[2];
                d[2] = tdir;
            }

            if (d[1] != SV.DI_NODIR && d[1] != turnaround && SV.SV_StepDirection(actor, d[1], dist))
            {
                return;
            }

            if (d[2] != SV.DI_NODIR && d[2] != turnaround && SV.SV_StepDirection(actor, d[2], dist))
            {
                return;
            }

            /* there is no direct path to the player, so pick another direction */

            if (olddir != SV.DI_NODIR && SV.SV_StepDirection(actor, olddir, dist))
            {
                return;
            }

            if ((Lib.rand() & 1) != 0)             /* randomly determine direction of search */
            {
                for (tdir = 0; tdir <= 315; tdir += 45)
                {
                    if (tdir != turnaround && SV.SV_StepDirection(actor, tdir, dist))
                    {
                        return;
                    }
                }
            }
            else
            {
                for (tdir = 315; tdir >= 0; tdir -= 45)
                {
                    if (tdir != turnaround && SV.SV_StepDirection(actor, tdir, dist))
                    {
                        return;
                    }
                }
            }

            if (turnaround != SV.DI_NODIR && SV.SV_StepDirection(actor, turnaround, dist))
            {
                return;
            }

            actor.ideal_yaw = olddir;             // can't move

            // if a bridge was pulled out from underneath a monster, it may not have
            // a valid standing position at all

            if (!M.M_CheckBottom(actor))
            {
                SV.SV_FixCheckBottom(actor);
            }
        }