Beispiel #1
0
        /// <summary>
        /// SV_Physics_Pusher
        /// </summary>
        static void Physics_Pusher(edict_t ent)
        {
            float oldltime  = ent.v.ltime;
            float thinktime = ent.v.nextthink;
            float movetime;

            if (thinktime < ent.v.ltime + Host.FrameTime)
            {
                movetime = thinktime - ent.v.ltime;
                if (movetime < 0)
                {
                    movetime = 0;
                }
            }
            else
            {
                movetime = (float)Host.FrameTime;
            }

            if (movetime != 0)
            {
                PushMove(ent, movetime);        // advances ent.v.ltime if not blocked
            }

            if (thinktime > oldltime && thinktime <= ent.v.ltime)
            {
                ent.v.nextthink          = 0;
                Progs.GlobalStruct.time  = (float)sv.time;
                Progs.GlobalStruct.self  = EdictToProg(ent);
                Progs.GlobalStruct.other = EdictToProg(sv.edicts[0]);
                Progs.Execute(ent.v.think);
                if (ent.free)
                {
                    return;
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// SV_RunThink
        /// Runs thinking code if time.  There is some play in the exact time the think
        /// function will be called, because it is called before any movement is done
        /// in a frame.  Not used for pushmove objects, because they must be exact.
        /// Returns false if the entity removed itself.
        /// </summary>
        static bool RunThink(edict_t ent)
        {
            float thinktime;

            thinktime = ent.v.nextthink;
            if (thinktime <= 0 || thinktime > sv.time + Host.FrameTime)
            {
                return(true);
            }

            if (thinktime < sv.time)
            {
                thinktime = (float)sv.time;     // don't let things stay in the past.
            }
            // it is possible to start that way
            // by a trigger with a local time.
            ent.v.nextthink          = 0;
            Progs.GlobalStruct.time  = thinktime;
            Progs.GlobalStruct.self  = EdictToProg(ent);
            Progs.GlobalStruct.other = EdictToProg(sv.edicts[0]);
            Progs.Execute(ent.v.think);

            return(!ent.free);
        }
Beispiel #3
0
        /*
         * =================
         * PF_findradius
         *
         * Returns a chain of entities that have origins within a spherical area
         *
         * findradius (origin, radius)
         * =================
         */
        static unsafe void PF_findradius()
        {
            edict_t chain = Server.sv.edicts[0];

            float *org = GetVector(OFS.OFS_PARM0);
            float  rad = GetFloat(OFS.OFS_PARM1);

            Vector3 vorg;

            Copy(org, out vorg);

            for (int i = 1; i < Server.sv.num_edicts; i++)
            {
                edict_t ent = Server.sv.edicts[i];
                if (ent.free)
                {
                    continue;
                }
                if (ent.v.solid == Solids.SOLID_NOT)
                {
                    continue;
                }

                Vector3 v = vorg - (Common.ToVector(ref ent.v.origin) +
                                    (Common.ToVector(ref ent.v.mins) + Common.ToVector(ref ent.v.maxs)) * 0.5f);
                if (v.Length > rad)
                {
                    continue;
                }

                ent.v.chain = Server.EdictToProg(chain);
                chain       = ent;
            }

            ReturnEdict(chain);
        }
Beispiel #4
0
        /// <summary>
        /// SV_MoveToGoal
        /// </summary>
        public static void MoveToGoal()
        {
            edict_t ent  = ProgToEdict(Progs.GlobalStruct.self);
            edict_t goal = ProgToEdict(ent.v.goalentity);
            float   dist = QBuiltins.GetFloat(OFS.OFS_PARM0);

            if (((int)ent.v.flags & (EdictFlags.FL_ONGROUND | EdictFlags.FL_FLY | EdictFlags.FL_SWIM)) == 0)
            {
                QBuiltins.ReturnFloat(0);
                return;
            }

            // if the next step hits the enemy, return immediately
            if (ProgToEdict(ent.v.enemy) != sv.edicts[0] && CloseEnough(ent, goal, dist))
            {
                return;
            }

            // bump around...
            if ((Sys.Random() & 3) == 1 || !StepDirection(ent, ent.v.ideal_yaw, dist))
            {
                NewChaseDir(ent, goal, dist);
            }
        }
Beispiel #5
0
        /// <summary>
        /// SV_WriteClientdataToMessage
        /// </summary>
        public static void WriteClientDataToMessage(edict_t ent, MsgWriter msg)
        {
            //
            // send a damage message
            //
            if (ent.v.dmg_take != 0 || ent.v.dmg_save != 0)
            {
                edict_t other = ProgToEdict(ent.v.dmg_inflictor);
                msg.WriteByte(Protocol.svc_damage);
                msg.WriteByte((int)ent.v.dmg_save);
                msg.WriteByte((int)ent.v.dmg_take);
                msg.WriteCoord(other.v.origin.x + 0.5f * (other.v.mins.x + other.v.maxs.x));
                msg.WriteCoord(other.v.origin.y + 0.5f * (other.v.mins.y + other.v.maxs.y));
                msg.WriteCoord(other.v.origin.z + 0.5f * (other.v.mins.z + other.v.maxs.z));

                ent.v.dmg_take = 0;
                ent.v.dmg_save = 0;
            }

            //
            // send the current viewpos offset from the view entity
            //
            SetIdealPitch();            // how much to look up / down ideally

            // a fixangle might get lost in a dropped packet.  Oh well.
            if (ent.v.fixangle != 0)
            {
                msg.WriteByte(Protocol.svc_setangle);
                msg.WriteAngle(ent.v.angles.x);
                msg.WriteAngle(ent.v.angles.y);
                msg.WriteAngle(ent.v.angles.z);
                ent.v.fixangle = 0;
            }

            int bits = 0;

            if (ent.v.view_ofs.z != Protocol.DEFAULT_VIEWHEIGHT)
            {
                bits |= Protocol.SU_VIEWHEIGHT;
            }

            if (ent.v.idealpitch != 0)
            {
                bits |= Protocol.SU_IDEALPITCH;
            }

            // stuff the sigil bits into the high bits of items for sbar, or else
            // mix in items2
            float val = Progs.GetEdictFieldFloat(ent, "items2", 0);
            int   items;

            if (val != 0)
            {
                items = (int)ent.v.items | ((int)val << 23);
            }
            else
            {
                items = (int)ent.v.items | ((int)Progs.GlobalStruct.serverflags << 28);
            }

            bits |= Protocol.SU_ITEMS;

            if (((int)ent.v.flags & EdictFlags.FL_ONGROUND) != 0)
            {
                bits |= Protocol.SU_ONGROUND;
            }

            if (ent.v.waterlevel >= 2)
            {
                bits |= Protocol.SU_INWATER;
            }

            if (ent.v.punchangle.x != 0)
            {
                bits |= Protocol.SU_PUNCH1;
            }
            if (ent.v.punchangle.y != 0)
            {
                bits |= Protocol.SU_PUNCH2;
            }
            if (ent.v.punchangle.z != 0)
            {
                bits |= Protocol.SU_PUNCH3;
            }

            if (ent.v.velocity.x != 0)
            {
                bits |= Protocol.SU_VELOCITY1;
            }
            if (ent.v.velocity.y != 0)
            {
                bits |= Protocol.SU_VELOCITY2;
            }
            if (ent.v.velocity.z != 0)
            {
                bits |= Protocol.SU_VELOCITY3;
            }

            if (ent.v.weaponframe != 0)
            {
                bits |= Protocol.SU_WEAPONFRAME;
            }

            if (ent.v.armorvalue != 0)
            {
                bits |= Protocol.SU_ARMOR;
            }

            //	if (ent.v.weapon)
            bits |= Protocol.SU_WEAPON;

            // send the data

            msg.WriteByte(Protocol.svc_clientdata);
            msg.WriteShort(bits);

            if ((bits & Protocol.SU_VIEWHEIGHT) != 0)
            {
                msg.WriteChar((int)ent.v.view_ofs.z);
            }

            if ((bits & Protocol.SU_IDEALPITCH) != 0)
            {
                msg.WriteChar((int)ent.v.idealpitch);
            }

            if ((bits & Protocol.SU_PUNCH1) != 0)
            {
                msg.WriteChar((int)ent.v.punchangle.x);
            }
            if ((bits & Protocol.SU_VELOCITY1) != 0)
            {
                msg.WriteChar((int)(ent.v.velocity.x / 16));
            }

            if ((bits & Protocol.SU_PUNCH2) != 0)
            {
                msg.WriteChar((int)ent.v.punchangle.y);
            }
            if ((bits & Protocol.SU_VELOCITY2) != 0)
            {
                msg.WriteChar((int)(ent.v.velocity.y / 16));
            }

            if ((bits & Protocol.SU_PUNCH3) != 0)
            {
                msg.WriteChar((int)ent.v.punchangle.z);
            }
            if ((bits & Protocol.SU_VELOCITY3) != 0)
            {
                msg.WriteChar((int)(ent.v.velocity.z / 16));
            }

            // always sent
            msg.WriteLong(items);

            if ((bits & Protocol.SU_WEAPONFRAME) != 0)
            {
                msg.WriteByte((int)ent.v.weaponframe);
            }
            if ((bits & Protocol.SU_ARMOR) != 0)
            {
                msg.WriteByte((int)ent.v.armorvalue);
            }
            if ((bits & Protocol.SU_WEAPON) != 0)
            {
                msg.WriteByte(ModelIndex(Progs.GetString(ent.v.weaponmodel)));
            }

            msg.WriteShort((int)ent.v.health);
            msg.WriteByte((int)ent.v.currentammo);
            msg.WriteByte((int)ent.v.ammo_shells);
            msg.WriteByte((int)ent.v.ammo_nails);
            msg.WriteByte((int)ent.v.ammo_rockets);
            msg.WriteByte((int)ent.v.ammo_cells);

            if (Common.GameKind == GameKind.StandardQuake)
            {
                msg.WriteByte((int)ent.v.weapon);
            }
            else
            {
                for (int i = 0; i < 32; i++)
                {
                    if ((((int)ent.v.weapon) & (1 << i)) != 0)
                    {
                        msg.WriteByte(i);
                        break;
                    }
                }
            }
        }
Beispiel #6
0
        static trace_t Move(ref v3f start, ref v3f mins, ref v3f maxs, ref v3f end, int type, edict_t passedict)
        {
            Vector3 vstart, vmins, vmaxs, vend;

            Mathlib.Copy(ref start, out vstart);
            Mathlib.Copy(ref mins, out vmins);
            Mathlib.Copy(ref maxs, out vmaxs);
            Mathlib.Copy(ref end, out vend);
            return(Move(ref vstart, ref vmins, ref vmaxs, ref vend, type, passedict));
        }
Beispiel #7
0
        /// <summary>
        /// SV_Physics_Client
        /// Player character actions
        /// </summary>
        static void Physics_Client(edict_t ent, int num)
        {
            if (!svs.clients[num - 1].active)
            {
                return;         // unconnected slot
            }
            //
            // call standard client pre-think
            //
            Progs.GlobalStruct.time = (float)sv.time;
            Progs.GlobalStruct.self = EdictToProg(ent);
            Progs.Execute(Progs.GlobalStruct.PlayerPreThink);

            //
            // do a move
            //
            CheckVelocity(ent);

            //
            // decide which move function to call
            //
            switch ((int)ent.v.movetype)
            {
            case Movetypes.MOVETYPE_NONE:
                if (!RunThink(ent))
                {
                    return;
                }
                break;

            case Movetypes.MOVETYPE_WALK:
                if (!RunThink(ent))
                {
                    return;
                }
                if (!CheckWater(ent) && ((int)ent.v.flags & EdictFlags.FL_WATERJUMP) == 0)
                {
                    AddGravity(ent);
                }
                CheckStuck(ent);

                WalkMove(ent);
                break;

            case Movetypes.MOVETYPE_TOSS:
            case Movetypes.MOVETYPE_BOUNCE:
                Physics_Toss(ent);
                break;

            case Movetypes.MOVETYPE_FLY:
                if (!RunThink(ent))
                {
                    return;
                }
                FlyMove(ent, (float)Host.FrameTime, null);
                break;

            case Movetypes.MOVETYPE_NOCLIP:
                if (!RunThink(ent))
                {
                    return;
                }
                Mathlib.VectorMA(ref ent.v.origin, (float)Host.FrameTime, ref ent.v.velocity, out ent.v.origin);
                break;

            default:
                Sys.Error("SV_Physics_client: bad movetype {0}", (int)ent.v.movetype);
                break;
            }

            //
            // call standard player post-think
            //
            LinkEdict(ent, true);

            Progs.GlobalStruct.time = (float)sv.time;
            Progs.GlobalStruct.self = EdictToProg(ent);
            Progs.Execute(Progs.GlobalStruct.PlayerPostThink);
        }
Beispiel #8
0
        /// <summary>
        /// SV_Physics_Toss
        /// Toss, bounce, and fly movement.  When onground, do nothing.
        /// </summary>
        private static void Physics_Toss(edict_t ent)
        {
            // regular thinking
            if (!RunThink(ent))
            {
                return;
            }

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

            CheckVelocity(ent);

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


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

            // move origin
            v3f move;

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

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

            float backoff;

            if (ent.v.movetype == Movetypes.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 != Movetypes.MOVETYPE_BOUNCE)
                {
                    ent.v.flags        = (int)ent.v.flags | EdictFlags.FL_ONGROUND;
                    ent.v.groundentity = EdictToProg(trace.ent);
                    ent.v.velocity     = default(v3f);
                    ent.v.avelocity    = default(v3f);
                }
            }

            // check for in water
            CheckWaterTransition(ent);
        }
Beispiel #9
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);
            }
        }
Beispiel #10
0
        static void PF_Spawn()
        {
            edict_t ed = Server.AllocEdict();

            ReturnEdict(ed);
        }
Beispiel #11
0
 /// <summary>
 /// SV_FixCheckBottom
 /// </summary>
 static void FixCheckBottom(edict_t ent)
 {
     ent.v.flags = (int)ent.v.flags | EdictFlags.FL_PARTIALGROUND;
 }
Beispiel #12
0
        /// <summary>
        /// SV_movestep
        /// 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
        /// </summary>
        public static bool MoveStep(edict_t ent, ref v3f move, bool relink)
        {
            trace_t trace;

            // try the move
            v3f oldorg = ent.v.origin;
            v3f neworg;

            Mathlib.VectorAdd(ref ent.v.origin, ref move, out neworg);

            // flying monsters don't step up
            if (((int)ent.v.flags & (EdictFlags.FL_SWIM | EdictFlags.FL_FLY)) != 0)
            {
                // try one move with vertical motion, then one without
                for (int i = 0; i < 2; i++)
                {
                    Mathlib.VectorAdd(ref ent.v.origin, ref move, out neworg);
                    edict_t enemy = ProgToEdict(ent.v.enemy);
                    if (i == 0 && enemy != sv.edicts[0])
                    {
                        float dz = ent.v.origin.z - enemy.v.origin.z;
                        if (dz > 40)
                        {
                            neworg.z -= 8;
                        }
                        if (dz < 30)
                        {
                            neworg.z += 8;
                        }
                    }

                    trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref neworg, 0, ent);
                    if (trace.fraction == 1)
                    {
                        if (((int)ent.v.flags & EdictFlags.FL_SWIM) != 0 &&
                            PointContents(ref trace.endpos) == Contents.CONTENTS_EMPTY)
                        {
                            return(false);       // swim monster left water
                        }
                        Mathlib.Copy(ref trace.endpos, out ent.v.origin);
                        if (relink)
                        {
                            LinkEdict(ent, true);
                        }
                        return(true);
                    }

                    if (enemy == sv.edicts[0])
                    {
                        break;
                    }
                }

                return(false);
            }

            // push down from a step height above the wished position
            neworg.z += STEPSIZE;
            v3f end = neworg;

            end.z -= STEPSIZE * 2;

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

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

            if (trace.startsolid)
            {
                neworg.z -= STEPSIZE;
                trace     = Move(ref neworg, ref ent.v.mins, ref ent.v.maxs, ref end, 0, ent);
                if (trace.allsolid || trace.startsolid)
                {
                    return(false);
                }
            }
            if (trace.fraction == 1)
            {
                // if monster had the ground pulled out, go ahead and fall
                if (((int)ent.v.flags & EdictFlags.FL_PARTIALGROUND) != 0)
                {
                    Mathlib.VectorAdd(ref ent.v.origin, ref move, out ent.v.origin);
                    if (relink)
                    {
                        LinkEdict(ent, true);
                    }
                    ent.v.flags = (int)ent.v.flags & ~EdictFlags.FL_ONGROUND;
                    return(true);
                }

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

            // check point traces down for dangling corners
            Mathlib.Copy(ref trace.endpos, out ent.v.origin);

            if (!CheckBottom(ent))
            {
                if (((int)ent.v.flags & EdictFlags.FL_PARTIALGROUND) != 0)
                {
                    // entity had floor mostly pulled out from underneath it
                    // and is trying to correct
                    if (relink)
                    {
                        LinkEdict(ent, true);
                    }
                    return(true);
                }
                ent.v.origin = oldorg;
                return(false);
            }

            if (((int)ent.v.flags & EdictFlags.FL_PARTIALGROUND) != 0)
            {
                ent.v.flags = (int)ent.v.flags & ~EdictFlags.FL_PARTIALGROUND;
            }
            ent.v.groundentity = EdictToProg(trace.ent);

            // the move is ok
            if (relink)
            {
                LinkEdict(ent, true);
            }
            return(true);
        }
Beispiel #13
0
        /// <summary>
        /// SV_NewChaseDir
        /// </summary>
        static void NewChaseDir(edict_t actor, edict_t enemy, float dist)
        {
            float olddir     = Mathlib.AngleMod((int)(actor.v.ideal_yaw / 45) * 45);
            float turnaround = Mathlib.AngleMod(olddir - 180);

            float deltax = enemy.v.origin.x - actor.v.origin.x;
            float deltay = enemy.v.origin.y - actor.v.origin.y;
            v3f   d;

            if (deltax > 10)
            {
                d.y = 0;
            }
            else if (deltax < -10)
            {
                d.y = 180;
            }
            else
            {
                d.y = DI_NODIR;
            }
            if (deltay < -10)
            {
                d.z = 270;
            }
            else if (deltay > 10)
            {
                d.z = 90;
            }
            else
            {
                d.z = DI_NODIR;
            }

            // try direct route
            float tdir;

            if (d.y != DI_NODIR && d.z != DI_NODIR)
            {
                if (d.y == 0)
                {
                    tdir = (d.z == 90 ? 45 : 315);
                }
                else
                {
                    tdir = (d.z == 90 ? 135 : 215);
                }

                if (tdir != turnaround && StepDirection(actor, tdir, dist))
                {
                    return;
                }
            }

            // try other directions
            if (((Sys.Random() & 3) & 1) != 0 || Math.Abs(deltay) > Math.Abs(deltax))
            {
                tdir = d.y;
                d.y  = d.z;
                d.z  = tdir;
            }

            if (d.y != DI_NODIR && d.y != turnaround && StepDirection(actor, d.y, dist))
            {
                return;
            }

            if (d.z != DI_NODIR && d.z != turnaround && StepDirection(actor, d.z, dist))
            {
                return;
            }

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

            if (olddir != DI_NODIR && StepDirection(actor, olddir, dist))
            {
                return;
            }

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

            if (turnaround != DI_NODIR && StepDirection(actor, turnaround, dist))
            {
                return;
            }

            actor.v.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 (!CheckBottom(actor))
            {
                FixCheckBottom(actor);
            }
        }
Beispiel #14
0
        /// <summary>
        /// SV_CheckBottom
        /// </summary>
        public static bool 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 (PointContents(ref start) != Contents.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 * STEPSIZE;
            trace_t trace = Move(ref start, ref Common.ZeroVector, ref Common.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 = Move(ref start, ref Common.ZeroVector, ref Common.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 > STEPSIZE)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Beispiel #15
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]);
            }
        }
Beispiel #16
0
        static void PF_Remove()
        {
            edict_t ed = GetEdict(OFS.OFS_PARM0);

            Server.FreeEdict(ed);
        }
Beispiel #17
0
        /// <summary>
        /// SV_Move
        /// mins and maxs are relative
        /// if the entire move stays in a solid volume, trace.allsolid will be set
        /// if the starting point is in a solid, it will be allowed to move out to an open area
        /// nomonsters is used for line of sight or edge testing, where mosnters
        /// shouldn't be considered solid objects
        /// passedict is explicitly excluded from clipping checks (normally NULL)
        /// </summary>
        public static trace_t Move(ref Vector3 start, ref Vector3 mins, ref Vector3 maxs, ref Vector3 end, int type, edict_t passedict)
        {
            moveclip_t clip = new moveclip_t();

            // clip to world
            clip.trace = ClipMoveToEntity(sv.edicts[0], ref start, ref mins, ref maxs, ref end);

            clip.start     = start;
            clip.end       = end;
            clip.mins      = mins;
            clip.maxs      = maxs;
            clip.type      = type;
            clip.passedict = passedict;

            if (type == MOVE_MISSILE)
            {
                clip.mins2 = Vector3.One * -15;
                clip.maxs2 = Vector3.One * 15;
            }
            else
            {
                clip.mins2 = mins;
                clip.maxs2 = maxs;
            }

            // create the bounding box of the entire move
            MoveBounds(ref start, ref clip.mins2, ref clip.maxs2, ref end, out clip.boxmins, out clip.boxmaxs);

            // clip to entities
            ClipToLinks(_AreaNodes[0], clip);

            return(clip.trace);
        }
Beispiel #18
0
        /// <summary>
        /// PF_checkbottom
        /// </summary>
        static void PF_checkbottom()
        {
            edict_t ent = GetEdict(OFS.OFS_PARM0);

            ReturnFloat(Server.CheckBottom(ent) ? 1 : 0);
        }
Beispiel #19
0
        /// <summary>
        /// SV_PushMove
        /// </summary>
        static void PushMove(edict_t pusher, float movetime)
        {
            if (pusher.v.velocity.IsEmpty)
            {
                pusher.v.ltime += movetime;
                return;
            }

            v3f move, mins, maxs;

            Mathlib.VectorScale(ref pusher.v.velocity, movetime, out move);
            Mathlib.VectorAdd(ref pusher.v.absmin, ref move, out mins);
            Mathlib.VectorAdd(ref pusher.v.absmax, ref move, out maxs);

            v3f pushorig = pusher.v.origin;

            edict_t[] moved_edict = new edict_t[QDef.MAX_EDICTS];
            v3f[]     moved_from  = new v3f[QDef.MAX_EDICTS];

            // move the pusher to it's final position

            Mathlib.VectorAdd(ref pusher.v.origin, ref move, out pusher.v.origin);
            pusher.v.ltime += movetime;
            LinkEdict(pusher, false);


            // see if any solid entities are inside the final position
            int num_moved = 0;

            for (int e = 1; e < sv.num_edicts; e++)
            {
                edict_t check = sv.edicts[e];
                if (check.free)
                {
                    continue;
                }
                if (check.v.movetype == Movetypes.MOVETYPE_PUSH ||
                    check.v.movetype == Movetypes.MOVETYPE_NONE ||
                    check.v.movetype == Movetypes.MOVETYPE_NOCLIP)
                {
                    continue;
                }

                // if the entity is standing on the pusher, it will definately be moved
                if (!(((int)check.v.flags & EdictFlags.FL_ONGROUND) != 0 && ProgToEdict(check.v.groundentity) == pusher))
                {
                    if (check.v.absmin.x >= maxs.x || check.v.absmin.y >= maxs.y ||
                        check.v.absmin.z >= maxs.z || check.v.absmax.x <= mins.x ||
                        check.v.absmax.y <= mins.y || check.v.absmax.z <= mins.z)
                    {
                        continue;
                    }

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

                // remove the onground flag for non-players
                if (check.v.movetype != Movetypes.MOVETYPE_WALK)
                {
                    check.v.flags = (int)check.v.flags & ~EdictFlags.FL_ONGROUND;
                }

                v3f entorig = check.v.origin;
                moved_from[num_moved]  = entorig;
                moved_edict[num_moved] = check;
                num_moved++;

                // try moving the contacted entity
                pusher.v.solid = Solids.SOLID_NOT;
                PushEntity(check, ref move);
                pusher.v.solid = Solids.SOLID_BSP;

                // if it is still inside the pusher, block
                edict_t block = TestEntityPosition(check);
                if (block != null)
                {
                    // fail the move
                    if (check.v.mins.x == check.v.maxs.x)
                    {
                        continue;
                    }
                    if (check.v.solid == Solids.SOLID_NOT || check.v.solid == Solids.SOLID_TRIGGER)
                    {
                        // corpse
                        check.v.mins.x = check.v.mins.y = 0;
                        check.v.maxs   = check.v.mins;
                        continue;
                    }

                    check.v.origin = entorig;
                    LinkEdict(check, true);

                    pusher.v.origin = pushorig;
                    LinkEdict(pusher, false);
                    pusher.v.ltime -= movetime;

                    // if the pusher has a "blocked" function, call it
                    // otherwise, just stay in place until the obstacle is gone
                    if (pusher.v.blocked != 0)
                    {
                        Progs.GlobalStruct.self  = EdictToProg(pusher);
                        Progs.GlobalStruct.other = EdictToProg(check);
                        Progs.Execute(pusher.v.blocked);
                    }

                    // move back any entities we already moved
                    for (int i = 0; i < num_moved; i++)
                    {
                        moved_edict[i].v.origin = moved_from[i];
                        LinkEdict(moved_edict[i], false);
                    }
                    return;
                }
            }
        }
Beispiel #20
0
        /*
         * =============
         * PF_aim
         *
         * Pick a vector for the player to shoot along
         * vector aim(entity, missilespeed)
         * =============
         */
        static void PF_aim()
        {
            edict_t ent   = GetEdict(OFS.OFS_PARM0);
            float   speed = GetFloat(OFS.OFS_PARM1);

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

            start.Z += 20;

            // try sending a trace straight
            Vector3 dir;

            Mathlib.Copy(ref Progs.GlobalStruct.v_forward, out dir);
            Vector3 end = start + dir * 2048;
            trace_t tr  = Server.Move(ref start, ref Common.ZeroVector, ref Common.ZeroVector, ref end, 0, ent);

            if (tr.ent != null && tr.ent.v.takedamage == Damages.DAMAGE_AIM &&
                (Host.TeamPlay == 0 || ent.v.team <= 0 || ent.v.team != tr.ent.v.team))
            {
                ReturnVector(ref Progs.GlobalStruct.v_forward);
                return;
            }

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

            for (int i = 1; i < Server.sv.num_edicts; i++)
            {
                edict_t check = Server.sv.edicts[i];
                if (check.v.takedamage != Damages.DAMAGE_AIM)
                {
                    continue;
                }
                if (check == ent)
                {
                    continue;
                }
                if (Host.TeamPlay != 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, Common.ToVector(ref Progs.GlobalStruct.v_forward));
                if (dist < bestdist)
                {
                    continue;   // to far to turn
                }
                tr = Server.Move(ref start, ref Common.ZeroVector, ref Common.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 Progs.GlobalStruct.v_forward);
                Mathlib.VectorScale(ref Progs.GlobalStruct.v_forward, dist, out end2);
                end2.z = dir2.z;
                Mathlib.Normalize(ref end2);
                ReturnVector(ref end2);
            }
            else
            {
                ReturnVector(ref bestdir);
            }
        }
Beispiel #21
0
 /// <summary>
 /// SV_Physics_None
 /// Non moving objects can only think
 /// </summary>
 static void Physics_None(edict_t ent)
 {
     // regular thinking
     RunThink(ent);
 }
Beispiel #22
0
        /// <summary>
        /// RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
        /// </summary>
        public static unsafe void ReturnEdict(edict_t e)
        {
            int prog = Server.EdictToProg(e);

            ReturnInt(prog);
        }
Beispiel #23
0
        /// <summary>
        /// SV_Physics
        /// </summary>
        public static void Physics()
        {
            // let the progs know that a new frame has started
            Progs.GlobalStruct.self  = EdictToProg(sv.edicts[0]);
            Progs.GlobalStruct.other = Progs.GlobalStruct.self;
            Progs.GlobalStruct.time  = (float)sv.time;
            Progs.Execute(Progs.GlobalStruct.StartFrame);

            //
            // treat each object in turn
            //
            for (int i = 0; i < sv.num_edicts; i++)
            {
                edict_t ent = sv.edicts[i];
                if (ent.free)
                {
                    continue;
                }

                if (Progs.GlobalStruct.force_retouch != 0)
                {
                    LinkEdict(ent, true);       // force retouch even for stationary
                }

                if (i > 0 && i <= svs.maxclients)
                {
                    Physics_Client(ent, i);
                }
                else
                {
                    switch ((int)ent.v.movetype)
                    {
                    case Movetypes.MOVETYPE_PUSH:
                        Physics_Pusher(ent);
                        break;

                    case Movetypes.MOVETYPE_NONE:
                        Physics_None(ent);
                        break;

                    case Movetypes.MOVETYPE_NOCLIP:
                        Physics_Noclip(ent);
                        break;

                    case Movetypes.MOVETYPE_STEP:
                        Physics_Step(ent);
                        break;

                    case Movetypes.MOVETYPE_TOSS:
                    case Movetypes.MOVETYPE_BOUNCE:
                    case Movetypes.MOVETYPE_FLY:
                    case Movetypes.MOVETYPE_FLYMISSILE:
                        Physics_Toss(ent);
                        break;

                    default:
                        Sys.Error("SV_Physics: bad movetype {0}", (int)ent.v.movetype);
                        break;
                    }
                }
            }

            if (Progs.GlobalStruct.force_retouch != 0)
            {
                Progs.GlobalStruct.force_retouch -= 1;
            }

            sv.time += Host.FrameTime;
        }
Beispiel #24
0
        static void SetMinMaxSize(edict_t e, ref Vector3 min, ref Vector3 max, bool rotate)
        {
            if (min.X > max.X || min.Y > max.Y || min.Z > max.Z)
            {
                Progs.RunError("backwards mins/maxs");
            }

            rotate = false;             // FIXME: implement rotation properly again

            Vector3 rmin = min, rmax = max;

            if (!rotate)
            {
                //rmin = min;
                //rmax = max;
            }
            else
            {
                // find min / max for rotations
                //angles = e.v.angles;

                //a = angles[1] / 180 * M_PI;

                //xvector[0] = cos(a);
                //xvector[1] = sin(a);
                //yvector[0] = -sin(a);
                //yvector[1] = cos(a);

                //VectorCopy(min, bounds[0]);
                //VectorCopy(max, bounds[1]);

                //rmin[0] = rmin[1] = rmin[2] = 9999;
                //rmax[0] = rmax[1] = rmax[2] = -9999;

                //for (i = 0; i <= 1; i++)
                //{
                //    base[0] = bounds[i][0];
                //    for (j = 0; j <= 1; j++)
                //    {
                //        base[1] = bounds[j][1];
                //        for (k = 0; k <= 1; k++)
                //        {
                //            base[2] = bounds[k][2];

                //            // transform the point
                //            transformed[0] = xvector[0] * base[0] + yvector[0] * base[1];
                //            transformed[1] = xvector[1] * base[0] + yvector[1] * base[1];
                //            transformed[2] = base[2];

                //            for (l = 0; l < 3; l++)
                //            {
                //                if (transformed[l] < rmin[l])
                //                    rmin[l] = transformed[l];
                //                if (transformed[l] > rmax[l])
                //                    rmax[l] = transformed[l];
                //            }
                //        }
                //    }
                //}
            }

            // set derived values
            Mathlib.Copy(ref rmin, out e.v.mins);
            Mathlib.Copy(ref rmax, out e.v.maxs);
            Vector3 s = max - min;

            Mathlib.Copy(ref s, out e.v.size);

            Server.LinkEdict(e, false);
        }
Beispiel #25
0
        /// <summary>
        /// SV_WalkMove
        /// Only used by players
        /// </summary>
        static void WalkMove(edict_t ent)
        {
            //
            // do a regular slide move unless it looks like you ran into a step
            //
            int oldonground = (int)ent.v.flags & EdictFlags.FL_ONGROUND;

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

            v3f     oldorg    = ent.v.origin;
            v3f     oldvel    = ent.v.velocity;
            trace_t steptrace = new trace_t();
            int     clip      = FlyMove(ent, (float)Host.FrameTime, steptrace);

            if ((clip & 2) == 0)
            {
                return;         // move didn't block on a step
            }
            if (ent.v.movetype != Movetypes.MOVETYPE_WALK)
            {
                return;         // gibbed by a trigger
            }
            if (_NoStep.Value != 0)
            {
                return;
            }

            if (((int)_Player.v.flags & EdictFlags.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   = Common.ZeroVector3f;
            v3f downmove = upmove;

            upmove.z   = STEPSIZE;
            downmove.z = (float)(-STEPSIZE + oldvel.z * Host.FrameTime);

            // 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             = FlyMove(ent, (float)Host.FrameTime, 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 = TryUnstick(ent, ref oldvel);
                }
            }

            // extra friction based on view angle
            if ((clip & 2) != 0)
            {
                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 == Solids.SOLID_BSP)
                {
                    ent.v.flags        = (int)ent.v.flags | EdictFlags.FL_ONGROUND;
                    ent.v.groundentity = EdictToProg(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 #26
0
        /// <summary>
        /// ED_LoadFromFile
        /// The entities are directly placed in the array, rather than allocated with
        /// ED_Alloc, because otherwise an error loading the map would have entity
        /// number references out of order.
        ///
        /// Creates a server's entity / program execution context by
        /// parsing textual entity definitions out of an ent file.
        ///
        /// Used for both fresh maps and savegame loads.  A fresh map would also need
        /// to call ED_CallSpawnFunctions () to let the objects initialize themselves.
        /// </summary>
        public static void LoadFromFile(string data)
        {
            edict_t ent     = null;
            int     inhibit = 0;

            Progs.GlobalStruct.time = (float)Server.sv.time;

            // parse ents
            while (true)
            {
                // parse the opening brace
                data = Common.Parse(data);
                if (data == null)
                {
                    break;
                }

                if (Common.Token != "{")
                {
                    Sys.Error("ED_LoadFromFile: found {0} when expecting {", Common.Token);
                }

                if (ent == null)
                {
                    ent = Server.EdictNum(0);
                }
                else
                {
                    ent = Server.AllocEdict();
                }
                data = ParseEdict(data, ent);

                // remove things from different skill levels or deathmatch
                if (Host.Deathmatch != 0)
                {
                    if (((int)ent.v.spawnflags & SpawnFlags.SPAWNFLAG_NOT_DEATHMATCH) != 0)
                    {
                        Server.FreeEdict(ent);
                        inhibit++;
                        continue;
                    }
                }
                else if ((Host.CurrentSkill == 0 && ((int)ent.v.spawnflags & SpawnFlags.SPAWNFLAG_NOT_EASY) != 0) ||
                         (Host.CurrentSkill == 1 && ((int)ent.v.spawnflags & SpawnFlags.SPAWNFLAG_NOT_MEDIUM) != 0) ||
                         (Host.CurrentSkill >= 2 && ((int)ent.v.spawnflags & SpawnFlags.SPAWNFLAG_NOT_HARD) != 0))
                {
                    Server.FreeEdict(ent);
                    inhibit++;
                    continue;
                }

                //
                // immediately call spawn function
                //
                if (ent.v.classname == 0)
                {
                    Con.Print("No classname for:\n");
                    Print(ent);
                    Server.FreeEdict(ent);
                    continue;
                }

                // look for the spawn function
                int func = IndexOfFunction(GetString(ent.v.classname));
                if (func == -1)
                {
                    Con.Print("No spawn function for:\n");
                    Print(ent);
                    Server.FreeEdict(ent);
                    continue;
                }

                Progs.GlobalStruct.self = Server.EdictToProg(ent);
                Execute(func);
            }

            Con.DPrint("{0} entities inhibited\n", inhibit);
        }
Beispiel #27
0
        /// <summary>
        /// SV_FlyMove
        /// The basic solid body movement clip that slides along multiple planes
        /// Returns the clipflags if the velocity was modified (hit something solid)
        /// 1 = floor
        /// 2 = wall / step
        /// 4 = dead stop
        /// If steptrace is not NULL, the trace of any vertical wall hit will be stored
        /// </summary>
        static int 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[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 == Solids.SOLID_BSP)
                    {
                        ent.v.flags        = (int)ent.v.flags | EdictFlags.FL_ONGROUND;
                        ent.v.groundentity = EdictToProg(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
                //
                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 >= 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 #28
0
        /// <summary>
        /// ED_ParseEdict
        /// Parses an edict out of the given string, returning the new position
        /// ed should be a properly initialized empty edict.
        /// Used for initial level load and for savegames.
        /// </summary>
        public static string ParseEdict(string data, edict_t ent)
        {
            bool init = false;

            // clear it
            if (ent != Server.sv.edicts[0])     // hack
            {
                ent.Clear();
            }

            // go through all the dictionary pairs
            bool anglehack;

            while (true)
            {
                // parse key
                data = Common.Parse(data);
                if (Common.Token.StartsWith("}"))
                {
                    break;
                }

                if (data == null)
                {
                    Sys.Error("ED_ParseEntity: EOF without closing brace");
                }

                string token = Common.Token;

                // anglehack is to allow QuakeEd to write single scalar angles
                // and allow them to be turned into vectors. (FIXME...)
                if (token == "angle")
                {
                    token     = "angles";
                    anglehack = true;
                }
                else
                {
                    anglehack = false;
                }

                // FIXME: change light to _light to get rid of this hack
                if (token == "light")
                {
                    token = "light_lev";        // hack for single light def
                }
                string keyname = token.TrimEnd();

                // parse value
                data = Common.Parse(data);
                if (data == null)
                {
                    Sys.Error("ED_ParseEntity: EOF without closing brace");
                }

                if (Common.Token.StartsWith("}"))
                {
                    Sys.Error("ED_ParseEntity: closing brace without data");
                }

                init = true;

                // keynames with a leading underscore are used for utility comments,
                // and are immediately discarded by quake
                if (keyname[0] == '_')
                {
                    continue;
                }

                ddef_t key = FindField(keyname);
                if (key == null)
                {
                    Con.Print("'{0}' is not a field\n", keyname);
                    continue;
                }

                token = Common.Token;
                if (anglehack)
                {
                    token = "0 " + token + " 0";
                }

                if (!ParsePair(ent, key, token))
                {
                    Host.Error("ED_ParseEdict: parse error");
                }
            }

            if (!init)
            {
                ent.free = true;
            }

            return(data);
        }
Beispiel #29
0
 /// <summary>
 /// EDICT_TO_PROG(e)
 /// </summary>
 public static int EdictToProg(edict_t e)
 {
     return(Array.IndexOf(_Server.edicts, e)); // todo: optimize this
 }
Beispiel #30
0
        /// <summary>
        /// SV_WriteEntitiesToClient
        /// </summary>
        static void WriteEntitiesToClient(edict_t clent, MsgWriter msg)
        {
            // find the client's PVS
            Vector3 org = Common.ToVector(ref clent.v.origin) + Common.ToVector(ref clent.v.view_ofs);

            byte[] pvs = FatPVS(ref org);

            // send over all entities (except the client) that touch the pvs
            for (int e = 1; e < sv.num_edicts; e++)
            {
                edict_t ent = sv.edicts[e];
                // ignore if not touching a PV leaf
                if (ent != clent)       // clent is ALLWAYS sent
                {
                    // ignore ents without visible models
                    string mname = Progs.GetString(ent.v.model);
                    if (String.IsNullOrEmpty(mname))
                    {
                        continue;
                    }

                    int i;
                    for (i = 0; i < ent.num_leafs; i++)
                    {
                        if ((pvs[ent.leafnums[i] >> 3] & (1 << (ent.leafnums[i] & 7))) != 0)
                        {
                            break;
                        }
                    }

                    if (i == ent.num_leafs)
                    {
                        continue;               // not visible
                    }
                }

                if (msg.Capacity - msg.Length < 16)
                {
                    Con.Print("packet overflow\n");
                    return;
                }

                // send an update
                int bits = 0;
                v3f miss;
                Mathlib.VectorSubtract(ref ent.v.origin, ref ent.baseline.origin, out miss);
                if (miss.x < -0.1f || miss.x > 0.1f)
                {
                    bits |= Protocol.U_ORIGIN1;
                }
                if (miss.y < -0.1f || miss.y > 0.1f)
                {
                    bits |= Protocol.U_ORIGIN2;
                }
                if (miss.z < -0.1f || miss.z > 0.1f)
                {
                    bits |= Protocol.U_ORIGIN3;
                }

                if (ent.v.angles.x != ent.baseline.angles.x)
                {
                    bits |= Protocol.U_ANGLE1;
                }

                if (ent.v.angles.y != ent.baseline.angles.y)
                {
                    bits |= Protocol.U_ANGLE2;
                }

                if (ent.v.angles.z != ent.baseline.angles.z)
                {
                    bits |= Protocol.U_ANGLE3;
                }

                if (ent.v.movetype == Movetypes.MOVETYPE_STEP)
                {
                    bits |= Protocol.U_NOLERP;  // don't mess up the step animation
                }
                if (ent.baseline.colormap != ent.v.colormap)
                {
                    bits |= Protocol.U_COLORMAP;
                }

                if (ent.baseline.skin != ent.v.skin)
                {
                    bits |= Protocol.U_SKIN;
                }

                if (ent.baseline.frame != ent.v.frame)
                {
                    bits |= Protocol.U_FRAME;
                }

                if (ent.baseline.effects != ent.v.effects)
                {
                    bits |= Protocol.U_EFFECTS;
                }

                if (ent.baseline.modelindex != ent.v.modelindex)
                {
                    bits |= Protocol.U_MODEL;
                }

                if (e >= 256)
                {
                    bits |= Protocol.U_LONGENTITY;
                }

                if (bits >= 256)
                {
                    bits |= Protocol.U_MOREBITS;
                }

                //
                // write the message
                //
                msg.WriteByte(bits | Protocol.U_SIGNAL);

                if ((bits & Protocol.U_MOREBITS) != 0)
                {
                    msg.WriteByte(bits >> 8);
                }
                if ((bits & Protocol.U_LONGENTITY) != 0)
                {
                    msg.WriteShort(e);
                }
                else
                {
                    msg.WriteByte(e);
                }

                if ((bits & Protocol.U_MODEL) != 0)
                {
                    msg.WriteByte((int)ent.v.modelindex);
                }
                if ((bits & Protocol.U_FRAME) != 0)
                {
                    msg.WriteByte((int)ent.v.frame);
                }
                if ((bits & Protocol.U_COLORMAP) != 0)
                {
                    msg.WriteByte((int)ent.v.colormap);
                }
                if ((bits & Protocol.U_SKIN) != 0)
                {
                    msg.WriteByte((int)ent.v.skin);
                }
                if ((bits & Protocol.U_EFFECTS) != 0)
                {
                    msg.WriteByte((int)ent.v.effects);
                }
                if ((bits & Protocol.U_ORIGIN1) != 0)
                {
                    msg.WriteCoord(ent.v.origin.x);
                }
                if ((bits & Protocol.U_ANGLE1) != 0)
                {
                    msg.WriteAngle(ent.v.angles.x);
                }
                if ((bits & Protocol.U_ORIGIN2) != 0)
                {
                    msg.WriteCoord(ent.v.origin.y);
                }
                if ((bits & Protocol.U_ANGLE2) != 0)
                {
                    msg.WriteAngle(ent.v.angles.y);
                }
                if ((bits & Protocol.U_ORIGIN3) != 0)
                {
                    msg.WriteCoord(ent.v.origin.z);
                }
                if ((bits & Protocol.U_ANGLE3) != 0)
                {
                    msg.WriteAngle(ent.v.angles.z);
                }
            }
        }