/// <summary> /// PF_checkclient /// Returns a client (or object that has a client enemy) that would be a /// valid target. /// /// If there are more than one valid options, they are cycled each frame /// /// If (self.origin + self.viewofs) is not in the PVS of the current target, /// it is not returned at all. /// /// name checkclient () /// </summary> static void PF_checkclient() { // find a new check if on a new frame if (Server.sv.time - Server.sv.lastchecktime >= 0.1) { Server.sv.lastcheck = PF_newcheckclient(Server.sv.lastcheck); Server.sv.lastchecktime = Server.sv.time; } // return check if it might be visible edict_t ent = Server.EdictNum(Server.sv.lastcheck); if (ent.free || ent.v.health <= 0) { ReturnEdict(Server.sv.edicts[0]); return; } // if current entity can't possibly see the check entity, return 0 edict_t self = Server.ProgToEdict(Progs.GlobalStruct.self); Vector3 view = Common.ToVector(ref self.v.origin) + Common.ToVector(ref self.v.view_ofs); mleaf_t leaf = Mod.PointInLeaf(ref view, Server.sv.worldmodel); int l = Array.IndexOf(Server.sv.worldmodel.leafs, leaf) - 1; if ((l < 0) || (_CheckPvs[l >> 3] & (1 << (l & 7))) == 0) { _NotVisCount++; ReturnEdict(Server.sv.edicts[0]); return; } // might be able to see it _InVisCount++; ReturnEdict(ent); }
public void Clear() { this.leaf = null; this.leafnext = null; this.entity = null; this.entnext = null; }
// S_UpdateAmbientSounds static void UpdateAmbientSounds() { if (!_Ambient) { return; } // calc ambient sound levels if (Client.Cl.worldmodel == null) { return; } mleaf_t l = Mod.PointInLeaf(ref _ListenerOrigin, Client.Cl.worldmodel); if (l == null || _AmbientLevel.Value == 0) { for (int i = 0; i < Ambients.NUM_AMBIENTS; i++) { _Channels[i].sfx = null; } return; } for (int i = 0; i < Ambients.NUM_AMBIENTS; i++) { channel_t chan = _Channels[i]; chan.sfx = _AmbientSfx[i]; float vol = _AmbientLevel.Value * l.ambient_sound_level[i]; if (vol < 8) { vol = 0; } // don't adjust volume too fast if (chan.master_vol < vol) { chan.master_vol += (int)(Host.FrameTime * _AmbientFade.Value); if (chan.master_vol > vol) { chan.master_vol = (int)vol; } } else if (chan.master_vol > vol) { chan.master_vol -= (int)(Host.FrameTime * _AmbientFade.Value); if (chan.master_vol < vol) { chan.master_vol = (int)vol; } } chan.leftvol = chan.rightvol = chan.master_vol; } }
/// <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> /// R_RecursiveWorldNode /// </summary> private static void RecursiveWorldNode(mnodebase_t node) { if (node.contents == Contents.CONTENTS_SOLID) { return; // solid } if (node.visframe != _VisFrameCount) { return; } if (CullBox(ref node.mins, ref node.maxs)) { return; } int c; // if a leaf node, draw stuff if (node.contents < 0) { mleaf_t pleaf = (mleaf_t)node; msurface_t[] marks = pleaf.marksurfaces; int mark = pleaf.firstmarksurface; c = pleaf.nummarksurfaces; if (c != 0) { do { marks[mark].visframe = _FrameCount; mark++; } while(--c != 0); } // deal with model fragments in this leaf if (pleaf.efrags != null) { StoreEfrags(pleaf.efrags); } return; } // node is just a decision point, so go down the apropriate sides mnode_t n = (mnode_t)node; // find which side of the node we are on mplane_t plane = n.plane; double dot; switch (plane.type) { case Planes.PLANE_X: dot = _ModelOrg.X - plane.dist; break; case Planes.PLANE_Y: dot = _ModelOrg.Y - plane.dist; break; case Planes.PLANE_Z: dot = _ModelOrg.Z - plane.dist; break; default: dot = Vector3.Dot(_ModelOrg, plane.normal) - plane.dist; break; } int side = (dot >= 0 ? 0 : 1); // recurse down the children, front side first RecursiveWorldNode(n.children[side]); // draw stuff c = n.numsurfaces; if (c != 0) { msurface_t[] surf = client.cl.worldmodel.surfaces; int offset = n.firstsurface; if (dot < 0 - QDef.BACKFACE_EPSILON) { side = Surf.SURF_PLANEBACK; } else if (dot > QDef.BACKFACE_EPSILON) { side = 0; } for ( ; c != 0; c--, offset++) { if (surf[offset].visframe != _FrameCount) { continue; } // don't backface underwater surfaces, because they warp if ((surf[offset].flags & Surf.SURF_UNDERWATER) == 0 && ((dot < 0) ^ ((surf[offset].flags & Surf.SURF_PLANEBACK) != 0))) { continue; // wrong side } // if sorting by texture, just store it out if (_glTexSort.Value != 0) { if (!_IsMirror || surf[offset].texinfo.texture != client.cl.worldmodel.textures[_MirrorTextureNum]) { surf[offset].texturechain = surf[offset].texinfo.texture.texturechain; surf[offset].texinfo.texture.texturechain = surf[offset]; } } else if ((surf[offset].flags & Surf.SURF_DRAWSKY) != 0) { surf[offset].texturechain = _SkyChain; _SkyChain = surf[offset]; } else if ((surf[offset].flags & Surf.SURF_DRAWTURB) != 0) { surf[offset].texturechain = _WaterChain; _WaterChain = surf[offset]; } else { DrawSequentialPoly(surf[offset]); } } } // recurse down the back side RecursiveWorldNode(n.children[side == 0 ? 1 : 0]); }
/// <summary> /// R_SplitEntityOnNode /// </summary> static void SplitEntityOnNode(mnodebase_t node) { if (node.contents == Contents.CONTENTS_SOLID) { return; } // add an efrag if the node is a leaf if (node.contents < 0) { if (_EfragTopNode == null) { _EfragTopNode = node as mnode_t; } mleaf_t leaf = (mleaf_t)(object)node; // grab an efrag off the free list EFrag ef = Client.Cl.free_efrags; if (ef == null) { Con.Print("Too many efrags!\n"); return; // no free fragments... } Client.Cl.free_efrags = Client.Cl.free_efrags.entnext; ef.entity = _AddEnt; // add the entity link // *lastlink = ef; if (_LastObj is Entity) { ((Entity)_LastObj).efrag = ef; } else { ((EFrag)_LastObj).entnext = ef; } _LastObj = ef; // lastlink = &ef->entnext; ef.entnext = null; // set the leaf links ef.leaf = leaf; ef.leafnext = leaf.efrags; leaf.efrags = ef; return; } // NODE_MIXED mnode_t n = node as mnode_t; if (n == null) { return; } mplane_t splitplane = n.plane; int sides = Mathlib.BoxOnPlaneSide(ref _EMins, ref _EMaxs, splitplane); if (sides == 3) { // split on this plane // if this is the first splitter of this bmodel, remember it if (_EfragTopNode == null) { _EfragTopNode = n; } } // recurse down the contacted sides if ((sides & 1) != 0) { SplitEntityOnNode(n.children[0]); } if ((sides & 2) != 0) { SplitEntityOnNode(n.children[1]); } }
/// <summary> /// R_NewMap /// </summary> public static void NewMap() { for (int i = 0; i < 256; i++) _LightStyleValue[i] = 264; // normal light value _WorldEntity.Clear(); _WorldEntity.model = Client.cl.worldmodel; // clear out efrags in case the level hasn't been reloaded // FIXME: is this one short? for (int i = 0; i < Client.cl.worldmodel.numleafs; i++) Client.cl.worldmodel.leafs[i].efrags = null; _ViewLeaf = null; ClearParticles(); BuildLightMaps(); // identify sky texture _SkyTextureNum = -1; _MirrorTextureNum = -1; model_t world = Client.cl.worldmodel; for (int i = 0; i < world.numtextures; i++) { if (world.textures[i] == null) continue; if (world.textures[i].name != null) { if (world.textures[i].name.StartsWith("sky")) _SkyTextureNum = i; if (world.textures[i].name.StartsWith("window02_1")) _MirrorTextureNum = i; } world.textures[i].texturechain = null; } }
/// <summary> /// R_SetupFrame /// </summary> static void SetupFrame() { // don't allow cheats in multiplayer if (Client.cl.maxclients > 1) Cvar.Set("r_fullbright", "0"); AnimateLight(); _FrameCount++; // build the transformation matrix for the given view angles Render.Origin = _RefDef.vieworg; Mathlib.AngleVectors(ref _RefDef.viewangles, out ViewPn, out ViewRight, out ViewUp); // current viewleaf _OldViewLeaf = _ViewLeaf; _ViewLeaf = Mod.PointInLeaf(ref Render.Origin, Client.cl.worldmodel); View.SetContentsColor(_ViewLeaf.contents); View.CalcBlend(); _CacheThrash = false; _BrushPolys = 0; _AliasPolys = 0; }
static int PF_newcheckclient(int check) { // cycle to the next one if (check < 1) { check = 1; } if (check > Server.svs.maxclients) { check = Server.svs.maxclients; } int i = check + 1; if (check == Server.svs.maxclients) { i = 1; } edict_t ent; for (; ; i++) { if (i == Server.svs.maxclients + 1) { i = 1; } ent = Server.EdictNum(i); if (i == check) { break; // didn't find anything else } if (ent.free) { continue; } if (ent.v.health <= 0) { continue; } if (((int)ent.v.flags & EdictFlags.FL_NOTARGET) != 0) { continue; } // anything that is a client, or has a client as an enemy break; } // get the PVS for the entity Vector3 org = Common.ToVector(ref ent.v.origin) + Common.ToVector(ref ent.v.view_ofs); mleaf_t leaf = Mod.PointInLeaf(ref org, Server.sv.worldmodel); byte[] pvs = Mod.LeafPVS(leaf, Server.sv.worldmodel); Buffer.BlockCopy(pvs, 0, _CheckPvs, 0, pvs.Length); return(i); }
/// <summary> /// Mod_LeafPVS /// </summary> public static byte[] LeafPVS(mleaf_t leaf, model_t model) { if (leaf == model.leafs[0]) return _Novis; return DecompressVis(leaf.compressed_vis, leaf.visofs, model); }
/// <summary> /// Mod_LoadLeafs /// </summary> static void LoadLeafs(ref lump_t l) { if ((l.filelen % dleaf_t.SizeInBytes) != 0) Sys.Error("MOD_LoadBmodel: funny lump size in {0}", _LoadModel.name); int count = l.filelen / dleaf_t.SizeInBytes; mleaf_t[] dest = new mleaf_t[count]; for (int i = 0; i < dest.Length; i++) dest[i] = new mleaf_t(); _LoadModel.leafs = dest; _LoadModel.numleafs = count; for (int i = 0, offset = l.fileofs; i < count; i++, offset += dleaf_t.SizeInBytes) { dleaf_t src = Sys.BytesToStructure<dleaf_t>(_ModBase, offset); dest[i].mins.X = Common.LittleShort(src.mins[0]); dest[i].mins.Y = Common.LittleShort(src.mins[1]); dest[i].mins.Z = Common.LittleShort(src.mins[2]); dest[i].maxs.X = Common.LittleShort(src.maxs[0]); dest[i].maxs.Y = Common.LittleShort(src.maxs[1]); dest[i].maxs.Z = Common.LittleShort(src.maxs[2]); int p = Common.LittleLong(src.contents); dest[i].contents = p; dest[i].marksurfaces = _LoadModel.marksurfaces; dest[i].firstmarksurface = Common.LittleShort((short)src.firstmarksurface); dest[i].nummarksurfaces = Common.LittleShort((short)src.nummarksurfaces); p = Common.LittleLong(src.visofs); if (p == -1) dest[i].compressed_vis = null; else { dest[i].compressed_vis = _LoadModel.visdata; // loadmodel->visdata + p; dest[i].visofs = p; } dest[i].efrags = null; for (int j = 0; j < 4; j++) dest[i].ambient_sound_level[j] = src.ambient_level[j]; // gl underwater warp // Uze: removed underwater warp as too ugly //if (dest[i].contents != Contents.CONTENTS_EMPTY) //{ // for (int j = 0; j < dest[i].nummarksurfaces; j++) // dest[i].marksurfaces[dest[i].firstmarksurface + j].flags |= Surf.SURF_UNDERWATER; //} } }