示例#1
0
        /// <summary>
        /// SV_HullPointContents
        /// </summary>
        static int HullPointContents(hull_t hull, int num, ref Vector3 p)
        {
            while (num >= 0)
            {
                if (num < hull.firstclipnode || num > hull.lastclipnode)
                {
                    Sys.Error("SV_HullPointContents: bad node number");
                }

                short[]  node_children = hull.clipnodes[num].children;
                mplane_t plane         = hull.planes[hull.clipnodes[num].planenum];
                float    d;
                if (plane.type < 3)
                {
                    d = Mathlib.Comp(ref p, plane.type) - plane.dist;
                }
                else
                {
                    d = Vector3.Dot(plane.normal, p) - plane.dist;
                }
                if (d < 0)
                {
                    num = node_children[1];
                }
                else
                {
                    num = node_children[0];
                }
            }

            return(num);
        }
示例#2
0
        /// <summary>
        /// SV_TouchLinks
        /// </summary>
        static void TouchLinks(edict_t ent, areanode_t node)
        {
            // touch linked edicts
            link_t next;

            for (link_t l = node.trigger_edicts.Next; l != node.trigger_edicts; l = next)
            {
                next = l.Next;
                edict_t touch = (edict_t)l.Owner;// EDICT_FROM_AREA(l);
                if (touch == ent)
                {
                    continue;
                }
                if (touch.v.touch == 0 || touch.v.solid != Solids.SOLID_TRIGGER)
                {
                    continue;
                }
                if (ent.v.absmin.x > touch.v.absmax.x || ent.v.absmin.y > touch.v.absmax.y ||
                    ent.v.absmin.z > touch.v.absmax.z || ent.v.absmax.x < touch.v.absmin.x ||
                    ent.v.absmax.y < touch.v.absmin.y || ent.v.absmax.z < touch.v.absmin.z)
                {
                    continue;
                }

                int old_self  = Progs.GlobalStruct.self;
                int old_other = Progs.GlobalStruct.other;

                Progs.GlobalStruct.self  = EdictToProg(touch);
                Progs.GlobalStruct.other = EdictToProg(ent);
                Progs.GlobalStruct.time  = (float)sv.time;
                Progs.Execute(touch.v.touch);

                Progs.GlobalStruct.self  = old_self;
                Progs.GlobalStruct.other = old_other;
            }

            // recurse down both sides
            if (node.axis == -1)
            {
                return;
            }

            if (Mathlib.Comp(ref ent.v.absmax, node.axis) > node.dist)
            {
                TouchLinks(ent, node.children[0]);
            }
            if (Mathlib.Comp(ref ent.v.absmin, node.axis) < node.dist)
            {
                TouchLinks(ent, node.children[1]);
            }
        }
示例#3
0
        static void PF_makestatic()
        {
            edict_t   ent = GetEdict(OFS.OFS_PARM0);
            MsgWriter msg = Server.sv.signon;

            msg.WriteByte(Protocol.svc_spawnstatic);
            msg.WriteByte(Server.ModelIndex(Progs.GetString(ent.v.model)));
            msg.WriteByte((int)ent.v.frame);
            msg.WriteByte((int)ent.v.colormap);
            msg.WriteByte((int)ent.v.skin);
            for (int i = 0; i < 3; i++)
            {
                msg.WriteCoord(Mathlib.Comp(ref ent.v.origin, i));
                msg.WriteAngle(Mathlib.Comp(ref ent.v.angles, i));
            }

            // throw the entity away now
            Server.FreeEdict(ent);
        }
示例#4
0
        /// <summary>
        /// SV_ClipToLinks
        /// Mins and maxs enclose the entire area swept by the move
        /// </summary>
        static void ClipToLinks(areanode_t node, moveclip_t clip)
        {
            link_t  next;
            trace_t trace;

            // touch linked edicts
            for (link_t l = node.solid_edicts.Next; l != node.solid_edicts; l = next)
            {
                next = l.Next;
                edict_t touch = (edict_t)l.Owner;// EDICT_FROM_AREA(l);
                if (touch.v.solid == Solids.SOLID_NOT)
                {
                    continue;
                }
                if (touch == clip.passedict)
                {
                    continue;
                }
                if (touch.v.solid == Solids.SOLID_TRIGGER)
                {
                    Sys.Error("Trigger in clipping list");
                }

                if (clip.type == MOVE_NOMONSTERS && touch.v.solid != Solids.SOLID_BSP)
                {
                    continue;
                }

                if (clip.boxmins.X > touch.v.absmax.x || clip.boxmins.Y > touch.v.absmax.y ||
                    clip.boxmins.Z > touch.v.absmax.z || clip.boxmaxs.X < touch.v.absmin.x ||
                    clip.boxmaxs.Y < touch.v.absmin.y || clip.boxmaxs.Z < touch.v.absmin.z)
                {
                    continue;
                }

                if (clip.passedict != null && clip.passedict.v.size.x != 0 && touch.v.size.x == 0)
                {
                    continue;   // points never interact
                }
                // might intersect, so do an exact clip
                if (clip.trace.allsolid)
                {
                    return;
                }
                if (clip.passedict != null)
                {
                    if (ProgToEdict(touch.v.owner) == clip.passedict)
                    {
                        continue;       // don't clip against own missiles
                    }
                    if (ProgToEdict(clip.passedict.v.owner) == touch)
                    {
                        continue;       // don't clip against owner
                    }
                }

                if (((int)touch.v.flags & EdictFlags.FL_MONSTER) != 0)
                {
                    trace = ClipMoveToEntity(touch, ref clip.start, ref clip.mins2, ref clip.maxs2, ref clip.end);
                }
                else
                {
                    trace = ClipMoveToEntity(touch, ref clip.start, ref clip.mins, ref clip.maxs, ref clip.end);
                }

                if (trace.allsolid || trace.startsolid || trace.fraction < clip.trace.fraction)
                {
                    trace.ent = touch;
                    if (clip.trace.startsolid)
                    {
                        clip.trace            = trace;
                        clip.trace.startsolid = true;
                    }
                    else
                    {
                        clip.trace = trace;
                    }
                }
                else if (trace.startsolid)
                {
                    clip.trace.startsolid = true;
                }
            }

            // recurse down both sides
            if (node.axis == -1)
            {
                return;
            }

            if (Mathlib.Comp(ref clip.boxmaxs, node.axis) > node.dist)
            {
                ClipToLinks(node.children[0], clip);
            }
            if (Mathlib.Comp(ref clip.boxmins, node.axis) < node.dist)
            {
                ClipToLinks(node.children[1], clip);
            }
        }
示例#5
0
        /// <summary>
        /// SV_RecursiveHullCheck
        /// </summary>
        public static bool 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 != Contents.CONTENTS_SOLID)
                {
                    trace.allsolid = false;
                    if (num == Contents.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(RecursiveHullCheck(hull, node_children[0], p1f, p2f, ref p1, ref p2, trace));
            }
            if (t1 < 0 && t2 < 0)
            {
                return(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 + DIST_EPSILON) / (t1 - t2);
            }
            else
            {
                frac = (t1 - 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 (!RecursiveHullCheck(hull, node_children[side], p1f, midf, ref p1, ref mid, trace))
            {
                return(false);
            }

            if (HullPointContents(hull, node_children[side ^ 1], ref mid) != Contents.CONTENTS_SOLID)
            {
                // go past the node
                return(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 (HullPointContents(hull, hull.firstclipnode, ref mid) == Contents.CONTENTS_SOLID)
            {
                // shouldn't really happen, but does occasionally
                frac -= 0.1f;
                if (frac < 0)
                {
                    trace.fraction = midf;
                    trace.endpos   = mid;
                    Con.DPrint("backup past 0\n");
                    return(false);
                }
                midf = p1f + (p2f - p1f) * frac;
                mid  = p1 + (p2 - p1) * frac;
            }

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

            return(false);
        }
示例#6
0
        /// <summary>
        /// SV_LinkEdict
        ///
        /// Needs to be called any time an entity changes origin, mins, maxs, or solid
        /// flags ent->v.modified
        /// sets ent->v.absmin and ent->v.absmax
        /// if touchtriggers, calls prog functions for the intersected triggers
        /// </summary>
        public static void LinkEdict(edict_t ent, bool touch_triggers)
        {
            if (ent.area.Prev != null)
            {
                UnlinkEdict(ent);       // unlink from old position
            }
            if (ent == sv.edicts[0])
            {
                return;         // don't add the world
            }
            if (ent.free)
            {
                return;
            }

            // set the abs box
            Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.mins, out ent.v.absmin);
            Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.maxs, out ent.v.absmax);

            //
            // to make items easier to pick up and allow them to be grabbed off
            // of shelves, the abs sizes are expanded
            //
            if (((int)ent.v.flags & EdictFlags.FL_ITEM) != 0)
            {
                ent.v.absmin.x -= 15;
                ent.v.absmin.y -= 15;
                ent.v.absmax.x += 15;
                ent.v.absmax.y += 15;
            }
            else
            {   // because movement is clipped an epsilon away from an actual edge,
                // we must fully check even when bounding boxes don't quite touch
                ent.v.absmin.x -= 1;
                ent.v.absmin.y -= 1;
                ent.v.absmin.z -= 1;
                ent.v.absmax.x += 1;
                ent.v.absmax.y += 1;
                ent.v.absmax.z += 1;
            }

            // link to PVS leafs
            ent.num_leafs = 0;
            if (ent.v.modelindex != 0)
            {
                FindTouchedLeafs(ent, sv.worldmodel.nodes[0]);
            }

            if (ent.v.solid == Solids.SOLID_NOT)
            {
                return;
            }

            // find the first node that the ent's box crosses
            areanode_t node = _AreaNodes[0];

            while (true)
            {
                if (node.axis == -1)
                {
                    break;
                }
                if (Mathlib.Comp(ref ent.v.absmin, node.axis) > node.dist)
                {
                    node = node.children[0];
                }
                else if (Mathlib.Comp(ref ent.v.absmax, node.axis) < node.dist)
                {
                    node = node.children[1];
                }
                else
                {
                    break;              // crosses the node
                }
            }

            // link it in

            if (ent.v.solid == Solids.SOLID_TRIGGER)
            {
                ent.area.InsertBefore(node.trigger_edicts);
            }
            else
            {
                ent.area.InsertBefore(node.solid_edicts);
            }

            // if touch_triggers, touch all entities at this node and decend for more
            if (touch_triggers)
            {
                TouchLinks(ent, _AreaNodes[0]);
            }
        }
示例#7
0
        /// <summary>
        /// SubdividePolygon
        /// </summary>
        static void SubdividePolygon(int numverts, Vector3[] verts)
        {
            if (numverts > 60)
            {
                Sys.Error("numverts = {0}", numverts);
            }

            Vector3 mins, maxs;

            BoundPoly(numverts, verts, out mins, out maxs);

            float[] dist = new float[64];
            for (int i = 0; i < 3; i++)
            {
                double m = (Mathlib.Comp(ref mins, i) + Mathlib.Comp(ref maxs, i)) * 0.5;
                m = Mod.SubdivideSize * Math.Floor(m / Mod.SubdivideSize + 0.5);
                if (Mathlib.Comp(ref maxs, i) - m < 8)
                {
                    continue;
                }

                if (m - Mathlib.Comp(ref mins, i) < 8)
                {
                    continue;
                }

                for (int j = 0; j < numverts; j++)
                {
                    dist[j] = (float)(Mathlib.Comp(ref verts[j], i) - m);
                }

                Vector3[] front = new Vector3[64];
                Vector3[] back  = new Vector3[64];

                // cut it

                // wrap cases
                dist[numverts]  = dist[0];
                verts[numverts] = verts[0]; // Uze: source array must be at least numverts + 1 elements long

                int f = 0, b = 0;
                for (int j = 0; j < numverts; j++)
                {
                    if (dist[j] >= 0)
                    {
                        front[f] = verts[j];
                        f++;
                    }
                    if (dist[j] <= 0)
                    {
                        back[b] = verts[j];
                        b++;
                    }
                    if (dist[j] == 0 || dist[j + 1] == 0)
                    {
                        continue;
                    }
                    if ((dist[j] > 0) != (dist[j + 1] > 0))
                    {
                        // clip point
                        float frac = dist[j] / (dist[j] - dist[j + 1]);
                        front[f] = back[b] = verts[j] + (verts[j + 1] - verts[j]) * frac;
                        f++;
                        b++;
                    }
                }

                SubdividePolygon(f, front);
                SubdividePolygon(b, back);
                return;
            }

            glpoly_t poly = new glpoly_t();

            poly.next       = _WarpFace.polys;
            _WarpFace.polys = poly;
            poly.AllocVerts(numverts);
            for (int i = 0; i < numverts; i++)
            {
                Common.Copy(ref verts[i], poly.verts[i]);
                float s = Vector3.Dot(verts[i], _WarpFace.texinfo.vecs[0].Xyz);
                float t = Vector3.Dot(verts[i], _WarpFace.texinfo.vecs[1].Xyz);
                poly.verts[i][3] = s;
                poly.verts[i][4] = t;
            }
        }