mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-22 22:34:33 +01:00
Prepare footpath handling for surfaces and railings
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <openrct2-ui/interface/Widget.h>
|
||||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Cheats.h>
|
||||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
@@ -19,7 +20,10 @@
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/object/FootpathObject.h>
|
||||
#include <openrct2/object/FootpathRailingsObject.h>
|
||||
#include <openrct2/object/FootpathSurfaceObject.h>
|
||||
#include <openrct2/object/ObjectLimits.h>
|
||||
#include <openrct2/object/ObjectManager.h>
|
||||
#include <openrct2/platform/platform.h>
|
||||
#include <openrct2/sprites.h>
|
||||
#include <openrct2/world/Footpath.h>
|
||||
@@ -31,11 +35,12 @@ static constexpr const int32_t WH = 381;
|
||||
static constexpr const int32_t WW = 106;
|
||||
static constexpr const uint16_t ARROW_PULSE_DURATION = 200;
|
||||
|
||||
static uint8_t _footpathSelectedType;
|
||||
static uint8_t _footpathConstructDirection;
|
||||
static uint8_t _footpathConstructValidDirections;
|
||||
static uint8_t _footpathConstructionMode;
|
||||
|
||||
static std::vector<std::pair<ObjectType, ObjectEntryIndex>> _dropdownEntries;
|
||||
|
||||
// clang-format off
|
||||
enum
|
||||
{
|
||||
@@ -178,7 +183,7 @@ static void window_footpath_start_bridge_at_point(const ScreenCoordsXY& screenCo
|
||||
static void window_footpath_construct();
|
||||
static void window_footpath_remove();
|
||||
static void window_footpath_set_enabled_and_pressed_widgets();
|
||||
static void footpath_get_next_path_info(int32_t* type, CoordsXYZ& footpathLoc, int32_t* slope);
|
||||
static void footpath_get_next_path_info(ObjectEntryIndex* type, CoordsXYZ& footpathLoc, int32_t* slope);
|
||||
static bool footpath_select_default();
|
||||
|
||||
/**
|
||||
@@ -187,21 +192,10 @@ static bool footpath_select_default();
|
||||
*/
|
||||
rct_window* window_footpath_open()
|
||||
{
|
||||
// If a restricted path was selected when the game is no longer in Sandbox mode, reset it
|
||||
const auto* legacyPathEntry = GetLegacyFootpathEntry(gFootpathSelectedId);
|
||||
if (legacyPathEntry != nullptr && legacyPathEntry->GetPathSurfaceDescriptor().IsEditorOnly() && !gCheatsSandboxMode)
|
||||
if (!footpath_select_default())
|
||||
{
|
||||
legacyPathEntry = nullptr;
|
||||
}
|
||||
|
||||
// Select the default path if we don't have one
|
||||
if (legacyPathEntry == nullptr)
|
||||
{
|
||||
if (!footpath_select_default())
|
||||
{
|
||||
// No path objects to select from, don't open window
|
||||
return nullptr;
|
||||
}
|
||||
// No path objects to select from, don't open window
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if window is already open
|
||||
@@ -211,7 +205,7 @@ rct_window* window_footpath_open()
|
||||
return window;
|
||||
}
|
||||
|
||||
window = WindowCreate(ScreenCoordsXY(0, 29), 106, 381, &window_footpath_events, WC_FOOTPATH, 0);
|
||||
window = WindowCreate(ScreenCoordsXY(0, 29), WW, WH, &window_footpath_events, WC_FOOTPATH, 0);
|
||||
window->widgets = window_footpath_widgets;
|
||||
window->enabled_widgets = (1ULL << WIDX_CLOSE) | (1ULL << WIDX_FOOTPATH_TYPE) | (1ULL << WIDX_QUEUELINE_TYPE)
|
||||
| (1ULL << WIDX_DIRECTION_NW) | (1ULL << WIDX_DIRECTION_NE) | (1ULL << WIDX_DIRECTION_SW) | (1ULL << WIDX_DIRECTION_SE)
|
||||
@@ -344,53 +338,41 @@ static void window_footpath_mousedown(rct_window* w, rct_widgetindex widgetIndex
|
||||
*/
|
||||
static void window_footpath_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex)
|
||||
{
|
||||
if (dropdownIndex < 0 || static_cast<size_t>(dropdownIndex) >= _dropdownEntries.size())
|
||||
return;
|
||||
|
||||
auto entryIndex = _dropdownEntries[dropdownIndex];
|
||||
if (widgetIndex == WIDX_FOOTPATH_TYPE)
|
||||
{
|
||||
_footpathSelectedType = SELECTED_PATH_TYPE_NORMAL;
|
||||
gFootpathSelection.IsQueueSelected = false;
|
||||
if (entryIndex.first == ObjectType::Paths)
|
||||
{
|
||||
gFootpathSelection.LegacyPath = entryIndex.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
gFootpathSelection.LegacyPath = OBJECT_ENTRY_INDEX_NULL;
|
||||
gFootpathSelection.NormalSurface = entryIndex.second;
|
||||
}
|
||||
}
|
||||
else if (widgetIndex == WIDX_QUEUELINE_TYPE)
|
||||
{
|
||||
_footpathSelectedType = SELECTED_PATH_TYPE_QUEUE;
|
||||
gFootpathSelection.IsQueueSelected = true;
|
||||
if (entryIndex.first == ObjectType::Paths)
|
||||
{
|
||||
gFootpathSelection.LegacyPath = entryIndex.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
gFootpathSelection.LegacyPath = OBJECT_ENTRY_INDEX_NULL;
|
||||
gFootpathSelection.QueueSurface = entryIndex.second;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get path id
|
||||
int32_t pathId = dropdownIndex;
|
||||
if (pathId == -1)
|
||||
{
|
||||
pathId = gFootpathSelectedId;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool showEditorPaths = ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode);
|
||||
|
||||
int32_t i = 0, j = 0;
|
||||
for (; i < MAX_PATH_OBJECTS; i++)
|
||||
{
|
||||
const auto* legacyPathEntry = GetLegacyFootpathEntry(i);
|
||||
if (legacyPathEntry == nullptr)
|
||||
continue;
|
||||
|
||||
const PathSurfaceDescriptor& surfaceDescriptor = legacyPathEntry->GetPathSurfaceDescriptor();
|
||||
if (surfaceDescriptor.IsEditorOnly() && !showEditorPaths)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (j == pathId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
pathId = i;
|
||||
}
|
||||
|
||||
// Set selected path id
|
||||
gFootpathSelectedId = pathId;
|
||||
footpath_provisional_update();
|
||||
_window_footpath_cost = MONEY32_UNDEFINED;
|
||||
w->Invalidate();
|
||||
@@ -458,7 +440,7 @@ static void window_footpath_toolup(rct_window* w, rct_widgetindex widgetIndex, c
|
||||
*/
|
||||
static void window_footpath_update_provisional_path_for_bridge_mode(rct_window* w)
|
||||
{
|
||||
int32_t type, slope;
|
||||
int32_t slope;
|
||||
|
||||
if (_footpathConstructionMode != PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL)
|
||||
{
|
||||
@@ -475,9 +457,21 @@ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window*
|
||||
// Update provisional bridge mode path
|
||||
if (!(gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1))
|
||||
{
|
||||
ObjectEntryIndex type;
|
||||
ObjectEntryIndex railings = gFootpathSelection.Railings;
|
||||
|
||||
CoordsXYZ footpathLoc;
|
||||
footpath_get_next_path_info(&type, footpathLoc, &slope);
|
||||
_window_footpath_cost = footpath_provisional_set(type, footpathLoc, slope);
|
||||
PathConstructFlags pathConstructFlags = 0;
|
||||
if (gFootpathSelection.IsQueueSelected)
|
||||
pathConstructFlags |= PathConstructFlag::IsQueue;
|
||||
if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL)
|
||||
{
|
||||
pathConstructFlags |= PathConstructFlag::IsLegacyPathObject;
|
||||
type = gFootpathSelection.LegacyPath;
|
||||
}
|
||||
|
||||
_window_footpath_cost = footpath_provisional_set(type, railings, footpathLoc, slope, pathConstructFlags);
|
||||
widget_invalidate(w, WIDX_CONSTRUCT);
|
||||
}
|
||||
|
||||
@@ -490,7 +484,7 @@ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window*
|
||||
|
||||
gProvisionalFootpath.Flags ^= PROVISIONAL_PATH_FLAG_SHOW_ARROW;
|
||||
CoordsXYZ footpathLoc;
|
||||
footpath_get_next_path_info(&type, footpathLoc, &slope);
|
||||
footpath_get_next_path_info(nullptr, footpathLoc, &slope);
|
||||
gMapSelectArrowPosition = footpathLoc;
|
||||
gMapSelectArrowDirection = _footpathConstructDirection;
|
||||
if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_SHOW_ARROW)
|
||||
@@ -564,25 +558,52 @@ static void window_footpath_invalidate(rct_window* w)
|
||||
// Press / unpress footpath and queue type buttons
|
||||
w->pressed_widgets &= ~(1ULL << WIDX_FOOTPATH_TYPE);
|
||||
w->pressed_widgets &= ~(1ULL << WIDX_QUEUELINE_TYPE);
|
||||
w->pressed_widgets |= _footpathSelectedType == SELECTED_PATH_TYPE_NORMAL ? (1ULL << WIDX_FOOTPATH_TYPE)
|
||||
: (1ULL << WIDX_QUEUELINE_TYPE);
|
||||
w->pressed_widgets |= gFootpathSelection.IsQueueSelected ? (1ULL << WIDX_QUEUELINE_TYPE) : (1ULL << WIDX_FOOTPATH_TYPE);
|
||||
|
||||
// Enable / disable construct button
|
||||
window_footpath_widgets[WIDX_CONSTRUCT].type = _footpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL
|
||||
? WindowWidgetType::ImgBtn
|
||||
: WindowWidgetType::Empty;
|
||||
|
||||
// Set footpath and queue type button images
|
||||
auto pathImage = static_cast<uint32_t>(SPR_NONE);
|
||||
auto queueImage = static_cast<uint32_t>(SPR_NONE);
|
||||
const auto* legacyPathEntry = GetLegacyFootpathEntry(gFootpathSelectedId);
|
||||
if (legacyPathEntry != nullptr)
|
||||
if (gFootpathSelection.LegacyPath == OBJECT_ENTRY_INDEX_NULL)
|
||||
{
|
||||
pathImage = legacyPathEntry->GetPathSurfaceDescriptor().PreviewImage;
|
||||
queueImage = legacyPathEntry->GetQueueSurfaceDescriptor().PreviewImage;
|
||||
// Set footpath and queue type button images
|
||||
auto pathImage = static_cast<uint32_t>(SPR_NONE);
|
||||
auto queueImage = static_cast<uint32_t>(SPR_NONE);
|
||||
auto pathEntry = GetPathSurfaceEntry(gFootpathSelection.NormalSurface);
|
||||
if (pathEntry != nullptr)
|
||||
{
|
||||
pathImage = pathEntry->PreviewImageId;
|
||||
}
|
||||
|
||||
pathEntry = GetPathSurfaceEntry(gFootpathSelection.QueueSurface);
|
||||
if (pathEntry != nullptr)
|
||||
{
|
||||
queueImage = pathEntry->PreviewImageId;
|
||||
}
|
||||
|
||||
window_footpath_widgets[WIDX_FOOTPATH_TYPE].image = pathImage;
|
||||
window_footpath_widgets[WIDX_QUEUELINE_TYPE].image = queueImage;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
|
||||
|
||||
// Set footpath and queue type button images
|
||||
auto pathImage = static_cast<uint32_t>(SPR_NONE);
|
||||
auto queueImage = static_cast<uint32_t>(SPR_NONE);
|
||||
auto pathObj = static_cast<FootpathObject*>(
|
||||
objManager.GetLoadedObject(ObjectType::Paths, gFootpathSelection.LegacyPath));
|
||||
if (pathObj != nullptr)
|
||||
{
|
||||
auto pathEntry = reinterpret_cast<rct_footpath_entry*>(pathObj->GetLegacyData());
|
||||
pathImage = pathEntry->GetPreviewImage();
|
||||
queueImage = pathEntry->GetQueuePreviewImage();
|
||||
}
|
||||
|
||||
window_footpath_widgets[WIDX_FOOTPATH_TYPE].image = pathImage;
|
||||
window_footpath_widgets[WIDX_QUEUELINE_TYPE].image = queueImage;
|
||||
}
|
||||
window_footpath_widgets[WIDX_FOOTPATH_TYPE].image = pathImage;
|
||||
window_footpath_widgets[WIDX_QUEUELINE_TYPE].image = queueImage;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -607,22 +628,42 @@ static void window_footpath_paint(rct_window* w, rct_drawpixelinfo* dpi)
|
||||
{
|
||||
slope = TILE_ELEMENT_SLOPE_E_CORNER_UP;
|
||||
}
|
||||
int32_t image = ConstructionPreviewImages[slope][direction];
|
||||
|
||||
const auto* legacyPathEntry = GetLegacyFootpathEntry(gFootpathSelectedId);
|
||||
if (legacyPathEntry != nullptr)
|
||||
std::optional<uint32_t> baseImage;
|
||||
if (gFootpathSelection.LegacyPath == OBJECT_ENTRY_INDEX_NULL)
|
||||
{
|
||||
if (_footpathSelectedType == SELECTED_PATH_TYPE_NORMAL)
|
||||
image += legacyPathEntry->GetPathSurfaceDescriptor().Image;
|
||||
else
|
||||
image += legacyPathEntry->GetQueueSurfaceDescriptor().Image;
|
||||
auto selectedPath = gFootpathSelection.GetSelectedSurface();
|
||||
const auto* pathType = GetPathSurfaceEntry(selectedPath);
|
||||
if (pathType != nullptr)
|
||||
{
|
||||
baseImage = pathType->BaseImageId;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
|
||||
auto* pathObj = static_cast<FootpathObject*>(
|
||||
objManager.GetLoadedObject(ObjectType::Paths, gFootpathSelection.LegacyPath));
|
||||
if (pathObj != nullptr)
|
||||
{
|
||||
auto pathEntry = reinterpret_cast<const rct_footpath_entry*>(pathObj->GetLegacyData());
|
||||
if (gFootpathSelection.IsQueueSelected)
|
||||
baseImage = pathEntry->GetQueueImage();
|
||||
else
|
||||
baseImage = pathEntry->image;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw construction image
|
||||
screenCoords = w->windowPos
|
||||
+ ScreenCoordsXY{ window_footpath_widgets[WIDX_CONSTRUCT].midX(),
|
||||
window_footpath_widgets[WIDX_CONSTRUCT].bottom - 60 };
|
||||
gfx_draw_sprite(dpi, ImageId(image), screenCoords);
|
||||
if (baseImage)
|
||||
{
|
||||
auto image = *baseImage + ConstructionPreviewImages[slope][direction];
|
||||
|
||||
// Draw construction image
|
||||
screenCoords = w->windowPos
|
||||
+ ScreenCoordsXY{ window_footpath_widgets[WIDX_CONSTRUCT].midX(),
|
||||
window_footpath_widgets[WIDX_CONSTRUCT].bottom - 60 };
|
||||
gfx_draw_sprite(dpi, ImageId(image), screenCoords);
|
||||
}
|
||||
|
||||
// Draw build this... label
|
||||
screenCoords = w->windowPos
|
||||
@@ -651,30 +692,63 @@ static void window_footpath_paint(rct_window* w, rct_drawpixelinfo* dpi)
|
||||
*/
|
||||
static void window_footpath_show_footpath_types_dialog(rct_window* w, rct_widget* widget, bool showQueues)
|
||||
{
|
||||
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
|
||||
|
||||
uint32_t numPathTypes = 0;
|
||||
// If the game is in sandbox mode, also show paths that are normally restricted to the scenario editor
|
||||
bool showEditorPaths = ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode);
|
||||
|
||||
for (int32_t i = 0; i < MAX_PATH_OBJECTS; i++)
|
||||
_dropdownEntries.clear();
|
||||
std::optional<size_t> defaultIndex;
|
||||
for (ObjectEntryIndex i = 0; i < MAX_FOOTPATH_SURFACE_OBJECTS; i++)
|
||||
{
|
||||
const auto* legacyPathEntry = GetLegacyFootpathEntry(i);
|
||||
if (legacyPathEntry == nullptr)
|
||||
const auto* pathType = static_cast<FootpathSurfaceObject*>(objManager.GetLoadedObject(ObjectType::FootpathSurface, i));
|
||||
if (pathType == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& surfaceDescriptor = (showQueues) ? legacyPathEntry->GetQueueSurfaceDescriptor()
|
||||
: legacyPathEntry->GetPathSurfaceDescriptor();
|
||||
|
||||
if (surfaceDescriptor.IsEditorOnly() && !showEditorPaths)
|
||||
if ((pathType->Flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR) && !showEditorPaths)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto image = surfaceDescriptor.PreviewImage;
|
||||
if (showQueues != ((pathType->Flags & FOOTPATH_ENTRY_FLAG_IS_QUEUE) != 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (gFootpathSelection.LegacyPath == OBJECT_ENTRY_INDEX_NULL
|
||||
&& i == (showQueues ? gFootpathSelection.QueueSurface : gFootpathSelection.NormalSurface))
|
||||
{
|
||||
defaultIndex = numPathTypes;
|
||||
}
|
||||
|
||||
gDropdownItemsFormat[numPathTypes] = STR_NONE;
|
||||
gDropdownItemsArgs[numPathTypes] = image;
|
||||
gDropdownItemsArgs[numPathTypes] = pathType->PreviewImageId;
|
||||
_dropdownEntries.push_back({ ObjectType::FootpathSurface, i });
|
||||
numPathTypes++;
|
||||
}
|
||||
|
||||
for (ObjectEntryIndex i = 0; i < MAX_PATH_OBJECTS; i++)
|
||||
{
|
||||
auto* pathObj = static_cast<FootpathObject*>(objManager.GetLoadedObject(ObjectType::Paths, i));
|
||||
if (pathObj == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto pathEntry = reinterpret_cast<const rct_footpath_entry*>(pathObj->GetLegacyData());
|
||||
if ((pathEntry->flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR) && !showEditorPaths)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL && gFootpathSelection.LegacyPath == i)
|
||||
{
|
||||
defaultIndex = numPathTypes;
|
||||
}
|
||||
|
||||
gDropdownItemsFormat[numPathTypes] = STR_NONE;
|
||||
gDropdownItemsArgs[numPathTypes] = showQueues ? pathEntry->GetQueuePreviewImage() : pathEntry->GetPreviewImage();
|
||||
_dropdownEntries.push_back({ ObjectType::Paths, i });
|
||||
numPathTypes++;
|
||||
}
|
||||
|
||||
@@ -682,6 +756,8 @@ static void window_footpath_show_footpath_types_dialog(rct_window* w, rct_widget
|
||||
WindowDropdownShowImage(
|
||||
w->windowPos.x + widget->left, w->windowPos.y + widget->top, widget->height() + 1, w->colours[1], 0, numPathTypes, 47,
|
||||
36, itemsPerRow);
|
||||
if (defaultIndex)
|
||||
gDropdownDefaultIndex = static_cast<int32_t>(*defaultIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -777,9 +853,20 @@ static void window_footpath_set_provisional_path_at_point(const ScreenCoordsXY&
|
||||
slope &= ~RAISE_FOOTPATH_FLAG;
|
||||
z += PATH_HEIGHT_STEP;
|
||||
}
|
||||
int32_t pathType = (_footpathSelectedType << 7) + (gFootpathSelectedId & 0xFF);
|
||||
|
||||
_window_footpath_cost = footpath_provisional_set(pathType, { info.Loc, z }, slope);
|
||||
PathConstructFlags constructFlags = 0;
|
||||
auto pathType = gFootpathSelection.GetSelectedSurface();
|
||||
if (gFootpathSelection.IsQueueSelected)
|
||||
{
|
||||
constructFlags |= PathConstructFlag::IsQueue;
|
||||
}
|
||||
if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL)
|
||||
{
|
||||
constructFlags |= PathConstructFlag::IsLegacyPathObject;
|
||||
pathType = gFootpathSelection.LegacyPath;
|
||||
}
|
||||
_window_footpath_cost = footpath_provisional_set(
|
||||
pathType, gFootpathSelection.Railings, { info.Loc, z }, slope, constructFlags);
|
||||
window_invalidate_by_class(WC_FOOTPATH);
|
||||
}
|
||||
}
|
||||
@@ -872,11 +959,22 @@ static void window_footpath_place_path_at_point(const ScreenCoordsXY& screenCoor
|
||||
slope &= ~RAISE_FOOTPATH_FLAG;
|
||||
z += PATH_HEIGHT_STEP;
|
||||
}
|
||||
auto selectedType = (_footpathSelectedType << 7) + (gFootpathSelectedId & 0xFF);
|
||||
|
||||
// Try and place path
|
||||
gGameCommandErrorTitle = STR_CANT_BUILD_FOOTPATH_HERE;
|
||||
auto footpathPlaceAction = FootpathPlaceAction({ info.Loc, z }, slope, selectedType);
|
||||
auto selectedType = gFootpathSelection.GetSelectedSurface();
|
||||
PathConstructFlags constructFlags = 0;
|
||||
if (gFootpathSelection.IsQueueSelected)
|
||||
{
|
||||
constructFlags |= PathConstructFlag::IsQueue;
|
||||
}
|
||||
if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL)
|
||||
{
|
||||
constructFlags |= PathConstructFlag::IsLegacyPathObject;
|
||||
selectedType = gFootpathSelection.LegacyPath;
|
||||
}
|
||||
auto footpathPlaceAction = FootpathPlaceAction(
|
||||
{ info.Loc, z }, slope, selectedType, gFootpathSelection.Railings, INVALID_DIRECTION, constructFlags);
|
||||
footpathPlaceAction.SetCallback([](const GameAction* ga, const GameActions::Result* result) {
|
||||
if (result->Error == GameActions::Status::Ok)
|
||||
{
|
||||
@@ -960,12 +1058,22 @@ static void window_footpath_construct()
|
||||
_window_footpath_cost = MONEY32_UNDEFINED;
|
||||
footpath_provisional_update();
|
||||
|
||||
int32_t type, slope;
|
||||
ObjectEntryIndex type;
|
||||
int32_t slope;
|
||||
CoordsXYZ footpathLoc;
|
||||
footpath_get_next_path_info(&type, footpathLoc, &slope);
|
||||
|
||||
gGameCommandErrorTitle = STR_CANT_BUILD_FOOTPATH_HERE;
|
||||
auto footpathPlaceAction = FootpathPlaceAction(footpathLoc, slope, type, _footpathConstructDirection);
|
||||
PathConstructFlags constructFlags = 0;
|
||||
if (gFootpathSelection.IsQueueSelected)
|
||||
constructFlags |= PathConstructFlag::IsQueue;
|
||||
if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL)
|
||||
{
|
||||
constructFlags |= PathConstructFlag::IsLegacyPathObject;
|
||||
type = gFootpathSelection.LegacyPath;
|
||||
}
|
||||
auto footpathPlaceAction = FootpathPlaceAction(
|
||||
footpathLoc, slope, type, gFootpathSelection.Railings, _footpathConstructDirection, constructFlags);
|
||||
footpathPlaceAction.SetCallback([=](const GameAction* ga, const GameActions::Result* result) {
|
||||
if (result->Error == GameActions::Status::Ok)
|
||||
{
|
||||
@@ -1201,15 +1309,16 @@ static void window_footpath_set_enabled_and_pressed_widgets()
|
||||
*
|
||||
* rct2: 0x006A7B20
|
||||
*/
|
||||
static void footpath_get_next_path_info(int32_t* type, CoordsXYZ& footpathLoc, int32_t* slope)
|
||||
static void footpath_get_next_path_info(ObjectEntryIndex* type, CoordsXYZ& footpathLoc, int32_t* slope)
|
||||
{
|
||||
int32_t direction;
|
||||
|
||||
direction = _footpathConstructDirection;
|
||||
auto direction = _footpathConstructDirection;
|
||||
footpathLoc.x = gFootpathConstructFromPosition.x + CoordsDirectionDelta[direction].x;
|
||||
footpathLoc.y = gFootpathConstructFromPosition.y + CoordsDirectionDelta[direction].y;
|
||||
footpathLoc.z = gFootpathConstructFromPosition.z;
|
||||
*type = (_footpathSelectedType << 7) + (gFootpathSelectedId & 0xFF);
|
||||
if (type != nullptr)
|
||||
{
|
||||
*type = gFootpathSelection.GetSelectedSurface();
|
||||
}
|
||||
*slope = TILE_ELEMENT_SLOPE_FLAT;
|
||||
if (gFootpathConstructSlope != 0)
|
||||
{
|
||||
@@ -1222,34 +1331,141 @@ static void footpath_get_next_path_info(int32_t* type, CoordsXYZ& footpathLoc, i
|
||||
}
|
||||
}
|
||||
|
||||
static bool footpath_select_default()
|
||||
static ObjectEntryIndex footpath_get_default_surface(bool queue)
|
||||
{
|
||||
// Select first available footpath
|
||||
int32_t footpathId = -1;
|
||||
for (int32_t i = 0; i < object_entry_group_counts[EnumValue(ObjectType::Paths)]; i++)
|
||||
bool showEditorPaths = ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode);
|
||||
for (ObjectEntryIndex i = 0; i < MAX_FOOTPATH_SURFACE_OBJECTS; i++)
|
||||
{
|
||||
const auto* footpathObject = GetLegacyFootpathEntry(i);
|
||||
if (footpathObject == nullptr)
|
||||
continue;
|
||||
|
||||
footpathId = i;
|
||||
|
||||
const PathSurfaceDescriptor& surfaceDescriptor = footpathObject->GetPathSurfaceDescriptor();
|
||||
// Prioritise non-restricted path
|
||||
if (!surfaceDescriptor.IsEditorOnly())
|
||||
auto pathEntry = GetPathSurfaceEntry(i);
|
||||
if (pathEntry != nullptr)
|
||||
{
|
||||
break;
|
||||
if (!showEditorPaths && (pathEntry->Flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (queue == ((pathEntry->Flags & FOOTPATH_ENTRY_FLAG_IS_QUEUE) != 0))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (footpathId == -1)
|
||||
return OBJECT_ENTRY_INDEX_NULL;
|
||||
}
|
||||
|
||||
static ObjectEntryIndex footpath_get_default_railing()
|
||||
{
|
||||
for (ObjectEntryIndex i = 0; i < MAX_FOOTPATH_RAILINGS_OBJECTS; i++)
|
||||
{
|
||||
return false;
|
||||
const auto* railingEntry = GetPathRailingsEntry(i);
|
||||
if (railingEntry != nullptr)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
else
|
||||
return OBJECT_ENTRY_INDEX_NULL;
|
||||
}
|
||||
|
||||
static bool footpath_is_surface_okay(ObjectEntryIndex index, bool queue)
|
||||
{
|
||||
auto pathEntry = GetPathSurfaceEntry(index);
|
||||
if (pathEntry != nullptr)
|
||||
{
|
||||
gFootpathSelectedId = footpathId;
|
||||
return true;
|
||||
bool showEditorPaths = ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode);
|
||||
if (!showEditorPaths && (pathEntry->Flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (queue == ((pathEntry->Flags & FOOTPATH_ENTRY_FLAG_IS_QUEUE) != 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool footpath_is_legacy_path_okay(ObjectEntryIndex index)
|
||||
{
|
||||
bool showEditorPaths = ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode);
|
||||
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
|
||||
auto footpathObj = static_cast<FootpathObject*>(objManager.GetLoadedObject(ObjectType::Paths, index));
|
||||
if (footpathObj != nullptr)
|
||||
{
|
||||
auto pathEntry = reinterpret_cast<rct_footpath_entry*>(footpathObj->GetLegacyData());
|
||||
return showEditorPaths || !(pathEntry->flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static ObjectEntryIndex footpath_get_default_legacy_path()
|
||||
{
|
||||
for (ObjectEntryIndex i = 0; i < MAX_PATH_OBJECTS; i++)
|
||||
{
|
||||
if (footpath_is_legacy_path_okay(i))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return OBJECT_ENTRY_INDEX_NULL;
|
||||
}
|
||||
|
||||
static bool footpath_select_default()
|
||||
{
|
||||
// Select default footpath
|
||||
auto surfaceIndex = footpath_get_default_surface(false);
|
||||
if (footpath_is_surface_okay(gFootpathSelection.NormalSurface, false))
|
||||
{
|
||||
surfaceIndex = gFootpathSelection.NormalSurface;
|
||||
}
|
||||
|
||||
// Select default queue
|
||||
auto queueIndex = footpath_get_default_surface(true);
|
||||
if (footpath_is_surface_okay(gFootpathSelection.QueueSurface, true))
|
||||
{
|
||||
queueIndex = gFootpathSelection.QueueSurface;
|
||||
}
|
||||
|
||||
// Select default railing
|
||||
auto railingIndex = footpath_get_default_railing();
|
||||
const auto* railingEntry = GetPathRailingsEntry(gFootpathSelection.Railings);
|
||||
if (railingEntry != nullptr)
|
||||
{
|
||||
railingIndex = gFootpathSelection.Railings;
|
||||
}
|
||||
|
||||
// Select default legacy path
|
||||
auto legacyPathIndex = footpath_get_default_legacy_path();
|
||||
if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL)
|
||||
{
|
||||
if (footpath_is_legacy_path_okay(gFootpathSelection.LegacyPath))
|
||||
{
|
||||
// Keep legacy path selected
|
||||
legacyPathIndex = gFootpathSelection.LegacyPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset legacy path, we default to a surface (if there are any)
|
||||
gFootpathSelection.LegacyPath = OBJECT_ENTRY_INDEX_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (surfaceIndex == OBJECT_ENTRY_INDEX_NULL)
|
||||
{
|
||||
if (legacyPathIndex == OBJECT_ENTRY_INDEX_NULL)
|
||||
{
|
||||
// No surfaces or legacy paths available
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No surfaces available, so default to legacy path
|
||||
gFootpathSelection.LegacyPath = legacyPathIndex;
|
||||
}
|
||||
}
|
||||
|
||||
gFootpathSelection.NormalSurface = surfaceIndex;
|
||||
gFootpathSelection.QueueSurface = queueIndex;
|
||||
gFootpathSelection.Railings = railingIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
void window_footpath_keyboard_shortcut_turn_left()
|
||||
@@ -1349,5 +1565,5 @@ void window_footpath_keyboard_shortcut_build_current()
|
||||
|
||||
void window_footpath_reset_selected_path()
|
||||
{
|
||||
_footpathSelectedType = 0;
|
||||
gFootpathSelection = {};
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <openrct2/core/Guard.hpp>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/localisation/StringIds.h>
|
||||
#include <openrct2/object/FootpathObject.h>
|
||||
#include <openrct2/object/TerrainEdgeObject.h>
|
||||
#include <openrct2/object/TerrainSurfaceObject.h>
|
||||
#include <openrct2/ride/RideData.h>
|
||||
|
||||
@@ -25,11 +25,15 @@
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
FootpathPlaceAction::FootpathPlaceAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, Direction direction)
|
||||
FootpathPlaceAction::FootpathPlaceAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, Direction direction,
|
||||
PathConstructFlags constructFlags)
|
||||
: _loc(loc)
|
||||
, _slope(slope)
|
||||
, _type(type)
|
||||
, _railingsType(railingsType)
|
||||
, _direction(direction)
|
||||
, _constructFlags(constructFlags)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -37,8 +41,10 @@ void FootpathPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(_loc);
|
||||
visitor.Visit("object", _type);
|
||||
visitor.Visit("railingsObject", _railingsType);
|
||||
visitor.Visit("direction", _direction);
|
||||
visitor.Visit("slope", _slope);
|
||||
visitor.Visit("constructFlags", _constructFlags);
|
||||
}
|
||||
|
||||
uint16_t FootpathPlaceAction::GetActionFlags() const
|
||||
@@ -50,7 +56,8 @@ void FootpathPlaceAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
GameAction::Serialise(stream);
|
||||
|
||||
stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_direction);
|
||||
stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_railingsType) << DS_TAG(_direction)
|
||||
<< DS_TAG(_constructFlags);
|
||||
}
|
||||
|
||||
GameActions::Result::Ptr FootpathPlaceAction::Query() const
|
||||
@@ -149,11 +156,64 @@ GameActions::Result::Ptr FootpathPlaceAction::Execute() const
|
||||
}
|
||||
}
|
||||
|
||||
bool FootpathPlaceAction::IsSameAsPathElement(const PathElement* pathElement) const
|
||||
{
|
||||
// Check if both this action and the element is queue
|
||||
if (pathElement->IsQueue() != ((_constructFlags & PathConstructFlag::IsQueue) != 0))
|
||||
return false;
|
||||
|
||||
auto footpathObj = pathElement->GetLegacyPathEntry();
|
||||
if (footpathObj == nullptr)
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pathElement->GetSurfaceEntryIndex() == _type && pathElement->GetRailingsEntryIndex() == _railingsType;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return pathElement->GetLegacyPathEntryIndex() == _type;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FootpathPlaceAction::IsSameAsEntranceElement(const EntranceElement& entranceElement) const
|
||||
{
|
||||
if (entranceElement.HasLegacyPathEntry())
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return entranceElement.GetLegacyPathEntryIndex() == _type;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return entranceElement.GetSurfaceEntryIndex() == _type;
|
||||
}
|
||||
}
|
||||
|
||||
GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateQuery(PathElement* pathElement, GameActions::Result::Ptr res) const
|
||||
{
|
||||
const int32_t newFootpathType = (_type & (FOOTPATH_PROPERTIES_TYPE_MASK >> 4));
|
||||
const bool newPathIsQueue = ((_type >> 7) == 1);
|
||||
if (pathElement->GetLegacyPathEntryIndex() != newFootpathType || pathElement->IsQueue() != newPathIsQueue)
|
||||
if (!IsSameAsPathElement(pathElement))
|
||||
{
|
||||
res->Cost += MONEY(6, 00);
|
||||
}
|
||||
@@ -167,9 +227,7 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateQuery(PathElement* pa
|
||||
|
||||
GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateExecute(PathElement* pathElement, GameActions::Result::Ptr res) const
|
||||
{
|
||||
const int32_t newFootpathType = (_type & (FOOTPATH_PROPERTIES_TYPE_MASK >> 4));
|
||||
const bool newPathIsQueue = ((_type >> 7) == 1);
|
||||
if (pathElement->GetLegacyPathEntryIndex() != newFootpathType || pathElement->IsQueue() != newPathIsQueue)
|
||||
if (!IsSameAsPathElement(pathElement))
|
||||
{
|
||||
res->Cost += MONEY(6, 00);
|
||||
}
|
||||
@@ -181,14 +239,22 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateExecute(PathElement*
|
||||
footpath_remove_edges_at(_loc, reinterpret_cast<TileElement*>(pathElement));
|
||||
}
|
||||
|
||||
pathElement->SetLegacyPathEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE);
|
||||
bool isQueue = _type & FOOTPATH_ELEMENT_INSERT_QUEUE;
|
||||
pathElement->SetIsQueue(isQueue);
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
pathElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathElement->SetSurfaceEntryIndex(_type);
|
||||
pathElement->SetRailingsEntryIndex(_railingsType);
|
||||
}
|
||||
|
||||
pathElement->SetIsQueue((_constructFlags & PathConstructFlag::IsQueue) != 0);
|
||||
|
||||
auto* elem = pathElement->GetAdditionEntry();
|
||||
if (elem != nullptr)
|
||||
{
|
||||
if (isQueue)
|
||||
if (_constructFlags & PathConstructFlag::IsQueue)
|
||||
{
|
||||
// remove any addition that isn't a TV or a lamp
|
||||
if ((elem->flags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) == 0 && (elem->flags & PATH_BIT_FLAG_LAMP) == 0)
|
||||
@@ -238,16 +304,16 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertQuery(GameActions::Re
|
||||
{
|
||||
entrancePath = true;
|
||||
// Make the price the same as replacing a path
|
||||
if (entranceElement->GetLegacyPathEntryIndex() == (_type & 0xF))
|
||||
if (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res->Cost -= MONEY(6, 00);
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped.
|
||||
uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT)
|
||||
? CREATE_CROSSING_MODE_NONE
|
||||
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
||||
// Do not attempt to build a crossing with a queue or a sloped path.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
uint8_t crossingMode = isQueue || (_slope != TILE_ELEMENT_SLOPE_FLAT) ? CREATE_CROSSING_MODE_NONE
|
||||
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), crossingMode);
|
||||
if (!entrancePath && canBuild->Error != GameActions::Status::Ok)
|
||||
@@ -304,16 +370,16 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions::
|
||||
{
|
||||
entrancePath = true;
|
||||
// Make the price the same as replacing a path
|
||||
if (entranceElement->GetLegacyPathEntryIndex() == (_type & 0xF))
|
||||
if (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res->Cost -= MONEY(6, 00);
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped.
|
||||
uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT)
|
||||
? CREATE_CROSSING_MODE_NONE
|
||||
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
uint8_t crossingMode = isQueue || (_slope != TILE_ELEMENT_SLOPE_FLAT) ? CREATE_CROSSING_MODE_NONE
|
||||
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(),
|
||||
crossingMode);
|
||||
@@ -338,8 +404,14 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions::
|
||||
{
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath)
|
||||
{
|
||||
// Set the path type but make sure it's not a queue as that will not show up
|
||||
entranceElement->SetLegacyPathEntryIndex(_type & 0x7F);
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
entranceElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
entranceElement->SetSurfaceEntryIndex(_type);
|
||||
}
|
||||
map_invalidate_tile_full(_loc);
|
||||
}
|
||||
}
|
||||
@@ -349,10 +421,18 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions::
|
||||
Guard::Assert(pathElement != nullptr);
|
||||
|
||||
pathElement->SetClearanceZ(zHigh);
|
||||
pathElement->SetLegacyPathEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE);
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
pathElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathElement->SetSurfaceEntryIndex(_type);
|
||||
pathElement->SetRailingsEntryIndex(_railingsType);
|
||||
}
|
||||
pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK);
|
||||
pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED);
|
||||
pathElement->SetIsQueue(_type & FOOTPATH_ELEMENT_INSERT_QUEUE);
|
||||
pathElement->SetIsQueue(isQueue);
|
||||
pathElement->SetAddition(0);
|
||||
pathElement->SetRideIndex(RIDE_ID_NULL);
|
||||
pathElement->SetAdditionStatus(255);
|
||||
|
||||
@@ -18,12 +18,15 @@ private:
|
||||
CoordsXYZ _loc;
|
||||
uint8_t _slope{};
|
||||
ObjectEntryIndex _type{};
|
||||
ObjectEntryIndex _railingsType{};
|
||||
Direction _direction{ INVALID_DIRECTION };
|
||||
PathConstructFlags _constructFlags{};
|
||||
|
||||
public:
|
||||
FootpathPlaceAction() = default;
|
||||
FootpathPlaceAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, Direction direction = INVALID_DIRECTION);
|
||||
|
||||
FootpathPlaceAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType,
|
||||
Direction direction = INVALID_DIRECTION, PathConstructFlags constructFlags = 0);
|
||||
void AcceptParameters(GameActionParameterVisitor & visitor) override;
|
||||
|
||||
uint16_t GetActionFlags() const override;
|
||||
@@ -40,4 +43,6 @@ private:
|
||||
void AutomaticallySetPeepSpawn() const;
|
||||
void RemoveIntersectingWalls(PathElement * pathElement) const;
|
||||
PathElement* map_get_footpath_element_slope(const CoordsXYZ& footpathPos, int32_t slope) const;
|
||||
bool IsSameAsPathElement(const PathElement* pathElement) const;
|
||||
bool IsSameAsEntranceElement(const EntranceElement& entranceElement) const;
|
||||
};
|
||||
|
||||
@@ -22,11 +22,14 @@
|
||||
#include "../world/Wall.h"
|
||||
|
||||
FootpathPlaceFromTrackAction::FootpathPlaceFromTrackAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, uint8_t edges)
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, uint8_t edges,
|
||||
PathConstructFlags constructFlags)
|
||||
: _loc(loc)
|
||||
, _slope(slope)
|
||||
, _type(type)
|
||||
, _railingsType(railingsType)
|
||||
, _edges(edges)
|
||||
, _constructFlags(constructFlags)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -34,7 +37,8 @@ void FootpathPlaceFromTrackAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
GameAction::Serialise(stream);
|
||||
|
||||
stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_edges);
|
||||
stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_railingsType) << DS_TAG(_edges)
|
||||
<< DS_TAG(_constructFlags);
|
||||
}
|
||||
|
||||
uint16_t FootpathPlaceFromTrackAction::GetActionFlags() const
|
||||
@@ -122,16 +126,16 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertQuery(GameAc
|
||||
{
|
||||
entrancePath = true;
|
||||
// Make the price the same as replacing a path
|
||||
if (entranceElement->GetLegacyPathEntryIndex() == (_type & 0xF))
|
||||
if (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res->Cost -= MONEY(6, 00);
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped.
|
||||
uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT)
|
||||
? CREATE_CROSSING_MODE_NONE
|
||||
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
||||
// Do not attempt to build a crossing with a queue or a sloped path.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
uint8_t crossingMode = isQueue || (_slope != TILE_ELEMENT_SLOPE_FLAT) ? CREATE_CROSSING_MODE_NONE
|
||||
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), crossingMode);
|
||||
if (!entrancePath && canBuild->Error != GameActions::Status::Ok)
|
||||
@@ -189,16 +193,16 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(Game
|
||||
{
|
||||
entrancePath = true;
|
||||
// Make the price the same as replacing a path
|
||||
if (entranceElement->GetLegacyPathEntryIndex() == (_type & 0xF))
|
||||
if (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res->Cost -= MONEY(6, 00);
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped.
|
||||
uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT)
|
||||
? CREATE_CROSSING_MODE_NONE
|
||||
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
||||
// Do not attempt to build a crossing with a queue or a sloped path.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
uint8_t crossingMode = isQueue || (_slope != TILE_ELEMENT_SLOPE_FLAT) ? CREATE_CROSSING_MODE_NONE
|
||||
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(),
|
||||
crossingMode);
|
||||
@@ -222,8 +226,14 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(Game
|
||||
{
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath)
|
||||
{
|
||||
// Set the path type but make sure it's not a queue as that will not show up
|
||||
entranceElement->SetLegacyPathEntryIndex(_type & 0x7F);
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
entranceElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
entranceElement->SetSurfaceEntryIndex(_type);
|
||||
}
|
||||
map_invalidate_tile_full(_loc);
|
||||
}
|
||||
}
|
||||
@@ -233,10 +243,18 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(Game
|
||||
Guard::Assert(pathElement != nullptr);
|
||||
|
||||
pathElement->SetClearanceZ(zHigh);
|
||||
pathElement->SetLegacyPathEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE);
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
pathElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathElement->SetSurfaceEntryIndex(_type);
|
||||
pathElement->SetRailingsEntryIndex(_railingsType);
|
||||
}
|
||||
pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK);
|
||||
pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED);
|
||||
pathElement->SetIsQueue(_type & FOOTPATH_ELEMENT_INSERT_QUEUE);
|
||||
pathElement->SetIsQueue(isQueue);
|
||||
pathElement->SetAddition(0);
|
||||
pathElement->SetRideIndex(RIDE_ID_NULL);
|
||||
pathElement->SetAdditionStatus(255);
|
||||
@@ -254,3 +272,27 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(Game
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FootpathPlaceFromTrackAction::IsSameAsEntranceElement(const EntranceElement& entranceElement) const
|
||||
{
|
||||
if (entranceElement.HasLegacyPathEntry())
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return entranceElement.GetLegacyPathEntryIndex() == _type;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return entranceElement.GetSurfaceEntryIndex() == _type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,15 @@ private:
|
||||
CoordsXYZ _loc;
|
||||
uint8_t _slope{};
|
||||
ObjectEntryIndex _type{};
|
||||
ObjectEntryIndex _railingsType{};
|
||||
uint8_t _edges{};
|
||||
PathConstructFlags _constructFlags{};
|
||||
|
||||
public:
|
||||
FootpathPlaceFromTrackAction() = default;
|
||||
FootpathPlaceFromTrackAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, uint8_t edges);
|
||||
FootpathPlaceFromTrackAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, uint8_t edges,
|
||||
PathConstructFlags constructFlags = 0);
|
||||
|
||||
uint16_t GetActionFlags() const override;
|
||||
|
||||
@@ -32,4 +36,5 @@ public:
|
||||
private:
|
||||
GameActions::Result::Ptr ElementInsertQuery(GameActions::Result::Ptr res) const;
|
||||
GameActions::Result::Ptr ElementInsertExecute(GameActions::Result::Ptr res) const;
|
||||
bool IsSameAsEntranceElement(const EntranceElement& entranceElement) const;
|
||||
};
|
||||
|
||||
@@ -146,7 +146,14 @@ GameActions::Result::Ptr PlaceParkEntranceAction::Execute() const
|
||||
entranceElement->SetDirection(_loc.direction);
|
||||
entranceElement->SetSequenceIndex(index);
|
||||
entranceElement->SetEntranceType(ENTRANCE_TYPE_PARK_ENTRANCE);
|
||||
entranceElement->SetLegacyPathEntryIndex(_pathType);
|
||||
if (gFootpathSelection.LegacyPath == OBJECT_ENTRY_INDEX_NULL)
|
||||
{
|
||||
entranceElement->SetSurfaceEntryIndex(gFootpathSelection.NormalSurface);
|
||||
}
|
||||
else
|
||||
{
|
||||
entranceElement->SetLegacyPathEntryIndex(gFootpathSelection.LegacyPath);
|
||||
}
|
||||
|
||||
if (!entranceElement->IsGhost())
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@ void FootpathRailingsObject::Load()
|
||||
_descriptor.Flags = Flags;
|
||||
_descriptor.ScrollingMode = ScrollingMode;
|
||||
_descriptor.SupportType = SupportType;
|
||||
_descriptor.SupportColour = Colour;
|
||||
_descriptor.RailingsImage = RailingsImageId;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <thread>
|
||||
|
||||
struct TileElement;
|
||||
enum class RailingEntrySupportType : uint8_t;
|
||||
enum class ViewportInteractionItem : uint8_t;
|
||||
|
||||
struct attached_paint_struct
|
||||
@@ -251,6 +252,18 @@ struct paint_session : public PaintSessionCore
|
||||
}
|
||||
};
|
||||
|
||||
struct FootpathPaintInfo
|
||||
{
|
||||
uint32_t SurfaceImageId{};
|
||||
uint32_t BridgeImageId{};
|
||||
uint32_t RailingsImageId{};
|
||||
uint32_t SurfaceFlags{};
|
||||
uint32_t RailingFlags{};
|
||||
uint8_t ScrollingMode{};
|
||||
RailingEntrySupportType SupportType{};
|
||||
colour_t SupportColour = 255;
|
||||
};
|
||||
|
||||
struct RecordedPaintSession
|
||||
{
|
||||
PaintSessionCore Session;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Supports.h"
|
||||
|
||||
#include "../interface/Viewport.h"
|
||||
#include "../object/FootpathRailingsObject.h"
|
||||
#include "../sprites.h"
|
||||
#include "../world/Surface.h"
|
||||
#include "Paint.h"
|
||||
@@ -1168,7 +1169,7 @@ bool metal_b_supports_paint_setup(
|
||||
*/
|
||||
bool path_a_supports_paint_setup(
|
||||
paint_session* session, int32_t supportType, int32_t special, int32_t height, uint32_t imageColourFlags,
|
||||
const PathRailingsDescriptor* railingsDescriptor, bool* underground)
|
||||
const FootpathPaintInfo& pathPaintInfo, bool* underground)
|
||||
{
|
||||
if (underground != nullptr)
|
||||
{
|
||||
@@ -1202,7 +1203,7 @@ bool path_a_supports_paint_setup(
|
||||
{
|
||||
// save dx2
|
||||
PaintAddImageAsParent(
|
||||
session, (railingsDescriptor->BridgeImage + 48) | imageColourFlags, { 0, 0, baseHeight - 2 }, { 32, 32, 0 });
|
||||
session, (pathPaintInfo.BridgeImageId + 48) | imageColourFlags, { 0, 0, baseHeight - 2 }, { 32, 32, 0 });
|
||||
hasSupports = true;
|
||||
}
|
||||
else if (session->Support.slope & 0x10)
|
||||
@@ -1216,7 +1217,7 @@ bool path_a_supports_paint_setup(
|
||||
}
|
||||
|
||||
uint32_t imageId = (supportType * 24) + word_97B3C4[session->Support.slope & TILE_ELEMENT_SURFACE_SLOPE_MASK]
|
||||
+ railingsDescriptor->BridgeImage;
|
||||
+ pathPaintInfo.BridgeImageId;
|
||||
|
||||
PaintAddImageAsParent(
|
||||
session, imageId | imageColourFlags, { 0, 0, baseHeight }, { 32, 32, 11 }, { 0, 0, baseHeight + 2 });
|
||||
@@ -1239,7 +1240,7 @@ bool path_a_supports_paint_setup(
|
||||
}
|
||||
|
||||
uint32_t ebx = (supportType * 24) + word_97B3C4[session->Support.slope & TILE_ELEMENT_SURFACE_SLOPE_MASK]
|
||||
+ railingsDescriptor->BridgeImage;
|
||||
+ pathPaintInfo.BridgeImageId;
|
||||
|
||||
PaintAddImageAsParent(session, ebx | imageColourFlags, { 0, 0, baseHeight }, { 32, 32, 11 }, { 0, 0, baseHeight + 2 });
|
||||
|
||||
@@ -1251,7 +1252,7 @@ bool path_a_supports_paint_setup(
|
||||
{
|
||||
if (baseHeight & 0x10 || heightSteps == 1 || baseHeight + 16 == session->WaterHeight)
|
||||
{
|
||||
uint32_t imageId = (supportType * 24) + railingsDescriptor->BridgeImage + 23;
|
||||
uint32_t imageId = (supportType * 24) + pathPaintInfo.BridgeImageId + 23;
|
||||
|
||||
PaintAddImageAsParent(
|
||||
session, imageId | imageColourFlags, { 0, 0, baseHeight }, { 32, 32, ((heightSteps == 1) ? 7 : 12) });
|
||||
@@ -1261,7 +1262,7 @@ bool path_a_supports_paint_setup(
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t imageId = (supportType * 24) + railingsDescriptor->BridgeImage + 22;
|
||||
uint32_t imageId = (supportType * 24) + pathPaintInfo.BridgeImageId + 22;
|
||||
|
||||
PaintAddImageAsParent(
|
||||
session, imageId | imageColourFlags, { 0, 0, baseHeight }, { 32, 32, ((heightSteps == 2) ? 23 : 28) });
|
||||
@@ -1275,7 +1276,7 @@ bool path_a_supports_paint_setup(
|
||||
{
|
||||
uint16_t specialIndex = (special - 1) & 0xFFFF;
|
||||
|
||||
uint32_t imageId = railingsDescriptor->BridgeImage + 55 + specialIndex;
|
||||
uint32_t imageId = pathPaintInfo.BridgeImageId + 55 + specialIndex;
|
||||
|
||||
const unk_supports_desc& supportsDesc = byte_98D8D4[specialIndex];
|
||||
const unk_supports_desc_bound_box& boundBox = supportsDesc.bounding_box;
|
||||
@@ -1320,7 +1321,7 @@ bool path_a_supports_paint_setup(
|
||||
*/
|
||||
bool path_b_supports_paint_setup(
|
||||
paint_session* session, int32_t segment, int32_t special, int32_t height, uint32_t imageColourFlags,
|
||||
const PathRailingsDescriptor* railingsDescriptor)
|
||||
const FootpathPaintInfo& pathPaintInfo)
|
||||
{
|
||||
support_height* supportSegments = session->SupportSegments;
|
||||
|
||||
@@ -1342,7 +1343,7 @@ bool path_b_supports_paint_setup(
|
||||
uint16_t baseHeight;
|
||||
|
||||
if ((supportSegments[segment].slope & 0x20) || (height - supportSegments[segment].height < 6)
|
||||
|| !(railingsDescriptor->Flags & RAILING_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE))
|
||||
|| !(pathPaintInfo.RailingFlags & RAILING_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE))
|
||||
{
|
||||
baseHeight = supportSegments[segment].height;
|
||||
}
|
||||
@@ -1352,7 +1353,7 @@ bool path_b_supports_paint_setup(
|
||||
baseHeight = supportSegments[segment].height;
|
||||
|
||||
PaintAddImageAsParent(
|
||||
session, (railingsDescriptor->BridgeImage + 37 + imageOffset) | imageColourFlags,
|
||||
session, (pathPaintInfo.BridgeImageId + 37 + imageOffset) | imageColourFlags,
|
||||
{ SupportBoundBoxes[segment].x, SupportBoundBoxes[segment].y, baseHeight }, { 0, 0, 5 });
|
||||
baseHeight += 6;
|
||||
}
|
||||
@@ -1371,7 +1372,7 @@ bool path_b_supports_paint_setup(
|
||||
if (heightDiff > 0)
|
||||
{
|
||||
PaintAddImageAsParent(
|
||||
session, (railingsDescriptor->BridgeImage + 20 + (heightDiff - 1)) | imageColourFlags,
|
||||
session, (pathPaintInfo.BridgeImageId + 20 + (heightDiff - 1)) | imageColourFlags,
|
||||
{ SupportBoundBoxes[segment], baseHeight }, { 0, 0, heightDiff - 1 });
|
||||
}
|
||||
|
||||
@@ -1404,7 +1405,7 @@ bool path_b_supports_paint_setup(
|
||||
}
|
||||
|
||||
PaintAddImageAsParent(
|
||||
session, (railingsDescriptor->BridgeImage + 20 + (z - 1)) | imageColourFlags,
|
||||
session, (pathPaintInfo.BridgeImageId + 20 + (z - 1)) | imageColourFlags,
|
||||
{ SupportBoundBoxes[segment], baseHeight }, { 0, 0, (z - 1) });
|
||||
|
||||
baseHeight += z;
|
||||
@@ -1415,7 +1416,7 @@ bool path_b_supports_paint_setup(
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t imageId = railingsDescriptor->BridgeImage + 20 + (z - 1);
|
||||
uint32_t imageId = pathPaintInfo.BridgeImageId + 20 + (z - 1);
|
||||
if (z == 16)
|
||||
{
|
||||
imageId += 1;
|
||||
@@ -1449,7 +1450,7 @@ bool path_b_supports_paint_setup(
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t imageId = railingsDescriptor->BridgeImage + 20 + (z - 1);
|
||||
uint32_t imageId = pathPaintInfo.BridgeImageId + 20 + (z - 1);
|
||||
PaintAddImageAsParent(
|
||||
session, imageId | imageColourFlags, { SupportBoundBoxes[segment], baseHeight }, { 0, 0, 0 },
|
||||
{ SupportBoundBoxes[segment], baseHeight });
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "../common.h"
|
||||
#include "../world/Footpath.h"
|
||||
|
||||
struct FootpathPaintInfo;
|
||||
|
||||
constexpr const uint8_t NumVanillaWoodenSupportTypes = 49;
|
||||
|
||||
bool wooden_a_supports_paint_setup(
|
||||
@@ -24,10 +26,10 @@ bool metal_b_supports_paint_setup(
|
||||
paint_session* session, uint8_t supportType, uint8_t segment, int32_t special, int32_t height, uint32_t imageColourFlags);
|
||||
bool path_a_supports_paint_setup(
|
||||
paint_session* session, int32_t supportType, int32_t special, int32_t height, uint32_t imageColourFlags,
|
||||
const PathRailingsDescriptor* railingsDescriptor, bool* underground);
|
||||
const FootpathPaintInfo& pathPaintInfo, bool* underground);
|
||||
bool path_b_supports_paint_setup(
|
||||
paint_session* session, int32_t supportType, int32_t special, int32_t height, uint32_t imageColourFlags,
|
||||
const PathRailingsDescriptor* railingsDescriptor);
|
||||
const FootpathPaintInfo& pathPaintInfo);
|
||||
|
||||
// There are 13 types of metal supports. A graphic showing all of them is available here:
|
||||
// https://cloud.githubusercontent.com/assets/737603/19420485/7eaba28e-93ec-11e6-83cb-03190accc094.png
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "../../drawing/LightFX.h"
|
||||
#include "../../interface/Viewport.h"
|
||||
#include "../../localisation/Localisation.h"
|
||||
#include "../../object/FootpathObject.h"
|
||||
#include "../../object/FootpathSurfaceObject.h"
|
||||
#include "../../object/StationObject.h"
|
||||
#include "../../ride/RideData.h"
|
||||
#include "../../ride/TrackDesign.h"
|
||||
@@ -260,6 +262,7 @@ static void park_entrance_paint(paint_session* session, uint8_t direction, int32
|
||||
switch (part_index)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (surfaceDescriptor != nullptr)
|
||||
{
|
||||
image_id = (surfaceDescriptor->Image + 5 * (1 + (direction & 1))) | ghost_id;
|
||||
@@ -317,6 +320,7 @@ static void park_entrance_paint(paint_session* session, uint8_t direction, int32
|
||||
PaintAddImageAsChild(session, stsetup, 0, 0, 0x1C, 0x1C, 0x2F, text_height, 2, 2, text_height);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
case 2:
|
||||
entrance = static_cast<rct_entrance_type*>(object_entry_get_chunk(ObjectType::ParkEntrance, 0));
|
||||
|
||||
@@ -7,13 +7,18 @@
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "../../Context.h"
|
||||
#include "../../Game.h"
|
||||
#include "../../config/Config.h"
|
||||
#include "../../core/Numerics.hpp"
|
||||
#include "../../drawing/LightFX.h"
|
||||
#include "../../interface/Viewport.h"
|
||||
#include "../../localisation/Localisation.h"
|
||||
#include "../../object/FootpathObject.h"
|
||||
#include "../../object/FootpathRailingsObject.h"
|
||||
#include "../../object/FootpathSurfaceObject.h"
|
||||
#include "../../object/ObjectList.h"
|
||||
#include "../../object/ObjectManager.h"
|
||||
#include "../../peep/Peep.h"
|
||||
#include "../../peep/Staff.h"
|
||||
#include "../../ride/Track.h"
|
||||
@@ -87,11 +92,11 @@ static constexpr const uint8_t byte_98D8A4[] = {
|
||||
// clang-format on
|
||||
|
||||
void path_paint_box_support(
|
||||
paint_session* session, const PathElement& pathElement, int32_t height, const PathSurfaceDescriptor* footpathEntry,
|
||||
const PathRailingsDescriptor* railingEntry, bool hasSupports, uint32_t imageFlags, uint32_t sceneryImageFlags);
|
||||
paint_session* session, const PathElement& pathElement, int32_t height, const FootpathPaintInfo& pathPaintInfo,
|
||||
bool hasSupports, uint32_t imageFlags, uint32_t sceneryImageFlags);
|
||||
void path_paint_pole_support(
|
||||
paint_session* session, const PathElement& pathElement, int16_t height, const PathSurfaceDescriptor* surfaceDescriptor,
|
||||
const PathRailingsDescriptor* railingsDescriptor, bool hasSupports, uint32_t imageFlags, uint32_t sceneryImageFlags);
|
||||
paint_session* session, const PathElement& pathElement, int16_t height, const FootpathPaintInfo& pathPaintInfo,
|
||||
bool hasSupports, uint32_t imageFlags, uint32_t sceneryImageFlags);
|
||||
|
||||
/* rct2: 0x006A5AE5 */
|
||||
static void path_bit_lights_paint(
|
||||
@@ -327,9 +332,9 @@ static void path_bit_jumping_fountains_paint(
|
||||
*/
|
||||
static void sub_6A4101(
|
||||
paint_session* session, const PathElement& pathElement, uint16_t height, uint32_t connectedEdges, bool hasSupports,
|
||||
const PathRailingsDescriptor* railingsDescriptor, uint32_t imageFlags)
|
||||
const FootpathPaintInfo& pathPaintInfo, uint32_t imageFlags)
|
||||
{
|
||||
uint32_t base_image_id = railingsDescriptor->RailingsImage | imageFlags;
|
||||
uint32_t base_image_id = pathPaintInfo.RailingsImageId | imageFlags;
|
||||
|
||||
if (pathElement.IsQueue())
|
||||
{
|
||||
@@ -448,7 +453,7 @@ static void sub_6A4101(
|
||||
auto ride = get_ride(pathElement.GetRideIndex());
|
||||
if (direction < 2 && ride != nullptr && imageFlags == 0)
|
||||
{
|
||||
uint16_t scrollingMode = railingsDescriptor->ScrollingMode;
|
||||
uint16_t scrollingMode = pathPaintInfo.ScrollingMode;
|
||||
scrollingMode += direction;
|
||||
|
||||
auto ft = Formatter();
|
||||
@@ -496,7 +501,8 @@ static void sub_6A4101(
|
||||
drawnCorners = (connectedEdges & FOOTPATH_PROPERTIES_EDGES_CORNERS_MASK) >> 4;
|
||||
}
|
||||
|
||||
if (pathElement.IsSloped())
|
||||
auto slopeRailingsSupported = !(pathPaintInfo.SurfaceFlags & FOOTPATH_ENTRY_FLAG_NO_SLOPE_RAILINGS);
|
||||
if ((hasSupports || slopeRailingsSupported) && pathElement.IsSloped())
|
||||
{
|
||||
switch ((pathElement.GetSlopeDirection() + session->CurrentRotation) & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK)
|
||||
{
|
||||
@@ -670,7 +676,7 @@ static void sub_6A4101(
|
||||
*/
|
||||
static void sub_6A3F61(
|
||||
paint_session* session, const PathElement& pathElement, uint16_t connectedEdges, uint16_t height,
|
||||
const PathRailingsDescriptor* railingsDescriptor, uint32_t imageFlags, uint32_t sceneryImageFlags, bool hasSupports)
|
||||
const FootpathPaintInfo& pathPaintInfo, uint32_t imageFlags, uint32_t sceneryImageFlags, bool hasSupports)
|
||||
{
|
||||
// eax --
|
||||
// ebx --
|
||||
@@ -750,7 +756,7 @@ static void sub_6A3F61(
|
||||
// Redundant zoom-level check removed
|
||||
|
||||
if (paintScenery)
|
||||
sub_6A4101(session, pathElement, height, connectedEdges, hasSupports, railingsDescriptor, imageFlags);
|
||||
sub_6A4101(session, pathElement, height, connectedEdges, hasSupports, pathPaintInfo, imageFlags);
|
||||
}
|
||||
|
||||
// This is about tunnel drawing
|
||||
@@ -800,6 +806,31 @@ static void sub_6A3F61(
|
||||
}
|
||||
}
|
||||
|
||||
static FootpathPaintInfo GetFootpathPaintInfo(const PathElement& pathEl)
|
||||
{
|
||||
FootpathPaintInfo pathPaintInfo;
|
||||
|
||||
const auto* surfaceDescriptor = pathEl.GetSurfaceDescriptor();
|
||||
if (surfaceDescriptor != nullptr)
|
||||
{
|
||||
pathPaintInfo.SurfaceImageId = surfaceDescriptor->Image;
|
||||
pathPaintInfo.SurfaceFlags = surfaceDescriptor->Flags;
|
||||
}
|
||||
|
||||
const auto* railingsDescriptor = pathEl.GetRailingsDescriptor();
|
||||
if (railingsDescriptor != nullptr)
|
||||
{
|
||||
pathPaintInfo.BridgeImageId = railingsDescriptor->BridgeImage;
|
||||
pathPaintInfo.RailingsImageId = railingsDescriptor->RailingsImage;
|
||||
pathPaintInfo.RailingFlags = railingsDescriptor->Flags;
|
||||
pathPaintInfo.ScrollingMode = railingsDescriptor->ScrollingMode;
|
||||
pathPaintInfo.SupportType = railingsDescriptor->SupportType;
|
||||
pathPaintInfo.SupportColour = railingsDescriptor->SupportColour;
|
||||
}
|
||||
|
||||
return pathPaintInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* rct2: 0x0006A3590
|
||||
*/
|
||||
@@ -870,7 +901,11 @@ void PaintPath(paint_session* session, uint16_t height, const PathElement& tileE
|
||||
}
|
||||
else if (surface->GetBaseZ() != height)
|
||||
{
|
||||
hasSupports = true;
|
||||
const auto* surfaceEntry = tileElement.GetSurfaceEntry();
|
||||
const bool showUndergroundRailings = surfaceEntry == nullptr
|
||||
|| !(surfaceEntry->Flags & FOOTPATH_ENTRY_FLAG_NO_SLOPE_RAILINGS);
|
||||
if (surface->GetBaseZ() < height || showUndergroundRailings)
|
||||
hasSupports = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -944,23 +979,14 @@ void PaintPath(paint_session* session, uint16_t height, const PathElement& tileE
|
||||
PaintAddImageAsParent(session, imageId, { 16, 16, heightMarkerBaseZ }, { 1, 1, 0 });
|
||||
}
|
||||
|
||||
const PathSurfaceDescriptor* surfaceDescriptor = tileElement.GetSurfaceDescriptor();
|
||||
const PathRailingsDescriptor* railingsDescriptor = tileElement.GetRailingsDescriptor();
|
||||
|
||||
if (surfaceDescriptor != nullptr && railingsDescriptor != nullptr)
|
||||
auto pathPaintInfo = GetFootpathPaintInfo(tileElement);
|
||||
if (pathPaintInfo.SupportType == RailingEntrySupportType::Pole)
|
||||
{
|
||||
if (railingsDescriptor->SupportType == RailingEntrySupportType::Pole)
|
||||
{
|
||||
path_paint_pole_support(
|
||||
session, tileElement, height, surfaceDescriptor, railingsDescriptor, hasSupports, imageFlags,
|
||||
sceneryImageFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
path_paint_box_support(
|
||||
session, tileElement, height, surfaceDescriptor, railingsDescriptor, hasSupports, imageFlags,
|
||||
sceneryImageFlags);
|
||||
}
|
||||
path_paint_pole_support(session, tileElement, height, pathPaintInfo, hasSupports, imageFlags, sceneryImageFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
path_paint_box_support(session, tileElement, height, pathPaintInfo, hasSupports, imageFlags, sceneryImageFlags);
|
||||
}
|
||||
|
||||
#ifdef __ENABLE_LIGHTFX__
|
||||
@@ -996,8 +1022,8 @@ void PaintPath(paint_session* session, uint16_t height, const PathElement& tileE
|
||||
}
|
||||
|
||||
void path_paint_box_support(
|
||||
paint_session* session, const PathElement& pathElement, int32_t height, const PathSurfaceDescriptor* footpathEntry,
|
||||
const PathRailingsDescriptor* railingEntry, bool hasSupports, uint32_t imageFlags, uint32_t sceneryImageFlags)
|
||||
paint_session* session, const PathElement& pathElement, int32_t height, const FootpathPaintInfo& pathPaintInfo,
|
||||
bool hasSupports, uint32_t imageFlags, uint32_t sceneryImageFlags)
|
||||
{
|
||||
// Rol edges around rotation
|
||||
uint8_t edges = ((pathElement.GetEdges() << session->CurrentRotation) & 0xF)
|
||||
@@ -1011,19 +1037,17 @@ void path_paint_box_support(
|
||||
|
||||
uint16_t edi = edges | (corners << 4);
|
||||
|
||||
uint32_t imageId;
|
||||
uint32_t imageId = pathPaintInfo.SurfaceImageId;
|
||||
if (pathElement.IsSloped())
|
||||
{
|
||||
imageId = ((pathElement.GetSlopeDirection() + session->CurrentRotation) & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK)
|
||||
imageId += ((pathElement.GetSlopeDirection() + session->CurrentRotation) & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK)
|
||||
+ 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
imageId = byte_98D6E0[edi];
|
||||
imageId += byte_98D6E0[edi];
|
||||
}
|
||||
|
||||
imageId += footpathEntry->Image;
|
||||
|
||||
if (!session->DidPassSurface)
|
||||
{
|
||||
boundBoxOffset.x = 3;
|
||||
@@ -1057,18 +1081,17 @@ void path_paint_box_support(
|
||||
if (pathElement.IsSloped())
|
||||
{
|
||||
image_id = ((pathElement.GetSlopeDirection() + session->CurrentRotation) & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK)
|
||||
+ railingEntry->BridgeImage + 51;
|
||||
+ pathPaintInfo.BridgeImageId + 51;
|
||||
}
|
||||
else
|
||||
{
|
||||
image_id = byte_98D8A4[edges] + railingEntry->BridgeImage + 49;
|
||||
image_id = byte_98D8A4[edges] + pathPaintInfo.BridgeImageId + 49;
|
||||
}
|
||||
|
||||
PaintAddImageAsParent(
|
||||
session, image_id | imageFlags, { 0, 0, height }, { boundBoxSize, 0 },
|
||||
{ boundBoxOffset, height + boundingBoxZOffset });
|
||||
|
||||
// TODO: Revert this when path import works correctly.
|
||||
if (!pathElement.IsQueue() && !pathElement.ShouldDrawPathOverSupports())
|
||||
{
|
||||
// don't draw
|
||||
@@ -1081,7 +1104,7 @@ void path_paint_box_support(
|
||||
}
|
||||
}
|
||||
|
||||
sub_6A3F61(session, pathElement, edi, height, railingEntry, imageFlags, sceneryImageFlags, hasSupports);
|
||||
sub_6A3F61(session, pathElement, edi, height, pathPaintInfo, imageFlags, sceneryImageFlags, hasSupports);
|
||||
|
||||
uint16_t ax = 0;
|
||||
if (pathElement.IsSloped())
|
||||
@@ -1089,14 +1112,8 @@ void path_paint_box_support(
|
||||
ax = ((pathElement.GetSlopeDirection() + session->CurrentRotation) & 0x3) + 1;
|
||||
}
|
||||
|
||||
if (byte_98D8A4[edges] == 0)
|
||||
{
|
||||
path_a_supports_paint_setup(session, 0, ax, height, imageFlags, railingEntry, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
path_a_supports_paint_setup(session, 1, ax, height, imageFlags, railingEntry, nullptr);
|
||||
}
|
||||
auto supportType = byte_98D8A4[edges] == 0 ? 0 : 1;
|
||||
path_a_supports_paint_setup(session, supportType, ax, height, imageFlags, pathPaintInfo, nullptr);
|
||||
|
||||
height += 32;
|
||||
if (pathElement.IsSloped())
|
||||
@@ -1142,8 +1159,8 @@ void path_paint_box_support(
|
||||
}
|
||||
|
||||
void path_paint_pole_support(
|
||||
paint_session* session, const PathElement& pathElement, int16_t height, const PathSurfaceDescriptor* surfaceDescriptor,
|
||||
const PathRailingsDescriptor* railingsDescriptor, bool hasSupports, uint32_t imageFlags, uint32_t sceneryImageFlags)
|
||||
paint_session* session, const PathElement& pathElement, int16_t height, const FootpathPaintInfo& pathPaintInfo,
|
||||
bool hasSupports, uint32_t imageFlags, uint32_t sceneryImageFlags)
|
||||
{
|
||||
// Rol edges around rotation
|
||||
uint8_t edges = ((pathElement.GetEdges() << session->CurrentRotation) & 0xF)
|
||||
@@ -1158,18 +1175,16 @@ void path_paint_pole_support(
|
||||
|
||||
uint16_t edi = edges | (corners << 4);
|
||||
|
||||
uint32_t imageId;
|
||||
uint32_t imageId = pathPaintInfo.SurfaceImageId;
|
||||
if (pathElement.IsSloped())
|
||||
{
|
||||
imageId = ((pathElement.GetSlopeDirection() + session->CurrentRotation) & 3) + 16;
|
||||
imageId += ((pathElement.GetSlopeDirection() + session->CurrentRotation) & 3) + 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
imageId = byte_98D6E0[edi];
|
||||
imageId += byte_98D6E0[edi];
|
||||
}
|
||||
|
||||
imageId += surfaceDescriptor->Image;
|
||||
|
||||
// Below Surface
|
||||
if (!session->DidPassSurface)
|
||||
{
|
||||
@@ -1205,11 +1220,11 @@ void path_paint_pole_support(
|
||||
{
|
||||
bridgeImage = ((pathElement.GetSlopeDirection() + session->CurrentRotation)
|
||||
& FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK)
|
||||
+ railingsDescriptor->BridgeImage + 16;
|
||||
+ pathPaintInfo.BridgeImageId + 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
bridgeImage = edges + railingsDescriptor->BridgeImage;
|
||||
bridgeImage = edges + pathPaintInfo.BridgeImageId;
|
||||
bridgeImage |= imageFlags;
|
||||
}
|
||||
|
||||
@@ -1217,7 +1232,6 @@ void path_paint_pole_support(
|
||||
session, bridgeImage | imageFlags, { 0, 0, height }, { boundBoxSize, 0 },
|
||||
{ boundBoxOffset, height + boundingBoxZOffset });
|
||||
|
||||
// TODO: Revert this when path import works correctly.
|
||||
if (pathElement.IsQueue() || pathElement.ShouldDrawPathOverSupports())
|
||||
{
|
||||
PaintAddImageAsChild(
|
||||
@@ -1226,8 +1240,8 @@ void path_paint_pole_support(
|
||||
}
|
||||
}
|
||||
|
||||
sub_6A3F61(
|
||||
session, pathElement, edi, height, railingsDescriptor, imageFlags, sceneryImageFlags, hasSupports); // TODO: arguments
|
||||
sub_6A3F61(session, pathElement, edi, height, pathPaintInfo, imageFlags, sceneryImageFlags,
|
||||
hasSupports); // TODO: arguments
|
||||
|
||||
uint16_t ax = 0;
|
||||
if (pathElement.IsSloped())
|
||||
@@ -1246,7 +1260,10 @@ void path_paint_pole_support(
|
||||
{
|
||||
if (!(edges & (1 << i)))
|
||||
{
|
||||
path_b_supports_paint_setup(session, supports[i], ax, height, imageFlags, railingsDescriptor);
|
||||
const int32_t extraFlags = (pathPaintInfo.SupportColour != COLOUR_NULL && !pathElement.IsGhost())
|
||||
? SPRITE_ID_PALETTE_COLOUR_1(pathPaintInfo.SupportColour)
|
||||
: 0;
|
||||
path_b_supports_paint_setup(session, supports[i], ax, height, imageFlags | extraFlags, pathPaintInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1161,11 +1161,7 @@ static std::optional<money32> TrackDesignPlaceSceneryElement(
|
||||
z = (scenery.z * COORDS_Z_STEP + originZ) / COORDS_Z_STEP;
|
||||
if (mode == 0)
|
||||
{
|
||||
if (scenery.flags & (1 << 7))
|
||||
{
|
||||
// dh
|
||||
entry_index |= (1 << 7);
|
||||
}
|
||||
auto isQueue = scenery.IsQueue();
|
||||
|
||||
uint8_t bh = ((scenery.flags & 0xF) << rotation);
|
||||
flags = bh >> 4;
|
||||
@@ -1195,8 +1191,12 @@ static std::optional<money32> TrackDesignPlaceSceneryElement(
|
||||
}
|
||||
uint8_t slope = ((bh >> 5) & 0x3) | ((bh >> 2) & 0x4);
|
||||
uint8_t edges = bh & 0xF;
|
||||
PathConstructFlags constructFlags = PathConstructFlag::IsLegacyPathObject;
|
||||
if (isQueue)
|
||||
constructFlags |= PathConstructFlag::IsQueue;
|
||||
auto footpathPlaceAction = FootpathPlaceFromTrackAction(
|
||||
{ mapCoord.x, mapCoord.y, z * COORDS_Z_STEP }, slope, entry_index, edges);
|
||||
{ mapCoord.x, mapCoord.y, z * COORDS_Z_STEP }, slope, entry_index, OBJECT_ENTRY_INDEX_NULL, edges,
|
||||
constructFlags);
|
||||
footpathPlaceAction.SetFlags(flags);
|
||||
auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&footpathPlaceAction)
|
||||
: GameActions::QueryNested(&footpathPlaceAction);
|
||||
|
||||
@@ -39,6 +39,11 @@ struct TrackDesignSceneryElement
|
||||
uint8_t flags; // 0x13 direction quadrant tertiary colour
|
||||
uint8_t primary_colour; // 0x14
|
||||
uint8_t secondary_colour; // 0x15
|
||||
|
||||
bool IsQueue() const
|
||||
{
|
||||
return (flags & (1 << 7)) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
using namespace OpenRCT2::TrackMetaData;
|
||||
void footpath_update_queue_entrance_banner(const CoordsXY& footpathPos, TileElement* tileElement);
|
||||
|
||||
FootpathSelection gFootpathSelection;
|
||||
ProvisionalFootpath gProvisionalFootpath;
|
||||
uint16_t gFootpathSelectedId;
|
||||
CoordsXYZ gFootpathConstructFromPosition;
|
||||
@@ -139,21 +140,25 @@ money32 footpath_remove(const CoordsXYZ& footpathLoc, int32_t flags)
|
||||
*
|
||||
* rct2: 0x006A76FF
|
||||
*/
|
||||
money32 footpath_provisional_set(int32_t type, const CoordsXYZ& footpathLoc, int32_t slope)
|
||||
money32 footpath_provisional_set(
|
||||
ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope,
|
||||
PathConstructFlags constructFlags)
|
||||
{
|
||||
money32 cost;
|
||||
|
||||
footpath_provisional_remove();
|
||||
|
||||
auto footpathPlaceAction = FootpathPlaceAction(footpathLoc, slope, type);
|
||||
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 : MONEY32_UNDEFINED;
|
||||
if (res->Error == GameActions::Status::Ok)
|
||||
{
|
||||
gProvisionalFootpath.Type = type;
|
||||
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)
|
||||
@@ -1653,13 +1658,13 @@ ObjectEntryIndex PathElement::GetLegacyPathEntryIndex() const
|
||||
}
|
||||
|
||||
const FootpathObject* PathElement::GetLegacyPathEntry() const
|
||||
{
|
||||
{
|
||||
return GetLegacyFootpathEntry(GetLegacyPathEntryIndex());
|
||||
}
|
||||
}
|
||||
|
||||
void PathElement::SetLegacyPathEntryIndex(ObjectEntryIndex newIndex)
|
||||
{
|
||||
SurfaceIndex = newIndex & ~FOOTPATH_ELEMENT_INSERT_QUEUE;
|
||||
SurfaceIndex = newIndex;
|
||||
RailingsIndex = OBJECT_ENTRY_INDEX_NULL;
|
||||
Flags2 |= FOOTPATH_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY;
|
||||
}
|
||||
@@ -1761,6 +1766,7 @@ void PathElement::SetQueueBannerDirection(uint8_t direction)
|
||||
|
||||
bool PathElement::ShouldDrawPathOverSupports() const
|
||||
{
|
||||
// TODO: make this an actual decision of the tile element.
|
||||
return (GetRailingsDescriptor()->Flags & RAILING_ENTRY_FLAG_DRAW_PATH_OVER_SUPPORTS);
|
||||
}
|
||||
|
||||
@@ -2331,6 +2337,26 @@ const FootpathObject* GetLegacyFootpathEntry(ObjectEntryIndex entryIndex)
|
||||
return footpathObject;
|
||||
}
|
||||
|
||||
const FootpathSurfaceObject* GetPathSurfaceEntry(ObjectEntryIndex entryIndex)
|
||||
{
|
||||
auto& objMgr = OpenRCT2::GetContext()->GetObjectManager();
|
||||
auto obj = objMgr.GetLoadedObject(ObjectType::FootpathSurface, entryIndex);
|
||||
if (obj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return static_cast<FootpathSurfaceObject*>(obj);
|
||||
}
|
||||
|
||||
const FootpathRailingsObject* GetPathRailingsEntry(ObjectEntryIndex entryIndex)
|
||||
{
|
||||
auto& objMgr = OpenRCT2::GetContext()->GetObjectManager();
|
||||
auto obj = objMgr.GetLoadedObject(ObjectType::FootpathRailings, entryIndex);
|
||||
if (obj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return static_cast<FootpathRailingsObject*>(obj);
|
||||
}
|
||||
|
||||
ride_id_t PathElement::GetRideIndex() const
|
||||
{
|
||||
return rideIndex;
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#include "../interface/Viewport.h"
|
||||
#include "../object/Object.h"
|
||||
|
||||
class FootpathObject;
|
||||
class FootpathSurfaceObject;
|
||||
class FootpathRailingsObject;
|
||||
|
||||
enum
|
||||
{
|
||||
PROVISIONAL_PATH_FLAG_SHOW_ARROW = (1 << 0),
|
||||
@@ -25,8 +29,6 @@ constexpr auto FootpathMinHeight = 2 * COORDS_Z_STEP;
|
||||
constexpr auto PATH_HEIGHT_STEP = 2 * COORDS_Z_STEP;
|
||||
constexpr auto PATH_CLEARANCE = 4 * COORDS_Z_STEP;
|
||||
|
||||
#define FOOTPATH_ELEMENT_INSERT_QUEUE 0x80
|
||||
|
||||
class FootpathObject;
|
||||
|
||||
enum class RailingEntrySupportType : uint8_t
|
||||
@@ -99,16 +101,41 @@ struct PathRailingsDescriptor
|
||||
uint32_t BridgeImage;
|
||||
uint32_t RailingsImage;
|
||||
RailingEntrySupportType SupportType;
|
||||
colour_t SupportColour;
|
||||
uint8_t Flags;
|
||||
uint8_t ScrollingMode;
|
||||
};
|
||||
|
||||
using PathConstructFlags = uint8_t;
|
||||
namespace PathConstructFlag
|
||||
{
|
||||
constexpr PathConstructFlags IsQueue = 1 << 0;
|
||||
constexpr PathConstructFlags IsLegacyPathObject = 1 << 1;
|
||||
} // namespace PathConstructFlag
|
||||
|
||||
struct FootpathSelection
|
||||
{
|
||||
ObjectEntryIndex LegacyPath = OBJECT_ENTRY_INDEX_NULL;
|
||||
ObjectEntryIndex NormalSurface = OBJECT_ENTRY_INDEX_NULL;
|
||||
ObjectEntryIndex QueueSurface = OBJECT_ENTRY_INDEX_NULL;
|
||||
ObjectEntryIndex Railings = OBJECT_ENTRY_INDEX_NULL;
|
||||
bool IsQueueSelected{};
|
||||
|
||||
ObjectEntryIndex GetSelectedSurface() const
|
||||
{
|
||||
return IsQueueSelected ? QueueSurface : NormalSurface;
|
||||
}
|
||||
};
|
||||
|
||||
struct ProvisionalFootpath
|
||||
{
|
||||
ObjectEntryIndex Type;
|
||||
CoordsXYZ Position;
|
||||
uint8_t Slope;
|
||||
uint8_t Flags;
|
||||
ObjectEntryIndex SurfaceIndex;
|
||||
ObjectEntryIndex RailingsIndex;
|
||||
PathConstructFlags ConstructFlags;
|
||||
};
|
||||
|
||||
// Masks for values stored in TileElement.type
|
||||
@@ -192,6 +219,7 @@ enum
|
||||
FOOTPATH_CONNECTED_MAP_EDGE_IGNORE_NO_ENTRY = (1 << 7)
|
||||
};
|
||||
|
||||
extern FootpathSelection gFootpathSelection;
|
||||
extern ProvisionalFootpath gProvisionalFootpath;
|
||||
extern uint16_t gFootpathSelectedId;
|
||||
extern CoordsXYZ gFootpathConstructFromPosition;
|
||||
@@ -206,7 +234,9 @@ extern const CoordsXY BenchUseOffsets[NumOrthogonalDirections * 2];
|
||||
TileElement* map_get_footpath_element(const CoordsXYZ& coords);
|
||||
void footpath_interrupt_peeps(const CoordsXYZ& footpathPos);
|
||||
money32 footpath_remove(const CoordsXYZ& footpathLoc, int32_t flags);
|
||||
money32 footpath_provisional_set(int32_t type, const CoordsXYZ& footpathLoc, int32_t slope);
|
||||
money32 footpath_provisional_set(
|
||||
ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope,
|
||||
PathConstructFlags constructFlags);
|
||||
void footpath_provisional_remove();
|
||||
void footpath_provisional_update();
|
||||
CoordsXY footpath_get_coordinates_from_pos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement);
|
||||
@@ -224,6 +254,8 @@ int32_t footpath_is_connected_to_map_edge(const CoordsXYZ& footpathPos, int32_t
|
||||
void footpath_remove_edges_at(const CoordsXY& footpathPos, TileElement* tileElement);
|
||||
|
||||
const FootpathObject* GetLegacyFootpathEntry(ObjectEntryIndex entryIndex);
|
||||
const FootpathSurfaceObject* GetPathSurfaceEntry(ObjectEntryIndex entryIndex);
|
||||
const FootpathRailingsObject* GetPathRailingsEntry(ObjectEntryIndex entryIndex);
|
||||
|
||||
void footpath_queue_chain_reset();
|
||||
void footpath_queue_chain_push(ride_id_t rideIndex);
|
||||
|
||||
@@ -1574,7 +1574,9 @@ void map_restore_provisional_elements()
|
||||
if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1)
|
||||
{
|
||||
gProvisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_1;
|
||||
footpath_provisional_set(gProvisionalFootpath.Type, gProvisionalFootpath.Position, gProvisionalFootpath.Slope);
|
||||
footpath_provisional_set(
|
||||
gProvisionalFootpath.SurfaceIndex, gProvisionalFootpath.RailingsIndex, gProvisionalFootpath.Position,
|
||||
gProvisionalFootpath.Slope, gProvisionalFootpath.ConstructFlags);
|
||||
}
|
||||
if (window_find_by_class(WC_RIDE_CONSTRUCTION) != nullptr)
|
||||
{
|
||||
|
||||
@@ -293,6 +293,9 @@ public:
|
||||
const PathSurfaceDescriptor* GetSurfaceDescriptor() const;
|
||||
const PathRailingsDescriptor* GetRailingsDescriptor() const;
|
||||
|
||||
bool ShouldDrawPathOverSupports() const;
|
||||
void SetShouldDrawPathOverSupports(bool on);
|
||||
|
||||
uint8_t GetQueueBannerDirection() const;
|
||||
void SetQueueBannerDirection(uint8_t direction);
|
||||
|
||||
@@ -341,9 +344,6 @@ public:
|
||||
uint8_t GetAdditionStatus() const;
|
||||
void SetAdditionStatus(uint8_t newStatus);
|
||||
|
||||
bool ShouldDrawPathOverSupports() const;
|
||||
void SetShouldDrawPathOverSupports(bool on);
|
||||
|
||||
bool IsLevelCrossing(const CoordsXY& coords) const;
|
||||
};
|
||||
assert_struct_size(PathElement, 16);
|
||||
|
||||
Reference in New Issue
Block a user