diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index e8274e0f26..8a7fe162b9 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 4C29DEB3218C6AE500E8707F /* RCT12.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C29DEB2218C6AE500E8707F /* RCT12.cpp */; }; 4C3B4236205914F7000C5BB7 /* InGameConsole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C3B4234205914F7000C5BB7 /* InGameConsole.cpp */; }; 4C93F1AD1F8CD9F000A9330D /* Input.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C93F1AC1F8CD9F000A9330D /* Input.cpp */; }; 4C93F1AF1F8CD9F600A9330D /* KeyboardShortcut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C93F1AE1F8CD9F600A9330D /* KeyboardShortcut.cpp */; }; @@ -607,6 +608,7 @@ /* Begin PBXFileReference section */ 4C04D69F2056AA9600F82EBA /* linenoise.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = linenoise.hpp; sourceTree = ""; }; 4C1A53EC205FD19F000F8EF5 /* SceneryObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneryObject.cpp; sourceTree = ""; }; + 4C29DEB2218C6AE500E8707F /* RCT12.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RCT12.cpp; sourceTree = ""; }; 4C3B4234205914F7000C5BB7 /* InGameConsole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InGameConsole.cpp; sourceTree = ""; }; 4C3B4235205914F7000C5BB7 /* InGameConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InGameConsole.h; sourceTree = ""; }; 4C3B423720591513000C5BB7 /* StdInOutConsole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StdInOutConsole.cpp; sourceTree = ""; }; @@ -2751,6 +2753,7 @@ F76C846C1EC4E7CC00FA49E2 /* rct12 */ = { isa = PBXGroup; children = ( + 4C29DEB2218C6AE500E8707F /* RCT12.cpp */, 4C7B54032004C57B00A52E21 /* RCT12.h */, F76C846D1EC4E7CC00FA49E2 /* SawyerChunk.cpp */, F76C846E1EC4E7CC00FA49E2 /* SawyerChunk.h */, @@ -3641,6 +3644,7 @@ C64644FB1F3FA4120026AC2D /* EditorScenarioOptions.cpp in Sources */, C654DF321F69C0430040F43D /* InstallTrack.cpp in Sources */, C64644FF1F3FA4120026AC2D /* StaffList.cpp in Sources */, + 4C29DEB3218C6AE500E8707F /* RCT12.cpp in Sources */, C6D2BEE81F9BAACE008B557C /* MazeConstruction.cpp in Sources */, C666EE771F37ACB10061AA04 /* SavePrompt.cpp in Sources */, C654DF391F69C0430040F43D /* TitleCommandEditor.cpp in Sources */, diff --git a/src/openrct2/rct12/RCT12.cpp b/src/openrct2/rct12/RCT12.cpp new file mode 100644 index 0000000000..2a330c65d8 --- /dev/null +++ b/src/openrct2/rct12/RCT12.cpp @@ -0,0 +1,32 @@ +/***************************************************************************** + * Copyright (c) 2014-2018 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. + *****************************************************************************/ + +#include "RCT12.h" + +#include "../world/TileElement.h" + +uint8_t RCT12TileElementBase::GetType() const +{ + return this->type & TILE_ELEMENT_TYPE_MASK; +} + +uint8_t RCT12TileElementBase::GetDirection() const +{ + return this->type & TILE_ELEMENT_DIRECTION_MASK; +} + +bool RCT12TileElementBase::IsLastForTile() const +{ + return (this->flags & TILE_ELEMENT_FLAG_LAST_TILE) != 0; +} + +bool RCT12TileElementBase::IsGhost() const +{ + return (this->flags & TILE_ELEMENT_FLAG_GHOST) != 0; +} diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index 63a1068203..44058bcac5 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -12,6 +12,7 @@ // Structures shared between both RCT1 and RCT2. #include "../common.h" +#include "../world/Location.hpp" #define RCT12_MAX_RIDES_IN_PARK 255 #define RCT12_MAX_AWARDS 4 @@ -77,4 +78,296 @@ struct rct12_peep_spawn }; assert_struct_size(rct12_peep_spawn, 6); +enum class RCT12TileElementType : uint8_t +{ + Surface = (0 << 2), + Path = (1 << 2), + Track = (2 << 2), + SmallScenery = (3 << 2), + Entrance = (4 << 2), + Wall = (5 << 2), + LargeScenery = (6 << 2), + Banner = (7 << 2), + Corrupt = (8 << 2), + EightCarsCorrupt = (15 << 2), +}; +struct RCT12SurfaceElement; +struct RCT12PathElement; +struct RCT12TrackElement; +struct RCT12SmallSceneryElement; +struct RCT12LargeSceneryElement; +struct RCT12WallElement; +struct RCT12EntranceElement; +struct RCT12BannerElement; +struct RCT12CorruptElement; +struct RCT12EightCarsCorruptElement; + +struct RCT12TileElementBase +{ + uint8_t type; // 0 + uint8_t flags; // 1 + uint8_t base_height; // 2 + uint8_t clearance_height; // 3 + uint8_t GetType() const; + void SetType(uint8_t newType); + uint8_t GetDirection() const; + void SetDirection(uint8_t direction); + uint8_t GetDirectionWithOffset(uint8_t offset) const; + bool IsLastForTile() const; + bool IsGhost() const; + void Remove(); +}; +/** + * Map element structure + * size: 0x08 + */ +struct RCT12TileElement : public RCT12TileElementBase +{ + uint8_t pad_04[4]; + template TType* as() const + { + return (RCT12TileElementType)GetType() == TClass ? (TType*)this : nullptr; + } + +public: + RCT12SurfaceElement* AsSurface() const + { + return as(); + } + RCT12PathElement* AsPath() const + { + return as(); + } + RCT12TrackElement* AsTrack() const + { + return as(); + } + RCT12SmallSceneryElement* AsSmallScenery() const + { + return as(); + } + RCT12LargeSceneryElement* AsLargeScenery() const + { + return as(); + } + RCT12WallElement* AsWall() const + { + return as(); + } + RCT12EntranceElement* AsEntrance() const + { + return as(); + } + RCT12BannerElement* AsBanner() const + { + return as(); + } + RCT12CorruptElement* AsCorrupt() const + { + return as(); + } + RCT12EightCarsCorruptElement* AsEightCarsCorrupt() const + { + return as(); + } + void ClearAs(uint8_t newType); +}; +assert_struct_size(RCT12TileElement, 8); +struct RCT12SurfaceElement : RCT12TileElementBase +{ +private: + uint8_t slope; // 4 0xE0 Edge Style, 0x1F Slope + uint8_t terrain; // 5 0xE0 Terrain Style, 0x1F Water height + uint8_t grass_length; // 6 + uint8_t ownership; // 7 +public: + uint8_t GetSlope() const; + uint32_t GetSurfaceStyle() const; + uint32_t GetEdgeStyle() const; + uint8_t GetGrassLength() const; + uint8_t GetOwnership() const; + uint32_t GetWaterHeight() const; + uint8_t GetParkFences() const; + bool HasTrackThatNeedsWater() const; +}; +assert_struct_size(RCT12SurfaceElement, 8); +struct RCT12PathElement : RCT12TileElementBase +{ +private: + uint8_t entryIndex; // 4, 0xF0 Path type, 0x08 Ride sign, 0x04 Set when path is sloped, 0x03 Rotation + uint8_t additions; // 5, 0bGSSSAAAA: G = Ghost, S = station index, A = addition (0 means no addition) + uint8_t edges; // 6 + union + { + uint8_t additionStatus; // 7 + uint8_t rideIndex; + }; + +public: + uint8_t GetEntryIndex() const; + uint8_t GetQueueBannerDirection() const; + bool IsSloped() const; + uint8_t GetSlopeDirection() const; + uint8_t GetRideIndex() const; + uint8_t GetStationIndex() const; + bool IsWide() const; + bool IsQueue() const; + bool HasQueueBanner() const; + uint8_t GetEdges() const; + uint8_t GetCorners() const; + uint8_t GetEdgesAndCorners() const; + bool HasAddition() const; + uint8_t GetAddition() const; + uint8_t GetAdditionEntryIndex() const; + bool AdditionIsGhost() const; + uint8_t GetAdditionStatus() const; + uint8_t GetRCT1PathType() const; +}; +assert_struct_size(RCT12PathElement, 8); +struct RCT12TrackElement : RCT12TileElementBase +{ + uint8_t trackType; // 4 + union + { + struct + { + // The lower 4 bits are the track sequence. + // The upper 4 bits are either station bits or on-ride photo bits. + // + // Station bits: + // - Bit 8 marks green light + // - Bit 5-7 are station index. + // + // On-ride photo bits: + // - Bits 7 and 8 are never set + // - Bits 5 and 6 are set when a vehicle triggers the on-ride photo and act like a countdown from 3. + // - If any of the bits 5-8 are set, the game counts it as a photo being taken. + uint8_t sequence; // 5. + uint8_t colour; // 6 + }; + uint16_t mazeEntry; // 5 + }; + uint8_t rideIndex; // 7 +public: + uint8_t GetTrackType() const; + uint8_t GetSequenceIndex() const; + uint8_t GetRideIndex() const; + uint8_t GetColourScheme() const; + uint8_t GetStationIndex() const; + bool HasChain() const; + bool HasCableLift() const; + bool IsInverted() const; + uint8_t GetBrakeBoosterSpeed() const; + uint8_t HasGreenLight() const; + uint8_t GetSeatRotation() const; + uint16_t GetMazeEntry() const; + void MazeEntryAdd(uint16_t addVal); + void MazeEntrySubtract(uint16_t subVal); + bool IsTakingPhoto() const; + void GetPhotoTimeout(); + bool IsHighlighted() const; + // Used in RCT1, will be reintroduced at some point. + // (See https://github.com/OpenRCT2/OpenRCT2/issues/7059) + uint8_t GetDoorAState() const; + uint8_t GetDoorBState() const; +}; +assert_struct_size(RCT12TrackElement, 8); +struct RCT12SmallSceneryElement : RCT12TileElementBase +{ +private: + uint8_t entryIndex; // 4 + uint8_t age; // 5 + uint8_t colour_1; // 6 + uint8_t colour_2; // 7 +public: + uint8_t GetEntryIndex() const; + uint8_t GetAge() const; + uint8_t GetSceneryQuadrant() const; + colour_t GetPrimaryColour() const; + colour_t GetSecondaryColour() const; + bool NeedsSupports() const; +}; +assert_struct_size(RCT12SmallSceneryElement, 8); +struct RCT12LargeSceneryElement : RCT12TileElementBase +{ +private: + uint16_t entryIndex; // 4 + uint8_t colour[2]; // 6 +public: + uint32_t GetEntryIndex() const; + uint16_t GetSequenceIndex() const; + colour_t GetPrimaryColour() const; + colour_t GetSecondaryColour() const; + BannerIndex GetBannerIndex() const; +}; +assert_struct_size(RCT12LargeSceneryElement, 8); +struct RCT12WallElement : RCT12TileElementBase +{ +private: + uint8_t entryIndex; // 4 + union + { + uint8_t colour_3; // 5 + BannerIndex banner_index; // 5 + }; + uint8_t colour_1; // 6 0b_2221_1111 2 = colour_2 (uses flags for rest of colour2), 1 = colour_1 + uint8_t animation; // 7 0b_dfff_ft00 d = direction, f = frame num, t = across track flag (not used) +public: + uint8_t GetEntryIndex() const; + uint8_t GetSlope() const; + colour_t GetPrimaryColour() const; + colour_t GetSecondaryColour() const; + colour_t GetTertiaryColour() const; + uint8_t GetAnimationFrame() const; + BannerIndex GetBannerIndex() const; + bool IsAcrossTrack() const; + bool AnimationIsBackwards() const; + int32_t GetRCT1WallType(int32_t edge) const; + colour_t GetRCT1WallColour() const; +}; +assert_struct_size(RCT12WallElement, 8); +struct RCT12EntranceElement : RCT12TileElementBase +{ +private: + uint8_t entranceType; // 4 + uint8_t index; // 5. 0bUSSS????, S = station index. + uint8_t pathType; // 6 + uint8_t rideIndex; // 7 +public: + uint8_t GetEntranceType() const; + uint8_t GetRideIndex() const; + uint8_t GetStationIndex() const; + uint8_t GetSequenceIndex() const; + uint8_t GetPathType() const; +}; +assert_struct_size(RCT12EntranceElement, 8); +struct RCT12BannerElement : RCT12TileElementBase +{ +private: + BannerIndex index; // 4 + uint8_t position; // 5 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-private-field" + uint8_t flags; // 6 + uint8_t unused; // 7 +#pragma clang diagnostic pop +public: + BannerIndex GetIndex() const; + uint8_t GetPosition() const; + uint8_t GetAllowedEdges() const; +}; +assert_struct_size(RCT12BannerElement, 8); + +struct RCT12CorruptElement : RCT12TileElementBase +{ + uint8_t pad[4]; +}; +assert_struct_size(RCT12CorruptElement, 8); + +struct RCT12EightCarsCorruptElement : RCT12TileElementBase +{ + uint8_t pad[4]; +}; +assert_struct_size(RCT12EightCarsCorruptElement, 8); + #pragma pack(pop) diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 4cbf02899d..49255f52b9 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -32,6 +32,7 @@ #include "../peep/Staff.h" #include "../platform/platform.h" #include "../rct1/RCT1.h" +#include "../rct12/RCT12.h" #include "../ride/Ride.h" #include "../ride/Track.h" #include "../util/SawyerCoding.h" @@ -670,22 +671,24 @@ bool scenario_prepare_for_save() /** * Modifies the given S6 data so that ghost elements, rides with no track elements or unused banners / user strings are saved. + * + * TODO: This employs some black casting magic that should go away once we export to our own format instead of SV6. */ void scenario_fix_ghosts(rct_s6_data* s6) { // Remove all ghost elements - TileElement* destinationElement = s6->tile_elements; + RCT12TileElement* destinationElement = s6->tile_elements; for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) { for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) { - TileElement* originalElement = map_get_first_element_at(x, y); + RCT12TileElement* originalElement = reinterpret_cast(map_get_first_element_at(x, y)); do { if (originalElement->flags & TILE_ELEMENT_FLAG_GHOST) { - BannerIndex bannerIndex = tile_element_get_banner_index(originalElement); + BannerIndex bannerIndex = tile_element_get_banner_index(reinterpret_cast(originalElement)); if (bannerIndex != BANNER_INDEX_NULL) { rct_banner* banner = &s6->banners[bannerIndex]; diff --git a/src/openrct2/scenario/Scenario.h b/src/openrct2/scenario/Scenario.h index 045b8fb24d..57ed9a1913 100644 --- a/src/openrct2/scenario/Scenario.h +++ b/src/openrct2/scenario/Scenario.h @@ -104,7 +104,7 @@ struct rct_s6_data uint32_t scenario_srand_1; // SC6[5] - TileElement tile_elements[RCT2_MAX_TILE_ELEMENTS]; + RCT12TileElement tile_elements[RCT2_MAX_TILE_ELEMENTS]; // SC6[6] uint32_t next_free_tile_element_pointer_index;