/***************************************************************************** * Copyright (c) 2014-2023 OpenRCT2 developers * * For a complete list of all authors, please refer to contributors.md * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ #pragma once #include "../Identifiers.h" #include "../common.h" #include "../ride/RideTypes.h" #include "../ride/Station.h" #include "Banner.h" #include "Footpath.h" #include "tile_element/TileElementType.h" struct Banner; struct CoordsXY; struct LargeSceneryEntry; struct SmallSceneryEntry; struct WallSceneryEntry; struct PathBitEntry; struct BannerSceneryEntry; struct FootpathEntry; class LargeSceneryObject; class TerrainSurfaceObject; class TerrainEdgeObject; class FootpathObject; class FootpathSurfaceObject; class FootpathRailingsObject; using track_type_t = uint16_t; constexpr const uint8_t MAX_ELEMENT_HEIGHT = 255; constexpr const uint8_t OWNER_MASK = 0b00001111; #pragma pack(push, 1) struct TileElement; struct SurfaceElement; struct PathElement; struct TrackElement; struct SmallSceneryElement; struct LargeSceneryElement; struct WallElement; struct EntranceElement; struct BannerElement; struct TileElementBase { uint8_t Type; // 0 uint8_t Flags; // 1. Upper nibble: flags. Lower nibble: occupied quadrants (one bit per quadrant). uint8_t BaseHeight; // 2 uint8_t ClearanceHeight; // 3 uint8_t Owner; // 4 void Remove(); TileElementType GetType() const; void SetType(TileElementType newType); Direction GetDirection() const; void SetDirection(Direction direction); Direction GetDirectionWithOffset(uint8_t offset) const; bool IsLastForTile() const; void SetLastForTile(bool on); bool IsGhost() const; void SetGhost(bool isGhost); bool IsInvisible() const; void SetInvisible(bool on); uint8_t GetOccupiedQuadrants() const; void SetOccupiedQuadrants(uint8_t quadrants); int32_t GetBaseZ() const; void SetBaseZ(int32_t newZ); int32_t GetClearanceZ() const; void SetClearanceZ(int32_t newZ); uint8_t GetOwner() const; void SetOwner(uint8_t newOwner); template const TType* as() const { if constexpr (std::is_same_v) return reinterpret_cast(this); else return GetType() == TType::ElementType ? reinterpret_cast(this) : nullptr; } template TType* as() { if constexpr (std::is_same_v) return reinterpret_cast(this); else return GetType() == TType::ElementType ? reinterpret_cast(this) : nullptr; } const SurfaceElement* AsSurface() const { return as(); } SurfaceElement* AsSurface() { return as(); } const PathElement* AsPath() const { return as(); } PathElement* AsPath() { return as(); } const TrackElement* AsTrack() const { return as(); } TrackElement* AsTrack() { return as(); } const SmallSceneryElement* AsSmallScenery() const { return as(); } SmallSceneryElement* AsSmallScenery() { return as(); } const LargeSceneryElement* AsLargeScenery() const { return as(); } LargeSceneryElement* AsLargeScenery() { return as(); } const WallElement* AsWall() const { return as(); } WallElement* AsWall() { return as(); } const EntranceElement* AsEntrance() const { return as(); } EntranceElement* AsEntrance() { return as(); } const BannerElement* AsBanner() const { return as(); } BannerElement* AsBanner() { return as(); } }; /** * Map element structure * size: 0x10 */ struct TileElement : public TileElementBase { uint8_t Pad05[3]; uint8_t Pad08[8]; void ClearAs(TileElementType newType); RideId GetRideIndex() const; void SetBannerIndex(BannerIndex newIndex); void RemoveBannerEntry(); BannerIndex GetBannerIndex() const; }; assert_struct_size(TileElement, 16); struct SurfaceElement : TileElementBase { static constexpr TileElementType ElementType = TileElementType::Surface; private: uint8_t Slope; uint8_t WaterHeight; uint8_t GrassLength; uint8_t Ownership; uint8_t SurfaceStyle; uint8_t EdgeStyle; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" uint8_t Pad0B[5]; #pragma clang diagnostic pop public: uint8_t GetSlope() const; void SetSlope(uint8_t newSlope); uint32_t GetSurfaceStyle() const; TerrainSurfaceObject* GetSurfaceStyleObject() const; void SetSurfaceStyle(uint32_t newStyle); uint32_t GetEdgeStyle() const; TerrainEdgeObject* GetEdgeStyleObject() const; void SetEdgeStyle(uint32_t newStyle); bool CanGrassGrow() const; uint8_t GetGrassLength() const; void SetGrassLength(uint8_t newLength); void SetGrassLengthAndInvalidate(uint8_t newLength, const CoordsXY& coords); void UpdateGrassLength(const CoordsXY& coords); uint8_t GetOwnership() const; void SetOwnership(uint8_t newOwnership); int32_t GetWaterHeight() const; void SetWaterHeight(int32_t newWaterHeight); uint8_t GetParkFences() const; void SetParkFences(uint8_t newParkFences); bool HasTrackThatNeedsWater() const; void SetHasTrackThatNeedsWater(bool on); }; assert_struct_size(SurfaceElement, 16); struct PathElement : TileElementBase { static constexpr TileElementType ElementType = TileElementType::Path; private: ObjectEntryIndex SurfaceIndex; // 5 ObjectEntryIndex RailingsIndex; // 7 uint8_t Additions; // 9 (0 means no addition) uint8_t EdgesAndCorners; // 10 (edges in lower 4 bits, corners in upper 4) uint8_t Flags2; // 11 uint8_t SlopeDirection; // 12 union { uint8_t AdditionStatus; // 13, only used for litter bins RideId rideIndex; // 13 }; ::StationIndex StationIndex; // 15 public: ObjectEntryIndex GetLegacyPathEntryIndex() const; const FootpathObject* GetLegacyPathEntry() const; void SetLegacyPathEntryIndex(ObjectEntryIndex newIndex); bool HasLegacyPathEntry() const; ObjectEntryIndex GetSurfaceEntryIndex() const; const FootpathSurfaceObject* GetSurfaceEntry() const; void SetSurfaceEntryIndex(ObjectEntryIndex newIndex); ObjectEntryIndex GetRailingsEntryIndex() const; const FootpathRailingsObject* GetRailingsEntry() const; void SetRailingsEntryIndex(ObjectEntryIndex newIndex); const PathSurfaceDescriptor* GetSurfaceDescriptor() const; const PathRailingsDescriptor* GetRailingsDescriptor() const; uint8_t GetQueueBannerDirection() const; void SetQueueBannerDirection(uint8_t direction); bool IsSloped() const; void SetSloped(bool isSloped); bool HasJunctionRailings() const; void SetJunctionRailings(bool hasJunctionRailings); Direction GetSlopeDirection() const; void SetSlopeDirection(Direction newSlope); RideId GetRideIndex() const; void SetRideIndex(RideId newRideIndex); ::StationIndex GetStationIndex() const; void SetStationIndex(::StationIndex newStationIndex); bool IsWide() const; void SetWide(bool isWide); bool IsQueue() const; void SetIsQueue(bool isQueue); bool HasQueueBanner() const; void SetHasQueueBanner(bool hasQueueBanner); bool IsBroken() const; void SetIsBroken(bool isBroken); bool IsBlockedByVehicle() const; void SetIsBlockedByVehicle(bool isBlocked); uint8_t GetEdges() const; void SetEdges(uint8_t newEdges); uint8_t GetCorners() const; void SetCorners(uint8_t newCorners); uint8_t GetEdgesAndCorners() const; void SetEdgesAndCorners(uint8_t newEdgesAndCorners); bool HasAddition() const; uint8_t GetAddition() const; ObjectEntryIndex GetAdditionEntryIndex() const; const PathBitEntry* GetAdditionEntry() const; void SetAddition(uint8_t newAddition); bool AdditionIsGhost() const; void SetAdditionIsGhost(bool isGhost); uint8_t GetAdditionStatus() const; void SetAdditionStatus(uint8_t newStatus); bool ShouldDrawPathOverSupports() const; void SetShouldDrawPathOverSupports(bool on); bool IsLevelCrossing(const CoordsXY& coords) const; }; assert_struct_size(PathElement, 16); struct TrackElement : TileElementBase { static constexpr TileElementType ElementType = TileElementType::Track; private: track_type_t TrackType; union { struct { uint8_t Sequence; uint8_t ColourScheme; union { // - Bits 3 and 4 are never set // - Bits 1 and 2 are set when a vehicle triggers the on-ride photo and act like a countdown from 3. // - If any of the bits 1-4 are set, the game counts it as a photo being taken. uint8_t OnridePhotoBits; // Contains the brake/booster speed, divided by 2. uint8_t BrakeBoosterSpeed; }; StationIndex stationIndex; } URide; struct { uint16_t MazeEntry; // 6 } UMaze; }; uint8_t Flags2; RideId RideIndex; ride_type_t RideType; public: track_type_t GetTrackType() const; void SetTrackType(track_type_t newEntryIndex); ride_type_t GetRideType() const; void SetRideType(const ride_type_t rideType); uint8_t GetSequenceIndex() const; void SetSequenceIndex(uint8_t newSequenceIndex); RideId GetRideIndex() const; void SetRideIndex(RideId newRideIndex); uint8_t GetColourScheme() const; void SetColourScheme(uint8_t newColourScheme); StationIndex GetStationIndex() const; void SetStationIndex(StationIndex newStationIndex); bool HasChain() const; void SetHasChain(bool on); bool HasCableLift() const; void SetHasCableLift(bool on); bool IsInverted() const; void SetInverted(bool inverted); bool IsBrakeClosed() const; void SetBrakeClosed(bool isClosed); bool IsIndestructible() const; void SetIsIndestructible(bool isIndestructible); uint8_t GetBrakeBoosterSpeed() const; void SetBrakeBoosterSpeed(uint8_t speed); bool HasGreenLight() const; void SetHasGreenLight(bool on); uint8_t GetSeatRotation() const; void SetSeatRotation(uint8_t newSeatRotation); uint16_t GetMazeEntry() const; void SetMazeEntry(uint16_t newMazeEntry); void MazeEntryAdd(uint16_t addVal); void MazeEntrySubtract(uint16_t subVal); bool IsTakingPhoto() const; void SetPhotoTimeout(); void SetPhotoTimeout(uint8_t newValue); void DecrementPhotoTimeout(); uint8_t GetPhotoTimeout() const; bool IsHighlighted() const; void SetHighlight(bool on); // Used by ghost train, RCT1 feature, will be reintroduced at some point. // (See https://github.com/OpenRCT2/OpenRCT2/issues/7059) uint8_t GetDoorAState() const; uint8_t GetDoorBState() const; void SetDoorAState(uint8_t newState); void SetDoorBState(uint8_t newState); bool IsStation() const; bool IsBlockStart() const; }; assert_struct_size(TrackElement, 16); struct SmallSceneryElement : TileElementBase { static constexpr TileElementType ElementType = TileElementType::SmallScenery; private: ObjectEntryIndex entryIndex; // 5 uint8_t age; // 7 uint8_t Colour[3]; // 8 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" uint8_t Pad0B[5]; #pragma clang diagnostic pop public: ObjectEntryIndex GetEntryIndex() const; void SetEntryIndex(ObjectEntryIndex newIndex); const SmallSceneryEntry* GetEntry() const; uint8_t GetAge() const; void SetAge(uint8_t newAge); void IncreaseAge(const CoordsXY& sceneryPos); uint8_t GetSceneryQuadrant() const; void SetSceneryQuadrant(uint8_t newQuadrant); colour_t GetPrimaryColour() const; void SetPrimaryColour(colour_t colour); colour_t GetSecondaryColour() const; void SetSecondaryColour(colour_t colour); colour_t GetTertiaryColour() const; void SetTertiaryColour(colour_t colour); bool NeedsSupports() const; void SetNeedsSupports(); void UpdateAge(const CoordsXY& sceneryPos); }; assert_struct_size(SmallSceneryElement, 16); struct LargeSceneryElement : TileElementBase { static constexpr TileElementType ElementType = TileElementType::LargeScenery; private: ObjectEntryIndex EntryIndex; ::BannerIndex BannerIndex; uint8_t SequenceIndex; uint8_t Colour[3]; uint8_t Flags2; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" uint8_t pad[2]; #pragma clang diagnostic pop public: ObjectEntryIndex GetEntryIndex() const; void SetEntryIndex(ObjectEntryIndex newIndex); const LargeSceneryEntry* GetEntry() const; const LargeSceneryObject* GetObject() const; uint8_t GetSequenceIndex() const; void SetSequenceIndex(uint8_t newIndex); colour_t GetPrimaryColour() const; void SetPrimaryColour(colour_t colour); colour_t GetSecondaryColour() const; void SetSecondaryColour(colour_t colour); colour_t GetTertiaryColour() const; void SetTertiaryColour(colour_t colour); Banner* GetBanner() const; ::BannerIndex GetBannerIndex() const; void SetBannerIndex(::BannerIndex newIndex); bool IsAccounted() const; void SetIsAccounted(bool isAccounted); }; assert_struct_size(LargeSceneryElement, 16); struct WallElement : TileElementBase { static constexpr TileElementType ElementType = TileElementType::Wall; private: ObjectEntryIndex entryIndex; // 05 colour_t colour_1; // 07 colour_t colour_2; // 08 colour_t colour_3; // 09 BannerIndex banner_index; // 0A uint8_t animation; // 0C 0b_dfff_ft00 d = direction, f = frame num, t = across track flag (not used) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" uint8_t Pad0D[3]; #pragma clang diagnostic pop public: uint16_t GetEntryIndex() const; void SetEntryIndex(uint16_t newIndex); const WallSceneryEntry* GetEntry() const; uint8_t GetSlope() const; void SetSlope(uint8_t newslope); colour_t GetPrimaryColour() const; void SetPrimaryColour(colour_t newColour); colour_t GetSecondaryColour() const; void SetSecondaryColour(colour_t newColour); colour_t GetTertiaryColour() const; void SetTertiaryColour(colour_t newColour); uint8_t GetAnimationFrame() const; void SetAnimationFrame(uint8_t frameNum); Banner* GetBanner() const; BannerIndex GetBannerIndex() const; void SetBannerIndex(BannerIndex newIndex); bool IsAcrossTrack() const; void SetAcrossTrack(bool acrossTrack); bool AnimationIsBackwards() const; void SetAnimationIsBackwards(bool isBackwards); }; assert_struct_size(WallElement, 16); struct EntranceElement : TileElementBase { static constexpr TileElementType ElementType = TileElementType::Entrance; private: uint8_t entranceType; // 5 uint8_t SequenceIndex; // 6. Only uses the lower nibble. StationIndex stationIndex; // 7 ObjectEntryIndex PathType; // 8 RideId rideIndex; // A uint8_t flags2; // C #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" uint8_t Pad0D[3]; #pragma clang diagnostic pop public: uint8_t GetEntranceType() const; void SetEntranceType(uint8_t newType); RideId GetRideIndex() const; void SetRideIndex(RideId newRideIndex); StationIndex GetStationIndex() const; void SetStationIndex(StationIndex newStationIndex); uint8_t GetSequenceIndex() const; void SetSequenceIndex(uint8_t newSequenceIndex); bool HasLegacyPathEntry() const; ObjectEntryIndex GetLegacyPathEntryIndex() const; const FootpathObject* GetLegacyPathEntry() const; void SetLegacyPathEntryIndex(ObjectEntryIndex newPathType); ObjectEntryIndex GetSurfaceEntryIndex() const; const FootpathSurfaceObject* GetSurfaceEntry() const; void SetSurfaceEntryIndex(ObjectEntryIndex newIndex); const PathSurfaceDescriptor* GetPathSurfaceDescriptor() const; int32_t GetDirections() const; }; assert_struct_size(EntranceElement, 16); struct BannerElement : TileElementBase { static constexpr TileElementType ElementType = TileElementType::Banner; private: BannerIndex index; // 5 uint8_t position; // 7 uint8_t AllowedEdges; // 8 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" uint8_t Pad09[7]; #pragma clang diagnostic pop public: Banner* GetBanner() const; const BannerSceneryEntry* GetEntry() const; BannerIndex GetIndex() const; void SetIndex(BannerIndex newIndex); uint8_t GetPosition() const; void SetPosition(uint8_t newPosition); uint8_t GetAllowedEdges() const; void SetAllowedEdges(uint8_t newEdges); void ResetAllowedEdges(); }; assert_struct_size(BannerElement, 16); #pragma pack(pop) class QuarterTile { private: uint8_t _val{ 0 }; public: constexpr QuarterTile(uint8_t tileQuarter, uint8_t zQuarter) : _val(tileQuarter | (zQuarter << 4)) { } QuarterTile(uint8_t tileAndZQuarter) : _val(tileAndZQuarter) { } // Rotate both of the values amount. Returns new RValue QuarterTile const QuarterTile Rotate(uint8_t amount) const; uint8_t GetBaseQuarterOccupied() const { return _val & 0xF; } uint8_t GetZQuarterOccupied() const { return (_val >> 4) & 0xF; } }; enum { TILE_ELEMENT_QUADRANT_SW, TILE_ELEMENT_QUADRANT_NW, TILE_ELEMENT_QUADRANT_NE, TILE_ELEMENT_QUADRANT_SE }; enum { SURFACE_ELEMENT_HAS_TRACK_THAT_NEEDS_WATER = (1 << 6), }; enum { TILE_ELEMENT_DIRECTION_WEST, TILE_ELEMENT_DIRECTION_NORTH, TILE_ELEMENT_DIRECTION_EAST, TILE_ELEMENT_DIRECTION_SOUTH }; enum { TILE_ELEMENT_FLAG_GHOST = (1 << 4), TILE_ELEMENT_FLAG_INVISIBLE = (1 << 5), TILE_ELEMENT_FLAG_LAST_TILE = (1 << 7) }; enum { ENTRANCE_TYPE_RIDE_ENTRANCE, ENTRANCE_TYPE_RIDE_EXIT, ENTRANCE_TYPE_PARK_ENTRANCE }; enum { ELEMENT_IS_ABOVE_GROUND = 1 << 0, ELEMENT_IS_UNDERGROUND = 1 << 1, ELEMENT_IS_UNDERWATER = 1 << 2, }; enum { MAP_ELEM_TRACK_SEQUENCE_GREEN_LIGHT = (1 << 7), }; #define TILE_ELEMENT_QUADRANT_MASK 0b11000000 #define TILE_ELEMENT_TYPE_MASK 0b00111100 #define TILE_ELEMENT_DIRECTION_MASK 0b00000011 #define TILE_ELEMENT_OCCUPIED_QUADRANTS_MASK 0b00001111 #define TILE_ELEMENT_COLOUR_MASK 0b00011111 enum { LANDSCAPE_DOOR_CLOSED = 0, LANDSCAPE_DOOR_HALF_OPEN = 2, LANDSCAPE_DOOR_OPEN = 3, }; bool TileElementIsUnderground(TileElement* tileElement);