Skip to content

Commit

Permalink
Handle hybrid sv6 saves
Browse files Browse the repository at this point in the history
  • Loading branch information
duncanspumpkin committed Nov 30, 2021
1 parent cc557fa commit 131a34d
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 78 deletions.
1 change: 1 addition & 0 deletions src/openrct2/libopenrct2.vcxproj
Expand Up @@ -311,6 +311,7 @@
<ClInclude Include="platform\Crash.h" />
<ClInclude Include="platform\platform.h" />
<ClInclude Include="platform\Platform2.h" />
<ClInclude Include="rct12\EntryList.h" />
<ClInclude Include="rct12\Limits.h" />
<ClInclude Include="rct12\RCT12.h" />
<ClInclude Include="rct12\SawyerChunk.h" />
Expand Down
69 changes: 16 additions & 53 deletions src/openrct2/rct1/S4Importer.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -80,44 +81,6 @@ using namespace OpenRCT2;

namespace RCT1
{
class EntryList
{
private:
std::vector<std::string> _entries;

public:
size_t GetCount() const
{
return _entries.size();
}

const std::vector<std::string>& 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<ObjectEntryIndex>(i);
}
}
_entries.emplace_back(identifier);
return static_cast<ObjectEntryIndex>(_entries.size() - 1);
}

void AddRange(std::initializer_list<const char*> initializerList)
{
for (auto entry : initializerList)
{
GetOrAddEntry(entry);
}
}
};

class S4Importer final : public IParkImporter
{
private:
Expand All @@ -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)]{};
Expand Down Expand Up @@ -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<size_t>(object_entry_group_counts[EnumValue(objectType)]);
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -2456,7 +2419,7 @@ namespace RCT1
}
}

EntryList* GetEntryList(ObjectType objectType)
RCT12::EntryList* GetEntryList(ObjectType objectType)
{
switch (objectType)
{
Expand Down
65 changes: 65 additions & 0 deletions 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 <string>
#include <string_view>
#include <vector>

using ObjectEntryIndex = uint16_t;

namespace RCT12
{
class EntryList
{
private:
std::vector<std::string> _entries;

public:
size_t GetCount() const
{
return _entries.size();
}

const std::vector<std::string>& 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<ObjectEntryIndex>(i);
}
}
_entries.emplace_back(identifier);
return static_cast<ObjectEntryIndex>(_entries.size() - 1);
}

void AddRange(const std::initializer_list<std::string_view> initializerList)
{
for (auto entry : initializerList)
{
GetOrAddEntry(entry);
}
}

template<uint32_t i> void AddRange(const std::string_view (&list)[i])
{
for (auto entry : list)
{
GetOrAddEntry(entry);
}
}
};
} // namespace RCT12
16 changes: 16 additions & 0 deletions src/openrct2/rct12/RCT12.cpp
Expand Up @@ -22,6 +22,7 @@
#include "../world/Surface.h"
#include "../world/TileElement.h"
#include "../world/Wall.h"
#include "EntryList.h"

using namespace OpenRCT2;

Expand Down Expand Up @@ -1428,6 +1429,21 @@ void RCT12AddDefaultObjects(ObjectList& objectList)
}
}

static void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const std::vector<std::string>& 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)
Expand Down
5 changes: 5 additions & 0 deletions src/openrct2/rct12/RCT12.h
Expand Up @@ -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;
Expand Down Expand Up @@ -915,6 +919,7 @@ RCT12TrackType OpenRCT2FlatTrackTypeToRCT12(track_type_t origTrackType);
std::string_view GetStationIdentifierFromStyle(uint8_t style);
std::optional<uint8_t> GetStyleFromMusicIdentifier(std::string_view identifier);
void RCT12AddDefaultObjects(ObjectList& objectList);
void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const RCT12::EntryList& entryList);

static constexpr money32 RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE = 0x80000001;

Expand Down
52 changes: 31 additions & 21 deletions src/openrct2/rct2/RCT2.cpp
Expand Up @@ -274,35 +274,45 @@ namespace RCT2
return {};
}

static constexpr std::string_view _terrainSurfaces[] = {
"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 _terrainEdges[] = {
"rct2.terrain_edge.rock",
"rct2.terrain_edge.wood_red",
"rct2.terrain_edge.wood_black",
"rct2.terrain_edge.ice",
std::string_view GetTerrainSurfaceObject(uint8_t terrainSurface)
{
if (terrainSurface < std::size(DefaultTerrainSurfaces))
{
return DefaultTerrainSurfaces[terrainSurface];
}
else if (terrainSurface - std::size(DefaultTerrainSurfaces) < std::size(OpenRCT2HybridTerrainSurfaces))
{
return OpenRCT2HybridTerrainSurfaces[terrainSurface - std::size(DefaultTerrainSurfaces)];
}
return DefaultTerrainSurfaces[0];
}

// 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",
};

void AddDefaultObjects(ObjectList& objectList)
std::string_view GetTerrainEdgeObject(uint8_t terrainEdge)
{
RCT12AddDefaultObjects(objectList);

// Surfaces
for (size_t i = 0; i < std::size(_terrainSurfaces); i++)
if (terrainEdge < std::size(DefaultTerrainEdges))
{
objectList.SetObject(ObjectType::TerrainSurface, static_cast<ObjectEntryIndex>(i), _terrainSurfaces[i]);
return DefaultTerrainEdges[terrainEdge];
}

// Edges
for (size_t i = 0; i < std::size(_terrainEdges); i++)
else if (terrainEdge - std::size(DefaultTerrainEdges) < std::size(OpenRCT2HybridTerrainEdges))
{
objectList.SetObject(ObjectType::TerrainEdge, static_cast<ObjectEntryIndex>(i), _terrainEdges[i]);
return OpenRCT2HybridTerrainSurfaces[terrainEdge - std::size(DefaultTerrainEdges)];
}
return DefaultTerrainEdges[0];
}
} // namespace RCT2
19 changes: 18 additions & 1 deletion src/openrct2/rct2/RCT2.h
Expand Up @@ -1064,7 +1064,24 @@ namespace RCT2
const FootpathMapping* GetFootpathSurfaceId(
const ObjectEntryDescriptor& desc, bool ideallyLoaded = false, bool isQueue = false);
std::optional<rct_object_entry> GetBestObjectEntryForSurface(std::string_view surface, std::string_view railings);
void AddDefaultObjects(ObjectList& objectList);

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",
};

static constexpr std::string_view DefaultTerrainEdges[] = {
"rct2.terrain_edge.rock",
"rct2.terrain_edge.wood_red",
"rct2.terrain_edge.wood_black",
"rct2.terrain_edge.ice",
};

std::string_view GetTerrainSurfaceObject(uint8_t terrainSurface);
std::string_view GetTerrainEdgeObject(uint8_t terrainEdge);
} // namespace RCT2

std::vector<uint8_t> DecryptSea(const fs::path& path);
37 changes: 34 additions & 3 deletions src/openrct2/rct2/S6Importer.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1192,8 +1204,13 @@ namespace RCT2
auto src2 = src->AsSurface();

dst2->SetSlope(src2->GetSlope());
dst2->SetSurfaceStyle(src2->GetSurfaceStyle());
dst2->SetEdgeStyle(src2->GetEdgeStyle());

const auto surfaceStyle = _terrainSurfaceEntries.GetOrAddEntry(
RCT2::GetTerrainSurfaceObject(src2->GetSurfaceStyle()));
dst2->SetSurfaceStyle(surfaceStyle);
const auto edgeStyle = _terrainEdgeEntries.GetOrAddEntry(RCT2::GetTerrainEdgeObject(src2->GetEdgeStyle()));
dst2->SetEdgeStyle(edgeStyle);

dst2->SetGrassLength(src2->GetGrassLength());
dst2->SetOwnership(src2->GetOwnership());
dst2->SetParkFences(src2->GetParkFences());
Expand Down Expand Up @@ -1732,7 +1749,21 @@ namespace RCT2
}
}

AddDefaultObjects(objectList);
AddDefaultEntries();
for (auto tile : _s6.tile_elements)
{
auto* surface = tile.AsSurface();
if (surface == nullptr)
{
continue;
}
_terrainSurfaceEntries.GetOrAddEntry(RCT2::GetTerrainSurfaceObject(surface->GetSurfaceStyle()));
_terrainEdgeEntries.GetOrAddEntry(RCT2::GetTerrainEdgeObject(surface->GetEdgeStyle()));
}

AppendRequiredObjects(objectList, ObjectType::TerrainSurface, _terrainSurfaceEntries);
AppendRequiredObjects(objectList, ObjectType::TerrainEdge, _terrainEdgeEntries);
RCT12AddDefaultObjects(objectList);
return objectList;
}
};
Expand Down

0 comments on commit 131a34d

Please sign in to comment.