1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-24 23:34:37 +01:00

Backport track design changes

Co-authored-by: Ted John <ted@brambles.org>
This commit is contained in:
ζeh Matt
2021-10-11 19:49:05 +03:00
parent 6ea0d8639d
commit 6f8e017a32
11 changed files with 583 additions and 303 deletions

View File

@@ -598,6 +598,50 @@ template<> struct DataSerializerTraits_t<rct_object_entry>
}
};
template<> struct DataSerializerTraits_t<ObjectEntryDescriptor>
{
static void encode(OpenRCT2::IStream* stream, const ObjectEntryDescriptor& val)
{
stream->WriteValue<uint8_t>(static_cast<uint8_t>(val.Generation));
if (val.Generation == ObjectGeneration::DAT)
{
DataSerializerTraits<rct_object_entry> s;
s.encode(stream, val.Entry);
}
else
{
stream->WriteValue<uint8_t>(static_cast<uint8_t>(val.GetType()));
stream->WriteString(val.Identifier);
}
}
static void decode(OpenRCT2::IStream* stream, ObjectEntryDescriptor& val)
{
auto generation = static_cast<ObjectGeneration>(stream->ReadValue<uint8_t>());
if (generation == ObjectGeneration::DAT)
{
DataSerializerTraits<rct_object_entry> s;
rct_object_entry entry;
s.decode(stream, entry);
val = ObjectEntryDescriptor(entry);
}
else
{
auto type = static_cast<ObjectType>(stream->ReadValue<uint8_t>());
auto identifier = stream->ReadStdString();
val = ObjectEntryDescriptor(type, identifier);
}
}
static void log(OpenRCT2::IStream* stream, const ObjectEntryDescriptor& val)
{
auto identifier = std::string(val.GetName());
char msg[128] = {};
snprintf(msg, sizeof(msg), "ObjectEntryDescriptor[%s]", identifier.c_str());
stream->Write(msg, strlen(msg));
}
};
template<> struct DataSerializerTraits_t<TrackDesignTrackElement>
{
static void encode(OpenRCT2::IStream* stream, const TrackDesignTrackElement& val)
@@ -677,7 +721,7 @@ template<> struct DataSerializerTraits_t<TrackDesignSceneryElement>
stream->Write(&val.flags);
stream->Write(&val.primary_colour);
stream->Write(&val.secondary_colour);
DataSerializerTraits<rct_object_entry> s;
DataSerializerTraits<ObjectEntryDescriptor> s;
s.encode(stream, val.scenery_object);
}
static void decode(OpenRCT2::IStream* stream, TrackDesignSceneryElement& val)
@@ -688,7 +732,7 @@ template<> struct DataSerializerTraits_t<TrackDesignSceneryElement>
stream->Read(&val.flags);
stream->Read(&val.primary_colour);
stream->Read(&val.secondary_colour);
DataSerializerTraits<rct_object_entry> s;
DataSerializerTraits<ObjectEntryDescriptor> s;
s.decode(stream, val.scenery_object);
}
static void log(OpenRCT2::IStream* stream, const TrackDesignSceneryElement& val)
@@ -698,7 +742,9 @@ template<> struct DataSerializerTraits_t<TrackDesignSceneryElement>
msg, sizeof(msg), "TrackDesignSceneryElement(x = %d, y = %d, z = %d, flags = %d, colour1 = %d, colour2 = %d)",
val.x, val.y, val.z, val.flags, val.primary_colour, val.secondary_colour);
stream->Write(msg, strlen(msg));
stream->WriteArray(val.scenery_object.name, 8);
auto identifier = val.scenery_object.GetName();
stream->WriteArray(identifier.data(), identifier.size());
}
};
@@ -722,49 +768,6 @@ template<> struct DataSerializerTraits_t<rct_vehicle_colour>
}
};
template<> struct DataSerializerTraits_t<ObjectEntryDescriptor>
{
static void encode(OpenRCT2::IStream* stream, const ObjectEntryDescriptor& val)
{
stream->Write(&val.Generation);
if (val.Generation == ObjectGeneration::DAT)
{
DataSerializerTraits<rct_object_entry> s;
s.encode(stream, val.Entry);
}
else
{
DataSerializerTraits<std::string> s;
s.encode(stream, val.Identifier);
}
}
static void decode(OpenRCT2::IStream* stream, ObjectEntryDescriptor& val)
{
ObjectGeneration generation;
stream->Read(&generation);
if (generation == ObjectGeneration::DAT)
{
rct_object_entry obj;
DataSerializerTraits<rct_object_entry> s;
s.decode(stream, obj);
val = ObjectEntryDescriptor(obj);
}
else
{
std::string id;
DataSerializerTraits<std::string> s;
s.decode(stream, id);
val = ObjectEntryDescriptor(id);
}
}
static void log(OpenRCT2::IStream* stream, const ObjectEntryDescriptor& val)
{
char msg[128] = {};
snprintf(msg, sizeof(msg), "ObjectEntryDescriptor (Generation = %d)", static_cast<int32_t>(val.Generation));
stream->Write(msg, strlen(msg));
}
};
template<> struct DataSerializerTraits_t<IntensityRange>
{
static void encode(OpenRCT2::IStream* stream, const IntensityRange& val)

View File

@@ -3913,6 +3913,8 @@ enum
STR_FOLLOW_SUBJECT_TIP = 6458,
STR_UNSUPPORTED_OBJECT_FORMAT = 6459,
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
/* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings
};

View File

@@ -1347,21 +1347,12 @@ RCT12TrackType OpenRCT2FlatTrackTypeToRCT12(track_type_t origTrackType)
return origTrackType;
}
money64 RCT12CompletedCompanyValueToOpenRCT2(money32 origValue)
{
if (origValue == RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE)
return COMPANY_VALUE_ON_FAILED_OBJECTIVE;
return ToMoney64(origValue);
}
money32 OpenRCT2CompletedCompanyValueToRCT12(money64 origValue)
{
if (origValue == COMPANY_VALUE_ON_FAILED_OBJECTIVE)
return RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE;
return ToMoney32(origValue);
}
static constexpr std::string_view _stationStyles[] = {
"rct2.station.plain", "rct2.station.wooden", "rct2.station.canvas_tent", "rct2.station.castle_grey",
"rct2.station.castle_brown", "rct2.station.jungle", "rct2.station.log", "rct2.station.classical",
"rct2.station.abstract", "rct2.station.snow", "rct2.station.pagoda", "rct2.station.space",
"openrct2.station.noentrance"
};
static constexpr std::string_view _musicStyles[] = {
"rct2.music.dodgems",
@@ -1399,6 +1390,15 @@ static constexpr std::string_view _musicStyles[] = {
"rct2.music.candy",
};
std::string_view GetStationIdentifierFromStyle(uint8_t style)
{
if (style < std::size(_stationStyles))
{
return _stationStyles[style];
}
return {};
}
std::optional<uint8_t> GetStyleFromMusicIdentifier(std::string_view identifier)
{
auto it = std::find(std::begin(_musicStyles), std::end(_musicStyles), identifier);
@@ -1408,3 +1408,19 @@ std::optional<uint8_t> GetStyleFromMusicIdentifier(std::string_view identifier)
}
return std::nullopt;
}
money64 RCT12CompletedCompanyValueToOpenRCT2(money32 origValue)
{
if (origValue == RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE)
return COMPANY_VALUE_ON_FAILED_OBJECTIVE;
return ToMoney64(origValue);
}
money32 OpenRCT2CompletedCompanyValueToRCT12(money64 origValue)
{
if (origValue == COMPANY_VALUE_ON_FAILED_OBJECTIVE)
return RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE;
return ToMoney32(origValue);
}

View File

@@ -19,6 +19,8 @@
#include <string_view>
#include <vector>
class ObjectList;
using track_type_t = uint16_t;
using RCT12TrackType = uint8_t;
@@ -940,6 +942,7 @@ std::string ConvertFormattedStringToRCT2(std::string_view buffer, size_t maxLeng
std::string GetTruncatedRCT2String(std::string_view src, size_t maxLength);
track_type_t RCT12FlatTrackTypeToOpenRCT2(RCT12TrackType origTrackType);
RCT12TrackType OpenRCT2FlatTrackTypeToRCT12(track_type_t origTrackType);
std::string_view GetStationIdentifierFromStyle(uint8_t style);
std::optional<uint8_t> GetStyleFromMusicIdentifier(std::string_view identifier);
static constexpr money32 RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE = 0x80000001;

View File

@@ -7,7 +7,9 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../Context.h"
#include "../object/Object.h"
#include "../object/ObjectManager.h"
#include "../ride/Ride.h"
#include "../ride/RideData.h"
#include "../ride/Track.h"
@@ -156,3 +158,107 @@ RCT12TrackType OpenRCT2TrackTypeToRCT2(track_type_t origTrackType)
// This function is safe to run this way round.
return OpenRCT2FlatTrackTypeToRCT12(origTrackType);
}
static FootpathMapping _footpathMappings[] = {
// RCT2 mappings
{ "PATHASH ", "rct2.footpath_surface.ash", "rct2.footpath_surface.queue_yellow", "rct2.footpath_railings.bamboo_black" },
{ "PATHCRZY", "rct2.footpath_surface.crazy_paving", "rct2.footpath_surface.queue_yellow",
"rct2.footpath_railings.concrete" },
{ "PATHDIRT", "rct2.footpath_surface.dirt", "rct2.footpath_surface.queue_yellow", "rct2.footpath_railings.bamboo_brown" },
{ "PATHSPCE", "rct2.footpath_surface.tarmac_red", "rct2.footpath_surface.queue_red", "rct2.footpath_railings.space" },
{ "ROAD ", "rct2.footpath_surface.road", "rct2.footpath_surface.queue_blue", "rct2.footpath_railings.wood" },
{ "TARMACB ", "rct2.footpath_surface.tarmac_brown", "rct2.footpath_surface.queue_yellow",
"rct2.footpath_railings.concrete" },
{ "TARMACG ", "rct2.footpath_surface.tarmac_green", "rct2.footpath_surface.queue_green",
"rct2.footpath_railings.concrete_green" },
{ "TARMAC ", "rct2.footpath_surface.tarmac", "rct2.footpath_surface.queue_blue", "rct2.footpath_railings.wood" },
// Time Twister
{ "1920PATH", "rct2tt.footpath_surface.pavement", "rct2tt.footpath_surface.queue_pavement",
"rct2tt.footpath_railings.pavement" },
{ "FUTRPATH", "rct2tt.footpath_surface.circuitboard", "rct2tt.footpath_surface.queue_circuitboard",
"rct2tt.footpath_railings.circuitboard" },
{ "FUTRPAT2", "rct2tt.footpath_surface.circuitboard", "rct2tt.footpath_surface.queue_circuitboard",
"openrct2.footpath_railings.invisible" },
{ "JURRPATH", "rct2tt.footpath_surface.rocky", "rct2.footpath_surface.queue_yellow", "rct2tt.footpath_railings.rocky" },
{ "MEDIPATH", "rct2tt.footpath_surface.medieval", "rct2.footpath_surface.queue_yellow",
"rct2tt.footpath_railings.medieval" },
{ "MYTHPATH", "rct2tt.footpath_surface.mosaic", "rct2.footpath_surface.queue_yellow",
"rct2tt.footpath_railings.balustrade" },
{ "RANBPATH", "rct2tt.footpath_surface.rainbow", "rct2tt.footpath_surface.queue_rainbow",
"rct2tt.footpath_railings.rainbow" },
// RCT 1 mappings (for reverse lookup)
{ "PATHASH ", "rct1aa.footpath_surface.ash", "rct1aa.footpath_surface.queue_yellow",
"rct2.footpath_railings.bamboo_black" },
{ "PATHCRZY", "rct1.footpath_surface.crazy_paving", "rct1aa.footpath_surface.queue_yellow",
"rct2.footpath_railings.concrete" },
{ "PATHDIRT", "rct1.footpath_surface.dirt", "rct1aa.footpath_surface.queue_yellow", "rct2.footpath_railings.bamboo_brown" },
{ "PATHSPCE", "rct1aa.footpath_surface.tarmac_red", "rct1.footpath_surface.queue_red", "rct1ll.footpath_railings.space" },
{ "TARMACB ", "rct1aa.footpath_surface.tarmac_brown", "rct1aa.footpath_surface.queue_yellow",
"rct2.footpath_railings.concrete" },
{ "TARMACG ", "rct1aa.footpath_surface.tarmac_green", "rct1aa.footpath_surface.queue_green",
"rct2.footpath_railings.concrete_green" },
{ "TARMAC ", "rct1.footpath_surface.tarmac", "rct1.footpath_surface.queue_blue", "rct2.footpath_railings.wood" },
{ "PATHCRZY", "rct1.footpath_surface.tiles_brown", "rct1aa.footpath_surface.queue_yellow",
"rct2.footpath_railings.concrete" },
{ "PATHCRZY", "rct1aa.footpath_surface.tiles_grey", "rct1.footpath_surface.queue_blue", "rct2.footpath_railings.concrete" },
{ "PATHCRZY", "rct1ll.footpath_surface.tiles_red", "rct1.footpath_surface.queue_red", "rct2.footpath_railings.concrete" },
{ "PATHCRZY", "rct1ll.footpath_surface.tiles_green", "rct1aa.footpath_surface.queue_green",
"rct2.footpath_railings.concrete" },
};
const FootpathMapping* GetFootpathSurfaceId(const ObjectEntryDescriptor& desc, bool ideallyLoaded, bool isQueue)
{
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
auto name = desc.Entry.GetName();
for (const auto& mapping : _footpathMappings)
{
if (mapping.Original == name)
{
if (ideallyLoaded)
{
auto obj = objManager.GetLoadedObject(
ObjectEntryDescriptor(isQueue ? mapping.QueueSurface : mapping.NormalSurface));
if (obj == nullptr)
continue;
}
return &mapping;
}
}
return nullptr;
}
std::optional<rct_object_entry> GetBestObjectEntryForSurface(std::string_view surface, std::string_view railings)
{
rct_object_entry result;
std::memset(&result, 0, sizeof(result));
result.SetType(ObjectType::Paths);
auto foundMapping = false;
for (const auto& mapping : _footpathMappings)
{
if (surface == mapping.NormalSurface || surface == mapping.QueueSurface)
{
if (railings == mapping.Railing)
{
// Best match found
foundMapping = true;
result.SetName(mapping.Original);
break;
}
if (!foundMapping)
{
// Found a mapping, but keep searching to see if there is a closer match
foundMapping = true;
result.SetName(mapping.Original);
}
}
}
if (foundMapping)
return result;
return {};
}

View File

@@ -1077,3 +1077,15 @@ RCT12TrackType OpenRCT2TrackTypeToRCT2(track_type_t origTrackType);
* Handles single and multi-byte strings.
*/
size_t GetRCT2StringBufferLen(const char* buffer, size_t maxBufferLen);
struct FootpathMapping
{
std::string_view Original;
std::string_view NormalSurface;
std::string_view QueueSurface;
std::string_view Railing;
};
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);

View File

@@ -80,7 +80,7 @@ bool T6Exporter::SaveTrack(OpenRCT2::IStream* stream)
tempStream.WriteArray(_trackDesign->track_rail_colour, RCT12_NUM_COLOUR_SCHEMES);
tempStream.WriteArray(_trackDesign->track_support_colour, RCT12_NUM_COLOUR_SCHEMES);
tempStream.WriteValue<uint32_t>(_trackDesign->flags2);
tempStream.Write(&_trackDesign->vehicle_object, sizeof(rct_object_entry));
tempStream.Write(&_trackDesign->vehicle_object.Entry, sizeof(rct_object_entry));
tempStream.WriteValue<uint8_t>(_trackDesign->space_required_x);
tempStream.WriteValue<uint8_t>(_trackDesign->space_required_y);
tempStream.WriteArray(_trackDesign->vehicle_additional_colour, RCT2_MAX_CARS_PER_TRAIN);
@@ -123,7 +123,7 @@ bool T6Exporter::SaveTrack(OpenRCT2::IStream* stream)
for (const auto& sceneryElement : _trackDesign->scenery_elements)
{
tempStream.Write(&sceneryElement.scenery_object, sizeof(rct_object_entry));
tempStream.Write(&sceneryElement.scenery_object.Entry, sizeof(rct_object_entry));
tempStream.WriteValue<int8_t>(sceneryElement.x);
tempStream.WriteValue<int8_t>(sceneryElement.y);
tempStream.WriteValue<int8_t>(sceneryElement.z);

View File

@@ -200,7 +200,7 @@ public:
rct_td6_scenery_element t6SceneryElement{};
_stream.Read(&t6SceneryElement, sizeof(rct_td6_scenery_element));
TrackDesignSceneryElement sceneryElement{};
sceneryElement.scenery_object = t6SceneryElement.scenery_object;
sceneryElement.scenery_object = ObjectEntryDescriptor(t6SceneryElement.scenery_object);
sceneryElement.x = t6SceneryElement.x;
sceneryElement.y = t6SceneryElement.y;
sceneryElement.z = t6SceneryElement.z;

View File

@@ -41,6 +41,7 @@
#include "../management/Finance.h"
#include "../network/network.h"
#include "../object/FootpathObject.h"
#include "../object/FootpathSurfaceObject.h"
#include "../object/ObjectList.h"
#include "../object/ObjectManager.h"
#include "../object/ObjectRepository.h"
@@ -648,37 +649,133 @@ static void track_design_load_scenery_objects(TrackDesign* td6)
// Load scenery objects
for (const auto& scenery : td6->scenery_elements)
{
const rct_object_entry* sceneryEntry = &scenery.scenery_object;
object_manager_load_object(sceneryEntry);
if (scenery.scenery_object.HasValue())
{
objectManager.LoadObject(td6->vehicle_object);
}
}
}
struct TrackSceneryEntry
{
ObjectType Type = ObjectType::None;
ObjectEntryIndex Index = OBJECT_ENTRY_INDEX_NULL;
ObjectEntryIndex SecondaryIndex = OBJECT_ENTRY_INDEX_NULL; // For footpath railing
};
static ObjectEntryIndex TrackDesignGetDefaultSurfaceIndex(bool isQueue)
{
for (ObjectEntryIndex i = 0; i < MAX_FOOTPATH_SURFACE_OBJECTS; i++)
{
auto footpathSurfaceObj = GetPathSurfaceEntry(i);
if (footpathSurfaceObj != nullptr)
{
if (footpathSurfaceObj->Flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR)
{
continue;
}
if (isQueue != ((footpathSurfaceObj->Flags & FOOTPATH_ENTRY_FLAG_IS_QUEUE) != 0))
{
continue;
}
return i;
}
}
return OBJECT_ENTRY_INDEX_NULL;
}
static ObjectEntryIndex TrackDesignGetDefaultRailingIndex()
{
for (ObjectEntryIndex i = 0; i < MAX_FOOTPATH_RAILINGS_OBJECTS; i++)
{
auto footpathRailingsObj = GetPathRailingsEntry(i);
if (footpathRailingsObj != nullptr)
{
return i;
}
}
return OBJECT_ENTRY_INDEX_NULL;
}
static std::optional<TrackSceneryEntry> TrackDesignPlaceSceneryElementGetEntry(const TrackDesignSceneryElement& scenery)
{
TrackSceneryEntry result;
auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager();
if (scenery.scenery_object.GetType() == ObjectType::Paths)
{
auto footpathMapping = GetFootpathSurfaceId(scenery.scenery_object, true, scenery.IsQueue());
if (footpathMapping == nullptr)
{
// Check if legacy path object is loaded
auto obj = objectMgr.GetLoadedObject(scenery.scenery_object);
if (obj != nullptr)
{
result.Type = obj->GetObjectType();
result.Index = objectMgr.GetLoadedObjectEntryIndex(obj);
}
else
{
result.Type = ObjectType::FootpathSurface;
}
}
else
{
result.Type = ObjectType::FootpathSurface;
result.Index = objectMgr.GetLoadedObjectEntryIndex(
ObjectEntryDescriptor(scenery.IsQueue() ? footpathMapping->QueueSurface : footpathMapping->NormalSurface));
result.SecondaryIndex = objectMgr.GetLoadedObjectEntryIndex(ObjectEntryDescriptor(footpathMapping->Railing));
}
if (result.Index == OBJECT_ENTRY_INDEX_NULL)
result.Index = TrackDesignGetDefaultSurfaceIndex(scenery.IsQueue());
if (result.SecondaryIndex == OBJECT_ENTRY_INDEX_NULL)
result.SecondaryIndex = TrackDesignGetDefaultRailingIndex();
if (result.Index == OBJECT_ENTRY_INDEX_NULL || result.SecondaryIndex == OBJECT_ENTRY_INDEX_NULL)
{
_trackDesignPlaceStateSceneryUnavailable = true;
return {};
}
}
else
{
auto obj = objectMgr.GetLoadedObject(scenery.scenery_object);
if (obj != nullptr)
{
result.Type = obj->GetObjectType();
result.Index = objectMgr.GetLoadedObjectEntryIndex(obj);
}
else
{
_trackDesignPlaceStateSceneryUnavailable = true;
return {};
}
}
return result;
}
/**
*
* rct2: 0x006D247A
*/
static void track_design_mirror_scenery(TrackDesign* td6)
{
auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager();
for (auto& scenery : td6->scenery_elements)
{
ObjectType entry_type{ 0 };
ObjectEntryIndex entryIndex{ 0 };
if (!find_object_in_entry_group(&scenery.scenery_object, &entry_type, &entryIndex))
{
entry_type = scenery.scenery_object.GetType();
if (entry_type != ObjectType::Paths)
{
continue;
}
auto entryInfo = TrackDesignPlaceSceneryElementGetEntry(scenery);
if (!entryInfo)
continue;
entryIndex = 0;
}
switch (entry_type)
auto obj = objectMgr.GetLoadedObject(entryInfo->Type, entryInfo->Index);
switch (obj->GetObjectType())
{
case ObjectType::LargeScenery:
{
auto* sceneryEntry = static_cast<LargeSceneryEntry*>(object_entry_get_chunk(entry_type, entryIndex));
auto* sceneryEntry = reinterpret_cast<const LargeSceneryEntry*>(obj->GetLegacyData());
int16_t x1 = 0, x2 = 0, y1 = 0, y2 = 0;
for (rct_large_scenery_tile* tile = sceneryEntry->tiles; tile->x_offset != -1; tile++)
{
@@ -723,7 +820,7 @@ static void track_design_mirror_scenery(TrackDesign* td6)
}
case ObjectType::SmallScenery:
{
auto* sceneryEntry = static_cast<SmallSceneryEntry*>(object_entry_get_chunk(entry_type, entryIndex));
auto* sceneryEntry = reinterpret_cast<const SmallSceneryEntry*>(obj->GetLegacyData());
scenery.y = -scenery.y;
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_DIAGONAL))
@@ -753,6 +850,7 @@ static void track_design_mirror_scenery(TrackDesign* td6)
break;
}
case ObjectType::Paths:
case ObjectType::FootpathSurface:
{
scenery.y = -scenery.y;
@@ -768,7 +866,6 @@ static void track_design_mirror_scenery(TrackDesign* td6)
break;
}
default:
// This switch processes only ObjectType for Scenery items.
break;
}
}
@@ -865,54 +962,11 @@ static void track_design_update_max_min_coordinates(const CoordsXYZ& coords)
std::max(_trackPreviewMax.z, coords.z) };
}
static bool TrackDesignPlaceSceneryElementGetEntry(
ObjectType& entry_type, ObjectEntryIndex& entry_index, const TrackDesignSceneryElement& scenery)
{
if (!find_object_in_entry_group(&scenery.scenery_object, &entry_type, &entry_index))
{
entry_type = scenery.scenery_object.GetType();
if (entry_type != ObjectType::Paths)
{
_trackDesignPlaceStateSceneryUnavailable = true;
return true;
}
if (gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER)
{
_trackDesignPlaceStateSceneryUnavailable = true;
return true;
}
entry_index = 0;
for (; entry_index < object_entry_group_counts[EnumValue(ObjectType::Paths)]; entry_index++)
{
const auto* legacyPathEntry = GetLegacyFootpathEntry(entry_index);
if (legacyPathEntry == nullptr)
{
return true;
}
const auto& surfaceDescriptor = legacyPathEntry->GetPathSurfaceDescriptor();
if (surfaceDescriptor.IsEditorOnly())
{
return true;
}
}
if (entry_index == object_entry_group_counts[EnumValue(ObjectType::Paths)])
{
_trackDesignPlaceStateSceneryUnavailable = true;
return true;
}
}
return false;
}
static bool TrackDesignPlaceSceneryElementRemoveGhost(
CoordsXY mapCoord, const TrackDesignSceneryElement& scenery, uint8_t rotation, int32_t originZ)
{
ObjectType entry_type;
ObjectEntryIndex entry_index;
if (TrackDesignPlaceSceneryElementGetEntry(entry_type, entry_index, scenery))
auto entryInfo = TrackDesignPlaceSceneryElementGetEntry(scenery);
if (!entryInfo)
{
return true;
}
@@ -927,14 +981,14 @@ static bool TrackDesignPlaceSceneryElementRemoveGhost(
const uint32_t flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND
| GAME_COMMAND_FLAG_GHOST;
std::unique_ptr<GameAction> ga;
switch (entry_type)
switch (entryInfo->Type)
{
case ObjectType::SmallScenery:
{
uint8_t quadrant = (scenery.flags >> 2) + _currentTrackPieceDirection;
quadrant &= 3;
auto* sceneryEntry = get_small_scenery_entry(entry_index);
auto* sceneryEntry = get_small_scenery_entry(entryInfo->Index);
if (!(!sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_FULL_TILE) && sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_DIAGONAL))
&& sceneryEntry->HasFlag(
SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS))
@@ -942,7 +996,7 @@ static bool TrackDesignPlaceSceneryElementRemoveGhost(
quadrant = 0;
}
ga = std::make_unique<SmallSceneryRemoveAction>(CoordsXYZ{ mapCoord.x, mapCoord.y, z }, quadrant, entry_index);
ga = std::make_unique<SmallSceneryRemoveAction>(CoordsXYZ{ mapCoord.x, mapCoord.y, z }, quadrant, entryInfo->Index);
break;
}
case ObjectType::LargeScenery:
@@ -952,6 +1006,7 @@ static bool TrackDesignPlaceSceneryElementRemoveGhost(
ga = std::make_unique<WallRemoveAction>(CoordsXYZD{ mapCoord.x, mapCoord.y, z, sceneryRotation });
break;
case ObjectType::Paths:
case ObjectType::FootpathSurface:
ga = std::make_unique<FootpathRemoveAction>(CoordsXYZ{ mapCoord.x, mapCoord.y, z });
break;
default:
@@ -970,10 +1025,7 @@ static bool TrackDesignPlaceSceneryElementGetPlaceZ(const TrackDesignSceneryElem
_trackDesignPlaceSceneryZ = z;
}
ObjectType entry_type;
ObjectEntryIndex entry_index;
TrackDesignPlaceSceneryElementGetEntry(entry_type, entry_index, scenery);
TrackDesignPlaceSceneryElementGetEntry(scenery);
return true;
}
@@ -1007,9 +1059,8 @@ static std::optional<money32> TrackDesignPlaceSceneryElement(
|| _trackDesignPlaceOperation == PTD_OPERATION_PLACE_GHOST
|| _trackDesignPlaceOperation == PTD_OPERATION_PLACE_TRACK_PREVIEW)
{
ObjectType entry_type;
ObjectEntryIndex entry_index;
if (TrackDesignPlaceSceneryElementGetEntry(entry_type, entry_index, scenery))
auto entryInfo = TrackDesignPlaceSceneryElementGetEntry(scenery);
if (!entryInfo)
{
return 0;
}
@@ -1019,7 +1070,7 @@ static std::optional<money32> TrackDesignPlaceSceneryElement(
uint8_t flags;
uint8_t quadrant;
switch (entry_type)
switch (entryInfo->Type)
{
case ObjectType::SmallScenery:
{
@@ -1059,7 +1110,7 @@ static std::optional<money32> TrackDesignPlaceSceneryElement(
gGameCommandErrorTitle = STR_CANT_POSITION_THIS_HERE;
auto smallSceneryPlace = SmallSceneryPlaceAction(
{ mapCoord.x, mapCoord.y, z, rotation }, quadrant, entry_index, scenery.primary_colour,
{ mapCoord.x, mapCoord.y, z, rotation }, quadrant, entryInfo->Index, scenery.primary_colour,
scenery.secondary_colour);
smallSceneryPlace.SetFlags(flags);
@@ -1105,7 +1156,8 @@ static std::optional<money32> TrackDesignPlaceSceneryElement(
flags |= GAME_COMMAND_FLAG_REPLAY;
}
auto sceneryPlaceAction = LargeSceneryPlaceAction(
{ mapCoord.x, mapCoord.y, z, rotation }, entry_index, scenery.primary_colour, scenery.secondary_colour);
{ mapCoord.x, mapCoord.y, z, rotation }, entryInfo->Index, scenery.primary_colour,
scenery.secondary_colour);
sceneryPlaceAction.SetFlags(flags);
auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&sceneryPlaceAction)
: GameActions::QueryNested(&sceneryPlaceAction);
@@ -1148,7 +1200,7 @@ static std::optional<money32> TrackDesignPlaceSceneryElement(
flags |= GAME_COMMAND_FLAG_REPLAY;
}
auto wallPlaceAction = WallPlaceAction(
entry_index, { mapCoord.x, mapCoord.y, z }, rotation, scenery.primary_colour, scenery.secondary_colour,
entryInfo->Index, { mapCoord.x, mapCoord.y, z }, rotation, scenery.primary_colour, scenery.secondary_colour,
(scenery.flags & 0xFC) >> 2);
wallPlaceAction.SetFlags(flags);
auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&wallPlaceAction)
@@ -1158,6 +1210,7 @@ static std::optional<money32> TrackDesignPlaceSceneryElement(
break;
}
case ObjectType::Paths:
case ObjectType::FootpathSurface:
if (_trackDesignPlaceOperation == PTD_OPERATION_GET_PLACE_Z)
{
return 0;
@@ -1196,12 +1249,14 @@ static std::optional<money32> TrackDesignPlaceSceneryElement(
}
uint8_t slope = ((bh >> 5) & 0x3) | ((bh >> 2) & 0x4);
uint8_t edges = bh & 0xF;
PathConstructFlags constructFlags = PathConstructFlag::IsLegacyPathObject;
PathConstructFlags constructFlags = 0;
if (isQueue)
constructFlags |= PathConstructFlag::IsQueue;
if (entryInfo->Type == ObjectType::Paths)
constructFlags |= PathConstructFlag::IsLegacyPathObject;
auto footpathPlaceAction = FootpathPlaceFromTrackAction(
{ mapCoord.x, mapCoord.y, z * COORDS_Z_STEP }, slope, entry_index, OBJECT_ENTRY_INDEX_NULL, edges,
constructFlags);
{ mapCoord.x, mapCoord.y, z * COORDS_Z_STEP }, slope, entryInfo->Index, entryInfo->SecondaryIndex,
edges, constructFlags);
footpathPlaceAction.SetFlags(flags);
auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&footpathPlaceAction)
: GameActions::QueryNested(&footpathPlaceAction);
@@ -1903,7 +1958,13 @@ static bool track_design_place_preview(TrackDesign* td6, money32* cost, Ride** o
return false;
ride->custom_name = {};
ride->entrance_style = td6->entrance_style;
auto stationIdentifier = GetStationIdentifierFromStyle(td6->entrance_style);
ride->entrance_style = objManager.GetLoadedObjectEntryIndex(stationIdentifier);
if (ride->entrance_style == OBJECT_ENTRY_INDEX_NULL)
{
ride->entrance_style = gLastEntranceStyle;
}
for (int32_t i = 0; i < RCT12_NUM_COLOUR_SCHEMES; i++)
{

View File

@@ -32,13 +32,13 @@ struct TrackDesignEntranceElement
/* Track Scenery entry size: 0x16 */
struct TrackDesignSceneryElement
{
rct_object_entry scenery_object; // 0x00
int8_t x; // 0x10
int8_t y; // 0x11
int8_t z; // 0x12
uint8_t flags; // 0x13 direction quadrant tertiary colour
uint8_t primary_colour; // 0x14
uint8_t secondary_colour; // 0x15
ObjectEntryDescriptor scenery_object;
int8_t x;
int8_t y;
int8_t z;
uint8_t flags;
uint8_t primary_colour;
uint8_t secondary_colour;
bool IsQueue() const
{

View File

@@ -14,7 +14,12 @@
#include "../interface/Viewport.h"
#include "../localisation/Localisation.h"
#include "../localisation/StringIds.h"
#include "../object/FootpathObject.h"
#include "../object/FootpathRailingsObject.h"
#include "../object/FootpathSurfaceObject.h"
#include "../object/LargeSceneryObject.h"
#include "../object/ObjectList.h"
#include "../object/ObjectManager.h"
#include "../util/SawyerCoding.h"
#include "../util/Util.h"
#include "../windows/Intent.h"
@@ -41,9 +46,25 @@ ride_id_t gTrackDesignSaveRideIndex = RIDE_ID_NULL;
std::vector<const TileElement*> _trackSavedTileElements;
std::vector<TrackDesignSceneryElement> _trackSavedTileElementsDesc;
struct TrackDesignAddStatus
{
bool IsSuccess{};
rct_string_id Message{};
static TrackDesignAddStatus Success()
{
return { true, rct_string_id() };
}
static TrackDesignAddStatus Fail(rct_string_id message)
{
return { false, message };
}
};
static bool track_design_save_should_select_scenery_around(ride_id_t rideIndex, TileElement* tileElement);
static void track_design_save_select_nearby_scenery_for_tile(ride_id_t rideIndex, int32_t cx, int32_t cy);
static bool track_design_save_add_tile_element(
static TrackDesignAddStatus track_design_save_add_tile_element(
ViewportInteractionItem interactionType, const CoordsXY& loc, TileElement* tileElement);
static void track_design_save_remove_tile_element(
ViewportInteractionItem interactionType, const CoordsXY& loc, TileElement* tileElement);
@@ -72,11 +93,10 @@ void track_design_save_select_tile_element(
{
if (collect)
{
if (!track_design_save_add_tile_element(interactionType, loc, tileElement))
auto result = track_design_save_add_tile_element(interactionType, loc, tileElement);
if (!result.IsSuccess)
{
context_show_error(
STR_SAVE_TRACK_SCENERY_UNABLE_TO_SELECT_ADDITIONAL_ITEM_OF_SCENERY,
STR_SAVE_TRACK_SCENERY_TOO_MANY_ITEMS_SELECTED, {});
context_show_error(STR_SAVE_TRACK_SCENERY_UNABLE_TO_SELECT_ADDITIONAL_ITEM_OF_SCENERY, result.Message, {});
}
}
}
@@ -188,16 +208,18 @@ static void track_design_save_push_tile_element(const CoordsXY& loc, TileElement
}
}
/**
*
* rct2: 0x006D2FA7
*/
static bool track_design_is_supported_object(const Object* obj)
{
const auto& entry = obj->GetObjectEntry();
return !entry.IsEmpty();
}
static void track_design_save_push_tile_element_desc(
const rct_object_entry& entry, const CoordsXYZ& loc, uint8_t flags, uint8_t primaryColour, uint8_t secondaryColour)
{
auto tileLoc = TileCoordsXYZ(loc);
TrackDesignSceneryElement item{};
item.scenery_object = entry;
item.scenery_object = ObjectEntryDescriptor(entry);
item.x = tileLoc.x;
item.y = tileLoc.y;
item.z = tileLoc.z;
@@ -208,96 +230,146 @@ static void track_design_save_push_tile_element_desc(
_trackSavedTileElementsDesc.push_back(std::move(item));
}
static void track_design_save_add_scenery(const CoordsXY& loc, SmallSceneryElement* sceneryElement)
static void track_design_save_push_tile_element_desc(
const Object* obj, const CoordsXYZ& loc, uint8_t flags, uint8_t primaryColour, uint8_t secondaryColour)
{
int32_t entryType = sceneryElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::SmallScenery, entryType);
const auto& entry = obj->GetObjectEntry();
if (entry.IsEmpty())
{
// Unsupported, should have been blocked earlier
assert(false);
}
uint8_t flags = 0;
flags |= sceneryElement->GetDirection();
flags |= sceneryElement->GetSceneryQuadrant() << 2;
uint8_t primaryColour = sceneryElement->GetPrimaryColour();
uint8_t secondaryColour = sceneryElement->GetSecondaryColour();
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(sceneryElement));
track_design_save_push_tile_element_desc(
entry->GetObjectEntry(), { loc.x, loc.y, sceneryElement->GetBaseZ() }, flags, primaryColour, secondaryColour);
track_design_save_push_tile_element_desc(entry, loc, flags, primaryColour, secondaryColour);
}
static void track_design_save_add_large_scenery(const CoordsXY& loc, LargeSceneryElement* tileElement)
static TrackDesignAddStatus track_design_save_add_scenery(const CoordsXY& loc, SmallSceneryElement* sceneryElement)
{
rct_large_scenery_tile *sceneryTiles, *tile;
int32_t direction, sequence;
if (tileElement == nullptr)
auto entryIndex = sceneryElement->GetEntryIndex();
auto obj = object_entry_get_object(ObjectType::SmallScenery, entryIndex);
if (obj != nullptr && track_design_is_supported_object(obj))
{
log_warning("Null tile element");
return;
uint8_t flags = 0;
flags |= sceneryElement->GetDirection();
flags |= sceneryElement->GetSceneryQuadrant() << 2;
uint8_t primaryColour = sceneryElement->GetPrimaryColour();
uint8_t secondaryColour = sceneryElement->GetSecondaryColour();
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(sceneryElement));
track_design_save_push_tile_element_desc(
obj, { loc.x, loc.y, sceneryElement->GetBaseZ() }, flags, primaryColour, secondaryColour);
return TrackDesignAddStatus::Success();
}
int32_t entryType = tileElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::LargeScenery, entryType);
sceneryTiles = get_large_scenery_entry(entryType)->tiles;
return TrackDesignAddStatus::Fail(STR_UNSUPPORTED_OBJECT_FORMAT);
}
int32_t z = tileElement->base_height;
direction = tileElement->GetDirection();
sequence = tileElement->GetSequenceIndex();
auto sceneryOrigin = map_large_scenery_get_origin(
{ loc.x, loc.y, z << 3, static_cast<Direction>(direction) }, sequence, nullptr);
if (!sceneryOrigin.has_value())
static TrackDesignAddStatus track_design_save_add_large_scenery(const CoordsXY& loc, LargeSceneryElement* tileElement)
{
auto entryIndex = tileElement->GetEntryIndex();
auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager();
auto obj = objectMgr.GetLoadedObject(ObjectType::LargeScenery, entryIndex);
if (obj != nullptr && track_design_is_supported_object(obj))
{
return;
}
auto sceneryEntry = reinterpret_cast<const LargeSceneryEntry*>(obj->GetLegacyData());
auto sceneryTiles = sceneryEntry->tiles;
// Iterate through each tile of the large scenery element
sequence = 0;
for (tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++)
{
CoordsXY offsetPos{ tile->x_offset, tile->y_offset };
auto rotatedOffsetPos = offsetPos.Rotate(direction);
int32_t z = tileElement->base_height;
auto direction = tileElement->GetDirection();
auto sequence = tileElement->GetSequenceIndex();
CoordsXYZ tileLoc = { sceneryOrigin->x + rotatedOffsetPos.x, sceneryOrigin->y + rotatedOffsetPos.y,
sceneryOrigin->z + tile->z_offset };
auto largeElement = map_get_large_scenery_segment({ tileLoc, static_cast<Direction>(direction) }, sequence);
if (largeElement != nullptr)
auto sceneryOrigin = map_large_scenery_get_origin(
{ loc.x, loc.y, z << 3, static_cast<Direction>(direction) }, sequence, nullptr);
if (!sceneryOrigin.has_value())
{
if (sequence == 0)
{
uint8_t flags = largeElement->GetDirection();
uint8_t primaryColour = largeElement->GetPrimaryColour();
uint8_t secondaryColour = largeElement->GetSecondaryColour();
return TrackDesignAddStatus::Success();
}
track_design_save_push_tile_element_desc(
entry->GetObjectEntry(), tileLoc, flags, primaryColour, secondaryColour);
// Iterate through each tile of the large scenery element
sequence = 0;
for (auto tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++)
{
CoordsXY offsetPos{ tile->x_offset, tile->y_offset };
auto rotatedOffsetPos = offsetPos.Rotate(direction);
CoordsXYZ tileLoc = { sceneryOrigin->x + rotatedOffsetPos.x, sceneryOrigin->y + rotatedOffsetPos.y,
sceneryOrigin->z + tile->z_offset };
auto largeElement = map_get_large_scenery_segment({ tileLoc, static_cast<Direction>(direction) }, sequence);
if (largeElement != nullptr)
{
if (sequence == 0)
{
uint8_t flags = largeElement->GetDirection();
uint8_t primaryColour = largeElement->GetPrimaryColour();
uint8_t secondaryColour = largeElement->GetSecondaryColour();
track_design_save_push_tile_element_desc(obj, tileLoc, flags, primaryColour, secondaryColour);
}
track_design_save_push_tile_element({ tileLoc.x, tileLoc.y }, reinterpret_cast<TileElement*>(largeElement));
}
track_design_save_push_tile_element({ tileLoc.x, tileLoc.y }, reinterpret_cast<TileElement*>(largeElement));
}
return TrackDesignAddStatus::Success();
}
return TrackDesignAddStatus::Fail(STR_UNSUPPORTED_OBJECT_FORMAT);
}
static TrackDesignAddStatus track_design_save_add_wall(const CoordsXY& loc, WallElement* wallElement)
{
auto entryIndex = wallElement->GetEntryIndex();
auto obj = object_entry_get_object(ObjectType::Walls, entryIndex);
if (obj != nullptr && track_design_is_supported_object(obj))
{
uint8_t flags = 0;
flags |= wallElement->GetDirection();
flags |= wallElement->GetTertiaryColour() << 2;
uint8_t secondaryColour = wallElement->GetSecondaryColour();
uint8_t primaryColour = wallElement->GetPrimaryColour();
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(wallElement));
track_design_save_push_tile_element_desc(
obj, { loc.x, loc.y, wallElement->GetBaseZ() }, flags, primaryColour, secondaryColour);
return TrackDesignAddStatus::Success();
}
return TrackDesignAddStatus::Fail(STR_UNSUPPORTED_OBJECT_FORMAT);
}
static std::optional<rct_object_entry> track_design_save_footpath_get_best_entry(PathElement* pathElement)
{
rct_object_entry pathEntry;
auto legacyPathObj = pathElement->GetLegacyPathEntry();
if (legacyPathObj != nullptr)
{
pathEntry = legacyPathObj->GetObjectEntry();
if (!pathEntry.IsEmpty())
{
return pathEntry;
}
}
else
{
auto surfaceEntry = pathElement->GetSurfaceEntry();
if (surfaceEntry != nullptr)
{
auto surfaceId = surfaceEntry->GetIdentifier();
auto railingsEntry = pathElement->GetRailingsEntry();
auto railingsId = railingsEntry == nullptr ? "" : railingsEntry->GetIdentifier();
return GetBestObjectEntryForSurface(surfaceId, railingsId);
}
}
return {};
}
static void track_design_save_add_wall(const CoordsXY& loc, WallElement* wallElement)
static TrackDesignAddStatus track_design_save_add_footpath(const CoordsXY& loc, PathElement* pathElement)
{
int32_t entryType = wallElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::Walls, entryType);
uint8_t flags = 0;
flags |= wallElement->GetDirection();
flags |= wallElement->GetTertiaryColour() << 2;
uint8_t secondaryColour = wallElement->GetSecondaryColour();
uint8_t primaryColour = wallElement->GetPrimaryColour();
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(wallElement));
track_design_save_push_tile_element_desc(
entry->GetObjectEntry(), { loc.x, loc.y, wallElement->GetBaseZ() }, flags, primaryColour, secondaryColour);
}
static void track_design_save_add_footpath(const CoordsXY& loc, PathElement* pathElement)
{
int32_t entryType = pathElement->GetLegacyPathEntryIndex();
auto entry = object_entry_get_object(ObjectType::Paths, entryType);
auto pathEntry = track_design_save_footpath_get_best_entry(pathElement);
if (!pathElement)
{
return TrackDesignAddStatus::Fail(STR_UNSUPPORTED_OBJECT_FORMAT);
}
uint8_t flags = 0;
flags |= pathElement->GetEdges();
@@ -308,37 +380,34 @@ static void track_design_save_add_footpath(const CoordsXY& loc, PathElement* pat
flags |= 1 << 7;
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(pathElement));
track_design_save_push_tile_element_desc(entry->GetObjectEntry(), { loc.x, loc.y, pathElement->GetBaseZ() }, flags, 0, 0);
track_design_save_push_tile_element_desc(*pathEntry, { loc.x, loc.y, pathElement->GetBaseZ() }, flags, 0, 0);
return TrackDesignAddStatus::Success();
}
/**
*
* rct2: 0x006D2B3C
*/
static bool track_design_save_add_tile_element(
static TrackDesignAddStatus track_design_save_add_tile_element(
ViewportInteractionItem interactionType, const CoordsXY& loc, TileElement* tileElement)
{
if (!track_design_save_can_add_tile_element(tileElement))
{
return false;
return TrackDesignAddStatus::Fail(STR_SAVE_TRACK_SCENERY_TOO_MANY_ITEMS_SELECTED);
}
switch (interactionType)
{
case ViewportInteractionItem::Scenery:
track_design_save_add_scenery(loc, tileElement->AsSmallScenery());
return true;
return track_design_save_add_scenery(loc, tileElement->AsSmallScenery());
case ViewportInteractionItem::LargeScenery:
track_design_save_add_large_scenery(loc, tileElement->AsLargeScenery());
return true;
return track_design_save_add_large_scenery(loc, tileElement->AsLargeScenery());
case ViewportInteractionItem::Wall:
track_design_save_add_wall(loc, tileElement->AsWall());
return true;
return track_design_save_add_wall(loc, tileElement->AsWall());
case ViewportInteractionItem::Footpath:
track_design_save_add_footpath(loc, tileElement->AsPath());
return true;
return track_design_save_add_footpath(loc, tileElement->AsPath());
default:
return false;
return TrackDesignAddStatus::Fail(STR_UNKNOWN_OBJECT_TYPE);
}
}
@@ -370,7 +439,7 @@ static void track_design_save_pop_tile_element(const CoordsXY& loc, TileElement*
*
* rct2: 0x006D2FDD
*/
static void track_design_save_pop_tile_element_desc(const rct_object_entry& entry, const CoordsXYZ& loc, uint8_t flags)
static void track_design_save_pop_tile_element_desc(const ObjectEntryDescriptor& entry, const CoordsXYZ& loc, uint8_t flags)
{
size_t removeIndex = SIZE_MAX;
auto tileLoc = TileCoordsXYZ(loc);
@@ -399,93 +468,101 @@ static void track_design_save_pop_tile_element_desc(const rct_object_entry& entr
static void track_design_save_remove_scenery(const CoordsXY& loc, SmallSceneryElement* sceneryElement)
{
int32_t entryType = sceneryElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::SmallScenery, entryType);
auto entryIndex = sceneryElement->GetEntryIndex();
auto obj = object_entry_get_object(ObjectType::SmallScenery, entryIndex);
if (obj != nullptr)
{
uint8_t flags = 0;
flags |= sceneryElement->GetDirection();
flags |= sceneryElement->GetSceneryQuadrant() << 2;
uint8_t flags = 0;
flags |= sceneryElement->GetDirection();
flags |= sceneryElement->GetSceneryQuadrant() << 2;
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(sceneryElement));
track_design_save_pop_tile_element_desc(entry->GetObjectEntry(), { loc.x, loc.y, sceneryElement->GetBaseZ() }, flags);
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(sceneryElement));
track_design_save_pop_tile_element_desc(obj->GetDescriptor(), { loc.x, loc.y, sceneryElement->GetBaseZ() }, flags);
}
}
static void track_design_save_remove_large_scenery(const CoordsXY& loc, LargeSceneryElement* tileElement)
{
rct_large_scenery_tile *sceneryTiles, *tile;
int32_t direction, sequence;
if (tileElement == nullptr)
{
log_warning("Null tile element");
return;
}
int32_t entryType = tileElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::LargeScenery, entryType);
sceneryTiles = get_large_scenery_entry(entryType)->tiles;
int32_t z = tileElement->base_height;
direction = tileElement->GetDirection();
sequence = tileElement->GetSequenceIndex();
auto sceneryOrigin = map_large_scenery_get_origin(
{ loc.x, loc.y, z << 3, static_cast<Direction>(direction) }, sequence, nullptr);
if (!sceneryOrigin)
auto entryIndex = tileElement->GetEntryIndex();
auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager();
auto obj = objectMgr.GetLoadedObject(ObjectType::LargeScenery, entryIndex);
if (obj != nullptr)
{
return;
}
auto sceneryEntry = reinterpret_cast<const LargeSceneryEntry*>(obj->GetLegacyData());
auto sceneryTiles = sceneryEntry->tiles;
// Iterate through each tile of the large scenery element
sequence = 0;
for (tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++)
{
CoordsXY offsetPos{ tile->x_offset, tile->y_offset };
auto rotatedOffsetPos = offsetPos.Rotate(direction);
int32_t z = tileElement->base_height;
auto direction = tileElement->GetDirection();
auto sequence = tileElement->GetSequenceIndex();
CoordsXYZ tileLoc = { sceneryOrigin->x + rotatedOffsetPos.x, sceneryOrigin->y + rotatedOffsetPos.y,
sceneryOrigin->z + tile->z_offset };
auto largeElement = map_get_large_scenery_segment({ tileLoc, static_cast<Direction>(direction) }, sequence);
if (largeElement != nullptr)
auto sceneryOrigin = map_large_scenery_get_origin(
{ loc.x, loc.y, z << 3, static_cast<Direction>(direction) }, sequence, nullptr);
if (!sceneryOrigin)
{
if (sequence == 0)
return;
}
// Iterate through each tile of the large scenery element
sequence = 0;
for (auto tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++)
{
CoordsXY offsetPos{ tile->x_offset, tile->y_offset };
auto rotatedOffsetPos = offsetPos.Rotate(direction);
CoordsXYZ tileLoc = { sceneryOrigin->x + rotatedOffsetPos.x, sceneryOrigin->y + rotatedOffsetPos.y,
sceneryOrigin->z + tile->z_offset };
auto largeElement = map_get_large_scenery_segment({ tileLoc, static_cast<Direction>(direction) }, sequence);
if (largeElement != nullptr)
{
uint8_t flags = largeElement->GetDirection();
track_design_save_pop_tile_element_desc(entry->GetObjectEntry(), tileLoc, flags);
if (sequence == 0)
{
uint8_t flags = largeElement->GetDirection();
track_design_save_pop_tile_element_desc(obj->GetDescriptor(), tileLoc, flags);
}
track_design_save_pop_tile_element({ tileLoc.x, tileLoc.y }, reinterpret_cast<TileElement*>(largeElement));
}
track_design_save_pop_tile_element({ tileLoc.x, tileLoc.y }, reinterpret_cast<TileElement*>(largeElement));
}
}
}
static void track_design_save_remove_wall(const CoordsXY& loc, WallElement* wallElement)
{
int32_t entryType = wallElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::Walls, entryType);
auto entryIndex = wallElement->GetEntryIndex();
auto obj = object_entry_get_object(ObjectType::Walls, entryIndex);
if (obj != nullptr)
{
uint8_t flags = 0;
flags |= wallElement->GetDirection();
flags |= wallElement->GetTertiaryColour() << 2;
uint8_t flags = 0;
flags |= wallElement->GetDirection();
flags |= wallElement->GetTertiaryColour() << 2;
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(wallElement));
track_design_save_pop_tile_element_desc(entry->GetObjectEntry(), { loc.x, loc.y, wallElement->GetBaseZ() }, flags);
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(wallElement));
track_design_save_pop_tile_element_desc(obj->GetDescriptor(), { loc.x, loc.y, wallElement->GetBaseZ() }, flags);
}
}
static void track_design_save_remove_footpath(const CoordsXY& loc, PathElement* pathElement)
{
int32_t entryType = pathElement->GetLegacyPathEntryIndex();
auto entry = object_entry_get_object(ObjectType::Paths, entryType);
auto pathEntry = track_design_save_footpath_get_best_entry(pathElement);
if (pathElement)
{
uint8_t flags = 0;
flags |= pathElement->GetEdges();
flags |= (pathElement->GetSlopeDirection()) << 5;
if (pathElement->IsSloped())
flags |= 0b00010000;
if (pathElement->IsQueue())
flags |= 1 << 7;
uint8_t flags = 0;
flags |= pathElement->GetEdges();
if (pathElement->IsSloped())
flags |= (1 << 4);
flags |= (pathElement->GetSlopeDirection()) << 5;
if (pathElement->IsQueue())
flags |= (1 << 7);
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(pathElement));
track_design_save_pop_tile_element_desc(entry->GetObjectEntry(), { loc.x, loc.y, pathElement->GetBaseZ() }, flags);
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(pathElement));
track_design_save_pop_tile_element_desc(
ObjectEntryDescriptor(*pathEntry), { loc.x, loc.y, pathElement->GetBaseZ() }, flags);
}
}
/**