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"); }
/// <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); } }
static void CheckEmptyString(string s) { if (s == null || s.Length == 0 || s[0] <= ' ') { Progs.RunError("Bad string"); } }
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"); }
/// <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]); }
/// <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); }
// 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); }
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"); }
/// <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); } }
/// <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); }
/// <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]); } }
/// <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"); }
/// <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); }
static int SetTempString(string value) { if (_TempString == -1) { _TempString = Progs.NewString(value); } else { Progs.SetString(_TempString, value); } return(_TempString); }
/// <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); } }
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); }
/* * ============== * 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); }
//============================================================================ /// <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; }
/// <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); } }
/// <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); }
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); }
/// <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); }
/// <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); }
/* * ================= * 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); }
/// <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; }
/// <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; } } }
/// <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); }
/// <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; }
/// <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; } } }
/// <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; } } } }