diff --git a/CMakeLists.txt b/CMakeLists.txt
index 10c5a523ea..f5a817fa73 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -50,9 +50,9 @@ set(OBJECTS_VERSION "1.2.1")
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip")
set(OBJECTS_SHA1 "540e004abc683b3fe22211f5234e3d78ab023c5f")
-set(REPLAYS_VERSION "0.0.52")
+set(REPLAYS_VERSION "0.0.53")
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip")
-set(REPLAYS_SHA1 "3A1A6B5B25ACA3B8AADC618A9D2BE44F8A23A7BB")
+set(REPLAYS_SHA1 "8DDA5F2CC0B101D477396A3B016FF5F3EDFD074F")
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
option(WITH_TESTS "Build tests")
diff --git a/openrct2.proj b/openrct2.proj
index 2dad3d4aec..aa87bd36bd 100644
--- a/openrct2.proj
+++ b/openrct2.proj
@@ -48,8 +48,8 @@
304d13a126c15bf2c86ff13b81a2f2cc1856ac8d
https://github.com/OpenRCT2/objects/releases/download/v1.2.1/objects.zip
540e004abc683b3fe22211f5234e3d78ab023c5f
- https://github.com/OpenRCT2/replays/releases/download/v0.0.52/replays.zip
- 3A1A6B5B25ACA3B8AADC618A9D2BE44F8A23A7BB
+ https://github.com/OpenRCT2/replays/releases/download/v0.0.53/replays.zip
+ 8DDA5F2CC0B101D477396A3B016FF5F3EDFD074F
diff --git a/src/openrct2-ui/interface/Window.cpp b/src/openrct2-ui/interface/Window.cpp
index 14aee560f7..7ffc99deb4 100644
--- a/src/openrct2-ui/interface/Window.cpp
+++ b/src/openrct2-ui/interface/Window.cpp
@@ -274,7 +274,7 @@ rct_window* WindowCreate(
w->min_height = height;
w->max_height = height;
- w->focus2 = std::nullopt;
+ w->focus = std::nullopt;
w->page = 0;
w->var_48C = 0;
w->var_492 = 0;
diff --git a/src/openrct2-ui/scripting/CustomWindow.cpp b/src/openrct2-ui/scripting/CustomWindow.cpp
index 4e01689373..874427ef14 100644
--- a/src/openrct2-ui/scripting/CustomWindow.cpp
+++ b/src/openrct2-ui/scripting/CustomWindow.cpp
@@ -786,8 +786,7 @@ namespace OpenRCT2::Ui::Windows
auto wheight = viewportWidget->height() - 1;
if (viewport == nullptr)
{
- const auto focus = Focus2(CoordsXYZ(0, 0, 0));
- viewport_create(this, { left, top }, wwidth, wheight, focus);
+ viewport_create(this, { left, top }, wwidth, wheight, Focus(CoordsXYZ(0, 0, 0)));
flags |= WF_NO_SCROLLING;
Invalidate();
}
diff --git a/src/openrct2-ui/windows/Banner.cpp b/src/openrct2-ui/windows/Banner.cpp
index 3959bc29de..79310f0f81 100644
--- a/src/openrct2-ui/windows/Banner.cpp
+++ b/src/openrct2-ui/windows/Banner.cpp
@@ -79,10 +79,9 @@ private:
void CreateViewport()
{
rct_widget* viewportWidget = &window_banner_widgets[WIDX_VIEWPORT];
- const auto focus = Focus2(_bannerViewPos);
viewport_create(
this, windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 },
- (viewportWidget->width()) - 1, (viewportWidget->height()) - 1, focus);
+ (viewportWidget->width()) - 1, (viewportWidget->height()) - 1, Focus(_bannerViewPos));
if (viewport != nullptr)
viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
@@ -97,7 +96,7 @@ private:
return nullptr;
}
- TileElement* tileElement = map_get_first_element_at(banner->position.ToCoordsXY().ToTileCentre());
+ TileElement* tileElement = map_get_first_element_at(banner->position);
if (tileElement == nullptr)
{
return nullptr;
diff --git a/src/openrct2-ui/windows/EditorMain.cpp b/src/openrct2-ui/windows/EditorMain.cpp
index 121b8e4ac3..d0186f17db 100644
--- a/src/openrct2-ui/windows/EditorMain.cpp
+++ b/src/openrct2-ui/windows/EditorMain.cpp
@@ -40,8 +40,7 @@ rct_window* window_editor_main_open()
&window_editor_main_events, WC_MAIN_WINDOW, WF_STICK_TO_BACK);
window->widgets = window_editor_main_widgets;
- const auto focus = Focus2(CoordsXYZ(0x0FFF, 0x0FFF, 0));
- viewport_create(window, window->windowPos, window->width, window->height, focus);
+ viewport_create(window, window->windowPos, window->width, window->height, Focus(CoordsXYZ(0x0FFF, 0x0FFF, 0)));
window->viewport->flags |= 0x0400;
gCurrentRotation = 0;
diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp
index c7446b80c5..c7063690af 100644
--- a/src/openrct2-ui/windows/Guest.cpp
+++ b/src/openrct2-ui/windows/Guest.cpp
@@ -732,7 +732,7 @@ void window_guest_viewport_init(rct_window* w)
uint16_t origViewportFlags{};
if (w->viewport != nullptr)
{
- if (w->focus2.has_value())
+ if (w->focus.has_value())
return;
origViewportFlags = w->viewport->flags;
@@ -750,7 +750,7 @@ void window_guest_viewport_init(rct_window* w)
int32_t width = view_widget->width() - 1;
int32_t height = view_widget->height() - 1;
- viewport_create(w, screenPos, width, height, w->focus2.value());
+ viewport_create(w, screenPos, width, height, w->focus.value());
if (w->viewport != nullptr && reCreateViewport)
{
w->viewport->flags = origViewportFlags;
diff --git a/src/openrct2-ui/windows/Main.cpp b/src/openrct2-ui/windows/Main.cpp
index 347f2cc49f..ed7bab0503 100644
--- a/src/openrct2-ui/windows/Main.cpp
+++ b/src/openrct2-ui/windows/Main.cpp
@@ -41,8 +41,7 @@ rct_window* window_main_open()
WF_STICK_TO_BACK);
window->widgets = window_main_widgets;
- const auto focus = Focus2(CoordsXYZ(0x0FFF, 0x0FFF, 0));
- viewport_create(window, window->windowPos, window->width, window->height, focus);
+ viewport_create(window, window->windowPos, window->width, window->height, Focus(CoordsXYZ(0x0FFF, 0x0FFF, 0)));
window->viewport->flags |= VIEWPORT_FLAG_SOUND_ON;
gCurrentRotation = 0;
gShowGridLinesRefCount = 0;
diff --git a/src/openrct2-ui/windows/Park.cpp b/src/openrct2-ui/windows/Park.cpp
index 6b477ad3b4..9f3bf92f0d 100644
--- a/src/openrct2-ui/windows/Park.cpp
+++ b/src/openrct2-ui/windows/Park.cpp
@@ -740,11 +740,11 @@ static void window_park_init_viewport(rct_window* w)
if (w->page != WINDOW_PARK_PAGE_ENTRANCE)
return;
- std::optional focus = std::nullopt;
+ std::optional focus = std::nullopt;
if (!gParkEntrances.empty())
{
const auto& entrance = gParkEntrances[0];
- focus = Focus2(CoordsXYZ{ entrance.x + 16, entrance.y + 16, entrance.z + 32 });
+ focus = Focus(CoordsXYZ{ entrance.x + 16, entrance.y + 16, entrance.z + 32 });
}
if (w->viewport == nullptr)
@@ -760,7 +760,7 @@ static void window_park_init_viewport(rct_window* w)
// Call invalidate event
window_event_invalidate_call(w);
- w->focus2 = focus;
+ w->focus = focus;
if (focus.has_value())
{
diff --git a/src/openrct2-ui/windows/Player.cpp b/src/openrct2-ui/windows/Player.cpp
index fab5a3df40..9a6c6352de 100644
--- a/src/openrct2-ui/windows/Player.cpp
+++ b/src/openrct2-ui/windows/Player.cpp
@@ -547,7 +547,7 @@ static void window_player_set_page(rct_window* w, int32_t page)
{
if (w->viewport == nullptr)
{
- const auto focus = Focus2(TileCoordsXYZ(128, 128, 0).ToCoordsXYZ());
+ const auto focus = Focus(TileCoordsXYZ(128, 128, 0).ToCoordsXYZ());
viewport_create(w, w->windowPos, w->width, w->height, focus);
w->flags |= WF_NO_SCROLLING;
window_event_invalidate_call(w);
diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp
index ec0286cbb8..1f2d68054b 100644
--- a/src/openrct2-ui/windows/Ride.cpp
+++ b/src/openrct2-ui/windows/Ride.cpp
@@ -1589,7 +1589,7 @@ static void window_ride_init_viewport(rct_window* w)
int32_t viewSelectionIndex = w->ride.view - 1;
- std::optional focus;
+ std::optional focus;
if (viewSelectionIndex >= 0 && viewSelectionIndex < ride->num_vehicles && ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)
{
@@ -1609,7 +1609,7 @@ static void window_ride_init_viewport(rct_window* w)
}
if (vehId != SPRITE_INDEX_NULL)
{
- focus = Focus2(vehId);
+ focus = Focus(vehId);
}
}
else if (viewSelectionIndex >= ride->num_vehicles && viewSelectionIndex < (ride->num_vehicles + ride->num_stations))
@@ -1618,7 +1618,7 @@ static void window_ride_init_viewport(rct_window* w)
if (stationIndex)
{
const auto location = ride->stations[*stationIndex].GetStart();
- focus = Focus2(location);
+ focus = Focus(location);
}
}
else
@@ -1630,14 +1630,14 @@ static void window_ride_init_viewport(rct_window* w)
if (w->number < ride_overall_views.size())
{
const auto& view = ride_overall_views[w->number];
- focus = Focus2(view.loc, view.zoom);
+ focus = Focus(view.loc, view.zoom);
}
}
uint16_t viewport_flags = 0;
if (w->viewport != nullptr)
{
- if (focus == w->focus2)
+ if (focus == w->focus)
{
return;
}
@@ -1651,7 +1651,7 @@ static void window_ride_init_viewport(rct_window* w)
window_event_invalidate_call(w);
- w->focus2 = focus;
+ w->focus = focus;
// rct2: 0x006aec9c only used here so brought it into the function
if (!w->viewport && !ride->overall_view.IsNull())
@@ -1662,7 +1662,7 @@ static void window_ride_init_viewport(rct_window* w)
int32_t width = view_widget->width() - 1;
int32_t height = view_widget->height() - 1;
- viewport_create(w, screenPos, width, height, w->focus2.value());
+ viewport_create(w, screenPos, width, height, w->focus.value());
w->flags |= WF_NO_SCROLLING;
w->Invalidate();
@@ -1796,6 +1796,8 @@ static void window_ride_main_resize(rct_window* w)
w->flags |= WF_RESIZABLE;
window_set_resize(w, 316, minHeight, 500, 450);
+ // Unlike with other windows, the focus needs to be recentred so it’s best to just reset it.
+ w->focus = std::nullopt;
window_ride_init_viewport(w);
}
diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp
index 6d252746dc..8a34c04e84 100644
--- a/src/openrct2-ui/windows/RideConstruction.cpp
+++ b/src/openrct2-ui/windows/RideConstruction.cpp
@@ -2424,11 +2424,11 @@ static void sub_6CBCE2(
auto southTileCoords = centreTileCoords + TileDirectionDelta[TILE_ELEMENT_DIRECTION_SOUTH];
// Replace map elements with temporary ones containing track
- _backupTileElementArrays[0] = map_get_first_element_at(centreTileCoords.ToCoordsXY());
- _backupTileElementArrays[1] = map_get_first_element_at(eastTileCoords.ToCoordsXY());
- _backupTileElementArrays[2] = map_get_first_element_at(westTileCoords.ToCoordsXY());
- _backupTileElementArrays[3] = map_get_first_element_at(northTileCoords.ToCoordsXY());
- _backupTileElementArrays[4] = map_get_first_element_at(southTileCoords.ToCoordsXY());
+ _backupTileElementArrays[0] = map_get_first_element_at(centreTileCoords);
+ _backupTileElementArrays[1] = map_get_first_element_at(eastTileCoords);
+ _backupTileElementArrays[2] = map_get_first_element_at(westTileCoords);
+ _backupTileElementArrays[3] = map_get_first_element_at(northTileCoords);
+ _backupTileElementArrays[4] = map_get_first_element_at(southTileCoords);
map_set_tile_element(centreTileCoords, &_tempTrackTileElement);
map_set_tile_element(eastTileCoords, &_tempSideTrackTileElement);
map_set_tile_element(westTileCoords, &_tempSideTrackTileElement);
diff --git a/src/openrct2-ui/windows/Sign.cpp b/src/openrct2-ui/windows/Sign.cpp
index bddfd0dd20..b111f95c9b 100644
--- a/src/openrct2-ui/windows/Sign.cpp
+++ b/src/openrct2-ui/windows/Sign.cpp
@@ -127,10 +127,9 @@ public:
// Create viewport
rct_widget& viewportWidget = window_sign_widgets[WIDX_VIEWPORT];
- const auto focus = Focus2(CoordsXYZ{ signViewPosition, viewZ });
viewport_create(
this, windowPos + ScreenCoordsXY{ viewportWidget.left + 1, viewportWidget.top + 1 }, viewportWidget.width() - 1,
- viewportWidget.height() - 1, focus);
+ viewportWidget.height() - 1, Focus(CoordsXYZ{ signViewPosition, viewZ }));
viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
Invalidate();
@@ -300,10 +299,9 @@ public:
// Create viewport
rct_widget* viewportWidget = &window_sign_widgets[WIDX_VIEWPORT];
- const auto focus = Focus2(CoordsXYZ{ signViewPos });
viewport_create(
this, windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 }, viewportWidget->width() - 1,
- viewportWidget->height() - 1, focus);
+ viewportWidget->height() - 1, Focus(CoordsXYZ{ signViewPos }));
if (viewport != nullptr)
viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
Invalidate();
diff --git a/src/openrct2-ui/windows/Staff.cpp b/src/openrct2-ui/windows/Staff.cpp
index 6156c1cd5e..89da4d7b59 100644
--- a/src/openrct2-ui/windows/Staff.cpp
+++ b/src/openrct2-ui/windows/Staff.cpp
@@ -1339,7 +1339,7 @@ void window_staff_viewport_init(rct_window* w)
if (w->page != WINDOW_STAFF_OVERVIEW)
return;
- std::optional focus;
+ std::optional focus;
const auto peep = GetStaff(w);
if (peep == nullptr)
@@ -1349,14 +1349,14 @@ void window_staff_viewport_init(rct_window* w)
if (peep->State != PeepState::Picked)
{
- focus = Focus2(peep->sprite_index);
+ focus = Focus(peep->sprite_index);
}
uint16_t viewport_flags;
if (w->viewport)
{
- if (focus == w->focus2)
+ if (focus == w->focus)
return;
viewport_flags = w->viewport->flags;
@@ -1371,7 +1371,7 @@ void window_staff_viewport_init(rct_window* w)
window_event_invalidate_call(w);
- w->focus2 = focus;
+ w->focus = focus;
if (peep->State != PeepState::Picked)
{
diff --git a/src/openrct2-ui/windows/TitleCommandEditor.cpp b/src/openrct2-ui/windows/TitleCommandEditor.cpp
index 4b15b97904..b02e3fc1a3 100644
--- a/src/openrct2-ui/windows/TitleCommandEditor.cpp
+++ b/src/openrct2-ui/windows/TitleCommandEditor.cpp
@@ -227,7 +227,7 @@ void window_title_command_editor_open(TitleSequence* sequence, int32_t index, bo
WindowInitScrollWidgets(window);
rct_widget* const viewportWidget = &window_title_command_editor_widgets[WIDX_VIEWPORT];
- const auto focus = Focus2(CoordsXYZ{ 0, 0, 0 });
+ const auto focus = Focus(CoordsXYZ{ 0, 0, 0 });
viewport_create(
window, window->windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 },
viewportWidget->width() - 1, viewportWidget->height() - 1, focus);
diff --git a/src/openrct2-ui/windows/Viewport.cpp b/src/openrct2-ui/windows/Viewport.cpp
index abcd712170..66ee0f3a33 100644
--- a/src/openrct2-ui/windows/Viewport.cpp
+++ b/src/openrct2-ui/windows/Viewport.cpp
@@ -76,8 +76,7 @@ public:
enabled_widgets = (1ULL << WIDX_CLOSE) | (1ULL << WIDX_ZOOM_IN) | (1ULL << WIDX_ZOOM_OUT) | (1ULL << WIDX_LOCATE);
// Create viewport
- const auto focus = Focus2(TileCoordsXYZ(128, 128, 0).ToCoordsXYZ());
- viewport_create(this, windowPos, width, height, focus);
+ viewport_create(this, windowPos, width, height, Focus(TileCoordsXYZ(128, 128, 0).ToCoordsXYZ()));
if (viewport == nullptr)
{
Close();
diff --git a/src/openrct2/GameState.cpp b/src/openrct2/GameState.cpp
index 463405558a..53b1e9b7c5 100644
--- a/src/openrct2/GameState.cpp
+++ b/src/openrct2/GameState.cpp
@@ -56,6 +56,7 @@ GameState::GameState()
void GameState::InitAll(int32_t mapSize)
{
gInMapInitCode = true;
+ gCurrentTicks = 0;
gCurrentTicks = 0;
map_init(mapSize);
diff --git a/src/openrct2/actions/ClearAction.cpp b/src/openrct2/actions/ClearAction.cpp
index cfeea2f993..bccba7e5a7 100644
--- a/src/openrct2/actions/ClearAction.cpp
+++ b/src/openrct2/actions/ClearAction.cpp
@@ -214,7 +214,7 @@ void ClearAction::ResetClearLargeSceneryFlag()
{
for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++)
{
- auto tileElement = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY());
+ auto tileElement = map_get_first_element_at(TileCoordsXY{ x, y });
do
{
if (tileElement == nullptr)
diff --git a/src/openrct2/interface/Viewport.cpp b/src/openrct2/interface/Viewport.cpp
index 65e093703f..28cab048bd 100644
--- a/src/openrct2/interface/Viewport.cpp
+++ b/src/openrct2/interface/Viewport.cpp
@@ -117,14 +117,14 @@ std::optional centre_2d_coordinates(const CoordsXYZ& loc, rct_vi
return { screenCoord };
}
-CoordsXYZ Focus2::GetPos() const
+CoordsXYZ Focus::GetPos() const
{
return std::visit(
[](auto&& arg) {
using T = std::decay_t;
- if constexpr (std::is_same_v)
+ if constexpr (std::is_same_v)
return arg;
- else if constexpr (std::is_same_v)
+ else if constexpr (std::is_same_v)
{
auto* centreEntity = GetEntity(arg);
if (centreEntity != nullptr)
@@ -158,7 +158,7 @@ CoordsXYZ Focus2::GetPos() const
* flags: edx top most 2 bits 0b_X1 for zoom clear see below for 2nd bit.
* w: esi
*/
-void viewport_create(rct_window* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus2& focus)
+void viewport_create(rct_window* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus& focus)
{
rct_viewport* viewport = nullptr;
if (_viewports.size() >= MAX_VIEWPORT_COUNT)
@@ -188,9 +188,9 @@ void viewport_create(rct_window* w, const ScreenCoordsXY& screenCoords, int32_t
w->viewport_target_sprite = std::visit(
[](auto&& arg) {
using T = std::decay_t;
- if constexpr (std::is_same_v)
+ if constexpr (std::is_same_v)
return SPRITE_INDEX_NULL;
- else if constexpr (std::is_same_v)
+ else if constexpr (std::is_same_v)
return arg;
},
focus.data);
@@ -702,7 +702,7 @@ void viewport_update_smart_sprite_follow(rct_window* window)
break;
default: // All other types don't need any "smart" following; steam particle, duck, money effect, etc.
- window->focus2 = Focus2(window->viewport_smart_follow_sprite);
+ window->focus = Focus(window->viewport_smart_follow_sprite);
window->viewport_target_sprite = window->viewport_smart_follow_sprite;
break;
}
@@ -710,14 +710,14 @@ void viewport_update_smart_sprite_follow(rct_window* window)
void viewport_update_smart_guest_follow(rct_window* window, const Guest* peep)
{
- Focus2 focus = Focus2(peep->sprite_index);
+ Focus focus = Focus(peep->sprite_index);
window->viewport_target_sprite = peep->sprite_index;
if (peep->State == PeepState::Picked)
{
window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL;
window->viewport_target_sprite = SPRITE_INDEX_NULL;
- window->focus2 = std::nullopt; // No focus
+ window->focus = std::nullopt; // No focus
return;
}
@@ -734,7 +734,7 @@ void viewport_update_smart_guest_follow(rct_window* window, const Guest* peep)
const auto car = train->GetCar(peep->CurrentCar);
if (car != nullptr)
{
- focus = Focus2(car->sprite_index);
+ focus = Focus(car->sprite_index);
overallFocus = false;
window->viewport_target_sprite = car->sprite_index;
}
@@ -752,12 +752,12 @@ void viewport_update_smart_guest_follow(rct_window* window, const Guest* peep)
coordFocus.x = xy.x;
coordFocus.y = xy.y;
coordFocus.z = tile_element_height(xy) + (4 * COORDS_Z_STEP);
- focus = Focus2(coordFocus);
+ focus = Focus(coordFocus);
window->viewport_target_sprite = SPRITE_INDEX_NULL;
}
}
- window->focus2 = focus;
+ window->focus = focus;
}
void viewport_update_smart_staff_follow(rct_window* window, const Staff* peep)
@@ -766,17 +766,17 @@ void viewport_update_smart_staff_follow(rct_window* window, const Staff* peep)
{
window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL;
window->viewport_target_sprite = SPRITE_INDEX_NULL;
- window->focus2 = std::nullopt;
+ window->focus = std::nullopt;
return;
}
- window->focus2 = Focus2(window->viewport_smart_follow_sprite);
+ window->focus = Focus(window->viewport_smart_follow_sprite);
window->viewport_target_sprite = window->viewport_smart_follow_sprite;
}
void viewport_update_smart_vehicle_follow(rct_window* window)
{
- window->focus2 = Focus2(window->viewport_smart_follow_sprite);
+ window->focus = Focus(window->viewport_smart_follow_sprite);
window->viewport_target_sprite = window->viewport_smart_follow_sprite;
}
diff --git a/src/openrct2/interface/Viewport.h b/src/openrct2/interface/Viewport.h
index d9b22283ac..697eb65510 100644
--- a/src/openrct2/interface/Viewport.h
+++ b/src/openrct2/interface/Viewport.h
@@ -104,7 +104,7 @@ extern uint8_t gCurrentRotation;
void viewport_init_all();
std::optional centre_2d_coordinates(const CoordsXYZ& loc, rct_viewport* viewport);
-void viewport_create(rct_window* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus2& focus);
+void viewport_create(rct_window* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus& focus);
void viewport_remove(rct_viewport* viewport);
void viewports_invalidate(int32_t left, int32_t top, int32_t right, int32_t bottom, int32_t maxZoom = -1);
void viewport_update_position(rct_window* window);
diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h
index b78a0b1d48..e498a21691 100644
--- a/src/openrct2/interface/Window.h
+++ b/src/openrct2/interface/Window.h
@@ -195,7 +195,7 @@ struct rct_scroll
constexpr auto WINDOW_SCROLL_UNDEFINED = std::numeric_limits::max();
-struct Focus2
+struct Focus
{
using CoordinateFocus = CoordsXYZ;
using EntityFocus = uint16_t;
@@ -203,7 +203,7 @@ struct Focus2
uint8_t zoom = 0;
std::variant data;
- template constexpr explicit Focus2(T newValue, uint8_t newZoom = 0)
+ template constexpr explicit Focus(T newValue, uint8_t newZoom = 0)
{
data = newValue;
zoom = newZoom;
@@ -211,7 +211,7 @@ struct Focus2
CoordsXYZ GetPos() const;
- constexpr bool operator==(const Focus2& other) const
+ constexpr bool operator==(const Focus& other) const
{
if (zoom != other.zoom)
{
@@ -219,7 +219,7 @@ struct Focus2
}
return data == other.data;
}
- constexpr bool operator!=(const Focus2& other) const
+ constexpr bool operator!=(const Focus& other) const
{
return !(*this == other);
}
diff --git a/src/openrct2/interface/Window_internal.cpp b/src/openrct2/interface/Window_internal.cpp
index 576212edc7..35aaa071db 100644
--- a/src/openrct2/interface/Window_internal.cpp
+++ b/src/openrct2/interface/Window_internal.cpp
@@ -12,10 +12,10 @@ void rct_window::SetLocation(const CoordsXYZ& coords)
void rct_window::ScrollToViewport()
{
- if (viewport == nullptr || !focus2.has_value())
+ if (viewport == nullptr || !focus.has_value())
return;
- CoordsXYZ newCoords = focus2.value().GetPos();
+ CoordsXYZ newCoords = focus.value().GetPos();
auto mainWindow = window_get_main();
if (mainWindow != nullptr)
diff --git a/src/openrct2/interface/Window_internal.h b/src/openrct2/interface/Window_internal.h
index 444bde6e44..24b2796636 100644
--- a/src/openrct2/interface/Window_internal.h
+++ b/src/openrct2/interface/Window_internal.h
@@ -55,7 +55,7 @@ struct rct_window
uint32_t list_item_positions[1024]{};
uint16_t no_list_items{}; // 0 for no items
int16_t selected_list_item{}; // -1 for none selected
- std::optional focus2;
+ std::optional focus;
union
{
campaign_variables campaign;
diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj
index f88e448eb1..217ff1257f 100644
--- a/src/openrct2/libopenrct2.vcxproj
+++ b/src/openrct2/libopenrct2.vcxproj
@@ -310,12 +310,15 @@
+
+
+
@@ -332,6 +335,7 @@
+
@@ -356,6 +360,7 @@
+
@@ -396,7 +401,9 @@
+
+
diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp
index 3235d87a56..364bcbcff9 100644
--- a/src/openrct2/network/NetworkBase.cpp
+++ b/src/openrct2/network/NetworkBase.cpp
@@ -40,7 +40,7 @@
// This string specifies which version of network stream current build uses.
// It is used for making sure only compatible builds get connected, even within
// single OpenRCT2 version.
-#define NETWORK_STREAM_VERSION "9"
+#define NETWORK_STREAM_VERSION "10"
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
static Peep* _pickup_peep = nullptr;
diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp
index 68582bfa2b..2f27e93843 100644
--- a/src/openrct2/peep/GuestPathfinding.cpp
+++ b/src/openrct2/peep/GuestPathfinding.cpp
@@ -276,7 +276,7 @@ static uint8_t footpath_element_next_in_direction(TileCoordsXYZ loc, PathElement
}
loc += TileDirectionDelta[chosenDirection];
- nextTileElement = map_get_first_element_at(loc.ToCoordsXY());
+ nextTileElement = map_get_first_element_at(loc);
do
{
if (nextTileElement == nullptr)
@@ -327,7 +327,7 @@ static uint8_t footpath_element_dest_in_dir(
return PATH_SEARCH_LIMIT_REACHED;
loc += TileDirectionDelta[chosenDirection];
- tileElement = map_get_first_element_at(loc.ToCoordsXY());
+ tileElement = map_get_first_element_at(loc);
if (tileElement == nullptr)
{
return PATH_SEARCH_FAILED;
@@ -733,7 +733,7 @@ static void peep_pathfind_heuristic_search(
/* Get the next map element of interest in the direction of test_edge. */
bool found = false;
- TileElement* tileElement = map_get_first_element_at(loc.ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(loc);
if (tileElement == nullptr)
{
return;
@@ -1275,7 +1275,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep)
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
// Get the path element at this location
- TileElement* dest_tile_element = map_get_first_element_at(loc.ToCoordsXY());
+ TileElement* dest_tile_element = map_get_first_element_at(loc);
/* Where there are multiple matching map elements placed with zero
* clearance, save the first one for later use to determine the path
* slope - this maintains the original behaviour (which only processes
@@ -1797,7 +1797,7 @@ static int32_t guest_path_find_park_entrance(Peep* peep, uint8_t edges)
static void get_ride_queue_end(TileCoordsXYZ& loc)
{
TileCoordsXY queueEnd = { 0, 0 };
- TileElement* tileElement = map_get_first_element_at(loc.ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(loc);
if (tileElement == nullptr)
{
@@ -1845,7 +1845,7 @@ static void get_ride_queue_end(TileCoordsXYZ& loc)
}
nextTile += TileDirectionDelta[direction];
- tileElement = map_get_first_element_at(nextTile.ToCoordsXY());
+ tileElement = map_get_first_element_at(nextTile);
found = false;
if (tileElement == nullptr)
break;
diff --git a/src/openrct2/peep/Peep.cpp b/src/openrct2/peep/Peep.cpp
index caa3ef398e..71c27737e2 100644
--- a/src/openrct2/peep/Peep.cpp
+++ b/src/openrct2/peep/Peep.cpp
@@ -711,7 +711,7 @@ void Peep::UpdateFalling()
}
// If not drowning then falling. Note: peeps 'fall' after leaving a ride/enter the park.
- TileElement* tile_element = map_get_first_element_at({ x, y });
+ TileElement* tile_element = map_get_first_element_at(CoordsXY{ x, y });
TileElement* saved_map = nullptr;
int32_t saved_height = 0;
diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp
index 7c467b5b62..958f376cb8 100644
--- a/src/openrct2/rct1/S4Importer.cpp
+++ b/src/openrct2/rct1/S4Importer.cpp
@@ -2575,7 +2575,7 @@ namespace RCT1
{
for (int32_t y = 0; y < RCT1_MAX_MAP_SIZE; y++)
{
- TileElement* tileElement = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(TileCoordsXY{ x, y });
if (tileElement == nullptr)
continue;
do
diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp
index 5b5dab5620..9f224a8603 100644
--- a/src/openrct2/rct2/S6Importer.cpp
+++ b/src/openrct2/rct2/S6Importer.cpp
@@ -228,7 +228,7 @@ public:
gDateMonthsElapsed = static_cast(_s6.elapsed_months);
gDateMonthTicks = _s6.current_day;
- gCurrentTicks = _s6.scenario_ticks;
+ gCurrentTicks = _s6.game_ticks_1;
scenario_rand_seed(_s6.scenario_srand_0, _s6.scenario_srand_1);
@@ -478,6 +478,7 @@ public:
CheatsReset();
ClearRestrictedScenery();
}
+
void FixLandOwnership() const
{
if (String::Equals(_s6.scenario_filename, "Europe - European Cultural Festival.SC6"))
@@ -1761,6 +1762,15 @@ template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc
dst->IsCrashedVehicle = src->flags & RCT12_SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE;
}
+static uint32_t AdjustScenarioToCurrentTicks(const rct_s6_data& s6, uint32_t tick)
+{
+ // Previously gScenarioTicks was used as a time point, now it's gCurrentTicks.
+ // gCurrentTicks and gScenarioTicks are now exported as the same, older saves that have a different
+ // scenario tick must account for the difference between the two.
+ uint32_t ticksElapsed = s6.scenario_ticks - tick;
+ return s6.game_ticks_1 - ticksElapsed;
+}
+
template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt(baseSrc.sprite_index);
@@ -1793,7 +1803,7 @@ template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc)
dst->TimeInQueue = src->time_in_queue;
dst->CashInPocket = src->cash_in_pocket;
dst->CashSpent = src->cash_spent;
- dst->ParkEntryTime = src->park_entry_time;
+ dst->ParkEntryTime = AdjustScenarioToCurrentTicks(_s6, src->park_entry_time);
dst->RejoinQueueTimeout = src->rejoin_queue_timeout;
dst->PreviousRide = RCT12RideIdToOpenRCT2RideId(src->previous_ride);
dst->PreviousRideTimeOut = src->previous_ride_time_out;
@@ -1843,6 +1853,7 @@ template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc)
dst->AssignedStaffType = StaffType(src->staff_type);
dst->MechanicTimeSinceCall = src->mechanic_time_since_call;
+
dst->HireDate = src->park_entry_time;
dst->StaffOrders = src->staff_orders;
dst->StaffMowingTimeout = src->staff_mowing_timeout;
@@ -1967,7 +1978,7 @@ template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc)
auto src = static_cast(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->SubType = Litter::Type(src->type);
- dst->creationTick = src->creationTick;
+ dst->creationTick = AdjustScenarioToCurrentTicks(_s6, src->creationTick);
}
void S6Importer::ImportEntity(const RCT12SpriteBase& src)
diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp
index 412fb7af84..d2773269c0 100644
--- a/src/openrct2/ride/Ride.cpp
+++ b/src/openrct2/ride/Ride.cpp
@@ -2213,7 +2213,7 @@ static void ride_shop_connected(Ride* ride)
return;
TrackElement* trackElement = nullptr;
- TileElement* tileElement = map_get_first_element_at(shopLoc.ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(shopLoc);
do
{
if (tileElement == nullptr)
@@ -2569,7 +2569,7 @@ void Ride::ChainQueues() const
// This will fire for every entrance on this x, y and z, regardless whether that actually belongs to
// the ride or not.
- TileElement* tileElement = map_get_first_element_at(location.ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(location);
if (tileElement != nullptr)
{
do
@@ -2914,7 +2914,7 @@ static void ride_set_maze_entrance_exit_points(Ride* ride)
{
auto entranceExitMapPos = position->ToCoordsXYZ();
- TileElement* tileElement = map_get_first_element_at(position->ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(*position);
do
{
if (tileElement == nullptr)
@@ -5554,7 +5554,7 @@ void determine_ride_entrance_and_exit_locations()
{
for (int32_t y = 1; y < MAXIMUM_MAP_SIZE_TECHNICAL - 1; y++)
{
- TileElement* tileElement = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(TileCoordsXY{ x, y });
if (tileElement != nullptr)
{
diff --git a/src/openrct2/ride/RideConstruction.cpp b/src/openrct2/ride/RideConstruction.cpp
index b48053cc75..18fafd2572 100644
--- a/src/openrct2/ride/RideConstruction.cpp
+++ b/src/openrct2/ride/RideConstruction.cpp
@@ -347,7 +347,7 @@ void ride_clear_blocked_tiles(Ride* ride)
{
for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++)
{
- auto element = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY());
+ auto element = map_get_first_element_at(TileCoordsXY{ x, y });
if (element != nullptr)
{
do
diff --git a/src/openrct2/ride/RideRatings.cpp b/src/openrct2/ride/RideRatings.cpp
index 5517784300..f4805d10ad 100644
--- a/src/openrct2/ride/RideRatings.cpp
+++ b/src/openrct2/ride/RideRatings.cpp
@@ -1463,7 +1463,7 @@ static int32_t ride_ratings_get_scenery_score(Ride* ride)
xx++)
{
// Count scenery items on this tile
- TileElement* tileElement = map_get_first_element_at(TileCoordsXY{ xx, yy }.ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(TileCoordsXY{ xx, yy });
if (tileElement == nullptr)
continue;
do
diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp
index 377dbac717..5e1684d3b2 100644
--- a/src/openrct2/ride/TrackDesign.cpp
+++ b/src/openrct2/ride/TrackDesign.cpp
@@ -359,7 +359,7 @@ rct_string_id TrackDesign::CreateTrackDesignMaze(const Ride& ride)
{
for (; x < MAXIMUM_MAP_SIZE_BIG; x += COORDS_XY_STEP)
{
- auto tileElement = map_get_first_element_at({ x, y });
+ auto tileElement = map_get_first_element_at(CoordsXY{ x, y });
do
{
if (tileElement == nullptr)
@@ -465,7 +465,7 @@ CoordsXYE TrackDesign::MazeGetFirstElement(const Ride& ride)
{
for (tile.x = 0; tile.x < MAXIMUM_MAP_SIZE_BIG; tile.x += COORDS_XY_STEP)
{
- tile.element = map_get_first_element_at({ tile.x, tile.y });
+ tile.element = map_get_first_element_at(CoordsXY{ tile.x, tile.y });
do
{
if (tile.element == nullptr)
diff --git a/src/openrct2/ride/TrackDesignSave.cpp b/src/openrct2/ride/TrackDesignSave.cpp
index c6252a7500..90d5cbfb3c 100644
--- a/src/openrct2/ride/TrackDesignSave.cpp
+++ b/src/openrct2/ride/TrackDesignSave.cpp
@@ -624,7 +624,7 @@ static void track_design_save_select_nearby_scenery_for_tile(ride_id_t rideIndex
{
for (int32_t x = cx - TRACK_NEARBY_SCENERY_DISTANCE; x <= cx + TRACK_NEARBY_SCENERY_DISTANCE; x++)
{
- tileElement = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY());
+ tileElement = map_get_first_element_at(TileCoordsXY{ x, y });
if (tileElement == nullptr)
continue;
do
diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp
index ce35781f99..44e8a8cfd7 100644
--- a/src/openrct2/ride/Vehicle.cpp
+++ b/src/openrct2/ride/Vehicle.cpp
@@ -1897,7 +1897,7 @@ void Vehicle::UpdateMeasurements()
{
// Set tile_element to first element. Since elements aren't always ordered by base height,
// we must start at the first element and iterate through each tile element.
- auto tileElement = map_get_first_element_at({ x, y });
+ auto tileElement = map_get_first_element_at(CoordsXY{ x, y });
if (tileElement == nullptr)
return;
diff --git a/src/openrct2/ride/transport/Chairlift.cpp b/src/openrct2/ride/transport/Chairlift.cpp
index db0b0a2950..101f424449 100644
--- a/src/openrct2/ride/transport/Chairlift.cpp
+++ b/src/openrct2/ride/transport/Chairlift.cpp
@@ -110,7 +110,7 @@ static void chairlift_paint_util_draw_supports(paint_session* session, int32_t s
static const TrackElement* chairlift_paint_util_map_get_track_element_at_from_ride_fuzzy(
int32_t x, int32_t y, int32_t z, const Ride* ride)
{
- const TileElement* tileElement = map_get_first_element_at({ x, y });
+ const TileElement* tileElement = map_get_first_element_at(CoordsXY{ x, y });
if (tileElement == nullptr)
{
return nullptr;
diff --git a/src/openrct2/world/Banner.cpp b/src/openrct2/world/Banner.cpp
index 10d704a732..fa590e5a72 100644
--- a/src/openrct2/world/Banner.cpp
+++ b/src/openrct2/world/Banner.cpp
@@ -145,7 +145,7 @@ TileElement* banner_get_tile_element(BannerIndex bannerIndex)
auto banner = GetBanner(bannerIndex);
if (banner != nullptr)
{
- auto tileElement = map_get_first_element_at(banner->position.ToCoordsXY());
+ auto tileElement = map_get_first_element_at(banner->position);
if (tileElement != nullptr)
{
do
@@ -166,7 +166,7 @@ WallElement* banner_get_scrolling_wall_tile_element(BannerIndex bannerIndex)
if (banner == nullptr)
return nullptr;
- auto tileElement = map_get_first_element_at(banner->position.ToCoordsXY());
+ auto tileElement = map_get_first_element_at(banner->position);
if (tileElement == nullptr)
return nullptr;
diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp
index 0b0fd586cb..7d5424ce8f 100644
--- a/src/openrct2/world/Footpath.cpp
+++ b/src/openrct2/world/Footpath.cpp
@@ -1226,7 +1226,7 @@ void footpath_update_queue_chains()
if (location.IsNull())
continue;
- TileElement* tileElement = map_get_first_element_at(location.ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(location);
if (tileElement != nullptr)
{
do
@@ -2143,7 +2143,7 @@ static void footpath_remove_edges_towards(const CoordsXYRangedZ& footPathPos, in
// entrances and exits, shops, paths).
bool tile_element_wants_path_connection_towards(const TileCoordsXYZD& coords, const TileElement* const elementToBeRemoved)
{
- TileElement* tileElement = map_get_first_element_at(coords.ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(coords);
if (tileElement == nullptr)
return false;
do
diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp
index 46c4938d28..6a88ce3922 100644
--- a/src/openrct2/world/Map.cpp
+++ b/src/openrct2/world/Map.cpp
@@ -214,7 +214,7 @@ static void ReorganiseTileElements(size_t capacity)
{
for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++)
{
- const auto* element = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY());
+ const auto* element = map_get_first_element_at(TileCoordsXY{ x, y });
if (element == nullptr)
{
newElements.push_back(GetDefaultSurfaceElement());
@@ -285,14 +285,14 @@ void tile_element_iterator_begin(tile_element_iterator* it)
{
it->x = 0;
it->y = 0;
- it->element = map_get_first_element_at({ 0, 0 });
+ it->element = map_get_first_element_at(TileCoordsXY{ 0, 0 });
}
int32_t tile_element_iterator_next(tile_element_iterator* it)
{
if (it->element == nullptr)
{
- it->element = map_get_first_element_at(TileCoordsXY{ it->x, it->y }.ToCoordsXY());
+ it->element = map_get_first_element_at(TileCoordsXY{ it->x, it->y });
return 1;
}
@@ -305,7 +305,7 @@ int32_t tile_element_iterator_next(tile_element_iterator* it)
if (it->x < (MAXIMUM_MAP_SIZE_TECHNICAL - 1))
{
it->x++;
- it->element = map_get_first_element_at(TileCoordsXY{ it->x, it->y }.ToCoordsXY());
+ it->element = map_get_first_element_at(TileCoordsXY{ it->x, it->y });
return 1;
}
@@ -313,7 +313,7 @@ int32_t tile_element_iterator_next(tile_element_iterator* it)
{
it->x = 0;
it->y++;
- it->element = map_get_first_element_at(TileCoordsXY{ it->x, it->y }.ToCoordsXY());
+ it->element = map_get_first_element_at(TileCoordsXY{ it->x, it->y });
return 1;
}
@@ -325,15 +325,26 @@ void tile_element_iterator_restart_for_tile(tile_element_iterator* it)
it->element = nullptr;
}
-TileElement* map_get_first_element_at(const CoordsXY& elementPos)
+static bool IsTileLocationValid(const TileCoordsXY& coords)
{
- if (!map_is_location_valid(elementPos))
+ const bool is_x_valid = coords.x < MAXIMUM_MAP_SIZE_TECHNICAL && coords.x >= 0;
+ const bool is_y_valid = coords.y < MAXIMUM_MAP_SIZE_TECHNICAL && coords.y >= 0;
+ return is_x_valid && is_y_valid;
+}
+
+TileElement* map_get_first_element_at(const TileCoordsXY& tilePos)
+{
+ if (!IsTileLocationValid(tilePos))
{
log_verbose("Trying to access element outside of range");
return nullptr;
}
- auto tileElementPos = TileCoordsXY{ elementPos };
- return _tileIndex.GetFirstElementAt(tileElementPos);
+ return _tileIndex.GetFirstElementAt(tilePos);
+}
+
+TileElement* map_get_first_element_at(const CoordsXY& elementPos)
+{
+ return map_get_first_element_at(TileCoordsXY{ elementPos });
}
TileElement* map_get_nth_element_at(const CoordsXY& coords, int32_t n)
@@ -680,7 +691,7 @@ int16_t tile_element_water_height(const CoordsXY& loc)
*/
bool map_coord_is_connected(const TileCoordsXYZ& loc, uint8_t faceDirection)
{
- TileElement* tileElement = map_get_first_element_at(loc.ToCoordsXY());
+ TileElement* tileElement = map_get_first_element_at(loc);
if (tileElement == nullptr)
return false;
diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h
index ab472b3567..ecc7679ade 100644
--- a/src/openrct2/world/Map.h
+++ b/src/openrct2/world/Map.h
@@ -192,7 +192,8 @@ void map_init(int32_t size);
void map_count_remaining_land_rights();
void map_strip_ghost_flag_from_elements();
-TileElement* map_get_first_element_at(const CoordsXY& elementPos);
+TileElement* map_get_first_element_at(const CoordsXY& tilePos);
+TileElement* map_get_first_element_at(const TileCoordsXY& tilePos);
TileElement* map_get_nth_element_at(const CoordsXY& coords, int32_t n);
void map_set_tile_element(const TileCoordsXY& tilePos, TileElement* elements);
int32_t map_height_from_slope(const CoordsXY& coords, int32_t slopeDirection, bool isSloped);