Beispiel #1
0
    public static trace_t SV_ClipMoveToEntity(edict_t ent, ref Vector3 start, ref Vector3 mins, ref Vector3 maxs, ref Vector3 end)
    {
        trace_t trace = new trace_t();

        // fill in a default trace
        trace.fraction = 1;
        trace.allsolid = true;
        trace.endpos   = end;

        // get the clipping hull
        Vector3 offset;
        hull_t  hull = SV_HullForEntity(ent, ref mins, ref maxs, out offset);

        Vector3 start_l = start - offset;
        Vector3 end_l   = end - offset;

        // trace a line through the apropriate clipping hull
        SV_RecursiveHullCheck(hull, hull.firstclipnode, 0, 1, ref start_l, ref end_l, trace);

        // fix trace up by the offset
        if (trace.fraction != 1)
        {
            trace.endpos += offset;
        }

        // did we clip the move?
        if (trace.fraction < 1 || trace.startsolid)
        {
            trace.ent = ent;
        }

        return(trace);
    }
Beispiel #2
0
    static void PF_droptofloor()
    {
        edict_t ent = PROG_TO_EDICT(pr_global_struct.self);

        Vector3 org, mins, maxs;

        Mathlib.Copy(ref ent.v.origin, out org);
        Mathlib.Copy(ref ent.v.mins, out mins);
        Mathlib.Copy(ref ent.v.maxs, out maxs);
        Vector3 end = org;

        end.Z -= 256;

        trace_t trace = SV_Move(ref org, ref mins, ref maxs, ref end, 0, ent);

        if (trace.fraction == 1 || trace.allsolid)
        {
            G_FLOAT((float)0);
        }
        else
        {
            Mathlib.Copy(ref trace.endpos, out ent.v.origin);
            SV_LinkEdict(ent, false);
            ent.v.flags        = (int)ent.v.flags | q_shared.FL_ONGROUND;
            ent.v.groundentity = EDICT_TO_PROG(trace.ent);
            G_FLOAT((float)1);
        }
    }
Beispiel #3
0
    static unsafe void PF_traceline()
    {
        float * v1         = G_VECTOR(q_shared.OFS_PARM0);
        float * v2         = G_VECTOR(q_shared.OFS_PARM1);
        int     nomonsters = (int)G_FLOAT(q_shared.OFS_PARM2);
        edict_t ent        = G_EDICT(q_shared.OFS_PARM3);

        Vector3 vec1, vec2;

        Copy(v1, out vec1);
        Copy(v2, out vec2);
        trace_t trace = SV_Move(ref vec1, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref vec2, nomonsters, ent);

        pr_global_struct.trace_allsolid   = trace.allsolid ? 1 : 0;
        pr_global_struct.trace_startsolid = trace.startsolid ? 1 : 0;
        pr_global_struct.trace_fraction   = trace.fraction;
        pr_global_struct.trace_inwater    = trace.inwater ? 1 : 0;
        pr_global_struct.trace_inopen     = trace.inopen ? 1 : 0;
        Mathlib.Copy(ref trace.endpos, out pr_global_struct.trace_endpos);
        Mathlib.Copy(ref trace.plane.normal, out pr_global_struct.trace_plane_normal);
        pr_global_struct.trace_plane_dist = trace.plane.dist;
        if (trace.ent != null)
        {
            pr_global_struct.trace_ent = EDICT_TO_PROG(trace.ent);
        }
        else
        {
            pr_global_struct.trace_ent = EDICT_TO_PROG(sv.edicts[0]);
        }
    }
Beispiel #4
0
    public static void TraceLine(ref Vector3 start, ref Vector3 end, out Vector3 impact)
    {
        trace_t trace = new trace_t();

        SV_RecursiveHullCheck(cl.worldmodel.hulls[0], 0, 0, 1, ref start, ref end, trace);

        impact = trace.endpos;
    }
Beispiel #5
0
 public void HitWall(trace_t trace)
 {
     if (traceTime == 0 || ((HighResolutionTimer.Ticks - traceTime) / HighResolutionTimer.Frequency) > 1f)
     {
         //this.trace = trace;
         //Info.Text = "Hit Wall - " + trace.plane;
         traceTime = HighResolutionTimer.Ticks;
     }
 }
Beispiel #6
0
    public static edict_t SV_TestEntityPosition(edict_t ent)
    {
        trace_t trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref ent.v.origin, 0, ent);

        if (trace.startsolid)
        {
            return(sv.edicts[0]);
        }

        return(null);
    }
Beispiel #7
0
        public static trace_t Create()
        {
            trace_t t = new trace_t();

            t.m_AllSolid          = true;
            t.m_StartSolid        = true;
            t.m_Fraction          = 1f;
            t.m_FractionLeftSolid = 1f;
            t.m_EndPos            = Vector3.Zero;
            t.m_Contents          = 0;
            t.m_nBrushSide        = 0;

            return(t);
        }
Beispiel #8
0
    public static int SV_TryUnstick(edict_t ent, ref v3f oldvel)
    {
        v3f oldorg = ent.v.origin;
        v3f dir    = q_shared.ZeroVector3f;

        trace_t steptrace = new trace_t();

        for (int i = 0; i < 8; i++)
        {
            // try pushing a little in an axial direction
            switch (i)
            {
            case 0: dir.x = 2; dir.y = 0; break;

            case 1: dir.x = 0; dir.y = 2; break;

            case 2: dir.x = -2; dir.y = 0; break;

            case 3: dir.x = 0; dir.y = -2; break;

            case 4: dir.x = 2; dir.y = 2; break;

            case 5: dir.x = -2; dir.y = 2; break;

            case 6: dir.x = 2; dir.y = -2; break;

            case 7: dir.x = -2; dir.y = -2; break;
            }

            PushEntity(ent, ref dir);

            // retry the original move
            ent.v.velocity.x = oldvel.x;
            ent.v.velocity.y = oldvel.y;
            ent.v.velocity.z = 0;
            int clip = SV_FlyMove(ent, 0.1f, steptrace);

            if (Math.Abs(oldorg.y - ent.v.origin.y) > 4 || Math.Abs(oldorg.x - ent.v.origin.x) > 4)
            {
                return(clip);
            }

            // go back to the original pos and try again
            ent.v.origin = oldorg;
        }

        ent.v.velocity = q_shared.ZeroVector3f;
        return(7);               // still not moving
    }
Beispiel #9
0
        /**
         * Two entities have touched, so run their touch functions.
         */
        public static void SV_Impact(edict_t e1, trace_t trace)
        {
            edict_t e2;

            e2 = trace.ent;

            if (e1.touch != null && e1.solid != Defines.SOLID_NOT)
            {
                e1.touch.touch(e1, e2, trace.plane, trace.surface);
            }

            if (e2.touch != null && e2.solid != Defines.SOLID_NOT)
            {
                e2.touch.touch(e2, e1, GameBase.dummyplane, null);
            }
        }
Beispiel #10
0
    public static void SV_WallFriction(edict_t ent, trace_t trace)
    {
        Vector3 forward, right, up, vangle = ToVector(ref ent.v.v_angle);

        Mathlib.AngleVectors(ref vangle, out forward, out right, out up);
        float d = Vector3.Dot(trace.plane.normal, forward);

        d += 0.5f;
        if (d >= 0)
        {
            return;
        }

        // cut the tangential velocity
        Vector3 vel  = ToVector(ref ent.v.velocity);
        float   i    = Vector3.Dot(trace.plane.normal, vel);
        Vector3 into = trace.plane.normal * i;
        Vector3 side = vel - into;

        ent.v.velocity.x = side.X * (1 + d);
        ent.v.velocity.y = side.Y * (1 + d);
    }
Beispiel #11
0
    public static void SV_UserFriction()
    {
        float speed = Mathlib.LengthXY(ref sv_player.v.velocity);

        if (speed == 0)
        {
            return;
        }

        // if the leading edge is over a dropoff, increase friction
        Vector3 start, stop;

        start.X = stop.X = sv_player.v.origin.x + sv_player.v.velocity.x / speed * 16;
        start.Y = stop.Y = sv_player.v.origin.y + sv_player.v.velocity.y / speed * 16;
        start.Z = sv_player.v.origin.z + sv_player.v.mins.z;
        stop.Z  = start.Z - 34;

        trace_t trace    = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref stop, 1, sv_player);
        float   friction = sv_friction.value;

        if (trace.fraction == 1.0)
        {
            friction *= edgefriction.value;
        }

        // apply friction
        float control  = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
        float newspeed = (float)(speed - host_framtime * control * friction);

        if (newspeed < 0)
        {
            newspeed = 0;
        }
        newspeed /= speed;

        Mathlib.VectorScale(ref sv_player.v.velocity, newspeed, out sv_player.v.velocity);
    }
Beispiel #12
0
    public static int SV_FlyMove(edict_t ent, float time, trace_t steptrace)
    {
        v3f original_velocity = ent.v.velocity;
        v3f primal_velocity   = ent.v.velocity;

        int numbumps = 4;
        int blocked  = 0;

        Vector3[] planes    = new Vector3[q_shared.MAX_CLIP_PLANES];
        int       numplanes = 0;
        float     time_left = time;

        for (int bumpcount = 0; bumpcount < numbumps; bumpcount++)
        {
            if (ent.v.velocity.IsEmpty)
            {
                break;
            }

            v3f end;
            Mathlib.VectorMA(ref ent.v.origin, time_left, ref ent.v.velocity, out end);

            trace_t trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref end, 0, ent);

            if (trace.allsolid)
            {   // entity is trapped in another solid
                ent.v.velocity = default(v3f);
                return(3);
            }

            if (trace.fraction > 0)
            {   // actually covered some distance
                Mathlib.Copy(ref trace.endpos, out ent.v.origin);
                original_velocity = ent.v.velocity;
                numplanes         = 0;
            }

            if (trace.fraction == 1)
            {
                break;          // moved the entire distance
            }
            if (trace.ent == null)
            {
                Sys_Error("SV_FlyMove: !trace.ent");
            }

            if (trace.plane.normal.Z > 0.7)
            {
                blocked |= 1;           // floor
                if (trace.ent.v.solid == q_shared.SOLID_BSP)
                {
                    ent.v.flags        = (int)ent.v.flags | q_shared.FL_ONGROUND;
                    ent.v.groundentity = EDICT_TO_PROG(trace.ent);
                }
            }

            if (trace.plane.normal.Z == 0)
            {
                blocked |= 2;           // step
                if (steptrace != null)
                {
                    steptrace.CopyFrom(trace);  // save for player extrafriction
                }
            }

            //
            // run the impact function
            //
            SV_Impact(ent, trace.ent);
            if (ent.free)
            {
                break;          // removed by the impact function
            }
            time_left -= time_left * trace.fraction;

            // cliped to another plane
            if (numplanes >= q_shared.MAX_CLIP_PLANES)
            {
                // this shouldn't really happen
                ent.v.velocity = default(v3f);
                return(3);
            }

            planes[numplanes] = trace.plane.normal;
            numplanes++;

            //
            // modify original_velocity so it parallels all of the clip planes
            //
            v3f new_velocity = default(v3f);
            int i, j;
            for (i = 0; i < numplanes; i++)
            {
                ClipVelocity(ref original_velocity, ref planes[i], out new_velocity, 1);
                for (j = 0; j < numplanes; j++)
                {
                    if (j != i)
                    {
                        float dot = new_velocity.x * planes[j].X + new_velocity.y * planes[j].Y + new_velocity.z * planes[j].Z;
                        if (dot < 0)
                        {
                            break;      // not ok
                        }
                    }
                }
                if (j == numplanes)
                {
                    break;
                }
            }

            if (i != numplanes)
            {
                // go along this plane
                ent.v.velocity = new_velocity;
            }
            else
            {
                // go along the crease
                if (numplanes != 2)
                {
                    ent.v.velocity = default(v3f);
                    return(7);
                }
                Vector3 dir = Vector3.Cross(planes[0], planes[1]);
                float   d   = dir.X * ent.v.velocity.x + dir.Y * ent.v.velocity.y + dir.Z * ent.v.velocity.z;
                Mathlib.Copy(ref dir, out ent.v.velocity);
                Mathlib.VectorScale(ref ent.v.velocity, d, out ent.v.velocity);
            }

            //
            // if original velocity is against the original velocity, stop dead
            // to avoid tiny occilations in sloping corners
            //
            if (Mathlib.DotProduct(ref ent.v.velocity, ref primal_velocity) <= 0)
            {
                ent.v.velocity = default(v3f);
                return(blocked);
            }
        }

        return(blocked);
    }
Beispiel #13
0
    static void PF_aim()
    {
        edict_t ent   = G_EDICT(q_shared.OFS_PARM0);
        float   speed = G_FLOAT(q_shared.OFS_PARM1);

        Vector3 start = ToVector(ref ent.v.origin);

        start.Z += 20;

        // try sending a trace straight
        Vector3 dir;

        Mathlib.Copy(ref pr_global_struct.v_forward, out dir);
        Vector3 end = start + dir * 2048;
        trace_t tr  = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref end, 0, ent);

        if (tr.ent != null && tr.ent.v.takedamage == q_shared.DAMAGE_AIM &&
            (teamplay.value == 0 || ent.v.team <= 0 || ent.v.team != tr.ent.v.team))
        {
            G_VECTOR(ref pr_global_struct.v_forward);
            return;
        }

        // try all possible entities
        Vector3 bestdir  = dir;
        float   bestdist = sv_aim.value;
        edict_t bestent  = null;

        for (int i = 1; i < sv.num_edicts; i++)
        {
            edict_t check = sv.edicts[i];
            if (check.v.takedamage != q_shared.DAMAGE_AIM)
            {
                continue;
            }
            if (check == ent)
            {
                continue;
            }
            if (teamplay.value != 0 && ent.v.team > 0 && ent.v.team == check.v.team)
            {
                continue;       // don't aim at teammate
            }
            v3f tmp;
            Mathlib.VectorAdd(ref check.v.mins, ref check.v.maxs, out tmp);
            Mathlib.VectorMA(ref check.v.origin, 0.5f, ref tmp, out tmp);
            Mathlib.Copy(ref tmp, out end);

            dir = end - start;
            Mathlib.Normalize(ref dir);
            float dist = Vector3.Dot(dir, ToVector(ref pr_global_struct.v_forward));
            if (dist < bestdist)
            {
                continue;       // to far to turn
            }
            tr = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref end, 0, ent);
            if (tr.ent == check)
            {   // can shoot at this one
                bestdist = dist;
                bestent  = check;
            }
        }

        if (bestent != null)
        {
            v3f dir2, end2;
            Mathlib.VectorSubtract(ref bestent.v.origin, ref ent.v.origin, out dir2);
            float dist = Mathlib.DotProduct(ref dir2, ref pr_global_struct.v_forward);
            Mathlib.VectorScale(ref pr_global_struct.v_forward, dist, out end2);
            end2.z = dir2.z;
            Mathlib.Normalize(ref end2);
            G_VECTOR(ref end2);
        }
        else
        {
            G_VECTOR(ref bestdir);
        }
    }
Beispiel #14
0
        /**
         * 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.
         */

        // FIXME: since we need to test end position contents here, can we avoid
        // doing it again later in catagorize position?
        public static bool SV_movestep(edict_t ent, float[] move, bool relink)
        {
            float dz;

            float[] oldorg = { 0, 0, 0 };
            float[] neworg = { 0, 0, 0 };
            float[] end    = { 0, 0, 0 };

            trace_t trace = null;             // = new trace_t();
            int     i;
            float   stepsize;

            float[] test = { 0, 0, 0 };
            int     contents;

            //	   try the move
            Math3D.VectorCopy(ent.s.origin, oldorg);
            Math3D.VectorAdd(ent.s.origin, move, neworg);

            //	   flying monsters don't step up
            if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0)
            {
                // try one move with vertical motion, then one without
                for (i = 0; i < 2; i++)
                {
                    Math3D.VectorAdd(ent.s.origin, move, neworg);

                    if (i == 0 && ent.enemy != null)
                    {
                        if (ent.goalentity == null)
                        {
                            ent.goalentity = ent.enemy;
                        }

                        dz = ent.s.origin[2] - ent.goalentity.s.origin[2];

                        if (ent.goalentity.client != null)
                        {
                            if (dz > 40)
                            {
                                neworg[2] -= 8;
                            }

                            if (!((ent.flags & Defines.FL_SWIM) != 0 && ent.waterlevel < 2))
                            {
                                if (dz < 30)
                                {
                                    neworg[2] += 8;
                                }
                            }
                        }
                        else
                        {
                            if (dz > 8)
                            {
                                neworg[2] -= 8;
                            }
                            else if (dz > 0)
                            {
                                neworg[2] -= dz;
                            }
                            else if (dz < -8)
                            {
                                neworg[2] += 8;
                            }
                            else
                            {
                                neworg[2] += dz;
                            }
                        }
                    }

                    trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, neworg, ent, Defines.MASK_MONSTERSOLID);

                    // fly monsters don't enter water voluntarily
                    if ((ent.flags & Defines.FL_FLY) != 0)
                    {
                        if (ent.waterlevel == 0)
                        {
                            test[0]  = trace.endpos[0];
                            test[1]  = trace.endpos[1];
                            test[2]  = trace.endpos[2] + ent.mins[2] + 1;
                            contents = GameBase.gi.pointcontents(test);

                            if ((contents & Defines.MASK_WATER) != 0)
                            {
                                return(false);
                            }
                        }
                    }

                    // swim monsters don't exit water voluntarily
                    if ((ent.flags & Defines.FL_SWIM) != 0)
                    {
                        if (ent.waterlevel < 2)
                        {
                            test[0]  = trace.endpos[0];
                            test[1]  = trace.endpos[1];
                            test[2]  = trace.endpos[2] + ent.mins[2] + 1;
                            contents = GameBase.gi.pointcontents(test);

                            if ((contents & Defines.MASK_WATER) == 0)
                            {
                                return(false);
                            }
                        }
                    }

                    if (trace.fraction == 1)
                    {
                        Math3D.VectorCopy(trace.endpos, ent.s.origin);

                        if (relink)
                        {
                            GameBase.gi.linkentity(ent);
                            GameBase.G_TouchTriggers(ent);
                        }

                        return(true);
                    }

                    if (ent.enemy == null)
                    {
                        break;
                    }
                }

                return(false);
            }

            //	   push down from a step height above the wished position
            if ((ent.monsterinfo.aiflags & Defines.AI_NOSTEP) == 0)
            {
                stepsize = GameBase.STEPSIZE;
            }
            else
            {
                stepsize = 1;
            }

            neworg[2] += stepsize;
            Math3D.VectorCopy(neworg, end);
            end[2] -= stepsize * 2;

            trace = GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID);

            if (trace.allsolid)
            {
                return(false);
            }

            if (trace.startsolid)
            {
                neworg[2] -= stepsize;
                trace      = GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID);

                if (trace.allsolid || trace.startsolid)
                {
                    return(false);
                }
            }

            // don't go in to water
            if (ent.waterlevel == 0)
            {
                test[0]  = trace.endpos[0];
                test[1]  = trace.endpos[1];
                test[2]  = trace.endpos[2] + ent.mins[2] + 1;
                contents = GameBase.gi.pointcontents(test);

                if ((contents & Defines.MASK_WATER) != 0)
                {
                    return(false);
                }
            }

            if (trace.fraction == 1)
            {
                // if monster had the ground pulled out, go ahead and fall
                if ((ent.flags & Defines.FL_PARTIALGROUND) != 0)
                {
                    Math3D.VectorAdd(ent.s.origin, move, ent.s.origin);

                    if (relink)
                    {
                        GameBase.gi.linkentity(ent);
                        GameBase.G_TouchTriggers(ent);
                    }

                    ent.groundentity = null;

                    return(true);
                }

                return(false);                // walked off an edge
            }

            //	   check point traces down for dangling corners
            Math3D.VectorCopy(trace.endpos, ent.s.origin);

            if (!M.M_CheckBottom(ent))
            {
                if ((ent.flags & Defines.FL_PARTIALGROUND) != 0)
                {
                    // entity had floor mostly pulled out from underneath it
                    // and is trying to correct
                    if (relink)
                    {
                        GameBase.gi.linkentity(ent);
                        GameBase.G_TouchTriggers(ent);
                    }

                    return(true);
                }

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

                return(false);
            }

            if ((ent.flags & Defines.FL_PARTIALGROUND) != 0)
            {
                ent.flags &= ~Defines.FL_PARTIALGROUND;
            }

            ent.groundentity           = trace.ent;
            ent.groundentity_linkcount = trace.ent.linkcount;

            //	   the move is ok
            if (relink)
            {
                GameBase.gi.linkentity(ent);
                GameBase.G_TouchTriggers(ent);
            }

            return(true);
        }
Beispiel #15
0
        /*
        ==================
        SV_ClipMoveToEntity

        Handles selection or creation of a clipping hull, and offseting (and
        eventually rotation) of the end points
        ==================
        */
        public static trace_t SV_ClipMoveToEntity(prog.edict_t ent, double[] start, double[] mins, double[] maxs, double[] end)
        {
            trace_t trace;
            double[] offset = new double[3] {0, 0, 0};
            double[] start_l = new double[3] {0, 0, 0}, end_l = new double[3] {0, 0, 0};
            model.hull_t hull;

            // fill in a default trace
            trace = new trace_t();
            trace.fraction = 1;
            trace.allsolid = true;
            mathlib.VectorCopy(end, trace.endpos);

            // get the clipping hull
            hull = SV_HullForEntity(ent, mins, maxs, offset);

            mathlib.VectorSubtract(start, offset, start_l);
            mathlib.VectorSubtract(end, offset, end_l);
            //Debug.WriteLine(string.Format("end[2] {0:F6}", (float)end[2]));

            // trace a line through the apropriate clipping hull
            //Debug.WriteLine(string.Format("end_l[2] {0:F6}",(float)  end_l[2]));
            SV_RecursiveHullCheck(hull, hull.firstclipnode, 0, 1, start_l, end_l, trace);


            // fix trace up by the offset
            if (trace.fraction != 1)
                mathlib.VectorAdd(trace.endpos, offset, trace.endpos);

            // did we clip the move?
            if (trace.fraction < 1 || trace.startsolid)
                trace.ent = ent;

            return trace;
        }
Beispiel #16
0
        public static bool SV_RecursiveHullCheck(
            model.hull_t hull, int num, double p1f, double p2f, double[] p1, double[] p2, trace_t trace)
        {

            bspfile.dclipnode_t node;
            model.mplane_t plane;
            double t1, t2;
            double frac;
            int i;
            double[] mid = new double[3] {0, 0, 0};
            int side;
            double midf;

            //Debug.WriteLine(string.Format("SV_RecursiveHullCheck hull.firstclipnode:{0} num:{1} {2:F6} {3:F6} p1[0] {4:F6} p1[1] {5:F6}  p1[2] {6:F6} -  p2[0] {7:F6} p2[1] {8:F6} p2[2] {9:F6} num_hullcheck: {10}", hull.firstclipnode, num, (float)p1f, (float)p2f, (float)p1[0], (float)p1[1], (float)p1[2], (float)p2[0], (float)p2[1], (float)p2[2], num_hullcheck));
            num_hullcheck++;
            // check for empty
            if (num < 0)
            {
                if (num != bspfile.CONTENTS_SOLID)
                {
                    trace.allsolid = false;
                    if (num == bspfile.CONTENTS_EMPTY) 
                        trace.inopen = true;
                    else 
                        trace.inwater = true;
                }
                else trace.startsolid = true;

                //Debug.WriteLine(string.Format("empty"));
                return true; // empty
            }

            if (num < hull.firstclipnode || num > hull.lastclipnode) 
                sys_linux.Sys_Error("SV_RecursiveHullCheck: bad node number");

            //
            // find the point distances
            //
            node = hull.clipnodes[num];
            plane = hull.planes[node.planenum];

            if (plane.type < 3)
            {
                t1 = p1[plane.type] - plane.dist;
                t2 = p2[plane.type] - plane.dist;
            }
            else
            {
                t1 = mathlib.DotProduct(plane.normal, p1) - plane.dist;
                t2 = mathlib.DotProduct(plane.normal, p2) - plane.dist;
            }
            //Debug.WriteLine(string.Format("t1: {0:F6} t2: {1:F6}", (float)t1, (float)t2));

            if (t1 >= 0 && t2 >= 0)
            {
                return SV_RecursiveHullCheck(hull, node.children[0], p1f, p2f, p1, p2, trace);
            }
            if (t1 < 0 && t2 < 0)
            {
                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) frac = (t1 + DIST_EPSILON) / (t1 - t2);
            else frac = (t1 - DIST_EPSILON) / (t1 - t2);
            if (frac < 0) frac = 0;
            if (frac > 1) frac = 1;

            midf = p1f + (p2f - p1f) * frac;
            for (i = 0; i < 3; i++) mid[i] = p1[i] + frac * (p2[i] - p1[i]);

            side = (t1 < 0) ? 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) != bspfile.CONTENTS_SOLID) // go past the node
            {
                return SV_RecursiveHullCheck(hull, node.children[side ^ 1], midf, p2f, mid, p2, trace);
            }

            if (trace.allsolid) 
            {
                return false; // never got out of the solid area
            }

            //==================
            // the other side of the node is solid, this is the impact point
            //==================
            if (side == 0)
            {
                mathlib.VectorCopy(plane.normal, trace.plane.normal);
                trace.plane.dist = plane.dist;
            }
            else
            {
                mathlib.VectorSubtract(mathlib.vec3_origin, plane.normal, trace.plane.normal);
                trace.plane.dist = -plane.dist;
            }

            while (SV_HullPointContents(hull, hull.firstclipnode, mid) == bspfile.CONTENTS_SOLID)
            {
                // shouldn't really happen, but does occasionally
                frac -= 0.1;
                if (frac < 0)
                {
                    trace.fraction = midf;
                    mathlib.VectorCopy(mid, trace.endpos);
                    console.Con_DPrintf("backup past 0\n");
                    return false;
                }
                midf = p1f + (p2f - p1f) * frac;
                for (i = 0; i < 3; i++) 
                    mid[i] = p1[i] + frac * (p2[i] - p1[i]);
            }

            trace.fraction = midf;
            mathlib.VectorCopy(mid, trace.endpos);

            return false;
        }
Beispiel #17
0
    public static bool SV_RecursiveHullCheck(hull_t hull, int num, float p1f, float p2f, ref Vector3 p1, ref Vector3 p2, trace_t trace)
    {
        // check for empty
        if (num < 0)
        {
            if (num != q_shared.CONTENTS_SOLID)
            {
                trace.allsolid = false;
                if (num == q_shared.CONTENTS_EMPTY)
                {
                    trace.inopen = true;
                }
                else
                {
                    trace.inwater = true;
                }
            }
            else
            {
                trace.startsolid = true;
            }
            return(true);                // empty
        }

        if (num < hull.firstclipnode || num > hull.lastclipnode)
        {
            Sys_Error("SV_RecursiveHullCheck: bad node number");
        }

        //
        // find the point distances
        //
        short[]  node_children = hull.clipnodes[num].children;
        mplane_t plane = hull.planes[hull.clipnodes[num].planenum];
        float    t1, t2;

        if (plane.type < 3)
        {
            t1 = Mathlib.Comp(ref p1, plane.type) - plane.dist;
            t2 = Mathlib.Comp(ref p2, plane.type) - plane.dist;
        }
        else
        {
            t1 = Vector3.Dot(plane.normal, p1) - plane.dist;
            t2 = Vector3.Dot(plane.normal, p2) - plane.dist;
        }

        if (t1 >= 0 && t2 >= 0)
        {
            return(SV_RecursiveHullCheck(hull, node_children[0], p1f, p2f, ref p1, ref p2, trace));
        }
        if (t1 < 0 && t2 < 0)
        {
            return(SV_RecursiveHullCheck(hull, node_children[1], p1f, p2f, ref p1, ref p2, trace));
        }

        // put the crosspoint DIST_EPSILON pixels on the near side
        float frac;

        if (t1 < 0)
        {
            frac = (t1 + q_shared.DIST_EPSILON) / (t1 - t2);
        }
        else
        {
            frac = (t1 - q_shared.DIST_EPSILON) / (t1 - t2);
        }
        if (frac < 0)
        {
            frac = 0;
        }
        if (frac > 1)
        {
            frac = 1;
        }

        float   midf = p1f + (p2f - p1f) * frac;
        Vector3 mid  = p1 + (p2 - p1) * frac;

        int side = (t1 < 0) ? 1 : 0;

        // move up to the node
        if (!SV_RecursiveHullCheck(hull, node_children[side], p1f, midf, ref p1, ref mid, trace))
        {
            return(false);
        }

        if (SV_HullPointContents(hull, node_children[side ^ 1], ref mid) != q_shared.CONTENTS_SOLID)
        {
            // go past the node
            return(SV_RecursiveHullCheck(hull, node_children[side ^ 1], midf, p2f, ref mid, ref p2, trace));
        }

        if (trace.allsolid)
        {
            return(false);               // never got out of the solid area
        }
        //==================
        // the other side of the node is solid, this is the impact point
        //==================
        if (side == 0)
        {
            trace.plane.normal = plane.normal;
            trace.plane.dist   = plane.dist;
        }
        else
        {
            trace.plane.normal = -plane.normal;
            trace.plane.dist   = -plane.dist;
        }

        while (SV_HullPointContents(hull, hull.firstclipnode, ref mid) == q_shared.CONTENTS_SOLID)
        {
            // shouldn't really happen, but does occasionally
            frac -= 0.1f;
            if (frac < 0)
            {
                trace.fraction = midf;
                trace.endpos   = mid;
                Con_DPrintf("backup past 0\n");
                return(false);
            }
            midf = p1f + (p2f - p1f) * frac;
            mid  = p1 + (p2 - p1) * frac;
        }

        trace.fraction = midf;
        trace.endpos   = mid;

        return(false);
    }
Beispiel #18
0
    public static bool SV_CheckBottom(edict_t ent)
    {
        v3f mins, maxs;

        Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.mins, out mins);
        Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.maxs, out 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
        Vector3 start;

        start.Z = mins.z - 1;
        for (int x = 0; x <= 1; x++)
        {
            for (int y = 0; y <= 1; y++)
            {
                start.X = (x != 0 ? maxs.x : mins.x);
                start.Y = (y != 0 ? maxs.y : mins.y);
                if (SV_PointContents(ref start) != q_shared.CONTENTS_SOLID)
                {
                    goto RealCheck;
                }
            }
        }

        return(true);            // we got out easy

RealCheck:

        //
        // check it for real...
        //
        start.Z = mins.z;

        // the midpoint must be within 16 of the bottom
        start.X = (mins.x + maxs.x) * 0.5f;
        start.Y = (mins.y + maxs.y) * 0.5f;
        Vector3 stop = start;

        stop.Z -= 2 * q_shared.STEPSIZE;
        trace_t trace = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref stop, 1, ent);

        if (trace.fraction == 1.0)
        {
            return(false);
        }

        float mid    = trace.endpos.Z;
        float bottom = mid;

        // the corners must be within 16 of the midpoint
        for (int x = 0; x <= 1; x++)
        {
            for (int y = 0; y <= 1; y++)
            {
                start.X = stop.X = (x != 0 ? maxs.x : mins.x);
                start.Y = stop.Y = (y != 0 ? maxs.y : mins.y);

                trace = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref stop, 1, ent);

                if (trace.fraction != 1.0 && trace.endpos.Z > bottom)
                {
                    bottom = trace.endpos.Z;
                }
                if (trace.fraction == 1.0 || mid - trace.endpos.Z > q_shared.STEPSIZE)
                {
                    return(false);
                }
            }
        }

        return(true);
    }
Beispiel #19
0
        /*
         * ==================== CL_ClipMoveToEntities
         *
         * ====================
         */
        private static void ClipMoveToEntities(float[] start, float[] mins, float[] maxs, float[] end, trace_t tr)
        {
            int     i, x, zd, zu;
            trace_t trace;
            int     headnode;

            float[]        angles;
            entity_state_t ent;
            int            num;
            cmodel_t       cmodel;
            var            bmins = new float[3];
            var            bmaxs = new float[3];

            for (i = 0; i < Globals.cl.frame.num_entities; i++)
            {
                num = (Globals.cl.frame.parse_entities + i) & (Defines.MAX_PARSE_ENTITIES - 1);
                ent = Globals.cl_parse_entities[num];

                if (ent.solid == 0)
                {
                    continue;
                }

                if (ent.number == Globals.cl.playernum + 1)
                {
                    continue;
                }

                if (ent.solid == 31)
                {
                    // special value for bmodel
                    cmodel = Globals.cl.model_clip[ent.modelindex];

                    if (cmodel == null)
                    {
                        continue;
                    }

                    headnode = cmodel.headnode;
                    angles   = ent.angles;
                }
                else
                {
                    // encoded bbox
                    x        = 8 * (ent.solid & 31);
                    zd       = (int)(8 * (((uint)ent.solid >> 5) & 31));
                    zu       = (int)(8 * (((uint)ent.solid >> 10) & 63) - 32);
                    bmins[0] = bmins[1] = -x;
                    bmaxs[0] = bmaxs[1] = x;
                    bmins[2] = -zd;
                    bmaxs[2] = zu;
                    headnode = CM.HeadnodeForBox(bmins, bmaxs);
                    angles   = Globals.vec3_origin;                   // boxes don't rotate
                }

                if (tr.allsolid)
                {
                    return;
                }

                trace = CM.TransformedBoxTrace(start, end, mins, maxs, headnode, Defines.MASK_PLAYERSOLID, ent.origin, angles);

                if (trace.allsolid || trace.startsolid || trace.fraction < tr.fraction)
                {
                    trace.ent = ent.surrounding_ent;

                    if (tr.startsolid)
                    {
                        tr.set(trace);                         // rst: solved the Z U P P E L - P R O B L E

                        // M
                        tr.startsolid = true;
                    }
                    else
                    {
                        tr.set(trace);                         // rst: solved the Z U P P E L - P R O B L E
                    }
                    // M
                }
                else if (trace.startsolid)
                {
                    tr.startsolid = true;
                }
            }
        }
Beispiel #20
0
    public static void SV_WalkMove(edict_t ent)
    {
        //
        // do a regular slide move unless it looks like you ran into a step
        //
        int oldonground = (int)ent.v.flags & q_shared.FL_ONGROUND;

        ent.v.flags = (int)ent.v.flags & ~q_shared.FL_ONGROUND;

        v3f     oldorg    = ent.v.origin;
        v3f     oldvel    = ent.v.velocity;
        trace_t steptrace = new trace_t();
        int     clip      = SV_FlyMove(ent, (float)host_framtime, steptrace);

        if ((clip & 2) == 0)
        {
            return;             // move didn't block on a step
        }
        if (oldonground == 0 && ent.v.waterlevel == 0)
        {
            return;             // don't stair up while jumping
        }
        if (ent.v.movetype != q_shared.MOVETYPE_WALK)
        {
            return;             // gibbed by a trigger
        }
        if (sv_nostep.value != 0)
        {
            return;
        }

        if (((int)sv_player.v.flags & q_shared.FL_WATERJUMP) != 0)
        {
            return;
        }

        v3f nosteporg = ent.v.origin;
        v3f nostepvel = ent.v.velocity;

        //
        // try moving up and forward to go up a step
        //
        ent.v.origin = oldorg;  // back to start pos

        v3f upmove   = q_shared.ZeroVector3f;
        v3f downmove = upmove;

        upmove.z   = q_shared.STEPSIZE;
        downmove.z = (float)(-q_shared.STEPSIZE + oldvel.z * host_framtime);

        // move up
        PushEntity(ent, ref upmove);    // FIXME: don't link?

        // move forward
        ent.v.velocity.x = oldvel.x;
        ent.v.velocity.y = oldvel.y;
        ent.v.velocity.z = 0;
        clip             = SV_FlyMove(ent, (float)host_framtime, steptrace);

        // check for stuckness, possibly due to the limited precision of floats
        // in the clipping hulls
        if (clip != 0)
        {
            if (Math.Abs(oldorg.y - ent.v.origin.y) < 0.03125 && Math.Abs(oldorg.x - ent.v.origin.x) < 0.03125)
            {
                // stepping up didn't make any progress
                clip = SV_TryUnstick(ent, ref oldvel);
            }
        }

        // extra friction based on view angle
        if ((clip & 2) != 0)
        {
            SV_WallFriction(ent, steptrace);
        }

        // move down
        trace_t downtrace = PushEntity(ent, ref downmove);      // FIXME: don't link?

        if (downtrace.plane.normal.Z > 0.7)
        {
            if (ent.v.solid == q_shared.SOLID_BSP)
            {
                ent.v.flags        = (int)ent.v.flags | q_shared.FL_ONGROUND;
                ent.v.groundentity = EDICT_TO_PROG(downtrace.ent);
            }
        }
        else
        {
            // if the push down didn't end up on good ground, use the move without
            // the step up.  This happens near wall / slope combinations, and can
            // cause the player to hop up higher on a slope too steep to climb
            ent.v.origin   = nosteporg;
            ent.v.velocity = nostepvel;
        }
    }
Beispiel #21
0
    public static void SV_Physics_Toss(edict_t ent)
    {
        // regular thinking
        if (!SV_RunThink(ent))
        {
            return;
        }

        // if onground, return without moving
        if (((int)ent.v.flags & q_shared.FL_ONGROUND) != 0)
        {
            return;
        }

        SV_CheckVelocity(ent);

        // add gravity
        if (ent.v.movetype != q_shared.MOVETYPE_FLY && ent.v.movetype != q_shared.MOVETYPE_FLYMISSILE)
        {
            SV_AddGravity(ent);
        }


        // move angles
        Mathlib.VectorMA(ref ent.v.angles, (float)host_framtime, ref ent.v.avelocity, out ent.v.angles);

        // move origin
        v3f move;

        Mathlib.VectorScale(ref ent.v.velocity, (float)host_framtime, out move);
        trace_t trace = PushEntity(ent, ref move);

        if (trace.fraction == 1)
        {
            return;
        }
        if (ent.free)
        {
            return;
        }

        float backoff;

        if (ent.v.movetype == q_shared.MOVETYPE_BOUNCE)
        {
            backoff = 1.5f;
        }
        else
        {
            backoff = 1;
        }

        ClipVelocity(ref ent.v.velocity, ref trace.plane.normal, out ent.v.velocity, backoff);

        // stop if on ground
        if (trace.plane.normal.Z > 0.7f)
        {
            if (ent.v.velocity.z < 60 || ent.v.movetype != q_shared.MOVETYPE_BOUNCE)
            {
                ent.v.flags        = (int)ent.v.flags | q_shared.FL_ONGROUND;
                ent.v.groundentity = EDICT_TO_PROG(trace.ent);
                ent.v.velocity     = default(v3f);
                ent.v.avelocity    = default(v3f);
            }
        }

        // check for in water
        SV_CheckWaterTransition(ent);
    }
Beispiel #22
0
    public static void SV_SetIdealPitch()
    {
        if (((int)sv_player.v.flags & q_shared.FL_ONGROUND) == 0)
        {
            return;
        }

        double angleval = sv_player.v.angles.y * Math.PI * 2 / 360;
        double sinval   = Math.Sin(angleval);
        double cosval   = Math.Cos(angleval);

        float[] z = new float[q_shared.MAX_FORWARD];
        for (int i = 0; i < q_shared.MAX_FORWARD; i++)
        {
            v3f top = sv_player.v.origin;
            top.x += (float)(cosval * (i + 3) * 12);
            top.y += (float)(sinval * (i + 3) * 12);
            top.z += sv_player.v.view_ofs.z;

            v3f bottom = top;
            bottom.z -= 160;

            trace_t tr = Move(ref top, ref q_shared.ZeroVector3f, ref q_shared.ZeroVector3f, ref bottom, 1, sv_player);
            if (tr.allsolid)
            {
                return; // looking at a wall, leave ideal the way is was
            }
            if (tr.fraction == 1)
            {
                return; // near a dropoff
            }
            z[i] = top.z + tr.fraction * (bottom.z - top.z);
        }

        float dir   = 0; // Uze: int in original code???
        int   steps = 0;

        for (int j = 1; j < q_shared.MAX_FORWARD; j++)
        {
            float step = z[j] - z[j - 1];                                  // Uze: int in original code???
            if (step > -q_shared.ON_EPSILON && step < q_shared.ON_EPSILON) // Uze: comparing int with ON_EPSILON (0.1)???
            {
                continue;
            }

            if (dir != 0 && (step - dir > q_shared.ON_EPSILON || step - dir < -q_shared.ON_EPSILON))
            {
                return;     // mixed changes
            }
            steps++;
            dir = step;
        }

        if (dir == 0)
        {
            sv_player.v.idealpitch = 0;
            return;
        }

        if (steps < 2)
        {
            return;
        }
        sv_player.v.idealpitch = -dir * sv_idealpitchscale.value;
    }