diff --git a/src/openrct2/rct1.h b/src/openrct2/rct1.h index 89eaf43166..f2875119ff 100644 --- a/src/openrct2/rct1.h +++ b/src/openrct2/rct1.h @@ -26,6 +26,9 @@ #include "world/map.h" #include "world/sprite.h" +#define RCT1_MAX_MAP_ELEMENTS 0xC000 +#define RCT1_MAX_SPRITES 5000 + #pragma pack(push, 1) typedef struct rct1_entrance { uint16 x; @@ -71,10 +74,10 @@ typedef struct rct1_ride { uint8 num_stations; uint8 num_trains; uint8 num_cars_per_train; - uint8 unk_7A; - uint8 unk_7B; + uint8 proposed_num_vehicles; // 0x7A + uint8 proposed_num_cars_per_train; // 0x7B uint8 max_trains; - uint8 unk_7D; + uint8 min_max_cars_per_train; // 0x7D uint8 min_waiting_time; uint8 max_waiting_time; uint8 operation_option; @@ -85,13 +88,25 @@ typedef struct rct1_ride { uint16 unk_86; sint32 max_speed; sint32 average_speed; - uint8 pad_090[4]; + uint8 current_test_segment; // 0x90 + uint8 average_speed_test_timeout; // 0x91 + uint8 pad_0E2[0x2]; // 0x92 sint32 length[4]; uint16 time[4]; fixed16_2dp max_positive_vertical_g; fixed16_2dp max_negative_vertical_g; fixed16_2dp max_lateral_g; - uint8 unk_B2[18]; + fixed16_2dp previous_vertical_g;// 0xB2 + fixed16_2dp previous_lateral_g; // 0xB4 + uint8 pad_106[0x2]; + uint32 testing_flags; // 0xB8 + // x y map location of the current track piece during a test + // this is to prevent counting special tracks multiple times + rct_xy8 cur_test_track_location; // 0xBC + // Next 3 variables are related (XXXX XYYY ZZZa aaaa) + uint16 turn_count_default; // 0xBE X = current turn count + uint16 turn_count_banked; // 0xC0 + uint16 turn_count_sloped; // 0xC2 X = number turns > 3 elements union { uint8 num_inversions; uint8 num_holes; @@ -102,7 +117,8 @@ typedef struct rct1_ride { sint32 sheltered_length; uint8 unk_CC[2]; uint8 num_sheltered_sections; - uint8 unk_CF; + // see cur_test_track_location + uint8 cur_test_track_z; // 0xCF sint16 unk_D0; sint16 unk_D2; sint16 customers_per_hour; @@ -116,10 +132,8 @@ typedef struct rct1_ride { sint16 unk_E4; sint16 unk_E6; money16 price; - sint16 var_EA; - sint16 var_EC; - uint8 var_EE; - uint8 var_EF; + rct_xy8 chairlift_bullwheel_location[2]; // 0xEA + uint8 chairlift_bullwheel_z[2]; // 0xEE union { rating_tuple ratings; struct { @@ -129,7 +143,7 @@ typedef struct rct1_ride { }; }; uint16 value; - uint16 var_F8; + uint16 chairlift_bullwheel_rotation; // 0xF8 uint8 satisfaction; uint8 satisfaction_time_out; uint8 satisfaction_next; @@ -391,7 +405,14 @@ typedef union rct1_sprite { uint8 pad_00[0x100]; rct1_unk_sprite unknown; rct1_peep peep; - rct_litter litter; + rct_litter litter; + rct_balloon balloon; + rct_sprite duck; + rct_jumping_fountain jumping_fountain; + rct_money_effect money_effect; + rct_crashed_vehicle_particle crashed_vehicle_particle; + rct_crash_splash crash_splash; + rct_steam_particle steam_particle; } rct1_sprite; assert_struct_size(rct1_sprite, 0x100); @@ -414,9 +435,9 @@ typedef struct rct1_s4 { uint32 ticks; uint32 random_a; uint32 random_b; - rct_map_element map_elements[0xC000]; + rct_map_element map_elements[RCT1_MAX_MAP_ELEMENTS]; uint32 unk_counter; - rct1_sprite sprites[5000]; + rct1_sprite sprites[RCT1_MAX_SPRITES]; uint16 next_sprite_index; uint16 first_vehicle_sprite_index; uint16 first_peep_sprite_index; diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 03b1513d4d..8bf3833995 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -146,7 +146,6 @@ public: ImportRides(); ImportRideMeasurements(); ImportSprites(); - //FixNumPeepsInQueue(); ImportMapElements(); ImportMapAnimations(); ImportPeepSpawns(); @@ -615,6 +614,7 @@ private: dst->proposed_num_cars_per_train = src->num_cars_per_train + rideEntry->zero_cars; dst->special_track_elements = src->special_track_elements; dst->num_sheltered_sections = src->num_sheltered_sections; + dst->sheltered_length = src->sheltered_length; // Operation dst->depart_flags = src->depart_flags; @@ -694,14 +694,6 @@ private: } } - // Fix other Z - // if (dst->cur_test_track_z != 255) - // { - // dst->cur_test_track_z /= 2; - // } - // dst->chairlift_bullwheel_z[0] /= 2; - // dst->chairlift_bullwheel_z[1] /= 2; - // Maintenance dst->build_date = src->build_date; dst->inspection_interval = src->inspection_interval; @@ -724,11 +716,30 @@ private: dst->max_positive_vertical_g = src->max_positive_vertical_g; dst->max_negative_vertical_g = src->max_negative_vertical_g; dst->max_lateral_g = src->max_lateral_g; + dst->previous_lateral_g = src->previous_lateral_g; + dst->previous_vertical_g = src->previous_vertical_g; + dst->turn_count_banked = src->turn_count_banked; + dst->turn_count_default = src->turn_count_default; + dst->turn_count_sloped = src->turn_count_sloped; dst->drops = src->num_drops; dst->start_drop_height = src->start_drop_height / 2; dst->highest_drop_height = src->highest_drop_height / 2; dst->inversions = src->num_inversions; - dst->measurement_index = 255; + dst->boat_hire_return_direction = src->boat_hire_return_direction; + dst->boat_hire_return_position = src->boat_hire_return_position; + dst->measurement_index = src->data_logging_index; + dst->chairlift_bullwheel_rotation = src->chairlift_bullwheel_rotation; + for (int i = 0; i < 2; i++) + { + dst->chairlift_bullwheel_location[i] = src->chairlift_bullwheel_location[i]; + dst->chairlift_bullwheel_z[i] = src->chairlift_bullwheel_z[i] / 2; + } + dst->cur_test_track_z = src->cur_test_track_z / 2; + dst->cur_test_track_location = src->cur_test_track_location; + dst->testing_flags = src->testing_flags; + dst->current_test_segment = src->current_test_segment; + dst->current_test_station = 0xFF; + dst->average_speed_test_timeout = src->average_speed_test_timeout; // Finance / customers dst->upkeep_cost = src->upkeep_cost; @@ -746,6 +757,8 @@ private: dst->popularity_next = src->popularity_next; dst->popularity_time_out = src->popularity_time_out; + dst->num_riders = src->num_riders; + dst->music_tune_id = 255; } @@ -785,11 +798,13 @@ private: void ImportSprites() { ImportPeeps(); + ImportLitter(); + ImportMiscSprites(); } void ImportPeeps() { - for (int i = 0; i < 5000; i++) + for (int i = 0; i < RCT1_MAX_SPRITES; i++) { if (_s4.sprites[i].unknown.sprite_identifier == SPRITE_IDENTIFIER_PEEP) { @@ -810,11 +825,13 @@ private: dst->sprite_identifier = SPRITE_IDENTIFIER_PEEP; // Peep vs. staff (including which kind) dst->sprite_type = RCT1::GetPeepSpriteType(src->sprite_type); - dst->action = PEEP_ACTION_NONE_2; - dst->special_sprite = 0; - dst->action_sprite_image_offset = 0; - dst->no_action_frame_no = 0; - dst->action_sprite_type = 0; + dst->action = src->action; + dst->special_sprite = src->special_sprite; + dst->next_action_sprite_type = src->next_action_sprite_type; + dst->action_sprite_image_offset = src->action_sprite_image_offset; + dst->no_action_frame_no = src->no_action_frame_no; + dst->action_sprite_type = src->action_sprite_type; + dst->action_frame = src->action_frame; const rct_sprite_bounds* spriteBounds = g_sprite_entries[dst->sprite_type].sprite_bounds; dst->sprite_width = spriteBounds[dst->action_sprite_type].sprite_width; @@ -847,9 +864,19 @@ private: dst->tshirt_colour = RCT1::GetColour(src->tshirt_colour); dst->trousers_colour = RCT1::GetColour(src->trousers_colour); - dst->balloon_colour = RCT1::GetColour(src->balloon_colour); dst->umbrella_colour = RCT1::GetColour(src->umbrella_colour); dst->hat_colour = RCT1::GetColour(src->hat_colour); + + // Balloons were always blue in RCT1 without AA/LL + if (_gameVersion == FILE_VERSION_RCT1) + { + dst->balloon_colour = COLOUR_LIGHT_BLUE; + } + else + { + dst->balloon_colour = RCT1::GetColour(src->balloon_colour); + } + dst->destination_x = src->destination_x; dst->destination_y = src->destination_y; dst->destination_tolerence = src->destination_tolerence; @@ -874,6 +901,11 @@ private: dst->current_ride = src->current_ride; dst->current_ride_station = src->current_ride_station; + dst->current_train = src->current_train; + dst->current_car = src->current_car; + dst->current_seat = src->current_seat; + dst->time_on_ride = src->time_on_ride; + dst->days_in_queue = src->days_in_queue; dst->interactionRideIndex = 0xFF; @@ -898,27 +930,30 @@ private: dst->voucher_arguments = src->voucher_arguments; dst->voucher_type = src->voucher_type; - for (int i = 0; i < 32; i++) { + for (int i = 0; i < 32; i++) + { dst->rides_been_on[i] = src->rides_been_on[i]; } - for (int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { dst->ride_types_been_on[i] = src->ride_types_been_on[i]; } dst->photo1_ride_ref = src->photo1_ride_ref; - for (int i = 0; i < PEEP_MAX_THOUGHTS; i++) { + for (int i = 0; i < PEEP_MAX_THOUGHTS; i++) + { dst->thoughts[i] = src->thoughts[i]; } dst->previous_ride = 0xFF; - dst->thoughts->type = PEEP_THOUGHT_TYPE_NONE; - dst->var_C4 = 0; dst->guest_heading_to_ride_id = src->guest_heading_to_ride_id; // Doubles as staff orders dst->peep_is_lost_countdown = src->peep_is_lost_countdown; + // The ID is fixed later + dst->next_in_queue = src->next_in_queue; dst->peep_flags = 0; dst->pathfind_goal.x = 0xFF; @@ -939,30 +974,149 @@ private: } } - void ImportLitter() + void FixRidePeepLinks(rct_ride * ride, const uint16 * spriteIndexMap) { - for (int i = 0; i < 5000; i++) + for (int i = 0; i < RCT1_MAX_STATIONS; i++) { - if (_s4.sprites[i].unknown.sprite_identifier == SPRITE_IDENTIFIER_LITTER) { - rct_litter *srcLitter = &_s4.sprites[i].litter; - if (srcLitter->x != (sint16) 0x8000) { - rct_litter *litter = (rct_litter *) create_sprite(SPRITE_IDENTIFIER_LITTER); - move_sprite_to_list((rct_sprite *) litter, SPRITE_LIST_LITTER * 2); - - litter->x = srcLitter->x; - litter->y = srcLitter->y; - litter->z = srcLitter->z; - - sprite_move(srcLitter->x, srcLitter->y, srcLitter->z, (rct_sprite *) litter); - invalidate_sprite_2((rct_sprite *) litter); - - litter->sprite_direction = srcLitter->sprite_direction; - litter->type = srcLitter->type; - } + uint16 originalSpriteIndex = ride->last_peep_in_queue[i]; + if (originalSpriteIndex != SPRITE_INDEX_NULL) + { + ride->last_peep_in_queue[i] = spriteIndexMap[originalSpriteIndex]; } } } + void FixPeepNextInQueue(rct_peep * peep, const uint16 * spriteIndexMap) + { + uint16 originalSpriteIndex = peep->next_in_queue; + if (originalSpriteIndex != SPRITE_INDEX_NULL) + { + peep->next_in_queue = spriteIndexMap[originalSpriteIndex]; + } + } + + void ImportLitter() + { + for (int i = 0; i < RCT1_MAX_SPRITES; i++) + { + if (_s4.sprites[i].unknown.sprite_identifier == SPRITE_IDENTIFIER_LITTER) + { + rct_litter * srcLitter = &_s4.sprites[i].litter; + + rct_litter * litter = (rct_litter *) create_sprite(SPRITE_IDENTIFIER_LITTER); + move_sprite_to_list((rct_sprite *) litter, SPRITE_LIST_LITTER * 2); + + litter->sprite_identifier = srcLitter->sprite_identifier; + litter->type = srcLitter->type; + + litter->x = srcLitter->x; + litter->y = srcLitter->y; + litter->z = srcLitter->z; + litter->sprite_direction = srcLitter->sprite_direction; + litter->sprite_width = srcLitter->sprite_width; + litter->sprite_height_positive = srcLitter->sprite_height_positive; + litter->sprite_height_negative = srcLitter->sprite_height_negative; + + sprite_move(srcLitter->x, srcLitter->y, srcLitter->z, (rct_sprite *) litter); + invalidate_sprite_2((rct_sprite *) litter); + } + } + } + + void ImportMiscSprites() + { + for (int i = 0; i < RCT1_MAX_SPRITES; i++) + { + if (_s4.sprites[i].unknown.sprite_identifier == SPRITE_IDENTIFIER_MISC) + { + rct1_unk_sprite * src = &_s4.sprites[i].unknown; + rct_unk_sprite * dst = (rct_unk_sprite *) create_sprite(SPRITE_IDENTIFIER_MISC); + move_sprite_to_list((rct_sprite *) dst, SPRITE_LIST_MISC * 2); + + dst->sprite_identifier = src->sprite_identifier; + dst->misc_identifier = src->misc_identifier; + dst->flags = src->flags; + dst->x = src->x; + dst->y = src->y; + dst->z = src->z; + dst->sprite_direction = src->sprite_direction; + dst->sprite_width = src->sprite_width; + dst->sprite_height_negative = src->sprite_height_negative; + dst->sprite_height_positive = src->sprite_height_positive; + + switch (src->misc_identifier) { + case SPRITE_MISC_STEAM_PARTICLE: + ImportSteamParticle((rct_steam_particle *) dst, (rct_steam_particle *) src); + break; + case SPRITE_MISC_MONEY_EFFECT: + ImportMoneyEffect((rct_money_effect *) dst, (rct_money_effect *) src); + break; + case SPRITE_MISC_CRASHED_VEHICLE_PARTICLE: + break; + case SPRITE_MISC_EXPLOSION_CLOUD: + break; + case SPRITE_MISC_CRASH_SPLASH: + break; + case SPRITE_MISC_EXPLOSION_FLARE: + break; + case SPRITE_MISC_JUMPING_FOUNTAIN_WATER: + ImportJumpingFountainWater((rct_jumping_fountain *) dst, (rct_jumping_fountain *) src); + break; + case SPRITE_MISC_BALLOON: + ImportBalloon((rct_balloon*)dst, (rct_balloon*)src); + break; + case SPRITE_MISC_DUCK: + ImportDuck((rct_duck*)dst, (rct_duck*)src); + break; + } + + sprite_move(src->x, src->y, src->z, (rct_sprite *) dst); + invalidate_sprite_2((rct_sprite *) dst); + } + } + } + + void ImportMoneyEffect(rct_money_effect * dst, rct_money_effect * src) + { + dst->move_delay = src->move_delay; + dst->num_movements = src->num_movements; + dst->value = src->value; + dst->offset_x = dst->offset_x; + dst->wiggle = src->wiggle; + } + + void ImportSteamParticle(rct_steam_particle * dst, rct_steam_particle * src) + { + dst->frame = src->frame; + } + + void ImportJumpingFountainWater(rct_jumping_fountain * dst, rct_jumping_fountain * src) + { + dst->fountain_flags = src->fountain_flags; + dst->iteration = src->iteration; + dst->var_26a = src->var_26a; + dst->var_26b = src->var_26b; + } + + void ImportBalloon(rct_balloon * dst, rct_balloon * src) + { + // Balloons were always blue in RCT1 without AA/LL + if (_gameVersion == FILE_VERSION_RCT1) + { + dst->colour = COLOUR_LIGHT_BLUE; + } + else + { + dst->colour = RCT1::GetColour(src->colour); + } + } + + void ImportDuck(rct_duck * dst, rct_duck * src) + { + dst->frame = src->frame; + dst->state = src->state; + } + void ImportPeepSpawns() { for (int i = 0; i < 2; i++) @@ -1076,7 +1230,7 @@ private: void ImportMapElements() { - memcpy(gMapElements, _s4.map_elements, 0xC000 * sizeof(rct_map_element)); + memcpy(gMapElements, _s4.map_elements, RCT1_MAX_MAP_ELEMENTS * sizeof(rct_map_element)); ClearExtraTileEntries(); FixColours(); FixZ();