diff --git a/openrct2.vcxproj.user b/openrct2.vcxproj.user index fd6680fbf4..6df380b165 100644 --- a/openrct2.vcxproj.user +++ b/openrct2.vcxproj.user @@ -14,8 +14,7 @@ $(TargetDir) WindowsLocalDebugger $(TargetDir)\openrct2.exe - - + C:\Users\Ted\Desktop\rct1ll\Scenarios\sc1.sc4 $(TargetDir) diff --git a/src/rct1.c b/src/rct1.c index cb2db19731..db837e5aaa 100644 --- a/src/rct1.c +++ b/src/rct1.c @@ -1828,3 +1828,322 @@ bool rideTypeShouldLoseSeparateFlag(rct_ride_entry *ride) } #pragma endregion + +#pragma region RCT1 Scenario / Saved Game Import + +#include "audio/audio.h" +#include "localisation/date.h" +#include "peep/staff.h" + +static void rct1_import_s4_properly(rct1_s4 *s4); + +static const uint8 RCT1RideTypeConversionTable[] = { + RIDE_TYPE_WOODEN_ROLLER_COASTER, + RIDE_TYPE_STAND_UP_ROLLER_COASTER, + RIDE_TYPE_SUSPENDED_SWINGING_COASTER, + RIDE_TYPE_INVERTED_ROLLER_COASTER, + RIDE_TYPE_JUNIOR_ROLLER_COASTER, + RIDE_TYPE_MINIATURE_RAILWAY, + RIDE_TYPE_MONORAIL, + RIDE_TYPE_MINI_SUSPENDED_COASTER, + RIDE_TYPE_BOAT_RIDE, + RIDE_TYPE_WOODEN_WILD_MOUSE, + RIDE_TYPE_STEEPLECHASE, + RIDE_TYPE_CAR_RIDE, + RIDE_TYPE_LAUNCHED_FREEFALL, + RIDE_TYPE_BOBSLEIGH_COASTER, + RIDE_TYPE_OBSERVATION_TOWER, + RIDE_TYPE_LOOPING_ROLLER_COASTER, + RIDE_TYPE_DINGHY_SLIDE, + RIDE_TYPE_MINE_TRAIN_COASTER, + RIDE_TYPE_CHAIRLIFT, + RIDE_TYPE_CORKSCREW_ROLLER_COASTER, + RIDE_TYPE_MAZE, + RIDE_TYPE_SPIRAL_ROLLER_COASTER, + RIDE_TYPE_GO_KARTS, + RIDE_TYPE_LOG_FLUME, + RIDE_TYPE_RIVER_RAPIDS, + RIDE_TYPE_DODGEMS, + RIDE_TYPE_PIRATE_SHIP, + RIDE_TYPE_SWINGING_INVERTER_SHIP, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_DRINK_STALL, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_SHOP, + RIDE_TYPE_MERRY_GO_ROUND, + RIDE_TYPE_SHOP, + RIDE_TYPE_INFORMATION_KIOSK, + RIDE_TYPE_TOILETS, + RIDE_TYPE_FERRIS_WHEEL, + RIDE_TYPE_MOTION_SIMULATOR, + RIDE_TYPE_3D_CINEMA, + RIDE_TYPE_TOP_SPIN, + RIDE_TYPE_SPACE_RINGS, + RIDE_TYPE_REVERSE_FREEFALL_COASTER, + RIDE_TYPE_SHOP, + RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_TWIST, + RIDE_TYPE_HAUNTED_HOUSE, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_CIRCUS_SHOW, + RIDE_TYPE_GHOST_TRAIN, + RIDE_TYPE_TWISTER_ROLLER_COASTER, + RIDE_TYPE_WOODEN_ROLLER_COASTER, + RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER, + RIDE_TYPE_WILD_MOUSE, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_SHOP, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_VIRGINIA_REEL, + RIDE_TYPE_SPLASH_BOATS, + RIDE_TYPE_MINI_HELICOPTERS, + RIDE_TYPE_LAY_DOWN_ROLLER_COASTER, + RIDE_TYPE_SUSPENDED_MONORAIL, + RIDE_TYPE_NULL, + RIDE_TYPE_REVERSER_ROLLER_COASTER, + RIDE_TYPE_HEARTLINE_TWISTER_COASTER, + RIDE_TYPE_MINI_GOLF, + RIDE_TYPE_NULL, + RIDE_TYPE_ROTO_DROP, + RIDE_TYPE_FLYING_SAUCERS, + RIDE_TYPE_CROOKED_HOUSE, + RIDE_TYPE_MONORAIL_CYCLES, + RIDE_TYPE_COMPACT_INVERTED_COASTER, + RIDE_TYPE_WATER_COASTER, + RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER, + RIDE_TYPE_INVERTED_HAIRPIN_COASTER, + RIDE_TYPE_BOAT_RIDE, + RIDE_TYPE_SHOP, + RIDE_TYPE_RIVER_RAFTS, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_ENTERPRISE, + RIDE_TYPE_DRINK_STALL, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_DRINK_STALL +}; + +// rct2: 0x0097F0BC +static const uint8 RCT1ColourConversionTable[] = { + 0, 1, 2, 4, 5, 6, 7, 9, + 11, 12, 13, 14, 15, 16, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 30, 31, 29, 3, 10, 17, 8 +}; + +bool rct1_load_saved_game(const char *path) +{ + rct1_s4 *s4; + + s4 = malloc(sizeof(rct1_s4)); + if (!rct1_read_sv4(path, s4)) { + free(s4); + return false; + } + rct1_import_s4_properly(s4); + free(s4); + return true; +} + +bool rct1_load_scenario(const char *path) +{ + rct1_s4 *s4; + + s4 = malloc(sizeof(rct1_s4)); + if (!rct1_read_sc4(path, s4)) { + free(s4); + return false; + } + rct1_import_s4_properly(s4); + free(s4); + + scenario_begin(); + return true; +} + +static void rct1_import_map_elements(rct1_s4 *s4) +{ + memcpy(gMapElements, s4->map_elements, 0xC000 * sizeof(rct_map_element)); + rct1_clear_extra_tile_entries(); + // sub_69F143(); + rct1_fix_z(); + sub_69F3AB(); + sub_6A2730(); + rct1_fix_scenery(); + rct1_fix_terrain(); + rct1_fix_entrance_positions(); + + rct_map_element *mapElement; + for (int y = 0; y < 256; y++) { + for (int x = 0; x < 256; x++) { + restartTile: + mapElement = map_get_first_element_at(x, y); + do { + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_TRACK: + x = x; + // map_element_remove(mapElement); + // goto restartTile; + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + // if (mapElement->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) { + // map_element_remove(mapElement); + // goto restartTile; + // } + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + } + } +} + +static void rct1_import_ride(rct1_s4 *s4, rct_ride *dst, rct1_ride *src) +{ + memset(dst, 0, sizeof(rct_ride)); + + dst->type = RCT1RideTypeConversionTable[src->type]; + dst->subtype = src->type; + + // Ride name + dst->name = 0; + if (is_user_string_id(src->name)) { + const char *rideName = s4->string_table[(src->name - 0x8000) % 1024]; + if (rideName[0] != 0) { + rct_string_id rideNameStringId = user_string_allocate(4, rideName); + if (rideNameStringId != 0) { + dst->name = rideNameStringId; + } + } + } + if (dst->name == 0) { + dst->name = 1; + + uint16 *args = (uint16*)&dst->name_arguments; + args[0] = 2 + dst->type; + args[1] = src->name_argument_number; + } + + // + dst->status = RIDE_STATUS_CLOSED; + + // Station + dst->overall_view = src->overall_view; + for (int i = 0; i < 4; i++) { + dst->station_starts[i] = src->station_starts[i]; + dst->station_heights[i] = src->station_height[i]; + dst->station_length[i] = src->station_length[i]; + dst->station_depart[i] = src->station_depart[i]; + dst->entrances[i] = src->entrance[i]; + dst->exits[i] = src->exit[i]; + } + + // Operation + dst->mode = src->operating_mode; + dst->depart_flags = src->depart_flags; + dst->min_waiting_time = src->min_waiting_time; + dst->max_waiting_time = src->max_waiting_time; + dst->operation_option = src->operation_option; + dst->music = src->music; + + // Colours + dst->colour_scheme_type = src->colour_scheme; + if (s4->game_version == 108166) { + dst->track_colour_main[0] = RCT1ColourConversionTable[src->track_primary_colour]; + dst->track_colour_additional[0] = RCT1ColourConversionTable[src->track_secondary_colour]; + dst->track_colour_supports[0] = RCT1ColourConversionTable[src->track_support_colour]; + } else { + for (int i = 0; i < 4; i++) { + dst->track_colour_main[i] = RCT1ColourConversionTable[src->track_colour_main[i]]; + dst->track_colour_additional[i] = RCT1ColourConversionTable[src->track_colour_additional[i]]; + dst->track_colour_supports[i] = RCT1ColourConversionTable[src->track_colour_supports[i]]; + } + } + + // Maintenance + dst->inspection_interval = src->inspection_interval; + dst->last_inspection = src->last_inspection; + dst->reliability = src->reliability; + dst->unreliability_factor = src->unreliability_factor; + dst->breakdown_reason = src->breakdown_reason; + + // Finance + dst->price = src->price; +} + +static void rct1_import_s4_properly(rct1_s4 *s4) +{ + int mapSize = s4->map_size == 0 ? 128 : s4->map_size; + + pause_sounds(); + unpause_sounds(); + object_unload_all(); + map_init(mapSize); + banner_init(); + reset_park_entrances(); + user_string_clear_all(); + reset_sprite_list(); + ride_init_all(); + window_guest_list_init_vars_a(); + staff_reset_modes(); + park_init(); + finance_init(); + date_reset(); + window_guest_list_init_vars_b(); + window_staff_list_init_vars(); + RCT2_GLOBAL(0x0141F570, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; + window_new_ride_init_vars(); + RCT2_GLOBAL(0x0141F571, uint8) = 4; + news_item_init_queue(); + + rct_string_id stringId; + + rct1_load_default_objects(); + reset_loaded_objects(); + + for (int i = 0; i < MAX_RIDES; i++) { + if (s4->rides[i].type != RIDE_TYPE_NULL) { + rct1_import_ride(s4, GET_RIDE(i), &s4->rides[i]); + } + } + + // Map elements + rct1_import_map_elements(s4); + + // Finance + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, uint32) = ENCRYPT_MONEY(s4->cash); + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) = s4->park_entrance_fee; + + // Park name + const char *parkName = s4->scenario_name; + if (is_user_string_id((rct_string_id)s4->park_name_string_index)) { + const char *userString = s4->string_table[(s4->park_name_string_index - 0x8000) % 1024]; + if (userString[0] != 0) { + parkName = userString; + } + } + stringId = user_string_allocate(4, parkName); + if (stringId != 0) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id) = stringId; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32) = 0; + } + + // Scenario name + strcpy((char*)RCT2_ADDRESS_SCENARIO_NAME, s4->scenario_name); + + // Scenario objective + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) = s4->scenario_objective_type; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8) = s4->scenario_objective_years; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, uint32) = s4->scenario_objective_currency; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) = s4->scenario_objective_num_guests; + + // Restore view + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, uint16) = s4->view_x; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, uint16) = s4->view_y; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint8) = s4->view_zoom; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION + 1, uint8) = s4->view_rotation; +} + +#pragma endregion diff --git a/src/rct1.h b/src/rct1.h index 0307647a52..b28721fe74 100644 --- a/src/rct1.h +++ b/src/rct1.h @@ -511,4 +511,7 @@ void rct1_fix_landscape(); bool vehicleIsHigherInHierarchy(int track_type, char *currentVehicleName, char *comparedVehicleName); bool rideTypeShouldLoseSeparateFlag(rct_ride_entry *ride); +bool rct1_load_saved_game(const char *path); +bool rct1_load_scenario(const char *path); + #endif diff --git a/src/rct2.c b/src/rct2.c index e862f2d89a..3a03265152 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -365,10 +365,12 @@ bool rct2_open_file(const char *path) scenario_load_and_play_from_path(scenarioBasic.path); return true; } else if (_stricmp(extension, "td6") == 0 || _stricmp(extension, "td4") == 0) { - return true; - } else if (!_stricmp(extension, "td6") || !_stricmp(extension, "td4")) { // TODO track design install return true; + } else if (_stricmp(extension, "sv4") == 0) { + rct1_load_saved_game(path); + } else if (_stricmp(extension, "sc4") == 0) { + rct1_load_scenario(path); } return false;