diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 38c40b2b71..558c86d748 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -4216,6 +4216,9 @@ STR_5904 :Reset date STR_5905 :{SMALLFONT}{BLACK}A map generation tool that automatically creates a custom landscape STR_5906 :Zoom to cursor position STR_5907 :{SMALLFONT}{BLACK}When enabled, zooming in will centre around the cursor, as opposed to the screen centre. +STR_5908 :Allow arbitrary ride type changes +STR_5909 :{SMALLFONT}{BLACK}Allows changing ride type freely. May cause crashes. +STR_5910 :Apply ############# # Scenarios # diff --git a/src/cheats.c b/src/cheats.c index 1d4e6db53d..821577692c 100644 --- a/src/cheats.c +++ b/src/cheats.c @@ -43,6 +43,7 @@ bool gCheatsFreezeClimate = false; bool gCheatsDisableTrainLengthLimit = false; bool gCheatsDisablePlantAging = false; bool gCheatsEnableChainLiftOnAllTrack = false; +bool gCheatsAllowArbitraryRideTypeChanges = false; int park_rating_spinner_value; @@ -416,6 +417,7 @@ void game_command_cheat(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* e case CHEAT_HAVEFUN: gScenarioObjectiveType = OBJECTIVE_HAVE_FUN; break; case CHEAT_SETFORCEDPARKRATING: if(*edx > -1) { park_rating_spinner_value = *edx; } set_forced_park_rating(*edx); break; case CHEAT_RESETDATE: date_reset(); window_invalidate_by_class(WC_BOTTOM_TOOLBAR); break; + case CHEAT_ALLOW_ARBITRARY_RIDE_TYPE_CHANGES: gCheatsAllowArbitraryRideTypeChanges = !gCheatsAllowArbitraryRideTypeChanges; window_invalidate_by_class(WC_RIDE); break; } if (network_get_mode() == NETWORK_MODE_NONE) { config_save_default(); @@ -445,4 +447,5 @@ void cheats_reset() gCheatsNeverendingMarketing = false; gCheatsFreezeClimate = false; gCheatsDisablePlantAging = false; + gCheatsAllowArbitraryRideTypeChanges = false; } diff --git a/src/cheats.h b/src/cheats.h index 7e4579e03c..64a90906be 100644 --- a/src/cheats.h +++ b/src/cheats.h @@ -37,6 +37,7 @@ extern bool gCheatsFreezeClimate; extern bool gCheatsDisableTrainLengthLimit; extern bool gCheatsDisablePlantAging; extern bool gCheatsEnableChainLiftOnAllTrack; +extern bool gCheatsAllowArbitraryRideTypeChanges; enum { @@ -81,6 +82,7 @@ enum { CHEAT_SETFORCEDPARKRATING, CHEAT_NEVERENDINGMARKETING, CHEAT_RESETDATE, + CHEAT_ALLOW_ARBITRARY_RIDE_TYPE_CHANGES, }; enum { diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index d0613e4dfa..b0cfd4226b 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -3339,7 +3339,10 @@ enum { STR_MAP_GENERATOR_TIP = 5905, STR_ZOOM_TO_CURSOR = 5906, STR_ZOOM_TO_CURSOR_TIP = 5907, - + STR_CHEAT_ALLOW_ARBITRARY_RIDE_TYPE_CHANGES = 5908, + STR_CHEAT_ALLOW_ARBITRARY_RIDE_TYPE_CHANGES_TIP = 5909, + STR_APPLY = 5910, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working STR_COUNT = 32768 }; diff --git a/src/network/network.h b/src/network/network.h index bba5e39e1d..c96ee3773c 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -55,7 +55,7 @@ extern "C" { // This define specifies which version of network stream current build uses. // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -#define NETWORK_STREAM_VERSION "11" +#define NETWORK_STREAM_VERSION "12" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION #ifdef __cplusplus diff --git a/src/rct2/S6Exporter.cpp b/src/rct2/S6Exporter.cpp index 14622255bd..adc4bc1c77 100644 --- a/src/rct2/S6Exporter.cpp +++ b/src/rct2/S6Exporter.cpp @@ -565,6 +565,7 @@ extern "C" SDL_WriteU8(rw, gCheatsNeverendingMarketing); SDL_WriteU8(rw, gCheatsFreezeClimate); SDL_WriteU8(rw, gCheatsDisablePlantAging); + SDL_WriteU8(rw, gCheatsAllowArbitraryRideTypeChanges); gfx_invalidate_screen(); return 1; diff --git a/src/rct2/S6Importer.cpp b/src/rct2/S6Importer.cpp index b0dacb2b3f..6a4c2af15f 100644 --- a/src/rct2/S6Importer.cpp +++ b/src/rct2/S6Importer.cpp @@ -512,6 +512,7 @@ extern "C" gCheatsNeverendingMarketing = SDL_ReadU8(rw) != 0; gCheatsFreezeClimate = SDL_ReadU8(rw) != 0; gCheatsDisablePlantAging = SDL_ReadU8(rw) != 0; + gCheatsAllowArbitraryRideTypeChanges = SDL_ReadU8(rw) != 0; gLastAutoSaveTick = SDL_GetTicks(); return 1; diff --git a/src/ride/ride.c b/src/ride/ride.c index bb9ef53a67..7ddbed6d0d 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -3916,6 +3916,14 @@ static money32 ride_set_setting(uint8 rideIndex, uint8 setting, uint8 value, uin } } break; + case RIDE_SETTING_RIDE_TYPE: + if (!gCheatsAllowArbitraryRideTypeChanges) { + return MONEY32_UNDEFINED; + } + if (flags & GAME_COMMAND_FLAG_APPLY) { + ride->type = value; + } + break; } if (flags & GAME_COMMAND_FLAG_APPLY) { diff --git a/src/ride/ride.h b/src/ride/ride.h index 8cfa2cec45..8f069fc633 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -880,6 +880,7 @@ enum { RIDE_SETTING_MUSIC_TYPE, RIDE_SETTING_LIFT_HILL_SPEED, RIDE_SETTING_NUM_CIRCUITS, + RIDE_SETTING_RIDE_TYPE, }; #define MAX_RIDES 255 diff --git a/src/windows/cheats.c b/src/windows/cheats.c index a137ed14b4..a95e7b8f30 100644 --- a/src/windows/cheats.c +++ b/src/windows/cheats.c @@ -130,7 +130,8 @@ enum WINDOW_CHEATS_WIDGET_IDX { WIDX_SHOW_ALL_OPERATING_MODES, WIDX_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES, WIDX_DISABLE_TRAIN_LENGTH_LIMITS, - WIDX_ENABLE_CHAIN_LIFT_ON_ALL_TRACK + WIDX_ENABLE_CHAIN_LIFT_ON_ALL_TRACK, + WIDX_ENABLE_ARBITRARY_RIDE_TYPE_CHANGES, }; #pragma region MEASUREMENTS @@ -259,6 +260,7 @@ static rct_widget window_cheats_rides_widgets[] = { { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(6), OHPL(6), STR_CHEAT_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES, STR_NONE }, // Show vehicles from other track types { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(12), OHPL(12), STR_CHEAT_DISABLE_TRAIN_LENGTH_LIMIT, STR_CHEAT_DISABLE_TRAIN_LENGTH_LIMIT_TIP }, // Disable train length limits { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(13), OHPL(13), STR_CHEAT_ENABLE_CHAIN_LIFT_ON_ALL_TRACK, STR_CHEAT_ENABLE_CHAIN_LIFT_ON_ALL_TRACK_TIP }, // Enable chain lift on all track + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(14), OHPL(14), STR_CHEAT_ALLOW_ARBITRARY_RIDE_TYPE_CHANGES, STR_CHEAT_ALLOW_ARBITRARY_RIDE_TYPE_CHANGES_TIP }, // Allow arbitrary ride type changes { WIDGETS_END }, }; @@ -430,7 +432,8 @@ static uint64 window_cheats_page_enabled_widgets[] = { (1ULL << WIDX_CLOSE) | (1ULL << WIDX_TAB_1) | (1ULL << WIDX_TAB_2) | (1ULL << WIDX_TAB_3) | (1ULL << WIDX_TAB_4) | (1ULL << WIDX_RENEW_RIDES) | (1ULL << WIDX_MAKE_DESTRUCTIBLE) | (1ULL << WIDX_FIX_ALL) | (1ULL << WIDX_FAST_LIFT_HILL) | (1ULL << WIDX_DISABLE_BRAKES_FAILURE) | (1ULL << WIDX_DISABLE_ALL_BREAKDOWNS) | (1ULL << WIDX_BUILD_IN_PAUSE_MODE) | (1ULL << WIDX_RESET_CRASH_STATUS) | (1ULL << WIDX_10_MINUTE_INSPECTIONS) | - (1ULL << WIDX_SHOW_ALL_OPERATING_MODES) | (1ULL << WIDX_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES) | (1ULL << WIDX_DISABLE_TRAIN_LENGTH_LIMITS) | (1ULL << WIDX_ENABLE_CHAIN_LIFT_ON_ALL_TRACK) + (1ULL << WIDX_SHOW_ALL_OPERATING_MODES) | (1ULL << WIDX_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES) | (1ULL << WIDX_DISABLE_TRAIN_LENGTH_LIMITS) | + (1ULL << WIDX_ENABLE_CHAIN_LIFT_ON_ALL_TRACK) | (1ULL << WIDX_ENABLE_ARBITRARY_RIDE_TYPE_CHANGES) }; static rct_string_id window_cheats_page_titles[] = { @@ -758,6 +761,12 @@ static void window_cheats_rides_mouseup(rct_window *w, int widgetIndex) case WIDX_ENABLE_CHAIN_LIFT_ON_ALL_TRACK: game_do_command(0, GAME_COMMAND_FLAG_APPLY, CHEAT_ENABLECHAINLIFTONALLTRACK, 0, GAME_COMMAND_CHEAT, 0, 0); break; + case WIDX_ENABLE_ARBITRARY_RIDE_TYPE_CHANGES: + game_do_command(0, GAME_COMMAND_FLAG_APPLY, CHEAT_ALLOW_ARBITRARY_RIDE_TYPE_CHANGES, 0, GAME_COMMAND_CHEAT, 0, 0); + if (gCheatsAllowArbitraryRideTypeChanges) { + window_error_open(STR_WARNING_IN_CAPS, STR_THIS_FEATURE_IS_CURRENTLY_UNSTABLE); + } + break; } } @@ -830,6 +839,7 @@ static void window_cheats_invalidate(rct_window *w) widget_set_checkbox_value(w, WIDX_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES, gCheatsShowVehiclesFromOtherTrackTypes); widget_set_checkbox_value(w, WIDX_DISABLE_TRAIN_LENGTH_LIMITS, gCheatsDisableTrainLengthLimit); widget_set_checkbox_value(w, WIDX_ENABLE_CHAIN_LIFT_ON_ALL_TRACK, gCheatsEnableChainLiftOnAllTrack); + widget_set_checkbox_value(w, WIDX_ENABLE_ARBITRARY_RIDE_TYPE_CHANGES, gCheatsAllowArbitraryRideTypeChanges); break; } diff --git a/src/windows/ride.c b/src/windows/ride.c index de572b3248..23356b52e7 100644 --- a/src/windows/ride.c +++ b/src/windows/ride.c @@ -86,6 +86,10 @@ enum { WIDX_CLOSE_LIGHT, WIDX_TEST_LIGHT, WIDX_OPEN_LIGHT, + WIDX_RIDE_TYPE, + WIDX_RIDE_TYPE_INCREASE, + WIDX_RIDE_TYPE_DECREASE, + WIDX_RIDE_TYPE_APPLY, WIDX_VEHICLE_TYPE = 14, WIDX_VEHICLE_TYPE_DROPDOWN, @@ -214,6 +218,13 @@ static rct_widget window_ride_main_widgets[] = { { WWT_IMGBTN, 1, 296, 309, 48, 61, SPR_G2_RCT1_CLOSE_BUTTON_0, STR_CLOSE_RIDE_TIP }, { WWT_IMGBTN, 1, 296, 309, 62, 75, SPR_G2_RCT1_TEST_BUTTON_0, STR_TEST_RIDE_TIP }, { WWT_IMGBTN, 1, 296, 309, 76, 89, SPR_G2_RCT1_OPEN_BUTTON_0, STR_OPEN_RIDE_TIP }, + + // Ride type spinner + apply button + { WWT_SPINNER, 1, 7, 260, 180, 191, STR_ARG_6_STRINGID, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 249, 259, 181, 185, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 249, 259, 186, 190, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_CLOSEBOX, 1, 265, 307, 180, 191, STR_APPLY, STR_NONE }, + { WIDGETS_END }, }; @@ -243,6 +254,7 @@ static rct_widget window_ride_vehicle_widgets[] = { { WWT_SPINNER, 1, 164, 308, 190, 201, STR_1_CAR_PER_TRAIN, STR_NONE }, { WWT_DROPDOWN_BUTTON, 1, 297, 307, 191, 195, STR_NUMERIC_UP, STR_NONE }, { WWT_DROPDOWN_BUTTON, 1, 297, 307, 196, 200, STR_NUMERIC_DOWN, STR_NONE }, + { WIDGETS_END }, }; @@ -497,7 +509,7 @@ static rct_widget *window_ride_page_widgets[] = { }; const uint64 window_ride_page_enabled_widgets[] = { - 0x0000000003FDBFF4, + 0x000000003FFDBFF4, 0x00000000007EFFF4, 0x0000019E777DBFF4, 0x000000000003FFF4, @@ -955,6 +967,10 @@ static rct_window_event_list *window_ride_page_events[] = { #pragma endregion +static uint8 _rideType; + +static void set_operating_setting(int rideNumber, uint8 setting, uint8 value); + // Cached overall view for each ride // (Re)calculated when the ride window is opened typedef struct ride_overall_view_t { @@ -1539,6 +1555,7 @@ static rct_window *window_ride_open(int rideIndex) } } var_496(w) = numSubTypes; + _rideType = ride->type; return w; } @@ -1631,6 +1648,7 @@ rct_window *window_ride_open_station(int rideIndex, int stationIndex) w->ride.view = 1 + ride->num_vehicles + stationIndex; window_ride_init_viewport(w); + _rideType = ride->type; return w; } @@ -1734,6 +1752,7 @@ rct_window *window_ride_open_vehicle(rct_vehicle *vehicle) w->ride.view = view; window_ride_init_viewport(w); + _rideType = ride->type; window_invalidate(w); return w; @@ -2025,15 +2044,15 @@ static void window_ride_main_resize(rct_window *w) int width, height; w->flags |= WF_RESIZABLE; - int minHeight = 180; + int minHeight = 195; if (theme_get_flags() & UITHEME_FLAG_USE_LIGHTS_RIDE) - minHeight = 200 + RCT1_LIGHT_OFFSET - (ride_type_has_flag(get_ride(w->number)->type, RIDE_TYPE_FLAG_NO_TEST_MODE) ? 14 : 0); + minHeight = 215 + RCT1_LIGHT_OFFSET - (ride_type_has_flag(get_ride(w->number)->type, RIDE_TYPE_FLAG_NO_TEST_MODE) ? 14 : 0); window_set_resize(w, 316, minHeight, 500, 450); viewport = w->viewport; if (viewport != NULL) { width = w->width - 30; - height = w->height - 75; + height = w->height - 90; if (viewport->width != width || viewport->height != height) { viewport->width = width; viewport->height = height; @@ -2190,6 +2209,7 @@ static void window_ride_show_open_dropdown(rct_window *w, rct_widget *widget) */ static void window_ride_main_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) { + rct_ride *ride = get_ride(w->number); switch (widgetIndex) { case WIDX_VIEW_DROPDOWN: window_ride_show_view_dropdown(w, widget); @@ -2197,6 +2217,25 @@ static void window_ride_main_mousedown(int widgetIndex, rct_window *w, rct_widge case WIDX_OPEN: window_ride_show_open_dropdown(w, widget); break; + case WIDX_RIDE_TYPE_INCREASE: + if (_rideType >= 90) { + _rideType = 90; + } else { + _rideType++; + } + break; + case WIDX_RIDE_TYPE_DECREASE: + if (_rideType == 0) { + _rideType = 0; + } else { + _rideType--; + } + break; + case WIDX_RIDE_TYPE_APPLY: + if (_rideType >= 0 && _rideType <= 90) { + set_operating_setting(w->number, RIDE_SETTING_RIDE_TYPE, _rideType); + } + break; } } @@ -2347,6 +2386,7 @@ static void window_ride_main_invalidate(rct_window *w) set_format_arg(0, uint16, ride->name); set_format_arg(2, uint32, ride->name_arguments); + set_format_arg(6, uint16, _rideType + STR_RIDE_NAME_SPIRAL_ROLLER_COASTER); uint32 spriteIds[] = { SPR_CLOSED, SPR_OPEN, @@ -2362,13 +2402,40 @@ static void window_ride_main_invalidate(rct_window *w) // Anchor main page specific widgets window_ride_main_widgets[WIDX_VIEWPORT].right = w->width - 26; - window_ride_main_widgets[WIDX_VIEWPORT].bottom = w->height - 14; + window_ride_main_widgets[WIDX_VIEWPORT].bottom = w->height - 129; window_ride_main_widgets[WIDX_STATUS].right = w->width - 26; - window_ride_main_widgets[WIDX_STATUS].top = w->height - 13; - window_ride_main_widgets[WIDX_STATUS].bottom = w->height - 3; + window_ride_main_widgets[WIDX_STATUS].top = w->height - 28; + window_ride_main_widgets[WIDX_STATUS].bottom = w->height - 18; window_ride_main_widgets[WIDX_VIEW].right = w->width - 60; window_ride_main_widgets[WIDX_VIEW_DROPDOWN].right = w->width - 61; window_ride_main_widgets[WIDX_VIEW_DROPDOWN].left = w->width - 71; + window_ride_main_widgets[WIDX_RIDE_TYPE].right = w->width - 80; + window_ride_main_widgets[WIDX_RIDE_TYPE].top = w->height - 15; + window_ride_main_widgets[WIDX_RIDE_TYPE].bottom = w->height - 3; + window_ride_main_widgets[WIDX_RIDE_TYPE_INCREASE].right = w->width - 81; + window_ride_main_widgets[WIDX_RIDE_TYPE_INCREASE].left = w->width - 91; + window_ride_main_widgets[WIDX_RIDE_TYPE_INCREASE].top = w->height - 14; + window_ride_main_widgets[WIDX_RIDE_TYPE_INCREASE].bottom = w->height - 9; + window_ride_main_widgets[WIDX_RIDE_TYPE_DECREASE].right = w->width - 81; + window_ride_main_widgets[WIDX_RIDE_TYPE_DECREASE].left = w->width - 91; + window_ride_main_widgets[WIDX_RIDE_TYPE_DECREASE].top = w->height - 8; + window_ride_main_widgets[WIDX_RIDE_TYPE_DECREASE].bottom = w->height - 3; + window_ride_main_widgets[WIDX_RIDE_TYPE_APPLY].left = w->width - 78; + window_ride_main_widgets[WIDX_RIDE_TYPE_APPLY].right = w->width - 25; + window_ride_main_widgets[WIDX_RIDE_TYPE_APPLY].top = w->height - 15; + window_ride_main_widgets[WIDX_RIDE_TYPE_APPLY].bottom = w->height - 3; + + if (!gCheatsAllowArbitraryRideTypeChanges) { + window_ride_main_widgets[WIDX_RIDE_TYPE].type = WWT_14; + window_ride_main_widgets[WIDX_RIDE_TYPE_INCREASE].type = WWT_EMPTY; + window_ride_main_widgets[WIDX_RIDE_TYPE_DECREASE].type = WWT_EMPTY; + window_ride_main_widgets[WIDX_RIDE_TYPE_APPLY].type = WWT_EMPTY; + } else { + window_ride_main_widgets[WIDX_RIDE_TYPE].type = WWT_SPINNER; + window_ride_main_widgets[WIDX_RIDE_TYPE_INCREASE].type = WWT_DROPDOWN_BUTTON; + window_ride_main_widgets[WIDX_RIDE_TYPE_DECREASE].type = WWT_DROPDOWN_BUTTON; + window_ride_main_widgets[WIDX_RIDE_TYPE_APPLY].type = WWT_CLOSEBOX; + } window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10);