예제 #1
0
        static void PF_precache_model()
        {
            if (!Server.IsLoading)
            {
                Progs.RunError("PF_Precache_*: Precache can only be done in spawn functions");
            }

            string s = GetString(OFS.OFS_PARM0);

            ReturnInt(GetInt(OFS.OFS_PARM0)); //G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
            CheckEmptyString(s);

            for (int i = 0; i < QDef.MAX_MODELS; i++)
            {
                if (Server.sv.model_precache[i] == null)
                {
                    Server.sv.model_precache[i] = s;
                    Server.sv.models[i]         = Mod.ForName(s, true);
                    return;
                }
                if (Server.sv.model_precache[i] == s)
                {
                    return;
                }
            }
            Progs.RunError("PF_precache_model: overflow");
        }
예제 #2
0
        /// <summary>
        /// Host_Pause_f
        /// </summary>
        private static void Pause_f()
        {
            if (Cmd.Source == cmd_source_t.src_command)
            {
                Cmd.ForwardToServer();
                return;
            }
            if (_Pausable.Value == 0)
            {
                Server.ClientPrint("Pause not allowed.\n");
            }
            else
            {
                Server.sv.paused = !Server.sv.paused;

                if (Server.sv.paused)
                {
                    Server.BroadcastPrint("{0} paused the game\n", Progs.GetString(Server.Player.v.netname));
                }
                else
                {
                    Server.BroadcastPrint("{0} unpaused the game\n", Progs.GetString(Server.Player.v.netname));
                }

                // send notification to all clients
                Server.sv.reliable_datagram.WriteByte(Protocol.svc_setpause);
                Server.sv.reliable_datagram.WriteByte(Server.sv.paused ? 1 : 0);
            }
        }
예제 #3
0
 static void CheckEmptyString(string s)
 {
     if (s == null || s.Length == 0 || s[0] <= ' ')
     {
         Progs.RunError("Bad string");
     }
 }
예제 #4
0
        static void PF_precache_sound()
        {
            if (!Server.IsLoading)
            {
                Progs.RunError("PF_Precache_*: Precache can only be done in spawn functions");
            }

            string s = GetString(OFS.OFS_PARM0);

            ReturnInt(GetInt(OFS.OFS_PARM0)); //  G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
            CheckEmptyString(s);

            for (int i = 0; i < QDef.MAX_SOUNDS; i++)
            {
                if (Server.sv.sound_precache[i] == null)
                {
                    Server.sv.sound_precache[i] = s;
                    return;
                }
                if (Server.sv.sound_precache[i] == s)
                {
                    return;
                }
            }
            Progs.RunError("PF_precache_sound: overflow");
        }
예제 #5
0
        /// <summary>
        /// PF_Find
        /// entity (entity start, .string field, string match) find = #5;
        /// </summary>
        static void PF_Find()
        {
            int    e = GetInt(OFS.OFS_PARM0);
            int    f = GetInt(OFS.OFS_PARM1);
            string s = GetString(OFS.OFS_PARM2);

            if (s == null)
            {
                Progs.RunError("PF_Find: bad search string");
            }

            for (e++; e < Server.sv.num_edicts; e++)
            {
                edict_t ed = Server.EdictNum(e);
                if (ed.free)
                {
                    continue;
                }

                string t = Progs.GetString(ed.GetInt(f)); // E_STRING(ed, f);
                if (String.IsNullOrEmpty(t))
                {
                    continue;
                }

                if (t == s)
                {
                    ReturnEdict(ed);
                    return;
                }
            }

            ReturnEdict(Server.sv.edicts[0]);
        }
예제 #6
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);
        }
예제 #7
0
        // Host_Name_f
        static void Name_f()
        {
            if (Cmd.Argc == 1)
            {
                Con.Print("\"name\" is \"{0}\"\n", Client.Name);
                return;
            }

            string newName;

            if (Cmd.Argc == 2)
            {
                newName = Cmd.Argv(1);
            }
            else
            {
                newName = Cmd.Args;
            }

            if (newName.Length > 16)
            {
                newName = newName.Remove(15);
            }

            if (Cmd.Source == cmd_source_t.src_command)
            {
                if (Client.Name == newName)
                {
                    return;
                }

                Cvar.Set("_cl_name", newName);
                if (Client.Cls.state == ClientActivityState.Connected)
                {
                    Cmd.ForwardToServer();
                }

                return;
            }

            if (!String.IsNullOrEmpty(Host.HostClient.name) && Host.HostClient.name != "unconnected")
            {
                if (Host.HostClient.name != newName)
                {
                    Con.Print("{0} renamed to {1}\n", Host.HostClient.name, newName);
                }
            }

            Host.HostClient.name            = newName;
            Host.HostClient.edict.v.netname = Progs.NewString(newName);

            // send notification to all clients
            MessageWriter msg = Server.sv.reliable_datagram;

            msg.WriteByte(Protocol.svc_updatename);
            msg.WriteByte(Host.ClientNum);
            msg.WriteString(newName);
        }
예제 #8
0
        public static void Init(quakeparms_t parms)
        {
            _Params = parms;

            Cache.Init(1024 * 1024 * 16); // debug
            Cbuf.Init();
            Cmd.Init();
            View.Init();
            Chase.Init();
            InitVCR(parms);
            Common.Init(parms.basedir, parms.argv);
            InitLocal();
            Wad.LoadWadFile("gfx.wad");
            Key.Init();
            Con.Init();
            Menu.Init();
            Progs.Init();
            Mod.Init();
            Net.Init();
            Server.Init();

            //Con.Print("Exe: "__TIME__" "__DATE__"\n");
            //Con.Print("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0));

            Render.InitTextures();              // needed even for dedicated servers

            if (Client.Cls.state != ClientActivityState.Dedicated)
            {
                _BasePal = Common.LoadFile("gfx/palette.lmp");
                if (_BasePal == null)
                {
                    Sys.Error("Couldn't load gfx/palette.lmp");
                }

                _ColorMap = Common.LoadFile("gfx/colormap.lmp");
                if (_ColorMap == null)
                {
                    Sys.Error("Couldn't load gfx/colormap.lmp");
                }

                // on non win32, mouse comes before video for security reasons
                Input.Init();
                Vid.Init(_BasePal);
                Drawer.Init();
                Scr.Init();
                Render.Init();
                Sound.Init();
                CDAudio.Init();
                Sbar.Init();
                Client.Init();
            }

            Cbuf.InsertText("exec quake.rc\n");

            _IsInitialized = true;

            Con.DPrint("========Quake Initialized=========\n");
        }
예제 #9
0
        /// <summary>
        /// SV_DropClient
        /// Called when the player is getting totally kicked off the host
        /// if (crash = true), don't bother sending signofs
        /// </summary>
        public static void DropClient(bool crash)
        {
            client_t client = Host.HostClient;

            if (!crash)
            {
                // send any final messages (don't check for errors)
                if (Net.CanSendMessage(client.netconnection))
                {
                    MsgWriter msg = client.message;
                    msg.WriteByte(Protocol.svc_disconnect);
                    Net.SendMessage(client.netconnection, msg);
                }

                if (client.edict != null && client.spawned)
                {
                    // call the prog function for removing a client
                    // this will set the body to a dead frame, among other things
                    int saveSelf = Progs.GlobalStruct.self;
                    Progs.GlobalStruct.self = EdictToProg(client.edict);
                    Progs.Execute(Progs.GlobalStruct.ClientDisconnect);
                    Progs.GlobalStruct.self = saveSelf;
                }

                Con.DPrint("Client {0} removed\n", client.name);
            }

            // break the net connection
            Net.Close(client.netconnection);
            client.netconnection = null;

            // free the client (the body stays around)
            client.active    = false;
            client.name      = null;
            client.old_frags = -999999;
            Net.ActiveConnections--;

            // send notification to all clients
            for (int i = 0; i < Server.svs.maxclients; i++)
            {
                client_t cl = Server.svs.clients[i];
                if (!cl.active)
                {
                    continue;
                }

                cl.message.WriteByte(Protocol.svc_updatename);
                cl.message.WriteByte(Host.ClientNum);
                cl.message.WriteString("");
                cl.message.WriteByte(Protocol.svc_updatefrags);
                cl.message.WriteByte(Host.ClientNum);
                cl.message.WriteShort(0);
                cl.message.WriteByte(Protocol.svc_updatecolors);
                cl.message.WriteByte(Host.ClientNum);
                cl.message.WriteByte(0);
            }
        }
예제 #10
0
        /// <summary>
        /// SV_AddGravity
        /// </summary>
        static void AddGravity(edict_t ent)
        {
            float val = Progs.GetEdictFieldFloat(ent, "gravity");

            if (val == 0)
            {
                val = 1;
            }
            ent.v.velocity.z -= (float)(val * _Gravity.Value * Host.FrameTime);
        }
예제 #11
0
        /// <summary>
        /// SV_TouchLinks
        /// </summary>
        static void TouchLinks(edict_t ent, areanode_t node)
        {
            // touch linked edicts
            LinkList next;

            for (LinkList 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]);
            }
        }
예제 #12
0
        /// <summary>
        /// PF_errror
        /// This is a TERMINAL error, which will kill off the entire server.
        /// Dumps self.
        /// error(value)
        /// </summary>
        static void PF_error()
        {
            string s = PF_VarString(0);

            Con.Print("======SERVER ERROR in {0}:\n{1}\n",
                      Progs.GetString(Progs.xFunction.s_name), s);
            edict_t ed = Server.ProgToEdict(Progs.GlobalStruct.self);

            Progs.Print(ed);
            Host.Error("Program error");
        }
예제 #13
0
        /// <summary>
        /// ED_PrintEdict_f
        /// For debugging, prints a single edict
        /// </summary>
        static void PrintEdict_f()
        {
            int i = Common.atoi(Cmd.Argv(1));

            if (i >= Server.sv.num_edicts)
            {
                Con.Print("Bad edict number\n");
                return;
            }
            Progs.PrintNum(i);
        }
예제 #14
0
 static int SetTempString(string value)
 {
     if (_TempString == -1)
     {
         _TempString = Progs.NewString(value);
     }
     else
     {
         Progs.SetString(_TempString, value);
     }
     return(_TempString);
 }
예제 #15
0
        /// <summary>
        /// SV_CreateBaseline
        /// </summary>
        static void CreateBaseline()
        {
            for (int entnum = 0; entnum < sv.num_edicts; entnum++)
            {
                // get the current server version
                edict_t svent = EdictNum(entnum);
                if (svent.free)
                {
                    continue;
                }

                if (entnum > svs.maxclients && svent.v.modelindex == 0)
                {
                    continue;
                }

                //
                // create entity baseline
                //
                svent.baseline.origin = svent.v.origin;
                svent.baseline.angles = svent.v.angles;
                svent.baseline.frame  = (int)svent.v.frame;
                svent.baseline.skin   = (int)svent.v.skin;
                if (entnum > 0 && entnum <= svs.maxclients)
                {
                    svent.baseline.colormap   = entnum;
                    svent.baseline.modelindex = ModelIndex("progs/player.mdl");
                }
                else
                {
                    svent.baseline.colormap   = 0;
                    svent.baseline.modelindex = ModelIndex(Progs.GetString(svent.v.model));
                }

                //
                // add to the message
                //
                sv.signon.WriteByte(Protocol.svc_spawnbaseline);
                sv.signon.WriteShort(entnum);

                sv.signon.WriteByte(svent.baseline.modelindex);
                sv.signon.WriteByte(svent.baseline.frame);
                sv.signon.WriteByte(svent.baseline.colormap);
                sv.signon.WriteByte(svent.baseline.skin);

                sv.signon.WriteCoord(svent.baseline.origin.x);
                sv.signon.WriteAngle(svent.baseline.angles.x);
                sv.signon.WriteCoord(svent.baseline.origin.y);
                sv.signon.WriteAngle(svent.baseline.angles.y);
                sv.signon.WriteCoord(svent.baseline.origin.z);
                sv.signon.WriteAngle(svent.baseline.angles.z);
            }
        }
예제 #16
0
 private static edict_t FindViewthing()
 {
     for (int i = 0; i < Server.sv.num_edicts; i++)
     {
         edict_t e = Server.EdictNum(i);
         if (Progs.GetString(e.v.classname) == "viewthing")
         {
             return(e);
         }
     }
     Con.Print("No viewthing on map\n");
     return(null);
 }
예제 #17
0
        /*
         * ==============
         * PF_setspawnparms
         * ==============
         */
        static void PF_setspawnparms()
        {
            edict_t ent = GetEdict(OFS.OFS_PARM0);
            int     i   = Server.NumForEdict(ent);

            if (i < 1 || i > Server.svs.maxclients)
            {
                Progs.RunError("Entity is not a client");
            }

            // copy spawn parms out of the client_t
            client_t client = Server.svs.clients[i - 1];

            Progs.GlobalStruct.SetParams(client.spawn_parms);
        }
예제 #18
0
        //============================================================================


        /// <summary>
        /// PF_stuffcmd
        /// Sends text over to the client's execution buffer
        /// stuffcmd (clientent, value)
        /// </summary>
        static void PF_stuffcmd()
        {
            int entnum = Server.NumForEdict(GetEdict(OFS.OFS_PARM0));

            if (entnum < 1 || entnum > Server.svs.maxclients)
            {
                Progs.RunError("Parm 0 not a client");
            }
            string str = GetString(OFS.OFS_PARM1);

            client_t old = Host.HostClient;

            Host.HostClient = Server.svs.clients[entnum - 1];
            Host.ClientCommands("{0}", str);
            Host.HostClient = old;
        }
예제 #19
0
        /// <summary>
        /// SV_SaveSpawnparms
        /// Grabs the current state of each client for saving across the
        /// transition to another level
        /// </summary>
        public static void SaveSpawnparms()
        {
            Server.svs.serverflags = (int)Progs.GlobalStruct.serverflags;

            for (int i = 0; i < svs.maxclients; i++)
            {
                Host.HostClient = Server.svs.clients[i];
                if (!Host.HostClient.active)
                {
                    continue;
                }

                // call the progs to get default spawn parms for the new client
                Progs.GlobalStruct.self = EdictToProg(Host.HostClient.edict);
                Progs.Execute(Progs.GlobalStruct.SetChangeParms);
                AssignGlobalSpawnparams(Host.HostClient);
            }
        }
예제 #20
0
        /// <summary>
        /// Host_Kill_f
        /// </summary>
        private static void Kill_f()
        {
            if (Cmd.Source == cmd_source_t.src_command)
            {
                Cmd.ForwardToServer();
                return;
            }

            if (Server.Player.v.health <= 0)
            {
                Server.ClientPrint("Can't suicide -- allready dead!\n");
                return;
            }

            Progs.GlobalStruct.time = (float)Server.sv.time;
            Progs.GlobalStruct.self = Server.EdictToProg(Server.Player);
            Progs.Execute(Progs.GlobalStruct.ClientKill);
        }
예제 #21
0
        static void PF_makestatic()
        {
            edict_t       ent = GetEdict(OFS.OFS_PARM0);
            MessageWriter 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);
        }
예제 #22
0
        /// <summary>
        /// SV_CheckVelocity
        /// </summary>
        static void CheckVelocity(edict_t ent)
        {
            //
            // bound velocity
            //
            if (Mathlib.CheckNaN(ref ent.v.velocity, 0))
            {
                Con.Print("Got a NaN velocity on {0}\n", Progs.GetString(ent.v.classname));
            }

            if (Mathlib.CheckNaN(ref ent.v.origin, 0))
            {
                Con.Print("Got a NaN origin on {0}\n", Progs.GetString(ent.v.classname));
            }

            Vector3 max = Vector3.One * _MaxVelocity.Value;
            Vector3 min = -Vector3.One * _MaxVelocity.Value;

            Mathlib.Clamp(ref ent.v.velocity, ref min, ref max, out ent.v.velocity);
        }
예제 #23
0
        /// <summary>
        /// SV_ConnectClient
        /// Initializes a client_t for a new net connection.  This will only be called
        /// once for a player each game, not once for each level change.
        /// </summary>
        static void ConnectClient(int clientnum)
        {
            client_t client = svs.clients[clientnum];

            Con.DPrint("Client {0} connected\n", client.netconnection.address);

            int     edictnum = clientnum + 1;
            edict_t ent      = EdictNum(edictnum);

            // set up the client_t
            qsocket_t netconnection = client.netconnection;

            float[] spawn_parms = new float[NUM_SPAWN_PARMS];
            if (sv.loadgame)
            {
                Array.Copy(client.spawn_parms, spawn_parms, spawn_parms.Length);
            }

            client.Clear();
            client.netconnection         = netconnection;
            client.name                  = "unconnected";
            client.active                = true;
            client.spawned               = false;
            client.edict                 = ent;
            client.message.AllowOverflow = true; // we can catch it
            client.privileged            = false;

            if (sv.loadgame)
            {
                Array.Copy(spawn_parms, client.spawn_parms, spawn_parms.Length);
            }
            else
            {
                // call the progs to get default spawn parms for the new client
                Progs.Execute(Progs.GlobalStruct.SetNewParms);

                AssignGlobalSpawnparams(client);
            }

            SendServerInfo(client);
        }
예제 #24
0
        /*
         * =================
         * PF_setmodel
         *
         * setmodel(entity, model)
         * =================
         */
        static void PF_setmodel()
        {
            edict_t e     = GetEdict(OFS.OFS_PARM0);
            int     m_idx = GetInt(OFS.OFS_PARM1);
            string  m     = Progs.GetString(m_idx);

            // check to see if model was properly precached
            for (int i = 0; i < Server.sv.model_precache.Length; i++)
            {
                string check = Server.sv.model_precache[i];

                if (check == null)
                {
                    break;
                }

                if (check == m)
                {
                    e.v.model      = m_idx; // m - pr_strings;
                    e.v.modelindex = i;

                    Model mod = Server.sv.models[(int)e.v.modelindex];

                    if (mod != null)
                    {
                        SetMinMaxSize(e, ref mod.mins, ref mod.maxs, true);
                    }
                    else
                    {
                        SetMinMaxSize(e, ref Common.ZeroVector, ref Common.ZeroVector, true);
                    }

                    return;
                }
            }

            Progs.RunError("no precache: {0}\n", m);
        }
예제 #25
0
        /// <summary>
        /// SV_Impact
        /// Two entities have touched, so run their touch functions
        /// </summary>
        static void Impact(edict_t e1, edict_t e2)
        {
            int old_self  = Progs.GlobalStruct.self;
            int old_other = Progs.GlobalStruct.other;

            Progs.GlobalStruct.time = (float)sv.time;
            if (e1.v.touch != 0 && e1.v.solid != Solids.SOLID_NOT)
            {
                Progs.GlobalStruct.self  = EdictToProg(e1);
                Progs.GlobalStruct.other = EdictToProg(e2);
                Progs.Execute(e1.v.touch);
            }

            if (e2.v.touch != 0 && e2.v.solid != Solids.SOLID_NOT)
            {
                Progs.GlobalStruct.self  = EdictToProg(e2);
                Progs.GlobalStruct.other = EdictToProg(e1);
                Progs.Execute(e2.v.touch);
            }

            Progs.GlobalStruct.self  = old_self;
            Progs.GlobalStruct.other = old_other;
        }
예제 #26
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;
                }
            }
        }
예제 #27
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);
        }
예제 #28
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;
        }
예제 #29
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;
                }
            }
        }
예제 #30
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;
                    }
                }
            }
        }