From a07b56a6553613a0ce14b911feead6766e1ebfef Mon Sep 17 00:00:00 2001 From: Duncan Date: Fri, 2 Aug 2024 06:01:31 +0100 Subject: [PATCH] Move Viewport functions into Ui (#22454) * Move viewport functions into ui * Move footpath function to ui * Don't include viewport in footpath.h * Include missing includes --- .../engines/HardwareDisplayDrawingEngine.cpp | 1 + src/openrct2-ui/input/MouseInput.cpp | 1 + .../interface/ViewportInteraction.cpp | 1340 +++++++++-------- .../interface/ViewportInteraction.h | 21 + src/openrct2-ui/interface/ViewportQuery.cpp | 178 +++ src/openrct2-ui/interface/ViewportQuery.h | 19 + src/openrct2-ui/libopenrct2ui.vcxproj | 5 +- src/openrct2-ui/ride/Construction.cpp | 131 ++ src/openrct2-ui/ride/Construction.h | 1 + src/openrct2-ui/scripting/CustomListView.cpp | 1 + src/openrct2-ui/scripting/CustomListView.h | 2 + src/openrct2-ui/scripting/CustomMenu.cpp | 2 + src/openrct2-ui/windows/ClearScenery.cpp | 2 + src/openrct2-ui/windows/Footpath.cpp | 2 + src/openrct2-ui/windows/Guest.cpp | 2 + src/openrct2-ui/windows/Land.cpp | 2 + src/openrct2-ui/windows/Map.cpp | 3 + src/openrct2-ui/windows/MazeConstruction.cpp | 2 + src/openrct2-ui/windows/PatrolArea.cpp | 2 + src/openrct2-ui/windows/Player.cpp | 2 + src/openrct2-ui/windows/RideConstruction.cpp | 1 + src/openrct2-ui/windows/Scenery.cpp | 1 + src/openrct2-ui/windows/Staff.cpp | 1 + src/openrct2-ui/windows/StaffList.cpp | 2 + src/openrct2-ui/windows/TileInspector.cpp | 1 + src/openrct2-ui/windows/TrackDesignPlace.cpp | 1 + src/openrct2-ui/windows/Transparency.cpp | 1 + src/openrct2-ui/windows/Water.cpp | 1 + src/openrct2/ReplayManager.cpp | 1 + src/openrct2/actions/GameSetSpeedAction.cpp | 1 + src/openrct2/actions/LoadOrQuitAction.h | 1 + .../actions/RideFreezeRatingAction.cpp | 1 + src/openrct2/actions/RideSetSettingAction.cpp | 1 + src/openrct2/entity/EntityBase.cpp | 1 + src/openrct2/entity/Peep.cpp | 1 + src/openrct2/interface/Viewport.h | 6 - src/openrct2/network/NetworkBase.h | 1 + src/openrct2/object/ObjectManager.cpp | 1 + src/openrct2/paint/Painter.cpp | 1 + src/openrct2/paint/support/WoodenSupports.cpp | 1 + .../paint/tile_element/Paint.PathAddition.cpp | 1 + src/openrct2/ride/Ride.cpp | 1 + src/openrct2/ride/Ride.h | 1 + src/openrct2/ride/RideConstruction.cpp | 128 -- src/openrct2/ride/RideConstruction.h | 2 - src/openrct2/ride/TrackDesign.h | 1 + .../scenes/title/Command/SetLocation.cpp | 1 + src/openrct2/world/Footpath.cpp | 160 +- src/openrct2/world/Footpath.h | 4 +- 49 files changed, 1079 insertions(+), 965 deletions(-) create mode 100644 src/openrct2-ui/interface/ViewportInteraction.h create mode 100644 src/openrct2-ui/interface/ViewportQuery.cpp create mode 100644 src/openrct2-ui/interface/ViewportQuery.h diff --git a/src/openrct2-ui/drawing/engines/HardwareDisplayDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/HardwareDisplayDrawingEngine.cpp index e1c4fcc02b..95ab91c5ba 100644 --- a/src/openrct2-ui/drawing/engines/HardwareDisplayDrawingEngine.cpp +++ b/src/openrct2-ui/drawing/engines/HardwareDisplayDrawingEngine.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/src/openrct2-ui/input/MouseInput.cpp b/src/openrct2-ui/input/MouseInput.cpp index 9c1ce3bb63..c0f4efc9af 100644 --- a/src/openrct2-ui/input/MouseInput.cpp +++ b/src/openrct2-ui/input/MouseInput.cpp @@ -8,6 +8,7 @@ *****************************************************************************/ #include "../UiStringIds.h" +#include "../interface/ViewportInteraction.h" #include #include diff --git a/src/openrct2-ui/interface/ViewportInteraction.cpp b/src/openrct2-ui/interface/ViewportInteraction.cpp index 4a44fb10b9..e3cff73dd7 100644 --- a/src/openrct2-ui/interface/ViewportInteraction.cpp +++ b/src/openrct2-ui/interface/ViewportInteraction.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "ViewportInteraction.h" + #include "../UiStringIds.h" #include "../windows/Window.h" #include "Viewport.h" @@ -54,761 +56,767 @@ using namespace OpenRCT2; using namespace OpenRCT2::Ui::Windows; -static void ViewportInteractionRemoveScenery(const SmallSceneryElement& smallSceneryElement, const CoordsXY& mapCoords); -static void ViewportInteractionRemoveFootpath(const PathElement& pathElement, const CoordsXY& mapCoords); -static void ViewportInteractionRemovePathAddition(const PathElement& pathElement, const CoordsXY& mapCoords); -static void ViewportInteractionRemoveParkWall(const WallElement& wallElement, const CoordsXY& mapCoords); -static void ViewportInteractionRemoveLargeScenery(const LargeSceneryElement& largeSceneryElement, const CoordsXY& mapCoords); -static void ViewportInteractionRemoveParkEntrance(const EntranceElement& entranceElement, CoordsXY mapCoords); -static Peep* ViewportInteractionGetClosestPeep(ScreenCoordsXY screenCoords, int32_t maxDistance); - -/** - * - * rct2: 0x006ED9D0 - */ -static InteractionInfo ViewportInteractionGetItemLeft(const ScreenCoordsXY& screenCoords) +namespace OpenRCT2::Ui { - InteractionInfo info{}; - // No click input for scenario editor or track manager - if (gScreenFlags & (SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_MANAGER)) - return info; + static void ViewportInteractionRemoveScenery(const SmallSceneryElement& smallSceneryElement, const CoordsXY& mapCoords); + static void ViewportInteractionRemoveFootpath(const PathElement& pathElement, const CoordsXY& mapCoords); + static void ViewportInteractionRemovePathAddition(const PathElement& pathElement, const CoordsXY& mapCoords); + static void ViewportInteractionRemoveParkWall(const WallElement& wallElement, const CoordsXY& mapCoords); + static void ViewportInteractionRemoveLargeScenery( + const LargeSceneryElement& largeSceneryElement, const CoordsXY& mapCoords); + static void ViewportInteractionRemoveParkEntrance(const EntranceElement& entranceElement, CoordsXY mapCoords); + static Peep* ViewportInteractionGetClosestPeep(ScreenCoordsXY screenCoords, int32_t maxDistance); - // - if ((gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) && GetGameState().EditorStep != EditorStep::RollercoasterDesigner) - return info; - - info = GetMapCoordinatesFromPos( - screenCoords, - EnumsToFlags(ViewportInteractionItem::Entity, ViewportInteractionItem::Ride, ViewportInteractionItem::ParkEntrance)); - auto tileElement = info.SpriteType != ViewportInteractionItem::Entity ? info.Element : nullptr; - // Only valid when info.SpriteType == ViewportInteractionItem::Entity, but can't assign nullptr without compiler - // complaining - auto sprite = info.Entity; - - // Allows only balloons to be popped and ducks to be quacked in title screen - if (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) + /** + * + * rct2: 0x006ED9D0 + */ + static InteractionInfo ViewportInteractionGetItemLeft(const ScreenCoordsXY& screenCoords) { - if (info.SpriteType == ViewportInteractionItem::Entity && (sprite->Is() || sprite->Is())) + InteractionInfo info{}; + // No click input for scenario editor or track manager + if (gScreenFlags & (SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_MANAGER)) return info; - info.SpriteType = ViewportInteractionItem::None; - return info; - } + // + if ((gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) && GetGameState().EditorStep != EditorStep::RollercoasterDesigner) + return info; - switch (info.SpriteType) - { - case ViewportInteractionItem::Entity: - switch (sprite->Type) - { - case EntityType::Vehicle: - { - auto vehicle = sprite->As(); - if (vehicle != nullptr && !vehicle->IsCableLift()) - vehicle->SetMapToolbar(); - else - info.SpriteType = ViewportInteractionItem::None; - } - break; - case EntityType::Guest: - case EntityType::Staff: - { - auto peep = sprite->As(); - if (peep != nullptr) - { - PeepSetMapTooltip(peep); - } - else - { - info.SpriteType = ViewportInteractionItem::None; - } - } - break; - default: - break; - } - break; - case ViewportInteractionItem::Ride: - Guard::ArgumentNotNull(tileElement); - RideSetMapTooltip(*tileElement); - break; - case ViewportInteractionItem::ParkEntrance: + info = GetMapCoordinatesFromPos( + screenCoords, + EnumsToFlags( + ViewportInteractionItem::Entity, ViewportInteractionItem::Ride, ViewportInteractionItem::ParkEntrance)); + auto tileElement = info.SpriteType != ViewportInteractionItem::Entity ? info.Element : nullptr; + // Only valid when info.SpriteType == ViewportInteractionItem::Entity, but can't assign nullptr without compiler + // complaining + auto sprite = info.Entity; + + // Allows only balloons to be popped and ducks to be quacked in title screen + if (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) { - auto& gameState = GetGameState(); - auto parkName = gameState.Park.Name.c_str(); + if (info.SpriteType == ViewportInteractionItem::Entity && (sprite->Is() || sprite->Is())) + return info; - auto ft = Formatter(); - ft.Add(STR_STRING); - ft.Add(parkName); - SetMapTooltip(ft); - break; - } - default: info.SpriteType = ViewportInteractionItem::None; - break; - } - - // If nothing is under cursor, find a close by peep - if (info.SpriteType == ViewportInteractionItem::None) - { - auto peep = ViewportInteractionGetClosestPeep(screenCoords, 32); - if (peep != nullptr) - { - info.Entity = peep; - info.SpriteType = ViewportInteractionItem::Entity; - info.Loc.x = peep->x; - info.Loc.y = peep->y; - PeepSetMapTooltip(peep); + return info; } - } - return info; -} - -bool ViewportInteractionLeftOver(const ScreenCoordsXY& screenCoords) -{ - auto info = ViewportInteractionGetItemLeft(screenCoords); - - switch (info.SpriteType) - { - case ViewportInteractionItem::Entity: - case ViewportInteractionItem::Ride: - case ViewportInteractionItem::ParkEntrance: - return true; - default: - return false; - } -} - -bool ViewportInteractionLeftClick(const ScreenCoordsXY& screenCoords) -{ - auto info = ViewportInteractionGetItemLeft(screenCoords); - - switch (info.SpriteType) - { - case ViewportInteractionItem::Entity: + switch (info.SpriteType) { - auto entity = info.Entity; - switch (entity->Type) - { - case EntityType::Vehicle: + case ViewportInteractionItem::Entity: + switch (sprite->Type) { - auto intent = Intent(WD_VEHICLE); - intent.PutExtra(INTENT_EXTRA_VEHICLE, entity); - ContextOpenIntent(&intent); - break; - } - case EntityType::Guest: - case EntityType::Staff: - { - auto intent = Intent(WindowClass::Peep); - intent.PutExtra(INTENT_EXTRA_PEEP, entity); - ContextOpenIntent(&intent); - break; - } - case EntityType::Balloon: - { - if (GameIsNotPaused()) + case EntityType::Vehicle: { - auto balloonPress = BalloonPressAction(entity->Id); - GameActions::Execute(&balloonPress); + auto vehicle = sprite->As(); + if (vehicle != nullptr && !vehicle->IsCableLift()) + vehicle->SetMapToolbar(); + else + info.SpriteType = ViewportInteractionItem::None; } - } - break; - case EntityType::Duck: - { - if (GameIsNotPaused()) + break; + case EntityType::Guest: + case EntityType::Staff: { - auto duck = entity->As(); - if (duck != nullptr) + auto peep = sprite->As(); + if (peep != nullptr) { - duck->Press(); + PeepSetMapTooltip(peep); + } + else + { + info.SpriteType = ViewportInteractionItem::None; } } + break; + default: + break; } break; - default: - break; - } - return true; - } - case ViewportInteractionItem::Ride: - { - auto intent = Intent(WD_TRACK); - intent.PutExtra(INTENT_EXTRA_TILE_ELEMENT, info.Element); - ContextOpenIntent(&intent); - return true; - } - case ViewportInteractionItem::ParkEntrance: - ContextOpenWindow(WindowClass::ParkInformation); - return true; - default: - return false; - } -} - -/** - * - * rct2: 0x006EDE88 - */ -static InteractionInfo ViewportInteractionGetItemRight(const ScreenCoordsXY& screenCoords) -{ - Ride* ride; - int32_t i; - InteractionInfo info{}; - // No click input for title screen or track manager - if (gScreenFlags & (SCREEN_FLAGS_TITLE_DEMO | SCREEN_FLAGS_TRACK_MANAGER)) - return info; - - // - if ((gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) && GetGameState().EditorStep != EditorStep::RollercoasterDesigner) - return info; - - constexpr auto flags = static_cast( - ~EnumsToFlags(ViewportInteractionItem::Terrain, ViewportInteractionItem::Water)); - info = GetMapCoordinatesFromPos(screenCoords, flags); - auto tileElement = info.Element; - - switch (info.SpriteType) - { - case ViewportInteractionItem::Entity: - { - auto sprite = info.Entity; - if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || sprite->Type != EntityType::Vehicle) + case ViewportInteractionItem::Ride: + Guard::ArgumentNotNull(tileElement); + RideSetMapTooltip(*tileElement); + break; + case ViewportInteractionItem::ParkEntrance: { - info.SpriteType = ViewportInteractionItem::None; - return info; - } + auto& gameState = GetGameState(); + auto parkName = gameState.Park.Name.c_str(); - auto vehicle = sprite->As(); - if (vehicle == nullptr) - { - info.SpriteType = ViewportInteractionItem::None; - return info; - } - ride = GetRide(vehicle->ride); - if (ride != nullptr && ride->status == RideStatus::Closed) - { auto ft = Formatter(); - ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); - ride->FormatNameTo(ft); + ft.Add(STR_STRING); + ft.Add(parkName); SetMapTooltip(ft); + break; } - return info; + default: + info.SpriteType = ViewportInteractionItem::None; + break; } - case ViewportInteractionItem::Ride: + + // If nothing is under cursor, find a close by peep + if (info.SpriteType == ViewportInteractionItem::None) { - if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) + auto peep = ViewportInteractionGetClosestPeep(screenCoords, 32); + if (peep != nullptr) { - info.SpriteType = ViewportInteractionItem::None; - return info; - } - if (tileElement->GetType() == TileElementType::Path) - { - info.SpriteType = ViewportInteractionItem::None; - return info; + info.Entity = peep; + info.SpriteType = ViewportInteractionItem::Entity; + info.Loc.x = peep->x; + info.Loc.y = peep->y; + PeepSetMapTooltip(peep); } + } - ride = GetRide(tileElement->GetRideIndex()); - if (ride == nullptr) - { - info.SpriteType = ViewportInteractionItem::None; - return info; - } + return info; + } - if (ride->status != RideStatus::Closed) - return info; + bool ViewportInteractionLeftOver(const ScreenCoordsXY& screenCoords) + { + auto info = ViewportInteractionGetItemLeft(screenCoords); - auto ft = Formatter(); - ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); + switch (info.SpriteType) + { + case ViewportInteractionItem::Entity: + case ViewportInteractionItem::Ride: + case ViewportInteractionItem::ParkEntrance: + return true; + default: + return false; + } + } - if (tileElement->GetType() == TileElementType::Entrance) + bool ViewportInteractionLeftClick(const ScreenCoordsXY& screenCoords) + { + auto info = ViewportInteractionGetItemLeft(screenCoords); + + switch (info.SpriteType) + { + case ViewportInteractionItem::Entity: { - StringId stringId; - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE) + auto entity = info.Entity; + switch (entity->Type) { - if (ride->num_stations > 1) + case EntityType::Vehicle: { - stringId = STR_RIDE_STATION_X_ENTRANCE; + auto intent = Intent(WD_VEHICLE); + intent.PutExtra(INTENT_EXTRA_VEHICLE, entity); + ContextOpenIntent(&intent); + break; } - else + case EntityType::Guest: + case EntityType::Staff: { - stringId = STR_RIDE_ENTRANCE; + auto intent = Intent(WindowClass::Peep); + intent.PutExtra(INTENT_EXTRA_PEEP, entity); + ContextOpenIntent(&intent); + break; } + case EntityType::Balloon: + { + if (GameIsNotPaused()) + { + auto balloonPress = BalloonPressAction(entity->Id); + GameActions::Execute(&balloonPress); + } + } + break; + case EntityType::Duck: + { + if (GameIsNotPaused()) + { + auto duck = entity->As(); + if (duck != nullptr) + { + duck->Press(); + } + } + } + break; + default: + break; } - else - { - if (ride->num_stations > 1) - { - stringId = STR_RIDE_STATION_X_EXIT; - } - else - { - stringId = STR_RIDE_EXIT; - } - } - ft.Add(stringId); + return true; } - else if (tileElement->AsTrack()->IsStation()) + case ViewportInteractionItem::Ride: { - StringId stringId; - if (ride->num_stations > 1) - { - stringId = STR_RIDE_STATION_X; - } - else - { - stringId = STR_RIDE_STATION; - } - ft.Add(stringId); + auto intent = Intent(WD_TRACK); + intent.PutExtra(INTENT_EXTRA_TILE_ELEMENT, info.Element); + ContextOpenIntent(&intent); + return true; } - else + case ViewportInteractionItem::ParkEntrance: + ContextOpenWindow(WindowClass::ParkInformation); + return true; + default: + return false; + } + } + + /** + * + * rct2: 0x006EDE88 + */ + static InteractionInfo ViewportInteractionGetItemRight(const ScreenCoordsXY& screenCoords) + { + Ride* ride; + int32_t i; + InteractionInfo info{}; + // No click input for title screen or track manager + if (gScreenFlags & (SCREEN_FLAGS_TITLE_DEMO | SCREEN_FLAGS_TRACK_MANAGER)) + return info; + + // + if ((gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) && GetGameState().EditorStep != EditorStep::RollercoasterDesigner) + return info; + + constexpr auto flags = static_cast( + ~EnumsToFlags(ViewportInteractionItem::Terrain, ViewportInteractionItem::Water)); + info = GetMapCoordinatesFromPos(screenCoords, flags); + auto tileElement = info.Element; + + switch (info.SpriteType) + { + case ViewportInteractionItem::Entity: { - // FIXME: Why does it *2 the value? - if (!GetGameState().Cheats.SandboxMode && !MapIsLocationOwned({ info.Loc, tileElement->GetBaseZ() * 2 })) + auto sprite = info.Entity; + if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || sprite->Type != EntityType::Vehicle) { info.SpriteType = ViewportInteractionItem::None; return info; } - ride->FormatNameTo(ft); + auto vehicle = sprite->As(); + if (vehicle == nullptr) + { + info.SpriteType = ViewportInteractionItem::None; + return info; + } + ride = GetRide(vehicle->ride); + if (ride != nullptr && ride->status == RideStatus::Closed) + { + auto ft = Formatter(); + ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); + ride->FormatNameTo(ft); + SetMapTooltip(ft); + } return info; } - - ride->FormatNameTo(ft); - - const auto& rtd = ride->GetRideTypeDescriptor(); - ft.Add(GetRideComponentName(rtd.NameConvention.station).capitalised); - - StationIndex::UnderlyingType stationIndex; - if (tileElement->GetType() == TileElementType::Entrance) - stationIndex = tileElement->AsEntrance()->GetStationIndex().ToUnderlying(); - else - stationIndex = tileElement->AsTrack()->GetStationIndex().ToUnderlying(); - - for (i = stationIndex; i >= 0; i--) - if (ride->GetStations()[i].Start.IsNull()) - stationIndex--; - stationIndex++; - ft.Add(stationIndex); - SetMapTooltip(ft); - return info; - } - case ViewportInteractionItem::Wall: - { - auto* wallEntry = tileElement->AsWall()->GetEntry(); - if (wallEntry->scrolling_mode != SCROLLING_MODE_NONE) + case ViewportInteractionItem::Ride: { - auto banner = tileElement->AsWall()->GetBanner(); - if (banner != nullptr) + if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) { - auto ft = Formatter(); - ft.Add(STR_MAP_TOOLTIP_BANNER_STRINGID_STRINGID); - banner->FormatTextTo(ft); - ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); - ft.Add(wallEntry->name); - SetMapTooltip(ft); + info.SpriteType = ViewportInteractionItem::None; return info; } - } - break; - } - case ViewportInteractionItem::LargeScenery: - { - auto* sceneryEntry = tileElement->AsLargeScenery()->GetEntry(); - if (sceneryEntry->scrolling_mode != SCROLLING_MODE_NONE) - { - auto banner = tileElement->AsLargeScenery()->GetBanner(); - if (banner != nullptr) + if (tileElement->GetType() == TileElementType::Path) { - auto ft = Formatter(); - ft.Add(STR_MAP_TOOLTIP_BANNER_STRINGID_STRINGID); - banner->FormatTextTo(ft); - ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); - ft.Add(sceneryEntry->name); - SetMapTooltip(ft); + info.SpriteType = ViewportInteractionItem::None; return info; } - } - break; - } - case ViewportInteractionItem::Banner: - { - auto banner = tileElement->AsBanner()->GetBanner(); - if (banner != nullptr) - { - auto* bannerEntry = ObjectManager::GetObjectEntry(banner->type); + + ride = GetRide(tileElement->GetRideIndex()); + if (ride == nullptr) + { + info.SpriteType = ViewportInteractionItem::None; + return info; + } + + if (ride->status != RideStatus::Closed) + return info; auto ft = Formatter(); - ft.Add(STR_MAP_TOOLTIP_BANNER_STRINGID_STRINGID); - banner->FormatTextTo(ft, /*addColour*/ true); ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); - ft.Add(bannerEntry->name); + + if (tileElement->GetType() == TileElementType::Entrance) + { + StringId stringId; + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE) + { + if (ride->num_stations > 1) + { + stringId = STR_RIDE_STATION_X_ENTRANCE; + } + else + { + stringId = STR_RIDE_ENTRANCE; + } + } + else + { + if (ride->num_stations > 1) + { + stringId = STR_RIDE_STATION_X_EXIT; + } + else + { + stringId = STR_RIDE_EXIT; + } + } + ft.Add(stringId); + } + else if (tileElement->AsTrack()->IsStation()) + { + StringId stringId; + if (ride->num_stations > 1) + { + stringId = STR_RIDE_STATION_X; + } + else + { + stringId = STR_RIDE_STATION; + } + ft.Add(stringId); + } + else + { + // FIXME: Why does it *2 the value? + if (!GetGameState().Cheats.SandboxMode && !MapIsLocationOwned({ info.Loc, tileElement->GetBaseZ() * 2 })) + { + info.SpriteType = ViewportInteractionItem::None; + return info; + } + + ride->FormatNameTo(ft); + return info; + } + + ride->FormatNameTo(ft); + + const auto& rtd = ride->GetRideTypeDescriptor(); + ft.Add(GetRideComponentName(rtd.NameConvention.station).capitalised); + + StationIndex::UnderlyingType stationIndex; + if (tileElement->GetType() == TileElementType::Entrance) + stationIndex = tileElement->AsEntrance()->GetStationIndex().ToUnderlying(); + else + stationIndex = tileElement->AsTrack()->GetStationIndex().ToUnderlying(); + + for (i = stationIndex; i >= 0; i--) + if (ride->GetStations()[i].Start.IsNull()) + stationIndex--; + stationIndex++; + ft.Add(stationIndex); SetMapTooltip(ft); return info; } - break; - } - default: - break; - } - - if (!(InputTestFlag(INPUT_FLAG_6)) || !(InputTestFlag(INPUT_FLAG_TOOL_ACTIVE))) - { - if (WindowFindByClass(WindowClass::RideConstruction) == nullptr && WindowFindByClass(WindowClass::Footpath) == nullptr) - { - info.SpriteType = ViewportInteractionItem::None; - return info; - } - } - - auto ft = Formatter(); - switch (info.SpriteType) - { - case ViewportInteractionItem::Scenery: - { - auto* sceneryEntry = tileElement->AsSmallScenery()->GetEntry(); - ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); - ft.Add(sceneryEntry->name); - SetMapTooltip(ft); - return info; - } - case ViewportInteractionItem::Footpath: - ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); - if (tileElement->AsPath()->IsQueue()) - ft.Add(STR_QUEUE_LINE_MAP_TIP); - else - ft.Add(STR_FOOTPATH_MAP_TIP); - SetMapTooltip(ft); - return info; - - case ViewportInteractionItem::PathAddition: - { - auto* pathAddEntry = tileElement->AsPath()->GetAdditionEntry(); - ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); - if (tileElement->AsPath()->IsBroken()) + case ViewportInteractionItem::Wall: { - ft.Add(STR_BROKEN); - } - ft.Add(pathAddEntry != nullptr ? pathAddEntry->name : STR_NONE); - SetMapTooltip(ft); - return info; - } - case ViewportInteractionItem::ParkEntrance: - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !GetGameState().Cheats.SandboxMode) - break; - - if (tileElement->GetType() != TileElementType::Entrance) - break; - - ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); - ft.Add(STR_OBJECT_SELECTION_PARK_ENTRANCE); - SetMapTooltip(ft); - return info; - - case ViewportInteractionItem::Wall: - { - auto* wallEntry = tileElement->AsWall()->GetEntry(); - ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); - ft.Add(wallEntry->name); - SetMapTooltip(ft); - return info; - } - case ViewportInteractionItem::LargeScenery: - { - auto* sceneryEntry = tileElement->AsLargeScenery()->GetEntry(); - ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); - ft.Add(sceneryEntry->name); - SetMapTooltip(ft); - return info; - } - default: - break; - } - - info.SpriteType = ViewportInteractionItem::None; - return info; -} - -bool ViewportInteractionRightOver(const ScreenCoordsXY& screenCoords) -{ - auto info = ViewportInteractionGetItemRight(screenCoords); - - return info.SpriteType != ViewportInteractionItem::None; -} - -/** - * - * rct2: 0x006E8A62 - */ -bool ViewportInteractionRightClick(const ScreenCoordsXY& screenCoords) -{ - CoordsXYE tileElement; - auto info = ViewportInteractionGetItemRight(screenCoords); - - switch (info.SpriteType) - { - case ViewportInteractionItem::None: - case ViewportInteractionItem::Terrain: - case ViewportInteractionItem::Water: - case ViewportInteractionItem::Label: - return false; - - case ViewportInteractionItem::Entity: - { - auto entity = info.Entity; - if (entity->Type == EntityType::Vehicle) - { - auto vehicle = entity->As(); - if (vehicle == nullptr) + auto* wallEntry = tileElement->AsWall()->GetEntry(); + if (wallEntry->scrolling_mode != SCROLLING_MODE_NONE) { + auto banner = tileElement->AsWall()->GetBanner(); + if (banner != nullptr) + { + auto ft = Formatter(); + ft.Add(STR_MAP_TOOLTIP_BANNER_STRINGID_STRINGID); + banner->FormatTextTo(ft); + ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); + ft.Add(wallEntry->name); + SetMapTooltip(ft); + return info; + } + } + break; + } + case ViewportInteractionItem::LargeScenery: + { + auto* sceneryEntry = tileElement->AsLargeScenery()->GetEntry(); + if (sceneryEntry->scrolling_mode != SCROLLING_MODE_NONE) + { + auto banner = tileElement->AsLargeScenery()->GetBanner(); + if (banner != nullptr) + { + auto ft = Formatter(); + ft.Add(STR_MAP_TOOLTIP_BANNER_STRINGID_STRINGID); + banner->FormatTextTo(ft); + ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); + ft.Add(sceneryEntry->name); + SetMapTooltip(ft); + return info; + } + } + break; + } + case ViewportInteractionItem::Banner: + { + auto banner = tileElement->AsBanner()->GetBanner(); + if (banner != nullptr) + { + auto* bannerEntry = ObjectManager::GetObjectEntry(banner->type); + + auto ft = Formatter(); + ft.Add(STR_MAP_TOOLTIP_BANNER_STRINGID_STRINGID); + banner->FormatTextTo(ft, /*addColour*/ true); + ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); + ft.Add(bannerEntry->name); + SetMapTooltip(ft); + return info; + } + break; + } + default: + break; + } + + if (!(InputTestFlag(INPUT_FLAG_6)) || !(InputTestFlag(INPUT_FLAG_TOOL_ACTIVE))) + { + if (WindowFindByClass(WindowClass::RideConstruction) == nullptr + && WindowFindByClass(WindowClass::Footpath) == nullptr) + { + info.SpriteType = ViewportInteractionItem::None; + return info; + } + } + + auto ft = Formatter(); + switch (info.SpriteType) + { + case ViewportInteractionItem::Scenery: + { + auto* sceneryEntry = tileElement->AsSmallScenery()->GetEntry(); + ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); + ft.Add(sceneryEntry->name); + SetMapTooltip(ft); + return info; + } + case ViewportInteractionItem::Footpath: + ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); + if (tileElement->AsPath()->IsQueue()) + ft.Add(STR_QUEUE_LINE_MAP_TIP); + else + ft.Add(STR_FOOTPATH_MAP_TIP); + SetMapTooltip(ft); + return info; + + case ViewportInteractionItem::PathAddition: + { + auto* pathAddEntry = tileElement->AsPath()->GetAdditionEntry(); + ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); + if (tileElement->AsPath()->IsBroken()) + { + ft.Add(STR_BROKEN); + } + ft.Add(pathAddEntry != nullptr ? pathAddEntry->name : STR_NONE); + SetMapTooltip(ft); + return info; + } + case ViewportInteractionItem::ParkEntrance: + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !GetGameState().Cheats.SandboxMode) break; - } - auto ride = GetRide(vehicle->ride); - if (ride != nullptr) + + if (tileElement->GetType() != TileElementType::Entrance) + break; + + ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); + ft.Add(STR_OBJECT_SELECTION_PARK_ENTRANCE); + SetMapTooltip(ft); + return info; + + case ViewportInteractionItem::Wall: + { + auto* wallEntry = tileElement->AsWall()->GetEntry(); + ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); + ft.Add(wallEntry->name); + SetMapTooltip(ft); + return info; + } + case ViewportInteractionItem::LargeScenery: + { + auto* sceneryEntry = tileElement->AsLargeScenery()->GetEntry(); + ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_REMOVE); + ft.Add(sceneryEntry->name); + SetMapTooltip(ft); + return info; + } + default: + break; + } + + info.SpriteType = ViewportInteractionItem::None; + return info; + } + + bool ViewportInteractionRightOver(const ScreenCoordsXY& screenCoords) + { + auto info = ViewportInteractionGetItemRight(screenCoords); + + return info.SpriteType != ViewportInteractionItem::None; + } + + /** + * + * rct2: 0x006E8A62 + */ + bool ViewportInteractionRightClick(const ScreenCoordsXY& screenCoords) + { + CoordsXYE tileElement; + auto info = ViewportInteractionGetItemRight(screenCoords); + + switch (info.SpriteType) + { + case ViewportInteractionItem::None: + case ViewportInteractionItem::Terrain: + case ViewportInteractionItem::Water: + case ViewportInteractionItem::Label: + return false; + + case ViewportInteractionItem::Entity: + { + auto entity = info.Entity; + if (entity->Type == EntityType::Vehicle) { - RideConstructionStart(*ride); + auto vehicle = entity->As(); + if (vehicle == nullptr) + { + break; + } + auto ride = GetRide(vehicle->ride); + if (ride != nullptr) + { + RideConstructionStart(*ride); + } } } + break; + case ViewportInteractionItem::Ride: + tileElement = { info.Loc, info.Element }; + RideModify(tileElement); + break; + case ViewportInteractionItem::Scenery: + ViewportInteractionRemoveScenery(*info.Element->AsSmallScenery(), info.Loc); + break; + case ViewportInteractionItem::Footpath: + ViewportInteractionRemoveFootpath(*info.Element->AsPath(), info.Loc); + break; + case ViewportInteractionItem::PathAddition: + ViewportInteractionRemovePathAddition(*info.Element->AsPath(), info.Loc); + break; + case ViewportInteractionItem::ParkEntrance: + ViewportInteractionRemoveParkEntrance(*info.Element->AsEntrance(), info.Loc); + break; + case ViewportInteractionItem::Wall: + ViewportInteractionRemoveParkWall(*info.Element->AsWall(), info.Loc); + break; + case ViewportInteractionItem::LargeScenery: + ViewportInteractionRemoveLargeScenery(*info.Element->AsLargeScenery(), info.Loc); + break; + case ViewportInteractionItem::Banner: + ContextOpenDetailWindow(WD_BANNER, info.Element->AsBanner()->GetIndex().ToUnderlying()); + break; } - break; - case ViewportInteractionItem::Ride: - tileElement = { info.Loc, info.Element }; - RideModify(tileElement); - break; - case ViewportInteractionItem::Scenery: - ViewportInteractionRemoveScenery(*info.Element->AsSmallScenery(), info.Loc); - break; - case ViewportInteractionItem::Footpath: - ViewportInteractionRemoveFootpath(*info.Element->AsPath(), info.Loc); - break; - case ViewportInteractionItem::PathAddition: - ViewportInteractionRemovePathAddition(*info.Element->AsPath(), info.Loc); - break; - case ViewportInteractionItem::ParkEntrance: - ViewportInteractionRemoveParkEntrance(*info.Element->AsEntrance(), info.Loc); - break; - case ViewportInteractionItem::Wall: - ViewportInteractionRemoveParkWall(*info.Element->AsWall(), info.Loc); - break; - case ViewportInteractionItem::LargeScenery: - ViewportInteractionRemoveLargeScenery(*info.Element->AsLargeScenery(), info.Loc); - break; - case ViewportInteractionItem::Banner: - ContextOpenDetailWindow(WD_BANNER, info.Element->AsBanner()->GetIndex().ToUnderlying()); - break; + + return true; } - return true; -} - -/** - * - * rct2: 0x006E08D2 - */ -static void ViewportInteractionRemoveScenery(const SmallSceneryElement& smallSceneryElement, const CoordsXY& mapCoords) -{ - auto removeSceneryAction = SmallSceneryRemoveAction( - { mapCoords.x, mapCoords.y, smallSceneryElement.GetBaseZ() }, smallSceneryElement.GetSceneryQuadrant(), - smallSceneryElement.GetEntryIndex()); - - GameActions::Execute(&removeSceneryAction); -} - -/** - * - * rct2: 0x006A614A - */ -static void ViewportInteractionRemoveFootpath(const PathElement& pathElement, const CoordsXY& mapCoords) -{ - WindowBase* w = WindowFindByClass(WindowClass::Footpath); - if (w != nullptr) - FootpathProvisionalUpdate(); - - TileElement* tileElement2 = MapGetFirstElementAt(mapCoords); - if (tileElement2 == nullptr) - return; - - auto z = pathElement.GetBaseZ(); - do + /** + * + * rct2: 0x006E08D2 + */ + static void ViewportInteractionRemoveScenery(const SmallSceneryElement& smallSceneryElement, const CoordsXY& mapCoords) { - if (tileElement2->GetType() == TileElementType::Path && tileElement2->GetBaseZ() == z) - { - auto action = FootpathRemoveAction({ mapCoords, z }); - GameActions::Execute(&action); - break; - } - } while (!(tileElement2++)->IsLastForTile()); -} + auto removeSceneryAction = SmallSceneryRemoveAction( + { mapCoords.x, mapCoords.y, smallSceneryElement.GetBaseZ() }, smallSceneryElement.GetSceneryQuadrant(), + smallSceneryElement.GetEntryIndex()); -/** - * - * rct2: 0x006A61AB - */ -static void ViewportInteractionRemovePathAddition(const PathElement& pathElement, const CoordsXY& mapCoords) -{ - auto footpathAdditionRemoveAction = FootpathAdditionRemoveAction({ mapCoords.x, mapCoords.y, pathElement.GetBaseZ() }); - GameActions::Execute(&footpathAdditionRemoveAction); -} - -/** - * - * rct2: 0x00666C0E - */ -void ViewportInteractionRemoveParkEntrance(const EntranceElement& entranceElement, CoordsXY mapCoords) -{ - int32_t rotation = entranceElement.GetDirectionWithOffset(1); - switch (entranceElement.GetSequenceIndex()) - { - case 1: - mapCoords += CoordsDirectionDelta[rotation]; - break; - case 2: - mapCoords -= CoordsDirectionDelta[rotation]; - break; - } - auto parkEntranceRemoveAction = ParkEntranceRemoveAction({ mapCoords.x, mapCoords.y, entranceElement.GetBaseZ() }); - GameActions::Execute(&parkEntranceRemoveAction); -} - -/** - * - * rct2: 0x006E57A9 - */ -static void ViewportInteractionRemoveParkWall(const WallElement& wallElement, const CoordsXY& mapCoords) -{ - auto* wallEntry = wallElement.GetEntry(); - if (wallEntry->scrolling_mode != SCROLLING_MODE_NONE) - { - ContextOpenDetailWindow(WD_SIGN_SMALL, wallElement.GetBannerIndex().ToUnderlying()); - } - else - { - CoordsXYZD wallLocation = { mapCoords.x, mapCoords.y, wallElement.GetBaseZ(), wallElement.GetDirection() }; - auto wallRemoveAction = WallRemoveAction(wallLocation); - GameActions::Execute(&wallRemoveAction); - } -} - -/** - * - * rct2: 0x006B88DC - */ -static void ViewportInteractionRemoveLargeScenery(const LargeSceneryElement& largeSceneryElement, const CoordsXY& mapCoords) -{ - auto* sceneryEntry = largeSceneryElement.GetEntry(); - - if (sceneryEntry->scrolling_mode != SCROLLING_MODE_NONE) - { - auto bannerIndex = largeSceneryElement.GetBannerIndex(); - ContextOpenDetailWindow(WD_SIGN, bannerIndex.ToUnderlying()); - } - else - { - auto removeSceneryAction = LargeSceneryRemoveAction( - { mapCoords.x, mapCoords.y, largeSceneryElement.GetBaseZ(), largeSceneryElement.GetDirection() }, - largeSceneryElement.GetSequenceIndex()); GameActions::Execute(&removeSceneryAction); } -} -struct PeepDistance -{ - Peep* peep = nullptr; - int32_t distance = std::numeric_limits::max(); -}; - -template -static PeepDistance GetClosestPeep( - const ScreenCoordsXY& viewportCoords, uint8_t rotation, const int32_t maxDistance, PeepDistance goal) -{ - for (auto peep : EntityList()) + /** + * + * rct2: 0x006A614A + */ + static void ViewportInteractionRemoveFootpath(const PathElement& pathElement, const CoordsXY& mapCoords) { - if (peep->x == kLocationNull) - continue; + WindowBase* w = WindowFindByClass(WindowClass::Footpath); + if (w != nullptr) + FootpathProvisionalUpdate(); - auto screenCoords = Translate3DTo2DWithZ(rotation, peep->GetLocation()); - auto spriteRect = ScreenRect( - screenCoords - ScreenCoordsXY{ peep->SpriteData.Width, peep->SpriteData.HeightMin }, - screenCoords + ScreenCoordsXY{ peep->SpriteData.Width, peep->SpriteData.HeightMax }); + TileElement* tileElement2 = MapGetFirstElementAt(mapCoords); + if (tileElement2 == nullptr) + return; - auto distance = abs(((spriteRect.GetLeft() + spriteRect.GetRight()) / 2) - viewportCoords.x) - + abs(((spriteRect.GetTop() + spriteRect.GetBottom()) / 2) - viewportCoords.y); - if (distance > maxDistance) - continue; - - if (distance < goal.distance) + auto z = pathElement.GetBaseZ(); + do { - goal.peep = peep; - goal.distance = distance; + if (tileElement2->GetType() == TileElementType::Path && tileElement2->GetBaseZ() == z) + { + auto action = FootpathRemoveAction({ mapCoords, z }); + GameActions::Execute(&action); + break; + } + } while (!(tileElement2++)->IsLastForTile()); + } + + /** + * + * rct2: 0x006A61AB + */ + static void ViewportInteractionRemovePathAddition(const PathElement& pathElement, const CoordsXY& mapCoords) + { + auto footpathAdditionRemoveAction = FootpathAdditionRemoveAction({ mapCoords.x, mapCoords.y, pathElement.GetBaseZ() }); + GameActions::Execute(&footpathAdditionRemoveAction); + } + + /** + * + * rct2: 0x00666C0E + */ + void ViewportInteractionRemoveParkEntrance(const EntranceElement& entranceElement, CoordsXY mapCoords) + { + int32_t rotation = entranceElement.GetDirectionWithOffset(1); + switch (entranceElement.GetSequenceIndex()) + { + case 1: + mapCoords += CoordsDirectionDelta[rotation]; + break; + case 2: + mapCoords -= CoordsDirectionDelta[rotation]; + break; + } + auto parkEntranceRemoveAction = ParkEntranceRemoveAction({ mapCoords.x, mapCoords.y, entranceElement.GetBaseZ() }); + GameActions::Execute(&parkEntranceRemoveAction); + } + + /** + * + * rct2: 0x006E57A9 + */ + static void ViewportInteractionRemoveParkWall(const WallElement& wallElement, const CoordsXY& mapCoords) + { + auto* wallEntry = wallElement.GetEntry(); + if (wallEntry->scrolling_mode != SCROLLING_MODE_NONE) + { + ContextOpenDetailWindow(WD_SIGN_SMALL, wallElement.GetBannerIndex().ToUnderlying()); + } + else + { + CoordsXYZD wallLocation = { mapCoords.x, mapCoords.y, wallElement.GetBaseZ(), wallElement.GetDirection() }; + auto wallRemoveAction = WallRemoveAction(wallLocation); + GameActions::Execute(&wallRemoveAction); } } - return goal; -} -static Peep* ViewportInteractionGetClosestPeep(ScreenCoordsXY screenCoords, int32_t maxDistance) -{ - auto* w = WindowFindFromPoint(screenCoords); - if (w == nullptr) - return nullptr; - - auto* viewport = w->viewport; - if (viewport == nullptr || viewport->zoom >= ZoomLevel{ 2 }) - return nullptr; - - auto viewportCoords = viewport->ScreenToViewportCoord(screenCoords); - - PeepDistance goal; - if (!(viewport->flags & VIEWPORT_FLAG_HIDE_GUESTS)) - goal = GetClosestPeep(viewportCoords, viewport->rotation, maxDistance, goal); - if (!(viewport->flags & VIEWPORT_FLAG_HIDE_STAFF)) - goal = GetClosestPeep(viewportCoords, viewport->rotation, maxDistance, goal); - return goal.peep; -} - -/** - * - * rct2: 0x0068A15E - */ -CoordsXY ViewportInteractionGetTileStartAtCursor(const ScreenCoordsXY& screenCoords) -{ - WindowBase* window = WindowFindFromPoint(screenCoords); - if (window == nullptr || window->viewport == nullptr) + /** + * + * rct2: 0x006B88DC + */ + static void ViewportInteractionRemoveLargeScenery(const LargeSceneryElement& largeSceneryElement, const CoordsXY& mapCoords) { - CoordsXY ret{}; - ret.SetNull(); - return ret; - } - auto viewport = window->viewport; - auto info = GetMapCoordinatesFromPosWindow( - window, screenCoords, EnumsToFlags(ViewportInteractionItem::Terrain, ViewportInteractionItem::Water)); - auto initialPos = info.Loc; + auto* sceneryEntry = largeSceneryElement.GetEntry(); - if (info.SpriteType == ViewportInteractionItem::None) - { - initialPos.SetNull(); - return initialPos; - } - - int16_t waterHeight = 0; - if (info.SpriteType == ViewportInteractionItem::Water) - { - waterHeight = info.Element->AsSurface()->GetWaterHeight(); - } - - auto initialVPPos = viewport->ScreenToViewportCoord(screenCoords); - CoordsXY mapPos = initialPos + CoordsXY{ 16, 16 }; - - for (int32_t i = 0; i < 5; i++) - { - int16_t z = waterHeight; - if (info.SpriteType != ViewportInteractionItem::Water) + if (sceneryEntry->scrolling_mode != SCROLLING_MODE_NONE) { - z = TileElementHeight(mapPos); + auto bannerIndex = largeSceneryElement.GetBannerIndex(); + ContextOpenDetailWindow(WD_SIGN, bannerIndex.ToUnderlying()); + } + else + { + auto removeSceneryAction = LargeSceneryRemoveAction( + { mapCoords.x, mapCoords.y, largeSceneryElement.GetBaseZ(), largeSceneryElement.GetDirection() }, + largeSceneryElement.GetSequenceIndex()); + GameActions::Execute(&removeSceneryAction); } - mapPos = ViewportPosToMapPos(initialVPPos, z, viewport->rotation); - mapPos.x = std::clamp(mapPos.x, initialPos.x, initialPos.x + 31); - mapPos.y = std::clamp(mapPos.y, initialPos.y, initialPos.y + 31); } - return mapPos.ToTileStart(); -} + struct PeepDistance + { + Peep* peep = nullptr; + int32_t distance = std::numeric_limits::max(); + }; + + template + static PeepDistance GetClosestPeep( + const ScreenCoordsXY& viewportCoords, uint8_t rotation, const int32_t maxDistance, PeepDistance goal) + { + for (auto peep : EntityList()) + { + if (peep->x == kLocationNull) + continue; + + auto screenCoords = Translate3DTo2DWithZ(rotation, peep->GetLocation()); + auto spriteRect = ScreenRect( + screenCoords - ScreenCoordsXY{ peep->SpriteData.Width, peep->SpriteData.HeightMin }, + screenCoords + ScreenCoordsXY{ peep->SpriteData.Width, peep->SpriteData.HeightMax }); + + auto distance = abs(((spriteRect.GetLeft() + spriteRect.GetRight()) / 2) - viewportCoords.x) + + abs(((spriteRect.GetTop() + spriteRect.GetBottom()) / 2) - viewportCoords.y); + if (distance > maxDistance) + continue; + + if (distance < goal.distance) + { + goal.peep = peep; + goal.distance = distance; + } + } + return goal; + } + + static Peep* ViewportInteractionGetClosestPeep(ScreenCoordsXY screenCoords, int32_t maxDistance) + { + auto* w = WindowFindFromPoint(screenCoords); + if (w == nullptr) + return nullptr; + + auto* viewport = w->viewport; + if (viewport == nullptr || viewport->zoom >= ZoomLevel{ 2 }) + return nullptr; + + auto viewportCoords = viewport->ScreenToViewportCoord(screenCoords); + + PeepDistance goal; + if (!(viewport->flags & VIEWPORT_FLAG_HIDE_GUESTS)) + goal = GetClosestPeep(viewportCoords, viewport->rotation, maxDistance, goal); + if (!(viewport->flags & VIEWPORT_FLAG_HIDE_STAFF)) + goal = GetClosestPeep(viewportCoords, viewport->rotation, maxDistance, goal); + return goal.peep; + } + + /** + * + * rct2: 0x0068A15E + */ + CoordsXY ViewportInteractionGetTileStartAtCursor(const ScreenCoordsXY& screenCoords) + { + WindowBase* window = WindowFindFromPoint(screenCoords); + if (window == nullptr || window->viewport == nullptr) + { + CoordsXY ret{}; + ret.SetNull(); + return ret; + } + auto viewport = window->viewport; + auto info = GetMapCoordinatesFromPosWindow( + window, screenCoords, EnumsToFlags(ViewportInteractionItem::Terrain, ViewportInteractionItem::Water)); + auto initialPos = info.Loc; + + if (info.SpriteType == ViewportInteractionItem::None) + { + initialPos.SetNull(); + return initialPos; + } + + int16_t waterHeight = 0; + if (info.SpriteType == ViewportInteractionItem::Water) + { + waterHeight = info.Element->AsSurface()->GetWaterHeight(); + } + + auto initialVPPos = viewport->ScreenToViewportCoord(screenCoords); + CoordsXY mapPos = initialPos + CoordsXY{ 16, 16 }; + + for (int32_t i = 0; i < 5; i++) + { + int16_t z = waterHeight; + if (info.SpriteType != ViewportInteractionItem::Water) + { + z = TileElementHeight(mapPos); + } + mapPos = ViewportPosToMapPos(initialVPPos, z, viewport->rotation); + mapPos.x = std::clamp(mapPos.x, initialPos.x, initialPos.x + 31); + mapPos.y = std::clamp(mapPos.y, initialPos.y, initialPos.y + 31); + } + + return mapPos.ToTileStart(); + } +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/interface/ViewportInteraction.h b/src/openrct2-ui/interface/ViewportInteraction.h new file mode 100644 index 0000000000..755da6706a --- /dev/null +++ b/src/openrct2-ui/interface/ViewportInteraction.h @@ -0,0 +1,21 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +#pragma once +#include + +namespace OpenRCT2::Ui +{ + bool ViewportInteractionLeftOver(const ScreenCoordsXY& screenCoords); + bool ViewportInteractionLeftClick(const ScreenCoordsXY& screenCoords); + bool ViewportInteractionRightOver(const ScreenCoordsXY& screenCoords); + bool ViewportInteractionRightClick(const ScreenCoordsXY& screenCoords); + + CoordsXY ViewportInteractionGetTileStartAtCursor(const ScreenCoordsXY& screenCoords); +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/interface/ViewportQuery.cpp b/src/openrct2-ui/interface/ViewportQuery.cpp new file mode 100644 index 0000000000..9b2e5efb70 --- /dev/null +++ b/src/openrct2-ui/interface/ViewportQuery.cpp @@ -0,0 +1,178 @@ +/***************************************************************************** + * 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 "ViewportQuery.h" + +#include "Viewport.h" +#include "Window.h" + +#include +#include +#include + +namespace OpenRCT2::Ui +{ + /** + * Determines the location of the footpath at which we point with the cursor. If no footpath is underneath the cursor, + * then return the location of the ground tile. Besides the location it also computes the direction of the yellow arrow + * when we are going to build a footpath bridge/tunnel. + * rct2: 0x00689726 + * In: + * screenX: eax + * screenY: ebx + * Out: + * x: ax + * y: bx + * direction: ecx + * tileElement: edx + */ + CoordsXY FootpathGetCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement) + { + WindowBase* window = WindowFindFromPoint(screenCoords); + if (window == nullptr || window->viewport == nullptr) + { + CoordsXY position{}; + position.SetNull(); + return position; + } + auto viewport = window->viewport; + auto info = GetMapCoordinatesFromPosWindow(window, screenCoords, EnumsToFlags(ViewportInteractionItem::Footpath)); + if (info.SpriteType != ViewportInteractionItem::Footpath + || !(viewport->flags & (VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL))) + { + info = GetMapCoordinatesFromPosWindow( + window, screenCoords, EnumsToFlags(ViewportInteractionItem::Terrain, ViewportInteractionItem::Footpath)); + if (info.SpriteType == ViewportInteractionItem::None) + { + auto position = info.Loc; + position.SetNull(); + return position; + } + } + + auto minPosition = info.Loc; + auto maxPosition = info.Loc + CoordsXY{ 31, 31 }; + auto myTileElement = info.Element; + auto position = info.Loc.ToTileCentre(); + auto z = 0; + if (info.SpriteType == ViewportInteractionItem::Footpath) + { + z = myTileElement->GetBaseZ(); + if (myTileElement->AsPath()->IsSloped()) + { + z += 8; + } + } + + auto start_vp_pos = viewport->ScreenToViewportCoord(screenCoords); + + for (int32_t i = 0; i < 5; i++) + { + if (info.SpriteType != ViewportInteractionItem::Footpath) + { + z = TileElementHeight(position); + } + position = ViewportPosToMapPos(start_vp_pos, z, viewport->rotation); + position.x = std::clamp(position.x, minPosition.x, maxPosition.x); + position.y = std::clamp(position.y, minPosition.y, maxPosition.y); + } + + // Determine to which edge the cursor is closest + uint32_t myDirection; + int32_t mod_x = position.x & 0x1F, mod_y = position.y & 0x1F; + if (mod_x < mod_y) + { + if (mod_x + mod_y < 32) + { + myDirection = 0; + } + else + { + myDirection = 1; + } + } + else + { + if (mod_x + mod_y < 32) + { + myDirection = 3; + } + else + { + myDirection = 2; + } + } + + position = position.ToTileStart(); + + if (direction != nullptr) + *direction = myDirection; + if (tileElement != nullptr) + *tileElement = myTileElement; + + return position; + } + + /** + * + * rct2: 0x0068A0C9 + * screenX: eax + * screenY: ebx + * x: ax + * y: bx + * direction: cl + * tileElement: edx + */ + CoordsXY FootpathBridgeGetInfoFromPos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement) + { + // First check if we point at an entrance or exit. In that case, we would want the path coming from the entrance/exit. + WindowBase* window = WindowFindFromPoint(screenCoords); + if (window == nullptr || window->viewport == nullptr) + { + CoordsXY ret{}; + ret.SetNull(); + return ret; + } + auto viewport = window->viewport; + auto info = GetMapCoordinatesFromPosWindow(window, screenCoords, EnumsToFlags(ViewportInteractionItem::Ride)); + *tileElement = info.Element; + if (info.SpriteType == ViewportInteractionItem::Ride + && viewport->flags & (VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL) + && (*tileElement)->GetType() == TileElementType::Entrance) + { + uint32_t directions = (*tileElement)->AsEntrance()->GetDirections(); + if (directions & 0x0F) + { + int32_t bx = UtilBitScanForward(directions); + bx += (*tileElement)->AsEntrance()->GetDirection(); + bx &= 3; + if (direction != nullptr) + *direction = bx; + return info.Loc; + } + } + + info = GetMapCoordinatesFromPosWindow( + window, screenCoords, + EnumsToFlags(ViewportInteractionItem::Terrain, ViewportInteractionItem::Footpath, ViewportInteractionItem::Ride)); + if (info.SpriteType == ViewportInteractionItem::Ride && (*tileElement)->GetType() == TileElementType::Entrance) + { + uint32_t directions = (*tileElement)->AsEntrance()->GetDirections(); + if (directions & 0x0F) + { + int32_t bx = (*tileElement)->GetDirectionWithOffset(UtilBitScanForward(directions)); + if (direction != nullptr) + *direction = bx; + return info.Loc; + } + } + + // We point at something else + return FootpathGetCoordinatesFromPos(screenCoords, direction, tileElement); + } +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/interface/ViewportQuery.h b/src/openrct2-ui/interface/ViewportQuery.h new file mode 100644 index 0000000000..cba9eb2d61 --- /dev/null +++ b/src/openrct2-ui/interface/ViewportQuery.h @@ -0,0 +1,19 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +#pragma once +#include + +struct TileElement; + +namespace OpenRCT2::Ui +{ + CoordsXY FootpathGetCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement); + CoordsXY FootpathBridgeGetInfoFromPos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement); +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/libopenrct2ui.vcxproj b/src/openrct2-ui/libopenrct2ui.vcxproj index a46933ff85..2ac5fd64f9 100644 --- a/src/openrct2-ui/libopenrct2ui.vcxproj +++ b/src/openrct2-ui/libopenrct2ui.vcxproj @@ -72,6 +72,8 @@ + + @@ -134,6 +136,7 @@ + @@ -253,4 +256,4 @@ - + \ No newline at end of file diff --git a/src/openrct2-ui/ride/Construction.cpp b/src/openrct2-ui/ride/Construction.cpp index 6aad021e35..9640c837a6 100644 --- a/src/openrct2-ui/ride/Construction.cpp +++ b/src/openrct2-ui/ride/Construction.cpp @@ -9,6 +9,8 @@ #include "Construction.h" +#include "../interface/Viewport.h" + #include #include #include @@ -104,4 +106,133 @@ namespace OpenRCT2 } return list; } + + /** + * + * rct2: 0x006CCF70 + */ + CoordsXYZD RideGetEntranceOrExitPositionFromScreenPosition(const ScreenCoordsXY& screenCoords) + { + CoordsXYZD entranceExitCoords{}; + gRideEntranceExitPlaceDirection = INVALID_DIRECTION; + // determine if the mouse is hovering over a station - that's the station to add the entrance to + auto info = GetMapCoordinatesFromPos(screenCoords, EnumsToFlags(ViewportInteractionItem::Ride)); + if (info.SpriteType != ViewportInteractionItem::None) + { + if (info.Element->GetType() == TileElementType::Track) + { + const auto* trackElement = info.Element->AsTrack(); + if (trackElement->GetRideIndex() == gRideEntranceExitPlaceRideIndex) + { + const auto& ted = GetTrackElementDescriptor(trackElement->GetTrackType()); + if (std::get<0>(ted.SequenceProperties) & TRACK_SEQUENCE_FLAG_ORIGIN) + { + if (trackElement->GetTrackType() == TrackElemType::Maze) + { + gRideEntranceExitPlaceStationIndex = StationIndex::FromUnderlying(0); + } + else + { + gRideEntranceExitPlaceStationIndex = trackElement->GetStationIndex(); + } + } + } + } + } + + auto ride = GetRide(gRideEntranceExitPlaceRideIndex); + if (ride == nullptr) + { + entranceExitCoords.SetNull(); + return entranceExitCoords; + } + + auto stationBaseZ = ride->GetStation(gRideEntranceExitPlaceStationIndex).GetBaseZ(); + + auto coordsAtHeight = ScreenGetMapXYWithZ(screenCoords, stationBaseZ); + if (!coordsAtHeight.has_value()) + { + entranceExitCoords.SetNull(); + return entranceExitCoords; + } + + entranceExitCoords = { coordsAtHeight->ToTileStart(), stationBaseZ, INVALID_DIRECTION }; + + if (ride->type == RIDE_TYPE_NULL) + { + entranceExitCoords.SetNull(); + return entranceExitCoords; + } + + auto stationStart = ride->GetStation(gRideEntranceExitPlaceStationIndex).Start; + if (stationStart.IsNull()) + { + entranceExitCoords.SetNull(); + return entranceExitCoords; + } + + // find the quadrant the mouse is hovering over - that's the direction to start searching for a station TileElement + Direction startDirection = 0; + auto mapX = (coordsAtHeight->x & 0x1F) - 16; + auto mapY = (coordsAtHeight->y & 0x1F) - 16; + if (std::abs(mapX) < std::abs(mapY)) + { + startDirection = mapY < 0 ? 3 : 1; + } + else + { + startDirection = mapX < 0 ? 0 : 2; + } + // check all 4 directions, starting with the mouse's quadrant + for (uint8_t directionIncrement = 0; directionIncrement < 4; directionIncrement++) + { + entranceExitCoords.direction = (startDirection + directionIncrement) & 3; + // search for TrackElement one tile over, shifted in the search direction + auto nextLocation = entranceExitCoords; + nextLocation += CoordsDirectionDelta[entranceExitCoords.direction]; + if (MapIsLocationValid(nextLocation)) + { + // iterate over every element in the tile until we find what we want + auto* tileElement = MapGetFirstElementAt(nextLocation); + if (tileElement == nullptr) + continue; + do + { + if (tileElement->GetType() != TileElementType::Track) + continue; + if (tileElement->GetBaseZ() != stationBaseZ) + continue; + auto* trackElement = tileElement->AsTrack(); + if (trackElement->GetRideIndex() != gRideEntranceExitPlaceRideIndex) + continue; + if (trackElement->GetTrackType() == TrackElemType::Maze) + { + // if it's a maze, it can place the entrance and exit immediately + entranceExitCoords.direction = DirectionReverse(entranceExitCoords.direction); + gRideEntranceExitPlaceDirection = entranceExitCoords.direction; + return entranceExitCoords; + } + // if it's not a maze, the sequence properties for the TrackElement must be found to determine if an + // entrance can be placed on that side + + gRideEntranceExitPlaceStationIndex = trackElement->GetStationIndex(); + + // get the ride entrance's side relative to the TrackElement + Direction direction = (DirectionReverse(entranceExitCoords.direction) - tileElement->GetDirection()) & 3; + const auto& ted = GetTrackElementDescriptor(trackElement->GetTrackType()); + if (ted.SequenceProperties[trackElement->GetSequenceIndex()] & (1 << direction)) + { + // if that side of the TrackElement supports stations, the ride entrance is valid and faces away from + // the station + entranceExitCoords.direction = DirectionReverse(entranceExitCoords.direction); + gRideEntranceExitPlaceDirection = entranceExitCoords.direction; + return entranceExitCoords; + } + } while (!(tileElement++)->IsLastForTile()); + } + } + gRideEntranceExitPlaceDirection = INVALID_DIRECTION; + return entranceExitCoords; + } + } // namespace OpenRCT2 diff --git a/src/openrct2-ui/ride/Construction.h b/src/openrct2-ui/ride/Construction.h index 63415e2325..20e6d2f4a9 100644 --- a/src/openrct2-ui/ride/Construction.h +++ b/src/openrct2-ui/ride/Construction.h @@ -165,4 +165,5 @@ namespace OpenRCT2 RideConstructionState state); void RideConstructNew(RideSelection listItem); + CoordsXYZD RideGetEntranceOrExitPositionFromScreenPosition(const ScreenCoordsXY& screenCoords); } // namespace OpenRCT2 diff --git a/src/openrct2-ui/scripting/CustomListView.cpp b/src/openrct2-ui/scripting/CustomListView.cpp index 6897741695..7ced77db88 100644 --- a/src/openrct2-ui/scripting/CustomListView.cpp +++ b/src/openrct2-ui/scripting/CustomListView.cpp @@ -11,6 +11,7 @@ # include "CustomListView.h" +# include "../interface/Viewport.h" # include "../interface/Widget.h" # include "../interface/Window.h" diff --git a/src/openrct2-ui/scripting/CustomListView.h b/src/openrct2-ui/scripting/CustomListView.h index dd2a3d7d7c..4f6a505aaf 100644 --- a/src/openrct2-ui/scripting/CustomListView.h +++ b/src/openrct2-ui/scripting/CustomListView.h @@ -11,6 +11,8 @@ #ifdef ENABLE_SCRIPTING +# include "../interface/Window.h" + # include # include # include diff --git a/src/openrct2-ui/scripting/CustomMenu.cpp b/src/openrct2-ui/scripting/CustomMenu.cpp index c9821dea16..12e80dc208 100644 --- a/src/openrct2-ui/scripting/CustomMenu.cpp +++ b/src/openrct2-ui/scripting/CustomMenu.cpp @@ -11,6 +11,8 @@ # include "CustomMenu.h" +# include "../interface/Viewport.h" + # include # include # include diff --git a/src/openrct2-ui/windows/ClearScenery.cpp b/src/openrct2-ui/windows/ClearScenery.cpp index d6e2a84fc8..1421bf8d38 100644 --- a/src/openrct2-ui/windows/ClearScenery.cpp +++ b/src/openrct2-ui/windows/ClearScenery.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/Viewport.h" + #include #include #include diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index 4113233cf1..35a8f48392 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/ViewportQuery.h" + #include #include #include diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp index 840ec7df94..20fc64e9a7 100644 --- a/src/openrct2-ui/windows/Guest.cpp +++ b/src/openrct2-ui/windows/Guest.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/ViewportQuery.h" + #include #include #include diff --git a/src/openrct2-ui/windows/Land.cpp b/src/openrct2-ui/windows/Land.cpp index 3daab508fb..f3fa0aeeb8 100644 --- a/src/openrct2-ui/windows/Land.cpp +++ b/src/openrct2-ui/windows/Land.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/Viewport.h" + #include #include #include diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp index b0959c9015..c714895f80 100644 --- a/src/openrct2-ui/windows/Map.cpp +++ b/src/openrct2-ui/windows/Map.cpp @@ -7,6 +7,9 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/ViewportInteraction.h" +#include "../interface/ViewportQuery.h" + #include #include #include diff --git a/src/openrct2-ui/windows/MazeConstruction.cpp b/src/openrct2-ui/windows/MazeConstruction.cpp index 421f5cb883..8e64c4e3e0 100644 --- a/src/openrct2-ui/windows/MazeConstruction.cpp +++ b/src/openrct2-ui/windows/MazeConstruction.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../ride/Construction.h" + #include #include #include diff --git a/src/openrct2-ui/windows/PatrolArea.cpp b/src/openrct2-ui/windows/PatrolArea.cpp index 4f72efd3e6..352d35bf66 100644 --- a/src/openrct2-ui/windows/PatrolArea.cpp +++ b/src/openrct2-ui/windows/PatrolArea.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/ViewportQuery.h" + #include #include #include diff --git a/src/openrct2-ui/windows/Player.cpp b/src/openrct2-ui/windows/Player.cpp index 325411471e..171f1bce96 100644 --- a/src/openrct2-ui/windows/Player.cpp +++ b/src/openrct2-ui/windows/Player.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/Viewport.h" + #include #include #include diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index af8df43cd8..85e29907c0 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -7,6 +7,7 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/ViewportInteraction.h" #include "../ride/Construction.h" #include diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index 80bfc28d77..d4913bb33f 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -6,6 +6,7 @@ * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/ViewportInteraction.h" #include #include diff --git a/src/openrct2-ui/windows/Staff.cpp b/src/openrct2-ui/windows/Staff.cpp index 30c384ab28..d49d132972 100644 --- a/src/openrct2-ui/windows/Staff.cpp +++ b/src/openrct2-ui/windows/Staff.cpp @@ -8,6 +8,7 @@ *****************************************************************************/ #include "../interface/Theme.h" +#include "../interface/ViewportQuery.h" #include #include diff --git a/src/openrct2-ui/windows/StaffList.cpp b/src/openrct2-ui/windows/StaffList.cpp index 3e23909430..91d03ce6e9 100644 --- a/src/openrct2-ui/windows/StaffList.cpp +++ b/src/openrct2-ui/windows/StaffList.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/ViewportQuery.h" + #include #include #include diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index b04b978637..028c34d027 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -8,6 +8,7 @@ *****************************************************************************/ #include "../UiStringIds.h" +#include "../interface/Viewport.h" #include #include diff --git a/src/openrct2-ui/windows/TrackDesignPlace.cpp b/src/openrct2-ui/windows/TrackDesignPlace.cpp index 0eb0c95198..1e934f6113 100644 --- a/src/openrct2-ui/windows/TrackDesignPlace.cpp +++ b/src/openrct2-ui/windows/TrackDesignPlace.cpp @@ -6,6 +6,7 @@ * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/ViewportInteraction.h" #include #include diff --git a/src/openrct2-ui/windows/Transparency.cpp b/src/openrct2-ui/windows/Transparency.cpp index fd2aa3689f..78761eda4a 100644 --- a/src/openrct2-ui/windows/Transparency.cpp +++ b/src/openrct2-ui/windows/Transparency.cpp @@ -6,6 +6,7 @@ * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/Viewport.h" #include #include diff --git a/src/openrct2-ui/windows/Water.cpp b/src/openrct2-ui/windows/Water.cpp index a63386b869..467302e0e4 100644 --- a/src/openrct2-ui/windows/Water.cpp +++ b/src/openrct2-ui/windows/Water.cpp @@ -6,6 +6,7 @@ * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../interface/Viewport.h" #include #include diff --git a/src/openrct2/ReplayManager.cpp b/src/openrct2/ReplayManager.cpp index 3c1a24c26f..d149b92367 100644 --- a/src/openrct2/ReplayManager.cpp +++ b/src/openrct2/ReplayManager.cpp @@ -29,6 +29,7 @@ #include "core/Path.hpp" #include "entity/EntityRegistry.h" #include "entity/EntityTweener.h" +#include "interface/Window.h" #include "management/NewsItem.h" #include "object/ObjectManager.h" #include "object/ObjectRepository.h" diff --git a/src/openrct2/actions/GameSetSpeedAction.cpp b/src/openrct2/actions/GameSetSpeedAction.cpp index 6f9ec173d4..569189acdb 100644 --- a/src/openrct2/actions/GameSetSpeedAction.cpp +++ b/src/openrct2/actions/GameSetSpeedAction.cpp @@ -11,6 +11,7 @@ #include "../Diagnostic.h" #include "../config/Config.h" +#include "../interface/Window.h" using namespace OpenRCT2; diff --git a/src/openrct2/actions/LoadOrQuitAction.h b/src/openrct2/actions/LoadOrQuitAction.h index f985f2c8a2..39e5344a9b 100644 --- a/src/openrct2/actions/LoadOrQuitAction.h +++ b/src/openrct2/actions/LoadOrQuitAction.h @@ -9,6 +9,7 @@ #pragma once +#include "../interface/Window.h" #include "GameAction.h" enum class LoadOrQuitModes : uint8_t diff --git a/src/openrct2/actions/RideFreezeRatingAction.cpp b/src/openrct2/actions/RideFreezeRatingAction.cpp index 3b0eefff45..5832ae5d0e 100644 --- a/src/openrct2/actions/RideFreezeRatingAction.cpp +++ b/src/openrct2/actions/RideFreezeRatingAction.cpp @@ -10,6 +10,7 @@ #include "RideFreezeRatingAction.h" #include "../Diagnostic.h" +#include "../interface/Window.h" using namespace OpenRCT2; diff --git a/src/openrct2/actions/RideSetSettingAction.cpp b/src/openrct2/actions/RideSetSettingAction.cpp index 18f14da269..20bc97603c 100644 --- a/src/openrct2/actions/RideSetSettingAction.cpp +++ b/src/openrct2/actions/RideSetSettingAction.cpp @@ -12,6 +12,7 @@ #include "../Context.h" #include "../Diagnostic.h" #include "../GameState.h" +#include "../interface/Window.h" #include "../object/ObjectManager.h" #include "../ride/Ride.h" #include "../ride/RideData.h" diff --git a/src/openrct2/entity/EntityBase.cpp b/src/openrct2/entity/EntityBase.cpp index 235c57577a..7b61eb001c 100644 --- a/src/openrct2/entity/EntityBase.cpp +++ b/src/openrct2/entity/EntityBase.cpp @@ -10,6 +10,7 @@ #include "EntityBase.h" #include "../core/DataSerialiser.h" +#include "../interface/Viewport.h" using namespace OpenRCT2; diff --git a/src/openrct2/entity/Peep.cpp b/src/openrct2/entity/Peep.cpp index 3d0a192b09..8f574cd529 100644 --- a/src/openrct2/entity/Peep.cpp +++ b/src/openrct2/entity/Peep.cpp @@ -26,6 +26,7 @@ #include "../entity/Balloon.h" #include "../entity/EntityRegistry.h" #include "../entity/EntityTweener.h" +#include "../interface/Viewport.h" #include "../interface/Window_internal.h" #include "../localisation/Formatter.h" #include "../localisation/Formatting.h" diff --git a/src/openrct2/interface/Viewport.h b/src/openrct2/interface/Viewport.h index 530c3ba4cf..75883321d0 100644 --- a/src/openrct2/interface/Viewport.h +++ b/src/openrct2/interface/Viewport.h @@ -159,12 +159,6 @@ InteractionInfo GetMapCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int InteractionInfo GetMapCoordinatesFromPosWindow(WindowBase* window, const ScreenCoordsXY& screenCoords, int32_t flags); InteractionInfo SetInteractionInfoFromPaintSession(PaintSession* session, uint32_t viewFlags, uint16_t filter); -bool ViewportInteractionLeftOver(const ScreenCoordsXY& screenCoords); -bool ViewportInteractionLeftClick(const ScreenCoordsXY& screenCoords); -bool ViewportInteractionRightOver(const ScreenCoordsXY& screenCoords); -bool ViewportInteractionRightClick(const ScreenCoordsXY& screenCoords); - -CoordsXY ViewportInteractionGetTileStartAtCursor(const ScreenCoordsXY& screenCoords); std::optional ScreenGetMapXY(const ScreenCoordsXY& screenCoords, Viewport** viewport); std::optional ScreenGetMapXYWithZ(const ScreenCoordsXY& screenCoords, int32_t z); diff --git a/src/openrct2/network/NetworkBase.h b/src/openrct2/network/NetworkBase.h index 87c5b2e31d..8a65b81f9b 100644 --- a/src/openrct2/network/NetworkBase.h +++ b/src/openrct2/network/NetworkBase.h @@ -11,6 +11,7 @@ #include "NetworkUser.h" #include +#include #include #ifndef DISABLE_NETWORK diff --git a/src/openrct2/object/ObjectManager.cpp b/src/openrct2/object/ObjectManager.cpp index 192ebca4d3..5134595c6f 100644 --- a/src/openrct2/object/ObjectManager.cpp +++ b/src/openrct2/object/ObjectManager.cpp @@ -16,6 +16,7 @@ #include "../core/Console.hpp" #include "../core/JobPool.h" #include "../core/Memory.hpp" +#include "../interface/Window.h" #include "../localisation/StringIds.h" #include "../ride/Ride.h" #include "../ride/RideAudio.h" diff --git a/src/openrct2/paint/Painter.cpp b/src/openrct2/paint/Painter.cpp index 17e1343887..8d2091eea6 100644 --- a/src/openrct2/paint/Painter.cpp +++ b/src/openrct2/paint/Painter.cpp @@ -19,6 +19,7 @@ #include "../interface/Chat.h" #include "../interface/InteractiveConsole.h" #include "../interface/Widget.h" +#include "../interface/Window.h" #include "../localisation/FormatCodes.h" #include "../localisation/Formatting.h" #include "../localisation/Language.h" diff --git a/src/openrct2/paint/support/WoodenSupports.cpp b/src/openrct2/paint/support/WoodenSupports.cpp index c8ea84d8f3..b6249588f8 100644 --- a/src/openrct2/paint/support/WoodenSupports.cpp +++ b/src/openrct2/paint/support/WoodenSupports.cpp @@ -9,6 +9,7 @@ #include "WoodenSupports.h" +#include "../../interface/Viewport.h" #include "../../sprites.h" #include "../../world/Map.h" #include "../../world/Surface.h" diff --git a/src/openrct2/paint/tile_element/Paint.PathAddition.cpp b/src/openrct2/paint/tile_element/Paint.PathAddition.cpp index df7c17b37c..1f79c8002f 100644 --- a/src/openrct2/paint/tile_element/Paint.PathAddition.cpp +++ b/src/openrct2/paint/tile_element/Paint.PathAddition.cpp @@ -11,6 +11,7 @@ #include "../../core/Numerics.hpp" #include "../../drawing/LightFX.h" +#include "../../interface/Viewport.h" #include "../../object/PathAdditionEntry.h" #include "../../profiling/Profiling.h" #include "Paint.TileElement.h" diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 1be571fa7b..564b12ce79 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -31,6 +31,7 @@ #include "../entity/EntityRegistry.h" #include "../entity/Peep.h" #include "../entity/Staff.h" +#include "../interface/Viewport.h" #include "../interface/Window_internal.h" #include "../localisation/Formatter.h" #include "../localisation/Formatting.h" diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index a52aa03c26..0d0d137268 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -13,6 +13,7 @@ #include "../actions/ResultWithMessage.h" #include "../core/BitSet.hpp" #include "../core/FixedPoint.hpp" +#include "../localisation/Formatter.h" #include "../object/MusicObject.h" #include "../rct2/DATLimits.h" #include "../rct2/Limits.h" diff --git a/src/openrct2/ride/RideConstruction.cpp b/src/openrct2/ride/RideConstruction.cpp index 1cd55b36d7..ff74f0da8d 100644 --- a/src/openrct2/ride/RideConstruction.cpp +++ b/src/openrct2/ride/RideConstruction.cpp @@ -1205,134 +1205,6 @@ money64 SetOperatingSettingNested(RideId rideId, RideSetSetting setting, uint8_t return res.Error == GameActions::Status::Ok ? 0 : kMoney64Undefined; } -/** - * - * rct2: 0x006CCF70 - */ -CoordsXYZD RideGetEntranceOrExitPositionFromScreenPosition(const ScreenCoordsXY& screenCoords) -{ - CoordsXYZD entranceExitCoords{}; - gRideEntranceExitPlaceDirection = INVALID_DIRECTION; - // determine if the mouse is hovering over a station - that's the station to add the entrance to - auto info = GetMapCoordinatesFromPos(screenCoords, EnumsToFlags(ViewportInteractionItem::Ride)); - if (info.SpriteType != ViewportInteractionItem::None) - { - if (info.Element->GetType() == TileElementType::Track) - { - const auto* trackElement = info.Element->AsTrack(); - if (trackElement->GetRideIndex() == gRideEntranceExitPlaceRideIndex) - { - const auto& ted = GetTrackElementDescriptor(trackElement->GetTrackType()); - if (std::get<0>(ted.SequenceProperties) & TRACK_SEQUENCE_FLAG_ORIGIN) - { - if (trackElement->GetTrackType() == TrackElemType::Maze) - { - gRideEntranceExitPlaceStationIndex = StationIndex::FromUnderlying(0); - } - else - { - gRideEntranceExitPlaceStationIndex = trackElement->GetStationIndex(); - } - } - } - } - } - - auto ride = GetRide(gRideEntranceExitPlaceRideIndex); - if (ride == nullptr) - { - entranceExitCoords.SetNull(); - return entranceExitCoords; - } - - auto stationBaseZ = ride->GetStation(gRideEntranceExitPlaceStationIndex).GetBaseZ(); - - auto coordsAtHeight = ScreenGetMapXYWithZ(screenCoords, stationBaseZ); - if (!coordsAtHeight.has_value()) - { - entranceExitCoords.SetNull(); - return entranceExitCoords; - } - - entranceExitCoords = { coordsAtHeight->ToTileStart(), stationBaseZ, INVALID_DIRECTION }; - - if (ride->type == RIDE_TYPE_NULL) - { - entranceExitCoords.SetNull(); - return entranceExitCoords; - } - - auto stationStart = ride->GetStation(gRideEntranceExitPlaceStationIndex).Start; - if (stationStart.IsNull()) - { - entranceExitCoords.SetNull(); - return entranceExitCoords; - } - - // find the quadrant the mouse is hovering over - that's the direction to start searching for a station TileElement - Direction startDirection = 0; - auto mapX = (coordsAtHeight->x & 0x1F) - 16; - auto mapY = (coordsAtHeight->y & 0x1F) - 16; - if (std::abs(mapX) < std::abs(mapY)) - { - startDirection = mapY < 0 ? 3 : 1; - } - else - { - startDirection = mapX < 0 ? 0 : 2; - } - // check all 4 directions, starting with the mouse's quadrant - for (uint8_t directionIncrement = 0; directionIncrement < 4; directionIncrement++) - { - entranceExitCoords.direction = (startDirection + directionIncrement) & 3; - // search for TrackElement one tile over, shifted in the search direction - auto nextLocation = entranceExitCoords; - nextLocation += CoordsDirectionDelta[entranceExitCoords.direction]; - if (MapIsLocationValid(nextLocation)) - { - // iterate over every element in the tile until we find what we want - auto* tileElement = MapGetFirstElementAt(nextLocation); - if (tileElement == nullptr) - continue; - do - { - if (tileElement->GetType() != TileElementType::Track) - continue; - if (tileElement->GetBaseZ() != stationBaseZ) - continue; - auto* trackElement = tileElement->AsTrack(); - if (trackElement->GetRideIndex() != gRideEntranceExitPlaceRideIndex) - continue; - if (trackElement->GetTrackType() == TrackElemType::Maze) - { - // if it's a maze, it can place the entrance and exit immediately - entranceExitCoords.direction = DirectionReverse(entranceExitCoords.direction); - gRideEntranceExitPlaceDirection = entranceExitCoords.direction; - return entranceExitCoords; - } - // if it's not a maze, the sequence properties for the TrackElement must be found to determine if an - // entrance can be placed on that side - - gRideEntranceExitPlaceStationIndex = trackElement->GetStationIndex(); - - // get the ride entrance's side relative to the TrackElement - Direction direction = (DirectionReverse(entranceExitCoords.direction) - tileElement->GetDirection()) & 3; - const auto& ted = GetTrackElementDescriptor(trackElement->GetTrackType()); - if (ted.SequenceProperties[trackElement->GetSequenceIndex()] & (1 << direction)) - { - // if that side of the TrackElement supports stations, the ride entrance is valid and faces away from - // the station - entranceExitCoords.direction = DirectionReverse(entranceExitCoords.direction); - gRideEntranceExitPlaceDirection = entranceExitCoords.direction; - return entranceExitCoords; - } - } while (!(tileElement++)->IsLastForTile()); - } - } - gRideEntranceExitPlaceDirection = INVALID_DIRECTION; - return entranceExitCoords; -} - /** * * rct2: 0x006CB945 diff --git a/src/openrct2/ride/RideConstruction.h b/src/openrct2/ride/RideConstruction.h index 4df813136c..940f335c46 100644 --- a/src/openrct2/ride/RideConstruction.h +++ b/src/openrct2/ride/RideConstruction.h @@ -91,8 +91,6 @@ void RideSelectPreviousSection(); bool RideModify(const CoordsXYE& input); -CoordsXYZD RideGetEntranceOrExitPositionFromScreenPosition(const ScreenCoordsXY& screenCoords); - bool RideSelectBackwardsFromFront(); bool RideSelectForwardsFromBack(); diff --git a/src/openrct2/ride/TrackDesign.h b/src/openrct2/ride/TrackDesign.h index 7edb5cb2c3..6ccee312cd 100644 --- a/src/openrct2/ride/TrackDesign.h +++ b/src/openrct2/ride/TrackDesign.h @@ -21,6 +21,7 @@ struct Ride; struct ResultWithMessage; +enum class ViewportInteractionItem : uint8_t; constexpr uint32_t kTrackPreviewImageSize = 370 * 217; diff --git a/src/openrct2/scenes/title/Command/SetLocation.cpp b/src/openrct2/scenes/title/Command/SetLocation.cpp index b577a2c80b..be14cd9124 100644 --- a/src/openrct2/scenes/title/Command/SetLocation.cpp +++ b/src/openrct2/scenes/title/Command/SetLocation.cpp @@ -10,6 +10,7 @@ #include "SetLocation.h" #include "../../../OpenRCT2.h" +#include "../../../interface/Viewport.h" #include "../../../interface/Window.h" #include "../../../interface/Window_internal.h" #include "../../../world/Map.h" diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 772fafdbb8..c9c849ae40 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -20,6 +20,7 @@ #include "../core/Guard.hpp" #include "../entity/EntityList.h" #include "../entity/EntityRegistry.h" +#include "../interface/Viewport.h" #include "../interface/Window_internal.h" #include "../management/Finance.h" #include "../network/network.h" @@ -231,165 +232,6 @@ void FootpathProvisionalUpdate() FootpathProvisionalRemove(); } -/** - * Determines the location of the footpath at which we point with the cursor. If no footpath is underneath the cursor, - * then return the location of the ground tile. Besides the location it also computes the direction of the yellow arrow - * when we are going to build a footpath bridge/tunnel. - * rct2: 0x00689726 - * In: - * screenX: eax - * screenY: ebx - * Out: - * x: ax - * y: bx - * direction: ecx - * tileElement: edx - */ -CoordsXY FootpathGetCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement) -{ - WindowBase* window = WindowFindFromPoint(screenCoords); - if (window == nullptr || window->viewport == nullptr) - { - CoordsXY position{}; - position.SetNull(); - return position; - } - auto viewport = window->viewport; - auto info = GetMapCoordinatesFromPosWindow(window, screenCoords, EnumsToFlags(ViewportInteractionItem::Footpath)); - if (info.SpriteType != ViewportInteractionItem::Footpath - || !(viewport->flags & (VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL))) - { - info = GetMapCoordinatesFromPosWindow( - window, screenCoords, EnumsToFlags(ViewportInteractionItem::Terrain, ViewportInteractionItem::Footpath)); - if (info.SpriteType == ViewportInteractionItem::None) - { - auto position = info.Loc; - position.SetNull(); - return position; - } - } - - auto minPosition = info.Loc; - auto maxPosition = info.Loc + CoordsXY{ 31, 31 }; - auto myTileElement = info.Element; - auto position = info.Loc.ToTileCentre(); - auto z = 0; - if (info.SpriteType == ViewportInteractionItem::Footpath) - { - z = myTileElement->GetBaseZ(); - if (myTileElement->AsPath()->IsSloped()) - { - z += 8; - } - } - - auto start_vp_pos = viewport->ScreenToViewportCoord(screenCoords); - - for (int32_t i = 0; i < 5; i++) - { - if (info.SpriteType != ViewportInteractionItem::Footpath) - { - z = TileElementHeight(position); - } - position = ViewportPosToMapPos(start_vp_pos, z, viewport->rotation); - position.x = std::clamp(position.x, minPosition.x, maxPosition.x); - position.y = std::clamp(position.y, minPosition.y, maxPosition.y); - } - - // Determine to which edge the cursor is closest - uint32_t myDirection; - int32_t mod_x = position.x & 0x1F, mod_y = position.y & 0x1F; - if (mod_x < mod_y) - { - if (mod_x + mod_y < 32) - { - myDirection = 0; - } - else - { - myDirection = 1; - } - } - else - { - if (mod_x + mod_y < 32) - { - myDirection = 3; - } - else - { - myDirection = 2; - } - } - - position = position.ToTileStart(); - - if (direction != nullptr) - *direction = myDirection; - if (tileElement != nullptr) - *tileElement = myTileElement; - - return position; -} - -/** - * - * rct2: 0x0068A0C9 - * screenX: eax - * screenY: ebx - * x: ax - * y: bx - * direction: cl - * tileElement: edx - */ -CoordsXY FootpathBridgeGetInfoFromPos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement) -{ - // First check if we point at an entrance or exit. In that case, we would want the path coming from the entrance/exit. - WindowBase* window = WindowFindFromPoint(screenCoords); - if (window == nullptr || window->viewport == nullptr) - { - CoordsXY ret{}; - ret.SetNull(); - return ret; - } - auto viewport = window->viewport; - auto info = GetMapCoordinatesFromPosWindow(window, screenCoords, EnumsToFlags(ViewportInteractionItem::Ride)); - *tileElement = info.Element; - if (info.SpriteType == ViewportInteractionItem::Ride - && viewport->flags & (VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL) - && (*tileElement)->GetType() == TileElementType::Entrance) - { - uint32_t directions = (*tileElement)->AsEntrance()->GetDirections(); - if (directions & 0x0F) - { - int32_t bx = UtilBitScanForward(directions); - bx += (*tileElement)->AsEntrance()->GetDirection(); - bx &= 3; - if (direction != nullptr) - *direction = bx; - return info.Loc; - } - } - - info = GetMapCoordinatesFromPosWindow( - window, screenCoords, - EnumsToFlags(ViewportInteractionItem::Terrain, ViewportInteractionItem::Footpath, ViewportInteractionItem::Ride)); - if (info.SpriteType == ViewportInteractionItem::Ride && (*tileElement)->GetType() == TileElementType::Entrance) - { - uint32_t directions = (*tileElement)->AsEntrance()->GetDirections(); - if (directions & 0x0F) - { - int32_t bx = (*tileElement)->GetDirectionWithOffset(UtilBitScanForward(directions)); - if (direction != nullptr) - *direction = bx; - return info.Loc; - } - } - - // We point at something else - return FootpathGetCoordinatesFromPos(screenCoords, direction, tileElement); -} - /** * * rct2: 0x00673883 diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index 6ff28f7c0e..209b7cfcb7 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -10,13 +10,13 @@ #pragma once #include "../Identifiers.h" -#include "../interface/Viewport.h" #include "../object/Object.h" class FootpathObject; class FootpathSurfaceObject; class FootpathRailingsObject; struct PathElement; +struct TileElement; enum { @@ -191,8 +191,6 @@ money64 FootpathProvisionalSet( PathConstructFlags constructFlags); void FootpathProvisionalRemove(); void FootpathProvisionalUpdate(); -CoordsXY FootpathGetCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement); -CoordsXY FootpathBridgeGetInfoFromPos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement); void FootpathRemoveLitter(const CoordsXYZ& footpathPos); void FootpathConnectEdges(const CoordsXY& footpathPos, TileElement* tileElement, int32_t flags); void FootpathUpdateQueueChains();