/* * Update status of marketing campaigns and send produce a news item when they have finished. * rct2: 0x0069E0C1 **/ void marketing_update() { for (int campaign = 0; campaign < ADVERTISING_CAMPAIGN_COUNT; campaign++) { uint8 campaign_weeks_left = RCT2_ADDRESS(0x01358102, uint8)[campaign]; if (campaign_weeks_left == 0) continue; window_invalidate_by_id(WC_FINANCES, 0); // High bit marks the campaign as inactive, on first check the campaign is set actice // this makes campaigns run a full x weeks even when started in the middle of a week RCT2_ADDRESS(0x01358102, uint8)[campaign] &= ~(1 << 7); if (campaign_weeks_left & (1 << 7)) continue; RCT2_ADDRESS(0x01358102, uint8)[campaign]--; if (campaign_weeks_left - 1 != 0) continue; int campaign_item = RCT2_ADDRESS(0x01358116, uint8)[campaign]; // This sets the string parameters for the marketing types that have an argument. if (campaign == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign == ADVERTISING_CAMPAIGN_RIDE) { RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x01362942 + 304 * campaign_item, uint16); RCT2_GLOBAL(0x013CE954, uint32) = RCT2_GLOBAL(0x01362944 + 152 * campaign_item, uint32); } else if (campaign == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) { campaign_item += 2016; if (campaign_item >= 2048) campaign_item += 96; RCT2_GLOBAL(0x013CE952, uint16) = campaign_item; } news_item_add_to_queue(NEWS_ITEM_MONEY, STR_MARKETING_FINISHED_BASE + campaign, 0); } }
/** * Update status of marketing campaigns and send produce a news item when they have finished. * rct2: 0x0069E0C1 */ void marketing_update() { for (sint32 campaign = 0; campaign < ADVERTISING_CAMPAIGN_COUNT; campaign++) { if (gCheatsNeverendingMarketing) continue; sint32 active = (gMarketingCampaignDaysLeft[campaign] & CAMPAIGN_ACTIVE_FLAG) != 0; if (gMarketingCampaignDaysLeft[campaign] == 0) continue; window_invalidate_by_class(WC_FINANCES); // High bit marks the campaign as inactive, on first check the campaign is set active // this makes campaigns run a full x weeks even when started in the middle of a week gMarketingCampaignDaysLeft[campaign] &= ~CAMPAIGN_ACTIVE_FLAG; if (active) continue; if (--gMarketingCampaignDaysLeft[campaign] != 0) continue; sint32 campaignItem = gMarketingCampaignRideIndex[campaign]; // This sets the string parameters for the marketing types that have an argument. if (campaign == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign == ADVERTISING_CAMPAIGN_RIDE) { Ride * ride = get_ride(campaignItem); set_format_arg(0, rct_string_id, ride->name); set_format_arg(2, uint32, ride->name_arguments); } else if (campaign == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) { set_format_arg(0, rct_string_id, ShopItemStringIds[campaignItem].plural); } if (gConfigNotifications.park_marketing_campaign_finished) { news_item_add_to_queue(NEWS_ITEM_MONEY, MarketingCampaignNames[campaign][2], 0); } } }
/** * Update status of marketing campaigns and send produce a news item when they have finished. * rct2: 0x0069E0C1 */ void marketing_update() { for (int campaign = 0; campaign < ADVERTISING_CAMPAIGN_COUNT; campaign++) { if (gCheatsNeverendingMarketing) continue; int active = (gMarketingCampaignDaysLeft[campaign] & CAMPAIGN_ACTIVE_FLAG) != 0; if (gMarketingCampaignDaysLeft[campaign] == 0) continue; window_invalidate_by_class(WC_FINANCES); // High bit marks the campaign as inactive, on first check the campaign is set active // this makes campaigns run a full x weeks even when started in the middle of a week gMarketingCampaignDaysLeft[campaign] &= ~CAMPAIGN_ACTIVE_FLAG; if (active) continue; if (--gMarketingCampaignDaysLeft[campaign] != 0) continue; int campaignItem = gMarketingCampaignRideIndex[campaign]; // This sets the string parameters for the marketing types that have an argument. if (campaign == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign == ADVERTISING_CAMPAIGN_RIDE) { rct_ride* ride = get_ride(campaignItem); RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = ride->name; RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, uint32) = ride->name_arguments; } else if (campaign == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) { RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = ShopItemStringIds[campaignItem].plural; } if (gConfigNotifications.park_marketing_campaign_finished) { news_item_add_to_queue(NEWS_ITEM_MONEY, STR_MARKETING_FINISHED_BASE + campaign, 0); } } }
/** * * rct2: 0x0069BF41 **/ void peep_problem_warnings_update() { rct_peep* peep; rct_ride* ride; uint16 spriteIndex; uint16 guests_in_park = RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16); int hunger_counter = 0, lost_counter = 0, noexit_counter = 0, thirst_counter = 0, litter_counter = 0, disgust_counter = 0, bathroom_counter = 0 ,vandalism_counter = 0; static int warning_throttle[7] = { 0, 0, 0, 0, 0, 0, 0 }; RCT2_GLOBAL(RCT2_ADDRESS_RIDE_COUNT, sint16) = ride_get_count(); // refactor this to somewhere else FOR_ALL_GUESTS(spriteIndex, peep) { if (peep->var_2A != 0 || peep->thoughts[0].var_2 > 5) continue; switch (peep->thoughts[0].type) { case PEEP_THOUGHT_TYPE_LOST: //0x10 lost_counter++; break; case PEEP_THOUGHT_TYPE_HUNGRY: // 0x14 if (peep->var_C5 == -1){ hunger_counter++; break; } ride = &g_ride_list[peep->var_C5]; if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x80000)) hunger_counter++; break; case PEEP_THOUGHT_TYPE_THIRSTY: if (peep->var_C5 == -1){ thirst_counter++; break; } ride = &g_ride_list[peep->var_C5]; if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x1000000)) thirst_counter++; break; case PEEP_THOUGHT_TYPE_BATHROOM: if (peep->var_C5 == -1){ bathroom_counter++; break; } ride = &g_ride_list[peep->var_C5]; if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x2000000)) bathroom_counter++; break; case PEEP_THOUGHT_TYPE_BAD_LITTER: // 0x1a litter_counter++; break; case PEEP_THOUGHT_TYPE_CANT_FIND_EXIT: // 0x1b noexit_counter++; break; case PEEP_THOUGHT_TYPE_PATH_DISGUSTING: // 0x1f disgust_counter++; break; case PEEP_THOUGHT_TYPE_VANDALISM: //0x21 vandalism_counter++; break; default: break; } } // could maybe be packed into a loop, would lose a lot of clarity though if (warning_throttle[0]) --warning_throttle[0]; else if ( hunger_counter >= PEEP_HUNGER_WARNING_THRESHOLD && hunger_counter >= guests_in_park / 16) { warning_throttle[0] = 4; news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_ARE_HUNGRY, 20); } if (warning_throttle[1]) --warning_throttle[1]; else if (thirst_counter >= PEEP_THIRST_WARNING_THRESHOLD && thirst_counter >= guests_in_park / 16) { warning_throttle[1] = 4; news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_ARE_THIRSTY, 21); } if (warning_throttle[2]) --warning_throttle[2]; else if (bathroom_counter >= PEEP_BATHROOM_WARNING_THRESHOLD && bathroom_counter >= guests_in_park / 16) { warning_throttle[2] = 4; news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_CANT_FIND_BATHROOM, 22); } if (warning_throttle[3]) --warning_throttle[3]; else if (litter_counter >= PEEP_LITTER_WARNING_THRESHOLD && litter_counter >= guests_in_park / 32) { warning_throttle[3] = 4; news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_DISLIKE_LITTER, 26); } if (warning_throttle[4]) --warning_throttle[4]; else if (disgust_counter >= PEEP_DISGUST_WARNING_THRESHOLD && disgust_counter >= guests_in_park / 32) { warning_throttle[4] = 4; news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_DISGUSTED_BY_PATHS, 31); } if (warning_throttle[5]) --warning_throttle[5]; else if (vandalism_counter >= PEEP_VANDALISM_WARNING_THRESHOLD && vandalism_counter >= guests_in_park / 32) { warning_throttle[5] = 4; news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_DISLIKE_VANDALISM, 33); } if (warning_throttle[6]) --warning_throttle[6]; else if (noexit_counter >= PEEP_NOEXIT_WARNING_THRESHOLD) { warning_throttle[6] = 4; news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_GETTING_LOST_OR_STUCK, 27); } else if (lost_counter >= PEEP_LOST_WARNING_THRESHOLD) { warning_throttle[6] = 4; news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_GETTING_LOST_OR_STUCK, 16); } }
/** * * rct2: 0x006848D4 */ void research_finish_item(rct_research_item* researchItem) { gResearchLastItem = *researchItem; research_invalidate_related_windows(); if (researchItem->type == RESEARCH_ENTRY_TYPE_RIDE) { // Ride uint32_t base_ride_type = researchItem->baseRideType; int32_t rideEntryIndex = researchItem->entryIndex; rct_ride_entry* rideEntry = get_ride_entry(rideEntryIndex); if (rideEntry != nullptr && base_ride_type != RIDE_TYPE_NULL) { bool ride_group_was_invented_before = false; bool ride_type_was_invented_before = ride_type_is_invented(base_ride_type); rct_string_id availabilityString; // Determine if the ride group this entry belongs to was invented before. if (RideGroupManager::RideTypeHasRideGroups(base_ride_type)) { const RideGroup* rideGroup = RideGroupManager::GetRideGroup(base_ride_type, rideEntry); if (rideGroup->IsInvented()) { ride_group_was_invented_before = true; } } ride_type_set_invented(base_ride_type); openrct2_assert( base_ride_type < std::size(RideTypePossibleTrackConfigurations), "Invalid base_ride_type = %d", base_ride_type); ride_entry_set_invented(rideEntryIndex); bool seenRideEntry[MAX_RIDE_OBJECTS]{}; rct_research_item* researchItem2 = gResearchItems; for (; researchItem2->rawValue != RESEARCHED_ITEMS_END; researchItem2++) { if (researchItem2->rawValue != RESEARCHED_ITEMS_SEPARATOR && researchItem2->type == RESEARCH_ENTRY_TYPE_RIDE) { uint8_t index = researchItem2->entryIndex; seenRideEntry[index] = true; } } // RCT2 made non-separated vehicles available at once, by removing all but one from research. // To ensure old files keep working, look for ride entries not in research, and make them available as well. for (int32_t i = 0; i < MAX_RIDE_OBJECTS; i++) { if (!seenRideEntry[i]) { rct_ride_entry* rideEntry2 = get_ride_entry(i); if (rideEntry2 != nullptr) { for (uint8_t j = 0; j < MAX_RIDE_TYPES_PER_RIDE_ENTRY; j++) { if (rideEntry2->ride_type[j] == base_ride_type) { ride_entry_set_invented(i); break; } } } } } // If a vehicle should be listed separately (maze, mini golf, flat rides, shops) if (RideGroupManager::RideTypeIsIndependent(base_ride_type)) { availabilityString = STR_NEWS_ITEM_RESEARCH_NEW_RIDE_AVAILABLE; set_format_arg(0, rct_string_id, rideEntry->naming.name); } // If a vehicle is the first to be invented for its ride group, show the ride group name. else if ( !ride_type_was_invented_before || (RideGroupManager::RideTypeHasRideGroups(base_ride_type) && !ride_group_was_invented_before)) { rct_ride_name naming = get_ride_naming(base_ride_type, rideEntry); availabilityString = STR_NEWS_ITEM_RESEARCH_NEW_RIDE_AVAILABLE; set_format_arg(0, rct_string_id, naming.name); } // If the vehicle should not be listed separately and it isn't the first to be invented for its ride group, // report it as a new vehicle for the existing ride group. else { availabilityString = STR_NEWS_ITEM_RESEARCH_NEW_VEHICLE_AVAILABLE; rct_ride_name baseRideNaming = get_ride_naming(base_ride_type, rideEntry); set_format_arg(0, rct_string_id, baseRideNaming.name); set_format_arg(2, rct_string_id, rideEntry->naming.name); } if (!gSilentResearch) { if (gConfigNotifications.ride_researched) { news_item_add_to_queue(NEWS_ITEM_RESEARCH, availabilityString, researchItem->rawValue); } } research_invalidate_related_windows(); } } else { // Scenery rct_scenery_group_entry* sceneryGroupEntry = get_scenery_group_entry(researchItem->entryIndex); if (sceneryGroupEntry != nullptr) { scenery_group_set_invented(researchItem->entryIndex); set_format_arg(0, rct_string_id, sceneryGroupEntry->name); if (!gSilentResearch) { if (gConfigNotifications.ride_researched) { news_item_add_to_queue( NEWS_ITEM_RESEARCH, STR_NEWS_ITEM_RESEARCH_NEW_SCENERY_SET_AVAILABLE, researchItem->rawValue); } } research_invalidate_related_windows(); init_scenery(); } } }