diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 660c2e460d..bbf479f5fa 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -3,7 +3,7 @@ - Feature: [#21062] [Plugin] Add API for managing a guest's items. - Improved: [#18632] Land ownership and construction rights are now shown on top of the water. - Improved: [#20951] Activate OpenRCT2 window after using native file dialog on macOS. -- Improved: [#21184] The construction marker for rides, paths and large scenery is not shown on top of the water. +- Improved: [#21184] The construction marker for rides, paths and large scenery is now shown on top of the water. - Improved: [#21227] Entrance style dropdown is now sorted alphabetically everywhere. - Change: [#21200] Raise maximum lift speeds of the Reverser Coaster, Side Friction Coaster, and Virginia Reel for RCT1 parity. - Change: [#21225] Raise maximum allowed misc entities to 1600. diff --git a/src/openrct2-ui/windows/EditorInventionsList.cpp b/src/openrct2-ui/windows/EditorInventionsList.cpp index 5f1d5e621e..c8a9b64aa6 100644 --- a/src/openrct2-ui/windows/EditorInventionsList.cpp +++ b/src/openrct2-ui/windows/EditorInventionsList.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,8 @@ #pragma region Widgets +using namespace OpenRCT2; + static constexpr int32_t WW = 600; static constexpr int32_t WH = 400; static constexpr StringId WINDOW_TITLE = STR_INVENTION_LIST; @@ -220,14 +223,15 @@ public: ScreenSize OnScrollGetSize(int32_t scrollIndex) override { + const auto& gameState = GetGameState(); ScreenSize size{}; if (scrollIndex == 0) { - size.height = static_cast(gResearchItemsInvented.size()) * SCROLLABLE_ROW_HEIGHT; + size.height = static_cast(gameState.ResearchItemsInvented.size()) * SCROLLABLE_ROW_HEIGHT; } else { - size.height = static_cast(gResearchItemsUninvented.size()) * SCROLLABLE_ROW_HEIGHT; + size.height = static_cast(gameState.ResearchItemsUninvented.size()) * SCROLLABLE_ROW_HEIGHT; } return size; } @@ -265,6 +269,8 @@ public: void OnScrollDraw(int32_t scrollIndex, DrawPixelInfo& dpi) override { + const auto& gameState = GetGameState(); + // Draw background uint8_t paletteIndex = ColourMapA[colours[1]].mid_light; GfxClear(&dpi, paletteIndex); @@ -273,7 +279,7 @@ public: int32_t itemY = -SCROLLABLE_ROW_HEIGHT; auto* dragItem = WindowEditorInventionsListDragGetItem(); - const auto& researchList = scrollIndex == 0 ? gResearchItemsInvented : gResearchItemsUninvented; + const auto& researchList = scrollIndex == 0 ? gameState.ResearchItemsInvented : gameState.ResearchItemsUninvented; for (const auto& researchItem : researchList) { itemY += SCROLLABLE_ROW_HEIGHT; @@ -512,6 +518,7 @@ public: void MoveResearchItem(const ResearchItem& item, ResearchItem* beforeItem, bool isInvented) { + auto& gameState = GetGameState(); _selectedResearchItem = nullptr; Invalidate(); @@ -524,7 +531,7 @@ public: ResearchRemove(item); - auto& researchList = isInvented ? gResearchItemsInvented : gResearchItemsUninvented; + auto& researchList = isInvented ? gameState.ResearchItemsInvented : gameState.ResearchItemsUninvented; if (beforeItem != nullptr) { for (size_t i = 0; i < researchList.size(); i++) @@ -544,7 +551,8 @@ public: private: ResearchItem* GetItemFromScrollY(bool isInvented, int32_t y) const { - auto& researchList = isInvented ? gResearchItemsInvented : gResearchItemsUninvented; + auto& gameState = GetGameState(); + auto& researchList = isInvented ? gameState.ResearchItemsInvented : gameState.ResearchItemsUninvented; for (auto& researchItem : researchList) { y -= SCROLLABLE_ROW_HEIGHT; @@ -559,7 +567,8 @@ private: ResearchItem* GetItemFromScrollYIncludeSeps(bool isInvented, int32_t y) const { - auto& researchList = isInvented ? gResearchItemsInvented : gResearchItemsUninvented; + auto& gameState = GetGameState(); + auto& researchList = isInvented ? gameState.ResearchItemsInvented : gameState.ResearchItemsUninvented; for (auto& researchItem : researchList) { y -= SCROLLABLE_ROW_HEIGHT; diff --git a/src/openrct2-ui/windows/Research.cpp b/src/openrct2-ui/windows/Research.cpp index c7fc989516..9d6e591a03 100644 --- a/src/openrct2-ui/windows/Research.cpp +++ b/src/openrct2-ui/windows/Research.cpp @@ -329,24 +329,26 @@ static WidgetIndex GetWidgetIndexOffset(WidgetIndex baseWidgetIndex, WidgetIndex void WindowResearchDevelopmentMouseUp(WidgetIndex widgetIndex, WidgetIndex baseWidgetIndex) { + const auto& gameState = GetGameState(); auto widgetOffset = GetWidgetIndexOffset(baseWidgetIndex, WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP); if (widgetIndex == (WIDX_LAST_DEVELOPMENT_BUTTON + widgetOffset)) { - News::OpenSubject(News::ItemType::Research, gResearchLastItem->rawValue); + News::OpenSubject(News::ItemType::Research, gameState.ResearchLastItem->rawValue); } } void WindowResearchDevelopmentPrepareDraw(WindowBase* w, WidgetIndex baseWidgetIndex) { + const auto& gameState = GetGameState(); // Offset the widget index to allow reuse from other windows auto widgetOffset = GetWidgetIndexOffset(baseWidgetIndex, WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP); w->widgets[WIDX_LAST_DEVELOPMENT_BUTTON + widgetOffset].type = WindowWidgetType::Empty; // Display button to link to the last development, if there is one - if (gResearchLastItem.has_value()) + if (gameState.ResearchLastItem.has_value()) { - auto type = gResearchLastItem->type; + auto type = gameState.ResearchLastItem->type; w->widgets[WIDX_LAST_DEVELOPMENT_BUTTON + widgetOffset].type = WindowWidgetType::FlatBtn; const auto image = type == Research::EntryType::Ride ? SPR_NEW_RIDE : SPR_NEW_SCENERY; w->widgets[WIDX_LAST_DEVELOPMENT_BUTTON + widgetOffset].image = ImageId(image); @@ -355,11 +357,13 @@ void WindowResearchDevelopmentPrepareDraw(WindowBase* w, WidgetIndex baseWidgetI void WindowResearchDevelopmentDraw(WindowBase* w, DrawPixelInfo& dpi, WidgetIndex baseWidgetIndex) { + const auto& gameState = GetGameState(); + auto widgetOffset = GetWidgetIndexOffset(baseWidgetIndex, WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP); auto screenCoords = w->windowPos + ScreenCoordsXY{ 10, w->widgets[WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP + widgetOffset].top + 12 }; - if (gResearchProgressStage == RESEARCH_STAGE_FINISHED_ALL) + if (gameState.ResearchProgressStage == RESEARCH_STAGE_FINISHED_ALL) { // Research type auto ft = Formatter(); @@ -383,53 +387,53 @@ void WindowResearchDevelopmentDraw(WindowBase* w, DrawPixelInfo& dpi, WidgetInde // Research type auto ft = Formatter(); StringId label = STR_RESEARCH_TYPE_LABEL; - if (gResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH) + if (gameState.ResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH) { ft.Add(STR_RESEARCH_UNKNOWN); } - else if (gResearchProgressStage == RESEARCH_STAGE_DESIGNING) + else if (gameState.ResearchProgressStage == RESEARCH_STAGE_DESIGNING) { - ft.Add(gResearchNextItem->GetCategoryName()); + ft.Add(gameState.ResearchNextItem->GetCategoryName()); } - else if (gResearchNextItem->type == Research::EntryType::Ride) + else if (gameState.ResearchNextItem->type == Research::EntryType::Ride) { - const auto& rtd = GetRideTypeDescriptor(gResearchNextItem->baseRideType); + const auto& rtd = GetRideTypeDescriptor(gameState.ResearchNextItem->baseRideType); if (rtd.HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY)) { - ft.Add(gResearchNextItem->GetName()); + ft.Add(gameState.ResearchNextItem->GetName()); } - else if (gResearchNextItem->flags & RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE) + else if (gameState.ResearchNextItem->flags & RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE) { ft.Add(rtd.Naming.Name); } else { - ft.Add(gResearchNextItem->GetName()); + ft.Add(gameState.ResearchNextItem->GetName()); ft.Add(rtd.Naming.Name); label = STR_RESEARCH_TYPE_LABEL_VEHICLE; } } else { - ft.Add(gResearchNextItem->GetName()); + ft.Add(gameState.ResearchNextItem->GetName()); } DrawTextWrapped(dpi, screenCoords, 296, label, ft); screenCoords.y += 25; // Progress ft = Formatter(); - ft.Add(ResearchStageNames[gResearchProgressStage]); + ft.Add(ResearchStageNames[gameState.ResearchProgressStage]); DrawTextWrapped(dpi, screenCoords, 296, STR_RESEARCH_PROGRESS_LABEL, ft); screenCoords.y += 15; // Expected ft = Formatter(); - if (gResearchProgressStage != RESEARCH_STAGE_INITIAL_RESEARCH && gResearchExpectedDay != 255) + if (gameState.ResearchProgressStage != RESEARCH_STAGE_INITIAL_RESEARCH && gameState.ResearchExpectedDay != 255) { // TODO: Should probably use game date format setting ft.Add(STR_RESEARCH_EXPECTED_FORMAT); - ft.Add(DateDayNames[gResearchExpectedDay]); - ft.Add(DateGameMonthNames[gResearchExpectedMonth]); + ft.Add(DateDayNames[gameState.ResearchExpectedDay]); + ft.Add(DateGameMonthNames[gameState.ResearchExpectedMonth]); } else { @@ -441,30 +445,30 @@ void WindowResearchDevelopmentDraw(WindowBase* w, DrawPixelInfo& dpi, WidgetInde // Last development screenCoords = w->windowPos + ScreenCoordsXY{ 10, w->widgets[WIDX_LAST_DEVELOPMENT_GROUP + widgetOffset].top + 12 }; - if (gResearchLastItem.has_value()) + if (gameState.ResearchLastItem.has_value()) { StringId lastDevelopmentFormat = STR_EMPTY; auto ft = Formatter(); - if (gResearchLastItem->type == Research::EntryType::Scenery) + if (gameState.ResearchLastItem->type == Research::EntryType::Scenery) { lastDevelopmentFormat = STR_RESEARCH_SCENERY_LABEL; - ft.Add(gResearchLastItem->GetName()); + ft.Add(gameState.ResearchLastItem->GetName()); } else { lastDevelopmentFormat = STR_RESEARCH_RIDE_LABEL; - const auto& rtd = GetRideTypeDescriptor(gResearchLastItem->baseRideType); + const auto& rtd = GetRideTypeDescriptor(gameState.ResearchLastItem->baseRideType); if (rtd.HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY)) { - ft.Add(gResearchLastItem->GetName()); + ft.Add(gameState.ResearchLastItem->GetName()); } - else if (gResearchLastItem->flags & RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE) + else if (gameState.ResearchLastItem->flags & RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE) { ft.Add(rtd.Naming.Name); } else { - ft.Add(gResearchLastItem->GetName()); + ft.Add(gameState.ResearchLastItem->GetName()); ft.Add(rtd.Naming.Name); lastDevelopmentFormat = STR_RESEARCH_VEHICLE_LABEL; } @@ -480,6 +484,7 @@ void WindowResearchDevelopmentDraw(WindowBase* w, DrawPixelInfo& dpi, WidgetInde void WindowResearchFundingMouseDown(WindowBase* w, WidgetIndex widgetIndex, WidgetIndex baseWidgetIndex) { + const auto& gameState = GetGameState(); auto widgetOffset = GetWidgetIndexOffset(baseWidgetIndex, WIDX_RESEARCH_FUNDING); if (widgetIndex != (WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON + widgetOffset)) @@ -496,12 +501,13 @@ void WindowResearchFundingMouseDown(WindowBase* w, WidgetIndex widgetIndex, Widg { w->windowPos.x + dropdownWidget->left, w->windowPos.y + dropdownWidget->top }, dropdownWidget->height() + 1, w->colours[1], 0, Dropdown::Flag::StayOpen, 4, dropdownWidget->width() - 3); - int32_t currentResearchLevel = gResearchFundingLevel; + int32_t currentResearchLevel = gameState.ResearchFundingLevel; Dropdown::SetChecked(currentResearchLevel, true); } void WindowResearchFundingMouseUp(WidgetIndex widgetIndex, WidgetIndex baseWidgetIndex) { + const auto& gameState = GetGameState(); auto widgetOffset = GetWidgetIndexOffset(baseWidgetIndex, WIDX_RESEARCH_FUNDING); switch (widgetIndex - widgetOffset) @@ -514,9 +520,9 @@ void WindowResearchFundingMouseUp(WidgetIndex widgetIndex, WidgetIndex baseWidge case WIDX_SHOPS_AND_STALLS: case WIDX_SCENERY_AND_THEMING: { - auto activeResearchTypes = gResearchPriorities; + auto activeResearchTypes = gameState.ResearchPriorities; activeResearchTypes ^= 1uLL << (widgetIndex - (WIDX_TRANSPORT_RIDES + widgetOffset)); - auto gameAction = ParkSetResearchFundingAction(activeResearchTypes, gResearchFundingLevel); + auto gameAction = ParkSetResearchFundingAction(activeResearchTypes, gameState.ResearchFundingLevel); GameActions::Execute(&gameAction); break; } @@ -525,20 +531,22 @@ void WindowResearchFundingMouseUp(WidgetIndex widgetIndex, WidgetIndex baseWidge void WindowResearchFundingDropdown(WidgetIndex widgetIndex, int32_t selectedIndex, WidgetIndex baseWidgetIndex) { + const auto& gameState = GetGameState(); auto widgetOffset = GetWidgetIndexOffset(baseWidgetIndex, WIDX_RESEARCH_FUNDING); if (widgetIndex != (WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON + widgetOffset) || selectedIndex == -1) return; - auto gameAction = ParkSetResearchFundingAction(gResearchPriorities, selectedIndex); + auto gameAction = ParkSetResearchFundingAction(gameState.ResearchPriorities, selectedIndex); GameActions::Execute(&gameAction); } void WindowResearchFundingPrepareDraw(WindowBase* w, WidgetIndex baseWidgetIndex) { + const auto& gameState = GetGameState(); auto widgetOffset = GetWidgetIndexOffset(baseWidgetIndex, WIDX_RESEARCH_FUNDING); - if ((GetGameState().ParkFlags & PARK_FLAGS_NO_MONEY) || gResearchProgressStage == RESEARCH_STAGE_FINISHED_ALL) + if ((GetGameState().ParkFlags & PARK_FLAGS_NO_MONEY) || gameState.ResearchProgressStage == RESEARCH_STAGE_FINISHED_ALL) { w->widgets[WIDX_RESEARCH_FUNDING + widgetOffset].type = WindowWidgetType::Empty; w->widgets[WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON + widgetOffset].type = WindowWidgetType::Empty; @@ -550,12 +558,12 @@ void WindowResearchFundingPrepareDraw(WindowBase* w, WidgetIndex baseWidgetIndex } // Current funding - int32_t currentResearchLevel = gResearchFundingLevel; + int32_t currentResearchLevel = gameState.ResearchFundingLevel; w->widgets[WIDX_RESEARCH_FUNDING + widgetOffset].text = ResearchFundingLevelNames[currentResearchLevel]; // Checkboxes - uint8_t activeResearchTypes = gResearchPriorities; - int32_t uncompletedResearchTypes = gResearchUncompletedCategories; + uint8_t activeResearchTypes = gameState.ResearchPriorities; + int32_t uncompletedResearchTypes = gameState.ResearchUncompletedCategories; for (int32_t i = 0; i < 7; i++) { int32_t mask = 1 << i; @@ -585,7 +593,8 @@ void WindowResearchFundingDraw(WindowBase* w, DrawPixelInfo& dpi) if (GetGameState().ParkFlags & PARK_FLAGS_NO_MONEY) return; - int32_t currentResearchLevel = gResearchFundingLevel; + const auto& gameState = GetGameState(); + int32_t currentResearchLevel = gameState.ResearchFundingLevel; auto ft = Formatter(); ft.Add(research_cost_table[currentResearchLevel]); DrawTextBasic(dpi, w->windowPos + ScreenCoordsXY{ 10, 77 }, STR_RESEARCH_COST_PER_MONTH, ft); diff --git a/src/openrct2/GameState.h b/src/openrct2/GameState.h index 61265f57b6..d931d18e08 100644 --- a/src/openrct2/GameState.h +++ b/src/openrct2/GameState.h @@ -68,6 +68,19 @@ namespace OpenRCT2 colour_t StaffHandymanColour; colour_t StaffMechanicColour; colour_t StaffSecurityColour; + + uint8_t ResearchFundingLevel; + uint8_t ResearchPriorities; + uint16_t ResearchProgress; + uint8_t ResearchProgressStage; + uint8_t ResearchExpectedMonth; + uint8_t ResearchExpectedDay; + std::optional ResearchLastItem; + std::optional ResearchNextItem; + + std::vector ResearchItemsUninvented; + std::vector ResearchItemsInvented; + uint8_t ResearchUncompletedCategories; }; GameState_t& GetGameState(); diff --git a/src/openrct2/actions/ParkSetResearchFundingAction.cpp b/src/openrct2/actions/ParkSetResearchFundingAction.cpp index 055b4a94cf..23867fadc3 100644 --- a/src/openrct2/actions/ParkSetResearchFundingAction.cpp +++ b/src/openrct2/actions/ParkSetResearchFundingAction.cpp @@ -10,6 +10,7 @@ #include "ParkSetResearchFundingAction.h" #include "../Context.h" +#include "../GameState.h" #include "../core/MemoryStream.h" #include "../localisation/StringIds.h" #include "../management/Research.h" @@ -17,6 +18,8 @@ #include "../ui/WindowManager.h" #include "../windows/Intent.h" +using namespace OpenRCT2; + ParkSetResearchFundingAction::ParkSetResearchFundingAction(uint32_t priorities, uint8_t fundingAmount) : _priorities(priorities) , _fundingAmount(fundingAmount) @@ -52,8 +55,9 @@ GameActions::Result ParkSetResearchFundingAction::Query() const GameActions::Result ParkSetResearchFundingAction::Execute() const { - gResearchPriorities = _priorities; - gResearchFundingLevel = _fundingAmount; + auto& gameState = GetGameState(); + gameState.ResearchPriorities = _priorities; + gameState.ResearchFundingLevel = _fundingAmount; auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_RESEARCH)); diff --git a/src/openrct2/management/Finance.cpp b/src/openrct2/management/Finance.cpp index 70afa4d2ed..6810b60bbe 100644 --- a/src/openrct2/management/Finance.cpp +++ b/src/openrct2/management/Finance.cpp @@ -123,12 +123,13 @@ void FinancePayWages() **/ void FinancePayResearch() { - if (GetGameState().ParkFlags & PARK_FLAGS_NO_MONEY) + const auto& gameState = GetGameState(); + if (gameState.ParkFlags & PARK_FLAGS_NO_MONEY) { return; } - const uint8_t level = gResearchFundingLevel; + const uint8_t level = gameState.ResearchFundingLevel; FinancePayment(research_cost_table[level] / 4, ExpenditureType::Research); } @@ -266,7 +267,7 @@ void FinanceUpdateDailyProfit() } // Research costs - uint8_t level = gResearchFundingLevel; + uint8_t level = gameState.ResearchFundingLevel; current_profit -= research_cost_table[level]; // Loan costs diff --git a/src/openrct2/management/Research.cpp b/src/openrct2/management/Research.cpp index 5ff1ca088f..99349efac9 100644 --- a/src/openrct2/management/Research.cpp +++ b/src/openrct2/management/Research.cpp @@ -51,21 +51,6 @@ static constexpr int32_t _researchRate[] = { 400, }; -uint8_t gResearchFundingLevel; -uint8_t gResearchPriorities; -uint16_t gResearchProgress; -uint8_t gResearchProgressStage; -std::optional gResearchLastItem; -uint8_t gResearchExpectedMonth; -uint8_t gResearchExpectedDay; -std::optional gResearchNextItem; - -std::vector gResearchItemsUninvented; -std::vector gResearchItemsInvented; - -// 0x00EE787C -uint8_t gResearchUncompletedCategories; - static bool _researchedRideTypes[RIDE_TYPE_COUNT]; static bool _researchedRideEntries[MAX_RIDE_OBJECTS]; static bool _researchedSceneryItems[SCENERY_TYPE_COUNT][UINT16_MAX]; @@ -76,10 +61,10 @@ bool gSilentResearch = false; * * rct2: 0x006671AD, part of 0x00667132 */ -void ResearchResetItems() +void ResearchResetItems(GameState_t& gameState) { - gResearchItemsUninvented.clear(); - gResearchItemsInvented.clear(); + gameState.ResearchItemsUninvented.clear(); + gameState.ResearchItemsInvented.clear(); } /** @@ -88,14 +73,15 @@ void ResearchResetItems() */ void ResearchUpdateUncompletedTypes() { + auto& gameState = GetGameState(); int32_t uncompletedResearchTypes = 0; - for (auto const& researchItem : gResearchItemsUninvented) + for (auto const& researchItem : gameState.ResearchItemsUninvented) { uncompletedResearchTypes |= EnumToFlag(researchItem.category); } - gResearchUncompletedCategories = uncompletedResearchTypes; + gameState.ResearchUncompletedCategories = uncompletedResearchTypes; } /** @@ -104,17 +90,19 @@ void ResearchUpdateUncompletedTypes() */ static void ResearchCalculateExpectedDate() { - if (gResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH || gResearchFundingLevel == RESEARCH_FUNDING_NONE) + auto& gameState = GetGameState(); + if (gameState.ResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH + || gameState.ResearchFundingLevel == RESEARCH_FUNDING_NONE) { - gResearchExpectedDay = 255; + gameState.ResearchExpectedDay = 255; } else { auto& date = GetDate(); - int32_t progressRemaining = gResearchProgressStage == RESEARCH_STAGE_COMPLETING_DESIGN ? 0x10000 : 0x20000; - progressRemaining -= gResearchProgress; - int32_t daysRemaining = (progressRemaining / _researchRate[gResearchFundingLevel]) * 128; + int32_t progressRemaining = gameState.ResearchProgressStage == RESEARCH_STAGE_COMPLETING_DESIGN ? 0x10000 : 0x20000; + progressRemaining -= gameState.ResearchProgress; + int32_t daysRemaining = (progressRemaining / _researchRate[gameState.ResearchFundingLevel]) * 128; int32_t expectedDay = date.GetMonthTicks() + (daysRemaining & 0xFFFF); int32_t dayQuotient = expectedDay / 0x10000; @@ -123,8 +111,8 @@ static void ResearchCalculateExpectedDate() int32_t expectedMonth = DateGetMonth(date.GetMonthsElapsed() + dayQuotient + (daysRemaining >> 16)); expectedDay = (dayRemainder * Date::GetDaysInMonth(expectedMonth)) >> 16; - gResearchExpectedDay = expectedDay; - gResearchExpectedMonth = expectedMonth; + gameState.ResearchExpectedDay = expectedDay; + gameState.ResearchExpectedMonth = expectedMonth; } } @@ -136,11 +124,12 @@ static void ResearchInvalidateRelatedWindows() static void ResearchMarkAsFullyCompleted() { - gResearchProgress = 0; - gResearchProgressStage = RESEARCH_STAGE_FINISHED_ALL; + auto& gameState = GetGameState(); + gameState.ResearchProgress = 0; + gameState.ResearchProgressStage = RESEARCH_STAGE_FINISHED_ALL; ResearchInvalidateRelatedWindows(); // Reset funding to 0 if no more rides. - auto gameAction = ParkSetResearchFundingAction(gResearchPriorities, 0); + auto gameAction = ParkSetResearchFundingAction(gameState.ResearchPriorities, 0); GameActions::Execute(&gameAction); } @@ -150,37 +139,40 @@ static void ResearchMarkAsFullyCompleted() */ static void ResearchNextDesign() { - if (gResearchItemsUninvented.empty()) + auto& gameState = GetGameState(); + if (gameState.ResearchItemsUninvented.empty()) { ResearchMarkAsFullyCompleted(); return; } // Try to find a research item of a matching type, if none found, use any first item - auto it = std::find_if(gResearchItemsUninvented.begin(), gResearchItemsUninvented.end(), [](const auto& e) { - return (gResearchPriorities & EnumToFlag(e.category)) != 0; - }); - if (it == gResearchItemsUninvented.end()) + auto it = std::find_if( + gameState.ResearchItemsUninvented.begin(), gameState.ResearchItemsUninvented.end(), + [&gameState](const auto& e) { return (gameState.ResearchPriorities & EnumToFlag(e.category)) != 0; }); + if (it == gameState.ResearchItemsUninvented.end()) { - it = gResearchItemsUninvented.begin(); + it = gameState.ResearchItemsUninvented.begin(); } - gResearchNextItem = *it; - gResearchProgress = 0; - gResearchProgressStage = RESEARCH_STAGE_DESIGNING; + gameState.ResearchNextItem = *it; + gameState.ResearchProgress = 0; + gameState.ResearchProgressStage = RESEARCH_STAGE_DESIGNING; ResearchInvalidateRelatedWindows(); } static void MarkResearchItemInvented(const ResearchItem& researchItem) { - gResearchItemsUninvented.erase( - std::remove(gResearchItemsUninvented.begin(), gResearchItemsUninvented.end(), researchItem), - gResearchItemsUninvented.end()); + auto& gameState = GetGameState(); + gameState.ResearchItemsUninvented.erase( + std::remove(gameState.ResearchItemsUninvented.begin(), gameState.ResearchItemsUninvented.end(), researchItem), + gameState.ResearchItemsUninvented.end()); - if (std::find(gResearchItemsInvented.begin(), gResearchItemsInvented.end(), researchItem) == gResearchItemsInvented.end()) + if (std::find(gameState.ResearchItemsInvented.begin(), gameState.ResearchItemsInvented.end(), researchItem) + == gameState.ResearchItemsInvented.end()) { - gResearchItemsInvented.push_back(researchItem); + gameState.ResearchItemsInvented.push_back(researchItem); } } @@ -190,7 +182,8 @@ static void MarkResearchItemInvented(const ResearchItem& researchItem) */ void ResearchFinishItem(const ResearchItem& researchItem) { - gResearchLastItem = researchItem; + auto& gameState = GetGameState(); + gameState.ResearchLastItem = researchItem; ResearchInvalidateRelatedWindows(); if (researchItem.type == Research::EntryType::Ride) @@ -213,7 +206,7 @@ void ResearchFinishItem(const ResearchItem& researchItem) RideEntrySetInvented(rideEntryIndex); bool seenRideEntry[MAX_RIDE_OBJECTS]{}; - for (auto const& researchItem3 : gResearchItemsUninvented) + for (auto const& researchItem3 : gameState.ResearchItemsUninvented) { ObjectEntryIndex index = researchItem3.entryIndex; seenRideEntry[index] = true; @@ -322,46 +315,46 @@ void ResearchUpdate() return; } - if ((gameState.ParkFlags & PARK_FLAGS_NO_MONEY) && gResearchFundingLevel == RESEARCH_FUNDING_NONE) + if ((gameState.ParkFlags & PARK_FLAGS_NO_MONEY) && gameState.ResearchFundingLevel == RESEARCH_FUNDING_NONE) { researchLevel = RESEARCH_FUNDING_NORMAL; } else { - researchLevel = gResearchFundingLevel; + researchLevel = gameState.ResearchFundingLevel; } - currentResearchProgress = gResearchProgress; + currentResearchProgress = gameState.ResearchProgress; currentResearchProgress += _researchRate[researchLevel]; if (currentResearchProgress <= 0xFFFF) { - gResearchProgress = currentResearchProgress; + gameState.ResearchProgress = currentResearchProgress; } else { - switch (gResearchProgressStage) + switch (gameState.ResearchProgressStage) { case RESEARCH_STAGE_INITIAL_RESEARCH: ResearchNextDesign(); ResearchCalculateExpectedDate(); break; case RESEARCH_STAGE_DESIGNING: - gResearchProgress = 0; - gResearchProgressStage = RESEARCH_STAGE_COMPLETING_DESIGN; + gameState.ResearchProgress = 0; + gameState.ResearchProgressStage = RESEARCH_STAGE_COMPLETING_DESIGN; ResearchCalculateExpectedDate(); ResearchInvalidateRelatedWindows(); break; case RESEARCH_STAGE_COMPLETING_DESIGN: - MarkResearchItemInvented(*gResearchNextItem); - ResearchFinishItem(*gResearchNextItem); - gResearchProgress = 0; - gResearchProgressStage = RESEARCH_STAGE_INITIAL_RESEARCH; + MarkResearchItemInvented(*gameState.ResearchNextItem); + ResearchFinishItem(*gameState.ResearchNextItem); + gameState.ResearchProgress = 0; + gameState.ResearchProgressStage = RESEARCH_STAGE_INITIAL_RESEARCH; ResearchCalculateExpectedDate(); ResearchUpdateUncompletedTypes(); ResearchInvalidateRelatedWindows(); break; case RESEARCH_STAGE_FINISHED_ALL: - gResearchFundingLevel = RESEARCH_FUNDING_NONE; + gameState.ResearchFundingLevel = RESEARCH_FUNDING_NONE; break; } } @@ -373,6 +366,7 @@ void ResearchUpdate() */ void ResearchResetCurrentItem() { + auto& gameState = GetGameState(); SetEveryRideTypeNotInvented(); SetEveryRideEntryNotInvented(); @@ -380,14 +374,14 @@ void ResearchResetCurrentItem() SetAllSceneryItemsInvented(); SetAllSceneryGroupsNotInvented(); - for (const auto& researchItem : gResearchItemsInvented) + for (const auto& researchItem : gameState.ResearchItemsInvented) { ResearchFinishItem(researchItem); } - gResearchLastItem = std::nullopt; - gResearchProgressStage = RESEARCH_STAGE_INITIAL_RESEARCH; - gResearchProgress = 0; + gameState.ResearchLastItem = std::nullopt; + gameState.ResearchProgressStage = RESEARCH_STAGE_INITIAL_RESEARCH; + gameState.ResearchProgress = 0; } /** @@ -396,13 +390,14 @@ void ResearchResetCurrentItem() */ static void ResearchInsertUnresearched(ResearchItem&& item) { + auto& gameState = GetGameState(); // First check to make sure that entry is not already accounted for if (item.Exists()) { return; } - gResearchItemsUninvented.push_back(std::move(item)); + gameState.ResearchItemsUninvented.push_back(std::move(item)); } /** @@ -411,13 +406,14 @@ static void ResearchInsertUnresearched(ResearchItem&& item) */ static void ResearchInsertResearched(ResearchItem&& item) { + auto& gameState = GetGameState(); // First check to make sure that entry is not already accounted for if (item.Exists()) { return; } - gResearchItemsInvented.push_back(std::move(item)); + gameState.ResearchItemsInvented.push_back(std::move(item)); } /** @@ -426,11 +422,13 @@ static void ResearchInsertResearched(ResearchItem&& item) */ void ResearchRemove(const ResearchItem& researchItem) { - gResearchItemsUninvented.erase( - std::remove(gResearchItemsUninvented.begin(), gResearchItemsUninvented.end(), researchItem), - gResearchItemsUninvented.end()); - gResearchItemsInvented.erase( - std::remove(gResearchItemsInvented.begin(), gResearchItemsInvented.end(), researchItem), gResearchItemsInvented.end()); + auto& gameState = GetGameState(); + gameState.ResearchItemsUninvented.erase( + std::remove(gameState.ResearchItemsUninvented.begin(), gameState.ResearchItemsUninvented.end(), researchItem), + gameState.ResearchItemsUninvented.end()); + gameState.ResearchItemsInvented.erase( + std::remove(gameState.ResearchItemsInvented.begin(), gameState.ResearchItemsInvented.end(), researchItem), + gameState.ResearchItemsInvented.end()); } void ResearchInsert(ResearchItem&& item, bool researched) @@ -451,7 +449,8 @@ void ResearchInsert(ResearchItem&& item, bool researched) */ void ResearchPopulateListRandom() { - ResearchResetItems(); + auto& gameState = GetGameState(); + ResearchResetItems(gameState); // Rides for (int32_t i = 0; i < MAX_RIDE_OBJECTS; i++) @@ -615,6 +614,7 @@ void ScenerySetNotInvented(const ScenerySelection& sceneryItem) bool SceneryGroupIsInvented(int32_t sgIndex) { + auto& gameState = GetGameState(); const auto sgEntry = OpenRCT2::ObjectManager::GetObjectEntry(sgIndex); if (sgEntry == nullptr || sgEntry->SceneryEntries.empty()) { @@ -633,7 +633,8 @@ bool SceneryGroupIsInvented(int32_t sgIndex) } return std::none_of( - std::begin(gResearchItemsUninvented), std::end(gResearchItemsUninvented), [sgIndex](const ResearchItem& item) { + std::begin(gameState.ResearchItemsUninvented), std::end(gameState.ResearchItemsUninvented), + [sgIndex](const ResearchItem& item) { return item.type == Research::EntryType::Scenery && item.entryIndex == sgIndex; }); } @@ -737,11 +738,12 @@ StringId ResearchItem::GetName() const */ void ResearchRemoveFlags() { - for (auto& researchItem : gResearchItemsUninvented) + auto& gameState = GetGameState(); + for (auto& researchItem : gameState.ResearchItemsUninvented) { researchItem.flags &= ~(RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED | RESEARCH_ENTRY_FLAG_SCENERY_SET_ALWAYS_RESEARCHED); } - for (auto& researchItem : gResearchItemsInvented) + for (auto& researchItem : gameState.ResearchItemsInvented) { researchItem.flags &= ~(RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED | RESEARCH_ENTRY_FLAG_SCENERY_SET_ALWAYS_RESEARCHED); } @@ -794,16 +796,18 @@ static void ResearchMarkItemAsResearched(const ResearchItem& item) static void ResearchRebuildInventedTables() { + auto& gameState = GetGameState(); SetEveryRideTypeNotInvented(); SetEveryRideEntryInvented(); SetEveryRideEntryNotInvented(); SetAllSceneryItemsNotInvented(); - for (const auto& item : gResearchItemsInvented) + for (const auto& item : gameState.ResearchItemsInvented) { // Ignore item, if the research of it is in progress - if (gResearchProgressStage == RESEARCH_STAGE_DESIGNING || gResearchProgressStage == RESEARCH_STAGE_COMPLETING_DESIGN) + if (gameState.ResearchProgressStage == RESEARCH_STAGE_DESIGNING + || gameState.ResearchProgressStage == RESEARCH_STAGE_COMPLETING_DESIGN) { - if (item == gResearchNextItem) + if (item == gameState.ResearchNextItem) { continue; } @@ -816,9 +820,10 @@ static void ResearchRebuildInventedTables() static void ResearchAddAllMissingItems(bool isResearched) { + auto& gameState = GetGameState(); // Mark base ridetypes as seen if they exist in the invented research list. bool seenBaseEntry[MAX_RIDE_OBJECTS]{}; - for (auto const& researchItem : gResearchItemsInvented) + for (auto const& researchItem : gameState.ResearchItemsInvented) { ObjectEntryIndex index = researchItem.baseRideType; seenBaseEntry[index] = true; @@ -843,7 +848,7 @@ static void ResearchAddAllMissingItems(bool isResearched) } // Mark base ridetypes as seen if they exist in the uninvented research list. - for (auto const& researchItem : gResearchItemsUninvented) + for (auto const& researchItem : gameState.ResearchItemsUninvented) { ObjectEntryIndex index = researchItem.baseRideType; seenBaseEntry[index] = true; @@ -884,13 +889,14 @@ static void ResearchAddAllMissingItems(bool isResearched) void ResearchFix() { + auto& gameState = GetGameState(); // Remove null entries from the research list - ResearchRemoveNullItems(gResearchItemsInvented); - ResearchRemoveNullItems(gResearchItemsUninvented); + ResearchRemoveNullItems(gameState.ResearchItemsInvented); + ResearchRemoveNullItems(gameState.ResearchItemsUninvented); // Add missing entries to the research list // If research is complete, mark all the missing items as available - ResearchAddAllMissingItems(gResearchProgressStage == RESEARCH_STAGE_FINISHED_ALL); + ResearchAddAllMissingItems(gameState.ResearchProgressStage == RESEARCH_STAGE_FINISHED_ALL); // Now rebuild all the tables that say whether a ride or scenery item is invented ResearchRebuildInventedTables(); @@ -899,18 +905,20 @@ void ResearchFix() void ResearchItemsMakeAllUnresearched() { - gResearchItemsUninvented.insert( - gResearchItemsUninvented.end(), std::make_move_iterator(gResearchItemsInvented.begin()), - std::make_move_iterator(gResearchItemsInvented.end())); - gResearchItemsInvented.clear(); + auto& gameState = GetGameState(); + gameState.ResearchItemsUninvented.insert( + gameState.ResearchItemsUninvented.end(), std::make_move_iterator(gameState.ResearchItemsInvented.begin()), + std::make_move_iterator(gameState.ResearchItemsInvented.end())); + gameState.ResearchItemsInvented.clear(); } void ResearchItemsMakeAllResearched() { - gResearchItemsInvented.insert( - gResearchItemsInvented.end(), std::make_move_iterator(gResearchItemsUninvented.begin()), - std::make_move_iterator(gResearchItemsUninvented.end())); - gResearchItemsUninvented.clear(); + auto& gameState = GetGameState(); + gameState.ResearchItemsInvented.insert( + gameState.ResearchItemsInvented.end(), std::make_move_iterator(gameState.ResearchItemsUninvented.begin()), + std::make_move_iterator(gameState.ResearchItemsUninvented.end())); + gameState.ResearchItemsUninvented.clear(); } /** @@ -919,7 +927,10 @@ void ResearchItemsMakeAllResearched() */ void ResearchItemsShuffle() { - std::shuffle(std::begin(gResearchItemsUninvented), std::end(gResearchItemsUninvented), std::default_random_engine{}); + auto& gameState = GetGameState(); + std::shuffle( + std::begin(gameState.ResearchItemsUninvented), std::end(gameState.ResearchItemsUninvented), + std::default_random_engine{}); } bool ResearchItem::IsAlwaysResearched() const @@ -939,14 +950,15 @@ void ResearchItem::SetNull() bool ResearchItem::Exists() const { - for (auto const& researchItem : gResearchItemsUninvented) + auto& gameState = GetGameState(); + for (auto const& researchItem : gameState.ResearchItemsUninvented) { if (researchItem == *this) { return true; } } - for (auto const& researchItem : gResearchItemsInvented) + for (auto const& researchItem : gameState.ResearchItemsInvented) { if (researchItem == *this) { @@ -1039,9 +1051,10 @@ static void ResearchMarkRideTypeAsSeen(const ResearchItem& researchItem) void ResearchDetermineFirstOfType() { + auto& gameState = GetGameState(); _seenRideType.reset(); - for (const auto& researchItem : gResearchItemsInvented) + for (const auto& researchItem : gameState.ResearchItemsInvented) { if (researchItem.type != Research::EntryType::Ride) continue; @@ -1054,37 +1067,40 @@ void ResearchDetermineFirstOfType() if (rtd.HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY)) continue; - // The last research item will also be present in gResearchItemsInvented. + // The last research item will also be present in gameState.ResearchItemsInvented. // Avoid marking its ride type as "invented" prematurely. - if (gResearchLastItem.has_value() && !gResearchLastItem->IsNull() && researchItem == gResearchLastItem.value()) + if (gameState.ResearchLastItem.has_value() && !gameState.ResearchLastItem->IsNull() + && researchItem == gameState.ResearchLastItem.value()) continue; - // The next research item is (sometimes?) also present in gResearchItemsInvented, even though it isn't invented yet(!) - if (gResearchNextItem.has_value() && !gResearchNextItem->IsNull() && researchItem == gResearchNextItem.value()) + // The next research item is (sometimes?) also present in gameState.ResearchItemsInvented, even though it isn't invented + // yet(!) + if (gameState.ResearchNextItem.has_value() && !gameState.ResearchNextItem->IsNull() + && researchItem == gameState.ResearchNextItem.value()) continue; ResearchMarkRideTypeAsSeen(researchItem); } - if (gResearchLastItem.has_value()) + if (gameState.ResearchLastItem.has_value()) { - ResearchUpdateFirstOfType(&gResearchLastItem.value()); - ResearchMarkRideTypeAsSeen(gResearchLastItem.value()); + ResearchUpdateFirstOfType(&gameState.ResearchLastItem.value()); + ResearchMarkRideTypeAsSeen(gameState.ResearchLastItem.value()); } - if (gResearchNextItem.has_value()) + if (gameState.ResearchNextItem.has_value()) { - ResearchUpdateFirstOfType(&gResearchNextItem.value()); - ResearchMarkRideTypeAsSeen(gResearchNextItem.value()); + ResearchUpdateFirstOfType(&gameState.ResearchNextItem.value()); + ResearchMarkRideTypeAsSeen(gameState.ResearchNextItem.value()); } - for (auto& researchItem : gResearchItemsUninvented) + for (auto& researchItem : gameState.ResearchItemsUninvented) { - // The next research item is (sometimes?) also present in gResearchItemsUninvented - if (gResearchNextItem.has_value() && !gResearchNextItem->IsNull() - && researchItem.baseRideType == gResearchNextItem.value().baseRideType) + // The next research item is (sometimes?) also present in gameState.ResearchItemsUninvented + if (gameState.ResearchNextItem.has_value() && !gameState.ResearchNextItem->IsNull() + && researchItem.baseRideType == gameState.ResearchNextItem.value().baseRideType) { // Copy the "first of type" flag. - researchItem.flags = gResearchNextItem->flags; + researchItem.flags = gameState.ResearchNextItem->flags; continue; } diff --git a/src/openrct2/management/Research.h b/src/openrct2/management/Research.h index e13b7ce8b2..ceb4c9fe13 100644 --- a/src/openrct2/management/Research.h +++ b/src/openrct2/management/Research.h @@ -20,6 +20,11 @@ struct RideObjectEntry; struct ScenerySelection; +namespace OpenRCT2 +{ + struct GameState_t; +} + namespace Research { enum class EntryType : uint8_t @@ -110,21 +115,9 @@ enum RESEARCH_STAGE_FINISHED_ALL }; -extern uint8_t gResearchFundingLevel; -extern uint8_t gResearchPriorities; -extern uint16_t gResearchProgress; -extern uint8_t gResearchProgressStage; -extern uint8_t gResearchExpectedMonth; -extern uint8_t gResearchExpectedDay; -extern std::optional gResearchLastItem; -extern std::optional gResearchNextItem; - -extern std::vector gResearchItemsUninvented; -extern std::vector gResearchItemsInvented; -extern uint8_t gResearchUncompletedCategories; extern bool gSilentResearch; -void ResearchResetItems(); +void ResearchResetItems(OpenRCT2::GameState_t& gameState); void ResearchUpdateUncompletedTypes(); void ResearchUpdate(); void ResearchResetCurrentItem(); diff --git a/src/openrct2/park/ParkFile.cpp b/src/openrct2/park/ParkFile.cpp index a01450af5b..40047387c4 100644 --- a/src/openrct2/park/ParkFile.cpp +++ b/src/openrct2/park/ParkFile.cpp @@ -944,20 +944,22 @@ namespace OpenRCT2 void ReadWriteResearchChunk(GameState_t& gameState, OrcaStream& os) { - os.ReadWriteChunk(ParkFileChunkType::RESEARCH, [](OrcaStream::ChunkStream& cs) { + os.ReadWriteChunk(ParkFileChunkType::RESEARCH, [&gameState](OrcaStream::ChunkStream& cs) { // Research status - cs.ReadWrite(gResearchFundingLevel); - cs.ReadWrite(gResearchPriorities); - cs.ReadWrite(gResearchProgressStage); - cs.ReadWrite(gResearchProgress); - cs.ReadWrite(gResearchExpectedMonth); - cs.ReadWrite(gResearchExpectedDay); - ReadWriteResearchItem(cs, gResearchLastItem); - ReadWriteResearchItem(cs, gResearchNextItem); + cs.ReadWrite(gameState.ResearchFundingLevel); + cs.ReadWrite(gameState.ResearchPriorities); + cs.ReadWrite(gameState.ResearchProgressStage); + cs.ReadWrite(gameState.ResearchProgress); + cs.ReadWrite(gameState.ResearchExpectedMonth); + cs.ReadWrite(gameState.ResearchExpectedDay); + ReadWriteResearchItem(cs, gameState.ResearchLastItem); + ReadWriteResearchItem(cs, gameState.ResearchNextItem); // Invention list - cs.ReadWriteVector(gResearchItemsUninvented, [&cs](ResearchItem& item) { ReadWriteResearchItem(cs, item); }); - cs.ReadWriteVector(gResearchItemsInvented, [&cs](ResearchItem& item) { ReadWriteResearchItem(cs, item); }); + cs.ReadWriteVector( + gameState.ResearchItemsUninvented, [&cs](ResearchItem& item) { ReadWriteResearchItem(cs, item); }); + cs.ReadWriteVector( + gameState.ResearchItemsInvented, [&cs](ResearchItem& item) { ReadWriteResearchItem(cs, item); }); }); } diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 10f9f0c730..8a0066e14f 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -181,7 +181,7 @@ namespace RCT1 ImportTileElements(); ImportPeepSpawns(); ImportFinance(gameState); - ImportResearch(); + ImportResearch(gameState); ImportParkName(); ImportParkFlags(gameState); ImportClimate(gameState); @@ -1862,12 +1862,12 @@ namespace RCT1 return 0; } - void ImportResearch() + void ImportResearch(GameState_t& gameState) { // All available objects must be loaded before this method is called as it // requires them to correctly insert objects into the research list - ResearchResetItems(); + ResearchResetItems(gameState); size_t researchListCount; const RCT1::ResearchItem* researchList = GetResearchList(&researchListCount); @@ -2024,41 +2024,41 @@ namespace RCT1 { activeResearchTypes |= EnumToFlag(ResearchCategory::SceneryGroup); } - gResearchPriorities = activeResearchTypes; - gResearchFundingLevel = _s4.ResearchLevel; + gameState.ResearchPriorities = activeResearchTypes; + gameState.ResearchFundingLevel = _s4.ResearchLevel; // This will mark items as researched/unresearched according to the research list. // This needs to be called before importing progress, as it will reset it. ResearchResetCurrentItem(); // Research history - gResearchProgress = _s4.ResearchProgress; - gResearchProgressStage = _s4.ResearchProgressStage; - gResearchExpectedDay = _s4.NextResearchExpectedDay; - gResearchExpectedMonth = _s4.NextResearchExpectedMonth; + gameState.ResearchProgress = _s4.ResearchProgress; + gameState.ResearchProgressStage = _s4.ResearchProgressStage; + gameState.ResearchExpectedDay = _s4.NextResearchExpectedDay; + gameState.ResearchExpectedMonth = _s4.NextResearchExpectedMonth; if (_s4.LastResearchFlags == 0xFF) { - gResearchLastItem = std::nullopt; + gameState.ResearchLastItem = std::nullopt; } else { ::ResearchItem researchItem = {}; ConvertResearchEntry(&researchItem, _s4.LastResearchItem, _s4.LastResearchType); - gResearchLastItem = researchItem; + gameState.ResearchLastItem = researchItem; } if (_s4.NextResearchFlags == 0xFF) { - gResearchNextItem = std::nullopt; - gResearchProgressStage = RESEARCH_STAGE_INITIAL_RESEARCH; - gResearchProgress = 0; + gameState.ResearchNextItem = std::nullopt; + gameState.ResearchProgressStage = RESEARCH_STAGE_INITIAL_RESEARCH; + gameState.ResearchProgress = 0; } else { ::ResearchItem researchItem = {}; ConvertResearchEntry(&researchItem, _s4.NextResearchItem, _s4.NextResearchType); - gResearchNextItem = researchItem; + gameState.ResearchNextItem = researchItem; } } diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 094ec5dcef..4ff6937e78 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -283,7 +283,7 @@ namespace RCT2 ImportPeepSpawns(); gGuestChangeModifier = _s6.GuestCountChangeModifier; - gResearchFundingLevel = _s6.CurrentResearchLevel; + gameState.ResearchFundingLevel = _s6.CurrentResearchLevel; // Pad01357400 // _s6.ResearchedTrackTypesA // _s6.ResearchedTrackTypesB @@ -318,22 +318,24 @@ namespace RCT2 } } - gResearchPriorities = _s6.ActiveResearchTypes; - gResearchProgressStage = _s6.ResearchProgressStage; + gameState.ResearchPriorities = _s6.ActiveResearchTypes; + gameState.ResearchProgressStage = _s6.ResearchProgressStage; if (_s6.LastResearchedItemSubject != RCT12_RESEARCHED_ITEMS_SEPARATOR) - gResearchLastItem = RCT12ResearchItem{ _s6.LastResearchedItemSubject, EnumValue(ResearchCategory::Transport) } - .ToResearchItem(); + gameState.ResearchLastItem = RCT12ResearchItem{ _s6.LastResearchedItemSubject, + EnumValue(ResearchCategory::Transport) } + .ToResearchItem(); else - gResearchLastItem = std::nullopt; + gameState.ResearchLastItem = std::nullopt; // Pad01357CF8 if (_s6.NextResearchItem != RCT12_RESEARCHED_ITEMS_SEPARATOR) - gResearchNextItem = RCT12ResearchItem{ _s6.NextResearchItem, _s6.NextResearchCategory }.ToResearchItem(); + gameState.ResearchNextItem = RCT12ResearchItem{ _s6.NextResearchItem, _s6.NextResearchCategory } + .ToResearchItem(); else - gResearchNextItem = std::nullopt; + gameState.ResearchNextItem = std::nullopt; - gResearchProgress = _s6.ResearchProgress; - gResearchExpectedDay = _s6.NextResearchExpectedDay; - gResearchExpectedMonth = _s6.NextResearchExpectedMonth; + gameState.ResearchProgress = _s6.ResearchProgress; + gameState.ResearchExpectedDay = _s6.NextResearchExpectedDay; + gameState.ResearchExpectedMonth = _s6.NextResearchExpectedMonth; gameState.GuestInitialHappiness = _s6.GuestInitialHappiness; gameState.ParkSize = _s6.ParkSize; _guestGenerationProbability = _s6.GuestGenerationProbability; @@ -407,7 +409,7 @@ namespace RCT2 gLastEntranceStyle = _s6.LastEntranceStyle; // rct1_water_colour // Pad01358842 - ImportResearchList(); + ImportResearchList(gameState); gMapBaseZ = _s6.MapBaseZ; gBankLoanInterestRate = _s6.CurrentInterestRate; // Pad0135934B @@ -1638,7 +1640,7 @@ namespace RCT2 } } - void ImportResearchList() + void ImportResearchList(GameState_t gameState) { bool invented = true; for (const auto& researchItem : _s6.ResearchItems) @@ -1654,9 +1656,9 @@ namespace RCT2 } if (invented) - gResearchItemsInvented.emplace_back(researchItem.ToResearchItem()); + gameState.ResearchItemsInvented.emplace_back(researchItem.ToResearchItem()); else - gResearchItemsUninvented.emplace_back(researchItem.ToResearchItem()); + gameState.ResearchItemsUninvented.emplace_back(researchItem.ToResearchItem()); } } diff --git a/src/openrct2/scripting/bindings/world/ScResearch.cpp b/src/openrct2/scripting/bindings/world/ScResearch.cpp index 2d89735771..fe9a602275 100644 --- a/src/openrct2/scripting/bindings/world/ScResearch.cpp +++ b/src/openrct2/scripting/bindings/world/ScResearch.cpp @@ -12,6 +12,7 @@ # include "ScResearch.hpp" # include "../../../Context.h" +# include "../../../GameState.h" # include "../../../common.h" # include "../../../core/String.hpp" # include "../../../management/Research.h" @@ -20,6 +21,8 @@ # include "../../ScriptEngine.h" # include "../object/ScObject.hpp" +using namespace OpenRCT2; + namespace OpenRCT2::Scripting { static const DukEnumMap ResearchStageMap({ @@ -92,13 +95,13 @@ namespace OpenRCT2::Scripting uint8_t ScResearch::funding_get() const { - return gResearchFundingLevel; + return GetGameState().ResearchFundingLevel; } void ScResearch::funding_set(uint8_t value) { ThrowIfGameStateNotMutable(); - gResearchFundingLevel = std::clamp(value, RESEARCH_FUNDING_NONE, RESEARCH_FUNDING_MAXIMUM); + GetGameState().ResearchFundingLevel = std::clamp(value, RESEARCH_FUNDING_NONE, RESEARCH_FUNDING_MAXIMUM); } std::vector ScResearch::priorities_get() const @@ -107,7 +110,7 @@ namespace OpenRCT2::Scripting for (auto i = EnumValue(ResearchCategory::Transport); i <= EnumValue(ResearchCategory::SceneryGroup); i++) { auto category = static_cast(i); - if (gResearchPriorities & EnumToFlag(category)) + if (GetGameState().ResearchPriorities & EnumToFlag(category)) { result.emplace_back(ResearchCategoryMap[category]); } @@ -128,12 +131,12 @@ namespace OpenRCT2::Scripting priorities |= EnumToFlag(*category); } } - gResearchPriorities = priorities; + GetGameState().ResearchPriorities = priorities; } std::string ScResearch::stage_get() const { - return std::string(ResearchStageMap[gResearchProgressStage]); + return std::string(ResearchStageMap[GetGameState().ResearchProgressStage]); } void ScResearch::stage_set(const std::string& value) @@ -142,53 +145,57 @@ namespace OpenRCT2::Scripting auto it = ResearchStageMap.find(value); if (it != ResearchStageMap.end()) { - gResearchProgressStage = it->second; + GetGameState().ResearchProgressStage = it->second; } } uint16_t ScResearch::progress_get() const { - return gResearchProgress; + return GetGameState().ResearchProgress; } void ScResearch::progress_set(uint16_t value) { ThrowIfGameStateNotMutable(); - gResearchProgress = value; + GetGameState().ResearchProgress = value; } DukValue ScResearch::expectedMonth_get() const { - if (gResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH || gResearchExpectedDay == 255) + const auto& gameState = GetGameState(); + if (gameState.ResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH || gameState.ResearchExpectedDay == 255) return ToDuk(_context, nullptr); - return ToDuk(_context, gResearchExpectedMonth); + return ToDuk(_context, gameState.ResearchExpectedMonth); } DukValue ScResearch::expectedDay_get() const { - if (gResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH || gResearchExpectedDay == 255) + const auto& gameState = GetGameState(); + if (gameState.ResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH || gameState.ResearchExpectedDay == 255) return ToDuk(_context, nullptr); - return ToDuk(_context, gResearchExpectedDay + 1); + return ToDuk(_context, gameState.ResearchExpectedDay + 1); } DukValue ScResearch::lastResearchedItem_get() const { - if (!gResearchLastItem) + const auto& gameState = GetGameState(); + if (!gameState.ResearchLastItem) return ToDuk(_context, nullptr); - return ToDuk(_context, *gResearchLastItem); + return ToDuk(_context, *gameState.ResearchLastItem); } DukValue ScResearch::expectedItem_get() const { - if (gResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH || !gResearchNextItem) + const auto& gameState = GetGameState(); + if (gameState.ResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH || !gameState.ResearchNextItem) return ToDuk(_context, nullptr); - return ToDuk(_context, *gResearchNextItem); + return ToDuk(_context, *gameState.ResearchNextItem); } std::vector ScResearch::inventedItems_get() const { std::vector result; - for (auto& item : gResearchItemsInvented) + for (auto& item : GetGameState().ResearchItemsInvented) { result.push_back(ToDuk(_context, item)); } @@ -199,14 +206,14 @@ namespace OpenRCT2::Scripting { ThrowIfGameStateNotMutable(); auto list = ConvertResearchList(value); - gResearchItemsInvented = std::move(list); + GetGameState().ResearchItemsInvented = std::move(list); ResearchFix(); } std::vector ScResearch::uninventedItems_get() const { std::vector result; - for (auto& item : gResearchItemsUninvented) + for (auto& item : GetGameState().ResearchItemsUninvented) { result.push_back(ToDuk(_context, item)); } @@ -217,7 +224,7 @@ namespace OpenRCT2::Scripting { ThrowIfGameStateNotMutable(); auto list = ConvertResearchList(value); - gResearchItemsUninvented = std::move(list); + GetGameState().ResearchItemsUninvented = std::move(list); ResearchFix(); } diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index ae4e0b30e8..4383cd1520 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -266,10 +266,10 @@ void Park::Initialise() _guestGenerationProbability = 0; gTotalRideValueForMoney = 0; _suggestedGuestMaximum = 0; - gResearchLastItem = std::nullopt; + gameState.ResearchLastItem = std::nullopt; gMarketingCampaigns.clear(); - ResearchResetItems(); + ResearchResetItems(gameState); FinanceInit(); SetEveryRideTypeNotInvented(); @@ -281,10 +281,10 @@ void Park::Initialise() gPeepSpawns.clear(); ParkEntranceReset(); - gResearchPriorities = EnumsToFlags( + gameState.ResearchPriorities = EnumsToFlags( ResearchCategory::Transport, ResearchCategory::Gentle, ResearchCategory::Rollercoaster, ResearchCategory::Thrill, ResearchCategory::Water, ResearchCategory::Shop, ResearchCategory::SceneryGroup); - gResearchFundingLevel = RESEARCH_FUNDING_NORMAL; + gameState.ResearchFundingLevel = RESEARCH_FUNDING_NORMAL; gameState.GuestInitialCash = 50.00_GBP; gameState.GuestInitialHappiness = CalculateGuestInitialHappiness(50);