diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 4300ab4904..49a7422297 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3679,6 +3679,9 @@ STR_6436 :Toggle invisibility STR_6437 :Invisible STR_6438 :I STR_6439 :Tile Inspector: Toggle invisibility +STR_6440 :At least one footpath non-queue surface object must be selected. +STR_6441 :At least one footpath queue surface object must be selected. +STR_6442 :At least one footpath railing object must be selected. ############# # Scenarios # diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index 6a16582e66..59219c128a 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -98,15 +98,18 @@ static constexpr const ObjectPageDesc ObjectSelectionPages[] = { { STR_OBJECT_SELECTION_LARGE_SCENERY, SPR_TAB_SCENERY_URBAN, true }, { STR_OBJECT_SELECTION_WALLS_FENCES, SPR_TAB_SCENERY_WALLS, true }, { STR_OBJECT_SELECTION_PATH_SIGNS, SPR_TAB_SCENERY_SIGNAGE, true }, - { STR_OBJECT_SELECTION_FOOTPATHS, SPR_TAB_SCENERY_PATHS, false }, + { STR_OBJECT_SELECTION_FOOTPATHS, SPR_TAB_SCENERY_PATHS, true }, { STR_OBJECT_SELECTION_PATH_EXTRAS, SPR_TAB_SCENERY_PATH_ITEMS, false }, { STR_OBJECT_SELECTION_SCENERY_GROUPS, SPR_TAB_SCENERY_STATUES, false }, { STR_OBJECT_SELECTION_PARK_ENTRANCE, SPR_TAB_PARK, false }, { STR_OBJECT_SELECTION_WATER, SPR_TAB_WATER, false }, - { STR_OBJECT_SELECTION_TERRAIN_SURFACES, SPR_G2_TAB_LAND, true }, - { STR_OBJECT_SELECTION_TERRAIN_EDGES, SPR_G2_TAB_LAND, true }, - { STR_OBJECT_SELECTION_STATIONS, SPR_TAB_PARK, true }, + // Dummy place holder for string objects + { STR_NONE, static_cast(SPR_NONE), false }, + + { STR_OBJECT_SELECTION_TERRAIN_SURFACES, SPR_G2_TAB_LAND, true }, + { STR_OBJECT_SELECTION_TERRAIN_EDGES, SPR_G2_TAB_LAND, true }, + { STR_OBJECT_SELECTION_STATIONS, SPR_TAB_PARK, true }, { STR_OBJECT_SELECTION_MUSIC, SPR_TAB_MUSIC_0, false }, { STR_OBJECT_SELECTION_FOOTPATHS, SPR_TAB_SCENERY_PATHS, false }, { STR_OBJECT_SELECTION_FOOTPATHS, SPR_TAB_SCENERY_PATHS, false }, @@ -833,7 +836,7 @@ static void window_editor_object_selection_invalidate(rct_window* w) for (size_t i = 0; i < std::size(ObjectSelectionPages); i++) { auto widget = &w->widgets[WIDX_TAB_1 + i]; - if (!advancedMode && ObjectSelectionPages[i].IsAdvanced) + if (!advancedMode && ObjectSelectionPages[i].IsAdvanced || ObjectSelectionPages[i].Image == SPR_NONE) { widget->type = WindowWidgetType::Empty; } @@ -1536,8 +1539,5 @@ static std::string object_get_description(const Object* object) static ObjectType get_selected_object_type(rct_window* w) { auto tab = w->selected_tab; - if (tab >= EnumValue(ObjectType::ScenarioText)) - return static_cast(tab + 1); - else - return static_cast(tab); + return static_cast(tab); } diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index 22adf105a5..493b1f86f2 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -715,7 +715,7 @@ static void window_footpath_show_footpath_types_dialog(rct_window* w, rct_widget _dropdownEntries.clear(); std::optional defaultIndex; - for (size_t i = 0; i < MAX_FOOTPATH_SURFACE_OBJECTS; i++) + for (ObjectEntryIndex i = 0; i < MAX_FOOTPATH_SURFACE_OBJECTS; i++) { const auto* pathType = static_cast(objManager.GetLoadedObject(ObjectType::FootpathSurface, i)); if (pathType == nullptr) @@ -742,7 +742,7 @@ static void window_footpath_show_footpath_types_dialog(rct_window* w, rct_widget numPathTypes++; } - for (size_t i = 0; i < MAX_PATH_OBJECTS; i++) + for (ObjectEntryIndex i = 0; i < MAX_PATH_OBJECTS; i++) { auto* pathObj = static_cast(objManager.GetLoadedObject(ObjectType::Paths, i)); if (pathObj == nullptr) diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index bff45240ef..dcb7d70789 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -489,10 +489,20 @@ namespace Editor if (!isTrackDesignerManager) { - if (!editor_check_object_group_at_least_one_selected(ObjectType::Paths)) + if (!editor_check_object_group_at_least_one_surface_selected(false)) { - gGameCommandErrorText = STR_AT_LEAST_ONE_PATH_OBJECT_MUST_BE_SELECTED; - return ObjectType::Paths; + gGameCommandErrorText = STR_AT_LEAST_ONE_FOOTPATH_NON_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED; + return ObjectType::FootpathSurface; + } + if (!editor_check_object_group_at_least_one_surface_selected(true)) + { + gGameCommandErrorText = STR_AT_LEAST_ONE_FOOTPATH_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED; + return ObjectType::FootpathSurface; + } + if (!editor_check_object_group_at_least_one_selected(ObjectType::FootpathRailings)) + { + gGameCommandErrorText = STR_AT_LEAST_ONE_FOOTPATH_RAILING_OBJECT_MUST_BE_SELECTED; + return ObjectType::FootpathRailings; } } diff --git a/src/openrct2/EditorObjectSelectionSession.cpp b/src/openrct2/EditorObjectSelectionSession.cpp index 935d101342..92bacf8715 100644 --- a/src/openrct2/EditorObjectSelectionSession.cpp +++ b/src/openrct2/EditorObjectSelectionSession.cpp @@ -644,6 +644,23 @@ bool editor_check_object_group_at_least_one_selected(ObjectType checkObjectType) return false; } +bool editor_check_object_group_at_least_one_surface_selected(bool queue) +{ + auto numObjects = std::min(object_repository_get_items_count(), _objectSelectionFlags.size()); + const auto* items = object_repository_get_items(); + for (size_t i = 0; i < numObjects; i++) + { + const auto& ori = items[i]; + auto isQueue = (ori.FootpathSurfaceInfo.Flags & FOOTPATH_ENTRY_FLAG_IS_QUEUE) != 0; + if (ori.Type == ObjectType::FootpathSurface && (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED) + && queue == isQueue) + { + return true; + } + } + return false; +} + int32_t editor_remove_unused_objects() { sub_6AB211(); diff --git a/src/openrct2/EditorObjectSelectionSession.h b/src/openrct2/EditorObjectSelectionSession.h index e03be7004e..9df783e8b7 100644 --- a/src/openrct2/EditorObjectSelectionSession.h +++ b/src/openrct2/EditorObjectSelectionSession.h @@ -28,6 +28,7 @@ extern std::vector _objectSelectionFlags; extern int32_t _numSelectedObjectsForType[EnumValue(ObjectType::Count)]; bool editor_check_object_group_at_least_one_selected(ObjectType checkObjectType); +bool editor_check_object_group_at_least_one_surface_selected(bool queue); void editor_object_flags_free(); void unload_unselected_objects(); void sub_6AB211(); diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index ad79e909a4..31f48dfd8f 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -3938,6 +3938,10 @@ enum STR_TILE_INSPECTOR_INVISIBLE_SHORT = 6438, STR_SHORTCUT_TOGGLE_INVISIBILITY = 6439, + STR_AT_LEAST_ONE_FOOTPATH_NON_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED = 6440, + STR_AT_LEAST_ONE_FOOTPATH_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED = 6441, + STR_AT_LEAST_ONE_FOOTPATH_RAILING_OBJECT_MUST_BE_SELECTED = 6442, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings }; diff --git a/src/openrct2/object/FootpathSurfaceObject.cpp b/src/openrct2/object/FootpathSurfaceObject.cpp index 65641c0e96..66b89b6727 100644 --- a/src/openrct2/object/FootpathSurfaceObject.cpp +++ b/src/openrct2/object/FootpathSurfaceObject.cpp @@ -11,6 +11,7 @@ #include "../core/IStream.hpp" #include "../core/Json.hpp" +#include "../object/ObjectRepository.h" void FootpathSurfaceObject::Load() { @@ -61,3 +62,8 @@ void FootpathSurfaceObject::ReadJson(IReadObjectContext* context, json_t& root) PopulateTablesFromJson(context, root); } + +void FootpathSurfaceObject::SetRepositoryItem(ObjectRepositoryItem* item) const +{ + item->FootpathSurfaceInfo.Flags = Flags; +} diff --git a/src/openrct2/object/FootpathSurfaceObject.h b/src/openrct2/object/FootpathSurfaceObject.h index 89747ee393..c21ea2d1ab 100644 --- a/src/openrct2/object/FootpathSurfaceObject.h +++ b/src/openrct2/object/FootpathSurfaceObject.h @@ -26,4 +26,6 @@ public: void Unload() override; void DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t height) const override; + + void SetRepositoryItem(ObjectRepositoryItem* item) const override; }; diff --git a/src/openrct2/object/ObjectRepository.cpp b/src/openrct2/object/ObjectRepository.cpp index e62c33e996..1936d2c693 100644 --- a/src/openrct2/object/ObjectRepository.cpp +++ b/src/openrct2/object/ObjectRepository.cpp @@ -152,6 +152,9 @@ protected: ds << item.SceneryGroupInfo.Entries; break; } + case ObjectType::FootpathSurface: + ds << item.FootpathSurfaceInfo.Flags; + break; default: // Switch processes only ObjectType::Ride and ObjectType::SceneryGroup break; diff --git a/src/openrct2/object/ObjectRepository.h b/src/openrct2/object/ObjectRepository.h index c8bb70b978..3df9b74652 100644 --- a/src/openrct2/object/ObjectRepository.h +++ b/src/openrct2/object/ObjectRepository.h @@ -56,6 +56,10 @@ struct ObjectRepositoryItem { std::vector Entries; } SceneryGroupInfo; + struct + { + uint8_t Flags{}; + } FootpathSurfaceInfo; ObjectSourceGame GetFirstSourceGame() const {