diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 40931282c0..7c61d5a50e 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3647,6 +3647,8 @@ STR_6541 :{WINDOW_COLOUR_2}Rocky Mountain Construction Group, Josef Wiegand G STR_6542 :Contributors STR_6543 :Contributors… STR_6544 :Loan cannot be negative! +STR_6545 :Use RCT1 interest calculation +STR_6546 :Use the interest calculation algorithm of RollerCoaster Tycoon 1, which used a fixed percentage of approximately 1.33%. ############# # Scenarios # diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 9342f93d40..c9e22e15dc 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -8,6 +8,7 @@ - Feature: [objects#226] Port RCT1 Corkscrew Coaster train. - Feature: [objects#229] Port RCT1 go karts with helmets. - Improved: [#11473] Hot reload for plug-ins now works on macOS. +- Improved: [#12466] RCT1 parks now use RCT1’s interest calculation algorithm. - Improved: [#17288] Reorganise the order of shortcut keys in the Shortcut Keys window. - Improved: [#18706] Ability to view the list of contributors in-game. - Improved: [#18749] Ability to have 4 active awards for more than one month in a row. diff --git a/src/openrct2-ui/windows/EditorScenarioOptions.cpp b/src/openrct2-ui/windows/EditorScenarioOptions.cpp index 820d5763ad..d7c94ef098 100644 --- a/src/openrct2-ui/windows/EditorScenarioOptions.cpp +++ b/src/openrct2-ui/windows/EditorScenarioOptions.cpp @@ -80,6 +80,7 @@ enum { WIDX_INTEREST_RATE_INCREASE, WIDX_INTEREST_RATE_DECREASE, WIDX_FORBID_MARKETING, + WIDX_RCT1_INTEREST, // Guests tab WIDX_CASH_PER_GUEST = WIDX_PAGE_START, @@ -130,6 +131,7 @@ static Widget window_editor_scenario_options_financial_widgets[] = { MakeSpinnerWidgets({168, 99}, { 100, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // NB: 3 widgets MakeSpinnerWidgets({168, 116}, { 70, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // NB: 3 widgets MakeWidget ({ 8, 133}, {WW_FINANCIAL - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_FORBID_MARKETING, STR_FORBID_MARKETING_TIP ), + MakeWidget ({ 8, 116}, {WW_FINANCIAL - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_RCT1_INTEREST, STR_RCT1_INTEREST_TIP ), WIDGETS_END, }; @@ -394,6 +396,14 @@ private: Invalidate(); break; } + case WIDX_RCT1_INTEREST: + { + auto scenarioSetSetting = ScenarioSetSettingAction( + ScenarioSetSetting::UseRCT1Interest, gParkFlags & PARK_FLAGS_RCT1_INTEREST ? 0 : 1); + GameActions::Execute(&scenarioSetSetting); + Invalidate(); + break; + } } } @@ -557,7 +567,7 @@ private: if (gParkFlags & PARK_FLAGS_NO_MONEY) { SetWidgetPressed(WIDX_NO_MONEY, true); - for (int32_t i = WIDX_INITIAL_CASH; i <= WIDX_FORBID_MARKETING; i++) + for (int32_t i = WIDX_INITIAL_CASH; i <= WIDX_RCT1_INTEREST; i++) widgets[i].type = WindowWidgetType::Empty; } else @@ -572,10 +582,23 @@ private: widgets[WIDX_MAXIMUM_LOAN].type = WindowWidgetType::Spinner; widgets[WIDX_MAXIMUM_LOAN_INCREASE].type = WindowWidgetType::Button; widgets[WIDX_MAXIMUM_LOAN_DECREASE].type = WindowWidgetType::Button; - widgets[WIDX_INTEREST_RATE].type = WindowWidgetType::Spinner; - widgets[WIDX_INTEREST_RATE_INCREASE].type = WindowWidgetType::Button; - widgets[WIDX_INTEREST_RATE_DECREASE].type = WindowWidgetType::Button; widgets[WIDX_FORBID_MARKETING].type = WindowWidgetType::Checkbox; + + if (gParkFlags & PARK_FLAGS_RCT1_INTEREST) + { + widgets[WIDX_INTEREST_RATE].type = WindowWidgetType::Empty; + widgets[WIDX_INTEREST_RATE_INCREASE].type = WindowWidgetType::Empty; + widgets[WIDX_INTEREST_RATE_DECREASE].type = WindowWidgetType::Empty; + widgets[WIDX_RCT1_INTEREST].type = WindowWidgetType::Checkbox; + SetWidgetPressed(WIDX_RCT1_INTEREST, true); + } + else + { + widgets[WIDX_INTEREST_RATE].type = WindowWidgetType::Spinner; + widgets[WIDX_INTEREST_RATE_INCREASE].type = WindowWidgetType::Button; + widgets[WIDX_INTEREST_RATE_DECREASE].type = WindowWidgetType::Button; + widgets[WIDX_RCT1_INTEREST].type = WindowWidgetType::Empty; + } } SetWidgetPressed(WIDX_FORBID_MARKETING, gParkFlags & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN); diff --git a/src/openrct2-ui/windows/Finances.cpp b/src/openrct2-ui/windows/Finances.cpp index 8de723064b..7a74041e5b 100644 --- a/src/openrct2-ui/windows/Finances.cpp +++ b/src/openrct2-ui/windows/Finances.cpp @@ -557,12 +557,15 @@ public: // Loan and interest rate DrawTextBasic(&dpi, windowPos + ScreenCoordsXY{ 8, 279 }, STR_FINANCES_SUMMARY_LOAN); - auto ft = Formatter(); - ft.Add(gBankLoanInterestRate); - DrawTextBasic(&dpi, windowPos + ScreenCoordsXY{ 167, 279 }, STR_FINANCES_SUMMARY_AT_X_PER_YEAR, ft); + if (!(gParkFlags & PARK_FLAGS_RCT1_INTEREST)) + { + auto ft = Formatter(); + ft.Add(gBankLoanInterestRate); + DrawTextBasic(&dpi, windowPos + ScreenCoordsXY{ 167, 279 }, STR_FINANCES_SUMMARY_AT_X_PER_YEAR, ft); + } // Current cash - ft = Formatter(); + auto ft = Formatter(); ft.Add(gCash); StringId stringId = gCash >= 0 ? STR_CASH_LABEL : STR_CASH_NEGATIVE_LABEL; DrawTextBasic(&dpi, windowPos + ScreenCoordsXY{ 8, 294 }, stringId, ft); diff --git a/src/openrct2/actions/ScenarioSetSettingAction.cpp b/src/openrct2/actions/ScenarioSetSettingAction.cpp index 2a66f0c41f..3f018cc37b 100644 --- a/src/openrct2/actions/ScenarioSetSettingAction.cpp +++ b/src/openrct2/actions/ScenarioSetSettingAction.cpp @@ -246,6 +246,18 @@ GameActions::Result ScenarioSetSettingAction::Execute() const case ScenarioSetSetting::AllowEarlyCompletion: gAllowEarlyCompletionInNetworkPlay = _value; break; + case ScenarioSetSetting::UseRCT1Interest: + { + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_RCT1_INTEREST; + } + else + { + gParkFlags &= ~PARK_FLAGS_RCT1_INTEREST; + } + break; + } default: LOG_ERROR("Invalid setting: %u", _setting); return GameActions::Result(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); diff --git a/src/openrct2/actions/ScenarioSetSettingAction.h b/src/openrct2/actions/ScenarioSetSettingAction.h index 948a44d54b..f0b74cd4c0 100644 --- a/src/openrct2/actions/ScenarioSetSettingAction.h +++ b/src/openrct2/actions/ScenarioSetSettingAction.h @@ -35,6 +35,7 @@ enum class ScenarioSetSetting : uint8_t ParkRatingHigherDifficultyLevel, GuestGenerationHigherDifficultyLevel, AllowEarlyCompletion, + UseRCT1Interest, Count }; diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index bf0e8acd05..0d15d201a4 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -3941,6 +3941,9 @@ enum : uint16_t STR_LOAN_CANT_BE_NEGATIVE = 6544, + STR_RCT1_INTEREST = 6545, + STR_RCT1_INTEREST_TIP = 6546, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings }; diff --git a/src/openrct2/management/Finance.cpp b/src/openrct2/management/Finance.cpp index 6ed3cffd37..13620b516a 100644 --- a/src/openrct2/management/Finance.cpp +++ b/src/openrct2/management/Finance.cpp @@ -148,8 +148,9 @@ void FinancePayInterest() // This variable uses the 64-bit type as the computation below can involve multiplying very large numbers // that will overflow money32 if the loan is greater than (1 << 31) / (5 * current_interest_rate) const money64 current_loan = gBankLoan; - const uint8_t current_interest_rate = gBankLoanInterestRate; - const money32 interest_to_pay = (current_loan * 5 * current_interest_rate) >> 14; + const auto current_interest_rate = gBankLoanInterestRate; + const money32 interest_to_pay = (gParkFlags & PARK_FLAGS_RCT1_INTEREST) ? (current_loan / 2400) + : (current_loan * 5 * current_interest_rate) >> 14; FinancePayment(interest_to_pay, ExpenditureType::Interest); } diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index c2e281fa1f..66aa7596ed 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -43,7 +43,7 @@ // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -#define NETWORK_STREAM_VERSION "5" +#define NETWORK_STREAM_VERSION "6" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 6386765191..4ae86c35a1 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -2203,6 +2203,7 @@ namespace RCT1 // Flags gParkFlags = _s4.ParkFlags; gParkFlags &= ~PARK_FLAGS_ANTI_CHEAT_DEPRECATED; + gParkFlags |= PARK_FLAGS_RCT1_INTEREST; // Loopy Landscape parks can set a flag to lock the entry price to free. // If this flag is not set, the player can ask money for both rides and entry. if (!(_s4.ParkFlags & RCT1_PARK_FLAGS_PARK_ENTRY_LOCKED_AT_FREE)) diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index 43d74876f7..5c6496d8c2 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -40,7 +40,9 @@ enum : uint32_t PARK_FLAGS_NO_MONEY_SCENARIO = (1 << 17), // Deprecated, originally used in scenario editor PARK_FLAGS_SPRITES_INITIALISED = (1 << 18), // After a scenario is loaded this prevents edits in the scenario editor PARK_FLAGS_SIX_FLAGS_DEPRECATED = (1 << 19), // Not used anymore - PARK_FLAGS_UNLOCK_ALL_PRICES = (1u << 31), // OpenRCT2 only! + + PARK_FLAGS_RCT1_INTEREST = (1u << 30), // OpenRCT2 only + PARK_FLAGS_UNLOCK_ALL_PRICES = (1u << 31), // OpenRCT2 only }; struct Guest;