From 6d7b4b1808812659eb2d3378271bc07c3da95333 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Sun, 25 May 2014 13:59:31 +0100 Subject: [PATCH] add park update and guest generation --- src/addresses.h | 8 ++- src/game.c | 2 +- src/map.h | 9 +++ src/park.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++-- src/park.h | 12 ++++ src/peep.c | 14 ++++ src/peep.h | 19 ++++-- src/scenario.c | 23 +++++-- src/scenario.h | 1 + 9 files changed, 245 insertions(+), 14 deletions(-) diff --git a/src/addresses.h b/src/addresses.h index c271a43a7a..a13f7d286b 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -160,6 +160,8 @@ #define RCT2_ADDRESS_CURRENT_MONTH_YEAR 0x00F663A8 #define RCT2_ADDRESS_CURRENT_MONTH_TICKS 0x00F663AA +#define RCT2_ADDRESS_SCENARIO_SRAND_0 0x00F663B0 +#define RCT2_ADDRESS_SCENARIO_SRAND_1 0x00F663B4 #define RCT2_ADDRESS_MAP_ELEMENTS 0x00F663B8 #define RCT2_ADDRESS_SPRITE_LIST 0x010E63BC @@ -178,6 +180,7 @@ #define RCT2_ADDRESS_CURRENT_PARK_RATING 0x01357CB0 #define RCT2_ADDRESS_PARK_RATING_HISTORY 0x01357CB2 #define RCT2_ADDRESS_GUESTS_IN_PARK_HISTORY 0x01357CD2 +#define RCT2_ADDRESS_GUEST_GENERATION_PROBABILITY 0x013580EC #define RCT2_ADDRESS_OBJECTIVE_TYPE 0x013580F8 #define RCT2_ADDRESS_OBJECTIVE_YEAR 0x013580F9 #define RCT2_ADDRESS_OBJECTIVE_CURRENCY 0x013580FC @@ -194,8 +197,11 @@ #define RCT2_ADDRESS_AWARD_LIST 0x01358760 #define RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED 0x013587F8 #define RCT2_ADDRESS_CURRENT_INTEREST_RATE 0x0135934A -#define RCT2_ADDRESS_EXPENDITURE_TABLE 0x01357848 + +#define RCT2_ADDRESS_PEEP_SPAWNS 0x013573F2 + #define RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL 0x013573FF +#define RCT2_ADDRESS_EXPENDITURE_TABLE 0x01357848 #define RCT2_ADDRESS_HANDYMAN_COLOUR 0x01357BCD #define RCT2_ADDRESS_MECHANIC_COLOUR 0x01357BCE diff --git a/src/game.c b/src/game.c index 60db383966..2c0475910d 100644 --- a/src/game.c +++ b/src/game.c @@ -152,7 +152,7 @@ void game_logic_update() RCT2_CALLPROC_EBPSAFE(0x006D4204); // update vehicles RCT2_CALLPROC_EBPSAFE(0x00672AA4); // update text effects RCT2_CALLPROC_EBPSAFE(0x006ABE4C); // update rides - RCT2_CALLPROC_EBPSAFE(0x006674F7); // update park + park_update(); RCT2_CALLPROC_EBPSAFE(0x00684C7A); RCT2_CALLPROC_EBPSAFE(0x006B5A2A); RCT2_CALLPROC_EBPSAFE(0x006B6456); // update ride measurements diff --git a/src/map.h b/src/map.h index 108e339a82..355767bc81 100644 --- a/src/map.h +++ b/src/map.h @@ -182,6 +182,15 @@ enum { #define TILE_UNDEFINED_MAP_ELEMENT (rct_map_element*)-1 + +typedef struct { + uint16 x; + uint16 y; + uint8 z; + uint8 direction; +} rct2_peep_spawn; + + void map_init(); void map_update_tile_pointers(); int map_element_height(int x, int y); diff --git a/src/park.c b/src/park.c index 5031d7640b..f4a591e718 100644 --- a/src/park.c +++ b/src/park.c @@ -30,6 +30,8 @@ #include "string_ids.h" #include "window.h" +const int advertisingCampaignGuestGenerationProbabilities[] = { 400, 300, 200, 200, 250, 200 }; + int park_is_open() { return (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN) != 0; @@ -53,7 +55,7 @@ void park_init() RCT2_GLOBAL(0x01357846, uint16) = 0; RCT2_GLOBAL(0x013573FE, uint16) = 0; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, uint16) = 0; - RCT2_GLOBAL(0x013580EC, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_GENERATION_PROBABILITY, uint16) = 0; RCT2_GLOBAL(0x013580EE, uint16) = 0; RCT2_GLOBAL(0x01357CF4, sint32) = -1; @@ -332,9 +334,9 @@ money32 calculate_company_value() } /** -* -* rct2: 0x00667104 -*/ + * + * rct2: 0x00667104 + */ void reset_park_entrances() { RCT2_GLOBAL(0x013573D4, uint16) = 0; @@ -346,3 +348,164 @@ void reset_park_entrances() RCT2_GLOBAL(0x013573F2, uint16) = 0xFFFF; RCT2_GLOBAL(0x013573F8, uint16) = 0xFFFF; } + +/** + * + * rct2: 0x0066730A + */ +static int park_calculate_guest_generation_probability() +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + RCT2_CALLFUNC_X(0x0066730A, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return eax & 0xFFFF; +} + +static void get_random_peep_spawn(rct2_peep_spawn *spawn) +{ + rct2_peep_spawn *peepSpawns = RCT2_ADDRESS(RCT2_ADDRESS_PEEP_SPAWNS, rct2_peep_spawn); + + *spawn = peepSpawns[0]; + if (peepSpawns[1].x != 0xFFFF) + if (scenario_rand() & 0x80000) + *spawn = peepSpawns[1]; +} + +static int park_should_generate_new_guest() +{ + if ((scenario_rand() & 0xFFFF) < RCT2_GLOBAL(0x013580EC, uint16)) { + int difficultGeneration = (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) != 0; + if (!difficultGeneration || RCT2_GLOBAL(0x0135883C, uint16) + 150 < RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)) + return 1; + } + + return 0; +} + +static rct_peep *park_generate_new_guest() +{ + rct_peep *peep; + rct2_peep_spawn spawn; + get_random_peep_spawn(&spawn); + + if (spawn.x != 0xFFFF) { + spawn.z *= 16; + spawn.direction ^= 2; + peep = peep_generate(spawn.x, spawn.y, spawn.z); + if (peep != NULL) { + peep->var_1E = spawn.direction << 3; + + // Get the centre point of the tile the peep is on + peep->var_32 = (peep->x & 0xFFE0) + 16; + peep->var_34 = (peep->y & 0xFFE0) + 16; + + peep->var_36 = 5; + peep->var_76 = 0; + peep->var_78 = spawn.direction; + peep->var_37 = 0; + peep->state = PEEP_STATE_ENTERING_PARK; + } + } + + return peep; +} + +static rct_peep *park_generate_new_guest_due_to_campaign(int campaign) +{ + rct_peep *peep = park_generate_new_guest(); + if (peep != NULL) { + switch (campaign) { + case ADVERTISING_CAMPAIGN_PARK_ENTRY_FREE: + peep->item_standard_flags |= PEEP_ITEM_VOUCHER; + peep->var_F0 = 0; + break; + case ADVERTISING_CAMPAIGN_RIDE_FREE: + peep->item_standard_flags |= PEEP_ITEM_VOUCHER; + peep->var_F0 = 1; + peep->var_F1 = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + peep->var_C5 = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + peep->var_C6 = 240; + break; + case ADVERTISING_CAMPAIGN_PARK_ENTRY_HALF_PRICE: + peep->item_standard_flags |= PEEP_ITEM_VOUCHER; + peep->var_F0 = 2; + break; + case ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE: + peep->item_standard_flags |= PEEP_ITEM_VOUCHER; + peep->var_F0 = 3; + peep->var_F1 = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + break; + case ADVERTISING_CAMPAIGN_PARK: + break; + case ADVERTISING_CAMPAIGN_RIDE: + peep->var_C5 = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + peep->var_C6 = 240; + break; + } + } +} + +static int park_get_campaign_guest_generation_probability(int campaign) +{ + int probability = advertisingCampaignGuestGenerationProbabilities[campaign]; + rct_ride *ride; + + // Lower probability of guest generation if price was already low + switch (campaign) { + case ADVERTISING_CAMPAIGN_PARK_ENTRY_FREE: + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) < 4) + probability /= 8; + break; + case ADVERTISING_CAMPAIGN_PARK_ENTRY_HALF_PRICE: + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) < 6) + probability /= 8; + break; + case ADVERTISING_CAMPAIGN_RIDE_FREE: + ride = &(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[RCT2_ADDRESS(0x01358116, uint8)[campaign]]); + if (ride->price < 3) + probability /= 8; + break; + } + + return probability; +} + +static void park_generate_new_guests() +{ + // Check and generate a new guest + if (park_should_generate_new_guest()) + park_generate_new_guest(); + + // Extra guests generated by advertising campaigns + int campaign; + for (campaign = 0; campaign < ADVERTISING_CAMPAIGN_COUNT; campaign++) { + if (RCT2_ADDRESS(0x01358102, uint8)[campaign] != 0) { + // Random chance of guest generation + if ((scenario_rand() & 0xFFFF) < park_get_campaign_guest_generation_probability(campaign)) + park_generate_new_guest_due_to_campaign(campaign); + } + } +} + +/** + * + * rct2: 0x006674F7 + */ +void park_update() +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 0x0E) + return; + + // Every 5 seconds approximately + if (RCT2_GLOBAL(0x013628F4, uint8) % 512 == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, uint16) = calculate_park_rating(); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, money32) = calculate_park_value(); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_COMPANY_VALUE, money32) = calculate_company_value(); + window_invalidate_by_id(WC_FINANCES, 0); + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_GENERATION_PROBABILITY, uint16) = park_calculate_guest_generation_probability(); + RCT2_GLOBAL(0x009A9804, uint16) |= 0x10; + window_invalidate_by_id(WC_PARK_INFORMATION, 0); + } + + // Generate new guests + park_generate_new_guests(); +} \ No newline at end of file diff --git a/src/park.h b/src/park.h index b9663c56fb..3d4d778caa 100644 --- a/src/park.h +++ b/src/park.h @@ -51,6 +51,16 @@ enum { PARK_AWARD_BEST_GENTLE_RIDES, }; +enum { + ADVERTISING_CAMPAIGN_PARK_ENTRY_FREE, + ADVERTISING_CAMPAIGN_RIDE_FREE, + ADVERTISING_CAMPAIGN_PARK_ENTRY_HALF_PRICE, + ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE, + ADVERTISING_CAMPAIGN_PARK, + ADVERTISING_CAMPAIGN_RIDE, + ADVERTISING_CAMPAIGN_COUNT +}; + enum { PARK_FLAGS_PARK_OPEN = (1 << 0), PARK_FLAGS_FORBID_LANDSCAPE_CHANGES = (1 << 2), @@ -78,4 +88,6 @@ money32 calculate_park_value(); money32 calculate_company_value(); void reset_park_entrances(); +void park_update(); + #endif diff --git a/src/peep.c b/src/peep.c index 7b6a32d37b..a557ba9d66 100644 --- a/src/peep.c +++ b/src/peep.c @@ -288,4 +288,18 @@ void peep_update_crowd_noise() } } } +} + +/** + * + * rct2: 0x0069A05D + */ +rct_peep *peep_generate(int x, int y, int z) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ecx = y; + edx = z; + RCT2_CALLFUNC_X(0x0069A05D, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return (rct_peep*)esi; } \ No newline at end of file diff --git a/src/peep.h b/src/peep.h index f0a34bf82f..15c4c766d4 100644 --- a/src/peep.h +++ b/src/peep.h @@ -329,7 +329,8 @@ typedef struct { sint16 var_18; sint16 var_1A; sint16 var_1C; - uint32 pad_1E; + uint8 var_1E; + uint8 pad_1F[3]; uint16 name_string_idx; // 0x22 uint16 next_x; // 0x24 uint16 next_y; // 0x26 @@ -342,7 +343,10 @@ typedef struct { uint8 staff_type; // 0x2F uint8 tshirt_colour; // 0x30 uint8 trousers_colour; // 0x31 - uint8 pad_32[0x06]; + uint16 var_32; + uint16 var_34; + uint8 var_36; + uint8 var_37; uint8 energy; // 0x38 uint8 energy_growth_rate; // 0x39 uint8 happiness; // 0x3A @@ -368,7 +372,10 @@ typedef struct { uint8 current_train; // 0x6A uint8 current_car; // 0x6B uint8 current_seat; // 0x6C - uint8 pad_6D[0x0F]; + uint8 pad_6D[0x09]; + uint8 var_76; + uint8 var_78; + uint8 pad_79[0x03]; uint8 rides_been_on[32]; // 0x7C uint32 id; // 0x9C money32 cash_in_pocket; // 0xA0 @@ -391,7 +398,10 @@ typedef struct { uint8 no_of_food; // 0xEC uint8 no_of_drinks; // 0xED uint8 no_of_souvenirs; // 0xEE - uint8 pad_EF[0x04]; + uint8 pad_EF; + uint8 var_F0; + uint8 var_F1; + uint8 pad_F2; uint8 var_F3; uint8 pad_F4[0x02]; uint8 balloon_colour; // 0xF6 @@ -406,5 +416,6 @@ int peep_get_staff_count(); void peep_update_all(); void peep_problem_warnings_update(); void peep_update_crowd_noise(); +rct_peep *peep_generate(int x, int y, int z); #endif diff --git a/src/scenario.c b/src/scenario.c index f4e09f23cd..b35584e0f8 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -175,8 +175,11 @@ void scenario_load_and_play(const rct_scenario_basic *scenario) rct_window *mainWindow; rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - RCT2_GLOBAL(0x009AA0F0, uint32) = RCT2_GLOBAL(0x00F663B0, uint32) ^ timeGetTime(); - RCT2_GLOBAL(0x009AA0F4, uint32) = RCT2_GLOBAL(0x00F663B4, uint32) ^ timeGetTime(); + // Create the scenario pseduo-random seeds using the current time + uint32 srand0, srand1; + srand0 = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32) ^ timeGetTime(); + srand1 = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, uint32) ^ timeGetTime(); + RCT2_CALLPROC_EBPSAFE(0x006CBCC3); subsitute_path( @@ -214,8 +217,10 @@ void scenario_load_and_play(const rct_scenario_basic *scenario) RCT2_CALLPROC_EBPSAFE(0x0069E9A7); window_new_ride_init_vars(); - RCT2_GLOBAL(0x00F663B0, sint32) = RCT2_GLOBAL(0x009AA0F0, sint32); - RCT2_GLOBAL(0x00F663B4, sint32) = RCT2_GLOBAL(0x009AA0F4, sint32); + // Set the scenario pseduo-random seeds + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, sint32) = srand0; + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, sint32) = srand1; + RCT2_GLOBAL(0x009DEB7C, sint16) = 0; RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, sint32) &= 0xFFFFF7FF; if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, sint32) & 0x20000) @@ -678,3 +683,13 @@ void scenario_update() } +/** +* +* rct2: 0x006E37D2 +*/ +int scenario_rand() +{ + int eax = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32); + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32) += ror32(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, uint32) ^ 0x1234567F, 7); + return RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, uint32) = ror32(eax, 3); +} diff --git a/src/scenario.h b/src/scenario.h index 350d506f13..cb3822c147 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -128,5 +128,6 @@ int scenario_load_basic(const char *path); void scenario_load(const char *path); void scenario_load_and_play(const rct_scenario_basic *scenario); void scenario_update(); +int scenario_rand(); #endif