diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index f01b1a0b88..3eb744c77c 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -311,6 +311,7 @@ + diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 97fa00b34d..853a8ae796 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -45,6 +45,7 @@ #include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" #include "../peep/RideUseSystem.h" +#include "../rct12/EntryList.h" #include "../ride/RideData.h" #include "../ride/Station.h" #include "../ride/Track.h" @@ -80,44 +81,6 @@ using namespace OpenRCT2; namespace RCT1 { - class EntryList - { - private: - std::vector _entries; - - public: - size_t GetCount() const - { - return _entries.size(); - } - - const std::vector& GetEntries() const - { - return _entries; - } - - ObjectEntryIndex GetOrAddEntry(std::string_view identifier) - { - for (size_t i = 0; i < _entries.size(); i++) - { - if (_entries[i] == identifier) - { - return static_cast(i); - } - } - _entries.emplace_back(identifier); - return static_cast(_entries.size() - 1); - } - - void AddRange(std::initializer_list initializerList) - { - for (auto entry : initializerList) - { - GetOrAddEntry(entry); - } - } - }; - class S4Importer final : public IParkImporter { private: @@ -128,18 +91,18 @@ namespace RCT1 bool _isScenario = false; // Lists of dynamic object entries - EntryList _rideEntries; - EntryList _smallSceneryEntries; - EntryList _largeSceneryEntries; - EntryList _wallEntries; - EntryList _pathEntries; - EntryList _pathAdditionEntries; - EntryList _sceneryGroupEntries; - EntryList _waterEntry; - EntryList _terrainSurfaceEntries; - EntryList _terrainEdgeEntries; - EntryList _footpathSurfaceEntries; - EntryList _footpathRailingsEntries; + RCT12::EntryList _rideEntries; + RCT12::EntryList _smallSceneryEntries; + RCT12::EntryList _largeSceneryEntries; + RCT12::EntryList _wallEntries; + RCT12::EntryList _pathEntries; + RCT12::EntryList _pathAdditionEntries; + RCT12::EntryList _sceneryGroupEntries; + RCT12::EntryList _waterEntry; + RCT12::EntryList _terrainSurfaceEntries; + RCT12::EntryList _terrainEdgeEntries; + RCT12::EntryList _footpathSurfaceEntries; + RCT12::EntryList _footpathRailingsEntries; // Lookup tables for converting from RCT1 hard coded types to the new dynamic object entries ObjectEntryIndex _rideTypeToRideEntryMap[EnumValue(RideType::Count)]{}; @@ -598,7 +561,7 @@ namespace RCT1 case ObjectType::Paths: case ObjectType::PathBits: { - EntryList* entries = GetEntryList(objectType); + RCT12::EntryList* entries = GetEntryList(objectType); // Check if there are spare entries available size_t maxEntries = static_cast(object_entry_group_counts[EnumValue(objectType)]); @@ -1484,7 +1447,7 @@ namespace RCT1 } } - void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const EntryList& entryList) + void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const RCT12::EntryList& entryList) { AppendRequiredObjects(objectList, objectType, entryList.GetEntries()); } @@ -2456,7 +2419,7 @@ namespace RCT1 } } - EntryList* GetEntryList(ObjectType objectType) + RCT12::EntryList* GetEntryList(ObjectType objectType) { switch (objectType) { diff --git a/src/openrct2/rct12/EntryList.h b/src/openrct2/rct12/EntryList.h new file mode 100644 index 0000000000..0b6b05de04 --- /dev/null +++ b/src/openrct2/rct12/EntryList.h @@ -0,0 +1,65 @@ +/***************************************************************************** + * Copyright (c) 2014-2021 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 +#include +#include + +using ObjectEntryIndex = uint16_t; + +namespace RCT12 +{ + class EntryList + { + private: + std::vector _entries; + + public: + size_t GetCount() const + { + return _entries.size(); + } + + const std::vector& GetEntries() const + { + return _entries; + } + + ObjectEntryIndex GetOrAddEntry(std::string_view identifier) + { + for (size_t i = 0; i < _entries.size(); i++) + { + if (_entries[i] == identifier) + { + return static_cast(i); + } + } + _entries.emplace_back(identifier); + return static_cast(_entries.size() - 1); + } + + void AddRange(std::initializer_list initializerList) + { + for (auto entry : initializerList) + { + GetOrAddEntry(entry); + } + } + + template void AddRange(const std::string_view (&list)[i]) + { + for (auto entry : list) + { + GetOrAddEntry(entry); + } + } + }; +} // namespace RCT12 diff --git a/src/openrct2/rct12/RCT12.cpp b/src/openrct2/rct12/RCT12.cpp index b7ce369b01..6eeddf34de 100644 --- a/src/openrct2/rct12/RCT12.cpp +++ b/src/openrct2/rct12/RCT12.cpp @@ -22,6 +22,7 @@ #include "../world/Surface.h" #include "../world/TileElement.h" #include "../world/Wall.h" +#include "EntryList.h" using namespace OpenRCT2; @@ -889,46 +890,6 @@ std::optional GetStyleFromMusicIdentifier(std::string_view identifier) return std::nullopt; } -void SetDefaultRCT2TerrainObjects(ObjectList& objectList) -{ - // Surfaces - objectList.SetObject(ObjectType::TerrainSurface, 0, "rct2.terrain_surface.grass"); - objectList.SetObject(ObjectType::TerrainSurface, 1, "rct2.terrain_surface.sand"); - objectList.SetObject(ObjectType::TerrainSurface, 2, "rct2.terrain_surface.dirt"); - objectList.SetObject(ObjectType::TerrainSurface, 3, "rct2.terrain_surface.rock"); - objectList.SetObject(ObjectType::TerrainSurface, 4, "rct2.terrain_surface.martian"); - objectList.SetObject(ObjectType::TerrainSurface, 5, "rct2.terrain_surface.chequerboard"); - objectList.SetObject(ObjectType::TerrainSurface, 6, "rct2.terrain_surface.grass_clumps"); - objectList.SetObject(ObjectType::TerrainSurface, 7, "rct2.terrain_surface.ice"); - objectList.SetObject(ObjectType::TerrainSurface, 8, "rct2.terrain_surface.grid_red"); - objectList.SetObject(ObjectType::TerrainSurface, 9, "rct2.terrain_surface.grid_yellow"); - objectList.SetObject(ObjectType::TerrainSurface, 10, "rct2.terrain_surface.grid_purple"); - objectList.SetObject(ObjectType::TerrainSurface, 11, "rct2.terrain_surface.grid_green"); - objectList.SetObject(ObjectType::TerrainSurface, 12, "rct2.terrain_surface.sand_red"); - objectList.SetObject(ObjectType::TerrainSurface, 13, "rct2.terrain_surface.sand_brown"); - objectList.SetObject(ObjectType::TerrainSurface, 14, "rct1aa.terrain_surface.roof_red"); - objectList.SetObject(ObjectType::TerrainSurface, 15, "rct1ll.terrain_surface.roof_grey"); - objectList.SetObject(ObjectType::TerrainSurface, 16, "rct1ll.terrain_surface.rust"); - objectList.SetObject(ObjectType::TerrainSurface, 17, "rct1ll.terrain_surface.wood"); - - // Edges - objectList.SetObject(ObjectType::TerrainEdge, 0, "rct2.terrain_edge.rock"); - objectList.SetObject(ObjectType::TerrainEdge, 1, "rct2.terrain_edge.wood_red"); - objectList.SetObject(ObjectType::TerrainEdge, 2, "rct2.terrain_edge.wood_black"); - objectList.SetObject(ObjectType::TerrainEdge, 3, "rct2.terrain_edge.ice"); - objectList.SetObject(ObjectType::TerrainEdge, 4, "rct1.terrain_edge.brick"); - objectList.SetObject(ObjectType::TerrainEdge, 5, "rct1.terrain_edge.iron"); - objectList.SetObject(ObjectType::TerrainEdge, 6, "rct1aa.terrain_edge.grey"); - objectList.SetObject(ObjectType::TerrainEdge, 7, "rct1aa.terrain_edge.yellow"); - objectList.SetObject(ObjectType::TerrainEdge, 8, "rct1aa.terrain_edge.red"); - objectList.SetObject(ObjectType::TerrainEdge, 9, "rct1ll.terrain_edge.purple"); - objectList.SetObject(ObjectType::TerrainEdge, 10, "rct1ll.terrain_edge.green"); - objectList.SetObject(ObjectType::TerrainEdge, 11, "rct1ll.terrain_edge.stone_brown"); - objectList.SetObject(ObjectType::TerrainEdge, 12, "rct1ll.terrain_edge.stone_grey"); - objectList.SetObject(ObjectType::TerrainEdge, 13, "rct1ll.terrain_edge.skyscraper_a"); - objectList.SetObject(ObjectType::TerrainEdge, 14, "rct1ll.terrain_edge.skyscraper_b"); -} - void RCT12AddDefaultObjects(ObjectList& objectList) { // Stations @@ -947,6 +908,21 @@ void RCT12AddDefaultObjects(ObjectList& objectList) } } +static void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const std::vector& objectNames) +{ + for (const auto& objectName : objectNames) + { + auto descriptor = ObjectEntryDescriptor(objectName); + descriptor.Type = objectType; + objectList.Add(descriptor); + } +} + +void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const RCT12::EntryList& entryList) +{ + AppendRequiredObjects(objectList, objectType, entryList.GetEntries()); +} + money64 RCT12CompletedCompanyValueToOpenRCT2(money32 origValue) { if (origValue == RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE) diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index 9616db715b..f53a51b743 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -24,6 +24,10 @@ class ObjectList; using track_type_t = uint16_t; using RCT12TrackType = uint8_t; +namespace RCT12 +{ + class EntryList; +} constexpr uint8_t RCT2_STRING_FORMAT_ARG_START = 123; constexpr uint8_t RCT2_STRING_FORMAT_ARG_END = 141; @@ -832,8 +836,8 @@ track_type_t RCT12FlatTrackTypeToOpenRCT2(RCT12TrackType origTrackType); RCT12TrackType OpenRCT2FlatTrackTypeToRCT12(track_type_t origTrackType); std::string_view GetStationIdentifierFromStyle(uint8_t style); std::optional GetStyleFromMusicIdentifier(std::string_view identifier); -void SetDefaultRCT2TerrainObjects(ObjectList& objectList); void RCT12AddDefaultObjects(ObjectList& objectList); +void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const RCT12::EntryList& entryList); static constexpr money32 RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE = 0x80000001; diff --git a/src/openrct2/rct2/RCT2.cpp b/src/openrct2/rct2/RCT2.cpp index 89eb75e1f3..6f72425695 100644 --- a/src/openrct2/rct2/RCT2.cpp +++ b/src/openrct2/rct2/RCT2.cpp @@ -11,6 +11,7 @@ #include "../Context.h" #include "../object/Object.h" +#include "../object/ObjectList.h" #include "../object/ObjectManager.h" #include "../ride/Ride.h" #include "../ride/RideData.h" diff --git a/src/openrct2/rct2/RCT2.h b/src/openrct2/rct2/RCT2.h index 1826a97a27..5fdc6cc977 100644 --- a/src/openrct2/rct2/RCT2.h +++ b/src/openrct2/rct2/RCT2.h @@ -20,6 +20,7 @@ #include struct rct_ride_entry; +class ObjectList; enum class EditorStep : uint8_t; namespace RCT2 @@ -1063,6 +1064,37 @@ namespace RCT2 const FootpathMapping* GetFootpathSurfaceId( const ObjectEntryDescriptor& desc, bool ideallyLoaded = false, bool isQueue = false); std::optional GetBestObjectEntryForSurface(std::string_view surface, std::string_view railings); + + static constexpr std::string_view DefaultTerrainSurfaces[] = { + "rct2.terrain_surface.grass", "rct2.terrain_surface.sand", "rct2.terrain_surface.dirt", + "rct2.terrain_surface.rock", "rct2.terrain_surface.martian", "rct2.terrain_surface.chequerboard", + "rct2.terrain_surface.grass_clumps", "rct2.terrain_surface.ice", "rct2.terrain_surface.grid_red", + "rct2.terrain_surface.grid_yellow", "rct2.terrain_surface.grid_purple", "rct2.terrain_surface.grid_green", + "rct2.terrain_surface.sand_red", "rct2.terrain_surface.sand_brown", + }; + + // Additional surface styles added to OpenRCT2 as a feature if RCT1 linked + static constexpr std::string_view OpenRCT2HybridTerrainSurfaces[] = { + "rct1aa.terrain_surface.roof_red", + "rct1ll.terrain_surface.roof_grey", + "rct1ll.terrain_surface.rust", + "rct1ll.terrain_surface.wood", + }; + + static constexpr std::string_view DefaultTerrainEdges[] = { + "rct2.terrain_edge.rock", + "rct2.terrain_edge.wood_red", + "rct2.terrain_edge.wood_black", + "rct2.terrain_edge.ice", + }; + + // Additional surface edges added to OpenRCT2 as a feature if RCT1 was linked + static constexpr std::string_view OpenRCT2HybridTerrainEdges[] = { + "rct1.terrain_edge.brick", "rct1.terrain_edge.iron", "rct1aa.terrain_edge.grey", + "rct1aa.terrain_edge.yellow", "rct1aa.terrain_edge.red", "rct1ll.terrain_edge.purple", + "rct1ll.terrain_edge.green", "rct1ll.terrain_edge.stone_brown", "rct1ll.terrain_edge.stone_grey", + "rct1ll.terrain_edge.skyscraper_a", "rct1ll.terrain_edge.skyscraper_b", + }; } // namespace RCT2 std::vector DecryptSea(const fs::path& path); diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index ec27911ff6..91e09c9ad5 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -47,6 +47,7 @@ #include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" #include "../peep/RideUseSystem.h" +#include "../rct12/EntryList.h" #include "../rct12/RCT12.h" #include "../rct12/SawyerChunkReader.h" #include "../rct12/SawyerEncoding.h" @@ -94,6 +95,8 @@ namespace RCT2 ObjectEntryIndex _pathToSurfaceMap[16]; ObjectEntryIndex _pathToQueueSurfaceMap[16]; ObjectEntryIndex _pathToRailingMap[16]; + RCT12::EntryList _terrainSurfaceEntries; + RCT12::EntryList _terrainEdgeEntries; public: S6Importer(IObjectRepository& objectRepository) @@ -492,6 +495,15 @@ namespace RCT2 ClearRestrictedScenery(); } + void AddDefaultEntries() + { + // Add default surfaces + _terrainSurfaceEntries.AddRange(DefaultTerrainSurfaces); + + // Add default edges + _terrainEdgeEntries.AddRange(DefaultTerrainEdges); + } + void ConvertScenarioStringsToUTF8() { // Scenario details @@ -1192,8 +1204,10 @@ namespace RCT2 auto src2 = src->AsSurface(); dst2->SetSlope(src2->GetSlope()); + dst2->SetSurfaceStyle(src2->GetSurfaceStyle()); dst2->SetEdgeStyle(src2->GetEdgeStyle()); + dst2->SetGrassLength(src2->GetGrassLength()); dst2->SetOwnership(src2->GetOwnership()); dst2->SetParkFences(src2->GetParkFences()); @@ -1732,7 +1746,37 @@ namespace RCT2 } } - SetDefaultRCT2TerrainObjects(objectList); + // Add default rct2 terrain surfaces and edges + AddDefaultEntries(); + + // Find if any rct1 terrain surfaces or edges have been used + const bool hasRCT1Terrain = std::any_of( + std::begin(_s6.tile_elements), std::end(_s6.tile_elements), [](RCT12TileElement& tile) { + auto* surface = tile.AsSurface(); + if (surface == nullptr) + { + return false; + } + if (surface->GetSurfaceStyle() >= std::size(RCT2::DefaultTerrainSurfaces)) + { + return true; + } + if (surface->GetEdgeStyle() >= std::size(RCT2::DefaultTerrainEdges)) + { + return true; + } + return false; + }); + + // If an rct1 surface or edge then load all the Hybrid surfaces and edges + if (hasRCT1Terrain) + { + _terrainSurfaceEntries.AddRange(OpenRCT2HybridTerrainSurfaces); + _terrainEdgeEntries.AddRange(OpenRCT2HybridTerrainEdges); + } + + AppendRequiredObjects(objectList, ObjectType::TerrainSurface, _terrainSurfaceEntries); + AppendRequiredObjects(objectList, ObjectType::TerrainEdge, _terrainEdgeEntries); RCT12AddDefaultObjects(objectList); return objectList; }