From ac4b2c230cec01ceceb6810387bde5e43e3a2b80 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Tue, 14 Feb 2023 21:42:13 +0000 Subject: [PATCH] Implement RoadObject load Also fix unload issues --- src/OpenLoco/src/Objects/RoadObject.cpp | 109 ++++++++++++++++++++++-- src/OpenLoco/src/Objects/RoadObject.h | 29 ++++--- 2 files changed, 119 insertions(+), 19 deletions(-) diff --git a/src/OpenLoco/src/Objects/RoadObject.cpp b/src/OpenLoco/src/Objects/RoadObject.cpp index 189f46c452..54cfebd062 100644 --- a/src/OpenLoco/src/Objects/RoadObject.cpp +++ b/src/OpenLoco/src/Objects/RoadObject.cpp @@ -2,6 +2,9 @@ #include "Drawing/SoftwareDrawingEngine.h" #include "Graphics/Colour.h" #include "Graphics/Gfx.h" +#include "ObjectImageTable.h" +#include "ObjectManager.h" +#include "ObjectStringTable.h" #include namespace OpenLoco @@ -61,19 +64,113 @@ namespace OpenLoco // 0x00477BCF void RoadObject::load(const LoadedObjectHandle& handle, stdx::span data, ObjectManager::DependentObjects* dependencies) { - Interop::registers regs; - regs.esi = Interop::X86Pointer(this); - regs.ebx = handle.id; - regs.ecx = enumValue(handle.type); - Interop::call(0x00477BCF, regs); + auto remainingData = data.subspan(sizeof(RoadObject)); + + auto strRes = ObjectManager::loadStringTable(remainingData, handle, 0); + name = strRes.str; + remainingData = remainingData.subspan(strRes.tableLength); + + // NOTE: These aren't dependent (objects unless otherwise stated) as this object can load without the + // related object. + // Load compatible roads/tracks + compatibleTracks = 0; + compatibleRoads = 0; + for (auto i = 0; i < numCompatible; ++i) + { + ObjectHeader modHeader = *reinterpret_cast(remainingData.data()); + auto res = ObjectManager::findObjectHandle(modHeader); + if (res.has_value()) + { + if (res->type == ObjectType::track) + { + compatibleTracks |= 1U << res->id; + } + else if (res->type == ObjectType::road) + { + compatibleRoads |= 1U << res->id; + } + } + remainingData = remainingData.subspan(sizeof(ObjectHeader)); + } + + // Load Extra + std::fill(std::begin(mods), std::end(mods), 0xFF); + for (auto i = 0U, index = 0U; i < numMods; ++i) + { + ObjectHeader modHeader = *reinterpret_cast(remainingData.data()); + auto res = ObjectManager::findObjectHandle(modHeader); + if (res.has_value() && res->type == ObjectType::roadExtra) + { + mods[index++] = res->id; + } + remainingData = remainingData.subspan(sizeof(ObjectHeader)); + } + + // Load Tunnel (DEPENDENT OBJECT) + tunnel = 0xFF; + { + ObjectHeader unkHeader = *reinterpret_cast(remainingData.data()); + if (dependencies != nullptr) + { + dependencies->required.push_back(unkHeader); + } + auto res = ObjectManager::findObjectHandle(unkHeader); + if (res.has_value()) + { + tunnel = res->id; + } + remainingData = remainingData.subspan(sizeof(ObjectHeader)); + } + + // Load bridges (DEPENDENT OBJECT) + std::fill(std::begin(bridges), std::end(bridges), 0xFF); + for (auto i = 0U; i < numBridges; ++i) + { + ObjectHeader bridgeHeader = *reinterpret_cast(remainingData.data()); + if (dependencies != nullptr) + { + dependencies->required.push_back(bridgeHeader); + } + auto res = ObjectManager::findObjectHandle(bridgeHeader); + if (res.has_value()) + { + bridges[i] = res->id; + } + remainingData = remainingData.subspan(sizeof(ObjectHeader)); + } + + // Load stations (DEPENDENT OBJECT) + std::fill(std::begin(stations), std::end(stations), 0xFF); + for (auto i = 0U; i < numStations; ++i) + { + ObjectHeader stationHeader = *reinterpret_cast(remainingData.data()); + if (dependencies != nullptr) + { + dependencies->required.push_back(stationHeader); + } + auto res = ObjectManager::findObjectHandle(stationHeader); + if (res.has_value()) + { + stations[i] = res->id; + } + remainingData = remainingData.subspan(sizeof(ObjectHeader)); + } + + auto imgRes = ObjectManager::loadImageTable(remainingData); + image = imgRes.imageOffset; + assert(remainingData.size() == imgRes.tableLength); } // 0x00477D9E void RoadObject::unload() { name = 0; - var_0B = 0; + tunnel = 0; image = 0; std::fill(std::begin(bridges), std::end(bridges), 0); + std::fill(std::begin(mods), std::end(mods), 0); + std::fill(std::begin(stations), std::end(stations), 0); + compatibleTracks = 0; + compatibleRoads = 0; } } diff --git a/src/OpenLoco/src/Objects/RoadObject.h b/src/OpenLoco/src/Objects/RoadObject.h index 5a50e45a71..e90a193851 100644 --- a/src/OpenLoco/src/Objects/RoadObject.h +++ b/src/OpenLoco/src/Objects/RoadObject.h @@ -53,19 +53,22 @@ namespace OpenLoco int16_t sellCostFactor; // 0x06 int16_t tunnelCostFactor; // 0x08 uint8_t costIndex; // 0x0A - uint8_t var_0B; - Speed16 maxSpeed; // 0x0C - uint32_t image; // 0x0E - RoadObjectFlags flags; // 0x12 - uint8_t numBridges; // 0x14 - uint8_t bridges[7]; // 0x15 - uint8_t numStations; // 0x1C - uint8_t stations[7]; // 0x1D - uint8_t paintStyle; // 0x24 - uint8_t numMods; // 0x25 - uint8_t mods[2]; // 0x26 - uint8_t numCompatible; // 0x28 - uint8_t pad_29[0x30 - 0x29]; + uint8_t tunnel; // 0x0B + Speed16 maxSpeed; // 0x0C + uint32_t image; // 0x0E + RoadObjectFlags flags; // 0x12 + uint8_t numBridges; // 0x14 + uint8_t bridges[7]; // 0x15 + uint8_t numStations; // 0x1C + uint8_t stations[7]; // 0x1D + uint8_t paintStyle; // 0x24 + uint8_t numMods; // 0x25 + uint8_t mods[2]; // 0x26 + uint8_t numCompatible; // 0x28 + uint8_t pad_29; + uint16_t compatibleRoads; // 0x2A + uint16_t compatibleTracks; // 0x2C + uint8_t pad_2E[0x30 - 0x2E]; void drawPreviewImage(Gfx::RenderTarget& rt, const int16_t x, const int16_t y) const; bool validate() const;