diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 62a9fa8660..f7cbe597a8 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,5 +1,6 @@ 0.4.14 (in development) ------------------------------------------------------------------------ +- Feature: [#15750] Allow using different types of park entrance in one park. - Change: [#21659] Increase the Hybrid Roller Coaster’s maximum lift speed to 17 km/h (11 mph). - Change: [#22466] The Clear Scenery tool now uses a bulldozer cursor instead of a generic crosshair. diff --git a/src/openrct2-ui/WindowManager.cpp b/src/openrct2-ui/WindowManager.cpp index f07b493f23..d9a8ca5d6f 100644 --- a/src/openrct2-ui/WindowManager.cpp +++ b/src/openrct2-ui/WindowManager.cpp @@ -144,6 +144,8 @@ public: return TransparencyOpen(); case WindowClass::AssetPacks: return AssetPacksOpen(); + case WindowClass::EditorParkEntrance: + return EditorParkEntranceOpen(); default: Console::Error::WriteLine("Unhandled window class (%d)", wc); return nullptr; diff --git a/src/openrct2-ui/input/Shortcuts.cpp b/src/openrct2-ui/input/Shortcuts.cpp index e31fdf7878..7167da4447 100644 --- a/src/openrct2-ui/input/Shortcuts.cpp +++ b/src/openrct2-ui/input/Shortcuts.cpp @@ -127,11 +127,11 @@ static void ShortcutRotateConstructionObject() } // Rotate park entrance - w = WindowFindByClass(WindowClass::Map); - if (w != nullptr && !WidgetIsDisabled(*w, WC_MAP__WIDX_ROTATE_90) - && w->widgets[WC_MAP__WIDX_ROTATE_90].type != WindowWidgetType::Empty) + w = WindowFindByClass(WindowClass::EditorParkEntrance); + if (w != nullptr && !WidgetIsDisabled(*w, WC_EDITOR_PARK_ENTRANCE__WIDX_ROTATE_ENTRANCE_BUTTON) + && w->widgets[WC_EDITOR_PARK_ENTRANCE__WIDX_ROTATE_ENTRANCE_BUTTON].type != WindowWidgetType::Empty) { - w->OnMouseUp(WC_MAP__WIDX_ROTATE_90); + w->OnMouseUp(WC_EDITOR_PARK_ENTRANCE__WIDX_ROTATE_ENTRANCE_BUTTON); return; } diff --git a/src/openrct2-ui/interface/Theme.cpp b/src/openrct2-ui/interface/Theme.cpp index 3434b4cde5..3ab5777b3f 100644 --- a/src/openrct2-ui/interface/Theme.cpp +++ b/src/openrct2-ui/interface/Theme.cpp @@ -196,6 +196,7 @@ static constexpr WindowThemeDesc WindowThemeDescriptors[] = { WindowClass::Chat, "WC_CHAT", STR_CHAT, COLOURS_1(translucent(COLOUR_GREY) ) }, { WindowClass::Console, "WC_CONSOLE", STR_CONSOLE, COLOURS_2(translucent(COLOUR_LIGHT_BLUE), opaque(COLOUR_WHITE) ) }, { WindowClass::ProgressWindow, "WC_PROGRESS_WINDOW", STR_THEME_LOADING_WINDOW, COLOURS_1(opaque(COLOUR_BLACK) ) }, + { WindowClass::EditorParkEntrance, "WC_EDITOR_PARK_ENTRANCE", STR_OBJECT_SELECTION_PARK_ENTRANCE, COLOURS_2(opaque(COLOUR_DARK_GREEN), opaque(COLOUR_DARK_BROWN) ) }, }; #pragma endregion diff --git a/src/openrct2-ui/libopenrct2ui.vcxproj b/src/openrct2-ui/libopenrct2ui.vcxproj index dd474ce56a..567cbcba21 100644 --- a/src/openrct2-ui/libopenrct2ui.vcxproj +++ b/src/openrct2-ui/libopenrct2ui.vcxproj @@ -170,6 +170,7 @@ + diff --git a/src/openrct2-ui/windows/EditorParkEntrance.cpp b/src/openrct2-ui/windows/EditorParkEntrance.cpp new file mode 100644 index 0000000000..c141238f56 --- /dev/null +++ b/src/openrct2-ui/windows/EditorParkEntrance.cpp @@ -0,0 +1,380 @@ +/***************************************************************************** + * Copyright (c) 2014-2024 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace OpenRCT2::Ui::Windows +{ + static constexpr StringId kWindowTitle = STR_OBJECT_SELECTION_PARK_ENTRANCE; + static constexpr int32_t kImageSize = 116; + static constexpr int32_t kNumColumns = 4; + static constexpr int32_t kNumRows = 1; + static constexpr int32_t kScrollPadding = 2; + static constexpr int32_t kScrollWidth = (kImageSize * kNumColumns) + kScrollBarWidth + 4; + static constexpr int32_t kScrollHeight = (kImageSize * kNumRows); + static constexpr int32_t kWindowWidth = kScrollWidth + 28; + static constexpr int32_t kWindowHeight = kScrollHeight + 50; + + struct EntranceSelection + { + ObjectEntryIndex entryIndex = OBJECT_ENTRY_INDEX_NULL; + StringId stringId = STR_NONE; + ImageIndex imageId = static_cast(SPR_NONE); + }; + + enum WindowEditorParkEntranceListWidgetIdx + { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_TAB_CONTENT_PANEL, + WIDX_TAB, + WIDX_LIST, + WIDX_ROTATE_ENTRANCE_BUTTON, + }; + + validate_global_widx(WC_EDITOR_PARK_ENTRANCE, WIDX_ROTATE_ENTRANCE_BUTTON); + + // clang-format off + static Widget _widgets[] = { + WINDOW_SHIM(kWindowTitle, kWindowWidth, kWindowHeight), + MakeWidget ({ 0, 43 }, { kWindowWidth, kWindowHeight - 43 }, WindowWidgetType::Resize, WindowColour::Secondary ), + MakeTab ({ 3, 17 }, STR_NONE ), + MakeWidget ({ 2, 45 }, { kScrollWidth, kScrollHeight }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), + MakeWidget ({ kWindowWidth - 26, 59 }, { 24, 24 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_ROTATE_ARROW), STR_ROTATE_OBJECTS_90 ), + kWidgetsEnd, + }; + // clang-format on + + class EditorParkEntrance final : public Window + { + private: + ObjectEntryIndex _selectedEntranceType = 0; + ObjectEntryIndex _highlightedEntranceType = 0; + std::vector _entranceTypes{}; + + void InitParkEntranceItems() + { + _entranceTypes.clear(); + for (ObjectEntryIndex objectIndex = 0; objectIndex < MAX_PARK_ENTRANCE_OBJECTS; objectIndex++) + { + auto& objManager = GetContext()->GetObjectManager(); + auto* object = static_cast(objManager.GetLoadedObject(ObjectType::ParkEntrance, objectIndex)); + if (object != nullptr) + { + const auto* legacyData = reinterpret_cast(object->GetLegacyData()); + _entranceTypes.push_back({ objectIndex, legacyData->string_idx, legacyData->image_id }); + } + } + } + + void PaintPreview(DrawPixelInfo& dpi, ImageIndex imageStart, ScreenCoordsXY screenCoords, Direction direction) + { + imageStart += (direction * 3); + + switch (direction) + { + case 0: + GfxDrawSprite(dpi, ImageId(imageStart + 1), screenCoords + ScreenCoordsXY{ -32, 14 }); + GfxDrawSprite(dpi, ImageId(imageStart + 0), screenCoords + ScreenCoordsXY{ 0, 28 }); + GfxDrawSprite(dpi, ImageId(imageStart + 2), screenCoords + ScreenCoordsXY{ 32, 44 }); + break; + case 1: + GfxDrawSprite(dpi, ImageId(imageStart + 1), screenCoords + ScreenCoordsXY{ 32, 14 }); + GfxDrawSprite(dpi, ImageId(imageStart + 0), screenCoords + ScreenCoordsXY{ 0, 28 }); + GfxDrawSprite(dpi, ImageId(imageStart + 2), screenCoords + ScreenCoordsXY{ -32, 44 }); + break; + case 2: + GfxDrawSprite(dpi, ImageId(imageStart + 2), screenCoords + ScreenCoordsXY{ -32, 14 }); + GfxDrawSprite(dpi, ImageId(imageStart + 0), screenCoords + ScreenCoordsXY{ 0, 28 }); + GfxDrawSprite(dpi, ImageId(imageStart + 1), screenCoords + ScreenCoordsXY{ 32, 44 }); + break; + case 3: + GfxDrawSprite(dpi, ImageId(imageStart + 2), screenCoords + ScreenCoordsXY{ 32, 14 }); + GfxDrawSprite(dpi, ImageId(imageStart + 0), screenCoords + ScreenCoordsXY{ 0, 28 }); + GfxDrawSprite(dpi, ImageId(imageStart + 1), screenCoords + ScreenCoordsXY{ -32, 44 }); + break; + } + } + + CoordsXYZD PlaceParkEntranceGetMapPosition(const ScreenCoordsXY& screenCoords) + { + CoordsXYZD parkEntranceMapPosition{ 0, 0, 0, INVALID_DIRECTION }; + const CoordsXY mapCoords = ViewportInteractionGetTileStartAtCursor(screenCoords); + parkEntranceMapPosition = { mapCoords.x, mapCoords.y, 0, INVALID_DIRECTION }; + if (parkEntranceMapPosition.IsNull()) + return parkEntranceMapPosition; + + auto surfaceElement = MapGetSurfaceElementAt(mapCoords); + if (surfaceElement == nullptr) + { + parkEntranceMapPosition.SetNull(); + return parkEntranceMapPosition; + } + + parkEntranceMapPosition.z = surfaceElement->GetWaterHeight(); + if (parkEntranceMapPosition.z == 0) + { + parkEntranceMapPosition.z = surfaceElement->GetBaseZ(); + if ((surfaceElement->GetSlope() & kTileSlopeRaisedCornersMask) != 0) + { + parkEntranceMapPosition.z += 16; + if (surfaceElement->GetSlope() & kTileSlopeDiagonalFlag) + { + parkEntranceMapPosition.z += 16; + } + } + } + parkEntranceMapPosition.direction = (gWindowSceneryRotation - GetCurrentRotation()) & 3; + return parkEntranceMapPosition; + } + + void PlaceParkEntranceToolUpdate(const ScreenCoordsXY& screenCoords) + { + MapInvalidateSelectionRect(); + MapInvalidateMapSelectionTiles(); + gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE; + gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_ARROW; + gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT; + CoordsXYZD parkEntrancePosition = PlaceParkEntranceGetMapPosition(screenCoords); + if (parkEntrancePosition.IsNull()) + { + ParkEntranceRemoveGhost(); + return; + } + + int32_t sideDirection = (parkEntrancePosition.direction + 1) & 3; + gMapSelectionTiles.clear(); + gMapSelectionTiles.push_back({ parkEntrancePosition.x, parkEntrancePosition.y }); + gMapSelectionTiles.push_back({ parkEntrancePosition.x + CoordsDirectionDelta[sideDirection].x, + parkEntrancePosition.y + CoordsDirectionDelta[sideDirection].y }); + gMapSelectionTiles.push_back({ parkEntrancePosition.x - CoordsDirectionDelta[sideDirection].x, + parkEntrancePosition.y - CoordsDirectionDelta[sideDirection].y }); + + gMapSelectArrowPosition = parkEntrancePosition; + gMapSelectArrowDirection = parkEntrancePosition.direction; + + gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE_CONSTRUCT | MAP_SELECT_FLAG_ENABLE_ARROW; + MapInvalidateMapSelectionTiles(); + if (gParkEntranceGhostExists && parkEntrancePosition == gParkEntranceGhostPosition) + { + return; + } + + ParkEntranceRemoveGhost(); + + auto gameAction = ParkEntrancePlaceAction(parkEntrancePosition, gFootpathSelectedId, _selectedEntranceType); + gameAction.SetFlags(GAME_COMMAND_FLAG_GHOST); + + auto result = GameActions::Execute(&gameAction); + if (result.Error == GameActions::Status::Ok) + { + gParkEntranceGhostPosition = parkEntrancePosition; + gParkEntranceGhostExists = true; + } + } + + void PlaceParkEntranceToolDown(const ScreenCoordsXY& screenCoords) + { + ParkEntranceRemoveGhost(); + + CoordsXYZD parkEntrancePosition = PlaceParkEntranceGetMapPosition(screenCoords); + if (!parkEntrancePosition.IsNull()) + { + auto gameAction = ParkEntrancePlaceAction(parkEntrancePosition, gFootpathSelectedId, _selectedEntranceType); + auto result = GameActions::Execute(&gameAction); + if (result.Error == GameActions::Status::Ok) + { + Audio::Play3D(Audio::SoundId::PlaceItem, result.Position); + } + } + } + + ObjectEntryIndex ScrollGetEntranceListItemAt(const ScreenCoordsXY& screenCoords) + { + if (screenCoords.x <= 0 || screenCoords.y <= 0) + return OBJECT_ENTRY_INDEX_NULL; + + size_t column = screenCoords.x / kImageSize; + size_t row = screenCoords.y / kImageSize; + if (column >= 5) + return OBJECT_ENTRY_INDEX_NULL; + + size_t index = column + (row * 5); + if (index >= _entranceTypes.size()) + return OBJECT_ENTRY_INDEX_NULL; + + return _entranceTypes[index].entryIndex; + } + + public: + void OnOpen() override + { + widgets = _widgets; + + InitScrollWidgets(); + + list_information_type = 0; + min_width = kWindowWidth; + min_height = kWindowHeight; + max_width = kWindowWidth; + max_height = kWindowHeight; + + InitParkEntranceItems(); + pressed_widgets |= 1LL << WIDX_TAB; + + ToolSet(*this, WIDX_LIST, Tool::EntranceDown); + InputSetFlag(INPUT_FLAG_6, true); + } + + void OnMouseUp(WidgetIndex widgetIndex) override + { + switch (widgetIndex) + { + case WIDX_CLOSE: + Close(); + break; + case WIDX_ROTATE_ENTRANCE_BUTTON: + gWindowSceneryRotation = DirectionNext(gWindowSceneryRotation); + Invalidate(); + break; + } + } + + void OnClose() override + { + if (gCurrentToolWidget.window_classification == classification) + ToolCancel(); + } + + void OnUpdate() override + { + if (gCurrentToolWidget.window_classification != classification) + Close(); + } + + void OnDraw(DrawPixelInfo& dpi) override + { + DrawWidgets(dpi); + GfxDrawSprite( + dpi, ImageId(SPR_TAB_PARK_ENTRANCE), + windowPos + ScreenCoordsXY{ widgets[WIDX_TAB].left, widgets[WIDX_TAB].top }); + } + + void OnScrollDraw(int32_t scrollIndex, DrawPixelInfo& dpi) override + { + GfxClear(dpi, ColourMapA[colours[1].colour].mid_light); + + ScreenCoordsXY coords{ 1, 1 }; + + for (auto& entranceType : _entranceTypes) + { + // Draw flat button rectangle + int32_t buttonFlags = 0; + if (_selectedEntranceType == entranceType.entryIndex) + buttonFlags |= INSET_RECT_FLAG_BORDER_INSET; + else if (_highlightedEntranceType == entranceType.entryIndex) + buttonFlags |= INSET_RECT_FLAG_FILL_MID_LIGHT; + + if (buttonFlags != 0) + GfxFillRectInset( + dpi, { coords, coords + ScreenCoordsXY{ kImageSize - 1, kImageSize - 1 } }, colours[1], + INSET_RECT_FLAG_FILL_MID_LIGHT | buttonFlags); + + DrawPixelInfo clipDPI; + auto screenPos = coords + ScreenCoordsXY{ kScrollPadding, kScrollPadding }; + if (ClipDrawPixelInfo( + clipDPI, dpi, screenPos, kImageSize - (2 * kScrollPadding), kImageSize - (2 * kScrollPadding))) + { + PaintPreview( + clipDPI, entranceType.imageId, ScreenCoordsXY{ kImageSize / 2, kImageSize / 2 }, + gWindowSceneryRotation); + } + + // Next position + coords.x += kImageSize; + if (coords.x >= kImageSize * kNumColumns + 1) + { + coords.x = 1; + coords.y += kImageSize; + } + } + } + + void OnToolDown(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) override + { + PlaceParkEntranceToolDown(screenCoords); + } + + void OnToolUpdate(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) override + { + PlaceParkEntranceToolUpdate(screenCoords); + } + + void OnToolAbort(WidgetIndex widgetIndex) override + { + ParkEntranceRemoveGhost(); + Invalidate(); + HideGridlines(); + HideLandRights(); + HideConstructionRights(); + } + + void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override + { + auto highlighted = ScrollGetEntranceListItemAt(screenCoords); + if (highlighted != OBJECT_ENTRY_INDEX_NULL) + { + _highlightedEntranceType = highlighted; + Invalidate(); + } + } + + void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override + { + auto selected = ScrollGetEntranceListItemAt(screenCoords); + if (selected == OBJECT_ENTRY_INDEX_NULL) + { + return; + } + + _selectedEntranceType = selected; + + Audio::Play(Audio::SoundId::Click1, 0, windowPos.x + (width / 2)); + Invalidate(); + } + }; + + WindowBase* EditorParkEntranceOpen() + { + WindowBase* window; + + // Check if window is already open + window = WindowBringToFrontByClass(WindowClass::EditorParkEntrance); + if (window != nullptr) + return window; + + window = WindowCreate( + WindowClass::EditorParkEntrance, kWindowWidth, kWindowHeight, WF_10 | WF_RESIZABLE); + + return window; + } +} // namespace OpenRCT2::Ui::Windows diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp index c714895f80..69f7282319 100644 --- a/src/openrct2-ui/windows/Map.cpp +++ b/src/openrct2-ui/windows/Map.cpp @@ -7,11 +7,10 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ -#include "../interface/ViewportInteraction.h" -#include "../interface/ViewportQuery.h" - #include #include +#include +#include #include #include #include @@ -22,21 +21,17 @@ #include #include #include -#include #include #include #include #include #include #include -#include -#include #include #include #include #include #include -#include #include #include #include @@ -126,12 +121,9 @@ namespace OpenRCT2::Ui::Windows WIDX_CONSTRUCTION_RIGHTS_OWNED_CHECKBOX, WIDX_LAND_SALE_CHECKBOX, WIDX_CONSTRUCTION_RIGHTS_SALE_CHECKBOX, - WIDX_ROTATE_90, WIDX_MAP_GENERATOR }; - validate_global_widx(WC_MAP, WIDX_ROTATE_90); - // clang-format off static Widget window_map_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), @@ -152,7 +144,6 @@ static Widget window_map_widgets[] = { MakeWidget ({ 58, 197}, {184, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CONSTRUCTION_RIGHTS_OWNED, STR_SET_CONSTRUCTION_RIGHTS_TO_BE_OWNED_TIP ), MakeWidget ({ 58, 197}, {184, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_LAND_SALE, STR_SET_LAND_TO_BE_AVAILABLE_TIP ), MakeWidget ({ 58, 197}, {174, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CONSTRUCTION_RIGHTS_SALE, STR_SET_CONSTRUCTION_RIGHTS_TO_BE_AVAILABLE_TIP), - MakeWidget ({218, 45}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_ROTATE_ARROW), STR_ROTATE_OBJECTS_90 ), MakeWidget ({110, 189}, {131, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_MAPGEN_WINDOW_TITLE, STR_MAP_GENERATOR_TIP ), kWidgetsEnd, }; @@ -334,20 +325,13 @@ static Widget window_map_widgets[] = { Invalidate(); break; case WIDX_BUILD_PARK_ENTRANCE: - Invalidate(); - if (ToolSet(*this, widgetIndex, Tool::UpArrow)) - break; - - gParkEntranceGhostExists = false; - InputSetFlag(INPUT_FLAG_6, true); - - ShowGridlines(); - ShowLandRights(); - ShowConstructionRights(); - break; - case WIDX_ROTATE_90: - gWindowSceneryRotation = (gWindowSceneryRotation + 1) & 3; + { + if (!WindowFindByClass(WindowClass::EditorParkEntrance)) + ContextOpenWindow(WindowClass::EditorParkEntrance); + else + WindowCloseByClass(WindowClass::EditorParkEntrance); break; + } case WIDX_PEOPLE_STARTING_POSITION: if (ToolSet(*this, widgetIndex, Tool::UpArrow)) break; @@ -475,9 +459,6 @@ static Widget window_map_widgets[] = { case WIDX_SET_LAND_RIGHTS: SetLandRightsToolUpdate(screenCoords); break; - case WIDX_BUILD_PARK_ENTRANCE: - PlaceParkEntranceToolUpdate(screenCoords); - break; case WIDX_PEOPLE_STARTING_POSITION: SetPeepSpawnToolUpdate(screenCoords); break; @@ -488,9 +469,6 @@ static Widget window_map_widgets[] = { { switch (widgetIndex) { - case WIDX_BUILD_PARK_ENTRANCE: - PlaceParkEntranceToolDown(screenCoords); - break; case WIDX_PEOPLE_STARTING_POSITION: SetPeepSpawnToolDown(screenCoords); break; @@ -523,13 +501,6 @@ static Widget window_map_widgets[] = { HideLandRights(); HideConstructionRights(); break; - case WIDX_BUILD_PARK_ENTRANCE: - ParkEntranceRemoveGhost(); - Invalidate(); - HideGridlines(); - HideLandRights(); - HideConstructionRights(); - break; case WIDX_PEOPLE_STARTING_POSITION: Invalidate(); HideGridlines(); @@ -569,99 +540,6 @@ static Widget window_map_widgets[] = { MapInvalidateSelectionRect(); } - CoordsXYZD PlaceParkEntranceGetMapPosition(const ScreenCoordsXY& screenCoords) - { - CoordsXYZD parkEntranceMapPosition{ 0, 0, 0, INVALID_DIRECTION }; - const CoordsXY mapCoords = ViewportInteractionGetTileStartAtCursor(screenCoords); - parkEntranceMapPosition = { mapCoords.x, mapCoords.y, 0, INVALID_DIRECTION }; - if (parkEntranceMapPosition.IsNull()) - return parkEntranceMapPosition; - - auto surfaceElement = MapGetSurfaceElementAt(mapCoords); - if (surfaceElement == nullptr) - { - parkEntranceMapPosition.SetNull(); - return parkEntranceMapPosition; - } - - parkEntranceMapPosition.z = surfaceElement->GetWaterHeight(); - if (parkEntranceMapPosition.z == 0) - { - parkEntranceMapPosition.z = surfaceElement->GetBaseZ(); - if ((surfaceElement->GetSlope() & kTileSlopeRaisedCornersMask) != 0) - { - parkEntranceMapPosition.z += 16; - if (surfaceElement->GetSlope() & kTileSlopeDiagonalFlag) - { - parkEntranceMapPosition.z += 16; - } - } - } - parkEntranceMapPosition.direction = (gWindowSceneryRotation - GetCurrentRotation()) & 3; - return parkEntranceMapPosition; - } - - void PlaceParkEntranceToolUpdate(const ScreenCoordsXY& screenCoords) - { - MapInvalidateSelectionRect(); - MapInvalidateMapSelectionTiles(); - gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE; - gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_ARROW; - gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT; - CoordsXYZD parkEntrancePosition = PlaceParkEntranceGetMapPosition(screenCoords); - if (parkEntrancePosition.IsNull()) - { - ParkEntranceRemoveGhost(); - return; - } - - int32_t sideDirection = (parkEntrancePosition.direction + 1) & 3; - gMapSelectionTiles.clear(); - gMapSelectionTiles.push_back({ parkEntrancePosition.x, parkEntrancePosition.y }); - gMapSelectionTiles.push_back({ parkEntrancePosition.x + CoordsDirectionDelta[sideDirection].x, - parkEntrancePosition.y + CoordsDirectionDelta[sideDirection].y }); - gMapSelectionTiles.push_back({ parkEntrancePosition.x - CoordsDirectionDelta[sideDirection].x, - parkEntrancePosition.y - CoordsDirectionDelta[sideDirection].y }); - - gMapSelectArrowPosition = parkEntrancePosition; - gMapSelectArrowDirection = parkEntrancePosition.direction; - - gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE_CONSTRUCT | MAP_SELECT_FLAG_ENABLE_ARROW; - MapInvalidateMapSelectionTiles(); - if (gParkEntranceGhostExists && parkEntrancePosition == gParkEntranceGhostPosition) - { - return; - } - - ParkEntranceRemoveGhost(); - - auto gameAction = ParkEntrancePlaceAction(parkEntrancePosition, gFootpathSelectedId); - gameAction.SetFlags(GAME_COMMAND_FLAG_GHOST); - - auto result = GameActions::Execute(&gameAction); - if (result.Error == GameActions::Status::Ok) - { - gParkEntranceGhostPosition = parkEntrancePosition; - gParkEntranceGhostExists = true; - } - } - - void PlaceParkEntranceToolDown(const ScreenCoordsXY& screenCoords) - { - ParkEntranceRemoveGhost(); - - CoordsXYZD parkEntrancePosition = PlaceParkEntranceGetMapPosition(screenCoords); - if (!parkEntrancePosition.IsNull()) - { - auto gameAction = ParkEntrancePlaceAction(parkEntrancePosition, gFootpathSelectedId); - auto result = GameActions::Execute(&gameAction); - if (result.Error == GameActions::Status::Ok) - { - Audio::Play3D(Audio::SoundId::PlaceItem, result.Position); - } - } - } - void SetPeepSpawnToolUpdate(const ScreenCoordsXY& screenCoords) { int32_t direction; @@ -881,6 +759,9 @@ static Widget window_map_widgets[] = { if (_activeTool & (1 << 0)) pressed_widgets |= (1uLL << WIDX_CONSTRUCTION_RIGHTS_OWNED_CHECKBOX); + if (WindowFindByClass(WindowClass::EditorParkEntrance)) + pressed_widgets |= (1uLL << WIDX_BUILD_PARK_ENTRANCE); + // Set disabled widgets auto& gameState = GetGameState(); SetWidgetDisabled(WIDX_MAP_SIZE_LINK, gameState.MapSize.x != gameState.MapSize.y); @@ -908,8 +789,6 @@ static Widget window_map_widgets[] = { widgets[WIDX_SET_LAND_RIGHTS].bottom = height - 70 + 23; widgets[WIDX_BUILD_PARK_ENTRANCE].top = height - 46; widgets[WIDX_BUILD_PARK_ENTRANCE].bottom = height - 46 + 23; - widgets[WIDX_ROTATE_90].top = height - 46; - widgets[WIDX_ROTATE_90].bottom = height - 46 + 23; widgets[WIDX_PEOPLE_STARTING_POSITION].top = height - 46; widgets[WIDX_PEOPLE_STARTING_POSITION].bottom = height - 46 + 23; @@ -941,13 +820,6 @@ static Widget window_map_widgets[] = { if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || GetGameState().Cheats.SandboxMode) { - // scenario editor: build park entrance selected, show rotate button - if ((InputTestFlag(INPUT_FLAG_TOOL_ACTIVE)) && gCurrentToolWidget.window_classification == WindowClass::Map - && gCurrentToolWidget.widget_index == WIDX_BUILD_PARK_ENTRANCE) - { - widgets[WIDX_ROTATE_90].type = WindowWidgetType::FlatBtn; - } - // Always show set land rights button widgets[WIDX_SET_LAND_RIGHTS].type = WindowWidgetType::FlatBtn; diff --git a/src/openrct2-ui/windows/Themes.cpp b/src/openrct2-ui/windows/Themes.cpp index 3e7814d0ec..2ba167e351 100644 --- a/src/openrct2-ui/windows/Themes.cpp +++ b/src/openrct2-ui/windows/Themes.cpp @@ -149,6 +149,7 @@ static WindowClass window_themes_tab_1_classes[] = { static WindowClass window_themes_tab_2_classes[] = { WindowClass::ParkInformation, + WindowClass::EditorParkEntrance, WindowClass::Finances, WindowClass::NewCampaign, WindowClass::Research, diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index 8f135fb7f2..f120f888d4 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -90,6 +90,7 @@ namespace OpenRCT2::Ui::Windows WindowBase* ViewClippingOpen(); WindowBase* TransparencyOpen(); WindowBase* AssetPacksOpen(); + WindowBase* EditorParkEntranceOpen(); // WC_FINANCES WindowBase* FinancesOpen(); diff --git a/src/openrct2/EditorObjectSelectionSession.cpp b/src/openrct2/EditorObjectSelectionSession.cpp index a89ff15af4..0f010fda93 100644 --- a/src/openrct2/EditorObjectSelectionSession.cpp +++ b/src/openrct2/EditorObjectSelectionSession.cpp @@ -194,7 +194,8 @@ void SetupInUseSelectionFlags() if (parkEntranceEl->GetEntranceType() != ENTRANCE_TYPE_PARK_ENTRANCE) break; - Editor::SetSelectedObject(ObjectType::ParkEntrance, 0, ObjectSelectionFlags::InUse); + type = iter.element->AsEntrance()->getEntryIndex(); + Editor::SetSelectedObject(ObjectType::ParkEntrance, type, ObjectSelectionFlags::InUse); // Skip if not the middle part if (parkEntranceEl->GetSequenceIndex() != 0) @@ -692,9 +693,8 @@ int32_t EditorRemoveUnusedObjects() if (ObjectTypeIsIntransient(objectType)) continue; - // These object types require exactly one object to be selected at all times. - // Removing that object can badly break the game state. - if (objectType == ObjectType::ParkEntrance || objectType == ObjectType::Water) + // The water type controls the entire palette. Removing that object can badly break the game state. + if (objectType == ObjectType::Water) continue; // It’s hard to determine exactly if a scenery group is used, so do not remove these automatically. diff --git a/src/openrct2/actions/ParkEntrancePlaceAction.cpp b/src/openrct2/actions/ParkEntrancePlaceAction.cpp index fc56bf0b4d..8ad58ec0c8 100644 --- a/src/openrct2/actions/ParkEntrancePlaceAction.cpp +++ b/src/openrct2/actions/ParkEntrancePlaceAction.cpp @@ -24,9 +24,11 @@ using namespace OpenRCT2; -ParkEntrancePlaceAction::ParkEntrancePlaceAction(const CoordsXYZD& location, ObjectEntryIndex pathType) +ParkEntrancePlaceAction::ParkEntrancePlaceAction( + const CoordsXYZD& location, ObjectEntryIndex pathType, ObjectEntryIndex entranceType) : _loc(location) , _pathType(pathType) + , _entranceType(entranceType) { } @@ -34,6 +36,7 @@ void ParkEntrancePlaceAction::AcceptParameters(GameActionParameterVisitor& visit { visitor.Visit(_loc); visitor.Visit("footpathSurfaceObject", _pathType); + visitor.Visit("entranceObject", _entranceType); } uint16_t ParkEntrancePlaceAction::GetActionFlags() const @@ -47,6 +50,7 @@ void ParkEntrancePlaceAction::Serialise(DataSerialiser& stream) stream << DS_TAG(_loc); stream << DS_TAG(_pathType); + stream << DS_TAG(_entranceType); } GameActions::Result ParkEntrancePlaceAction::Query() const @@ -156,6 +160,7 @@ GameActions::Result ParkEntrancePlaceAction::Execute() const entranceElement->SetDirection(_loc.direction); entranceElement->SetSequenceIndex(index); entranceElement->SetEntranceType(ENTRANCE_TYPE_PARK_ENTRANCE); + entranceElement->setEntryIndex(_entranceType); if (gFootpathSelection.LegacyPath == OBJECT_ENTRY_INDEX_NULL) { entranceElement->SetSurfaceEntryIndex(gFootpathSelection.NormalSurface); diff --git a/src/openrct2/actions/ParkEntrancePlaceAction.h b/src/openrct2/actions/ParkEntrancePlaceAction.h index 006eeb1123..137357f6e0 100644 --- a/src/openrct2/actions/ParkEntrancePlaceAction.h +++ b/src/openrct2/actions/ParkEntrancePlaceAction.h @@ -16,10 +16,11 @@ class ParkEntrancePlaceAction final : public GameActionBase + diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index 32273c985e..7954508464 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -49,7 +49,7 @@ using namespace OpenRCT2; // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -constexpr uint8_t kNetworkStreamVersion = 1; +constexpr uint8_t kNetworkStreamVersion = 2; const std::string kNetworkStreamID = std::string(OPENRCT2_VERSION) + "-" + std::to_string(kNetworkStreamVersion); diff --git a/src/openrct2/object/EntranceObject.cpp b/src/openrct2/object/EntranceObject.cpp index 1a2000c1ca..d527b8b2f7 100644 --- a/src/openrct2/object/EntranceObject.cpp +++ b/src/openrct2/object/EntranceObject.cpp @@ -13,6 +13,8 @@ #include "../core/Json.hpp" #include "../core/String.hpp" #include "../drawing/Drawing.h" +#include "../localisation/LocalisationService.h" +#include "../paint/tile_element/Paint.TileElement.h" using namespace OpenRCT2; @@ -45,7 +47,6 @@ void EntranceObject::Unload() void EntranceObject::DrawPreview(DrawPixelInfo& dpi, int32_t width, int32_t height) const { auto screenCoords = ScreenCoordsXY{ width / 2, height / 2 }; - GfxDrawSprite(dpi, ImageId(_legacyType.image_id + 1), screenCoords + ScreenCoordsXY{ -32, 14 }); GfxDrawSprite(dpi, ImageId(_legacyType.image_id + 0), screenCoords + ScreenCoordsXY{ 0, 28 }); GfxDrawSprite(dpi, ImageId(_legacyType.image_id + 2), screenCoords + ScreenCoordsXY{ 32, 44 }); diff --git a/src/openrct2/object/ObjectLimits.h b/src/openrct2/object/ObjectLimits.h index 7ee211c21b..563d54a3c3 100644 --- a/src/openrct2/object/ObjectLimits.h +++ b/src/openrct2/object/ObjectLimits.h @@ -21,7 +21,7 @@ constexpr uint16_t MAX_BANNER_OBJECTS = 255; constexpr uint16_t MAX_PATH_OBJECTS = 255; constexpr uint16_t MAX_PATH_ADDITION_OBJECTS = 255; constexpr uint16_t MAX_SCENERY_GROUP_OBJECTS = 255; -constexpr uint16_t MAX_PARK_ENTRANCE_OBJECTS = 1; +constexpr uint16_t MAX_PARK_ENTRANCE_OBJECTS = 4; constexpr uint16_t MAX_WATER_OBJECTS = 1; constexpr uint16_t MAX_SCENARIO_TEXT_OBJECTS = 0; constexpr uint16_t MAX_TERRAIN_SURFACE_OBJECTS = 255; diff --git a/src/openrct2/paint/tile_element/Paint.Entrance.cpp b/src/openrct2/paint/tile_element/Paint.Entrance.cpp index 39cf0831b2..3f3e6d1a71 100644 --- a/src/openrct2/paint/tile_element/Paint.Entrance.cpp +++ b/src/openrct2/paint/tile_element/Paint.Entrance.cpp @@ -284,7 +284,8 @@ static void PaintParkEntrance(PaintSession& session, uint8_t direction, int32_t } auto& objManager = GetContext()->GetObjectManager(); - auto entrance = reinterpret_cast(objManager.GetLoadedObject(ObjectType::ParkEntrance, 0)); + auto entrance = reinterpret_cast( + objManager.GetLoadedObject(ObjectType::ParkEntrance, entranceEl.getEntryIndex())); auto sequence = entranceEl.GetSequenceIndex(); switch (sequence) { diff --git a/src/openrct2/park/ParkFile.h b/src/openrct2/park/ParkFile.h index da6bf79e7c..e538ac9fbb 100644 --- a/src/openrct2/park/ParkFile.h +++ b/src/openrct2/park/ParkFile.h @@ -11,7 +11,7 @@ namespace OpenRCT2 struct GameState_t; // Current version that is saved. - constexpr uint32_t PARK_FILE_CURRENT_VERSION = 34; + constexpr uint32_t PARK_FILE_CURRENT_VERSION = 35; // The minimum version that is forwards compatible with the current version. constexpr uint32_t PARK_FILE_MIN_VERSION = 33; diff --git a/src/openrct2/world/Entrance.cpp b/src/openrct2/world/Entrance.cpp index e5ed5e23c9..a10b6ac9e2 100644 --- a/src/openrct2/world/Entrance.cpp +++ b/src/openrct2/world/Entrance.cpp @@ -236,107 +236,3 @@ void ParkEntranceUpdateLocations() } } } - -StationIndex EntranceElement::GetStationIndex() const -{ - return stationIndex; -} - -void EntranceElement::SetStationIndex(StationIndex newStationIndex) -{ - stationIndex = newStationIndex; -} - -uint8_t EntranceElement::GetEntranceType() const -{ - return entranceType; -} - -void EntranceElement::SetEntranceType(uint8_t newType) -{ - entranceType = newType; -} - -RideId EntranceElement::GetRideIndex() const -{ - return rideIndex; -} - -void EntranceElement::SetRideIndex(RideId newRideIndex) -{ - rideIndex = newRideIndex; -} - -uint8_t EntranceElement::GetSequenceIndex() const -{ - return SequenceIndex & 0xF; -} - -void EntranceElement::SetSequenceIndex(uint8_t newSequenceIndex) -{ - SequenceIndex &= ~0xF; - SequenceIndex |= (newSequenceIndex & 0xF); -} - -bool EntranceElement::HasLegacyPathEntry() const -{ - return (flags2 & ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY) != 0; -} - -ObjectEntryIndex EntranceElement::GetLegacyPathEntryIndex() const -{ - if (HasLegacyPathEntry()) - return PathType; - - return OBJECT_ENTRY_INDEX_NULL; -} - -const FootpathObject* EntranceElement::GetLegacyPathEntry() const -{ - auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); - return static_cast(objMgr.GetLoadedObject(ObjectType::Paths, GetLegacyPathEntryIndex())); -} - -void EntranceElement::SetLegacyPathEntryIndex(ObjectEntryIndex newPathType) -{ - PathType = newPathType; - flags2 |= ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY; -} - -ObjectEntryIndex EntranceElement::GetSurfaceEntryIndex() const -{ - if (HasLegacyPathEntry()) - return OBJECT_ENTRY_INDEX_NULL; - - return PathType; -} - -const FootpathSurfaceObject* EntranceElement::GetSurfaceEntry() const -{ - auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); - return static_cast(objMgr.GetLoadedObject(ObjectType::FootpathSurface, GetSurfaceEntryIndex())); -} - -void EntranceElement::SetSurfaceEntryIndex(ObjectEntryIndex newIndex) -{ - PathType = newIndex; - flags2 &= ~ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY; -} - -const PathSurfaceDescriptor* EntranceElement::GetPathSurfaceDescriptor() const -{ - if (HasLegacyPathEntry()) - { - const auto* legacyPathEntry = GetLegacyPathEntry(); - if (legacyPathEntry == nullptr) - return nullptr; - - return &legacyPathEntry->GetPathSurfaceDescriptor(); - } - - const auto* surfaceEntry = GetSurfaceEntry(); - if (surfaceEntry == nullptr) - return nullptr; - - return &surfaceEntry->GetDescriptor(); -} diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 927e01e8ba..d551f5bb30 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -87,13 +87,6 @@ const std::array DirectionOffsets = { { 0, -1 }, }; -// rct2: 0x0097B974 -static constexpr uint16_t EntranceDirections[] = { - (4), 0, 0, 0, 0, 0, 0, 0, // ENTRANCE_TYPE_RIDE_ENTRANCE, - (4), 0, 0, 0, 0, 0, 0, 0, // ENTRANCE_TYPE_RIDE_EXIT, - (4 | 1), 0, 0, 0, 0, 0, 0, 0, // ENTRANCE_TYPE_PARK_ENTRANCE -}; - /** rct2: 0x0098D7F0 */ static constexpr uint8_t connected_path_count[] = { 0, // 0b0000 @@ -114,11 +107,6 @@ static constexpr uint8_t connected_path_count[] = { 4, // 0b1111 }; -int32_t EntranceElement::GetDirections() const -{ - return EntranceDirections[(GetEntranceType() * 8) + GetSequenceIndex()]; -} - static bool entrance_has_direction(const EntranceElement& entranceElement, int32_t direction) { return entranceElement.GetDirections() & (1 << (direction & 3)); diff --git a/src/openrct2/world/TileElement.h b/src/openrct2/world/TileElement.h index ec5a46fb5a..74e78d7a29 100644 --- a/src/openrct2/world/TileElement.h +++ b/src/openrct2/world/TileElement.h @@ -553,15 +553,16 @@ struct EntranceElement : TileElementBase static constexpr TileElementType ElementType = TileElementType::Entrance; private: - uint8_t entranceType; // 5 - uint8_t SequenceIndex; // 6. Only uses the lower nibble. - StationIndex stationIndex; // 7 - ObjectEntryIndex PathType; // 8 - RideId rideIndex; // A - uint8_t flags2; // C + uint8_t entranceType; // 5 + uint8_t SequenceIndex; // 6. Only uses the lower nibble. + StationIndex stationIndex; // 7 + ObjectEntryIndex PathType; // 8 + RideId rideIndex; // A + uint8_t flags2; // C + ObjectEntryIndex entryIndex; // D #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" - uint8_t Pad0D[3]; + uint8_t Pad0F[1]; #pragma clang diagnostic pop public: @@ -590,6 +591,9 @@ public: const PathSurfaceDescriptor* GetPathSurfaceDescriptor() const; int32_t GetDirections() const; + + ObjectEntryIndex getEntryIndex() const; + void setEntryIndex(ObjectEntryIndex newIndex); }; static_assert(sizeof(EntranceElement) == 16); diff --git a/src/openrct2/world/tile_element/EntranceElement.cpp b/src/openrct2/world/tile_element/EntranceElement.cpp new file mode 100644 index 0000000000..86ce7cfa43 --- /dev/null +++ b/src/openrct2/world/tile_element/EntranceElement.cpp @@ -0,0 +1,142 @@ +/***************************************************************************** + * Copyright (c) 2014-2024 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "../../Context.h" +#include "../../object/EntranceObject.h" +#include "../../object/FootpathObject.h" +#include "../../object/FootpathSurfaceObject.h" +#include "../../object/ObjectManager.h" +#include "../Entrance.h" +#include "../TileElement.h" + +// rct2: 0x0097B974 +static constexpr uint16_t EntranceDirections[] = { + (4), 0, 0, 0, 0, 0, 0, 0, // ENTRANCE_TYPE_RIDE_ENTRANCE, + (4), 0, 0, 0, 0, 0, 0, 0, // ENTRANCE_TYPE_RIDE_EXIT, + (4 | 1), 0, 0, 0, 0, 0, 0, 0, // ENTRANCE_TYPE_PARK_ENTRANCE +}; + +uint8_t EntranceElement::GetEntranceType() const +{ + return entranceType; +} + +void EntranceElement::SetEntranceType(uint8_t newType) +{ + entranceType = newType; +} + +RideId EntranceElement::GetRideIndex() const +{ + return rideIndex; +} + +void EntranceElement::SetRideIndex(RideId newRideIndex) +{ + rideIndex = newRideIndex; +} + +StationIndex EntranceElement::GetStationIndex() const +{ + return stationIndex; +} + +void EntranceElement::SetStationIndex(StationIndex newStationIndex) +{ + stationIndex = newStationIndex; +} + +uint8_t EntranceElement::GetSequenceIndex() const +{ + return SequenceIndex & 0xF; +} + +void EntranceElement::SetSequenceIndex(uint8_t newSequenceIndex) +{ + SequenceIndex &= ~0xF; + SequenceIndex |= (newSequenceIndex & 0xF); +} + +bool EntranceElement::HasLegacyPathEntry() const +{ + return (flags2 & ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY) != 0; +} + +ObjectEntryIndex EntranceElement::GetLegacyPathEntryIndex() const +{ + if (HasLegacyPathEntry()) + return PathType; + + return OBJECT_ENTRY_INDEX_NULL; +} + +const FootpathObject* EntranceElement::GetLegacyPathEntry() const +{ + auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); + return static_cast(objMgr.GetLoadedObject(ObjectType::Paths, GetLegacyPathEntryIndex())); +} + +void EntranceElement::SetLegacyPathEntryIndex(ObjectEntryIndex newPathType) +{ + PathType = newPathType; + flags2 |= ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY; +} + +ObjectEntryIndex EntranceElement::GetSurfaceEntryIndex() const +{ + if (HasLegacyPathEntry()) + return OBJECT_ENTRY_INDEX_NULL; + + return PathType; +} + +const FootpathSurfaceObject* EntranceElement::GetSurfaceEntry() const +{ + auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); + return static_cast(objMgr.GetLoadedObject(ObjectType::FootpathSurface, GetSurfaceEntryIndex())); +} + +void EntranceElement::SetSurfaceEntryIndex(ObjectEntryIndex newIndex) +{ + PathType = newIndex; + flags2 &= ~ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY; +} + +const PathSurfaceDescriptor* EntranceElement::GetPathSurfaceDescriptor() const +{ + if (HasLegacyPathEntry()) + { + const auto* legacyPathEntry = GetLegacyPathEntry(); + if (legacyPathEntry == nullptr) + return nullptr; + + return &legacyPathEntry->GetPathSurfaceDescriptor(); + } + + const auto* surfaceEntry = GetSurfaceEntry(); + if (surfaceEntry == nullptr) + return nullptr; + + return &surfaceEntry->GetDescriptor(); +} + +int32_t EntranceElement::GetDirections() const +{ + return EntranceDirections[(GetEntranceType() * 8) + GetSequenceIndex()]; +} + +ObjectEntryIndex EntranceElement::getEntryIndex() const +{ + return entryIndex; +} + +void EntranceElement::setEntryIndex(ObjectEntryIndex newIndex) +{ + entryIndex = newIndex; +}