/***************************************************************************** * Copyright (c) 2014-2020 OpenRCT2 developers * * For a complete list of all authors, please refer to contributors.md * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ #pragma once #include "../common.h" #include "../core/FileSystem.hpp" #include "../object/Object.h" #include "../rct12/RCT12.h" #include "../ride/RideRatings.h" #include "../ride/VehicleColour.h" #include "../world/EntityList.h" #include #include constexpr const uint8_t RCT2_MAX_STAFF = 200; constexpr const uint8_t RCT2_MAX_BANNERS_IN_PARK = 250; constexpr const uint8_t RCT2_MAX_VEHICLES_PER_RIDE = 31; constexpr const uint8_t RCT2_MAX_CARS_PER_TRAIN = 32; constexpr const uint8_t RCT2_MAX_CATEGORIES_PER_RIDE = 2; constexpr const uint8_t RCT2_MAX_RIDE_TYPES_PER_RIDE_ENTRY = 3; constexpr const uint8_t RCT2_MAX_VEHICLES_PER_RIDE_ENTRY = 4; constexpr const uint8_t RCT2_DOWNTIME_HISTORY_SIZE = 8; constexpr const uint8_t RCT2_CUSTOMER_HISTORY_SIZE = 10; constexpr const uint16_t RCT2_MAX_SPRITES = 10000; constexpr const uint32_t RCT2_MAX_TILE_ELEMENTS = 0x30000; constexpr const uint16_t RCT2_MAX_ANIMATED_OBJECTS = 2000; constexpr const uint8_t RCT2_MAX_RESEARCHED_RIDE_TYPE_QUADS = 8; // With 32 bits per uint32_t, this means there is room for 256 // types. constexpr const uint8_t RCT2_MAX_RESEARCHED_RIDE_ENTRY_QUADS = 8; // With 32 bits per uint32_t, this means there is room for 256 // entries. constexpr const uint8_t RCT2_MAX_RESEARCHED_SCENERY_ITEM_QUADS = 56; constexpr const uint16_t RCT2_MAX_RESEARCHED_SCENERY_ITEMS = (RCT2_MAX_RESEARCHED_SCENERY_ITEM_QUADS * 32); // There are 32 bits // per quad. constexpr const uint16_t RCT2_MAX_RESEARCH_ITEMS = 500; constexpr uint16_t TD6MaxTrackElements = 8192; constexpr const uint8_t RCT2_MAX_SMALL_SCENERY_OBJECTS = 252; constexpr const uint8_t RCT2_MAX_LARGE_SCENERY_OBJECTS = 128; constexpr const uint8_t RCT2_MAX_WALL_SCENERY_OBJECTS = 128; constexpr const uint8_t RCT2_MAX_BANNER_OBJECTS = 32; constexpr const uint8_t RCT2_MAX_PATH_OBJECTS = 16; constexpr const uint8_t RCT2_MAX_PATH_ADDITION_OBJECTS = 15; constexpr const uint8_t RCT2_MAX_SCENERY_GROUP_OBJECTS = 19; constexpr const uint8_t RCT2_MAX_PARK_ENTRANCE_OBJECTS = 1; constexpr const uint8_t RCT2_MAX_WATER_OBJECTS = 1; constexpr const uint8_t RCT2_MAX_SCENARIO_TEXT_OBJECTS = 1; constexpr const uint8_t RCT2_RIDE_TYPE_COUNT = 91; constexpr const rct_string_id RCT2_RIDE_STRING_START = 2; constexpr const uint16_t RCT2_MAXIMUM_MAP_SIZE_TECHNICAL = 256; // clang-format off constexpr const uint16_t RCT2_OBJECT_ENTRY_COUNT = RCT12_MAX_RIDE_OBJECTS + RCT2_MAX_SMALL_SCENERY_OBJECTS + RCT2_MAX_LARGE_SCENERY_OBJECTS + RCT2_MAX_WALL_SCENERY_OBJECTS + RCT2_MAX_BANNER_OBJECTS + RCT2_MAX_PATH_OBJECTS + RCT2_MAX_PATH_ADDITION_OBJECTS + RCT2_MAX_SCENERY_GROUP_OBJECTS + RCT2_MAX_PARK_ENTRANCE_OBJECTS + RCT2_MAX_WATER_OBJECTS + RCT2_MAX_SCENARIO_TEXT_OBJECTS; // clang-format on static_assert(RCT2_OBJECT_ENTRY_COUNT == 721); // clang-format off constexpr const int32_t rct2_object_entry_group_counts[] = { RCT12_MAX_RIDE_OBJECTS, RCT2_MAX_SMALL_SCENERY_OBJECTS, RCT2_MAX_LARGE_SCENERY_OBJECTS, RCT2_MAX_WALL_SCENERY_OBJECTS, RCT2_MAX_BANNER_OBJECTS, RCT2_MAX_PATH_OBJECTS, RCT2_MAX_PATH_ADDITION_OBJECTS, RCT2_MAX_SCENERY_GROUP_OBJECTS, RCT2_MAX_PARK_ENTRANCE_OBJECTS, RCT2_MAX_WATER_OBJECTS, RCT2_MAX_SCENARIO_TEXT_OBJECTS, }; // clang-format on #pragma pack(push, 1) struct rct_ride_entry; /** * Ride structure. * size: 0x0260 */ struct rct2_ride { uint8_t type; // 0x000 // pointer to static info. for example, wild mouse type is 0x36, subtype is // 0x4c. RCT12ObjectEntryIndex subtype; // 0x001 uint16_t pad_002; // 0x002 uint8_t mode; // 0x004 uint8_t colour_scheme_type; // 0x005 rct_vehicle_colour vehicle_colours[RCT2_MAX_CARS_PER_TRAIN]; // 0x006 uint8_t pad_046[0x03]; // 0x046, Used to be track colours in RCT1 without expansions // 0 = closed, 1 = open, 2 = test uint8_t status; // 0x049 rct_string_id name; // 0x04A union { uint32_t name_arguments; // 0x04C struct { rct_string_id name_arguments_type_name; // 0x04C uint16_t name_arguments_number; // 0x04E }; }; RCT12xy8 overall_view; // 0x050 RCT12xy8 station_starts[RCT12_MAX_STATIONS_PER_RIDE]; // 0x052 uint8_t station_heights[RCT12_MAX_STATIONS_PER_RIDE]; // 0x05A uint8_t station_length[RCT12_MAX_STATIONS_PER_RIDE]; // 0x05E uint8_t station_depart[RCT12_MAX_STATIONS_PER_RIDE]; // 0x062 // ride->vehicle index for current train waiting for passengers // at station uint8_t train_at_station[RCT12_MAX_STATIONS_PER_RIDE]; // 0x066 RCT12xy8 entrances[RCT12_MAX_STATIONS_PER_RIDE]; // 0x06A RCT12xy8 exits[RCT12_MAX_STATIONS_PER_RIDE]; // 0x072 uint16_t last_peep_in_queue[RCT12_MAX_STATIONS_PER_RIDE]; // 0x07A uint8_t pad_082[RCT12_MAX_STATIONS_PER_RIDE]; // 0x082, Used to be number of peeps in queue in RCT1, but this has moved. uint16_t vehicles[RCT2_MAX_VEHICLES_PER_RIDE + 1]; // 0x086, Points to the first car in the train uint8_t depart_flags; // 0x0C6 // Not sure if these should be uint or sint. uint8_t num_stations; // 0x0C7 uint8_t num_vehicles; // 0x0C8 uint8_t num_cars_per_train; // 0x0C9 uint8_t proposed_num_vehicles; // 0x0CA uint8_t proposed_num_cars_per_train; // 0x0CB uint8_t max_trains; // 0x0CC uint8_t min_max_cars_per_train; // 0x0CD uint8_t min_waiting_time; // 0x0CE uint8_t max_waiting_time; // 0x0CF union { uint8_t operation_option; // 0x0D0 uint8_t time_limit; // 0x0D0 uint8_t num_laps; // 0x0D0 uint8_t launch_speed; // 0x0D0 uint8_t speed; // 0x0D0 uint8_t rotations; // 0x0D0 }; uint8_t boat_hire_return_direction; // 0x0D1 RCT12xy8 boat_hire_return_position; // 0x0D2 uint8_t measurement_index; // 0x0D4 // bits 0 through 4 are the number of helix sections // bit 5: spinning tunnel, water splash, or rapids // bit 6: log reverser, waterfall // bit 7: whirlpool uint8_t special_track_elements; // 0x0D5 uint8_t pad_0D6[2]; // 0x0D6 // Divide this value by 29127 to get the human-readable max speed // (in RCT2, display_speed = (max_speed * 9) >> 18) int32_t max_speed; // 0x0D8 int32_t average_speed; // 0x0DC uint8_t current_test_segment; // 0x0E0 uint8_t average_speed_test_timeout; // 0x0E1 uint8_t pad_0E2[0x2]; // 0x0E2 int32_t length[RCT12_MAX_STATIONS_PER_RIDE]; // 0x0E4 uint16_t time[RCT12_MAX_STATIONS_PER_RIDE]; // 0x0F4 fixed16_2dp max_positive_vertical_g; // 0x0FC fixed16_2dp max_negative_vertical_g; // 0x0FE fixed16_2dp max_lateral_g; // 0x100 fixed16_2dp previous_vertical_g; // 0x102 fixed16_2dp previous_lateral_g; // 0x104 uint8_t pad_106[0x2]; // 0x106 uint32_t testing_flags; // 0x108 // x y map location of the current track piece during a test // this is to prevent counting special tracks multiple times RCT12xy8 cur_test_track_location; // 0x10C // Next 3 variables are related (XXXX XYYY ZZZa aaaa) uint16_t turn_count_default; // 0x10E X = current turn count uint16_t turn_count_banked; // 0x110 uint16_t turn_count_sloped; // 0x112 X = number turns > 3 elements union { uint8_t inversions; // 0x114 (???X XXXX) uint8_t holes; // 0x114 (???X XXXX) // This is a very rough approximation of how much of the ride is undercover. // It reaches the maximum value of 7 at about 50% undercover and doesn't increase beyond that. uint8_t sheltered_eighths; // 0x114 (XXX?-????) }; // Y is number of powered lifts, X is drops uint8_t drops; // 0x115 (YYXX XXXX) uint8_t start_drop_height; // 0x116 uint8_t highest_drop_height; // 0x117 int32_t sheltered_length; // 0x118 // Unused always 0? Should affect nausea uint16_t var_11C; // 0x11C uint8_t num_sheltered_sections; // 0x11E (?abY YYYY) // see cur_test_track_location uint8_t cur_test_track_z; // 0x11F // Customer counter in the current 960 game tick (about 30 seconds) interval uint16_t cur_num_customers; // 0x120 // Counts ticks to update customer intervals, resets each 960 game ticks. uint16_t num_customers_timeout; // 0x122 // Customer count in the last 10 * 960 game ticks (sliding window) uint16_t num_customers[RCT2_CUSTOMER_HISTORY_SIZE]; // 0x124 money16 price; // 0x138 RCT12xy8 chairlift_bullwheel_location[2]; // 0x13A uint8_t chairlift_bullwheel_z[2]; // 0x13E union { RatingTuple ratings; // 0x140 struct { ride_rating excitement; // 0x140 ride_rating intensity; // 0x142 ride_rating nausea; // 0x144 }; }; uint16_t value; // 0x146 uint16_t chairlift_bullwheel_rotation; // 0x148 uint8_t satisfaction; // 0x14A uint8_t satisfaction_time_out; // 0x14B uint8_t satisfaction_next; // 0x14C // Various flags stating whether a window needs to be refreshed uint8_t window_invalidate_flags; // 0x14D uint8_t pad_14E[0x02]; // 0x14E uint32_t total_customers; // 0x150 money32 total_profit; // 0x154 uint8_t popularity; // 0x158 uint8_t popularity_time_out; // 0x159 Updated every purchase and ?possibly by time? uint8_t popularity_next; // 0x15A When timeout reached this will be the next popularity uint8_t num_riders; // 0x15B uint8_t music_tune_id; // 0x15C uint8_t slide_in_use; // 0x15D union { uint16_t slide_peep; // 0x15E uint16_t maze_tiles; // 0x15E }; uint8_t pad_160[0xE]; // 0x160 uint8_t slide_peep_t_shirt_colour; // 0x16E uint8_t pad_16F[0x7]; // 0x16F uint8_t spiral_slide_progress; // 0x176 uint8_t pad_177[0x9]; // 0x177 int16_t build_date; // 0x180 money16 upkeep_cost; // 0x182 uint16_t race_winner; // 0x184 uint8_t pad_186[0x02]; // 0x186 uint32_t music_position; // 0x188 uint8_t breakdown_reason_pending; // 0x18C uint8_t mechanic_status; // 0x18D uint16_t mechanic; // 0x18E uint8_t inspection_station; // 0x190 uint8_t broken_vehicle; // 0x191 uint8_t broken_car; // 0x192 uint8_t breakdown_reason; // 0x193 money16 price_secondary; // 0x194 union { struct { uint8_t reliability_subvalue; // 0x196, 0 - 255, acts like the decimals for reliability_percentage uint8_t reliability_percentage; // 0x197, Starts at 100 and decreases from there. }; uint16_t reliability; // 0x196 }; // Small constant used to increase the unreliability as the game continues, // making breakdowns more and more likely. uint8_t unreliability_factor; // 0x198 // Range from [0, 100] uint8_t downtime; // 0x199 uint8_t inspection_interval; // 0x19A uint8_t last_inspection; // 0x19B uint8_t downtime_history[RCT2_DOWNTIME_HISTORY_SIZE]; // 0x19C uint32_t no_primary_items_sold; // 0x1A4 uint32_t no_secondary_items_sold; // 0x1A8 uint8_t breakdown_sound_modifier; // 0x1AC // Used to oscillate the sound when ride breaks down. // 0 = no change, 255 = max change uint8_t not_fixed_timeout; // 0x1AD uint8_t last_crash_type; // 0x1AE uint8_t connected_message_throttle; // 0x1AF money32 income_per_hour; // 0x1B0 money32 profit; // 0x1B4 uint8_t queue_time[RCT12_MAX_STATIONS_PER_RIDE]; // 0x1B8 uint8_t track_colour_main[RCT12_NUM_COLOUR_SCHEMES]; // 0x1BC uint8_t track_colour_additional[RCT12_NUM_COLOUR_SCHEMES]; // 0x1C0 uint8_t track_colour_supports[RCT12_NUM_COLOUR_SCHEMES]; // 0x1C4 uint8_t music; // 0x1C8 uint8_t entrance_style; // 0x1C9 uint16_t vehicle_change_timeout; // 0x1CA uint8_t num_block_brakes; // 0x1CC uint8_t lift_hill_speed; // 0x1CD uint16_t guests_favourite; // 0x1CE uint32_t lifecycle_flags; // 0x1D0 uint8_t vehicle_colours_extended[RCT2_MAX_CARS_PER_TRAIN]; // 0x1D4 uint16_t total_air_time; // 0x1F4 uint8_t current_test_station; // 0x1F6 uint8_t num_circuits; // 0x1F7 int16_t cable_lift_x; // 0x1F8 int16_t cable_lift_y; // 0x1FA uint8_t cable_lift_z; // 0x1FC uint8_t pad_1FD; // 0x1FD uint16_t cable_lift; // 0x1FE uint16_t queue_length[RCT12_MAX_STATIONS_PER_RIDE]; // 0x200 uint8_t pad_208[0x58]; // 0x208 uint8_t GetMinCarsPerTrain() const; uint8_t GetMaxCarsPerTrain() const; void SetMinCarsPerTrain(uint8_t newValue); void SetMaxCarsPerTrain(uint8_t newValue); }; assert_struct_size(rct2_ride, 0x260); /* Track Entrance entry size: 0x06 */ struct rct_td6_entrance_element { int8_t z; // 0x00 uint8_t direction; // 0x01 int16_t x; // 0x02 int16_t y; // 0x04 }; assert_struct_size(rct_td6_entrance_element, 0x06); /* Track Scenery entry size: 0x16 */ struct rct_td6_scenery_element { rct_object_entry scenery_object; // 0x00 int8_t x; // 0x10 int8_t y; // 0x11 int8_t z; // 0x12 uint8_t flags; // 0x13 direction quadrant tertiary colour uint8_t primary_colour; // 0x14 uint8_t secondary_colour; // 0x15 }; assert_struct_size(rct_td6_scenery_element, 0x16); /** * Track design structure. * size: 0xA3 */ struct rct_track_td6 { uint8_t type; // 0x00 RCT12ObjectEntryIndex vehicle_type; union { // After loading the track this is converted to // a cost but before its a flags register money32 cost; // 0x02 uint32_t flags; // 0x02 }; union { // After loading the track this is converted to // a flags register uint8_t ride_mode; // 0x06 uint8_t track_flags; // 0x06 }; uint8_t version_and_colour_scheme; // 0x07 0b0000_VVCC rct_vehicle_colour vehicle_colours[RCT2_MAX_CARS_PER_TRAIN]; // 0x08 union { uint8_t pad_48; uint8_t track_spine_colour_rct1; // 0x48 }; union { uint8_t entrance_style; // 0x49 uint8_t track_rail_colour_rct1; // 0x49 }; union { uint8_t total_air_time; // 0x4A uint8_t track_support_colour_rct1; // 0x4A }; uint8_t depart_flags; // 0x4B uint8_t number_of_trains; // 0x4C uint8_t number_of_cars_per_train; // 0x4D uint8_t min_waiting_time; // 0x4E uint8_t max_waiting_time; // 0x4F uint8_t operation_setting; int8_t max_speed; // 0x51 int8_t average_speed; // 0x52 uint16_t ride_length; // 0x53 uint8_t max_positive_vertical_g; // 0x55 int8_t max_negative_vertical_g; // 0x56 uint8_t max_lateral_g; // 0x57 union { uint8_t inversions; // 0x58 uint8_t holes; // 0x58 }; uint8_t drops; // 0x59 uint8_t highest_drop_height; // 0x5A uint8_t excitement; // 0x5B uint8_t intensity; // 0x5C uint8_t nausea; // 0x5D money16 upkeep_cost; // 0x5E uint8_t track_spine_colour[RCT12_NUM_COLOUR_SCHEMES]; // 0x60 uint8_t track_rail_colour[RCT12_NUM_COLOUR_SCHEMES]; // 0x64 uint8_t track_support_colour[RCT12_NUM_COLOUR_SCHEMES]; // 0x68 uint32_t flags2; // 0x6C rct_object_entry vehicle_object; // 0x70 uint8_t space_required_x; // 0x80 uint8_t space_required_y; // 0x81 uint8_t vehicle_additional_colour[RCT2_MAX_CARS_PER_TRAIN]; // 0x82 uint8_t lift_hill_speed_num_circuits; // 0xA2 0bCCCL_LLLL // 0xA3 (data starts here in file) }; assert_struct_size(rct_track_td6, 0xA3); /** * scores.dat file header. * size: 0x10 */ struct rct_scores_header { uint32_t var_0; uint32_t var_4; uint32_t var_8; uint32_t ScenarioCount; }; assert_struct_size(rct_scores_header, 0x10); /** * An entry of scores.dat * size: 0x02B0 */ struct rct_scores_entry { char Path[256]; uint8_t Category; uint8_t pad_0101[0x1F]; int8_t ObjectiveType; int8_t ObjectiveArg1; int32_t objectiveArg2; int16_t objectiveArg3; char Name[64]; char Details[256]; int32_t Flags; money32 CompanyValue; char CompletedBy[64]; }; assert_struct_size(rct_scores_entry, 0x02B0); struct RCT2SpriteVehicle : RCT12SpriteBase { uint8_t Pitch; // 0x1F uint8_t bank_rotation; // 0x20 uint8_t pad_21[3]; int32_t remaining_distance; // 0x24 int32_t velocity; // 0x28 int32_t acceleration; // 0x2C uint8_t ride; // 0x30 uint8_t vehicle_type; // 0x31 rct_vehicle_colour colours; // 0x32 union { uint16_t track_progress; // 0x34 struct { int8_t var_34; uint8_t var_35; }; }; union { int16_t TrackTypeAndDirection; // 0x36 RCT12xy8 boat_location; // 0x36 }; uint16_t track_x; // 0x38 uint16_t track_y; // 0x3A uint16_t track_z; // 0x3C uint16_t next_vehicle_on_train; // 0x3E uint16_t prev_vehicle_on_ride; // 0x40 uint16_t next_vehicle_on_ride; // 0x42 uint16_t var_44; uint16_t mass; // 0x46 uint16_t update_flags; // 0x48 uint8_t SwingSprite; uint8_t current_station; // 0x4B union { int16_t SwingPosition; // 0x4C int16_t current_time; // 0x4C struct { int8_t ferris_wheel_var_0; // 0x4C int8_t ferris_wheel_var_1; // 0x4D }; }; union { int16_t SwingSpeed; int16_t crash_z; // 0x4E }; uint8_t status; // 0x50 uint8_t sub_state; // 0x51 uint16_t peep[32]; // 0x52 uint8_t peep_tshirt_colours[32]; // 0x92 uint8_t num_seats; // 0xB2 uint8_t num_peeps; // 0xB3 uint8_t next_free_seat; // 0xB4 uint8_t restraints_position; // 0xB5 union { int16_t spin_speed; // 0xB6 int16_t crash_x; // 0xB6 }; uint16_t sound2_flags; // 0xB8 uint8_t spin_sprite; // 0xBA uint8_t sound1_id; // 0xBB uint8_t sound1_volume; // 0xBC uint8_t sound2_id; // 0xBD uint8_t sound2_volume; // 0xBE int8_t sound_vector_factor; union { uint16_t var_C0; int16_t crash_y; // 0xC0 uint16_t time_waiting; // 0xC0 uint16_t cable_lift_target; // 0xC0 }; uint8_t speed; // 0xC2 uint8_t powered_acceleration; // 0xC3 union { uint8_t dodgems_collision_direction; // 0xC4 uint8_t var_C4; }; uint8_t animation_frame; // 0xC5 uint8_t pad_C6[0x2]; uint32_t animationState; uint8_t scream_sound_id; // 0xCC uint8_t TrackSubposition; union { uint8_t var_CE; uint8_t num_laps; // 0xCE }; union { uint8_t var_CF; uint8_t brake_speed; // 0xCF }; uint16_t lost_time_out; // 0xD0 int8_t vertical_drop_countdown; // 0xD1 uint8_t var_D3; uint8_t mini_golf_current_animation; uint8_t mini_golf_flags; // 0xD5 uint8_t ride_subtype; // 0xD6 uint8_t colours_extended; // 0xD7 uint8_t seat_rotation; // 0xD8 uint8_t target_seat_rotation; // 0xD9 uint16_t GetTrackType() const { return TrackTypeAndDirection >> 2; } uint8_t GetTrackDirection() const { return TrackTypeAndDirection & RCT12VehicleTrackDirectionMask; } void SetTrackType(uint16_t trackType) { // set the upper 14 bits to 0 TrackTypeAndDirection &= ~RCT12VehicleTrackTypeMask; TrackTypeAndDirection |= trackType << 2; } void SetTrackDirection(uint8_t trackDirection) { // set the lower 2 bits only TrackTypeAndDirection &= ~RCT12VehicleTrackDirectionMask; TrackTypeAndDirection |= trackDirection & RCT12VehicleTrackDirectionMask; } }; assert_struct_size(RCT2SpriteVehicle, 0xDA); struct RCT2SpritePeep : RCT12SpriteBase { uint8_t pad_1F[0x22 - 0x1F]; rct_string_id name_string_idx; // 0x22 uint16_t next_x; // 0x24 uint16_t next_y; // 0x26 uint8_t next_z; // 0x28 uint8_t next_flags; // 0x29 uint8_t outside_of_park; // 0x2A uint8_t state; // 0x2B uint8_t sub_state; // 0x2C uint8_t sprite_type; // 0x2D uint8_t peep_type; // 0x2E union { uint8_t staff_type; // 0x2F uint8_t no_of_rides; // 0x2F }; uint8_t tshirt_colour; // 0x30 uint8_t trousers_colour; // 0x31 uint16_t destination_x; // 0x32 uint16_t destination_y; // 0x34 uint8_t destination_tolerance; // 0x36 uint8_t var_37; uint8_t energy; // 0x38 uint8_t energy_target; // 0x39 uint8_t happiness; // 0x3A uint8_t happiness_target; // 0x3B uint8_t nausea; // 0x3C uint8_t nausea_target; // 0x3D uint8_t hunger; // 0x3E uint8_t thirst; // 0x3F uint8_t toilet; // 0x40 uint8_t mass; // 0x41 uint8_t time_to_consume; // 0x42 uint8_t intensity; // 0x43 uint8_t nausea_tolerance; // 0x44 uint8_t window_invalidate_flags; // 0x45 money16 paid_on_drink; // 0x46 uint8_t ride_types_been_on[16]; // 0x48 uint32_t item_extra_flags; // 0x58 RCT12RideId photo2_ride_ref; // 0x5C RCT12RideId photo3_ride_ref; // 0x5D RCT12RideId photo4_ride_ref; // 0x5E uint8_t pad_5F[0x09]; // 0x5F RCT12RideId current_ride; // 0x68 uint8_t current_ride_station; // 0x69 uint8_t current_train; // 0x6A union { struct { uint8_t current_car; // 0x6B uint8_t current_seat; // 0x6C }; uint16_t time_to_sitdown; // 0x6B struct { uint8_t time_to_stand; // 0x6B uint8_t standing_flags; // 0x6C }; }; uint8_t special_sprite; // 0x6D uint8_t action_sprite_type; // 0x6E uint8_t next_action_sprite_type; // 0x6F uint8_t action_sprite_image_offset; // 0x70 uint8_t action; // 0x71 uint8_t action_frame; // 0x72 uint8_t step_progress; // 0x73 union { uint16_t mechanic_time_since_call; uint16_t next_in_queue; // 0x74 }; uint8_t pad_76; uint8_t pad_77; union { uint8_t maze_last_edge; // 0x78 uint8_t direction; }; RCT12RideId interaction_ride_index; uint16_t time_in_queue; // 0x7A uint8_t rides_been_on[32]; // 0x7C uint32_t id; // 0x9C money32 cash_in_pocket; // 0xA0 money32 cash_spent; // 0xA4 int32_t park_entry_time; // 0xA8 int8_t rejoin_queue_timeout; // 0xAC RCT12RideId previous_ride; // 0xAD uint16_t previous_ride_time_out; // 0xAE RCT12PeepThought thoughts[RCT12_PEEP_MAX_THOUGHTS]; // 0xB0 uint8_t path_check_optimisation; // 0xC4 union { uint8_t staff_id; // 0xC5 RCT12RideId guest_heading_to_ride_id; // 0xC5 }; union { uint8_t staff_orders; // 0xC6 uint8_t peep_is_lost_countdown; // 0xC6 }; RCT12RideId photo1_ride_ref; // 0xC7 uint32_t peep_flags; // 0xC8 rct12_xyzd8 pathfind_goal; // 0xCC rct12_xyzd8 pathfind_history[4]; // 0xD0 uint8_t no_action_frame_num; // 0xE0 uint8_t litter_count; // 0xE1 union { uint8_t time_on_ride; // 0xE2 uint8_t staff_mowing_timeout; // 0xE2 }; uint8_t disgusting_count; // 0xE3 union { money16 paid_to_enter; // 0xE4 uint16_t staff_lawns_mown; // 0xE4 uint16_t staff_rides_fixed; // 0xE4 }; union { money16 paid_on_rides; // 0xE6 uint16_t staff_gardens_watered; // 0xE6 uint16_t staff_rides_inspected; // 0xE6 }; union { money16 paid_on_food; // 0xE8 uint16_t staff_litter_swept; // 0xE8 }; union { money16 paid_on_souvenirs; // 0xEA uint16_t staff_bins_emptied; // 0xEA }; uint8_t no_of_food; // 0xEC uint8_t no_of_drinks; // 0xED uint8_t no_of_souvenirs; // 0xEE uint8_t vandalism_seen; // 0xEF 0xC0 vandalism thought timeout, 0x3F vandalism tiles seen uint8_t voucher_type; // 0xF0 RCT12RideId voucher_arguments; // 0xF1 ride_id or string_offset_id uint8_t surroundings_thought_timeout; // 0xF2 uint8_t angriness; // 0xF3 uint8_t time_lost; // 0xF4 the time the peep has been lost when it reaches 254 generates the lost thought uint8_t days_in_queue; // 0xF5 uint8_t balloon_colour; // 0xF6 uint8_t umbrella_colour; // 0xF7 uint8_t hat_colour; // 0xF8 RCT12RideId favourite_ride; // 0xF9 uint8_t favourite_ride_rating; // 0xFA uint8_t pad_FB; uint32_t item_standard_flags; // 0xFC uint64_t GetItemFlags() const { return item_standard_flags | (static_cast(item_extra_flags) << 32); } }; assert_struct_size(RCT2SpritePeep, 0x100); union RCT2Sprite { private: uint8_t pad_00[0x100]; public: RCT12SpriteBase unknown; RCT2SpriteVehicle vehicle; RCT2SpritePeep peep; RCT12SpriteLitter litter; RCT12SpriteBalloon balloon; RCT12SpriteDuck duck; RCT12SpriteJumpingFountain jumping_fountain; RCT12SpriteMoneyEffect money_effect; RCT12SpriteCrashedVehicleParticle crashed_vehicle_particle; RCT12SpriteCrashSplash crash_splash; RCT12SpriteSteamParticle steam_particle; RCT12SpriteParticle misc_particle; }; assert_struct_size(RCT2Sprite, 0x100); struct RCT2RideRatingCalculationData { uint16_t proximity_x; uint16_t proximity_y; uint16_t proximity_z; uint16_t proximity_start_x; uint16_t proximity_start_y; uint16_t proximity_start_z; uint8_t current_ride; uint8_t state; uint8_t proximity_track_type; uint8_t proximity_base_height; uint16_t proximity_total; uint16_t proximity_scores[26]; uint16_t num_brakes; uint16_t num_reversers; uint16_t station_flags; }; assert_struct_size(RCT2RideRatingCalculationData, 76); /** * SV6/SC6 header chunk * size: 0x20 */ struct rct_s6_header { uint8_t type; // 0x00 uint8_t classic_flag; // 0x01 uint16_t num_packed_objects; // 0x02 uint32_t version; // 0x04 uint32_t magic_number; // 0x08 uint8_t pad_0C[0x14]; }; assert_struct_size(rct_s6_header, 0x20); enum class EditorStep : uint8_t; /** * SC6 information chunk * size: 0x198 */ struct rct_s6_info { EditorStep editor_step; uint8_t category; // 0x01 uint8_t objective_type; // 0x02 uint8_t objective_arg_1; // 0x03 int32_t objective_arg_2; // 0x04 int16_t objective_arg_3; // 0x08 uint8_t pad_00A[0x3E]; char name[64]; // 0x48 char details[256]; // 0x88 rct_object_entry entry; // 0x188 }; assert_struct_size(rct_s6_info, 0x198); struct rct_s6_data { // SC6[0] rct_s6_header header; // SC6[1] rct_s6_info info; // SC6[2] // packed objects // SC6[3] union { rct_object_entry Objects[RCT2_OBJECT_ENTRY_COUNT]; struct { rct_object_entry RideObjects[RCT12_MAX_RIDE_OBJECTS]; rct_object_entry SceneryObjects[RCT2_MAX_SMALL_SCENERY_OBJECTS]; rct_object_entry LargeSceneryObjects[RCT2_MAX_LARGE_SCENERY_OBJECTS]; rct_object_entry WallSceneryObjects[RCT2_MAX_WALL_SCENERY_OBJECTS]; rct_object_entry BannerObjects[RCT2_MAX_BANNER_OBJECTS]; rct_object_entry PathObjects[RCT2_MAX_PATH_OBJECTS]; rct_object_entry PathAdditionObjects[RCT2_MAX_PATH_ADDITION_OBJECTS]; rct_object_entry SceneryGroupObjects[RCT2_MAX_SCENERY_GROUP_OBJECTS]; rct_object_entry ParkEntranceObjects[RCT2_MAX_PARK_ENTRANCE_OBJECTS]; rct_object_entry WaterObjects[RCT2_MAX_WATER_OBJECTS]; rct_object_entry ScenarioTextObjects[RCT2_MAX_SCENARIO_TEXT_OBJECTS]; }; }; // SC6[4] uint16_t elapsed_months; uint16_t current_day; uint32_t scenario_ticks; uint32_t scenario_srand_0; uint32_t scenario_srand_1; // SC6[5] RCT12TileElement tile_elements[RCT2_MAX_TILE_ELEMENTS]; // SC6[6] uint32_t next_free_tile_element_pointer_index; RCT2Sprite sprites[RCT2_MAX_SPRITES]; uint16_t sprite_lists_head[static_cast(EntityListId::Count)]; uint16_t sprite_lists_count[static_cast(EntityListId::Count)]; rct_string_id park_name; uint8_t pad_013573D6[2]; uint32_t park_name_args; money32 initial_cash; money32 current_loan; uint32_t park_flags; money16 park_entrance_fee; uint16_t rct1_park_entrance_x; uint16_t rct1_park_entrance_y; uint8_t pad_013573EE[2]; uint8_t rct1_park_entrance_z; uint8_t pad_013573F1; rct12_peep_spawn peep_spawns[RCT12_MAX_PEEP_SPAWNS]; uint8_t guest_count_change_modifier; uint8_t current_research_level; uint8_t pad_01357400[4]; uint32_t researched_ride_types[RCT2_MAX_RESEARCHED_RIDE_TYPE_QUADS]; uint32_t researched_ride_entries[RCT2_MAX_RESEARCHED_RIDE_ENTRY_QUADS]; uint32_t researched_track_types_a[128]; uint32_t researched_track_types_b[128]; // SC6[7] uint16_t guests_in_park; uint16_t guests_heading_for_park; // Ignored in scenario money32 expenditure_table[RCT12_EXPENDITURE_TABLE_MONTH_COUNT][RCT12_EXPENDITURE_TYPE_COUNT]; // SC6[8] uint16_t last_guests_in_park; uint8_t pad_01357BCA[3]; uint8_t handyman_colour; uint8_t mechanic_colour; uint8_t security_colour; // Ignored in scenario uint32_t researched_scenery_items[RCT2_MAX_RESEARCHED_SCENERY_ITEM_QUADS]; // SC6[9] uint16_t park_rating; // Ignored in scenario uint8_t park_rating_history[32]; uint8_t guests_in_park_history[32]; // SC6[10] uint8_t active_research_types; uint8_t research_progress_stage; uint32_t last_researched_item_subject; uint8_t pad_01357CF8[1000]; uint32_t next_research_item; uint16_t research_progress; uint8_t next_research_category; uint8_t next_research_expected_day; uint8_t next_research_expected_month; uint8_t guest_initial_happiness; uint16_t park_size; uint16_t guest_generation_probability; uint16_t total_ride_value_for_money; money32 maximum_loan; money16 guest_initial_cash; uint8_t guest_initial_hunger; uint8_t guest_initial_thirst; uint8_t objective_type; uint8_t objective_year; uint8_t pad_013580FA[2]; money32 objective_currency; uint16_t objective_guests; uint8_t campaign_weeks_left[20]; uint8_t campaign_ride_index[22]; // Ignored in scenario money32 balance_history[RCT12_FINANCE_GRAPH_SIZE]; // SC6[11] money32 current_expenditure; money32 current_profit; money32 weekly_profit_average_dividend; uint16_t weekly_profit_average_divisor; uint8_t pad_0135833A[2]; // Ignored in scenario money32 weekly_profit_history[RCT12_FINANCE_GRAPH_SIZE]; // SC6[12] money32 park_value; // Ignored in scenario money32 park_value_history[RCT12_FINANCE_GRAPH_SIZE]; // SC6[13] money32 completed_company_value; uint32_t total_admissions; money32 income_from_admissions; money32 company_value; uint8_t peep_warning_throttle[16]; rct12_award awards[RCT12_MAX_AWARDS]; money16 land_price; money16 construction_rights_price; uint16_t word_01358774; uint8_t pad_01358776[2]; uint32_t cd_key; uint8_t pad_0135877C[64]; uint32_t game_version_number; money32 completed_company_value_record; uint32_t loan_hash; uint16_t ride_count; uint8_t pad_013587CA[6]; money32 historical_profit; uint8_t pad_013587D4[4]; char scenario_completed_name[32]; money32 cash; uint8_t pad_013587FC[50]; uint16_t park_rating_casualty_penalty; uint16_t map_size_units; uint16_t map_size_minus_2; uint16_t map_size; uint16_t map_max_xy; uint32_t same_price_throughout; uint16_t suggested_max_guests; uint16_t park_rating_warning_days; uint8_t last_entrance_style; uint8_t rct1_water_colour; uint8_t pad_01358842[2]; RCT12ResearchItem research_items[RCT2_MAX_RESEARCH_ITEMS]; uint16_t map_base_z; char scenario_name[64]; char scenario_description[256]; uint8_t current_interest_rate; uint8_t pad_0135934B; uint32_t same_price_throughout_extended; int16_t park_entrance_x[RCT12_MAX_PARK_ENTRANCES]; int16_t park_entrance_y[RCT12_MAX_PARK_ENTRANCES]; int16_t park_entrance_z[RCT12_MAX_PARK_ENTRANCES]; uint8_t park_entrance_direction[RCT12_MAX_PARK_ENTRANCES]; char scenario_filename[256]; uint8_t saved_expansion_pack_names[3256]; RCT12Banner banners[RCT2_MAX_BANNERS_IN_PARK]; char custom_strings[RCT12_MAX_USER_STRINGS][RCT12_USER_STRING_MAX_LENGTH]; uint32_t game_ticks_1; rct2_ride rides[RCT12_MAX_RIDES_IN_PARK]; uint16_t saved_age; int16_t saved_view_x; int16_t saved_view_y; uint8_t saved_view_zoom; uint8_t saved_view_rotation; RCT12MapAnimation map_animations[RCT2_MAX_ANIMATED_OBJECTS]; uint16_t num_map_animations; uint8_t pad_0138B582[2]; RCT2RideRatingCalculationData ride_ratings_calc_data; uint8_t pad_0138B5D0[60]; RCT12RideMeasurement ride_measurements[8]; uint32_t next_guest_index; uint16_t grass_and_scenery_tilepos; uint32_t patrol_areas[(RCT2_MAX_STAFF + RCT12_STAFF_TYPE_COUNT) * RCT12_PATROL_AREA_SIZE]; uint8_t staff_modes[RCT2_MAX_STAFF + RCT12_STAFF_TYPE_COUNT]; uint8_t pad_13CA73E; uint8_t pad_13CA73F; uint8_t byte_13CA740; uint8_t pad_13CA741; uint8_t byte_13CA742[4]; // unused uint8_t climate; uint8_t pad_013CA747; uint16_t climate_update_timer; uint8_t current_weather; uint8_t next_weather; uint8_t temperature; uint8_t next_temperature; uint8_t current_weather_effect; uint8_t next_weather_effect; uint8_t current_weather_gloom; uint8_t next_weather_gloom; uint8_t current_weather_level; uint8_t next_weather_level; rct12_news_item news_items[RCT12_MAX_NEWS_ITEMS]; char rct1_scenario_name[62]; // Unused in RCT2 uint16_t rct1_scenario_slot_index; // Unused in RCT2 uint32_t rct1_scenario_flags; // Unused in RCT2 uint16_t wide_path_tile_loop_x; uint16_t wide_path_tile_loop_y; uint8_t pad_13CE778[434]; }; assert_struct_size(rct_s6_data, 0x46b44a); struct rct_stex_entry { rct_string_id scenario_name; // 0x00 rct_string_id park_name; // 0x02 rct_string_id details; // 0x04 uint8_t var_06; }; assert_struct_size(rct_stex_entry, 7); #pragma pack(pop) std::vector DecryptSea(const fs::path& path); ObjectEntryIndex RCT2RideTypeToOpenRCT2RideType(uint8_t rct2RideType, const rct_ride_entry* rideEntry); bool RCT2TrackTypeIsBooster(uint8_t rideType, uint16_t trackType); bool RCT2RideTypeNeedsConversion(uint8_t rct2RideType); uint8_t OpenRCT2RideTypeToRCT2RideType(ObjectEntryIndex openrct2Type); track_type_t RCT2TrackTypeToOpenRCT2(RCT12TrackType origTrackType, uint8_t rideType, bool convertFlat); RCT12TrackType OpenRCT2TrackTypeToRCT2(track_type_t origTrackType); /** * Iterates an RCT2 string buffer and returns the length of the string in bytes. * Handles single and multi-byte strings. */ size_t GetRCT2StringBufferLen(const char* buffer, size_t maxBufferLen); struct FootpathMapping { std::string_view Original; std::string_view NormalSurface; std::string_view QueueSurface; std::string_view Railing; }; const FootpathMapping* GetFootpathSurfaceId( const ObjectEntryDescriptor& desc, bool ideallyLoaded = false, bool isQueue = false); std::optional GetBestObjectEntryForSurface(std::string_view surface, std::string_view railings);