static byte[] _FatPvs = new byte[BspFile.MAX_MAP_LEAFS / 8]; // fatpvs // SV_Init public static void Init() { for (int i = 0; i < _BoxClipNodes.Length; i++) { _BoxClipNodes[i].children = new short[2]; } for (int i = 0; i < _BoxPlanes.Length; i++) { _BoxPlanes[i] = new mplane_t(); } for (int i = 0; i < _AreaNodes.Length; i++) { _AreaNodes[i] = new areanode_t(); } if (_Friction == null) { _Friction = new Cvar("sv_friction", "4", false, true); _EdgeFriction = new Cvar("edgefriction", "2"); _StopSpeed = new Cvar("sv_stopspeed", "100"); _Gravity = new Cvar("sv_gravity", "800", false, true); _MaxVelocity = new Cvar("sv_maxvelocity", "2000"); _NoStep = new Cvar("sv_nostep", "0"); _MaxSpeed = new Cvar("sv_maxspeed", "320", false, true); _Accelerate = new Cvar("sv_accelerate", "10"); _Aim = new Cvar("sv_aim", "0.93"); _IdealPitchScale = new Cvar("sv_idealpitchscale", "0.8"); } for (int i = 0; i < QDef.MAX_MODELS; i++) { _LocalModels[i] = "*" + i.ToString(); } }
/// <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]); } }
/// <summary> /// SV_CreateAreaNode /// </summary> static areanode_t CreateAreaNode(int depth, ref Vector3 mins, ref Vector3 maxs) { areanode_t anode = _AreaNodes[_NumAreaNodes]; _NumAreaNodes++; anode.trigger_edicts.Clear(); anode.solid_edicts.Clear(); if (depth == AREA_DEPTH) { anode.axis = -1; anode.children[0] = anode.children[1] = null; return(anode); } Vector3 size = maxs - mins; Vector3 mins1 = mins; Vector3 mins2 = mins; Vector3 maxs1 = maxs; Vector3 maxs2 = maxs; if (size.X > size.Y) { anode.axis = 0; anode.dist = 0.5f * (maxs.X + mins.X); maxs1.X = mins2.X = anode.dist; } else { anode.axis = 1; anode.dist = 0.5f * (maxs.Y + mins.Y); maxs1.Y = mins2.Y = anode.dist; } anode.children[0] = CreateAreaNode(depth + 1, ref mins2, ref maxs2); anode.children[1] = CreateAreaNode(depth + 1, ref mins1, ref maxs1); return(anode); }
/// <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_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]); } }