/// <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); }
/// <summary> /// SV_TouchLinks /// </summary> static void TouchLinks(edict_t ent, areanode_t node) { // touch linked edicts link_t next; for (link_t 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]); } }
static void PF_makestatic() { edict_t ent = GetEdict(OFS.OFS_PARM0); MsgWriter 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_ClipToLinks /// Mins and maxs enclose the entire area swept by the move /// </summary> static void ClipToLinks(areanode_t node, moveclip_t clip) { link_t next; trace_t trace; // touch linked edicts for (link_t l = node.solid_edicts.Next; l != node.solid_edicts; l = next) { next = l.Next; edict_t touch = (edict_t)l.Owner;// EDICT_FROM_AREA(l); if (touch.v.solid == Solids.SOLID_NOT) { continue; } if (touch == clip.passedict) { continue; } if (touch.v.solid == Solids.SOLID_TRIGGER) { Sys.Error("Trigger in clipping list"); } if (clip.type == MOVE_NOMONSTERS && touch.v.solid != Solids.SOLID_BSP) { continue; } if (clip.boxmins.X > touch.v.absmax.x || clip.boxmins.Y > touch.v.absmax.y || clip.boxmins.Z > touch.v.absmax.z || clip.boxmaxs.X < touch.v.absmin.x || clip.boxmaxs.Y < touch.v.absmin.y || clip.boxmaxs.Z < touch.v.absmin.z) { continue; } if (clip.passedict != null && clip.passedict.v.size.x != 0 && touch.v.size.x == 0) { continue; // points never interact } // might intersect, so do an exact clip if (clip.trace.allsolid) { return; } if (clip.passedict != null) { if (ProgToEdict(touch.v.owner) == clip.passedict) { continue; // don't clip against own missiles } if (ProgToEdict(clip.passedict.v.owner) == touch) { continue; // don't clip against owner } } if (((int)touch.v.flags & EdictFlags.FL_MONSTER) != 0) { trace = ClipMoveToEntity(touch, ref clip.start, ref clip.mins2, ref clip.maxs2, ref clip.end); } else { trace = ClipMoveToEntity(touch, ref clip.start, ref clip.mins, ref clip.maxs, ref clip.end); } if (trace.allsolid || trace.startsolid || trace.fraction < clip.trace.fraction) { trace.ent = touch; if (clip.trace.startsolid) { clip.trace = trace; clip.trace.startsolid = true; } else { clip.trace = trace; } } else if (trace.startsolid) { clip.trace.startsolid = true; } } // recurse down both sides if (node.axis == -1) { return; } if (Mathlib.Comp(ref clip.boxmaxs, node.axis) > node.dist) { ClipToLinks(node.children[0], clip); } if (Mathlib.Comp(ref clip.boxmins, node.axis) < node.dist) { ClipToLinks(node.children[1], clip); } }
/// <summary> /// SV_RecursiveHullCheck /// </summary> public static bool 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 != Contents.CONTENTS_SOLID) { trace.allsolid = false; if (num == Contents.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(RecursiveHullCheck(hull, node_children[0], p1f, p2f, ref p1, ref p2, trace)); } if (t1 < 0 && t2 < 0) { return(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 + DIST_EPSILON) / (t1 - t2); } else { frac = (t1 - 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 (!RecursiveHullCheck(hull, node_children[side], p1f, midf, ref p1, ref mid, trace)) { return(false); } if (HullPointContents(hull, node_children[side ^ 1], ref mid) != Contents.CONTENTS_SOLID) { // go past the node return(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 (HullPointContents(hull, hull.firstclipnode, ref mid) == Contents.CONTENTS_SOLID) { // shouldn't really happen, but does occasionally frac -= 0.1f; if (frac < 0) { trace.fraction = midf; trace.endpos = mid; Con.DPrint("backup past 0\n"); return(false); } midf = p1f + (p2f - p1f) * frac; mid = p1 + (p2 - p1) * frac; } trace.fraction = midf; trace.endpos = mid; return(false); }
/// <summary> /// SV_LinkEdict /// /// Needs to be called any time an entity changes origin, mins, maxs, or solid /// flags ent->v.modified /// sets ent->v.absmin and ent->v.absmax /// if touchtriggers, calls prog functions for the intersected triggers /// </summary> public static void LinkEdict(edict_t ent, bool touch_triggers) { if (ent.area.Prev != null) { UnlinkEdict(ent); // unlink from old position } if (ent == sv.edicts[0]) { return; // don't add the world } if (ent.free) { return; } // set the abs box Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.mins, out ent.v.absmin); Mathlib.VectorAdd(ref ent.v.origin, ref ent.v.maxs, out ent.v.absmax); // // to make items easier to pick up and allow them to be grabbed off // of shelves, the abs sizes are expanded // if (((int)ent.v.flags & EdictFlags.FL_ITEM) != 0) { ent.v.absmin.x -= 15; ent.v.absmin.y -= 15; ent.v.absmax.x += 15; ent.v.absmax.y += 15; } else { // because movement is clipped an epsilon away from an actual edge, // we must fully check even when bounding boxes don't quite touch ent.v.absmin.x -= 1; ent.v.absmin.y -= 1; ent.v.absmin.z -= 1; ent.v.absmax.x += 1; ent.v.absmax.y += 1; ent.v.absmax.z += 1; } // link to PVS leafs ent.num_leafs = 0; if (ent.v.modelindex != 0) { FindTouchedLeafs(ent, sv.worldmodel.nodes[0]); } if (ent.v.solid == Solids.SOLID_NOT) { return; } // find the first node that the ent's box crosses areanode_t node = _AreaNodes[0]; while (true) { if (node.axis == -1) { break; } if (Mathlib.Comp(ref ent.v.absmin, node.axis) > node.dist) { node = node.children[0]; } else if (Mathlib.Comp(ref ent.v.absmax, node.axis) < node.dist) { node = node.children[1]; } else { break; // crosses the node } } // link it in if (ent.v.solid == Solids.SOLID_TRIGGER) { ent.area.InsertBefore(node.trigger_edicts); } else { ent.area.InsertBefore(node.solid_edicts); } // if touch_triggers, touch all entities at this node and decend for more if (touch_triggers) { TouchLinks(ent, _AreaNodes[0]); } }
/// <summary> /// SubdividePolygon /// </summary> static void SubdividePolygon(int numverts, Vector3[] verts) { if (numverts > 60) { Sys.Error("numverts = {0}", numverts); } Vector3 mins, maxs; BoundPoly(numverts, verts, out mins, out maxs); float[] dist = new float[64]; for (int i = 0; i < 3; i++) { double m = (Mathlib.Comp(ref mins, i) + Mathlib.Comp(ref maxs, i)) * 0.5; m = Mod.SubdivideSize * Math.Floor(m / Mod.SubdivideSize + 0.5); if (Mathlib.Comp(ref maxs, i) - m < 8) { continue; } if (m - Mathlib.Comp(ref mins, i) < 8) { continue; } for (int j = 0; j < numverts; j++) { dist[j] = (float)(Mathlib.Comp(ref verts[j], i) - m); } Vector3[] front = new Vector3[64]; Vector3[] back = new Vector3[64]; // cut it // wrap cases dist[numverts] = dist[0]; verts[numverts] = verts[0]; // Uze: source array must be at least numverts + 1 elements long int f = 0, b = 0; for (int j = 0; j < numverts; j++) { if (dist[j] >= 0) { front[f] = verts[j]; f++; } if (dist[j] <= 0) { back[b] = verts[j]; b++; } if (dist[j] == 0 || dist[j + 1] == 0) { continue; } if ((dist[j] > 0) != (dist[j + 1] > 0)) { // clip point float frac = dist[j] / (dist[j] - dist[j + 1]); front[f] = back[b] = verts[j] + (verts[j + 1] - verts[j]) * frac; f++; b++; } } SubdividePolygon(f, front); SubdividePolygon(b, back); return; } glpoly_t poly = new glpoly_t(); poly.next = _WarpFace.polys; _WarpFace.polys = poly; poly.AllocVerts(numverts); for (int i = 0; i < numverts; i++) { Common.Copy(ref verts[i], poly.verts[i]); float s = Vector3.Dot(verts[i], _WarpFace.texinfo.vecs[0].Xyz); float t = Vector3.Dot(verts[i], _WarpFace.texinfo.vecs[1].Xyz); poly.verts[i][3] = s; poly.verts[i][4] = t; } }