diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 9ee540d706..0ffd1578de 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,5 +1,6 @@ 0.1.3 (in development) ------------------------------------------------------------------------ +- Feature: [#1417] Allow saving track designs for flat rides. - Feature: [#1675] Auto-rotate shops to face footpaths. - Feature: [#6510] Ability to select edges or a row of tiles by holding down Ctrl using the land tool. - Feature: [#7187] Option for early scenario completion. diff --git a/src/openrct2-ui/windows/NewRide.cpp b/src/openrct2-ui/windows/NewRide.cpp index b080505abd..b37b7af89b 100644 --- a/src/openrct2-ui/windows/NewRide.cpp +++ b/src/openrct2-ui/windows/NewRide.cpp @@ -958,43 +958,39 @@ static void window_new_ride_paint_ride_information(rct_window *w, rct_drawpixeli set_format_arg(2, rct_string_id, rideNaming.description); gfx_draw_string_left_wrapped(dpi, gCommonFormatArgs, x, y, width, STR_NEW_RIDE_NAME_AND_DESCRIPTION, COLOUR_BLACK); - // Number of designs available - if (ride_type_has_flag(item.type, RIDE_TYPE_FLAG_HAS_TRACK)) + char availabilityString[AVAILABILITY_STRING_SIZE]; + window_new_ride_list_vehicles_for(item.type, rideEntry, availabilityString); + + if (availabilityString[0] != 0) { - char availabilityString[AVAILABILITY_STRING_SIZE]; - window_new_ride_list_vehicles_for(item.type, rideEntry, availabilityString); - - if (availabilityString[0] != 0) - { - const char * drawString = availabilityString; - gfx_draw_string_left_clipped(dpi, STR_AVAILABLE_VEHICLES, &drawString, COLOUR_BLACK, x, y + 39, WW - 2); - } - - // Track designs are disabled in multiplayer, so don't say there are any designs available when in multiplayer - if (network_get_mode() != NETWORK_MODE_NONE) { - _lastTrackDesignCount = 0; - } - else if (item.type != _lastTrackDesignCountRideType.type || item.entry_index != _lastTrackDesignCountRideType.entry_index) { - _lastTrackDesignCountRideType = item; - _lastTrackDesignCount = get_num_track_designs(item); - } - - rct_string_id stringId; - switch (_lastTrackDesignCount) { - case 0: - stringId = STR_CUSTOM_DESIGNED_LAYOUT; - break; - case 1: - stringId = STR_1_DESIGN_AVAILABLE; - break; - default: - stringId = STR_X_DESIGNS_AVAILABLE; - break; - } - - gfx_draw_string_left(dpi, stringId, &_lastTrackDesignCount, COLOUR_BLACK, x, y + 51); + const char * drawString = availabilityString; + gfx_draw_string_left_clipped(dpi, STR_AVAILABLE_VEHICLES, &drawString, COLOUR_BLACK, x, y + 39, WW - 2); } + // Track designs are disabled in multiplayer, so don't say there are any designs available when in multiplayer + if (network_get_mode() != NETWORK_MODE_NONE) { + _lastTrackDesignCount = 0; + } + else if (item.type != _lastTrackDesignCountRideType.type || item.entry_index != _lastTrackDesignCountRideType.entry_index) { + _lastTrackDesignCountRideType = item; + _lastTrackDesignCount = get_num_track_designs(item); + } + + rct_string_id designCountStringId; + switch (_lastTrackDesignCount) { + case 0: + designCountStringId = STR_CUSTOM_DESIGNED_LAYOUT; + break; + case 1: + designCountStringId = STR_1_DESIGN_AVAILABLE; + break; + default: + designCountStringId = STR_X_DESIGNS_AVAILABLE; + break; + } + + gfx_draw_string_left(dpi, designCountStringId, &_lastTrackDesignCount, COLOUR_BLACK, x, y + 51); + // Price if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) { // Get price of ride @@ -1039,14 +1035,13 @@ static void window_new_ride_select(rct_window *w) } #endif - if (allowTrackDesigns && ride_type_has_flag(item.type, RIDE_TYPE_FLAG_HAS_TRACK)) { - if (_lastTrackDesignCount > 0) { - auto intent = Intent(WC_TRACK_DESIGN_LIST); - intent.putExtra(INTENT_EXTRA_RIDE_TYPE, item.type); - intent.putExtra(INTENT_EXTRA_RIDE_ENTRY_INDEX, item.entry_index); - context_open_intent(&intent); - return; - } + if (allowTrackDesigns && _lastTrackDesignCount > 0) + { + auto intent = Intent(WC_TRACK_DESIGN_LIST); + intent.putExtra(INTENT_EXTRA_RIDE_TYPE, item.type); + intent.putExtra(INTENT_EXTRA_RIDE_ENTRY_INDEX, item.entry_index); + context_open_intent(&intent); + return; } ride_construct_new(item); diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp index 0f0b65ebbb..12fa8de611 100644 --- a/src/openrct2-ui/windows/Ride.cpp +++ b/src/openrct2-ui/windows/Ride.cpp @@ -5088,6 +5088,8 @@ static void window_ride_measurements_mousedown(rct_window *w, rct_widgetindex wi if (widgetIndex != WIDX_SAVE_TRACK_DESIGN) return; + Ride *ride = get_ride(w->number); + gDropdownItemsFormat[0] = STR_SAVE_TRACK_DESIGN_ITEM; gDropdownItemsFormat[1] = STR_SAVE_TRACK_DESIGN_WITH_SCENERY_ITEM; @@ -5104,6 +5106,11 @@ static void window_ride_measurements_mousedown(rct_window *w, rct_widgetindex wi { dropdown_set_disabled(1, true); } + else if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) + { + // Disable saving without scenery if we're a flat ride + dropdown_set_disabled(0, true); + } } /** @@ -5225,14 +5232,12 @@ static void window_ride_measurements_invalidate(rct_window *w) window_ride_measurements_widgets[WIDX_SAVE_DESIGN].type = WWT_EMPTY; window_ride_measurements_widgets[WIDX_CANCEL_DESIGN].type = WWT_EMPTY; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) { - window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].type = WWT_FLATBTN; - w->disabled_widgets |= (1 << WIDX_SAVE_TRACK_DESIGN); - if (ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED) { - if (ride->excitement != RIDE_RATING_UNDEFINED) { - w->disabled_widgets &= ~(1 << WIDX_SAVE_TRACK_DESIGN); - window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].tooltip = STR_SAVE_TRACK_DESIGN; - } + window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].type = WWT_FLATBTN; + w->disabled_widgets |= (1 << WIDX_SAVE_TRACK_DESIGN); + if (ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED) { + if (ride->excitement != RIDE_RATING_UNDEFINED) { + w->disabled_widgets &= ~(1 << WIDX_SAVE_TRACK_DESIGN); + window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].tooltip = STR_SAVE_TRACK_DESIGN; } } } diff --git a/src/openrct2-ui/windows/TrackDesignPlace.cpp b/src/openrct2-ui/windows/TrackDesignPlace.cpp index 6e8714c861..ac123499e1 100644 --- a/src/openrct2-ui/windows/TrackDesignPlace.cpp +++ b/src/openrct2-ui/windows/TrackDesignPlace.cpp @@ -515,6 +515,9 @@ static void window_track_place_draw_mini_preview_track(rct_track_td6 *td6, sint3 { uint8 rotation = (_currentTrackPieceDirection + get_current_rotation()) & 3; rct_td6_track_element *trackElement = td6->track_elements; + + const rct_preview_track * * trackBlockArray = (ride_type_has_flag(td6->type, RIDE_TYPE_FLAG_HAS_TRACK)) ? TrackBlocks : FlatRideTrackBlocks; + while (trackElement->type != 255) { sint32 trackType = trackElement->type; if (trackType == TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP) { @@ -522,7 +525,7 @@ static void window_track_place_draw_mini_preview_track(rct_track_td6 *td6, sint3 } // Follow a single track piece shape - const rct_preview_track *trackBlock = TrackBlocks[trackType]; + const rct_preview_track *trackBlock = trackBlockArray[trackType]; while (trackBlock->index != 255) { sint16 x = origin.x; sint16 y = origin.y; diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index f6a8bcd964..35802c7ac2 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -34,7 +34,7 @@ // This string 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 "8" +#define NETWORK_STREAM_VERSION "9" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION static rct_peep* _pickup_peep = nullptr; diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index 15a25f6df3..7197e16172 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -32,6 +32,8 @@ #define RCT12_PATROL_AREA_SIZE 128 #define RCT12_STAFF_TYPE_COUNT 4 #define RCT12_NUM_COLOUR_SCHEMES 4 +#define RCT12_MAX_VEHICLES_PER_RIDE 32 +#define RCT12_MAX_VEHICLE_COLOURS 32 #define RCT12_SOUND_ID_NULL 0xFF #define RCT12_EXPENDITURE_TABLE_MONTH_COUNT 16 diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 8ab65f643e..0eb3006313 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -1384,6 +1384,8 @@ static sint32 track_design_place_maze(rct_track_td6 * td6, sint16 x, sint16 y, s static bool track_design_place_ride(rct_track_td6 * td6, sint16 x, sint16 y, sint16 z, uint8 rideIndex) { + const rct_preview_track * * trackBlockArray = (ride_type_has_flag(td6->type, RIDE_TYPE_FLAG_HAS_TRACK)) ? TrackBlocks : FlatRideTrackBlocks; + gTrackPreviewOrigin.x = x; gTrackPreviewOrigin.y = y; gTrackPreviewOrigin.z = z; @@ -1415,7 +1417,7 @@ static bool track_design_place_ride(rct_track_td6 * td6, sint16 x, sint16 y, sin switch (_trackDesignPlaceOperation) { case PTD_OPERATION_DRAW_OUTLINES: - for (const rct_preview_track * trackBlock = TrackBlocks[trackType]; trackBlock->index != 0xFF; trackBlock++) + for (const rct_preview_track * trackBlock = trackBlockArray[trackType]; trackBlock->index != 0xFF; trackBlock++) { LocationXY16 tile = {x, y}; map_offset_with_rotation(&tile.x, &tile.y, trackBlock->x, trackBlock->y, rotation); @@ -1426,7 +1428,7 @@ static bool track_design_place_ride(rct_track_td6 * td6, sint16 x, sint16 y, sin case PTD_OPERATION_CLEAR_OUTLINES: { const rct_track_coordinates * trackCoordinates = &TrackCoordinates[trackType]; - const rct_preview_track * trackBlock = TrackBlocks[trackType]; + const rct_preview_track * trackBlock = trackBlockArray[trackType]; sint32 tempZ = z - trackCoordinates->z_begin + trackBlock->z; uint8 flags = GAME_COMMAND_FLAG_APPLY | @@ -1495,7 +1497,7 @@ static bool track_design_place_ride(rct_track_td6 * td6, sint16 x, sint16 y, sin case PTD_OPERATION_GET_PLACE_Z: { sint32 tempZ = z - TrackCoordinates[trackType].z_begin; - for (const rct_preview_track * trackBlock = TrackBlocks[trackType]; trackBlock->index != 0xFF; trackBlock++) + for (const rct_preview_track * trackBlock = trackBlockArray[trackType]; trackBlock->index != 0xFF; trackBlock++) { sint16 tmpX = x; sint16 tmpY = y; @@ -1793,6 +1795,17 @@ static bool track_design_place_preview(rct_track_td6 * td6, money32 * cost, uint ride->track_colour_supports[i] = td6->track_support_colour[i]; } + // Flat rides need their vehicle colours loaded for display + // in the preview window + if (!ride_type_has_flag(td6->type, RIDE_TYPE_FLAG_HAS_TRACK)) + { + for (sint32 i = 0; i < RCT12_MAX_VEHICLE_COLOURS; i++) + { + ride->vehicle_colours[i] = td6->vehicle_colours[i]; + ride->vehicle_colours_extended[i] = td6->vehicle_additional_colour[i]; + } + } + byte_9D8150 = true; uint8 backup_rotation = _currentTrackPieceDirection; uint32 backup_park_flags = gParkFlags; @@ -2008,7 +2021,7 @@ static money32 place_track_design(sint16 x, sint16 y, sint16 z, uint8 flags, uin ride->track_colour_supports[i] = td6->track_support_colour[i]; } - for (sint32 i = 0; i < 32; i++) + for (sint32 i = 0; i < MAX_VEHICLES_PER_RIDE; i++) { ride->vehicle_colours[i].body_colour = td6->vehicle_colours[i].body_colour; ride->vehicle_colours[i].trim_colour = td6->vehicle_colours[i].trim_colour; @@ -2242,6 +2255,14 @@ void track_design_draw_preview(rct_track_td6 * td6, uint8 * pixels) sint32 size_y = gTrackPreviewMax.y - gTrackPreviewMin.y; sint32 size_z = gTrackPreviewMax.z - gTrackPreviewMin.z; + // Special case for flat rides - Z-axis info is irrelevant + // and must be zeroed out lest the preview be off-centre + if (!ride_type_has_flag(td6->type, RIDE_TYPE_FLAG_HAS_TRACK)) + { + centre.z = 0; + size_z = 0; + } + sint32 zoom_level = 1; if (size_x < size_y) diff --git a/src/openrct2/ride/TrackDesignSave.cpp b/src/openrct2/ride/TrackDesignSave.cpp index 4411b97305..7681f3f25c 100644 --- a/src/openrct2/ride/TrackDesignSave.cpp +++ b/src/openrct2/ride/TrackDesignSave.cpp @@ -158,11 +158,6 @@ bool track_design_save(uint8 rideIndex) return false; } - if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) { - context_show_error(STR_CANT_SAVE_TRACK_DESIGN, gGameCommandErrorText); - return false; - } - _trackDesign = track_design_save_to_td6(rideIndex); if (_trackDesign == nullptr) { context_show_error(STR_CANT_SAVE_TRACK_DESIGN, gGameCommandErrorText); @@ -724,12 +719,14 @@ static rct_track_td6 *track_design_save_to_td6(uint8 rideIndex) (ride->colour_scheme_type & 3) | (1 << 3); // Version .TD6 - for (sint32 i = 0; i < 32; i++) { + for (sint32 i = 0; i < RCT12_MAX_VEHICLES_PER_RIDE; i++) + { td6->vehicle_colours[i] = ride->vehicle_colours[i]; td6->vehicle_additional_colour[i] = ride->vehicle_colours_extended[i]; } - for (sint32 i = 0; i < RCT12_NUM_COLOUR_SCHEMES; i++) { + for (sint32 i = 0; i < RCT12_NUM_COLOUR_SCHEMES; i++) + { td6->track_spine_colour[i] = ride->track_colour_main[i]; td6->track_rail_colour[i] = ride->track_colour_additional[i]; td6->track_support_colour[i] = ride->track_colour_supports[i];