/// <summary> /// SV_AirAccelerate /// </summary> static void AirAccelerate(Vector3 wishveloc) { float wishspd = Mathlib.Normalize(ref wishveloc); if (wishspd > 30) { wishspd = 30; } float currentspeed = Vector3.Dot(Common.ToVector(ref _Player.v.velocity), wishveloc); float addspeed = wishspd - currentspeed; if (addspeed <= 0) { return; } float accelspeed = (float)(_Accelerate.Value * _WishSpeed * Host.FrameTime); if (accelspeed > addspeed) { accelspeed = addspeed; } wishveloc *= accelspeed; _Player.v.velocity.x += wishveloc.X; _Player.v.velocity.y += wishveloc.Y; _Player.v.velocity.z += wishveloc.Z; }
/// <summary> /// SV_HullPointContents /// </summary> static int HullPointContents(hull_t hull, int num, ref Vector3 p) { while (num >= 0) { if (num < hull.firstclipnode || num > hull.lastclipnode) { Sys.Error("SV_HullPointContents: bad node number"); } short[] node_children = hull.clipnodes[num].children; mplane_t plane = hull.planes[hull.clipnodes[num].planenum]; float d; if (plane.type < 3) { d = Mathlib.Comp(ref p, plane.type) - plane.dist; } else { d = Vector3.Dot(plane.normal, p) - plane.dist; } if (d < 0) { num = node_children[1]; } else { num = node_children[0]; } } return(num); }
// Chase_Update public static void Update() { // if can't see player, reset Vector3 forward, up, right; Mathlib.AngleVectors(ref Client.cl.viewangles, out forward, out right, out up); // calc exact destination _Dest = Render.RefDef.vieworg - forward * _Back.Value - right * _Right.Value; _Dest.Z = Render.RefDef.vieworg.Z + _Up.Value; // find the spot the player is looking at Vector3 dest = Render.RefDef.vieworg + forward * 4096; Vector3 stop; TraceLine(ref Render.RefDef.vieworg, ref dest, out stop); // calculate pitch to look at the same spot from camera stop -= Render.RefDef.vieworg; float dist; Vector3.Dot(ref stop, ref forward, out dist); if (dist < 1) { dist = 1; } Render.RefDef.viewangles.X = (float)(-Math.Atan(stop.Z / dist) / Math.PI * 180.0); //r_refdef.viewangles[PITCH] = -atan(stop[2] / dist) / M_PI * 180; // move towards destination Render.RefDef.vieworg = _Dest; //VectorCopy(chase_dest, r_refdef.vieworg); }
/// <summary> /// SV_ReadClientMove /// </summary> static void ReadClientMove(ref usercmd_t move) { client_t client = Host.HostClient; // read ping time client.ping_times[client.num_pings % NUM_PING_TIMES] = (float)(sv.time - Net.Reader.ReadFloat()); client.num_pings++; // read current angles Vector3 angles = Net.Reader.ReadAngles(); Mathlib.Copy(ref angles, out client.edict.v.v_angle); // read movement move.forwardmove = Net.Reader.ReadShort(); move.sidemove = Net.Reader.ReadShort(); move.upmove = Net.Reader.ReadShort(); // read buttons int bits = Net.Reader.ReadByte(); client.edict.v.button0 = bits & 1; client.edict.v.button2 = (bits & 2) >> 1; int i = Net.Reader.ReadByte(); if (i != 0) { client.edict.v.impulse = i; } }
static void Test5_f() { Entity p = Client.ViewEntity; if (p == null) { return; } OpenTK.Vector3 org = p.origin; for (int i = 0; i < Server.sv.edicts.Length; i++) { edict_t ed = Server.sv.edicts[i]; if (ed.free) { continue; } OpenTK.Vector3 vmin, vmax; Mathlib.Copy(ref ed.v.absmax, out vmax); Mathlib.Copy(ref ed.v.absmin, out vmin); if (org.X >= vmin.X && org.Y >= vmin.Y && org.Z >= vmin.Z && org.X <= vmax.X && org.Y <= vmax.Y && org.Z <= vmax.Z) { Con.Print("{0}\n", i); } } }
/// <summary> /// R_TeleportSplash /// </summary> public static void TeleportSplash(ref Vector3 org) { for (int i = -16; i < 16; i += 4) { for (int j = -16; j < 16; j += 4) { for (int k = -24; k < 32; k += 4) { particle_t p = AllocParticle(); if (p == null) { return; } p.die = (float)(Client.cl.time + 0.2 + (Sys.Random() & 7) * 0.02); p.color = 7 + (Sys.Random() & 7); p.type = ptype_t.pt_slowgrav; Vector3 dir = new Vector3(j * 8, i * 8, k * 8); p.org = org + new Vector3(i + (Sys.Random() & 3), j + (Sys.Random() & 3), k + (Sys.Random() & 3)); Mathlib.Normalize(ref dir); float vel = 50 + (Sys.Random() & 63); p.vel = dir * vel; } } } }
/// <summary> /// R_LavaSplash /// </summary> public static void LavaSplash(ref Vector3 org) { Vector3 dir; for (int i = -16; i < 16; i++) { for (int j = -16; j < 16; j++) { for (int k = 0; k < 1; k++) { particle_t p = AllocParticle(); if (p == null) { return; } p.die = (float)(Client.cl.time + 2 + (Sys.Random() & 31) * 0.02); p.color = 224 + (Sys.Random() & 7); p.type = ptype_t.pt_slowgrav; dir.X = j * 8 + (Sys.Random() & 7); dir.Y = i * 8 + (Sys.Random() & 7); dir.Z = 256; p.org = org + dir; p.org.Z += Sys.Random() & 63; Mathlib.Normalize(ref dir); float vel = 50 + (Sys.Random() & 63); p.vel = dir * vel; } } } }
/* * ================= * PF_traceline * * Used for use tracing and shot targeting * Traces are blocked by bbox and exact bsp entityes, and also slide box entities * if the tryents flag is set. * * traceline (vector1, vector2, tryents) * ================= */ static unsafe void PF_traceline() { float * v1 = GetVector(OFS.OFS_PARM0); float * v2 = GetVector(OFS.OFS_PARM1); int nomonsters = (int)GetFloat(OFS.OFS_PARM2); edict_t ent = GetEdict(OFS.OFS_PARM3); Vector3 vec1, vec2; Copy(v1, out vec1); Copy(v2, out vec2); trace_t trace = Server.Move(ref vec1, ref Common.ZeroVector, ref Common.ZeroVector, ref vec2, nomonsters, ent); Progs.GlobalStruct.trace_allsolid = trace.allsolid ? 1 : 0; Progs.GlobalStruct.trace_startsolid = trace.startsolid ? 1 : 0; Progs.GlobalStruct.trace_fraction = trace.fraction; Progs.GlobalStruct.trace_inwater = trace.inwater ? 1 : 0; Progs.GlobalStruct.trace_inopen = trace.inopen ? 1 : 0; Mathlib.Copy(ref trace.endpos, out Progs.GlobalStruct.trace_endpos); Mathlib.Copy(ref trace.plane.normal, out Progs.GlobalStruct.trace_plane_normal); Progs.GlobalStruct.trace_plane_dist = trace.plane.dist; if (trace.ent != null) { Progs.GlobalStruct.trace_ent = Server.EdictToProg(trace.ent); } else { Progs.GlobalStruct.trace_ent = Server.EdictToProg(Server.sv.edicts[0]); } }
/// <summary> /// PushEntity /// Does not change the entities velocity at all /// </summary> private static trace_t PushEntity(edict_t ent, ref v3f push) { v3f 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); }
/* * =============== * PF_droptofloor * * void() droptofloor * =============== */ static void PF_droptofloor() { edict_t ent = Server.ProgToEdict(Progs.GlobalStruct.self); Vector3 org, mins, maxs; Mathlib.Copy(ref ent.v.origin, out org); Mathlib.Copy(ref ent.v.mins, out mins); Mathlib.Copy(ref ent.v.maxs, out maxs); Vector3 end = org; end.Z -= 256; trace_t trace = Server.Move(ref org, ref mins, ref maxs, ref end, 0, ent); if (trace.fraction == 1 || trace.allsolid) { ReturnFloat(0); } else { Mathlib.Copy(ref trace.endpos, out ent.v.origin); Server.LinkEdict(ent, false); ent.v.flags = (int)ent.v.flags | EdictFlags.FL_ONGROUND; ent.v.groundentity = Server.EdictToProg(trace.ent); ReturnFloat(1); } }
// angledelta() static float AngleDelta(float a) { a = Mathlib.AngleMod(a); if (a > 180) { a -= 360; } return(a); }
/* * ================= * PF_normalize * * vector normalize(vector) * ================= */ static unsafe void PF_normalize() { float * value1 = GetVector(OFS.OFS_PARM0); Vector3 tmp; Copy(value1, out tmp); Mathlib.Normalize(ref tmp); ReturnVector(ref tmp); }
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)); }
/* * ============== * PF_makevectors * * Writes new values for v_forward, v_up, and v_right based on angles * makevectors(vector) * ============== */ static unsafe void PF_makevectors() { float * av = GetVector(OFS.OFS_PARM0); Vector3 a = new Vector3(av[0], av[1], av[2]); Vector3 fw, right, up; Mathlib.AngleVectors(ref a, out fw, out right, out up); Mathlib.Copy(ref fw, out Progs.GlobalStruct.v_forward); Mathlib.Copy(ref right, out Progs.GlobalStruct.v_right); Mathlib.Copy(ref up, out Progs.GlobalStruct.v_up); }
/// <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]); } }
// CL_AdjustAngles // // Moves the local angle positions static void AdjustAngles() { float speed = (float)Host.FrameTime; if (ClientInput.SpeedBtn.IsDown) { speed *= _AngleSpeedKey.Value; } if (!ClientInput.StrafeBtn.IsDown) { Cl.viewangles.Y -= speed * _YawSpeed.Value * KeyState(ref ClientInput.RightBtn); Cl.viewangles.Y += speed * _YawSpeed.Value * KeyState(ref ClientInput.LeftBtn); Cl.viewangles.Y = Mathlib.AngleMod(Cl.viewangles.Y); } if (ClientInput.KLookBtn.IsDown) { View.StopPitchDrift(); Cl.viewangles.X -= speed * _PitchSpeed.Value * KeyState(ref ClientInput.ForwardBtn); Cl.viewangles.X += speed * _PitchSpeed.Value * KeyState(ref ClientInput.BackBtn); } float up = KeyState(ref ClientInput.LookUpBtn); float down = KeyState(ref ClientInput.LookDownBtn); Cl.viewangles.X -= speed * _PitchSpeed.Value * up; Cl.viewangles.X += speed * _PitchSpeed.Value * down; if (up != 0 || down != 0) { View.StopPitchDrift(); } if (Cl.viewangles.X > 80) { Cl.viewangles.X = 80; } if (Cl.viewangles.X < -70) { Cl.viewangles.X = -70; } if (Cl.viewangles.Z > 50) { Cl.viewangles.Z = 50; } if (Cl.viewangles.Z < -50) { Cl.viewangles.Z = -50; } }
/// <summary> /// SV_Physics_Noclip /// A moving object that doesn't obey physics /// </summary> static void Physics_Noclip(edict_t ent) { // regular thinking if (!RunThink(ent)) { return; } Mathlib.VectorMA(ref ent.v.angles, (float)Host.FrameTime, ref ent.v.avelocity, out ent.v.angles); Mathlib.VectorMA(ref ent.v.origin, (float)Host.FrameTime, ref ent.v.velocity, out ent.v.origin); LinkEdict(ent, false); }
/// <summary> /// SV_ClientThink /// the move fields specify an intended velocity in pix/sec /// the angle fields specify an exact angular motion in degrees /// </summary> static void ClientThink() { if (_Player.v.movetype == Movetypes.MOVETYPE_NONE) { return; } _OnGround = ((int)_Player.v.flags & EdictFlags.FL_ONGROUND) != 0; DropPunchAngle(); // // if dead, behave differently // if (_Player.v.health <= 0) { return; } // // angles // show 1/3 the pitch angle and all the roll angle _Cmd = Host.HostClient.cmd; v3f v_angle; Mathlib.VectorAdd(ref _Player.v.v_angle, ref _Player.v.punchangle, out v_angle); Vector3 pang = Common.ToVector(ref _Player.v.angles); Vector3 pvel = Common.ToVector(ref _Player.v.velocity); _Player.v.angles.z = View.CalcRoll(ref pang, ref pvel) * 4; if (_Player.v.fixangle == 0) { _Player.v.angles.x = -v_angle.x / 3; _Player.v.angles.y = v_angle.y; } if (((int)_Player.v.flags & EdictFlags.FL_WATERJUMP) != 0) { WaterJump(); return; } // // walk // if ((_Player.v.waterlevel >= 2) && (_Player.v.movetype != Movetypes.MOVETYPE_NOCLIP)) { WaterMove(); return; } AirMove(); }
static void DropPunchAngle() { Vector3 v = Common.ToVector(ref _Player.v.punchangle); double len = Mathlib.Normalize(ref v) - 10 * Host.FrameTime; if (len < 0) { len = 0; } v *= (float)len; Mathlib.Copy(ref v, out _Player.v.punchangle); }
static bool IsCollinear(float[] prev, float[] cur, float[] next) { Vector3 v1 = new Vector3(cur[0] - prev[0], cur[1] - prev[1], cur[2] - prev[2]); Mathlib.Normalize(ref v1); Vector3 v2 = new Vector3(next[0] - prev[0], next[1] - prev[1], next[2] - prev[2]); Mathlib.Normalize(ref v2); v1 -= v2; return((Math.Abs(v1.X) <= COLINEAR_EPSILON) && (Math.Abs(v1.Y) <= COLINEAR_EPSILON) && (Math.Abs(v1.Z) <= COLINEAR_EPSILON)); }
/// <summary> /// SV_AirMove /// </summary> static void AirMove() { Vector3 pangles = Common.ToVector(ref _Player.v.angles); Mathlib.AngleVectors(ref pangles, out _Forward, out _Right, out _Up); float fmove = _Cmd.forwardmove; float smove = _Cmd.sidemove; // hack to not let you back into teleporter if (sv.time < _Player.v.teleport_time && fmove < 0) { fmove = 0; } Vector3 wishvel = _Forward * fmove + _Right * smove; if ((int)_Player.v.movetype != Movetypes.MOVETYPE_WALK) { wishvel.Z = _Cmd.upmove; } else { wishvel.Z = 0; } _WishDir = wishvel; _WishSpeed = Mathlib.Normalize(ref _WishDir); if (_WishSpeed > _MaxSpeed.Value) { wishvel *= _MaxSpeed.Value / _WishSpeed; _WishSpeed = _MaxSpeed.Value; } if (_Player.v.movetype == Movetypes.MOVETYPE_NOCLIP) { // noclip Mathlib.Copy(ref wishvel, out _Player.v.velocity); } else if (_OnGround) { UserFriction(); Accelerate(); } else { // not on ground, so little effect on velocity AirAccelerate(wishvel); } }
// SND_Spatialize static void Spatialize(channel_t ch) { // anything coming from the view entity will allways be full volume if (ch.entnum == Client.Cl.viewentity) { ch.leftvol = ch.master_vol; ch.rightvol = ch.master_vol; return; } // calculate stereo seperation and distance attenuation SFX snd = ch.sfx; Vector3 source_vec = ch.origin - _ListenerOrigin; float dist = Mathlib.Normalize(ref source_vec) * ch.dist_mult; float dot = Vector3.Dot(_ListenerRight, source_vec); float rscale, lscale; if (_shm.channels == 1) { rscale = 1.0f; lscale = 1.0f; } else { rscale = 1.0f + dot; lscale = 1.0f - dot; } // add in distance effect float scale = (1.0f - dist) * rscale; ch.rightvol = (int)(ch.master_vol * scale); if (ch.rightvol < 0) { ch.rightvol = 0; } scale = (1.0f - dist) * lscale; ch.leftvol = (int)(ch.master_vol * scale); if (ch.leftvol < 0) { ch.leftvol = 0; } }
/* * ============== * PF_changeyaw * * This was a major timewaster in progs, so it was converted to C * ============== */ public static void PF_changeyaw() { edict_t ent = Server.ProgToEdict(Progs.GlobalStruct.self); float current = Mathlib.AngleMod(ent.v.angles.y); float ideal = ent.v.ideal_yaw; float speed = ent.v.yaw_speed; if (current == ideal) { return; } float move = ideal - current; if (ideal > current) { if (move >= 180) { move = move - 360; } } else { if (move <= -180) { move = move + 360; } } if (move > 0) { if (move > speed) { move = speed; } } else { if (move < -speed) { move = -speed; } } ent.v.angles.y = Mathlib.AngleMod(current + move); }
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> /// V_CalcRoll /// Used by view and sv_user /// </summary> public static float CalcRoll(ref Vector3 angles, ref Vector3 velocity) { Mathlib.AngleVectors(ref angles, out _Forward, out _Right, out _Up); float side = Vector3.Dot(velocity, _Right); float sign = side < 0 ? -1 : 1; side = Math.Abs(side); float value = _ClRollAngle.Value; if (side < _ClRollSpeed.Value) { side = side * value / _ClRollSpeed.Value; } else { side = value; } return(side * sign); }
/// <summary> /// SV_FindTouchedLeafs /// </summary> static void FindTouchedLeafs(edict_t ent, mnodebase_t node) { if (node.contents == Contents.CONTENTS_SOLID) { return; } // add an efrag if the node is a leaf if (node.contents < 0) { if (ent.num_leafs == Progs.MAX_ENT_LEAFS) { return; } mleaf_t leaf = (mleaf_t)node; int leafnum = Array.IndexOf(sv.worldmodel.leafs, leaf) - 1; ent.leafnums[ent.num_leafs] = (short)leafnum; ent.num_leafs++; return; } // NODE_MIXED mnode_t n = (mnode_t)node; mplane_t splitplane = n.plane; int sides = Mathlib.BoxOnPlaneSide(ref ent.v.absmin, ref ent.v.absmax, splitplane); // recurse down the contacted sides if ((sides & 1) != 0) { FindTouchedLeafs(ent, n.children[0]); } if ((sides & 2) != 0) { FindTouchedLeafs(ent, n.children[1]); } }
/// <summary> /// SV_WallFriction /// </summary> static void WallFriction(edict_t ent, trace_t trace) { Vector3 forward, right, up, vangle = Common.ToVector(ref ent.v.v_angle); Mathlib.AngleVectors(ref vangle, out forward, out right, out up); float d = Vector3.Dot(trace.plane.normal, forward); d += 0.5f; if (d >= 0) { return; } // cut the tangential velocity Vector3 vel = Common.ToVector(ref ent.v.velocity); float i = Vector3.Dot(trace.plane.normal, vel); Vector3 into = trace.plane.normal * i; Vector3 side = vel - into; ent.v.velocity.x = side.X * (1 + d); ent.v.velocity.y = side.Y * (1 + d); }
/// <summary> /// SV_UserFriction /// </summary> static void UserFriction() { float speed = Mathlib.LengthXY(ref _Player.v.velocity); if (speed == 0) { return; } // if the leading edge is over a dropoff, increase friction Vector3 start, stop; start.X = stop.X = _Player.v.origin.x + _Player.v.velocity.x / speed * 16; start.Y = stop.Y = _Player.v.origin.y + _Player.v.velocity.y / speed * 16; start.Z = _Player.v.origin.z + _Player.v.mins.z; stop.Z = start.Z - 34; trace_t trace = Move(ref start, ref Common.ZeroVector, ref Common.ZeroVector, ref stop, 1, _Player); float friction = _Friction.Value; if (trace.fraction == 1.0) { friction *= _EdgeFriction.Value; } // apply friction float control = speed < _StopSpeed.Value ? _StopSpeed.Value : speed; float newspeed = (float)(speed - Host.FrameTime * control * friction); if (newspeed < 0) { newspeed = 0; } newspeed /= speed; Mathlib.VectorScale(ref _Player.v.velocity, newspeed, out _Player.v.velocity); }
/// <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); }