/* ** g_levellocals.h ** The static data for a level ** **--------------------------------------------------------------------------- ** Copyright 1998-2016 Randy Heit ** Copyright 2005-2017 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions ** are met: ** ** 1. Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **--------------------------------------------------------------------------- ** */ #pragma once #include "doomdata.h" #include "g_level.h" #include "r_defs.h" #include "r_sky.h" #include "portal.h" #include "p_blockmap.h" #include "p_local.h" #include "po_man.h" #include "p_acs.h" #include "p_tags.h" #include "actor.h" #include "p_destructible.h" #include "r_data/r_sections.h" #include "r_data/r_canvastexture.h" class DACSThinker; class DFraggleThinker; class DSpotState; struct FLevelData { TArray vertexes; TArray sectors; TArray linebuffer; // contains the line lists for the sectors. TArray subsectorbuffer; // contains the subsector lists for the sectors. TArray lines; TArray sides; TArray segbuffer; // contains the seg links for the sidedefs. TArray segs; TArray subsectors; TArray nodes; TArray gamesubsectors; TArray gamenodes; node_t *headgamenode; TArray rejectmatrix; TArray Zones; TArray Polyobjects; TArray sectorPortals; TArray linePortals; // Portal information. FDisplacementTable Displacements; FPortalBlockmap PortalBlockmap; TArray linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups. TArray portalGroups; TArray linePortalSpans; FSectionContainer sections; FCanvasTextureInfo canvasTextureInfo; // [ZZ] Destructible geometry information TMap healthGroups; FBlockmap blockmap; TArray PolyBlockMap; // These are copies of the loaded map data that get used by the savegame code to skip unaltered fields // Without such a mechanism the savegame format would become too slow and large because more than 80-90% are normally still unaltered. TArray loadsectors; TArray loadlines; TArray loadsides; // Maintain single and multi player starting spots. TArray deathmatchstarts; FPlayerStart playerstarts[MAXPLAYERS]; TArray AllPlayerStarts; FBehaviorContainer Behaviors; }; struct FLevelLocals : public FLevelData { void Tick(); void Mark(); void AddScroller(int secnum); void SetInterMusic(const char *nextmap); void SetMusicVolume(float v); void ClearLevelData(); void ClearPortals(); bool CheckIfExitIsGood(AActor *self, level_info_t *newmap); void FormatMapName(FString &mapname, const char *mapnamecolor); void ClearAllSubsectorLinks(); void TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineindexforid = -1); FSectorTagIterator GetSectorTagIterator(int tag) { return FSectorTagIterator(tag); } FSectorTagIterator GetSectorTagIterator(int tag, line_t *line) { return FSectorTagIterator(tag, line); } FLineIdIterator GetLineIdIterator(int tag) { return FLineIdIterator(tag); } template TThinkerIterator GetThinkerIterator(FName subtype = NAME_None) { if (subtype == NAME_None) return TThinkerIterator(); else return TThinkerIterator(subtype); } FActorIterator GetActorIterator(int tid) { return FActorIterator(tid); } NActorIterator GetActorIterator(FName type, int tid) { return NActorIterator(type, tid); } bool SectorHasTags(sector_t *sector) { return tagManager.SectorHasTags(sector); } bool SectorHasTag(sector_t *sector, int tag) { return tagManager.SectorHasTag(sector, tag); } bool SectorHasTag(int sector, int tag) { return tagManager.SectorHasTag(sector, tag); } int GetFirstSectorTag(const sector_t *sect) const { return tagManager.GetFirstSectorTag(sect); } int GetFirstSectorTag(int i) const { return tagManager.GetFirstSectorTag(i); } int GetFirstLineId(const line_t *sect) const { return tagManager.GetFirstLineID(sect); } bool LineHasId(int line, int tag) { return tagManager.LineHasID(line, tag); } bool LineHasId(line_t *line, int tag) { return tagManager.LineHasID(line, tag); } int FindFirstSectorFromTag(int tag) { auto it = GetSectorTagIterator(tag); return it.Next(); } int FindFirstLineFromID(int tag) { auto it = GetLineIdIterator(tag); return it.Next(); } sector_t *PointInSector(const DVector2 &pos) { return P_PointInSector(pos); } FPolyObj *GetPolyobj (int polyNum) { auto index = Polyobjects.FindEx([=](const auto &poly) { return poly.tag == polyNum; }); return index == Polyobjects.Size()? nullptr : &Polyobjects[index]; } uint8_t md5[16]; // for savegame validation. If the MD5 does not match the savegame won't be loaded. int time; // time in the hub int maptime; // time in the map int totaltime; // time in the game int starttime; int partime; int sucktime; uint32_t spawnindex; level_info_t *info; int cluster; int clusterflags; int levelnum; int lumpnum; FString LevelName; FString MapName; // the lump name (E1M1, MAP01, etc) FString NextMap; // go here when using the regular exit FString NextSecretMap; // map to go to when used secret exit FString F1Pic; EMapType maptype; uint64_t ShaderStartTime = 0; // tell the shader system when we started the level (forces a timer restart) static const int BODYQUESIZE = 32; TObjPtr bodyque[BODYQUESIZE]; int bodyqueslot; int NumMapSections; uint32_t flags; uint32_t flags2; uint32_t flags3; uint32_t fadeto; // The color the palette fades to (usually black) uint32_t outsidefog; // The fog for sectors with sky ceilings uint32_t hazardcolor; // what color strife hazard blends the screen color as uint32_t hazardflash; // what color strife hazard flashes the screen color as FString Music; int musicorder; int cdtrack; unsigned int cdid; FTextureID skytexture1; FTextureID skytexture2; float skyspeed1; // Scrolling speed of sky textures, in pixels per ms float skyspeed2; int total_secrets; int found_secrets; int total_items; int found_items; int total_monsters; int killed_monsters; double gravity; double aircontrol; double airfriction; int airsupply; int DefaultEnvironment; // Default sound environment. TArray Scrolls; // NULL if no DScrollers in this level int8_t WallVertLight; // Light diffs for vert/horiz walls int8_t WallHorizLight; bool FromSnapshot; // The current map was restored from a snapshot bool HasHeightSecs; // true if some Transfer_Heights effects are present in the map. If this is false, some checks in the renderer can be shortcut. bool HasDynamicLights; // Another render optimization for maps with no lights at all. double teamdamage; // former OpenGL-exclusive properties that should also be usable by the true color software renderer. int fogdensity; int outsidefogdensity; int skyfog; FName deathsequence; float pixelstretch; float MusicVolume; // Hardware render stuff that can either be set via CVAR or MAPINFO ELightMode lightMode; bool brightfog; bool lightadditivesurfaces; bool notexturefill; int ImpactDecalCount; FDynamicLight *lights; // links to global game objects TArray> CorpseQueue; TObjPtr FraggleScriptThinker = nullptr; TObjPtr ACSThinker = nullptr; TObjPtr SpotState = nullptr; bool IsJumpingAllowed() const; bool IsCrouchingAllowed() const; bool IsFreelookAllowed() const; node_t *HeadNode() const { return nodes.Size() == 0 ? nullptr : &nodes[nodes.Size() - 1]; } node_t *HeadGamenode() const { return headgamenode; } // Returns true if level is loaded from saved game or is being revisited as a part of a hub bool IsReentering() const { return savegamerestore || (info != nullptr && info->Snapshot.mBuffer != nullptr && info->isValid()); } }; #ifndef NO_DEFINE_LEVEL extern FLevelLocals level; inline FSectorPortal *line_t::GetTransferredPortal() { return portaltransferred >= level.sectorPortals.Size() ? (FSectorPortal*)nullptr : &level.sectorPortals[portaltransferred]; } inline FSectorPortal *sector_t::GetPortal(int plane) { return &level.sectorPortals[Portals[plane]]; } inline double sector_t::GetPortalPlaneZ(int plane) { return level.sectorPortals[Portals[plane]].mPlaneZ; } inline DVector2 sector_t::GetPortalDisplacement(int plane) { return level.sectorPortals[Portals[plane]].mDisplacement; } inline int sector_t::GetPortalType(int plane) { return level.sectorPortals[Portals[plane]].mType; } inline int sector_t::GetOppositePortalGroup(int plane) { return level.sectorPortals[Portals[plane]].mDestination->PortalGroup; } inline bool sector_t::PortalBlocksView(int plane) { if (GetPortalType(plane) != PORTS_LINKEDPORTAL) return false; return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); } inline bool sector_t::PortalBlocksSight(int plane) { return PLANEF_LINKED != (planes[plane].Flags & (PLANEF_NORENDER | PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED | PLANEF_LINKED)); } inline bool sector_t::PortalBlocksMovement(int plane) { return PLANEF_LINKED != (planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED | PLANEF_LINKED)); } inline bool sector_t::PortalBlocksSound(int plane) { return PLANEF_LINKED != (planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED | PLANEF_LINKED)); } inline bool sector_t::PortalIsLinked(int plane) { return (GetPortalType(plane) == PORTS_LINKEDPORTAL); } inline FLinePortal *line_t::getPortal() const { return portalindex >= level.linePortals.Size() ? (FLinePortal*)NULL : &level.linePortals[portalindex]; } // returns true if the portal is crossable by actors inline bool line_t::isLinePortal() const { return portalindex >= level.linePortals.Size() ? false : !!(level.linePortals[portalindex].mFlags & PORTF_PASSABLE); } // returns true if the portal needs to be handled by the renderer inline bool line_t::isVisualPortal() const { return portalindex >= level.linePortals.Size() ? false : !!(level.linePortals[portalindex].mFlags & PORTF_VISIBLE); } inline line_t *line_t::getPortalDestination() const { return portalindex >= level.linePortals.Size() ? (line_t*)NULL : level.linePortals[portalindex].mDestination; } inline int line_t::getPortalAlignment() const { return portalindex >= level.linePortals.Size() ? 0 : level.linePortals[portalindex].mAlign; } inline bool line_t::hitSkyWall(AActor* mo) const { return backsector && backsector->GetTexture(sector_t::ceiling) == skyflatnum && mo->Z() >= backsector->ceilingplane.ZatPoint(mo->PosRelative(this)); } #endif