1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-02-01 19:25:12 +01:00

Merge pull request #21304 from Gymnasiast/refactor/gresearch-to-gamestate

Move gResearch* globals to GameState_t
This commit is contained in:
Tulio Leao
2024-01-29 20:03:31 -03:00
committed by GitHub
13 changed files with 287 additions and 231 deletions

View File

@@ -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.

View File

@@ -11,6 +11,7 @@
#include <openrct2-ui/interface/Widget.h>
#include <openrct2-ui/windows/Window.h>
#include <openrct2/Editor.h>
#include <openrct2/GameState.h>
#include <openrct2/Input.h>
#include <openrct2/OpenRCT2.h>
#include <openrct2/interface/Cursors.h>
@@ -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<int32_t>(gResearchItemsInvented.size()) * SCROLLABLE_ROW_HEIGHT;
size.height = static_cast<int32_t>(gameState.ResearchItemsInvented.size()) * SCROLLABLE_ROW_HEIGHT;
}
else
{
size.height = static_cast<int32_t>(gResearchItemsUninvented.size()) * SCROLLABLE_ROW_HEIGHT;
size.height = static_cast<int32_t>(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;

View File

@@ -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<StringId>(STR_RESEARCH_UNKNOWN);
}
else if (gResearchProgressStage == RESEARCH_STAGE_DESIGNING)
else if (gameState.ResearchProgressStage == RESEARCH_STAGE_DESIGNING)
{
ft.Add<StringId>(gResearchNextItem->GetCategoryName());
ft.Add<StringId>(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<StringId>(gResearchNextItem->GetName());
ft.Add<StringId>(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<StringId>(rtd.Naming.Name);
}
else
{
ft.Add<StringId>(gResearchNextItem->GetName());
ft.Add<StringId>(gameState.ResearchNextItem->GetName());
ft.Add<StringId>(rtd.Naming.Name);
label = STR_RESEARCH_TYPE_LABEL_VEHICLE;
}
}
else
{
ft.Add<StringId>(gResearchNextItem->GetName());
ft.Add<StringId>(gameState.ResearchNextItem->GetName());
}
DrawTextWrapped(dpi, screenCoords, 296, label, ft);
screenCoords.y += 25;
// Progress
ft = Formatter();
ft.Add<StringId>(ResearchStageNames[gResearchProgressStage]);
ft.Add<StringId>(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<StringId>(STR_RESEARCH_EXPECTED_FORMAT);
ft.Add<StringId>(DateDayNames[gResearchExpectedDay]);
ft.Add<StringId>(DateGameMonthNames[gResearchExpectedMonth]);
ft.Add<StringId>(DateDayNames[gameState.ResearchExpectedDay]);
ft.Add<StringId>(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<StringId>(gResearchLastItem->GetName());
ft.Add<StringId>(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<StringId>(gResearchLastItem->GetName());
ft.Add<StringId>(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<StringId>(rtd.Naming.Name);
}
else
{
ft.Add<StringId>(gResearchLastItem->GetName());
ft.Add<StringId>(gameState.ResearchLastItem->GetName());
ft.Add<StringId>(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<money64>(research_cost_table[currentResearchLevel]);
DrawTextBasic(dpi, w->windowPos + ScreenCoordsXY{ 10, 77 }, STR_RESEARCH_COST_PER_MONTH, ft);

View File

@@ -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<ResearchItem> ResearchLastItem;
std::optional<ResearchItem> ResearchNextItem;
std::vector<ResearchItem> ResearchItemsUninvented;
std::vector<ResearchItem> ResearchItemsInvented;
uint8_t ResearchUncompletedCategories;
};
GameState_t& GetGameState();

View File

@@ -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));

View File

@@ -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

View File

@@ -51,21 +51,6 @@ static constexpr int32_t _researchRate[] = {
400,
};
uint8_t gResearchFundingLevel;
uint8_t gResearchPriorities;
uint16_t gResearchProgress;
uint8_t gResearchProgressStage;
std::optional<ResearchItem> gResearchLastItem;
uint8_t gResearchExpectedMonth;
uint8_t gResearchExpectedDay;
std::optional<ResearchItem> gResearchNextItem;
std::vector<ResearchItem> gResearchItemsUninvented;
std::vector<ResearchItem> 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<SceneryGroupEntry>(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;
}

View File

@@ -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<ResearchItem> gResearchLastItem;
extern std::optional<ResearchItem> gResearchNextItem;
extern std::vector<ResearchItem> gResearchItemsUninvented;
extern std::vector<ResearchItem> gResearchItemsInvented;
extern uint8_t gResearchUncompletedCategories;
extern bool gSilentResearch;
void ResearchResetItems();
void ResearchResetItems(OpenRCT2::GameState_t& gameState);
void ResearchUpdateUncompletedTypes();
void ResearchUpdate();
void ResearchResetCurrentItem();

View File

@@ -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); });
});
}

View File

@@ -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;
}
}

View File

@@ -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());
}
}

View File

@@ -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<uint8_t> 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<uint8_t>(value, RESEARCH_FUNDING_NONE, RESEARCH_FUNDING_MAXIMUM);
GetGameState().ResearchFundingLevel = std::clamp<uint8_t>(value, RESEARCH_FUNDING_NONE, RESEARCH_FUNDING_MAXIMUM);
}
std::vector<std::string> 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<ResearchCategory>(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<DukValue> ScResearch::inventedItems_get() const
{
std::vector<DukValue> 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<DukValue> ScResearch::uninventedItems_get() const
{
std::vector<DukValue> 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();
}

View File

@@ -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);