diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index 817a7955ed..7af92b03e7 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -26,10 +27,12 @@ #include static constexpr const rct_string_id WINDOW_TITLE = STR_FOOTPATHS; -static constexpr const int32_t WH = 381; +static constexpr const int32_t WH = 421; static constexpr const int32_t WW = 106; static constexpr const uint16_t ARROW_PULSE_DURATION = 200; +static ObjectEntryIndex _selectedRailings = OBJECT_ENTRY_INDEX_NULL; + // clang-format off enum { @@ -53,6 +56,7 @@ enum WINDOW_FOOTPATH_WIDGET_IDX WIDX_TYPE_GROUP, WIDX_FOOTPATH_TYPE, WIDX_QUEUELINE_TYPE, + WIDX_RAILINGS_TYPE, WIDX_DIRECTION_GROUP, WIDX_DIRECTION_NW, @@ -76,29 +80,30 @@ static rct_widget window_footpath_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), // Type group - MakeWidget({ 3, 17}, {100, 55}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_TYPE ), + MakeWidget({ 3, 17}, {100, 95}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_TYPE ), MakeWidget({ 6, 30}, { 47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_FOOTPATH_TIP ), MakeWidget({53, 30}, { 47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_QUEUE_LINE_PATH_TIP ), + MakeWidget({29, 69}, { 47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_FOOTPATH_TIP ), // Direction group - MakeWidget({ 3, 75}, {100, 77}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_DIRECTION ), - MakeWidget({53, 87}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_NE, STR_DIRECTION_TIP ), - MakeWidget({53, 116}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_SE, STR_DIRECTION_TIP ), - MakeWidget({ 8, 116}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_SW, STR_DIRECTION_TIP ), - MakeWidget({ 8, 87}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_NW, STR_DIRECTION_TIP ), + MakeWidget({ 3, 115}, {100, 77}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_DIRECTION ), + MakeWidget({53, 127}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_NE, STR_DIRECTION_TIP ), + MakeWidget({53, 156}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_SE, STR_DIRECTION_TIP ), + MakeWidget({ 8, 156}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_SW, STR_DIRECTION_TIP ), + MakeWidget({ 8, 127}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_NW, STR_DIRECTION_TIP ), // Slope group - MakeWidget({ 3, 155}, {100, 41}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_SLOPE ), - MakeWidget({17, 167}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_DOWN, STR_SLOPE_DOWN_TIP ), - MakeWidget({41, 167}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_LEVEL, STR_LEVEL_TIP ), - MakeWidget({65, 167}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_UP, STR_SLOPE_UP_TIP ), - MakeWidget({ 8, 202}, { 90, 90}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_CONSTRUCT_THE_SELECTED_FOOTPATH_SECTION_TIP), - MakeWidget({30, 295}, { 46, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_DEMOLISH_CURRENT_SECTION, STR_REMOVE_PREVIOUS_FOOTPATH_SECTION_TIP ), + MakeWidget({ 3, 195}, {100, 41}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_SLOPE ), + MakeWidget({17, 207}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_DOWN, STR_SLOPE_DOWN_TIP ), + MakeWidget({41, 207}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_LEVEL, STR_LEVEL_TIP ), + MakeWidget({65, 207}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_UP, STR_SLOPE_UP_TIP ), + MakeWidget({ 8, 242}, { 90, 90}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_CONSTRUCT_THE_SELECTED_FOOTPATH_SECTION_TIP), + MakeWidget({30, 335}, { 46, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_DEMOLISH_CURRENT_SECTION, STR_REMOVE_PREVIOUS_FOOTPATH_SECTION_TIP ), // Mode group - MakeWidget({ 3, 321}, {100, 54}, WindowWidgetType::Groupbox, WindowColour::Primary ), - MakeWidget({13, 332}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_FOOTPATH_LAND, STR_CONSTRUCT_FOOTPATH_ON_LAND_TIP ), - MakeWidget({57, 332}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_FOOTPATH_BRIDGE, STR_CONSTRUCT_BRIDGE_OR_TUNNEL_FOOTPATH_TIP ), + MakeWidget({ 3, 361}, {100, 54}, WindowWidgetType::Groupbox, WindowColour::Primary ), + MakeWidget({13, 372}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_FOOTPATH_LAND, STR_CONSTRUCT_FOOTPATH_ON_LAND_TIP ), + MakeWidget({57, 372}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_FOOTPATH_BRIDGE, STR_CONSTRUCT_BRIDGE_OR_TUNNEL_FOOTPATH_TIP ), {WIDGETS_END}, }; @@ -165,6 +170,7 @@ static constexpr const uint8_t ConstructionPreviewImages[][4] = { static void window_footpath_mousedown_direction(int32_t direction); static void window_footpath_mousedown_slope(int32_t slope); static void window_footpath_show_footpath_types_dialog(rct_window* w, rct_widget* widget, bool showQueues); +static void window_footpath_show_railings_types_dialog(rct_window* w, rct_widget* widget); static void window_footpath_set_provisional_path_at_point(const ScreenCoordsXY& screenCoords); static void window_footpath_set_selection_start_bridge_at_point(const ScreenCoordsXY& screenCoords); static void window_footpath_place_path_at_point(const ScreenCoordsXY& screenCoords); @@ -205,12 +211,12 @@ rct_window* window_footpath_open() return window; } - window = WindowCreate(ScreenCoordsXY(0, 29), 106, 381, &window_footpath_events, WC_FOOTPATH, 0); + window = WindowCreate(ScreenCoordsXY(0, 29), WW, WH, &window_footpath_events, WC_FOOTPATH, 0); window->widgets = window_footpath_widgets; window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_FOOTPATH_TYPE) | (1 << WIDX_QUEUELINE_TYPE) - | (1 << WIDX_DIRECTION_NW) | (1 << WIDX_DIRECTION_NE) | (1 << WIDX_DIRECTION_SW) | (1 << WIDX_DIRECTION_SE) - | (1 << WIDX_SLOPEDOWN) | (1 << WIDX_LEVEL) | (1 << WIDX_SLOPEUP) | (1 << WIDX_CONSTRUCT) | (1 << WIDX_REMOVE) - | (1 << WIDX_CONSTRUCT_ON_LAND) | (1 << WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL); + | (1 << WIDX_RAILINGS_TYPE) | (1 << WIDX_DIRECTION_NW) | (1 << WIDX_DIRECTION_NE) | (1 << WIDX_DIRECTION_SW) + | (1 << WIDX_DIRECTION_SE) | (1 << WIDX_SLOPEDOWN) | (1 << WIDX_LEVEL) | (1 << WIDX_SLOPEUP) | (1 << WIDX_CONSTRUCT) + | (1 << WIDX_REMOVE) | (1 << WIDX_CONSTRUCT_ON_LAND) | (1 << WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL); WindowInitScrollWidgets(window); window_push_others_right(window); @@ -308,6 +314,9 @@ static void window_footpath_mousedown(rct_window* w, rct_widgetindex widgetIndex case WIDX_QUEUELINE_TYPE: window_footpath_show_footpath_types_dialog(w, widget, true); break; + case WIDX_RAILINGS_TYPE: + window_footpath_show_railings_types_dialog(w, widget); + break; case WIDX_DIRECTION_NW: window_footpath_mousedown_direction(0); break; @@ -346,6 +355,16 @@ static void window_footpath_dropdown(rct_window* w, rct_widgetindex widgetIndex, { gFootpathSelectedType = SELECTED_PATH_TYPE_QUEUE; } + else if (widgetIndex == WIDX_RAILINGS_TYPE) + { + if (dropdownIndex != -1) + _selectedRailings = dropdownIndex; + + footpath_provisional_update(); + _window_footpath_cost = MONEY32_UNDEFINED; + w->Invalidate(); + return; + } else { return; @@ -471,7 +490,7 @@ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window* { CoordsXYZ footpathLoc; footpath_get_next_path_info(&type, footpathLoc, &slope); - _window_footpath_cost = footpath_provisional_set(type, footpathLoc, slope); + _window_footpath_cost = footpath_provisional_set(type, _selectedRailings, footpathLoc, slope); widget_invalidate(w, WIDX_CONSTRUCT); } @@ -578,6 +597,14 @@ static void window_footpath_invalidate(rct_window* w) } window_footpath_widgets[WIDX_FOOTPATH_TYPE].image = pathImage; window_footpath_widgets[WIDX_QUEUELINE_TYPE].image = queueImage; + + auto railingsImage = static_cast(SPR_NONE); + auto railingsEntry = get_path_railings_entry(_selectedRailings); + if (railingsEntry != nullptr) + { + railingsImage = railingsEntry->PreviewImageId; + } + window_footpath_widgets[WIDX_RAILINGS_TYPE].image = railingsImage; } /** @@ -677,6 +704,32 @@ static void window_footpath_show_footpath_types_dialog(rct_window* w, rct_widget 36, itemsPerRow); } +static void window_footpath_show_railings_types_dialog(rct_window* w, rct_widget* widget) +{ + uint32_t numRailingsTypes = 0; + // If the game is in sandbox mode, also show paths that are normally restricted to the scenario editor + + for (int32_t i = 0; i < MAX_FOOTPATH_RAILINGS_OBJECTS; i++) + { + FootpathRailingsObject* railingsEntry = get_path_railings_entry(i); + if (railingsEntry == nullptr) + { + continue; + } + + int32_t image = railingsEntry->PreviewImageId; + + gDropdownItemsFormat[numRailingsTypes] = STR_NONE; + gDropdownItemsArgs[numRailingsTypes] = image; + numRailingsTypes++; + } + + auto itemsPerRow = DropdownGetAppropriateImageDropdownItemsPerRow(numRailingsTypes); + WindowDropdownShowImage( + w->windowPos.x + widget->left, w->windowPos.y + widget->top, widget->height() + 1, w->colours[1], 0, numRailingsTypes, + 47, 36, itemsPerRow); +} + /** * * rct2: 0x006A8111 0x006A8135 0x006A815C 0x006A8183 @@ -772,7 +825,7 @@ static void window_footpath_set_provisional_path_at_point(const ScreenCoordsXY& } int32_t pathType = (gFootpathSelectedType << 7) + (gFootpathSelectedId & 0xFF); - _window_footpath_cost = footpath_provisional_set(pathType, { info.Loc, z }, slope); + _window_footpath_cost = footpath_provisional_set(pathType, _selectedRailings, { info.Loc, z }, slope); window_invalidate_by_class(WC_FOOTPATH); } } @@ -869,7 +922,7 @@ static void window_footpath_place_path_at_point(const ScreenCoordsXY& screenCoor // Try and place path gGameCommandErrorTitle = STR_CANT_BUILD_FOOTPATH_HERE; - auto footpathPlaceAction = FootpathPlaceAction({ info.Loc, z }, slope, selectedType); + auto footpathPlaceAction = FootpathPlaceAction({ info.Loc, z }, slope, selectedType, _selectedRailings); footpathPlaceAction.SetCallback([](const GameAction* ga, const GameActions::Result* result) { if (result->Error == GameActions::Status::Ok) { @@ -958,7 +1011,7 @@ static void window_footpath_construct() footpath_get_next_path_info(&type, footpathLoc, &slope); gGameCommandErrorTitle = STR_CANT_BUILD_FOOTPATH_HERE; - auto footpathPlaceAction = FootpathPlaceAction(footpathLoc, slope, type, gFootpathConstructDirection); + auto footpathPlaceAction = FootpathPlaceAction(footpathLoc, slope, type, _selectedRailings, gFootpathConstructDirection); footpathPlaceAction.SetCallback([=](const GameAction* ga, const GameActions::Result* result) { if (result->Error == GameActions::Status::Ok) { diff --git a/src/openrct2/actions/FootpathPlaceAction.cpp b/src/openrct2/actions/FootpathPlaceAction.cpp index cdb5352778..978e5255f1 100644 --- a/src/openrct2/actions/FootpathPlaceAction.cpp +++ b/src/openrct2/actions/FootpathPlaceAction.cpp @@ -25,10 +25,12 @@ using namespace OpenRCT2; -FootpathPlaceAction::FootpathPlaceAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, Direction direction) +FootpathPlaceAction::FootpathPlaceAction( + const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, Direction direction) : _loc(loc) , _slope(slope) , _type(type) + , _railingsType(railingsType) , _direction(direction) { } @@ -37,6 +39,7 @@ void FootpathPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) { visitor.Visit(_loc); visitor.Visit("object", _type); + visitor.Visit("railingsObject", _railingsType); visitor.Visit("direction", _direction); visitor.Visit("slope", _slope); } @@ -182,7 +185,7 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateExecute(PathElement* } pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); - pathElement->SetRailingEntryIndex(OBJECT_ENTRY_INDEX_NULL); + pathElement->SetRailingEntryIndex(_railingsType); bool isQueue = _type & FOOTPATH_ELEMENT_INSERT_QUEUE; pathElement->SetIsQueue(isQueue); @@ -349,7 +352,7 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions:: pathElement->SetClearanceZ(zHigh); pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); - pathElement->SetRailingEntryIndex(OBJECT_ENTRY_INDEX_NULL); + pathElement->SetRailingEntryIndex(_railingsType); pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED); pathElement->SetIsQueue(_type & FOOTPATH_ELEMENT_INSERT_QUEUE); diff --git a/src/openrct2/actions/FootpathPlaceAction.h b/src/openrct2/actions/FootpathPlaceAction.h index f8b4ff83ce..15a3a66632 100644 --- a/src/openrct2/actions/FootpathPlaceAction.h +++ b/src/openrct2/actions/FootpathPlaceAction.h @@ -18,11 +18,14 @@ private: CoordsXYZ _loc; uint8_t _slope{}; ObjectEntryIndex _type{}; + ObjectEntryIndex _railingsType{}; Direction _direction{ INVALID_DIRECTION }; public: FootpathPlaceAction() = default; - FootpathPlaceAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, Direction direction = INVALID_DIRECTION); + FootpathPlaceAction( + const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, + Direction direction = INVALID_DIRECTION); void AcceptParameters(GameActionParameterVisitor & visitor) override; diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index 6685743190..f9c4c98b7c 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -1,4 +1,4 @@ -/***************************************************************************** +/***************************************************************************** * Copyright (c) 2014-2020 OpenRCT2 developers * * For a complete list of all authors, please refer to contributors.md @@ -829,8 +829,8 @@ paint_struct* PaintAddImageAsChild( int32_t bound_box_length_y, int32_t bound_box_length_z, int32_t z_offset, int32_t bound_box_offset_x, int32_t bound_box_offset_y, int32_t bound_box_offset_z) { - assert(bound_box_length_x > 0); - assert(bound_box_length_y > 0); + /*assert(bound_box_length_x > 0); + assert(bound_box_length_y > 0);*/ return PaintAddImageAsChild( session, image_id, { x_offset, y_offset, z_offset }, { bound_box_length_x, bound_box_length_y, bound_box_length_z }, { bound_box_offset_x, bound_box_offset_y, bound_box_offset_z }); diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 4a8db5f073..c659b44a95 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -147,13 +147,14 @@ money32 footpath_remove(const CoordsXYZ& footpathLoc, int32_t flags) * * rct2: 0x006A76FF */ -money32 footpath_provisional_set(int32_t type, const CoordsXYZ& footpathLoc, int32_t slope) +money32 footpath_provisional_set( + ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope) { money32 cost; footpath_provisional_remove(); - auto footpathPlaceAction = FootpathPlaceAction(footpathLoc, slope, type); + auto footpathPlaceAction = FootpathPlaceAction(footpathLoc, slope, type, railingsType); footpathPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED); auto res = GameActions::Execute(&footpathPlaceAction); cost = res->Error == GameActions::Status::Ok ? res->Cost : MONEY32_UNDEFINED; @@ -2275,6 +2276,16 @@ PathSurfaceEntry* get_path_surface_entry(ObjectEntryIndex entryIndex) return result; } +FootpathRailingsObject* get_path_railings_entry(ObjectEntryIndex entryIndex) +{ + auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); + auto obj = objMgr.GetLoadedObject(ObjectType::FootpathRailings, entryIndex); + if (obj == nullptr) + return nullptr; + + return static_cast(obj); +} + ride_id_t PathElement::GetRideIndex() const { return rideIndex; diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index f0facb21a1..a8370f3b04 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -177,7 +177,8 @@ extern const CoordsXY BenchUseOffsets[NumOrthogonalDirections * 2]; TileElement* map_get_footpath_element(const CoordsXYZ& coords); void footpath_interrupt_peeps(const CoordsXYZ& footpathPos); money32 footpath_remove(const CoordsXYZ& footpathLoc, int32_t flags); -money32 footpath_provisional_set(int32_t type, const CoordsXYZ& footpathLoc, int32_t slope); +money32 footpath_provisional_set( + ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope); void footpath_provisional_remove(); void footpath_provisional_update(); CoordsXY footpath_get_coordinates_from_pos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement); @@ -196,6 +197,7 @@ void footpath_remove_edges_at(const CoordsXY& footpathPos, TileElement* tileElem int32_t entrance_get_directions(const TileElement* tileElement); PathSurfaceEntry* get_path_surface_entry(ObjectEntryIndex entryIndex); +FootpathRailingsObject* get_path_railings_entry(ObjectEntryIndex entryIndex); void footpath_queue_chain_reset(); void footpath_queue_chain_push(ride_id_t rideIndex); diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index e95c00365c..dbacf8465d 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -1554,7 +1554,8 @@ void map_restore_provisional_elements() if (gFootpathProvisionalFlags & PROVISIONAL_PATH_FLAG_1) { gFootpathProvisionalFlags &= ~PROVISIONAL_PATH_FLAG_1; - footpath_provisional_set(gFootpathProvisionalType, gFootpathProvisionalPosition, gFootpathProvisionalSlope); + footpath_provisional_set( + gFootpathProvisionalType, OBJECT_ENTRY_INDEX_NULL, gFootpathProvisionalPosition, gFootpathProvisionalSlope); } if (window_find_by_class(WC_RIDE_CONSTRUCTION) != nullptr) {