/// <summary> /// SV_CloseEnough /// </summary> private Boolean CloseEnough(MemoryEdict ent, MemoryEdict goal, Single dist) { if (goal.v.absmin.x > ent.v.absmax.x + dist) { return(false); } if (goal.v.absmin.y > ent.v.absmax.y + dist) { return(false); } if (goal.v.absmin.z > ent.v.absmax.z + dist) { return(false); } if (goal.v.absmax.x < ent.v.absmin.x - dist) { return(false); } if (goal.v.absmax.y < ent.v.absmin.y - dist) { return(false); } if (goal.v.absmax.z < ent.v.absmin.z - dist) { return(false); } return(true); }
/// <summary> /// SV_StepDirection /// Turns to the movement direction, and walks the current distance if facing it. /// </summary> private bool StepDirection(MemoryEdict ent, float yaw, float dist) { ent.v.ideal_yaw = yaw; this.Host.ProgramsBuiltIn.PF_changeyaw(); yaw = ( float )(yaw * Math.PI * 2.0 / 360); Vector3 move; move.X = ( float )Math.Cos(yaw) * dist; move.Y = ( float )Math.Sin(yaw) * dist; move.Z = 0; var oldorigin = ent.v.origin; if (this.MoveStep(ent, ref move, false)) { var delta = ent.v.angles.Y - ent.v.ideal_yaw; if (delta > 45 && delta < 315) { // not turned far enough, so don't take the step ent.v.origin = oldorigin; } this.LinkEdict(ent, true); return(true); } this.LinkEdict(ent, true); return(false); }
/// <summary> /// SV_StepDirection /// Turns to the movement direction, and walks the current distance if facing it. /// </summary> private Boolean StepDirection(MemoryEdict ent, Single yaw, Single dist) { ent.v.ideal_yaw = yaw; Host.ProgramsBuiltIn.PF_changeyaw(); yaw = ( Single )(yaw * Math.PI * 2.0 / 360); Vector3f move; move.x = ( Single )Math.Cos(yaw) * dist; move.y = ( Single )Math.Sin(yaw) * dist; move.z = 0; var oldorigin = ent.v.origin; if (MoveStep(ent, ref move, false)) { var delta = ent.v.angles.y - ent.v.ideal_yaw; if (delta > 45 && delta < 315) { // not turned far enough, so don't take the step ent.v.origin = oldorigin; } LinkEdict(ent, true); return(true); } LinkEdict(ent, true); return(false); }
/// <summary> /// SV_Physics_Pusher /// </summary> private void Physics_Pusher( MemoryEdict ent ) { var oldltime = ent.v.ltime; var thinktime = ent.v.nextthink; Single movetime; if ( thinktime < ent.v.ltime + Host.FrameTime ) { movetime = thinktime - ent.v.ltime; if ( movetime < 0 ) movetime = 0; } else movetime = ( Single ) 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; Host.Programs.GlobalStruct.time = ( Single ) sv.time; Host.Programs.GlobalStruct.self = EdictToProg( ent ); Host.Programs.GlobalStruct.other = EdictToProg( sv.edicts[0] ); Host.Programs.Execute( ent.v.think ); if ( ent.free ) return; } }
private void WriteClientPunches(MemoryEdict ent, MessageWriter msg, int bits) { if ((bits & ProtocolDef.SU_PUNCH1) != 0) { msg.WriteChar(( int )ent.v.punchangle.X); } if ((bits & ProtocolDef.SU_VELOCITY1) != 0) { msg.WriteChar(( int )(ent.v.velocity.X / 16)); } if ((bits & ProtocolDef.SU_PUNCH2) != 0) { msg.WriteChar(( int )ent.v.punchangle.Y); } if ((bits & ProtocolDef.SU_VELOCITY2) != 0) { msg.WriteChar(( int )(ent.v.velocity.Y / 16)); } if ((bits & ProtocolDef.SU_PUNCH3) != 0) { msg.WriteChar(( int )ent.v.punchangle.Z); } if ((bits & ProtocolDef.SU_VELOCITY3) != 0) { msg.WriteChar(( int )(ent.v.velocity.Z / 16)); } }
/// <summary> /// SV_CheckWaterTransition /// </summary> private void CheckWaterTransition(MemoryEdict ent) { var org = Utilities.ToVector(ref ent.v.origin); var cont = PointContents(ref org); if (ent.v.watertype == 0) { // just spawned here ent.v.watertype = cont; ent.v.waterlevel = 1; return; } if (cont <= ( Int32 )Q1Contents.Water) { if (ent.v.watertype == ( Int32 )Q1Contents.Empty) { // just crossed into water StartSound(ent, 0, "misc/h2ohit1.wav", 255, 1); } ent.v.watertype = cont; ent.v.waterlevel = 1; } else { if (ent.v.watertype != ( Int32 )Q1Contents.Empty) { // just crossed into water StartSound(ent, 0, "misc/h2ohit1.wav", 255, 1); } ent.v.watertype = ( Int32 )Q1Contents.Empty; ent.v.waterlevel = cont; } }
/// <summary> /// SV_Physics_Step /// </summary> private void Physics_Step(MemoryEdict ent) { Boolean hitsound; // freefall if not onground if ((( Int32 )ent.v.flags & (EdictFlags.FL_ONGROUND | EdictFlags.FL_FLY | EdictFlags.FL_SWIM)) == 0) { if (ent.v.velocity.z < Host.Cvars.Gravity.Get <Single>() * -0.1) { hitsound = true; } else { hitsound = false; } AddGravity(ent); CheckVelocity(ent); FlyMove(ent, ( Single )Host.FrameTime, null); LinkEdict(ent, true); if ((( Int32 )ent.v.flags & EdictFlags.FL_ONGROUND) != 0) // just hit ground { if (hitsound) { StartSound(ent, 0, "demon/dland2.wav", 255, 1); } } } // regular thinking RunThink(ent); CheckWaterTransition(ent); }
/// <summary> /// SV_WriteClientdataToMessage /// </summary> public void WriteClientDataToMessage(MemoryEdict ent, MessageWriter msg) { // // send a damage message // this.WriteClientDamageMessage(ent, msg); // // send the current viewpos offset from the view entity // this.SetIdealPitch(); // how much to look up / down ideally // a fixangle might get lost in a dropped packet. Oh well. this.WriteClientFixAngle(ent, msg); var bits = this.GenerateClientBits(ent, out var items); // send the data this.WriteClientHeader(msg, bits); this.WriteClientView(ent, msg, bits); this.WriteClientPunches(ent, msg, bits); // always sent this.WriteClientItems(ent, msg, items, bits); this.WriteClientHealth(ent, msg); this.WriteClientAmmo(ent, msg); this.WriteClientWeapons(ent, msg); }
/// <summary> /// PushEntity /// Does not change the entities velocity at all /// </summary> private Trace_t PushEntity(MemoryEdict ent, ref Vector3f push) { Vector3f end; MathLib.VectorAdd(ref ent.v.origin, ref push, out end); Trace_t trace; if (ent.v.movetype == Movetypes.MOVETYPE_FLYMISSILE) { trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref end, MOVE_MISSILE, ent); } else if (ent.v.solid == Solids.SOLID_TRIGGER || ent.v.solid == Solids.SOLID_NOT) { // only clip against bmodels trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref end, MOVE_NOMONSTERS, ent); } else { trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref end, MOVE_NORMAL, ent); } MathLib.Copy(ref trace.endpos, out ent.v.origin); LinkEdict(ent, true); if (trace.ent != null) { Impact(ent, trace.ent); } return(trace); }
/// <summary> /// SV_Physics_Step /// </summary> private void Physics_Step(MemoryEdict ent) { bool hitsound; // freefall if not onground if ((( int )ent.v.flags & (EdictFlags.FL_ONGROUND | EdictFlags.FL_FLY | EdictFlags.FL_SWIM)) == 0) { if (ent.v.velocity.Z < this.Host.Cvars.Gravity.Get <float>() * -0.1) { hitsound = true; } else { hitsound = false; } this.AddGravity(ent); this.CheckVelocity(ent); this.FlyMove(ent, ( float )this.Host.FrameTime, null); this.LinkEdict(ent, true); if ((( int )ent.v.flags & EdictFlags.FL_ONGROUND) != 0) // just hit ground { if (hitsound) { this.StartSound(ent, 0, "demon/dland2.wav", 255, 1); } } } // regular thinking this.RunThink(ent); this.CheckWaterTransition(ent); }
private Boolean TryRandomChaseDir(Single turnaround, MemoryEdict actor, Single dist) { if ((MathLib.Random() & 1) != 0) //randomly determine direction of search { for (var tdir = 0; tdir <= 315; tdir += 45) { if (tdir != turnaround && StepDirection(actor, tdir, dist)) { return(false); } } } else { for (var tdir = 315; tdir >= 0; tdir -= 45) { if (tdir != turnaround && StepDirection(actor, tdir, dist)) { return(false); } } } if (turnaround != DI_NODIR && StepDirection(actor, turnaround, dist)) { return(false); } return(true); }
/// <summary> /// SV_CheckStuck /// This is a big hack to try and fix the rare case of getting stuck in the world /// clipping hull. /// </summary> private void CheckStuck( MemoryEdict ent ) { if ( TestEntityPosition( ent ) == null ) { ent.v.oldorigin = ent.v.origin; return; } var org = ent.v.origin; ent.v.origin = ent.v.oldorigin; if ( TestEntityPosition( ent ) == null ) { Host.Console.DPrint( "Unstuck.\n" ); LinkEdict( ent, true ); return; } for ( var z = 0; z < 18; z++ ) for ( var i = -1; i <= 1; i++ ) for ( var j = -1; j <= 1; j++ ) { ent.v.origin.x = org.x + i; ent.v.origin.y = org.y + j; ent.v.origin.z = org.z + z; if ( TestEntityPosition( ent ) == null ) { Host.Console.DPrint( "Unstuck.\n" ); LinkEdict( ent, true ); return; } } ent.v.origin = org; Host.Console.DPrint( "player is stuck.\n" ); }
/// <summary> /// SV_RunClients /// </summary> public void RunClients() { for (var i = 0; i < this.svs.maxclients; i++) { this.Host.HostClient = this.svs.clients[i]; if (!this.Host.HostClient.active) { continue; } this._Player = this.Host.HostClient.edict; if (!this.ReadClientMessage()) { this.DropClient(false); // client misbehaved... continue; } if (!this.Host.HostClient.spawned) { // clear client movement until a new packet is received this.Host.HostClient.cmd.Clear(); continue; } // always pause in single player if in console or menus if (!this.sv.paused && (this.svs.maxclients > 1 || this.Host.Keyboard.Destination == KeyDestination.key_game)) { this.ClientThink(); } } }
/// <summary> /// SV_ClipMoveToEntity /// Handles selection or creation of a clipping hull, and offseting (and /// eventually rotation) of the end points /// </summary> private Trace_t ClipMoveToEntity(MemoryEdict ent, ref Vector3 start, ref Vector3 mins, ref Vector3 maxs, ref Vector3 end) { var trace = new Trace_t(); // fill in a default trace trace.fraction = 1; trace.allsolid = true; trace.endpos = end; // get the clipping hull Vector3 offset; var hull = HullForEntity(ent, ref mins, ref maxs, out offset); var start_l = start - offset; var end_l = end - offset; // trace a line through the apropriate clipping hull RecursiveHullCheck(hull, hull.firstclipnode, 0, 1, ref start_l, ref end_l, trace); // fix trace up by the offset if (trace.fraction != 1) { trace.endpos += offset; } // did we clip the move? if (trace.fraction < 1 || trace.startsolid) { trace.ent = ent; } return(trace); }
/// <summary> /// SV_AddGravity /// </summary> private void AddGravity( MemoryEdict ent ) { var val = Host.Programs.GetEdictFieldFloat( ent, "gravity" ); if ( val == 0 ) val = 1; ent.v.velocity.z -= ( Single ) ( val * Host.Cvars.Gravity.Get<Single>() * Host.FrameTime ); }
private void WriteClientPunches(MemoryEdict ent, MessageWriter msg, Int32 bits) { if ((bits & ProtocolDef.SU_PUNCH1) != 0) { msg.WriteChar(( Int32 )ent.v.punchangle.x); } if ((bits & ProtocolDef.SU_VELOCITY1) != 0) { msg.WriteChar(( Int32 )(ent.v.velocity.x / 16)); } if ((bits & ProtocolDef.SU_PUNCH2) != 0) { msg.WriteChar(( Int32 )ent.v.punchangle.y); } if ((bits & ProtocolDef.SU_VELOCITY2) != 0) { msg.WriteChar(( Int32 )(ent.v.velocity.y / 16)); } if ((bits & ProtocolDef.SU_PUNCH3) != 0) { msg.WriteChar(( Int32 )ent.v.punchangle.z); } if ((bits & ProtocolDef.SU_VELOCITY3) != 0) { msg.WriteChar(( Int32 )(ent.v.velocity.z / 16)); } }
/// <summary> /// SV_CheckWater /// </summary> private bool CheckWater(MemoryEdict ent) { Vector3 point; point.X = ent.v.origin.X; point.Y = ent.v.origin.Y; point.Z = ent.v.origin.Z + ent.v.mins.Z + 1; ent.v.waterlevel = 0; ent.v.watertype = ( int )Q1Contents.Empty; var cont = this.PointContents(ref point); if (cont <= ( int )Q1Contents.Water) { ent.v.watertype = cont; ent.v.waterlevel = 1; point.Z = ent.v.origin.Z + (ent.v.mins.Z + ent.v.maxs.Z) * 0.5f; cont = this.PointContents(ref point); if (cont <= ( int )Q1Contents.Water) { ent.v.waterlevel = 2; point.Z = ent.v.origin.Z + ent.v.view_ofs.Z; cont = this.PointContents(ref point); if (cont <= ( int )Q1Contents.Water) { ent.v.waterlevel = 3; } } } return(ent.v.waterlevel > 1); }
/// <summary> /// SV_CheckWater /// </summary> private Boolean CheckWater(MemoryEdict ent) { Vector3 point; point.X = ent.v.origin.x; point.Y = ent.v.origin.y; point.Z = ent.v.origin.z + ent.v.mins.z + 1; ent.v.waterlevel = 0; ent.v.watertype = ( Int32 )Q1Contents.Empty; var cont = PointContents(ref point); if (cont <= ( Int32 )Q1Contents.Water) { ent.v.watertype = cont; ent.v.waterlevel = 1; point.Z = ent.v.origin.z + (ent.v.mins.z + ent.v.maxs.z) * 0.5f; cont = PointContents(ref point); if (cont <= ( Int32 )Q1Contents.Water) { ent.v.waterlevel = 2; point.Z = ent.v.origin.z + ent.v.view_ofs.z; cont = PointContents(ref point); if (cont <= ( Int32 )Q1Contents.Water) { ent.v.waterlevel = 3; } } } return(ent.v.waterlevel > 1); }
/// <summary> /// SV_CloseEnough /// </summary> private bool CloseEnough(MemoryEdict ent, MemoryEdict goal, float dist) { if (goal.v.absmin.X > ent.v.absmax.X + dist) { return(false); } if (goal.v.absmin.Y > ent.v.absmax.Y + dist) { return(false); } if (goal.v.absmin.Z > ent.v.absmax.Z + dist) { return(false); } if (goal.v.absmax.X < ent.v.absmin.X - dist) { return(false); } if (goal.v.absmax.Y < ent.v.absmin.Y - dist) { return(false); } if (goal.v.absmax.Z < ent.v.absmin.Z - dist) { return(false); } return(true); }
private void WriteClientAmmo(MemoryEdict ent, MessageWriter msg) { 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); }
/// <summary> /// SV_UnlinkEdict /// call before removing an entity, and before trying to move one, /// so it doesn't clip against itself /// flags ent->v.modified /// </summary> public void UnlinkEdict(MemoryEdict ent) { if (ent.area.Prev == null) { return; // not linked in anywhere } ent.area.Remove(); //RemoveLink(&ent->area); //ent->area.prev = ent->area.next = NULL; }
/// <summary> /// SV_AddGravity /// </summary> private void AddGravity(MemoryEdict ent) { var val = this.Host.Programs.GetEdictFieldFloat(ent, "gravity"); if (val == 0) { val = 1; } ent.v.velocity.Z -= ( float )(val * this.Host.Cvars.Gravity.Get <float>() * this.Host.FrameTime); }
/// <summary> /// SV_Physics_Noclip /// A moving object that doesn't obey physics /// </summary> private void Physics_Noclip( MemoryEdict ent ) { // regular thinking if ( !RunThink( ent ) ) return; MathLib.VectorMA( ref ent.v.angles, ( Single ) Host.FrameTime, ref ent.v.avelocity, out ent.v.angles ); MathLib.VectorMA( ref ent.v.origin, ( Single ) Host.FrameTime, ref ent.v.velocity, out ent.v.origin ); LinkEdict( ent, false ); }
/// <summary> /// NUM_FOR_EDICT /// </summary> public int NumForEdict(MemoryEdict e) { var i = Array.IndexOf(this.sv.edicts, e); // todo: optimize this if (i < 0) { Utilities.Error("NUM_FOR_EDICT: bad pointer"); } return(i); }
public MemoryEdict ent; // entity the surface is on public void CopyFrom(Trace_t src) { allsolid = src.allsolid; startsolid = src.startsolid; inopen = src.inopen; inwater = src.inwater; fraction = src.fraction; endpos = src.endpos; plane = src.plane; ent = src.ent; }
public MemoryEdict ent; // entity the surface is on public void CopyFrom(Trace_t src) { this.allsolid = src.allsolid; this.startsolid = src.startsolid; this.inopen = src.inopen; this.inwater = src.inwater; this.fraction = src.fraction; this.endpos = src.endpos; this.plane = src.plane; this.ent = src.ent; }
public Single GetEdictFieldFloat(MemoryEdict ed, String field, Single defValue = 0) { var def = CachedSearch(ed, field); if (def == null) { return(defValue); } return(ed.GetFloat(def.ofs)); }
public Boolean SetEdictFieldFloat(MemoryEdict ed, String field, Single value) { var def = CachedSearch(ed, field); if (def != null) { ed.SetFloat(def.ofs, value); return(true); } return(false); }
private void WriteClientFixAngle(MemoryEdict ent, MessageWriter msg) { if (ent.v.fixangle != 0) { msg.WriteByte(ProtocolDef.svc_setangle); msg.WriteAngle(ent.v.angles.X); msg.WriteAngle(ent.v.angles.Y); msg.WriteAngle(ent.v.angles.Z); ent.v.fixangle = 0; } }
/// <summary> /// SV_TestEntityPosition /// This could be a lot more efficient... /// </summary> private MemoryEdict TestEntityPosition(MemoryEdict ent) { var trace = Move(ref ent.v.origin, ref ent.v.mins, ref ent.v.maxs, ref ent.v.origin, 0, ent); if (trace.startsolid) { return(sv.edicts[0]); } return(null); }