public static trace_t SV_ClipMoveToEntity(edict_t ent, ref Vector3 start, ref Vector3 mins, ref Vector3 maxs, ref Vector3 end) { trace_t trace = new trace_t(); // fill in a default trace trace.fraction = 1; trace.allsolid = true; trace.endpos = end; // get the clipping hull Vector3 offset; hull_t hull = SV_HullForEntity(ent, ref mins, ref maxs, out offset); Vector3 start_l = start - offset; Vector3 end_l = end - offset; // trace a line through the apropriate clipping hull SV_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); }
static void PF_droptofloor() { edict_t ent = PROG_TO_EDICT(pr_global_struct.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 = SV_Move(ref org, ref mins, ref maxs, ref end, 0, ent); if (trace.fraction == 1 || trace.allsolid) { G_FLOAT((float)0); } else { Mathlib.Copy(ref trace.endpos, out ent.v.origin); SV_LinkEdict(ent, false); ent.v.flags = (int)ent.v.flags | q_shared.FL_ONGROUND; ent.v.groundentity = EDICT_TO_PROG(trace.ent); G_FLOAT((float)1); } }
static unsafe void PF_traceline() { float * v1 = G_VECTOR(q_shared.OFS_PARM0); float * v2 = G_VECTOR(q_shared.OFS_PARM1); int nomonsters = (int)G_FLOAT(q_shared.OFS_PARM2); edict_t ent = G_EDICT(q_shared.OFS_PARM3); Vector3 vec1, vec2; Copy(v1, out vec1); Copy(v2, out vec2); trace_t trace = SV_Move(ref vec1, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref vec2, nomonsters, ent); pr_global_struct.trace_allsolid = trace.allsolid ? 1 : 0; pr_global_struct.trace_startsolid = trace.startsolid ? 1 : 0; pr_global_struct.trace_fraction = trace.fraction; pr_global_struct.trace_inwater = trace.inwater ? 1 : 0; pr_global_struct.trace_inopen = trace.inopen ? 1 : 0; Mathlib.Copy(ref trace.endpos, out pr_global_struct.trace_endpos); Mathlib.Copy(ref trace.plane.normal, out pr_global_struct.trace_plane_normal); pr_global_struct.trace_plane_dist = trace.plane.dist; if (trace.ent != null) { pr_global_struct.trace_ent = EDICT_TO_PROG(trace.ent); } else { pr_global_struct.trace_ent = EDICT_TO_PROG(sv.edicts[0]); } }
public static void TraceLine(ref Vector3 start, ref Vector3 end, out Vector3 impact) { trace_t trace = new trace_t(); SV_RecursiveHullCheck(cl.worldmodel.hulls[0], 0, 0, 1, ref start, ref end, trace); impact = trace.endpos; }
public void HitWall(trace_t trace) { if (traceTime == 0 || ((HighResolutionTimer.Ticks - traceTime) / HighResolutionTimer.Frequency) > 1f) { //this.trace = trace; //Info.Text = "Hit Wall - " + trace.plane; traceTime = HighResolutionTimer.Ticks; } }
public static edict_t SV_TestEntityPosition(edict_t ent) { trace_t 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); }
public static trace_t Create() { trace_t t = new trace_t(); t.m_AllSolid = true; t.m_StartSolid = true; t.m_Fraction = 1f; t.m_FractionLeftSolid = 1f; t.m_EndPos = Vector3.Zero; t.m_Contents = 0; t.m_nBrushSide = 0; return(t); }
public static int SV_TryUnstick(edict_t ent, ref v3f oldvel) { v3f oldorg = ent.v.origin; v3f dir = q_shared.ZeroVector3f; trace_t steptrace = new trace_t(); for (int i = 0; i < 8; i++) { // try pushing a little in an axial direction switch (i) { case 0: dir.x = 2; dir.y = 0; break; case 1: dir.x = 0; dir.y = 2; break; case 2: dir.x = -2; dir.y = 0; break; case 3: dir.x = 0; dir.y = -2; break; case 4: dir.x = 2; dir.y = 2; break; case 5: dir.x = -2; dir.y = 2; break; case 6: dir.x = 2; dir.y = -2; break; case 7: dir.x = -2; dir.y = -2; break; } PushEntity(ent, ref dir); // retry the original move ent.v.velocity.x = oldvel.x; ent.v.velocity.y = oldvel.y; ent.v.velocity.z = 0; int clip = SV_FlyMove(ent, 0.1f, steptrace); if (Math.Abs(oldorg.y - ent.v.origin.y) > 4 || Math.Abs(oldorg.x - ent.v.origin.x) > 4) { return(clip); } // go back to the original pos and try again ent.v.origin = oldorg; } ent.v.velocity = q_shared.ZeroVector3f; return(7); // still not moving }
/** * Two entities have touched, so run their touch functions. */ public static void SV_Impact(edict_t e1, trace_t trace) { edict_t e2; e2 = trace.ent; if (e1.touch != null && e1.solid != Defines.SOLID_NOT) { e1.touch.touch(e1, e2, trace.plane, trace.surface); } if (e2.touch != null && e2.solid != Defines.SOLID_NOT) { e2.touch.touch(e2, e1, GameBase.dummyplane, null); } }
public static void SV_WallFriction(edict_t ent, trace_t trace) { Vector3 forward, right, up, vangle = 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 = 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); }
public static void SV_UserFriction() { float speed = Mathlib.LengthXY(ref sv_player.v.velocity); if (speed == 0) { return; } // if the leading edge is over a dropoff, increase friction Vector3 start, stop; start.X = stop.X = sv_player.v.origin.x + sv_player.v.velocity.x / speed * 16; start.Y = stop.Y = sv_player.v.origin.y + sv_player.v.velocity.y / speed * 16; start.Z = sv_player.v.origin.z + sv_player.v.mins.z; stop.Z = start.Z - 34; trace_t trace = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref stop, 1, sv_player); float friction = sv_friction.value; if (trace.fraction == 1.0) { friction *= edgefriction.value; } // apply friction float control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed; float newspeed = (float)(speed - host_framtime * control * friction); if (newspeed < 0) { newspeed = 0; } newspeed /= speed; Mathlib.VectorScale(ref sv_player.v.velocity, newspeed, out sv_player.v.velocity); }
public static int SV_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[q_shared.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 == q_shared.SOLID_BSP) { ent.v.flags = (int)ent.v.flags | q_shared.FL_ONGROUND; ent.v.groundentity = EDICT_TO_PROG(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 // SV_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 >= q_shared.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); }
static void PF_aim() { edict_t ent = G_EDICT(q_shared.OFS_PARM0); float speed = G_FLOAT(q_shared.OFS_PARM1); Vector3 start = ToVector(ref ent.v.origin); start.Z += 20; // try sending a trace straight Vector3 dir; Mathlib.Copy(ref pr_global_struct.v_forward, out dir); Vector3 end = start + dir * 2048; trace_t tr = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref end, 0, ent); if (tr.ent != null && tr.ent.v.takedamage == q_shared.DAMAGE_AIM && (teamplay.value == 0 || ent.v.team <= 0 || ent.v.team != tr.ent.v.team)) { G_VECTOR(ref pr_global_struct.v_forward); return; } // try all possible entities Vector3 bestdir = dir; float bestdist = sv_aim.value; edict_t bestent = null; for (int i = 1; i < sv.num_edicts; i++) { edict_t check = sv.edicts[i]; if (check.v.takedamage != q_shared.DAMAGE_AIM) { continue; } if (check == ent) { continue; } if (teamplay.value != 0 && ent.v.team > 0 && ent.v.team == check.v.team) { continue; // don't aim at teammate } v3f tmp; Mathlib.VectorAdd(ref check.v.mins, ref check.v.maxs, out tmp); Mathlib.VectorMA(ref check.v.origin, 0.5f, ref tmp, out tmp); Mathlib.Copy(ref tmp, out end); dir = end - start; Mathlib.Normalize(ref dir); float dist = Vector3.Dot(dir, ToVector(ref pr_global_struct.v_forward)); if (dist < bestdist) { continue; // to far to turn } tr = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref end, 0, ent); if (tr.ent == check) { // can shoot at this one bestdist = dist; bestent = check; } } if (bestent != null) { v3f dir2, end2; Mathlib.VectorSubtract(ref bestent.v.origin, ref ent.v.origin, out dir2); float dist = Mathlib.DotProduct(ref dir2, ref pr_global_struct.v_forward); Mathlib.VectorScale(ref pr_global_struct.v_forward, dist, out end2); end2.z = dir2.z; Mathlib.Normalize(ref end2); G_VECTOR(ref end2); } else { G_VECTOR(ref bestdir); } }
/** * Called by monster program code. The move will be adjusted for slopes and * stairs, but if the move isn't possible, no move is done, false is * returned, and pr_global_struct.trace_normal is set to the normal of the * blocking wall. */ // FIXME: since we need to test end position contents here, can we avoid // doing it again later in catagorize position? public static bool SV_movestep(edict_t ent, float[] move, bool relink) { float dz; float[] oldorg = { 0, 0, 0 }; float[] neworg = { 0, 0, 0 }; float[] end = { 0, 0, 0 }; trace_t trace = null; // = new trace_t(); int i; float stepsize; float[] test = { 0, 0, 0 }; int contents; // try the move Math3D.VectorCopy(ent.s.origin, oldorg); Math3D.VectorAdd(ent.s.origin, move, neworg); // flying monsters don't step up if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0) { // try one move with vertical motion, then one without for (i = 0; i < 2; i++) { Math3D.VectorAdd(ent.s.origin, move, neworg); if (i == 0 && ent.enemy != null) { if (ent.goalentity == null) { ent.goalentity = ent.enemy; } dz = ent.s.origin[2] - ent.goalentity.s.origin[2]; if (ent.goalentity.client != null) { if (dz > 40) { neworg[2] -= 8; } if (!((ent.flags & Defines.FL_SWIM) != 0 && ent.waterlevel < 2)) { if (dz < 30) { neworg[2] += 8; } } } else { if (dz > 8) { neworg[2] -= 8; } else if (dz > 0) { neworg[2] -= dz; } else if (dz < -8) { neworg[2] += 8; } else { neworg[2] += dz; } } } trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, neworg, ent, Defines.MASK_MONSTERSOLID); // fly monsters don't enter water voluntarily if ((ent.flags & Defines.FL_FLY) != 0) { if (ent.waterlevel == 0) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent.mins[2] + 1; contents = GameBase.gi.pointcontents(test); if ((contents & Defines.MASK_WATER) != 0) { return(false); } } } // swim monsters don't exit water voluntarily if ((ent.flags & Defines.FL_SWIM) != 0) { if (ent.waterlevel < 2) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent.mins[2] + 1; contents = GameBase.gi.pointcontents(test); if ((contents & Defines.MASK_WATER) == 0) { return(false); } } } if (trace.fraction == 1) { Math3D.VectorCopy(trace.endpos, ent.s.origin); if (relink) { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } return(true); } if (ent.enemy == null) { break; } } return(false); } // push down from a step height above the wished position if ((ent.monsterinfo.aiflags & Defines.AI_NOSTEP) == 0) { stepsize = GameBase.STEPSIZE; } else { stepsize = 1; } neworg[2] += stepsize; Math3D.VectorCopy(neworg, end); end[2] -= stepsize * 2; trace = GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID); if (trace.allsolid) { return(false); } if (trace.startsolid) { neworg[2] -= stepsize; trace = GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID); if (trace.allsolid || trace.startsolid) { return(false); } } // don't go in to water if (ent.waterlevel == 0) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent.mins[2] + 1; contents = GameBase.gi.pointcontents(test); if ((contents & Defines.MASK_WATER) != 0) { return(false); } } if (trace.fraction == 1) { // if monster had the ground pulled out, go ahead and fall if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { Math3D.VectorAdd(ent.s.origin, move, ent.s.origin); if (relink) { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } ent.groundentity = null; return(true); } return(false); // walked off an edge } // check point traces down for dangling corners Math3D.VectorCopy(trace.endpos, ent.s.origin); if (!M.M_CheckBottom(ent)) { if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } return(true); } Math3D.VectorCopy(oldorg, ent.s.origin); return(false); } if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { ent.flags &= ~Defines.FL_PARTIALGROUND; } ent.groundentity = trace.ent; ent.groundentity_linkcount = trace.ent.linkcount; // the move is ok if (relink) { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } return(true); }
/* ================== SV_ClipMoveToEntity Handles selection or creation of a clipping hull, and offseting (and eventually rotation) of the end points ================== */ public static trace_t SV_ClipMoveToEntity(prog.edict_t ent, double[] start, double[] mins, double[] maxs, double[] end) { trace_t trace; double[] offset = new double[3] {0, 0, 0}; double[] start_l = new double[3] {0, 0, 0}, end_l = new double[3] {0, 0, 0}; model.hull_t hull; // fill in a default trace trace = new trace_t(); trace.fraction = 1; trace.allsolid = true; mathlib.VectorCopy(end, trace.endpos); // get the clipping hull hull = SV_HullForEntity(ent, mins, maxs, offset); mathlib.VectorSubtract(start, offset, start_l); mathlib.VectorSubtract(end, offset, end_l); //Debug.WriteLine(string.Format("end[2] {0:F6}", (float)end[2])); // trace a line through the apropriate clipping hull //Debug.WriteLine(string.Format("end_l[2] {0:F6}",(float) end_l[2])); SV_RecursiveHullCheck(hull, hull.firstclipnode, 0, 1, start_l, end_l, trace); // fix trace up by the offset if (trace.fraction != 1) mathlib.VectorAdd(trace.endpos, offset, trace.endpos); // did we clip the move? if (trace.fraction < 1 || trace.startsolid) trace.ent = ent; return trace; }
public static bool SV_RecursiveHullCheck( model.hull_t hull, int num, double p1f, double p2f, double[] p1, double[] p2, trace_t trace) { bspfile.dclipnode_t node; model.mplane_t plane; double t1, t2; double frac; int i; double[] mid = new double[3] {0, 0, 0}; int side; double midf; //Debug.WriteLine(string.Format("SV_RecursiveHullCheck hull.firstclipnode:{0} num:{1} {2:F6} {3:F6} p1[0] {4:F6} p1[1] {5:F6} p1[2] {6:F6} - p2[0] {7:F6} p2[1] {8:F6} p2[2] {9:F6} num_hullcheck: {10}", hull.firstclipnode, num, (float)p1f, (float)p2f, (float)p1[0], (float)p1[1], (float)p1[2], (float)p2[0], (float)p2[1], (float)p2[2], num_hullcheck)); num_hullcheck++; // check for empty if (num < 0) { if (num != bspfile.CONTENTS_SOLID) { trace.allsolid = false; if (num == bspfile.CONTENTS_EMPTY) trace.inopen = true; else trace.inwater = true; } else trace.startsolid = true; //Debug.WriteLine(string.Format("empty")); return true; // empty } if (num < hull.firstclipnode || num > hull.lastclipnode) sys_linux.Sys_Error("SV_RecursiveHullCheck: bad node number"); // // find the point distances // node = hull.clipnodes[num]; plane = hull.planes[node.planenum]; if (plane.type < 3) { t1 = p1[plane.type] - plane.dist; t2 = p2[plane.type] - plane.dist; } else { t1 = mathlib.DotProduct(plane.normal, p1) - plane.dist; t2 = mathlib.DotProduct(plane.normal, p2) - plane.dist; } //Debug.WriteLine(string.Format("t1: {0:F6} t2: {1:F6}", (float)t1, (float)t2)); if (t1 >= 0 && t2 >= 0) { return SV_RecursiveHullCheck(hull, node.children[0], p1f, p2f, p1, p2, trace); } if (t1 < 0 && t2 < 0) { return SV_RecursiveHullCheck(hull, node.children[1], p1f, p2f, p1, p2, trace); } // put the crosspoint DIST_EPSILON pixels on the near side if (t1 < 0) frac = (t1 + DIST_EPSILON) / (t1 - t2); else frac = (t1 - DIST_EPSILON) / (t1 - t2); if (frac < 0) frac = 0; if (frac > 1) frac = 1; midf = p1f + (p2f - p1f) * frac; for (i = 0; i < 3; i++) mid[i] = p1[i] + frac * (p2[i] - p1[i]); side = (t1 < 0) ? 1 : 0; // move up to the node if (!SV_RecursiveHullCheck(hull, node.children[side], p1f, midf, p1, mid, trace)) { return false; } if (SV_HullPointContents(hull, node.children[side ^ 1], mid) != bspfile.CONTENTS_SOLID) // go past the node { return SV_RecursiveHullCheck(hull, node.children[side ^ 1], midf, p2f, mid, p2, trace); } if (trace.allsolid) { return false; // never got out of the solid area } //================== // the other side of the node is solid, this is the impact point //================== if (side == 0) { mathlib.VectorCopy(plane.normal, trace.plane.normal); trace.plane.dist = plane.dist; } else { mathlib.VectorSubtract(mathlib.vec3_origin, plane.normal, trace.plane.normal); trace.plane.dist = -plane.dist; } while (SV_HullPointContents(hull, hull.firstclipnode, mid) == bspfile.CONTENTS_SOLID) { // shouldn't really happen, but does occasionally frac -= 0.1; if (frac < 0) { trace.fraction = midf; mathlib.VectorCopy(mid, trace.endpos); console.Con_DPrintf("backup past 0\n"); return false; } midf = p1f + (p2f - p1f) * frac; for (i = 0; i < 3; i++) mid[i] = p1[i] + frac * (p2[i] - p1[i]); } trace.fraction = midf; mathlib.VectorCopy(mid, trace.endpos); return false; }
public static bool SV_RecursiveHullCheck(hull_t hull, int num, float p1f, float p2f, ref Vector3 p1, ref Vector3 p2, trace_t trace) { // check for empty if (num < 0) { if (num != q_shared.CONTENTS_SOLID) { trace.allsolid = false; if (num == q_shared.CONTENTS_EMPTY) { trace.inopen = true; } else { trace.inwater = true; } } else { trace.startsolid = true; } return(true); // empty } if (num < hull.firstclipnode || num > hull.lastclipnode) { Sys_Error("SV_RecursiveHullCheck: bad node number"); } // // find the point distances // short[] node_children = hull.clipnodes[num].children; mplane_t plane = hull.planes[hull.clipnodes[num].planenum]; float t1, t2; if (plane.type < 3) { t1 = Mathlib.Comp(ref p1, plane.type) - plane.dist; t2 = Mathlib.Comp(ref p2, plane.type) - plane.dist; } else { t1 = Vector3.Dot(plane.normal, p1) - plane.dist; t2 = Vector3.Dot(plane.normal, p2) - plane.dist; } if (t1 >= 0 && t2 >= 0) { return(SV_RecursiveHullCheck(hull, node_children[0], p1f, p2f, ref p1, ref p2, trace)); } if (t1 < 0 && t2 < 0) { return(SV_RecursiveHullCheck(hull, node_children[1], p1f, p2f, ref p1, ref p2, trace)); } // put the crosspoint DIST_EPSILON pixels on the near side float frac; if (t1 < 0) { frac = (t1 + q_shared.DIST_EPSILON) / (t1 - t2); } else { frac = (t1 - q_shared.DIST_EPSILON) / (t1 - t2); } if (frac < 0) { frac = 0; } if (frac > 1) { frac = 1; } float midf = p1f + (p2f - p1f) * frac; Vector3 mid = p1 + (p2 - p1) * frac; int side = (t1 < 0) ? 1 : 0; // move up to the node if (!SV_RecursiveHullCheck(hull, node_children[side], p1f, midf, ref p1, ref mid, trace)) { return(false); } if (SV_HullPointContents(hull, node_children[side ^ 1], ref mid) != q_shared.CONTENTS_SOLID) { // go past the node return(SV_RecursiveHullCheck(hull, node_children[side ^ 1], midf, p2f, ref mid, ref p2, trace)); } if (trace.allsolid) { return(false); // never got out of the solid area } //================== // the other side of the node is solid, this is the impact point //================== if (side == 0) { trace.plane.normal = plane.normal; trace.plane.dist = plane.dist; } else { trace.plane.normal = -plane.normal; trace.plane.dist = -plane.dist; } while (SV_HullPointContents(hull, hull.firstclipnode, ref mid) == q_shared.CONTENTS_SOLID) { // shouldn't really happen, but does occasionally frac -= 0.1f; if (frac < 0) { trace.fraction = midf; trace.endpos = mid; Con_DPrintf("backup past 0\n"); return(false); } midf = p1f + (p2f - p1f) * frac; mid = p1 + (p2 - p1) * frac; } trace.fraction = midf; trace.endpos = mid; return(false); }
public static bool SV_CheckBottom(edict_t ent) { v3f mins, maxs; Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.mins, out mins); Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.maxs, out maxs); // if all of the points under the corners are solid world, don't bother // with the tougher checks // the corners must be within 16 of the midpoint Vector3 start; start.Z = mins.z - 1; for (int x = 0; x <= 1; x++) { for (int y = 0; y <= 1; y++) { start.X = (x != 0 ? maxs.x : mins.x); start.Y = (y != 0 ? maxs.y : mins.y); if (SV_PointContents(ref start) != q_shared.CONTENTS_SOLID) { goto RealCheck; } } } return(true); // we got out easy RealCheck: // // check it for real... // start.Z = mins.z; // the midpoint must be within 16 of the bottom start.X = (mins.x + maxs.x) * 0.5f; start.Y = (mins.y + maxs.y) * 0.5f; Vector3 stop = start; stop.Z -= 2 * q_shared.STEPSIZE; trace_t trace = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref stop, 1, ent); if (trace.fraction == 1.0) { return(false); } float mid = trace.endpos.Z; float bottom = mid; // the corners must be within 16 of the midpoint for (int x = 0; x <= 1; x++) { for (int y = 0; y <= 1; y++) { start.X = stop.X = (x != 0 ? maxs.x : mins.x); start.Y = stop.Y = (y != 0 ? maxs.y : mins.y); trace = SV_Move(ref start, ref q_shared.ZeroVector, ref q_shared.ZeroVector, ref stop, 1, ent); if (trace.fraction != 1.0 && trace.endpos.Z > bottom) { bottom = trace.endpos.Z; } if (trace.fraction == 1.0 || mid - trace.endpos.Z > q_shared.STEPSIZE) { return(false); } } } return(true); }
/* * ==================== CL_ClipMoveToEntities * * ==================== */ private static void ClipMoveToEntities(float[] start, float[] mins, float[] maxs, float[] end, trace_t tr) { int i, x, zd, zu; trace_t trace; int headnode; float[] angles; entity_state_t ent; int num; cmodel_t cmodel; var bmins = new float[3]; var bmaxs = new float[3]; for (i = 0; i < Globals.cl.frame.num_entities; i++) { num = (Globals.cl.frame.parse_entities + i) & (Defines.MAX_PARSE_ENTITIES - 1); ent = Globals.cl_parse_entities[num]; if (ent.solid == 0) { continue; } if (ent.number == Globals.cl.playernum + 1) { continue; } if (ent.solid == 31) { // special value for bmodel cmodel = Globals.cl.model_clip[ent.modelindex]; if (cmodel == null) { continue; } headnode = cmodel.headnode; angles = ent.angles; } else { // encoded bbox x = 8 * (ent.solid & 31); zd = (int)(8 * (((uint)ent.solid >> 5) & 31)); zu = (int)(8 * (((uint)ent.solid >> 10) & 63) - 32); bmins[0] = bmins[1] = -x; bmaxs[0] = bmaxs[1] = x; bmins[2] = -zd; bmaxs[2] = zu; headnode = CM.HeadnodeForBox(bmins, bmaxs); angles = Globals.vec3_origin; // boxes don't rotate } if (tr.allsolid) { return; } trace = CM.TransformedBoxTrace(start, end, mins, maxs, headnode, Defines.MASK_PLAYERSOLID, ent.origin, angles); if (trace.allsolid || trace.startsolid || trace.fraction < tr.fraction) { trace.ent = ent.surrounding_ent; if (tr.startsolid) { tr.set(trace); // rst: solved the Z U P P E L - P R O B L E // M tr.startsolid = true; } else { tr.set(trace); // rst: solved the Z U P P E L - P R O B L E } // M } else if (trace.startsolid) { tr.startsolid = true; } } }
public static void SV_WalkMove(edict_t ent) { // // do a regular slide move unless it looks like you ran into a step // int oldonground = (int)ent.v.flags & q_shared.FL_ONGROUND; ent.v.flags = (int)ent.v.flags & ~q_shared.FL_ONGROUND; v3f oldorg = ent.v.origin; v3f oldvel = ent.v.velocity; trace_t steptrace = new trace_t(); int clip = SV_FlyMove(ent, (float)host_framtime, steptrace); if ((clip & 2) == 0) { return; // move didn't block on a step } if (oldonground == 0 && ent.v.waterlevel == 0) { return; // don't stair up while jumping } if (ent.v.movetype != q_shared.MOVETYPE_WALK) { return; // gibbed by a trigger } if (sv_nostep.value != 0) { return; } if (((int)sv_player.v.flags & q_shared.FL_WATERJUMP) != 0) { return; } v3f nosteporg = ent.v.origin; v3f nostepvel = ent.v.velocity; // // try moving up and forward to go up a step // ent.v.origin = oldorg; // back to start pos v3f upmove = q_shared.ZeroVector3f; v3f downmove = upmove; upmove.z = q_shared.STEPSIZE; downmove.z = (float)(-q_shared.STEPSIZE + oldvel.z * host_framtime); // move up PushEntity(ent, ref upmove); // FIXME: don't link? // move forward ent.v.velocity.x = oldvel.x; ent.v.velocity.y = oldvel.y; ent.v.velocity.z = 0; clip = SV_FlyMove(ent, (float)host_framtime, steptrace); // check for stuckness, possibly due to the limited precision of floats // in the clipping hulls if (clip != 0) { if (Math.Abs(oldorg.y - ent.v.origin.y) < 0.03125 && Math.Abs(oldorg.x - ent.v.origin.x) < 0.03125) { // stepping up didn't make any progress clip = SV_TryUnstick(ent, ref oldvel); } } // extra friction based on view angle if ((clip & 2) != 0) { SV_WallFriction(ent, steptrace); } // move down trace_t downtrace = PushEntity(ent, ref downmove); // FIXME: don't link? if (downtrace.plane.normal.Z > 0.7) { if (ent.v.solid == q_shared.SOLID_BSP) { ent.v.flags = (int)ent.v.flags | q_shared.FL_ONGROUND; ent.v.groundentity = EDICT_TO_PROG(downtrace.ent); } } else { // if the push down didn't end up on good ground, use the move without // the step up. This happens near wall / slope combinations, and can // cause the player to hop up higher on a slope too steep to climb ent.v.origin = nosteporg; ent.v.velocity = nostepvel; } }
public static void SV_Physics_Toss(edict_t ent) { // regular thinking if (!SV_RunThink(ent)) { return; } // if onground, return without moving if (((int)ent.v.flags & q_shared.FL_ONGROUND) != 0) { return; } SV_CheckVelocity(ent); // add gravity if (ent.v.movetype != q_shared.MOVETYPE_FLY && ent.v.movetype != q_shared.MOVETYPE_FLYMISSILE) { SV_AddGravity(ent); } // move angles Mathlib.VectorMA(ref ent.v.angles, (float)host_framtime, ref ent.v.avelocity, out ent.v.angles); // move origin v3f move; Mathlib.VectorScale(ref ent.v.velocity, (float)host_framtime, out move); trace_t trace = PushEntity(ent, ref move); if (trace.fraction == 1) { return; } if (ent.free) { return; } float backoff; if (ent.v.movetype == q_shared.MOVETYPE_BOUNCE) { backoff = 1.5f; } else { backoff = 1; } ClipVelocity(ref ent.v.velocity, ref trace.plane.normal, out ent.v.velocity, backoff); // stop if on ground if (trace.plane.normal.Z > 0.7f) { if (ent.v.velocity.z < 60 || ent.v.movetype != q_shared.MOVETYPE_BOUNCE) { ent.v.flags = (int)ent.v.flags | q_shared.FL_ONGROUND; ent.v.groundentity = EDICT_TO_PROG(trace.ent); ent.v.velocity = default(v3f); ent.v.avelocity = default(v3f); } } // check for in water SV_CheckWaterTransition(ent); }
public static void SV_SetIdealPitch() { if (((int)sv_player.v.flags & q_shared.FL_ONGROUND) == 0) { return; } double angleval = sv_player.v.angles.y * Math.PI * 2 / 360; double sinval = Math.Sin(angleval); double cosval = Math.Cos(angleval); float[] z = new float[q_shared.MAX_FORWARD]; for (int i = 0; i < q_shared.MAX_FORWARD; i++) { v3f top = sv_player.v.origin; top.x += (float)(cosval * (i + 3) * 12); top.y += (float)(sinval * (i + 3) * 12); top.z += sv_player.v.view_ofs.z; v3f bottom = top; bottom.z -= 160; trace_t tr = Move(ref top, ref q_shared.ZeroVector3f, ref q_shared.ZeroVector3f, ref bottom, 1, sv_player); if (tr.allsolid) { return; // looking at a wall, leave ideal the way is was } if (tr.fraction == 1) { return; // near a dropoff } z[i] = top.z + tr.fraction * (bottom.z - top.z); } float dir = 0; // Uze: int in original code??? int steps = 0; for (int j = 1; j < q_shared.MAX_FORWARD; j++) { float step = z[j] - z[j - 1]; // Uze: int in original code??? if (step > -q_shared.ON_EPSILON && step < q_shared.ON_EPSILON) // Uze: comparing int with ON_EPSILON (0.1)??? { continue; } if (dir != 0 && (step - dir > q_shared.ON_EPSILON || step - dir < -q_shared.ON_EPSILON)) { return; // mixed changes } steps++; dir = step; } if (dir == 0) { sv_player.v.idealpitch = 0; return; } if (steps < 2) { return; } sv_player.v.idealpitch = -dir * sv_idealpitchscale.value; }