1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-02-03 18:07:53 +01:00

Confine provisional paths to Footpath.cpp

This commit is contained in:
Gymnasiast
2024-09-03 19:43:42 +02:00
parent ab3e919678
commit 4ff99d6fd1
10 changed files with 194 additions and 141 deletions

View File

@@ -9,27 +9,24 @@
#include "ProvisionalElements.h"
#include <openrct2-ui/windows/Window.h>
#include <openrct2/interface/Window.h>
#include <openrct2/interface/WindowClasses.h>
#include <openrct2/network/network.h>
#include <openrct2/profiling/Profiling.h>
#include <openrct2/ride/RideConstruction.h>
#include <openrct2/world/Footpath.h>
#include <openrct2-ui/windows/Window.h>
using namespace OpenRCT2::Ui::Windows;
namespace OpenRCT2
namespace OpenRCT2::Ui
{
void ProvisionalElementsRemove()
{
PROFILED_FUNCTION();
if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1)
{
FootpathProvisionalRemove();
gProvisionalFootpath.Flags |= PROVISIONAL_PATH_FLAG_1;
}
FootpathRemoveProvisionalTemporarily();
if (WindowFindByClass(WindowClass::RideConstruction) != nullptr)
{
RideRemoveProvisionalTrackPiece();
@@ -47,13 +44,8 @@ namespace OpenRCT2
{
PROFILED_FUNCTION();
if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1)
{
gProvisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_1;
FootpathProvisionalSet(
gProvisionalFootpath.SurfaceIndex, gProvisionalFootpath.RailingsIndex, gProvisionalFootpath.Position,
gProvisionalFootpath.Slope, gProvisionalFootpath.ConstructFlags);
}
FootpathRestoreProvisional();
if (WindowFindByClass(WindowClass::RideConstruction) != nullptr)
{
RideRestoreProvisionalTrackPiece();
@@ -66,4 +58,4 @@ namespace OpenRCT2
TrackPlaceRestoreProvisional();
}
}
} // namespace OpenRCT2
} // namespace OpenRCT2::Ui

View File

@@ -9,8 +9,31 @@
#pragma once
namespace OpenRCT2
namespace OpenRCT2::Ui
{
void ProvisionalElementsRemove();
void ProvisionalElementsRestore();
} // namespace OpenRCT2
namespace Windows
{
/**
* Called after building something else, which might affect the ability to build paths there.
*/
void FootpathRecheckProvisional();
/**
* Permanently remove provisional footpaths - e.g. after successful placement, or when cancelling placement.
*/
void FootpathRemoveProvisional();
void FootpathUpdateProvisional();
/**
* Used when performing actions on footpaths where provisional elements may interfere, and where the provisional
* elements must be restored later on (which can be done by calling `WindowFootpathRestoreProvisional()`.
*/
void FootpathRemoveProvisionalTemporarily();
/**
* Restore provisional elements that have been removed using `WindowFootpathRemoveProvisionalTemporarily()`.
*/
void FootpathRestoreProvisional();
} // namespace Windows
} // namespace OpenRCT2::Ui

View File

@@ -557,6 +557,9 @@ public:
case INTENT_ACTION_RESTORE_PROVISIONAL_ELEMENTS:
ProvisionalElementsRestore();
break;
case INTENT_ACTION_REMOVE_PROVISIONAL_FOOTPATH:
FootpathRemoveProvisional();
break;
default:
break;

View File

@@ -9,6 +9,7 @@
#include "ViewportInteraction.h"
#include "../ProvisionalElements.h"
#include "../UiStringIds.h"
#include "../windows/Window.h"
#include "Viewport.h"
@@ -629,7 +630,7 @@ namespace OpenRCT2::Ui
{
WindowBase* w = WindowFindByClass(WindowClass::Footpath);
if (w != nullptr)
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
TileElement* tileElement2 = MapGetFirstElementAt(mapCoords);
if (tileElement2 == nullptr)

View File

@@ -7,6 +7,7 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include <openrct2-ui/ProvisionalElements.h>
#include <openrct2-ui/UiContext.h>
#include <openrct2-ui/input/InputManager.h>
#include <openrct2-ui/input/ShortcutIds.h>
@@ -31,6 +32,7 @@
#include <openrct2/object/FootpathSurfaceObject.h>
#include <openrct2/object/ObjectLimits.h>
#include <openrct2/object/ObjectManager.h>
#include <openrct2/paint/VirtualFloor.h>
#include <openrct2/platform/Platform.h>
#include <openrct2/sprites.h>
#include <openrct2/world/Footpath.h>
@@ -40,6 +42,10 @@
namespace OpenRCT2::Ui::Windows
{
static money64 FootpathProvisionalSet(
ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope,
PathConstructFlags constructFlags);
enum
{
PATH_CONSTRUCTION_MODE_LAND,
@@ -47,6 +53,8 @@ namespace OpenRCT2::Ui::Windows
PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL
};
static ProvisionalFootpath _provisionalFootpath;
#pragma region Measurements
static constexpr StringId WINDOW_TITLE = STR_FOOTPATHS;
@@ -199,7 +207,7 @@ namespace OpenRCT2::Ui::Windows
void OnClose() override
{
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
ViewportSetVisibility(ViewportVisibility::Default);
MapInvalidateMapSelectionTiles();
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT;
@@ -291,7 +299,7 @@ namespace OpenRCT2::Ui::Windows
_windowFootpathCost = kMoney64Undefined;
ToolCancel();
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
MapInvalidateMapSelectionTiles();
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT;
_footpathConstructionMode = PATH_CONSTRUCTION_MODE_LAND;
@@ -308,7 +316,7 @@ namespace OpenRCT2::Ui::Windows
_windowFootpathCost = kMoney64Undefined;
ToolCancel();
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
MapInvalidateMapSelectionTiles();
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT;
_footpathConstructionMode = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL;
@@ -361,7 +369,7 @@ namespace OpenRCT2::Ui::Windows
return;
}
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
_windowFootpathCost = kMoney64Undefined;
Invalidate();
}
@@ -522,14 +530,14 @@ namespace OpenRCT2::Ui::Windows
}
// Recheck area for construction. Set by ride_construction window
if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_2)
if (_provisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_2)
{
FootpathProvisionalRemove();
gProvisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_2;
FootpathRemoveProvisional();
_provisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_2;
}
// Update provisional bridge mode path
if (!(gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1))
if (!(_provisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1))
{
ObjectEntryIndex type;
ObjectEntryIndex railings = gFootpathSelection.Railings;
@@ -550,13 +558,13 @@ namespace OpenRCT2::Ui::Windows
{
_footpathConstructionNextArrowPulse = curTime + ARROW_PULSE_DURATION;
gProvisionalFootpath.Flags ^= PROVISIONAL_PATH_FLAG_SHOW_ARROW;
_provisionalFootpath.Flags ^= PROVISIONAL_PATH_FLAG_SHOW_ARROW;
CoordsXYZ footpathLoc;
int32_t slope;
FootpathGetNextPathInfo(nullptr, footpathLoc, &slope);
gMapSelectArrowPosition = footpathLoc;
gMapSelectArrowDirection = _footpathConstructDirection;
if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_SHOW_ARROW)
if (_provisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_SHOW_ARROW)
{
gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE_ARROW;
}
@@ -752,7 +760,7 @@ namespace OpenRCT2::Ui::Windows
*/
void WindowFootpathMousedownDirection(int32_t direction)
{
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
_footpathConstructDirection = (direction - GetCurrentRotation()) & 3;
_windowFootpathCost = kMoney64Undefined;
WindowFootpathSetEnabledAndPressedWidgets();
@@ -764,7 +772,7 @@ namespace OpenRCT2::Ui::Windows
*/
void WindowFootpathMousedownSlope(int32_t slope)
{
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
gFootpathConstructSlope = slope;
_windowFootpathCost = kMoney64Undefined;
WindowFootpathSetEnabledAndPressedWidgets();
@@ -889,7 +897,7 @@ namespace OpenRCT2::Ui::Windows
if (info.SpriteType == ViewportInteractionItem::None || info.Element == nullptr)
{
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE;
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
return kTileSlopeFlat;
}
@@ -975,7 +983,7 @@ namespace OpenRCT2::Ui::Windows
// Check for change
auto provisionalPos = CoordsXYZ(*mapPos, _footpathPlaceZ);
if ((gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1) && gProvisionalFootpath.Position == provisionalPos)
if ((_provisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1) && _provisionalFootpath.Position == provisionalPos)
{
return;
}
@@ -986,7 +994,7 @@ namespace OpenRCT2::Ui::Windows
gMapSelectPositionA = *mapPos;
gMapSelectPositionB = *mapPos;
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
// Figure out what slope and height to use
int32_t slope = kTileSlopeFlat;
@@ -1007,7 +1015,7 @@ namespace OpenRCT2::Ui::Windows
if (baseZ == 0)
{
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE;
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
return;
}
}
@@ -1075,7 +1083,7 @@ namespace OpenRCT2::Ui::Windows
return;
}
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
auto mapPos = FootpathGetPlacePositionFromScreenPosition(screenCoords);
if (!mapPos)
@@ -1170,7 +1178,7 @@ namespace OpenRCT2::Ui::Windows
ToolCancel();
gFootpathConstructFromPosition = { mapCoords, z };
_footpathConstructDirection = direction;
gProvisionalFootpath.Flags = 0;
_provisionalFootpath.Flags = 0;
gFootpathConstructSlope = 0;
_footpathConstructionMode = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL;
_footpathConstructValidDirections = INVALID_DIRECTION;
@@ -1184,7 +1192,7 @@ namespace OpenRCT2::Ui::Windows
void WindowFootpathConstruct()
{
_windowFootpathCost = kMoney64Undefined;
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
ObjectEntryIndex type;
int32_t slope;
@@ -1350,7 +1358,7 @@ namespace OpenRCT2::Ui::Windows
TileElement* tileElement;
_windowFootpathCost = kMoney64Undefined;
FootpathProvisionalUpdate();
FootpathUpdateProvisional();
tileElement = FootpathGetTileElementToRemove();
if (tileElement != nullptr)
@@ -1694,4 +1702,124 @@ namespace OpenRCT2::Ui::Windows
WindowCloseByClass(WindowClass::Footpath);
}
}
/**
*
* rct2: 0x006A76FF
*/
static money64 FootpathProvisionalSet(
ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope,
PathConstructFlags constructFlags)
{
money64 cost;
FootpathRemoveProvisional();
auto footpathPlaceAction = FootpathPlaceAction(
footpathLoc, slope, type, railingsType, INVALID_DIRECTION, constructFlags);
footpathPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED);
auto res = GameActions::Execute(&footpathPlaceAction);
cost = res.Error == GameActions::Status::Ok ? res.Cost : kMoney64Undefined;
if (res.Error == GameActions::Status::Ok)
{
_provisionalFootpath.SurfaceIndex = type;
_provisionalFootpath.RailingsIndex = railingsType;
_provisionalFootpath.Position = footpathLoc;
_provisionalFootpath.Slope = slope;
_provisionalFootpath.ConstructFlags = constructFlags;
_provisionalFootpath.Flags |= PROVISIONAL_PATH_FLAG_1;
if (gFootpathGroundFlags & ELEMENT_IS_UNDERGROUND)
{
ViewportSetVisibility(ViewportVisibility::UndergroundViewOn);
}
else
{
ViewportSetVisibility(ViewportVisibility::UndergroundViewOff);
}
}
// Invalidate previous footpath piece.
VirtualFloorInvalidate();
if (!isToolActive(WindowClass::Scenery))
{
if (res.Error != GameActions::Status::Ok)
{
// If we can't build this, don't show a virtual floor.
VirtualFloorSetHeight(0);
}
else if (
_provisionalFootpath.Slope == kTileSlopeFlat
|| _provisionalFootpath.Position.z < gFootpathConstructFromPosition.z)
{
// Going either straight on, or down.
VirtualFloorSetHeight(_provisionalFootpath.Position.z);
}
else
{
// Going up in the world!
VirtualFloorSetHeight(_provisionalFootpath.Position.z + LAND_HEIGHT_STEP);
}
}
return cost;
}
/**
*
* rct2: 0x006A77FF
*/
void FootpathRemoveProvisional()
{
if (_provisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1)
{
_provisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_1;
auto action = FootpathRemoveAction(_provisionalFootpath.Position);
action.SetFlags(GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST);
GameActions::Execute(&action);
}
}
/**
*
* rct2: 0x006A7831
*/
void FootpathUpdateProvisional()
{
if (_provisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_SHOW_ARROW)
{
_provisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_SHOW_ARROW;
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_ARROW;
MapInvalidateTileFull(gFootpathConstructFromPosition);
}
FootpathRemoveProvisional();
}
void FootpathRemoveProvisionalTemporarily()
{
if (_provisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1)
{
FootpathRemoveProvisional();
_provisionalFootpath.Flags |= PROVISIONAL_PATH_FLAG_1;
}
}
void FootpathRestoreProvisional()
{
if (_provisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1)
{
_provisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_1;
FootpathProvisionalSet(
_provisionalFootpath.SurfaceIndex, _provisionalFootpath.RailingsIndex, _provisionalFootpath.Position,
_provisionalFootpath.Slope, _provisionalFootpath.ConstructFlags);
}
}
void FootpathRecheckProvisional()
{
_provisionalFootpath.Flags |= PROVISIONAL_PATH_FLAG_2;
}
} // namespace OpenRCT2::Ui::Windows

View File

@@ -7,6 +7,8 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "openrct2-ui/ProvisionalElements.h"
#include <limits>
#include <openrct2-ui/UiContext.h>
#include <openrct2-ui/input/InputManager.h>
@@ -46,7 +48,6 @@
#include <openrct2/util/Math.hpp>
#include <openrct2/windows/Intent.h>
#include <openrct2/world/Entrance.h>
#include <openrct2/world/Footpath.h>
#include <openrct2/world/Park.h>
constexpr int8_t kDefaultSpeedIncrement = 2;
@@ -1018,7 +1019,7 @@ namespace OpenRCT2::Ui::Windows
{
Construct();
// Force any footpath construction to recheck the area.
gProvisionalFootpath.Flags |= PROVISIONAL_PATH_FLAG_2;
FootpathRecheckProvisional();
break;
}
case WIDX_DEMOLISH:

View File

@@ -10,6 +10,7 @@
#include "FootpathPlaceAction.h"
#include "../Cheats.h"
#include "../Context.h"
#include "../Diagnostic.h"
#include "../GameState.h"
#include "../OpenRCT2.h"
@@ -19,6 +20,7 @@
#include "../management/Finance.h"
#include "../object/PathAdditionEntry.h"
#include "../ride/RideConstruction.h"
#include "../windows/Intent.h"
#include "../world/ConstructionClearance.h"
#include "../world/Footpath.h"
#include "../world/Location.hpp"
@@ -109,7 +111,9 @@ GameActions::Result FootpathPlaceAction::Query() const
GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_ERR_VALUE_OUT_OF_RANGE);
}
FootpathProvisionalRemove();
auto intent = Intent(INTENT_ACTION_REMOVE_PROVISIONAL_FOOTPATH);
ContextBroadcastIntent(&intent);
auto tileElement = MapGetFootpathElementSlope(_loc, _slope);
if (tileElement == nullptr)
{

View File

@@ -51,6 +51,7 @@ enum IntentAction
INTENT_ACTION_PROGRESS_CLOSE,
INTENT_ACTION_REMOVE_PROVISIONAL_ELEMENTS,
INTENT_ACTION_RESTORE_PROVISIONAL_ELEMENTS,
INTENT_ACTION_REMOVE_PROVISIONAL_FOOTPATH,
INTENT_ACTION_NULL = 255,
};

View File

@@ -49,7 +49,6 @@ using namespace OpenRCT2::TrackMetaData;
void FootpathUpdateQueueEntranceBanner(const CoordsXY& footpathPos, TileElement* tileElement);
FootpathSelection gFootpathSelection;
ProvisionalFootpath gProvisionalFootpath;
uint16_t gFootpathSelectedId;
CoordsXYZ gFootpathConstructFromPosition;
uint8_t gFootpathConstructSlope;
@@ -121,99 +120,6 @@ PathElement* MapGetFootpathElement(const CoordsXYZ& coords)
return nullptr;
}
/**
*
* rct2: 0x006A76FF
*/
money64 FootpathProvisionalSet(
ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope,
PathConstructFlags constructFlags)
{
money64 cost;
FootpathProvisionalRemove();
auto footpathPlaceAction = FootpathPlaceAction(footpathLoc, slope, type, railingsType, INVALID_DIRECTION, constructFlags);
footpathPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED);
auto res = GameActions::Execute(&footpathPlaceAction);
cost = res.Error == GameActions::Status::Ok ? res.Cost : kMoney64Undefined;
if (res.Error == GameActions::Status::Ok)
{
gProvisionalFootpath.SurfaceIndex = type;
gProvisionalFootpath.RailingsIndex = railingsType;
gProvisionalFootpath.Position = footpathLoc;
gProvisionalFootpath.Slope = slope;
gProvisionalFootpath.ConstructFlags = constructFlags;
gProvisionalFootpath.Flags |= PROVISIONAL_PATH_FLAG_1;
if (gFootpathGroundFlags & ELEMENT_IS_UNDERGROUND)
{
ViewportSetVisibility(ViewportVisibility::UndergroundViewOn);
}
else
{
ViewportSetVisibility(ViewportVisibility::UndergroundViewOff);
}
}
// Invalidate previous footpath piece.
VirtualFloorInvalidate();
if (!isToolActive(WindowClass::Scenery))
{
if (res.Error != GameActions::Status::Ok)
{
// If we can't build this, don't show a virtual floor.
VirtualFloorSetHeight(0);
}
else if (
gProvisionalFootpath.Slope == kTileSlopeFlat || gProvisionalFootpath.Position.z < gFootpathConstructFromPosition.z)
{
// Going either straight on, or down.
VirtualFloorSetHeight(gProvisionalFootpath.Position.z);
}
else
{
// Going up in the world!
VirtualFloorSetHeight(gProvisionalFootpath.Position.z + LAND_HEIGHT_STEP);
}
}
return cost;
}
/**
*
* rct2: 0x006A77FF
*/
void FootpathProvisionalRemove()
{
if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1)
{
gProvisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_1;
auto action = FootpathRemoveAction(gProvisionalFootpath.Position);
action.SetFlags(GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST);
GameActions::Execute(&action);
}
}
/**
*
* rct2: 0x006A7831
*/
void FootpathProvisionalUpdate()
{
if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_SHOW_ARROW)
{
gProvisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_SHOW_ARROW;
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_ARROW;
MapInvalidateTileFull(gFootpathConstructFromPosition);
}
FootpathProvisionalRemove();
}
/**
*
* rct2: 0x00673883

View File

@@ -173,7 +173,6 @@ enum
};
extern FootpathSelection gFootpathSelection;
extern ProvisionalFootpath gProvisionalFootpath;
extern uint16_t gFootpathSelectedId;
extern CoordsXYZ gFootpathConstructFromPosition;
extern uint8_t gFootpathConstructSlope;
@@ -186,11 +185,6 @@ extern const std::array<CoordsXY, kNumOrthogonalDirections * 2> BenchUseOffsets;
PathElement* MapGetFootpathElement(const CoordsXYZ& coords);
void FootpathInterruptPeeps(const CoordsXYZ& footpathPos);
money64 FootpathProvisionalSet(
ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope,
PathConstructFlags constructFlags);
void FootpathProvisionalRemove();
void FootpathProvisionalUpdate();
void FootpathRemoveLitter(const CoordsXYZ& footpathPos);
void FootpathConnectEdges(const CoordsXY& footpathPos, TileElement* tileElement, int32_t flags);
void FootpathUpdateQueueChains();