diff --git a/src/openrct2-ui/windows/NewRide.cpp b/src/openrct2-ui/windows/NewRide.cpp index 0ac71c4988..9764fc7814 100644 --- a/src/openrct2-ui/windows/NewRide.cpp +++ b/src/openrct2-ui/windows/NewRide.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -212,7 +213,7 @@ static void window_new_ride_scrollmouseover(rct_window *w, int32_t scrollIndex, static void window_new_ride_invalidate(rct_window *w); static void window_new_ride_paint(rct_window *w, rct_drawpixelinfo *dpi); static void window_new_ride_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int32_t scrollIndex); -static void window_new_ride_list_vehicles_for(const uint8_t rideType, const rct_ride_entry * rideEntry, char * out); +static void window_new_ride_list_vehicles_for(uint8_t rideType, const rct_ride_entry* rideEntry, char* buffer, size_t bufferLen); // 0x0098E354 static rct_window_event_list window_new_ride_events = { @@ -346,15 +347,15 @@ static ride_list_item* window_new_ride_iterate_over_ride_group( { bool buttonForRideTypeCreated = false; bool allowDrawingOverLastButton = false; - uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideType); char preferredVehicleName[DAT_NAME_LENGTH + 1]; safe_strcpy(preferredVehicleName, " ", sizeof(preferredVehicleName)); // For each ride entry for this ride type - while (*rideEntryIndexPtr != RIDE_ENTRY_INDEX_NULL) + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + auto& rideEntries = objManager.GetAllRideEntries(rideType); + for (auto rideEntryIndex : rideEntries) { - uint8_t rideEntryIndex = *rideEntryIndexPtr++; char rideEntryName[DAT_NAME_LENGTH + 1]; std::memcpy(rideEntryName, object_entry_get_entry(OBJECT_TYPE_RIDE, rideEntryIndex)->name, 8); rideEntryName[DAT_NAME_LENGTH] = 0; @@ -975,7 +976,7 @@ static void window_new_ride_paint_ride_information( gfx_draw_string_left_wrapped(dpi, gCommonFormatArgs, x, y, width, STR_NEW_RIDE_NAME_AND_DESCRIPTION, COLOUR_BLACK); char availabilityString[AVAILABILITY_STRING_SIZE]; - window_new_ride_list_vehicles_for(item.type, rideEntry, availabilityString); + window_new_ride_list_vehicles_for(item.type, rideEntry, availabilityString, sizeof(availabilityString)); if (availabilityString[0] != 0) { @@ -1056,27 +1057,20 @@ static void window_new_ride_select(rct_window* w) ride_construct_new(item); } -static void window_new_ride_list_vehicles_for(const uint8_t rideType, const rct_ride_entry* rideEntry, char* out) +static void window_new_ride_list_vehicles_for(uint8_t rideType, const rct_ride_entry* rideEntry, char* buffer, size_t bufferLen) { - rct_ride_entry* currentRideEntry; - const RideGroup *rideGroup, *currentRideGroup; - int32_t rideEntryIndex; - + std::fill_n(buffer, bufferLen, 0); if (RideGroupManager::RideTypeIsIndependent(rideType)) { - out[0] = 0; return; } - std::fill_n(out, AVAILABILITY_STRING_SIZE, 0x00); - - uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideType); - - for (uint8_t *currentRideEntryIndex = rideEntryIndexPtr, numItems = 0; *currentRideEntryIndex != RIDE_ENTRY_INDEX_NULL; - currentRideEntryIndex++) + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + auto& rideEntries = objManager.GetAllRideEntries(rideType); + auto isFirst = true; + for (auto rideEntryIndex : rideEntries) { - rideEntryIndex = *currentRideEntryIndex; - currentRideEntry = get_ride_entry(rideEntryIndex); + auto currentRideEntry = get_ride_entry(rideEntryIndex); // Skip if vehicle type is not invented yet if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) @@ -1085,22 +1079,23 @@ static void window_new_ride_list_vehicles_for(const uint8_t rideType, const rct_ // Skip if vehicle does not belong to the same ride group if (RideGroupManager::RideTypeHasRideGroups(rideType)) { - rideGroup = RideGroupManager::GetRideGroup(rideType, (rct_ride_entry*)rideEntry); - currentRideGroup = RideGroupManager::GetRideGroup(rideType, (rct_ride_entry*)currentRideEntry); + auto rideGroup = RideGroupManager::GetRideGroup(rideType, rideEntry); + auto currentRideGroup = RideGroupManager::GetRideGroup(rideType, currentRideEntry); if (!rideGroup->Equals(currentRideGroup)) continue; } - const char* vehicleName = language_get_string(currentRideEntry->naming.name); - - if (numItems > 0) + // Append comma if not the first iteration + if (!isFirst) { - safe_strcat(out, ", ", AVAILABILITY_STRING_SIZE); + safe_strcat(buffer, ", ", bufferLen); } - safe_strcat(out, vehicleName, AVAILABILITY_STRING_SIZE); + // Append vehicle name + auto vehicleName = language_get_string(currentRideEntry->naming.name); + safe_strcat(buffer, vehicleName, bufferLen); - numItems++; + isFirst = false; } } diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp index 4029eed716..a76e83ee97 100644 --- a/src/openrct2-ui/windows/Ride.cpp +++ b/src/openrct2-ui/windows/Ride.cpp @@ -2321,6 +2321,7 @@ static void window_ride_show_ride_type_dropdown(rct_window* w, rct_widget* widge static void populate_vehicle_type_dropdown(Ride* ride) { + auto& objManager = GetContext()->GetObjectManager(); rct_ride_entry* rideEntry = ride->GetRideEntry(); bool selectionShouldBeExpanded; @@ -2356,13 +2357,10 @@ static void populate_vehicle_type_dropdown(Ride* ride) if (selectionShouldBeExpanded && (rideTypeIterator == RIDE_TYPE_MAZE || rideTypeIterator == RIDE_TYPE_MINI_GOLF)) continue; - uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideTypeIterator); - - for (uint8_t* currentRideEntryIndex = rideEntryIndexPtr; *currentRideEntryIndex != RIDE_ENTRY_INDEX_NULL; - currentRideEntryIndex++) + auto& rideEntries = objManager.GetAllRideEntries(rideTypeIterator); + for (auto rideEntryIndex : rideEntries) { - int32_t rideEntryIndex = *currentRideEntryIndex; - rct_ride_entry* currentRideEntry = get_ride_entry(rideEntryIndex); + auto currentRideEntry = get_ride_entry(rideEntryIndex); // Skip if vehicle type has not been invented yet if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) diff --git a/src/openrct2/actions/RideSetVehiclesAction.hpp b/src/openrct2/actions/RideSetVehiclesAction.hpp index 61a3b2bd7e..2ff20d4e0f 100644 --- a/src/openrct2/actions/RideSetVehiclesAction.hpp +++ b/src/openrct2/actions/RideSetVehiclesAction.hpp @@ -17,6 +17,7 @@ #include "../localisation/Localisation.h" #include "../localisation/StringIds.h" #include "../management/Research.h" +#include "../object/ObjectManager.h" #include "../ride/Ride.h" #include "../ui/UiContext.h" #include "../ui/WindowManager.h" @@ -247,11 +248,10 @@ private: continue; } - uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideTypeIterator); - for (uint8_t* currentRideEntryIndex = rideEntryIndexPtr; *currentRideEntryIndex != RIDE_ENTRY_INDEX_NULL; - currentRideEntryIndex++) + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + auto& rideEntries = objManager.GetAllRideEntries(rideTypeIterator); + for (auto rideEntryIndex : rideEntries) { - uint8_t rideEntryIndex = *currentRideEntryIndex; if (rideEntryIndex == _value) { if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) diff --git a/src/openrct2/actions/TrackDesignAction.cpp b/src/openrct2/actions/TrackDesignAction.cpp index c940c1712e..87e5dcd6a6 100644 --- a/src/openrct2/actions/TrackDesignAction.cpp +++ b/src/openrct2/actions/TrackDesignAction.cpp @@ -9,8 +9,10 @@ #include "TrackDesignAction.h" +#include "../Context.h" #include "../management/Finance.h" #include "../management/Research.h" +#include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" #include "../ride/RideGroupManager.h" #include "../ride/TrackDesign.h" @@ -57,20 +59,20 @@ GameActionResult::Ptr TrackDesignAction::Query() const uint8_t rideGroupIndex = ori->RideInfo.RideGroupIndex; const RideGroup* td6RideGroup = RideGroupManager::RideGroupFind(_td.type, rideGroupIndex); - uint8_t* availableRideEntries = get_ride_entry_indices_for_ride_type(_td.type); - for (uint8_t* rei = availableRideEntries; *rei != RIDE_ENTRY_INDEX_NULL; rei++) + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + auto& rideEntries = objManager.GetAllRideEntries(_td.type); + for (auto rideEntryIndex : rideEntries) { - rct_ride_entry* ire = get_ride_entry(*rei); - - if (!ride_entry_is_invented(*rei) && !gCheatsIgnoreResearchStatus) + if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) { continue; } - const RideGroup* irg = RideGroupManager::GetRideGroup(_td.type, ire); - if (td6RideGroup->Equals(irg)) + auto rideEntry = get_ride_entry(rideEntryIndex); + auto rideGroup = RideGroupManager::GetRideGroup(_td.type, rideEntry); + if (td6RideGroup->Equals(rideGroup)) { - entryIndex = *rei; + entryIndex = rideEntryIndex; break; } } @@ -148,20 +150,20 @@ GameActionResult::Ptr TrackDesignAction::Execute() const uint8_t rideGroupIndex = ori->RideInfo.RideGroupIndex; const RideGroup* td6RideGroup = RideGroupManager::RideGroupFind(_td.type, rideGroupIndex); - uint8_t* availableRideEntries = get_ride_entry_indices_for_ride_type(_td.type); - for (uint8_t* rei = availableRideEntries; *rei != RIDE_ENTRY_INDEX_NULL; rei++) + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + auto& rideEntries = objManager.GetAllRideEntries(_td.type); + for (auto rideEntryIndex : rideEntries) { - rct_ride_entry* ire = get_ride_entry(*rei); - - if (!ride_entry_is_invented(*rei) && !gCheatsIgnoreResearchStatus) + if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) { continue; } - const RideGroup* irg = RideGroupManager::GetRideGroup(_td.type, ire); - if (td6RideGroup->Equals(irg)) + auto rideEntry = get_ride_entry(rideEntryIndex); + auto rideGroup = RideGroupManager::GetRideGroup(_td.type, rideEntry); + if (td6RideGroup->Equals(rideGroup)) { - entryIndex = *rei; + entryIndex = rideEntryIndex; break; } } diff --git a/src/openrct2/object/ObjectManager.cpp b/src/openrct2/object/ObjectManager.cpp index aefcd6f25c..48d578f846 100644 --- a/src/openrct2/object/ObjectManager.cpp +++ b/src/openrct2/object/ObjectManager.cpp @@ -19,6 +19,7 @@ #include "Object.h" #include "ObjectList.h" #include "ObjectRepository.h" +#include "RideObject.h" #include "SceneryGroupObject.h" #include "SmallSceneryObject.h" #include "WallObject.h" @@ -35,6 +36,10 @@ class ObjectManager final : public IObjectManager private: IObjectRepository& _objectRepository; std::vector _loadedObjects; + std::array, RIDE_TYPE_COUNT> _rideTypeToObjectMap; + + // Used to return a safe empty vector back from GetAllRideEntries, can be removed when std::span is available + std::vector _nullRideTypeEntries; public: explicit ObjectManager(IObjectRepository& objectRepository) @@ -287,6 +292,16 @@ public: } } + const std::vector& GetAllRideEntries(uint8_t rideType) override + { + if (rideType >= RIDE_TYPE_COUNT) + { + // Return an empty vector + return _nullRideTypeEntries; + } + return _rideTypeToObjectMap[rideType]; + } + private: Object* LoadObject(const std::string& name) { @@ -642,7 +657,33 @@ private: void ResetTypeToRideEntryIndexMap() { - reset_type_to_ride_entry_index_map(*this); + // Clear all ride objects + for (auto& v : _rideTypeToObjectMap) + { + v.clear(); + } + + // Build object lists + auto maxRideObjects = static_cast(object_entry_group_counts[OBJECT_TYPE_RIDE]); + for (size_t i = 0; i < maxRideObjects; i++) + { + auto rideObject = static_cast(GetLoadedObject(OBJECT_TYPE_RIDE, i)); + if (rideObject != nullptr) + { + const auto entry = static_cast(rideObject->GetLegacyData()); + if (entry != nullptr) + { + for (auto rideType : entry->ride_type) + { + if (rideType < _rideTypeToObjectMap.size()) + { + auto& v = _rideTypeToObjectMap[rideType]; + v.push_back(static_cast(i)); + } + } + } + } + } } static void ReportMissingObject(const rct_object_entry* entry) diff --git a/src/openrct2/object/ObjectManager.h b/src/openrct2/object/ObjectManager.h index 06e708eb6b..eb2e7672fd 100644 --- a/src/openrct2/object/ObjectManager.h +++ b/src/openrct2/object/ObjectManager.h @@ -39,6 +39,7 @@ interface IObjectManager virtual void ResetObjects() abstract; virtual std::vector GetPackableObjects() abstract; + virtual const std::vector& GetAllRideEntries(uint8_t rideType) abstract; }; std::unique_ptr CreateObjectManager(IObjectRepository& objectRepository); diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index e9067943e5..4b2108eb41 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -73,7 +73,6 @@ using namespace OpenRCT2; -uint8_t gTypeToRideEntryIndexMap[TYPE_TO_RIDE_ENTRY_SLOTS]; static constexpr const int32_t RideInspectionInterval[] = { 10, 20, 30, 45, 60, 120, 0, 0, }; @@ -244,64 +243,6 @@ rct_ride_entry* Ride::GetRideEntry() const return get_ride_entry(subtype); } -/** - * - * rct2: 0x006DED68 - */ -void reset_type_to_ride_entry_index_map(IObjectManager& objectManager) -{ - size_t stride = MAX_RIDE_OBJECTS + 1; - uint8_t* entryTypeTable = (uint8_t*)malloc(RIDE_TYPE_COUNT * stride); - std::fill_n(entryTypeTable, RIDE_TYPE_COUNT * stride, 0xFF); - - for (uint8_t i = 0; i < MAX_RIDE_OBJECTS; i++) - { - auto obj = objectManager.GetLoadedObject(OBJECT_TYPE_RIDE, i); - if (obj != nullptr) - { - for (uint8_t j = 0; j < MAX_RIDE_TYPES_PER_RIDE_ENTRY; j++) - { - auto rideEntry = (rct_ride_entry*)obj->GetLegacyData(); - uint8_t rideType = rideEntry->ride_type[j]; - if (rideType < RIDE_TYPE_COUNT) - { - uint8_t* entryArray = &entryTypeTable[rideType * stride]; - uint8_t* nextEntry = (uint8_t*)memchr(entryArray, 0xFF, stride); - *nextEntry = i; - } - } - } - } - - uint8_t* dst = gTypeToRideEntryIndexMap; - for (uint8_t i = 0; i < RIDE_TYPE_COUNT; i++) - { - uint8_t* entryArray = &entryTypeTable[i * stride]; - uint8_t* entry = entryArray; - while (*entry != 0xFF) - { - *dst++ = *entry++; - } - *dst++ = 0xFF; - } - - free(entryTypeTable); -} - -uint8_t* get_ride_entry_indices_for_ride_type(uint8_t rideType) -{ - uint8_t* entryIndexList = gTypeToRideEntryIndexMap; - while (rideType > 0) - { - do - { - entryIndexList++; - } while (*(entryIndexList - 1) != RIDE_ENTRY_INDEX_NULL); - rideType--; - } - return entryIndexList; -} - int32_t ride_get_count() { return (int32_t)GetRideManager().size(); @@ -7552,31 +7493,32 @@ int32_t ride_get_entry_index(int32_t rideType, int32_t rideSubType) if (subType == RIDE_ENTRY_INDEX_NULL) { - uint8_t* availableRideEntries = get_ride_entry_indices_for_ride_type(rideType); - for (uint8_t* rideEntryIndex = availableRideEntries; *rideEntryIndex != RIDE_ENTRY_INDEX_NULL; rideEntryIndex++) + auto& objManager = GetContext()->GetObjectManager(); + auto& rideEntries = objManager.GetAllRideEntries(rideType); + if (rideEntries.size() > 0) { - rct_ride_entry* rideEntry = get_ride_entry(*rideEntryIndex); - if (rideEntry == nullptr) + subType = rideEntries[0]; + for (auto rideEntryIndex : rideEntries) { - return RIDE_ENTRY_INDEX_NULL; - } + auto rideEntry = get_ride_entry(rideEntryIndex); + if (rideEntry == nullptr) + { + return RIDE_ENTRY_INDEX_NULL; + } - // Can happen in select-by-track-type mode - if (!ride_entry_is_invented(*rideEntryIndex) && !gCheatsIgnoreResearchStatus) - { - continue; - } + // Can happen in select-by-track-type mode + if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) + { + continue; + } - if (!RideGroupManager::RideTypeIsIndependent(rideType)) - { - subType = *rideEntryIndex; - break; + if (!RideGroupManager::RideTypeIsIndependent(rideType)) + { + subType = rideEntryIndex; + break; + } } } - if (subType == RIDE_ENTRY_INDEX_NULL) - { - subType = availableRideEntries[0]; - } } return subType; diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index deefe91a74..f9a22ed99d 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -474,15 +474,6 @@ assert_struct_size(ride_name_args, 4); #pragma pack(pop) -/* - * This array should probably be only 91 + 128 * 3 = 475 bytes long. - * It was originally stored at address 0x009E32F8 and continued until 0x009E34E3 - * (inclusive). 0x009E34E4 is the address of s6 header, so it's likely it had - * some padding at the end as well. - */ -#define TYPE_TO_RIDE_ENTRY_SLOTS 492 -extern uint8_t gTypeToRideEntryIndexMap[TYPE_TO_RIDE_ENTRY_SLOTS]; - // Constants used by the lifecycle_flags property at 0x1D0 enum { @@ -1157,8 +1148,6 @@ TrackColour ride_get_track_colour(Ride* ride, int32_t colourScheme); vehicle_colour ride_get_vehicle_colour(Ride* ride, int32_t vehicleIndex); int32_t ride_get_unused_preset_vehicle_colour(uint8_t ride_sub_type); void ride_set_vehicle_colours_to_random_preset(Ride* ride, uint8_t preset_index); -uint8_t* get_ride_entry_indices_for_ride_type(uint8_t rideType); -void reset_type_to_ride_entry_index_map(IObjectManager& objectManager); void ride_measurements_update(); std::pair ride_get_measurement(Ride* ride); void ride_breakdown_add_news_item(Ride* ride); diff --git a/src/openrct2/ride/RideGroupManager.cpp b/src/openrct2/ride/RideGroupManager.cpp index c219b757a3..9294e90396 100644 --- a/src/openrct2/ride/RideGroupManager.cpp +++ b/src/openrct2/ride/RideGroupManager.cpp @@ -9,10 +9,12 @@ #include "RideGroupManager.h" +#include "../Context.h" #include "../config/Config.h" #include "../core/String.hpp" #include "../localisation/StringIds.h" #include "../management/Research.h" +#include "../object/ObjectManager.h" #include "Ride.h" #include "RideData.h" #include "Track.h" @@ -169,23 +171,20 @@ bool RideGroup::IsInvented() const if (!ride_type_is_invented(this->RideType)) return false; - uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(this->RideType); - - while (*rideEntryIndexPtr != RIDE_ENTRY_INDEX_NULL) + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + auto& rideEntries = objManager.GetAllRideEntries(this->RideType); + for (auto rideEntryIndex : rideEntries) { - uint8_t rideEntryIndex = *rideEntryIndexPtr++; - - if (!ride_entry_is_invented(rideEntryIndex)) - continue; - - rct_ride_entry* rideEntry = get_ride_entry(rideEntryIndex); - const RideGroup* rideEntryRideGroup = RideGroupManager::GetRideGroup(this->RideType, rideEntry); - - if (!this->Equals(rideEntryRideGroup)) - continue; - - // The ride entry is invented and belongs to the same ride group. This means the ride group is invented. - return true; + if (ride_entry_is_invented(rideEntryIndex)) + { + auto rideEntry = get_ride_entry(rideEntryIndex); + auto rideEntryRideGroup = RideGroupManager::GetRideGroup(this->RideType, rideEntry); + if (this->Equals(rideEntryRideGroup)) + { + // The ride entry is invented and belongs to the same ride group. This means the ride group is invented. + return true; + } + } } return false;