From 0d6cde2cdbb21f0fd49019b557847503eae28a14 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 25 Jun 2017 18:34:37 +0100 Subject: [PATCH 01/11] Create a Park class --- src/openrct2/Context.cpp | 1 + src/openrct2/world/Park.cpp | 59 ++++++++++++++++++++++++++++++------- src/openrct2/world/Park.h | 24 ++++++++++++--- 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index f09f37de80..f2d8d53446 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -52,6 +52,7 @@ #include "title/TitleScreen.h" #include "title/TitleSequenceManager.h" #include "ui/WindowManager.h" +#include "world/Park.h" #include "Version.h" #include "audio/audio.h" diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index db33468581..981b03625f 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -213,7 +213,7 @@ sint32 calculate_park_rating() sint32 num_lost_guests; // -150 to +3 based on a range of guests from 0 to 2000 - result -= 150 - (Math::Min((uint16)2000, gNumGuestsInPark) / 13); + result -= 150 - (std::min(2000, gNumGuestsInPark) / 13); // Find the number of happy peeps and the number of peeps who can't find the park exit num_happy_peeps = 0; @@ -231,7 +231,7 @@ sint32 calculate_park_rating() result -= 500; if (gNumGuestsInPark > 0) - result += 2 * Math::Min(250, (num_happy_peeps * 300) / gNumGuestsInPark); + result += 2 * std::min(250, (num_happy_peeps * 300) / gNumGuestsInPark); // Up to 25 guests can be lost without affecting the park rating. if (num_lost_guests > 25) @@ -281,13 +281,13 @@ sint32 calculate_park_rating() average_intensity = -average_intensity; } - average_excitement = Math::Min((average_excitement / 2), 50); - average_intensity = Math::Min((average_intensity / 2), 50); + average_excitement = std::min(average_excitement / 2, 50); + average_intensity = std::min(average_intensity / 2, 50); result += 100 - average_excitement - average_intensity; } - total_ride_excitement = Math::Min(1000, total_ride_excitement); - total_ride_intensity = Math::Min(1000, total_ride_intensity); + total_ride_excitement = std::min(1000, total_ride_excitement); + total_ride_intensity = std::min(1000, total_ride_intensity); result -= 200 - ((total_ride_excitement + total_ride_intensity) / 10); } @@ -305,7 +305,7 @@ sint32 calculate_park_rating() if (litter->creationTick - gScenarioTicks >= 7680) num_litter++; } - result -= 600 - (4 * (150 - Math::Min((sint16)150, num_litter))); + result -= 600 - (4 * (150 - std::min(150, num_litter))); } result -= gParkRatingCasualtyPenalty; @@ -407,7 +407,7 @@ static sint32 park_calculate_guest_generation_probability() // If difficult guest generation, extra guests are available for good rides if (gParkFlags & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) { - suggestedMaxGuests = Math::Min(suggestedMaxGuests, 1000); + suggestedMaxGuests = std::min(suggestedMaxGuests, 1000); FOR_ALL_RIDES(i, ride) { if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) continue; @@ -430,12 +430,12 @@ static sint32 park_calculate_guest_generation_probability() } } - suggestedMaxGuests = Math::Min(suggestedMaxGuests, 65535); + suggestedMaxGuests = std::min(suggestedMaxGuests, 65535); gTotalRideValueForMoney = totalRideValueForMoney; _suggestedGuestMaximum = suggestedMaxGuests; // Begin with 50 + park rating - probability = 50 + Math::Clamp(0u, gParkRating - 200u, 650u); + probability = 50 + Math::Clamp(0, gParkRating - 200, 650); // The more guests, the lower the chance of a new one sint32 numGuests = gNumGuestsInPark + gNumGuestsHeadingForPark; @@ -623,7 +623,7 @@ void park_update_histories() // Update guests in park history for (sint32 i = 31; i > 0; i--) gGuestsInParkHistory[i] = gGuestsInParkHistory[i - 1]; - gGuestsInParkHistory[0] = Math::Min(guestsInPark, 5000) / 20; + gGuestsInParkHistory[0] = std::min(guestsInPark, 5000) / 20; window_invalidate_by_class(WC_PARK_INFORMATION); // Update current cash history @@ -1036,3 +1036,40 @@ bool park_entry_price_unlocked() } return false; } + +using namespace OpenRCT2; + +uint16 Park::GetParkRating() const +{ + return gParkRating; +} + +money32 Park::GetParkValue() const +{ + return gParkValue; +} + +money32 Park::GetCompanyValue() const +{ + return gCompanyValue; +} + +void Park::Update() +{ + park_update(); +} + +sint32 Park::CalculateParkRating() const +{ + return calculate_park_rating(); +} + +money32 Park::CalculateParkValue() const +{ + return calculate_park_value(); +} + +money32 Park::CalculateCompanyValue() const +{ + return calculate_company_value(); +} diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index c6a50c2e15..5822c48a0d 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -14,10 +14,10 @@ *****************************************************************************/ #pragma endregion -#ifndef _PARK_H_ -#define _PARK_H_ +#pragma once #include "../common.h" +#include "Map.h" #define DECRYPT_MONEY(money) ((money32)rol32((money) ^ 0xF4EC9621, 13)) #define ENCRYPT_MONEY(money) ((money32)(ror32((money), 13) ^ 0xF4EC9621)) @@ -49,6 +49,24 @@ enum : uint32 PARK_FLAGS_UNLOCK_ALL_PRICES = (1u << 31), // OpenRCT2 only! }; +namespace OpenRCT2 +{ + class Park final + { + public: + uint16 GetParkRating() const; + money32 GetParkValue() const; + money32 GetCompanyValue() const; + + void Update(); + + private: + sint32 CalculateParkRating() const; + money32 CalculateParkValue() const; + money32 CalculateCompanyValue() const; + }; +} + enum { BUY_LAND_RIGHTS_FLAG_BUY_LAND, @@ -117,5 +135,3 @@ money16 park_get_entrance_fee(); bool park_ride_prices_unlocked(); bool park_entry_price_unlocked(); - -#endif From 721dc007784734c550c8e0364c2d3b2e4dfa572c Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 22 Jul 2017 23:19:09 +0000 Subject: [PATCH 02/11] Move park_update into Park class. Co-authored-by: Aaron van Geffen --- src/openrct2/Context.cpp | 7 +++++ src/openrct2/Context.h | 2 ++ src/openrct2/Game.cpp | 4 ++- src/openrct2/world/Park.cpp | 53 ++++++++++++++++++++----------------- src/openrct2/world/Park.h | 4 ++- 5 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index f2d8d53446..63b063acc0 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -105,6 +105,7 @@ namespace OpenRCT2 // Game states std::unique_ptr _titleScreen; + std::unique_ptr _park; sint32 _drawingEngineType = DRAWING_ENGINE_SOFTWARE; std::unique_ptr _drawingEngine; @@ -165,6 +166,11 @@ namespace OpenRCT2 return _uiContext; } + Park * GetPark() override + { + return _park.get(); + } + std::shared_ptr GetPlatformEnvironment() override { return _env; @@ -445,6 +451,7 @@ namespace OpenRCT2 game_init_all(150); _titleScreen = std::make_unique(); + _park = std::make_unique(); return true; } diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h index 15b9a51854..b6e1cb243d 100644 --- a/src/openrct2/Context.h +++ b/src/openrct2/Context.h @@ -71,6 +71,7 @@ enum namespace OpenRCT2 { interface IPlatformEnvironment; + class Park; namespace Audio { @@ -101,6 +102,7 @@ namespace OpenRCT2 virtual std::shared_ptr GetAudioContext() abstract; virtual std::shared_ptr GetUiContext() abstract; + virtual Park * GetPark() abstract; virtual std::shared_ptr GetPlatformEnvironment() abstract; virtual Localisation::LocalisationService& GetLocalisationService() abstract; virtual std::shared_ptr GetObjectManager() abstract; diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index a3aa578523..b0934b7565 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -111,6 +111,8 @@ rct_string_id gGameCommandErrorText; uint8 gErrorType; rct_string_id gErrorStringId; +using namespace OpenRCT2; + sint32 game_command_callback_get_index(GAME_COMMAND_CALLBACK_POINTER * callback) { for (uint32 i = 0; i < Util::CountOf(game_command_callback_table); i++) @@ -489,7 +491,7 @@ void game_logic_update() vehicle_update_all(); sprite_misc_update_all(); ride_update_all(); - park_update(); + GetContext()->GetPark()->Update(); research_update(); ride_ratings_update_all(); ride_measurements_update(); diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 981b03625f..6655780516 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -545,30 +545,6 @@ static void park_generate_new_guests() } } -/** - * - * rct2: 0x006674F7 - */ -void park_update() -{ - if (gScreenFlags & (SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) - return; - - // Every 5 seconds approximately - if (gCurrentTicks % 512 == 0) { - gParkRating = calculate_park_rating(); - gParkValue = calculate_park_value(); - gCompanyValue = calculate_company_value(); - window_invalidate_by_class(WC_FINANCES); - _guestGenerationProbability = park_calculate_guest_generation_probability(); - auto intent = Intent(INTENT_ACTION_UPDATE_PARK_RATING); - context_broadcast_intent(&intent); - } - - // Generate new guests - park_generate_new_guests(); -} - uint8 calculate_guest_initial_happiness(uint8 percentage) { if (percentage < 15) { // There is a minimum of 15% happiness @@ -1039,6 +1015,21 @@ bool park_entry_price_unlocked() using namespace OpenRCT2; +static Park * _singleton = nullptr; + +Park::Park() +{ + _singleton = this; +} + +Park::~Park() +{ + if (_singleton == this) + { + _singleton = nullptr; + } +} + uint16 Park::GetParkRating() const { return gParkRating; @@ -1056,7 +1047,19 @@ money32 Park::GetCompanyValue() const void Park::Update() { - park_update(); + // Every 5 seconds approximately + if (gCurrentTicks % 512 == 0) + { + gParkRating = CalculateParkRating(); + gParkValue = CalculateParkValue(); + gCompanyValue = CalculateCompanyValue(); + _guestGenerationProbability = park_calculate_guest_generation_probability(); + window_invalidate_by_class(WC_FINANCES); + auto intent = Intent(INTENT_ACTION_UPDATE_PARK_RATING); + context_broadcast_intent(&intent); + } + + park_generate_new_guests(); } sint32 Park::CalculateParkRating() const diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index 5822c48a0d..392fa1ce9f 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -54,6 +54,9 @@ namespace OpenRCT2 class Park final { public: + Park(); + ~Park(); + uint16 GetParkRating() const; money32 GetParkValue() const; money32 GetCompanyValue() const; @@ -113,7 +116,6 @@ money32 calculate_company_value(); void reset_park_entry(); rct_peep * park_generate_new_guest(); -void park_update(); void park_update_histories(); void update_park_fences(sint32 x, sint32 y); void update_park_fences_around_tile(sint32 x, sint32 y); From 1ab3863257f1eb501f46571e47809f2e6dd8803d Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 23 Jul 2017 01:48:09 +0100 Subject: [PATCH 03/11] Move more park functions into class --- src/openrct2/world/Park.cpp | 457 ++++++++++++++++++------------------ src/openrct2/world/Park.h | 13 +- 2 files changed, 246 insertions(+), 224 deletions(-) diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 6655780516..1b4731f28d 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -190,171 +190,6 @@ sint32 park_calculate_size() return tiles; } -/** - * - * rct2: 0x00669EAA - */ -sint32 calculate_park_rating() -{ - if (_forcedParkRating >= 0) - return _forcedParkRating; - - sint32 result; - - result = 1150; - if (gParkFlags & PARK_FLAGS_DIFFICULT_PARK_RATING) - result = 1050; - - // Guests - { - rct_peep* peep; - uint16 spriteIndex; - sint32 num_happy_peeps; - sint32 num_lost_guests; - - // -150 to +3 based on a range of guests from 0 to 2000 - result -= 150 - (std::min(2000, gNumGuestsInPark) / 13); - - // Find the number of happy peeps and the number of peeps who can't find the park exit - num_happy_peeps = 0; - num_lost_guests = 0; - FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->outside_of_park != 0) - continue; - if (peep->happiness > 128) - num_happy_peeps++; - if ((peep->peep_flags & PEEP_FLAGS_LEAVING_PARK) && (peep->peep_is_lost_countdown < 90)) - num_lost_guests++; - } - - // Peep happiness -500 to +0 - result -= 500; - - if (gNumGuestsInPark > 0) - result += 2 * std::min(250, (num_happy_peeps * 300) / gNumGuestsInPark); - - // Up to 25 guests can be lost without affecting the park rating. - if (num_lost_guests > 25) - result -= (num_lost_guests - 25) * 7; - } - - // Rides - { - sint32 i; - sint32 total_ride_uptime = 0, total_ride_intensity = 0, total_ride_excitement = 0; - sint32 num_rides, num_exciting_rides = 0; - Ride* ride; - - num_rides = 0; - FOR_ALL_RIDES(i, ride) - { - total_ride_uptime += 100 - ride->downtime; - - if (ride->excitement != RIDE_RATING_UNDEFINED) - { - total_ride_excitement += ride->excitement / 8; - total_ride_intensity += ride->intensity / 8; - num_exciting_rides++; - } - num_rides++; - } - result -= 200; - if (num_rides > 0) - result += (total_ride_uptime / num_rides) * 2; - - result -= 100; - - if (num_exciting_rides > 0) - { - sint32 average_excitement = total_ride_excitement / num_exciting_rides; - sint32 average_intensity = total_ride_intensity / num_exciting_rides; - - average_excitement -= 46; - if (average_excitement < 0) - { - average_excitement = -average_excitement; - } - - average_intensity -= 65; - if (average_intensity < 0) - { - average_intensity = -average_intensity; - } - - average_excitement = std::min(average_excitement / 2, 50); - average_intensity = std::min(average_intensity / 2, 50); - result += 100 - average_excitement - average_intensity; - } - - total_ride_excitement = std::min(1000, total_ride_excitement); - total_ride_intensity = std::min(1000, total_ride_intensity); - result -= 200 - ((total_ride_excitement + total_ride_intensity) / 10); - } - - // Litter - { - rct_litter* litter; - uint16 sprite_idx; - sint16 num_litter; - - num_litter = 0; - for (sprite_idx = gSpriteListHead[SPRITE_LIST_LITTER]; sprite_idx != SPRITE_INDEX_NULL; sprite_idx = litter->next) { - litter = &(get_sprite(sprite_idx)->litter); - - // Ignore recently dropped litter - if (litter->creationTick - gScenarioTicks >= 7680) - num_litter++; - } - result -= 600 - (4 * (150 - std::min(150, num_litter))); - } - - result -= gParkRatingCasualtyPenalty; - result = Math::Clamp(0, result, 999); - return result; -} - -static money32 calculate_ride_value(Ride *ride) -{ - if (ride->type == RIDE_TYPE_NULL) - return 0; - if (ride->value == RIDE_VALUE_UNDEFINED) - return 0; - - // Fair value * (...) - return (ride->value * 10) * (ride_customers_in_last_5_minutes(ride) + rideBonusValue[ride->type] * 4); -} - -/** - * - * rct2: 0x0066A3F6 - */ -money32 calculate_park_value() -{ - - // Sum ride values - money32 result = 0; - for (sint32 i = 0; i < 255; i++) { - Ride* ride = get_ride(i); - result += calculate_ride_value(ride); - } - - // +7.00 per guest - result += gNumGuestsInPark * MONEY(7, 00); - - return result; -} - -/** - * Calculate the company value. - * Cash + Park Value - Loan - * - * rct2: 0x0066A498 - */ -money32 calculate_company_value() -{ - return gCash + gParkValue - gBankLoan; -} - /** * * rct2: 0x00667104 @@ -492,59 +327,6 @@ static uint32 get_random_peep_spawn_index() } } -rct_peep *park_generate_new_guest() -{ - rct_peep *peep = nullptr; - PeepSpawn spawn = gPeepSpawns[get_random_peep_spawn_index()]; - - if (spawn.x != 0xFFFF) { - spawn.direction ^= 2; - peep = peep_generate(spawn.x, spawn.y, spawn.z); - if (peep != nullptr) { - peep->sprite_direction = spawn.direction << 3; - - // Get the centre point of the tile the peep is on - peep->destination_x = (peep->x & 0xFFE0) + 16; - peep->destination_y = (peep->y & 0xFFE0) + 16; - - peep->destination_tolerance = 5; - peep->direction = spawn.direction; - peep->var_37 = 0; - peep->state = PEEP_STATE_ENTERING_PARK; - } - } - - return peep; -} - -static rct_peep *park_generate_new_guest_due_to_campaign(sint32 campaign) -{ - rct_peep *peep = park_generate_new_guest(); - if (peep != nullptr) - marketing_set_guest_campaign(peep, campaign); - return peep; -} - -static void park_generate_new_guests() -{ - // Generate a new guest for some probability - if ((sint32)(scenario_rand() & 0xFFFF) < _guestGenerationProbability) { - sint32 difficultGeneration = (gParkFlags & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) != 0; - if (!difficultGeneration || _suggestedGuestMaximum + 150 >= gNumGuestsInPark) - park_generate_new_guest(); - } - - // Extra guests generated by advertising campaigns - sint32 campaign; - for (campaign = 0; campaign < ADVERTISING_CAMPAIGN_COUNT; campaign++) { - if (gMarketingCampaignDaysLeft[campaign] != 0) { - // Random chance of guest generation - if ((sint32)(scenario_rand() & 0xFFFF) < marketing_get_campaign_guest_generation_probability(campaign)) - park_generate_new_guest_due_to_campaign(campaign); - } - } -} - uint8 calculate_guest_initial_happiness(uint8 percentage) { if (percentage < 15) { // There is a minimum of 15% happiness @@ -1058,21 +840,250 @@ void Park::Update() auto intent = Intent(INTENT_ACTION_UPDATE_PARK_RATING); context_broadcast_intent(&intent); } - - park_generate_new_guests(); + GenerateGuests(); } sint32 Park::CalculateParkRating() const { - return calculate_park_rating(); + if (_forcedParkRating >= 0) + { + return _forcedParkRating; + } + + sint32 result = 1150; + if (gParkFlags & PARK_FLAGS_DIFFICULT_PARK_RATING) + { + result = 1050; + } + + // Guests + { + // -150 to +3 based on a range of guests from 0 to 2000 + result -= 150 - (std::min(2000, gNumGuestsInPark) / 13); + + // Find the number of happy peeps and the number of peeps who can't find the park exit + sint32 happyGuestCount = 0; + sint32 lostGuestCount = 0; + uint16 spriteIndex; + rct_peep * peep; + FOR_ALL_GUESTS(spriteIndex, peep) + { + if (peep->outside_of_park == 0) + { + if (peep->happiness > 128) + { + happyGuestCount++; + } + if ((peep->peep_flags & PEEP_FLAGS_LEAVING_PARK) && + (peep->peep_is_lost_countdown < 90)) + { + lostGuestCount++; + } + } + } + + // Peep happiness -500 to +0 + result -= 500; + if (gNumGuestsInPark > 0) + { + result += 2 * std::min(250, (happyGuestCount * 300) / gNumGuestsInPark); + } + + // Up to 25 guests can be lost without affecting the park rating. + if (lostGuestCount > 25) + { + result -= (lostGuestCount - 25) * 7; + } + } + + // Rides + { + sint32 rideCount = 0; + sint32 excitingRideCount = 0; + sint32 totalRideUptime = 0; + sint32 totalRideIntensity = 0; + sint32 totalRideExcitement = 0; + + sint32 i; + Ride * ride; + FOR_ALL_RIDES(i, ride) + { + totalRideUptime += 100 - ride->downtime; + if (ride->excitement != RIDE_RATING_UNDEFINED) + { + totalRideExcitement += ride->excitement / 8; + totalRideIntensity += ride->intensity / 8; + excitingRideCount++; + } + rideCount++; + } + result -= 200; + if (rideCount > 0) + { + result += (totalRideUptime / rideCount) * 2; + } + result -= 100; + if (excitingRideCount > 0) + { + sint32 averageExcitement = totalRideExcitement / excitingRideCount; + sint32 averageIntensity = totalRideIntensity / excitingRideCount; + + averageExcitement -= 46; + if (averageExcitement < 0) + { + averageExcitement = -averageExcitement; + } + + averageIntensity -= 65; + if (averageIntensity < 0) + { + averageIntensity = -averageIntensity; + } + + averageExcitement = std::min(averageExcitement / 2, 50); + averageIntensity = std::min(averageIntensity / 2, 50); + result += 100 - averageExcitement - averageIntensity; + } + + totalRideExcitement = std::min(1000, totalRideExcitement); + totalRideIntensity = std::min(1000, totalRideIntensity); + result -= 200 - ((totalRideExcitement + totalRideIntensity) / 10); + } + + // Litter + { + rct_litter * litter; + sint32 litterCount = 0; + for (uint16 spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL; spriteIndex = litter->next) + { + litter = &(get_sprite(spriteIndex)->litter); + + // Ignore recently dropped litter + if (litter->creationTick - gScenarioTicks >= 7680) + { + litterCount++; + } + } + result -= 600 - (4 * (150 - std::min(150, litterCount))); + } + + result -= gParkRatingCasualtyPenalty; + result = Math::Clamp(0, result, 999); + return result; } money32 Park::CalculateParkValue() const { - return calculate_park_value(); + money32 result = 0; + + // Sum ride values + for (sint32 i = 0; i < MAX_RIDES; i++) + { + auto ride = get_ride(i); + result += CalculateRideValue(ride); + } + + // +7.00 per guest + result += gNumGuestsInPark * MONEY(7, 00); + + return result; +} + +money32 Park::CalculateRideValue(const Ride * ride) const +{ + money32 result = 0; + if (ride->type != RIDE_TYPE_NULL && + ride->value != RIDE_VALUE_UNDEFINED) + { + // Fair value * (...) + result = (ride->value * 10) * (ride_customers_in_last_5_minutes(ride) + rideBonusValue[ride->type] * 4); + } + return result; } money32 Park::CalculateCompanyValue() const { - return calculate_company_value(); + return finance_get_current_cash() + gParkValue - gBankLoan; +} + +void Park::GenerateGuests() +{ + // Generate a new guest for some probability + if ((sint32)(scenario_rand() & 0xFFFF) < _guestGenerationProbability) + { + bool difficultGeneration = (gParkFlags & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) != 0; + if (!difficultGeneration || _suggestedGuestMaximum + 150 >= gNumGuestsInPark) + { + park_generate_new_guest(); + } + } + + // Extra guests generated by advertising campaigns + for (sint32 campaign = 0; campaign < ADVERTISING_CAMPAIGN_COUNT; campaign++) + { + if (gMarketingCampaignDaysLeft[campaign] != 0) + { + // Random chance of guest generation + if ((sint32)(scenario_rand() & 0xFFFF) < marketing_get_campaign_guest_generation_probability(campaign)) + { + GenerateGuestFromCampaign(campaign); + } + } + } +} + +rct_peep * Park::GenerateGuestFromCampaign(sint32 campaign) +{ + auto peep = GenerateGuest(); + if (peep != nullptr) + { + marketing_set_guest_campaign(peep, campaign); + } + return peep; +} + +rct_peep * Park::GenerateGuest() +{ + rct_peep * peep = nullptr; + PeepSpawn spawn = gPeepSpawns[get_random_peep_spawn_index()]; + + if (spawn.x != PEEP_SPAWN_UNDEFINED) + { + spawn.direction ^= 2; + peep = peep_generate(spawn.x, spawn.y, spawn.z); + if (peep != nullptr) + { + peep->sprite_direction = spawn.direction << 3; + + // Get the centre point of the tile the peep is on + peep->destination_x = (peep->x & 0xFFE0) + 16; + peep->destination_y = (peep->y & 0xFFE0) + 16; + + peep->destination_tolerance = 5; + peep->direction = spawn.direction; + peep->var_37 = 0; + peep->state = PEEP_STATE_ENTERING_PARK; + } + } + return peep; +} + +sint32 calculate_park_rating() +{ + return _singleton->CalculateParkRating(); +} + +money32 calculate_park_value() +{ + return _singleton->CalculateParkValue(); +} + +money32 calculate_company_value() +{ + return _singleton->CalculateCompanyValue(); +} + +rct_peep * park_generate_new_guest() +{ + return _singleton->GenerateGuest(); } diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index 392fa1ce9f..e4a03ec85f 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -17,6 +17,7 @@ #pragma once #include "../common.h" +#include "../ride/Ride.h" #include "Map.h" #define DECRYPT_MONEY(money) ((money32)rol32((money) ^ 0xF4EC9621, 13)) @@ -49,6 +50,9 @@ enum : uint32 PARK_FLAGS_UNLOCK_ALL_PRICES = (1u << 31), // OpenRCT2 only! }; +struct rct_peep; +struct rct_ride; + namespace OpenRCT2 { class Park final @@ -63,10 +67,17 @@ namespace OpenRCT2 void Update(); - private: sint32 CalculateParkRating() const; money32 CalculateParkValue() const; money32 CalculateCompanyValue() const; + + rct_peep * GenerateGuest(); + + private: + money32 CalculateRideValue(const Ride * ride) const; + + void GenerateGuests(); + rct_peep * GenerateGuestFromCampaign(sint32 campaign); }; } From b705e0ce7a50b874b41a9b498266953a9ff485da Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 23 Jul 2017 12:43:52 +0100 Subject: [PATCH 04/11] Move update histories to park class --- src/openrct2/world/Park.cpp | 109 +++++++++++++++++------------------- src/openrct2/world/Park.h | 2 + 2 files changed, 52 insertions(+), 59 deletions(-) diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 1b4731f28d..08f4733bc5 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -351,65 +351,6 @@ uint8 calculate_guest_initial_happiness(uint8 percentage) { return 40; // This is the lowest possible value } -/** - * - * rct2: 0x0066A231 - */ -void park_update_histories() -{ - sint32 guestsInPark = gNumGuestsInPark; - sint32 lastGuestsInPark = gNumGuestsInParkLastWeek; - gNumGuestsInParkLastWeek = guestsInPark; - auto intent = Intent(INTENT_ACTION_UPDATE_GUEST_COUNT); - context_broadcast_intent(&intent); - - sint32 changeInGuestsInPark = guestsInPark - lastGuestsInPark; - sint32 guestChangeModifier = 1; - if (changeInGuestsInPark > -20) { - guestChangeModifier++; - if (changeInGuestsInPark < 20) - guestChangeModifier = 0; - } - gGuestChangeModifier = guestChangeModifier; - - // Update park rating history - for (sint32 i = 31; i > 0; i--) - gParkRatingHistory[i] = gParkRatingHistory[i - 1]; - gParkRatingHistory[0] = calculate_park_rating() / 4; - window_invalidate_by_class(WC_PARK_INFORMATION); - - // Update guests in park history - for (sint32 i = 31; i > 0; i--) - gGuestsInParkHistory[i] = gGuestsInParkHistory[i - 1]; - gGuestsInParkHistory[0] = std::min(guestsInPark, 5000) / 20; - window_invalidate_by_class(WC_PARK_INFORMATION); - - // Update current cash history - for (sint32 i = 127; i > 0; i--) - gCashHistory[i] = gCashHistory[i - 1]; - gCashHistory[0] = gCash - gBankLoan; - window_invalidate_by_class(WC_FINANCES); - - // Update weekly profit history - money32 currentWeeklyProfit = gWeeklyProfitAverageDividend; - if (gWeeklyProfitAverageDivisor != 0) { - currentWeeklyProfit /= gWeeklyProfitAverageDivisor; - } - - for (sint32 i = 127; i > 0; i--) - gWeeklyProfitHistory[i] = gWeeklyProfitHistory[i - 1]; - gWeeklyProfitHistory[0] = currentWeeklyProfit; - - gWeeklyProfitAverageDividend = 0; - gWeeklyProfitAverageDivisor = 0; - window_invalidate_by_class(WC_FINANCES); - - // Update park value history - for (sint32 i = 127; i > 0; i--) - gParkValueHistory[i] = gParkValueHistory[i - 1]; - gParkValueHistory[0] = gParkValue; -} - void park_set_open(sint32 open) { game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, open << 8, GAME_COMMAND_SET_PARK_OPEN, 0, 0); @@ -1068,6 +1009,56 @@ rct_peep * Park::GenerateGuest() return peep; } +template +static void HistoryPushRecord(T history[TSize], T newItem) +{ + for (size_t i = TSize - 1; i > 0; i--) + { + history[i] = history[i - 1]; + } + history[0] = newItem; +} + +void Park::UpdateHistories() +{ + uint8 guestChangeModifier = 1; + sint32 changeInGuestsInPark = (sint32)gNumGuestsInPark - (sint32)gNumGuestsInParkLastWeek; + if (changeInGuestsInPark > -20) + { + guestChangeModifier++; + if (changeInGuestsInPark < 20) + { + guestChangeModifier = 0; + } + } + gGuestChangeModifier = guestChangeModifier; + gNumGuestsInParkLastWeek = gNumGuestsInPark; + + // Update park rating, guests in park and current cash history + HistoryPushRecord(gParkRatingHistory, calculate_park_rating() / 4); + HistoryPushRecord(gGuestsInParkHistory, std::min(gNumGuestsInPark, 5000) / 20); + HistoryPushRecord(gCashHistory, finance_get_current_cash() - gBankLoan); + + // Update weekly profit history + money32 currentWeeklyProfit = gWeeklyProfitAverageDividend; + if (gWeeklyProfitAverageDivisor != 0) + { + currentWeeklyProfit /= gWeeklyProfitAverageDivisor; + } + HistoryPushRecord(gWeeklyProfitHistory, currentWeeklyProfit); + gWeeklyProfitAverageDividend = 0; + gWeeklyProfitAverageDivisor = 0; + + // Update park value history + HistoryPushRecord(gParkValueHistory, gParkValue); + + // Invalidate relevant windows + auto intent = Intent(INTENT_ACTION_UPDATE_GUEST_COUNT); + context_broadcast_intent(&intent); + window_invalidate_by_class(WC_PARK_INFORMATION); + window_invalidate_by_class(WC_FINANCES); +} + sint32 calculate_park_rating() { return _singleton->CalculateParkRating(); diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index e4a03ec85f..e17416e17b 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -73,6 +73,8 @@ namespace OpenRCT2 rct_peep * GenerateGuest(); + void UpdateHistories(); + private: money32 CalculateRideValue(const Ride * ride) const; From 8929e5533ba7dcc7149b66db44d4ca5d9c1f5782 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 23 Jul 2017 13:11:13 +0100 Subject: [PATCH 05/11] Move more calculation and logic to park class --- src/openrct2/world/Park.cpp | 377 +++++++++++++++++++----------------- src/openrct2/world/Park.h | 12 +- 2 files changed, 212 insertions(+), 177 deletions(-) diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 08f4733bc5..be35784588 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -151,45 +151,6 @@ void park_init() format_string(gS6Info.details, 256, STR_NO_DETAILS_YET, nullptr); } -/** - * - * rct2: 0x0066729F - */ -void park_reset_history() -{ - for (sint32 i = 0; i < 32; i++) { - gParkRatingHistory[i] = 255; - gGuestsInParkHistory[i] = 255; - } -} - -/** - * - * rct2: 0x0066A348 - */ -sint32 park_calculate_size() -{ - sint32 tiles; - tile_element_iterator it; - - tiles = 0; - tile_element_iterator_begin(&it); - do { - if (it.element->GetType() == TILE_ELEMENT_TYPE_SURFACE) { - if (it.element->properties.surface.ownership & (OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED | OWNERSHIP_OWNED)) { - tiles++; - } - } - } while (tile_element_iterator_next(&it)); - - if (tiles != gParkSize) { - gParkSize = tiles; - window_invalidate_by_class(WC_PARK_INFORMATION); - } - - return tiles; -} - /** * * rct2: 0x00667104 @@ -203,115 +164,6 @@ void reset_park_entry() } } -/** - * Calculates the probability of a new guest. Also sets total ride value and suggested guest maximum. - * Total ride value should probably be set elsewhere, as it's not just used for guest generation. - * Suggested guest maximum should probably be an output result, not a global. - * @returns A probability out of 65535 - * rct2: 0x0066730A - */ -static sint32 park_calculate_guest_generation_probability() -{ - uint32 probability; - sint32 i, suggestedMaxGuests; - money16 totalRideValueForMoney; - Ride *ride; - - // Calculate suggested guest maximum (based on ride type) and total ride value - suggestedMaxGuests = 0; - totalRideValueForMoney = 0; - FOR_ALL_RIDES(i, ride) { - if (ride->status != RIDE_STATUS_OPEN) - continue; - if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) - continue; - if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) - continue; - - // Add guest score for ride type - suggestedMaxGuests += rideBonusValue[ride->type]; - - // Add ride value - if (ride->value != RIDE_VALUE_UNDEFINED) { - money16 rideValueForMoney = (money16)(ride->value - ride->price); - if (rideValueForMoney > 0) { - totalRideValueForMoney += rideValueForMoney * 2; - } - } - } - - // If difficult guest generation, extra guests are available for good rides - if (gParkFlags & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) { - suggestedMaxGuests = std::min(suggestedMaxGuests, 1000); - FOR_ALL_RIDES(i, ride) { - if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) - continue; - if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) - continue; - - if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) - continue; - if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_DATA_LOGGING)) - continue; - if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) - continue; - if (ride->length[0] < (600 << 16)) - continue; - if (ride->excitement < RIDE_RATING(6,00)) - continue; - - // Bonus guests for good ride - suggestedMaxGuests += rideBonusValue[ride->type] * 2; - } - } - - suggestedMaxGuests = std::min(suggestedMaxGuests, 65535); - gTotalRideValueForMoney = totalRideValueForMoney; - _suggestedGuestMaximum = suggestedMaxGuests; - - // Begin with 50 + park rating - probability = 50 + Math::Clamp(0, gParkRating - 200, 650); - - // The more guests, the lower the chance of a new one - sint32 numGuests = gNumGuestsInPark + gNumGuestsHeadingForPark; - if (numGuests > suggestedMaxGuests) { - probability /= 4; - - // Even lower for difficult guest generation - if (gParkFlags & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) - probability /= 4; - } - - // Reduces chance for any more than 7000 guests - if (numGuests > 7000) - probability /= 4; - - // Penalty for overpriced entrance fee relative to total ride value - money16 entranceFee = park_get_entrance_fee(); - if (entranceFee > totalRideValueForMoney) { - probability /= 4; - - // Extra penalty for very overpriced entrance fee - if (entranceFee / 2 > totalRideValueForMoney) - probability /= 4; - } - - // Reward or penalties for park awards - for (i = 0; i < MAX_AWARDS; i++) { - Award *award = &gCurrentAwards[i]; - if (award->Time == 0) - continue; - - // +/- 0.25% of the probability - if (award_is_positive(award->Type)) - probability += probability / 4; - else - probability -= probability / 4; - } - - return probability; -} - /** * Choose a random peep spawn and iterates through until defined spawn is found. */ @@ -327,30 +179,6 @@ static uint32 get_random_peep_spawn_index() } } -uint8 calculate_guest_initial_happiness(uint8 percentage) { - if (percentage < 15) { - // There is a minimum of 15% happiness - percentage = 15; - } - else if (percentage > 98) { - // There is a maximum of 98% happiness - percentage = 98; - } - - /* The percentages follow this sequence: - 15 17 18 20 21 23 25 26 28 29 31 32 34 36 37 39 40 42 43 45 47 48 50 51 53... - - This sequence can be defined as PI*(9+n)/2 (the value is floored) - */ - uint8 n; - for (n = 1; n < 55; n++) { - if ((3.14159*(9 + n)) / 2 >= percentage) { - return (9 + n) * 4; - } - } - return 40; // This is the lowest possible value -} - void park_set_open(sint32 open) { game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, open << 8, GAME_COMMAND_SET_PARK_OPEN, 0, 0); @@ -683,7 +511,6 @@ void game_command_buy_land_rights( } } - void set_forced_park_rating(sint32 rating) { _forcedParkRating = rating; @@ -776,7 +603,10 @@ void Park::Update() gParkRating = CalculateParkRating(); gParkValue = CalculateParkValue(); gCompanyValue = CalculateCompanyValue(); - _guestGenerationProbability = park_calculate_guest_generation_probability(); + gTotalRideValueForMoney = CalculateTotalRideValue(); + _suggestedGuestMaximum = CalculateSuggestedMaxGuests(); + _guestGenerationProbability = CalculateGuestGenerationProbability(); + window_invalidate_by_class(WC_FINANCES); auto intent = Intent(INTENT_ACTION_UPDATE_PARK_RATING); context_broadcast_intent(&intent); @@ -784,6 +614,31 @@ void Park::Update() GenerateGuests(); } +sint32 Park::CalculateParkSize() const +{ + sint32 tiles; + tile_element_iterator it; + + tiles = 0; + tile_element_iterator_begin(&it); + do { + if (it.element->GetType() == TILE_ELEMENT_TYPE_SURFACE) + { + if (it.element->properties.surface.ownership & (OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED | OWNERSHIP_OWNED)) + { + tiles++; + } + } + } while (tile_element_iterator_next(&it)); + + if (tiles != gParkSize) { + gParkSize = tiles; + window_invalidate_by_class(WC_PARK_INFORMATION); + } + + return tiles; +} + sint32 Park::CalculateParkRating() const { if (_forcedParkRating >= 0) @@ -947,6 +802,145 @@ money32 Park::CalculateCompanyValue() const return finance_get_current_cash() + gParkValue - gBankLoan; } +money16 Park::CalculateTotalRideValue() const +{ + money16 totalRideValue = 0; + sint32 i; + Ride * ride; + FOR_ALL_RIDES(i, ride) + { + if (ride->status != RIDE_STATUS_OPEN) continue; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) continue; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) continue; + + // Add ride value + if (ride->value != RIDE_VALUE_UNDEFINED) + { + money16 rideValue = (money16)(ride->value - ride->price); + if (rideValue > 0) + { + totalRideValue += rideValue * 2; + } + } + } + return totalRideValue; +} + +uint32 Park::CalculateSuggestedMaxGuests() const +{ + uint32 suggestedMaxGuests = 0; + + // TODO combine the two ride loops + sint32 i; + Ride * ride; + FOR_ALL_RIDES(i, ride) + { + if (ride->status != RIDE_STATUS_OPEN) continue; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) continue; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) continue; + + // Add guest score for ride type + suggestedMaxGuests += rideBonusValue[ride->type]; + } + + // If difficult guest generation, extra guests are available for good rides + if (gParkFlags & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) + { + suggestedMaxGuests = std::min(suggestedMaxGuests, 1000); + FOR_ALL_RIDES(i, ride) + { + if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) continue; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) continue; + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) continue; + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) continue; + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_DATA_LOGGING)) continue; + if (ride->length[0] < (600 << 16)) continue; + if (ride->excitement < RIDE_RATING(6, 00)) continue; + + // Bonus guests for good ride + suggestedMaxGuests += rideBonusValue[ride->type] * 2; + } + } + + suggestedMaxGuests = std::min(suggestedMaxGuests, 65535); + return suggestedMaxGuests; +} + +uint32 Park::CalculateGuestGenerationProbability() const +{ + // Begin with 50 + park rating + uint32 probability = 50 + Math::Clamp(0, gParkRating - 200, 650); + + // The more guests, the lower the chance of a new one + sint32 numGuests = gNumGuestsInPark + gNumGuestsHeadingForPark; + if (numGuests > _suggestedGuestMaximum) + { + probability /= 4; + // Even lower for difficult guest generation + if (gParkFlags & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) + { + probability /= 4; + } + } + + // Reduces chance for any more than 7000 guests + if (numGuests > 7000) + { + probability /= 4; + } + + // Penalty for overpriced entrance fee relative to total ride value + money16 entranceFee = park_get_entrance_fee(); + if (entranceFee > gTotalRideValueForMoney) + { + probability /= 4; + // Extra penalty for very overpriced entrance fee + if (entranceFee / 2 > gTotalRideValueForMoney) + { + probability /= 4; + } + } + + // Reward or penalties for park awards + for (size_t i = 0; i < MAX_AWARDS; i++) + { + const auto award = &gCurrentAwards[i]; + if (award->Time != 0) + { + // +/- 0.25% of the probability + if (award_is_positive(award->Type)) + { + probability += probability / 4; + } + else + { + probability -= probability / 4; + } + } + } + + return probability; +} + +uint8 Park::CalculateGuestInitialHappiness(uint8 percentage) +{ + percentage = Math::Clamp(15, percentage, 98); + + // The percentages follow this sequence: + // 15 17 18 20 21 23 25 26 28 29 31 32 34 36 37 39 40 42 43 45 47 48 50 51 53... + // This sequence can be defined as PI*(9+n)/2 (the value is floored) + for (uint8 n = 1; n < 55; n++) + { + if ((3.14159 * (9 + n)) / 2 >= percentage) + { + return (9 + n) * 4; + } + } + + // This is the lowest possible value: + return 40; +} + void Park::GenerateGuests() { // Generate a new guest for some probability @@ -1019,6 +1013,15 @@ static void HistoryPushRecord(T history[TSize], T newItem) history[0] = newItem; } +void Park::ResetHistories() +{ + for (size_t i = 0; i < 32; i++) + { + gParkRatingHistory[i] = 255; + gGuestsInParkHistory[i] = 255; + } +} + void Park::UpdateHistories() { uint8 guestChangeModifier = 1; @@ -1059,6 +1062,17 @@ void Park::UpdateHistories() window_invalidate_by_class(WC_FINANCES); } +sint32 park_calculate_size() +{ + auto tiles = _singleton->CalculateParkSize(); + if (tiles != gParkSize) + { + gParkSize = tiles; + window_invalidate_by_class(WC_PARK_INFORMATION); + } + return tiles; +} + sint32 calculate_park_rating() { return _singleton->CalculateParkRating(); @@ -1078,3 +1092,18 @@ rct_peep * park_generate_new_guest() { return _singleton->GenerateGuest(); } + +void park_update_histories() +{ + _singleton->UpdateHistories(); +} + +void park_reset_history() +{ + _singleton->ResetHistories(); +} + +uint8 calculate_guest_initial_happiness(uint8 percentage) +{ + return Park::CalculateGuestInitialHappiness(percentage); +} diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index e17416e17b..c432044b2a 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -67,12 +67,18 @@ namespace OpenRCT2 void Update(); - sint32 CalculateParkRating() const; - money32 CalculateParkValue() const; - money32 CalculateCompanyValue() const; + sint32 CalculateParkSize() const; + sint32 CalculateParkRating() const; + money32 CalculateParkValue() const; + money32 CalculateCompanyValue() const; + money16 CalculateTotalRideValue() const; + uint32 CalculateSuggestedMaxGuests() const; + uint32 CalculateGuestGenerationProbability() const; + static uint8 CalculateGuestInitialHappiness(uint8 percentage); rct_peep * GenerateGuest(); + void ResetHistories(); void UpdateHistories(); private: From 5a7e34a26711832f38549ff87abddee2e3fe064f Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 23 Jul 2017 13:17:44 +0100 Subject: [PATCH 06/11] Move park initialisation to park class --- src/openrct2/world/Park.cpp | 154 +++++++++++++++++++----------------- src/openrct2/world/Park.h | 3 + 2 files changed, 83 insertions(+), 74 deletions(-) diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index be35784588..0b7bfc1a4d 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -15,6 +15,7 @@ #pragma endregion #include "../Cheats.h" +#include "../Context.h" #include "../config/Config.h" #include "../core/Math.hpp" #include "../core/Memory.hpp" @@ -36,13 +37,12 @@ #include "../ride/RideData.h" #include "../ride/ShopItem.h" #include "../scenario/Scenario.h" +#include "../windows/Intent.h" #include "Entrance.h" #include "Map.h" #include "Park.h" #include "Sprite.h" #include "Surface.h" -#include "../windows/Intent.h" -#include "../Context.h" rct_string_id gParkName; uint32 gParkNameArgs; @@ -79,78 +79,6 @@ sint32 _suggestedGuestMaximum; */ sint32 _guestGenerationProbability; -sint32 park_is_open() -{ - return (gParkFlags & PARK_FLAGS_PARK_OPEN) != 0; -} - -/** - * - * rct2: 0x00667132 - */ -void park_init() -{ - sint32 i; - - gUnk13CA740 = 0; - gParkName = STR_UNNAMED_PARK; - gStaffHandymanColour = COLOUR_BRIGHT_RED; - gStaffMechanicColour = COLOUR_LIGHT_BLUE; - gStaffSecurityColour = COLOUR_YELLOW; - gNumGuestsInPark = 0; - gNumGuestsInParkLastWeek = 0; - gNumGuestsHeadingForPark = 0; - gGuestChangeModifier = 0; - gParkRating = 0; - _guestGenerationProbability = 0; - gTotalRideValueForMoney = 0; - gResearchLastItem.rawValue = RESEARCHED_ITEMS_SEPARATOR; - - for (i = 0; i < 20; i++) - gMarketingCampaignDaysLeft[i] = 0; - - research_reset_items(); - finance_init(); - - set_every_ride_type_not_invented(); - - set_all_scenery_items_invented(); - - gParkEntranceFee = MONEY(10, 00); - - for (auto &peepSpawn : gPeepSpawns) - { - peepSpawn.x = PEEP_SPAWN_UNDEFINED; - } - - gResearchPriorities = - (1 << RESEARCH_CATEGORY_TRANSPORT) | - (1 << RESEARCH_CATEGORY_GENTLE) | - (1 << RESEARCH_CATEGORY_ROLLERCOASTER) | - (1 << RESEARCH_CATEGORY_THRILL) | - (1 << RESEARCH_CATEGORY_WATER) | - (1 << RESEARCH_CATEGORY_SHOP) | - (1 << RESEARCH_CATEGORY_SCENERY_GROUP); - gResearchFundingLevel = RESEARCH_FUNDING_NORMAL; - - gGuestInitialCash = MONEY(50,00); // Cash per guest (average) - gGuestInitialHappiness = calculate_guest_initial_happiness(50); // 50% - gGuestInitialHunger = 200; - gGuestInitialThirst = 200; - gScenarioObjectiveType = OBJECTIVE_GUESTS_BY; - gScenarioObjectiveYear = 4; - gScenarioObjectiveNumGuests = 1000; - gLandPrice = MONEY(90, 00); - gConstructionRightsPrice = MONEY(40,00); - gParkFlags = PARK_FLAGS_NO_MONEY | PARK_FLAGS_SHOW_REAL_GUEST_NAMES; - park_reset_history(); - finance_reset_history(); - award_reset(); - - gS6Info.name[0] = '\0'; - format_string(gS6Info.details, 256, STR_NO_DETAILS_YET, nullptr); -} - /** * * rct2: 0x00667104 @@ -580,6 +508,11 @@ Park::~Park() } } +bool Park::IsOpen() const +{ + return (gParkFlags & PARK_FLAGS_PARK_OPEN) != 0; +} + uint16 Park::GetParkRating() const { return gParkRating; @@ -595,6 +528,69 @@ money32 Park::GetCompanyValue() const return gCompanyValue; } +void Park::Initialise() +{ + gUnk13CA740 = 0; + gParkName = STR_UNNAMED_PARK; + gStaffHandymanColour = COLOUR_BRIGHT_RED; + gStaffMechanicColour = COLOUR_LIGHT_BLUE; + gStaffSecurityColour = COLOUR_YELLOW; + gNumGuestsInPark = 0; + gNumGuestsInParkLastWeek = 0; + gNumGuestsHeadingForPark = 0; + gGuestChangeModifier = 0; + gParkRating = 0; + _guestGenerationProbability = 0; + gTotalRideValueForMoney = 0; + gResearchLastItem.rawValue = RESEARCHED_ITEMS_SEPARATOR; + + for (size_t i = 0; i < 20; i++) + { + gMarketingCampaignDaysLeft[i] = 0; + } + + research_reset_items(); + finance_init(); + + set_every_ride_type_not_invented(); + + set_all_scenery_items_invented(); + + gParkEntranceFee = MONEY(10, 00); + + for (auto &peepSpawn : gPeepSpawns) + { + peepSpawn.x = PEEP_SPAWN_UNDEFINED; + } + + gResearchPriorities = + (1 << RESEARCH_CATEGORY_TRANSPORT) | + (1 << RESEARCH_CATEGORY_GENTLE) | + (1 << RESEARCH_CATEGORY_ROLLERCOASTER) | + (1 << RESEARCH_CATEGORY_THRILL) | + (1 << RESEARCH_CATEGORY_WATER) | + (1 << RESEARCH_CATEGORY_SHOP) | + (1 << RESEARCH_CATEGORY_SCENERY_GROUP); + gResearchFundingLevel = RESEARCH_FUNDING_NORMAL; + + gGuestInitialCash = MONEY(50,00); + gGuestInitialHappiness = CalculateGuestInitialHappiness(50); + gGuestInitialHunger = 200; + gGuestInitialThirst = 200; + gScenarioObjectiveType = OBJECTIVE_GUESTS_BY; + gScenarioObjectiveYear = 4; + gScenarioObjectiveNumGuests = 1000; + gLandPrice = MONEY(90,00); + gConstructionRightsPrice = MONEY(40,00); + gParkFlags = PARK_FLAGS_NO_MONEY | PARK_FLAGS_SHOW_REAL_GUEST_NAMES; + ResetHistories(); + finance_reset_history(); + award_reset(); + + gS6Info.name[0] = '\0'; + format_string(gS6Info.details, 256, STR_NO_DETAILS_YET, nullptr); +} + void Park::Update() { // Every 5 seconds approximately @@ -1062,6 +1058,16 @@ void Park::UpdateHistories() window_invalidate_by_class(WC_FINANCES); } +sint32 park_is_open() +{ + return _singleton->IsOpen(); +} + +void park_init() +{ + _singleton->Initialise(); +} + sint32 park_calculate_size() { auto tiles = _singleton->CalculateParkSize(); diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index c432044b2a..3d2cee926a 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -61,10 +61,13 @@ namespace OpenRCT2 Park(); ~Park(); + bool IsOpen() const; + uint16 GetParkRating() const; money32 GetParkValue() const; money32 GetCompanyValue() const; + void Initialise(); void Update(); sint32 CalculateParkSize() const; From 1db2a4986f5d8d7bd8a45cbbeba8428ddc85c6b0 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 23 Jul 2017 13:24:15 +0100 Subject: [PATCH 07/11] Rename gTotalRideValue to gTotalRideValueForMoney --- src/openrct2/scenario/Scenario.cpp | 4 ++-- src/openrct2/world/Park.cpp | 5 ++--- src/openrct2/world/Park.h | 9 +++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 542178f3e4..3194095415 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -250,8 +250,8 @@ void scenario_success_submit_name(const char *name) static void scenario_entrance_fee_too_high_check() { uint16 x = 0, y = 0; - money16 totalRideValue = gTotalRideValueForMoney; - money16 max_fee = totalRideValue + (totalRideValue / 2); + money16 totalRideValueForMoney = gTotalRideValueForMoney; + money16 max_fee = totalRideValueForMoney + (totalRideValueForMoney / 2); if ((gParkFlags & PARK_FLAGS_PARK_OPEN) && park_get_entrance_fee() > max_fee) { for (sint32 i = 0; i < MAX_PARK_ENTRANCES && gParkEntrances[i].x != LOCATION_NULL; i++) { diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 0b7bfc1a4d..cdeba36019 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -599,7 +599,7 @@ void Park::Update() gParkRating = CalculateParkRating(); gParkValue = CalculateParkValue(); gCompanyValue = CalculateCompanyValue(); - gTotalRideValueForMoney = CalculateTotalRideValue(); + gTotalRideValueForMoney = CalculateTotalRideValueForMoney(); _suggestedGuestMaximum = CalculateSuggestedMaxGuests(); _guestGenerationProbability = CalculateGuestGenerationProbability(); @@ -787,7 +787,6 @@ money32 Park::CalculateRideValue(const Ride * ride) const if (ride->type != RIDE_TYPE_NULL && ride->value != RIDE_VALUE_UNDEFINED) { - // Fair value * (...) result = (ride->value * 10) * (ride_customers_in_last_5_minutes(ride) + rideBonusValue[ride->type] * 4); } return result; @@ -798,7 +797,7 @@ money32 Park::CalculateCompanyValue() const return finance_get_current_cash() + gParkValue - gBankLoan; } -money16 Park::CalculateTotalRideValue() const +money16 Park::CalculateTotalRideValueForMoney() const { money16 totalRideValue = 0; sint32 i; diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index 3d2cee926a..d91151ed7b 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -74,9 +74,6 @@ namespace OpenRCT2 sint32 CalculateParkRating() const; money32 CalculateParkValue() const; money32 CalculateCompanyValue() const; - money16 CalculateTotalRideValue() const; - uint32 CalculateSuggestedMaxGuests() const; - uint32 CalculateGuestGenerationProbability() const; static uint8 CalculateGuestInitialHappiness(uint8 percentage); rct_peep * GenerateGuest(); @@ -85,10 +82,14 @@ namespace OpenRCT2 void UpdateHistories(); private: - money32 CalculateRideValue(const Ride * ride) const; + money32 CalculateRideValue(const Ride * ride) const; + money16 CalculateTotalRideValueForMoney() const; + uint32 CalculateSuggestedMaxGuests() const; + uint32 CalculateGuestGenerationProbability() const; void GenerateGuests(); rct_peep * GenerateGuestFromCampaign(sint32 campaign); + }; } From 665f34326b69feaaf3d52245bc22c89bc49ad9b0 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 23 Jul 2017 14:44:39 +0100 Subject: [PATCH 08/11] Move week update for park to park class --- src/openrct2/scenario/Scenario.cpp | 2 -- src/openrct2/world/Park.cpp | 14 +++++++++----- src/openrct2/world/Park.h | 1 - 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 3194095415..d1e4510d04 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -345,8 +345,6 @@ static void scenario_week_update() break; } } - park_update_histories(); - park_calculate_size(); } static void scenario_fortnight_update() diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index cdeba36019..763f97d806 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -607,6 +607,15 @@ void Park::Update() auto intent = Intent(INTENT_ACTION_UPDATE_PARK_RATING); context_broadcast_intent(&intent); } + + // Every week + if (date_is_week_start(gDateMonthTicks)) + { + UpdateHistories(); + gParkSize = CalculateParkSize(); + window_invalidate_by_class(WC_PARK_INFORMATION); + } + GenerateGuests(); } @@ -1098,11 +1107,6 @@ rct_peep * park_generate_new_guest() return _singleton->GenerateGuest(); } -void park_update_histories() -{ - _singleton->UpdateHistories(); -} - void park_reset_history() { _singleton->ResetHistories(); diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index d91151ed7b..0a553fff5a 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -139,7 +139,6 @@ money32 calculate_company_value(); void reset_park_entry(); rct_peep * park_generate_new_guest(); -void park_update_histories(); void update_park_fences(sint32 x, sint32 y); void update_park_fences_around_tile(sint32 x, sint32 y); From 8b3cad5ca023c0a7ca10ed30c285a0a50b1508b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Sat, 26 Aug 2017 22:47:38 +0200 Subject: [PATCH 09/11] Ensure park_init is only called on constructed parks --- src/openrct2/world/Park.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 763f97d806..15862a7e57 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -1073,6 +1073,10 @@ sint32 park_is_open() void park_init() { + if (_singleton == nullptr) + { + return; + } _singleton->Initialise(); } From c211ac5a7b69d9074ccac243e8f9373921128554 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sat, 19 May 2018 19:51:29 +0200 Subject: [PATCH 10/11] Replace singleton Park with relevant Context call. --- src/openrct2/world/Park.cpp | 34 ++++++++++------------------------ src/openrct2/world/Park.h | 3 --- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 15862a7e57..38fbf35d5b 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -493,21 +493,6 @@ bool park_entry_price_unlocked() using namespace OpenRCT2; -static Park * _singleton = nullptr; - -Park::Park() -{ - _singleton = this; -} - -Park::~Park() -{ - if (_singleton == this) - { - _singleton = nullptr; - } -} - bool Park::IsOpen() const { return (gParkFlags & PARK_FLAGS_PARK_OPEN) != 0; @@ -1068,21 +1053,22 @@ void Park::UpdateHistories() sint32 park_is_open() { - return _singleton->IsOpen(); + return GetContext()->GetPark()->IsOpen(); } void park_init() { - if (_singleton == nullptr) + auto park = GetContext()->GetPark(); + if (park == nullptr) { return; } - _singleton->Initialise(); + park->Initialise(); } sint32 park_calculate_size() { - auto tiles = _singleton->CalculateParkSize(); + auto tiles = GetContext()->GetPark()->CalculateParkSize(); if (tiles != gParkSize) { gParkSize = tiles; @@ -1093,27 +1079,27 @@ sint32 park_calculate_size() sint32 calculate_park_rating() { - return _singleton->CalculateParkRating(); + return GetContext()->GetPark()->CalculateParkRating(); } money32 calculate_park_value() { - return _singleton->CalculateParkValue(); + return GetContext()->GetPark()->CalculateParkValue(); } money32 calculate_company_value() { - return _singleton->CalculateCompanyValue(); + return GetContext()->GetPark()->CalculateCompanyValue(); } rct_peep * park_generate_new_guest() { - return _singleton->GenerateGuest(); + return GetContext()->GetPark()->GenerateGuest(); } void park_reset_history() { - _singleton->ResetHistories(); + GetContext()->GetPark()->ResetHistories(); } uint8 calculate_guest_initial_happiness(uint8 percentage) diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index 0a553fff5a..7b9e709d26 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -58,9 +58,6 @@ namespace OpenRCT2 class Park final { public: - Park(); - ~Park(); - bool IsOpen() const; uint16 GetParkRating() const; From bfa5bf6ecce203cfa4c7bbdb6ef82a10a8de6f4c Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sat, 19 May 2018 20:14:52 +0200 Subject: [PATCH 11/11] Refactor procedural park methods into Park calls. --- src/openrct2/Cheats.cpp | 5 ++- src/openrct2/actions/RideDemolishAction.hpp | 4 ++- src/openrct2/rct1/S4Importer.cpp | 5 ++- src/openrct2/scenario/Scenario.cpp | 11 ++++--- src/openrct2/world/Park.cpp | 36 ++++----------------- src/openrct2/world/Park.h | 5 --- 6 files changed, 24 insertions(+), 42 deletions(-) diff --git a/src/openrct2/Cheats.cpp b/src/openrct2/Cheats.cpp index 446714dbb7..3ed28301f0 100644 --- a/src/openrct2/Cheats.cpp +++ b/src/openrct2/Cheats.cpp @@ -30,6 +30,8 @@ #include "world/Sprite.h" #include "world/Surface.h" +using namespace OpenRCT2; + bool gCheatsSandboxMode = false; bool gCheatsDisableClearanceChecks = false; bool gCheatsDisableSupportLimits = false; @@ -267,8 +269,9 @@ static void cheat_clear_loan() static void cheat_generate_guests(sint32 count) { + auto park = GetContext()->GetPark(); for (sint32 i = 0; i < count; i++) - park_generate_new_guest(); + park->GenerateGuest(); window_invalidate_by_class(WC_BOTTOM_TOOLBAR); } diff --git a/src/openrct2/actions/RideDemolishAction.hpp b/src/openrct2/actions/RideDemolishAction.hpp index f591d51f10..a43e0bd8e4 100644 --- a/src/openrct2/actions/RideDemolishAction.hpp +++ b/src/openrct2/actions/RideDemolishAction.hpp @@ -31,6 +31,8 @@ #include "GameAction.h" #include "MazeSetTrackAction.hpp" +using namespace OpenRCT2; + struct RideDemolishAction : public GameActionBase { private: @@ -190,7 +192,7 @@ public: user_string_free(ride->name); ride->type = RIDE_TYPE_NULL; - gParkValue = calculate_park_value(); + gParkValue = GetContext()->GetPark()->CalculateCompanyValue(); auto res = std::make_unique(); res->ExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index ad626dacf7..b3a723f8fb 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -66,6 +66,8 @@ #include "../world/SmallScenery.h" #include "../world/Surface.h" +using namespace OpenRCT2; + static uint8 GetPathType(rct_tile_element * tileElement); static sint32 GetWallType(rct_tile_element * tileElement, sint32 edge); static uint8 GetWallColour(rct_tile_element * tileElement); @@ -316,7 +318,8 @@ public: { // Use the ratio between the old and new park value to calcute the ratio to // use for the park value history and the goal. - _parkValueConversionFactor = (calculate_park_value() * 10) / _s4.park_value; + auto park = GetContext()->GetPark(); + _parkValueConversionFactor = (park->CalculateParkValue() * 10) / _s4.park_value; } else { diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index d1e4510d04..1e5e56fced 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -90,6 +90,8 @@ char gScenarioFileName[MAX_PATH]; static sint32 scenario_create_ducks(); static void scenario_objective_check(); +using namespace OpenRCT2; + void scenario_begin() { game_load_init(); @@ -108,9 +110,10 @@ void scenario_begin() if (gScenarioObjectiveType != OBJECTIVE_NONE && !gLoadKeepWindowsOpen) context_open_window_view(WV_PARK_OBJECTIVE); - gParkRating = calculate_park_rating(); - gParkValue = calculate_park_value(); - gCompanyValue = calculate_company_value(); + auto park = GetContext()->GetPark(); + gParkRating = park->CalculateParkRating(); + gParkValue = park->CalculateParkValue(); + gCompanyValue = park->CalculateCompanyValue(); gHistoricalProfit = gInitialCash - gBankLoan; gCash = gInitialCash; @@ -169,7 +172,7 @@ void scenario_begin() gTotalAdmissions = 0; gTotalIncomeFromAdmissions = 0; safe_strcpy(gScenarioCompletedBy, "?", sizeof(gScenarioCompletedBy)); - park_reset_history(); + park->ResetHistories(); finance_reset_history(); award_reset(); reset_all_ride_build_dates(); diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 38fbf35d5b..8ad736ef7e 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -44,6 +44,8 @@ #include "Sprite.h" #include "Surface.h" +using namespace OpenRCT2; + rct_string_id gParkName; uint32 gParkNameArgs; uint32 gParkFlags; @@ -442,7 +444,8 @@ void game_command_buy_land_rights( void set_forced_park_rating(sint32 rating) { _forcedParkRating = rating; - gParkRating = calculate_park_rating(); + auto park = GetContext()->GetPark(); + gParkRating = park->CalculateParkRating(); auto intent = Intent(INTENT_ACTION_UPDATE_PARK_RATING); context_broadcast_intent(&intent); } @@ -491,8 +494,6 @@ bool park_entry_price_unlocked() return false; } -using namespace OpenRCT2; - bool Park::IsOpen() const { return (gParkFlags & PARK_FLAGS_PARK_OPEN) != 0; @@ -938,7 +939,7 @@ void Park::GenerateGuests() bool difficultGeneration = (gParkFlags & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) != 0; if (!difficultGeneration || _suggestedGuestMaximum + 150 >= gNumGuestsInPark) { - park_generate_new_guest(); + GenerateGuest(); } } @@ -1027,7 +1028,7 @@ void Park::UpdateHistories() gNumGuestsInParkLastWeek = gNumGuestsInPark; // Update park rating, guests in park and current cash history - HistoryPushRecord(gParkRatingHistory, calculate_park_rating() / 4); + HistoryPushRecord(gParkRatingHistory, CalculateParkRating() / 4); HistoryPushRecord(gGuestsInParkHistory, std::min(gNumGuestsInPark, 5000) / 20); HistoryPushRecord(gCashHistory, finance_get_current_cash() - gBankLoan); @@ -1077,31 +1078,6 @@ sint32 park_calculate_size() return tiles; } -sint32 calculate_park_rating() -{ - return GetContext()->GetPark()->CalculateParkRating(); -} - -money32 calculate_park_value() -{ - return GetContext()->GetPark()->CalculateParkValue(); -} - -money32 calculate_company_value() -{ - return GetContext()->GetPark()->CalculateCompanyValue(); -} - -rct_peep * park_generate_new_guest() -{ - return GetContext()->GetPark()->GenerateGuest(); -} - -void park_reset_history() -{ - GetContext()->GetPark()->ResetHistories(); -} - uint8 calculate_guest_initial_happiness(uint8 percentage) { return Park::CalculateGuestInitialHappiness(percentage); diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index 7b9e709d26..31a1462cd1 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -127,14 +127,9 @@ sint32 get_forced_park_rating(); sint32 park_is_open(); void park_init(); -void park_reset_history(); sint32 park_calculate_size(); -sint32 calculate_park_rating(); -money32 calculate_park_value(); -money32 calculate_company_value(); void reset_park_entry(); -rct_peep * park_generate_new_guest(); void update_park_fences(sint32 x, sint32 y); void update_park_fences_around_tile(sint32 x, sint32 y);