#pragma once #include "dZMCommon.h" #include "LDFFormat.h" #include "tinyxml2.h" #include #include #include namespace LUTriggers { struct Trigger; }; class Level; enum class eWaypointCommandType : uint32_t; struct WaypointCommand { eWaypointCommandType command{}; std::string data; }; struct SceneRef { std::string filename; uint32_t id{}; uint32_t sceneType{}; //0 = general, 1 = audio? std::string name; NiPoint3 unknown1; float unknown2{}; uint8_t color_r{}; uint8_t color_g{}; uint8_t color_b{}; Level* level; std::map triggers; }; struct SceneTransitionInfo { uint64_t sceneID{}; //id of the scene being transitioned to. NiPoint3 position; }; struct SceneTransition { std::string name; std::vector points; float width{}; }; struct MovingPlatformPathWaypoint { uint8_t lockPlayer{}; float wait{}; std::string departSound; std::string arriveSound; }; struct CameraPathWaypoint { float time{}; float fov{}; float tension{}; float continuity{}; float bias{}; }; struct RacingPathWaypoint { uint8_t isResetNode{}; uint8_t isNonHorizontalCamera{}; float planeWidth{}; float planeHeight{}; float shortestDistanceToEnd{}; }; struct PathWaypoint { NiPoint3 position; NiQuaternion rotation; // not included in all, but it's more convenient here MovingPlatformPathWaypoint movingPlatform; CameraPathWaypoint camera; RacingPathWaypoint racing; float speed{}; std::vector config; std::vector commands; }; enum class PathType : uint32_t { Movement = 0, MovingPlatform = 1, Property = 2, Camera = 3, Spawner = 4, Showcase = 5, Race = 6, Rail = 7 }; enum class PathBehavior : uint32_t { Loop = 0, Bounce = 1, Once = 2 }; enum class PropertyPathType : int32_t { Path = 0, EntireZone = 1, GenetatedRectangle = 2 }; enum class PropertyType : int32_t { Premiere = 0, Prize = 1, LUP = 2, Headspace = 3 }; enum class PropertyRentalPeriod : uint32_t { Forever = 0, Seconds = 1, Minutes = 2, Hours = 3, Days = 4, Weeks = 5, Months = 6, Years = 7 }; enum class PropertyAchievmentRequired : uint32_t { None = 0, Builder = 1, Craftsman = 2, SeniorBuilder = 3, JourneyMan = 4, MasterBuilder = 5, Architect = 6, SeniorArchitect = 7, MasterArchitect = 8, Visionary = 9, Exemplar = 10 }; struct MovingPlatformPath { std::string platformTravelSound; uint8_t timeBasedMovement{}; }; struct PropertyPath { PropertyPathType pathType{}; int32_t price{}; uint32_t rentalTime{}; uint64_t associatedZone{}; std::string displayName; std::string displayDesc; PropertyType type{}; uint32_t cloneLimit{}; float repMultiplier{}; PropertyRentalPeriod rentalPeriod{}; PropertyAchievmentRequired achievementRequired{}; // Player respawn coordinates in the main zone (not the property zone) NiPoint3 playerZoneCoords; float maxBuildHeight{}; }; struct CameraPath { std::string nextPath; uint8_t rotatePlayer{}; }; struct SpawnerPath { LOT spawnedLOT{}; uint32_t respawnTime{}; int32_t maxToSpawn{}; uint32_t amountMaintained{}; LWOOBJID spawnerObjID; uint8_t spawnerNetActive{}; }; struct Path { uint32_t pathVersion{}; PathType pathType; std::string pathName; uint32_t flags{}; PathBehavior pathBehavior; uint32_t waypointCount{}; std::vector pathWaypoints; SpawnerPath spawner; MovingPlatformPath movingPlatform; PropertyPath property; CameraPath camera; }; class Zone { public: enum class FileFormatVersion : uint32_t { //Times are guessed. PrePreAlpha = 30, PreAlpha = 32, LatePreAlpha = 33, EarlyAlpha = 35, Alpha = 36, LateAlpha = 37, Beta = 38, Launch = 39, Auramar = 40, Latest = 41 }; public: Zone(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID); ~Zone(); void Initalize(); void LoadZoneIntoMemory(); std::string GetFilePathForZoneID(); uint32_t CalculateChecksum(); void LoadLevelsIntoMemory(); void AddRevision(LWOSCENEID sceneID, uint32_t revision); const LWOZONEID& GetZoneID() const { return m_ZoneID; } const uint32_t GetChecksum() const { return m_CheckSum; } LUTriggers::Trigger* GetTrigger(uint32_t sceneID, uint32_t triggerID); const Path* GetPath(std::string name) const; uint32_t GetWorldID() const { return m_WorldID; } [[nodiscard]] std::string GetZoneName() const { return m_ZoneName; } std::string GetZoneRawPath() const { return m_ZoneRawPath; } std::string GetZonePath() const { return m_ZonePath; } const NiPoint3& GetSpawnPos() const { return m_Spawnpoint; } const NiQuaternion& GetSpawnRot() const { return m_SpawnpointRotation; } void SetSpawnPos(const NiPoint3& pos) { m_Spawnpoint = pos; } void SetSpawnRot(const NiQuaternion& rot) { m_SpawnpointRotation = rot; } private: LWOZONEID m_ZoneID; std::string m_ZoneFilePath; uint32_t m_NumberOfObjectsLoaded; uint32_t m_NumberOfSceneTransitionsLoaded; FileFormatVersion m_FileFormatVersion; uint32_t m_CheckSum; uint32_t m_WorldID; //should be equal to the MapID NiPoint3 m_Spawnpoint; NiQuaternion m_SpawnpointRotation; uint32_t m_SceneCount; std::string m_ZonePath; //Path to the .luz's folder std::string m_ZoneName; //Name given to the zone by a level designer std::string m_ZoneDesc; //Description of the zone by a level designer std::string m_ZoneRawPath; //Path to the .raw file of this zone. std::map m_Scenes; std::vector m_SceneTransitions; uint32_t m_PathDataLength; uint32_t m_PathChunkVersion; std::vector m_Paths; std::map m_MapRevisions; //rhs is the revision! //private ("helper") functions: void LoadScene(std::istream& file); void LoadLUTriggers(std::string triggerFile, SceneRef& scene); void LoadSceneTransition(std::istream& file); SceneTransitionInfo LoadSceneTransitionInfo(std::istream& file); void LoadPath(std::istream& file); };