diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 352df35239..78c58ea18a 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -2258,7 +2258,7 @@ STR_3208 :Track Designs Manager STR_3209 :Back to Previous Step: STR_3210 :Forward to Next Step: STR_3211 :Map size: -STR_3212 :{POP16}{COMMA16} × {PUSH16}{COMMA16} +STR_3212 :{COMMA16} × {COMMA16} STR_3213 :Can’t decrease map size any further STR_3214 :Can’t increase map size any further STR_3215 :Too close to edge of map diff --git a/src/openrct2-ui/input/MouseInput.cpp b/src/openrct2-ui/input/MouseInput.cpp index f59d2b69d7..e71e1def99 100644 --- a/src/openrct2-ui/input/MouseInput.cpp +++ b/src/openrct2-ui/input/MouseInput.cpp @@ -1619,11 +1619,12 @@ void InputScrollViewport(const ScreenCoordsXY& scrollScreenCoords) } // Clamp to the map maximum value (scenario specific) - if (mapCoord.x > GetMapSizeMinus2() || mapCoord.y > GetMapSizeMinus2()) + auto mapSizeMinus2 = GetMapSizeMinus2(); + if (mapCoord.x > mapSizeMinus2.x || mapCoord.y > mapSizeMinus2.y) { at_map_edge = 1; } - if (mapCoord_dy.x > GetMapSizeMinus2() || mapCoord_dy.y > GetMapSizeMinus2()) + if (mapCoord_dy.x > mapSizeMinus2.x || mapCoord_dy.y > mapSizeMinus2.y) { at_map_edge_dy = 1; } diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp index afe22dd403..03f9ffd15e 100644 --- a/src/openrct2-ui/windows/Map.cpp +++ b/src/openrct2-ui/windows/Map.cpp @@ -653,7 +653,7 @@ static void WindowMapTextinput(rct_window* w, rct_widgetindex widgetIndex, char* size += 2; size = std::clamp(size, MINIMUM_MAP_SIZE_TECHNICAL, MAXIMUM_MAP_SIZE_TECHNICAL); - auto changeMapSizeAction = ChangeMapSizeAction(size); + auto changeMapSizeAction = ChangeMapSizeAction({ size, size }); GameActions::Execute(&changeMapSizeAction); w->Invalidate(); } @@ -968,8 +968,8 @@ static void WindowMapShowDefaultScenarioEditorButtons(rct_window* w) w->widgets[WIDX_MAP_GENERATOR].type = WindowWidgetType::Button; auto ft = Formatter::Common(); - ft.Increment(2); - ft.Add(gMapSize - 2); + ft.Add(gMapSize.x - 2); + ft.Add(gMapSize.y - 2); } static void WindowMapInputsizeLand(rct_window* w) @@ -1359,7 +1359,7 @@ static void WindowMapSetPeepSpawnToolDown(const ScreenCoordsXY& screenCoords) */ static void MapWindowIncreaseMapSize() { - auto increaseMapSizeAction = ChangeMapSizeAction(gMapSize + 1); + auto increaseMapSizeAction = ChangeMapSizeAction({ gMapSize.x + 1, gMapSize.y + 1 }); GameActions::Execute(&increaseMapSizeAction); } @@ -1369,7 +1369,7 @@ static void MapWindowIncreaseMapSize() */ static void MapWindowDecreaseMapSize() { - auto decreaseMapSizeAction = ChangeMapSizeAction(gMapSize - 1); + auto decreaseMapSizeAction = ChangeMapSizeAction({ gMapSize.x - 1, gMapSize.y - 1 }); GameActions::Execute(&decreaseMapSizeAction); } diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index 009e072232..146c4d1248 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -2129,9 +2129,9 @@ static void Sub6CbcE2( if (ride == nullptr) return; - int32_t preserveMapSize = gMapSize; + auto preserveMapSize = gMapSize; - gMapSize = MAXIMUM_MAP_SIZE_TECHNICAL; + gMapSize = { MAXIMUM_MAP_SIZE_TECHNICAL, MAXIMUM_MAP_SIZE_TECHNICAL }; const auto& ted = GetTrackElementDescriptor(trackType); const auto* trackBlock = ted.Block; diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index bc6ca29b0a..28a36c1ec9 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -502,7 +502,7 @@ namespace OpenRCT2 viewport_init_all(); _gameState = std::make_unique(); - _gameState->InitAll(150); + _gameState->InitAll({ 150, 150 }); _titleScreen = std::make_unique(*_gameState); _uiContext->Initialise(); diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index cc06472969..31bf94c957 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -94,7 +94,7 @@ namespace Editor { OpenRCT2::Audio::StopAll(); object_list_load(); - OpenRCT2::GetContext()->GetGameState()->InitAll(150); + OpenRCT2::GetContext()->GetGameState()->InitAll({ 150, 150 }); gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR; gEditorStep = EditorStep::ObjectSelection; gParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; @@ -170,7 +170,7 @@ namespace Editor object_manager_unload_all_objects(); object_list_load(); - OpenRCT2::GetContext()->GetGameState()->InitAll(150); + OpenRCT2::GetContext()->GetGameState()->InitAll({ 150, 150 }); SetAllLandOwned(); gEditorStep = EditorStep::ObjectSelection; viewport_init_all(); @@ -191,7 +191,7 @@ namespace Editor object_manager_unload_all_objects(); object_list_load(); - OpenRCT2::GetContext()->GetGameState()->InitAll(150); + OpenRCT2::GetContext()->GetGameState()->InitAll({ 150, 150 }); SetAllLandOwned(); gEditorStep = EditorStep::ObjectSelection; viewport_init_all(); @@ -206,9 +206,7 @@ namespace Editor */ static void SetAllLandOwned() { - int32_t mapSize = gMapSize; - - MapRange range = { 64, 64, (mapSize - 3) * 32, (mapSize - 3) * 32 }; + MapRange range = { 64, 64, (gMapSize.x - 3) * 32, (gMapSize.y - 3) * 32 }; auto landSetRightsAction = LandSetRightsAction(range, LandSetRightSetting::SetForSale); landSetRightsAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND); GameActions::Execute(&landSetRightsAction); diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index ff479d8432..bd6d81532d 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -424,7 +424,7 @@ void game_fix_save_vars() // Fix the invisible border tiles. // At this point, we can be sure that surfaceElement is not NULL. - if (x == 0 || x == gMapSize - 1 || y == 0 || y == gMapSize - 1) + if (x == 0 || x == gMapSize.x - 1 || y == 0 || y == gMapSize.y - 1) { surfaceElement->SetBaseZ(MINIMUM_LAND_HEIGHT_BIG); surfaceElement->SetClearanceZ(MINIMUM_LAND_HEIGHT_BIG); diff --git a/src/openrct2/GameState.cpp b/src/openrct2/GameState.cpp index 71d4dc3ab2..6845573bd3 100644 --- a/src/openrct2/GameState.cpp +++ b/src/openrct2/GameState.cpp @@ -54,7 +54,7 @@ GameState::GameState() /** * Initialises the map, park etc. basically all S6 data. */ -void GameState::InitAll(int32_t mapSize) +void GameState::InitAll(const TileCoordsXY& mapSize) { PROFILED_FUNCTION(); diff --git a/src/openrct2/GameState.h b/src/openrct2/GameState.h index 5768543c96..2e203aad0b 100644 --- a/src/openrct2/GameState.h +++ b/src/openrct2/GameState.h @@ -10,6 +10,7 @@ #pragma once #include "Date.h" +#include "world/Location.hpp" #include #include @@ -82,7 +83,7 @@ namespace OpenRCT2 return *_park; } - void InitAll(int32_t mapSize); + void InitAll(const TileCoordsXY& mapSize); void Tick(); void UpdateLogic(LogicTimings* timings = nullptr); diff --git a/src/openrct2/actions/ChangeMapSizeAction.cpp b/src/openrct2/actions/ChangeMapSizeAction.cpp index 33975206f2..44b490e21e 100644 --- a/src/openrct2/actions/ChangeMapSizeAction.cpp +++ b/src/openrct2/actions/ChangeMapSizeAction.cpp @@ -15,7 +15,7 @@ #include "../ui/WindowManager.h" #include "../windows/Intent.h" -ChangeMapSizeAction::ChangeMapSizeAction(const int32_t targetSize) +ChangeMapSizeAction::ChangeMapSizeAction(const TileCoordsXY targetSize) : _targetSize(targetSize) { } @@ -33,11 +33,11 @@ void ChangeMapSizeAction::Serialise(DataSerialiser& stream) GameActions::Result ChangeMapSizeAction::Query() const { - if (_targetSize > MAXIMUM_MAP_SIZE_TECHNICAL) + if (_targetSize.x > MAXIMUM_MAP_SIZE_TECHNICAL || _targetSize.y > MAXIMUM_MAP_SIZE_TECHNICAL) { return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_INCREASE_MAP_SIZE_ANY_FURTHER, STR_NONE); } - if (_targetSize < 16) + if (_targetSize.x < 16 || _targetSize.y < 16) { return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_DECREASE_MAP_SIZE_ANY_FURTHER, STR_NONE); } @@ -46,18 +46,23 @@ GameActions::Result ChangeMapSizeAction::Query() const GameActions::Result ChangeMapSizeAction::Execute() const { - while (gMapSize != _targetSize) + // Expand map + while (_targetSize.x > gMapSize.x) { - if (_targetSize < gMapSize) - { - gMapSize--; - map_remove_out_of_range_elements(); - } - else - { - gMapSize++; - map_extend_boundary_surface(); - } + gMapSize.x++; + map_extend_boundary_surface_x(); + } + while (_targetSize.y > gMapSize.y) + { + gMapSize.y++; + map_extend_boundary_surface_y(); + } + + // Shrink map + if (_targetSize.x < gMapSize.x || _targetSize.y < gMapSize.y) + { + gMapSize = _targetSize; + map_remove_out_of_range_elements(); } auto* ctx = OpenRCT2::GetContext(); @@ -71,5 +76,6 @@ GameActions::Result ChangeMapSizeAction::Execute() const void ChangeMapSizeAction::AcceptParameters(GameActionParameterVisitor& visitor) { - visitor.Visit("targetSize", _targetSize); + visitor.Visit("targetSizeX", _targetSize.x); + visitor.Visit("targetSizeY", _targetSize.y); } diff --git a/src/openrct2/actions/ChangeMapSizeAction.h b/src/openrct2/actions/ChangeMapSizeAction.h index 650a57208c..332dd4cec6 100644 --- a/src/openrct2/actions/ChangeMapSizeAction.h +++ b/src/openrct2/actions/ChangeMapSizeAction.h @@ -16,7 +16,7 @@ class ChangeMapSizeAction final : public GameActionBase(32, normRange.GetLeft()); - auto bX = std::min(GetMapSizeMaxXY(), normRange.GetRight()); + auto bX = std::min(mapSizeMaxXY.x, normRange.GetRight()); auto aY = std::max(32, normRange.GetTop()); - auto bY = std::min(GetMapSizeMaxXY(), normRange.GetBottom()); + auto bY = std::min(mapSizeMaxXY.y, normRange.GetBottom()); MapRange validRange = MapRange{ aX, aY, bX, bY }; diff --git a/src/openrct2/actions/LandLowerAction.cpp b/src/openrct2/actions/LandLowerAction.cpp index 702697fa38..1e87b34b92 100644 --- a/src/openrct2/actions/LandLowerAction.cpp +++ b/src/openrct2/actions/LandLowerAction.cpp @@ -62,13 +62,7 @@ GameActions::Result LandLowerAction::QueryExecute(bool isExecuting) const if (_selectionType >= MAP_SELECT_TYPE_EDGE_0 && _selectionType <= MAP_SELECT_TYPE_EDGE_3) tableRow -= MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1; - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(GetMapSizeMaxXY(), _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(GetMapSizeMaxXY(), _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; + auto validRange = ClampRangeWithinMap(_range); res.Position = { _coords.x, _coords.y, tile_element_height(_coords) }; res.Expenditure = ExpenditureType::Landscaping; diff --git a/src/openrct2/actions/LandRaiseAction.cpp b/src/openrct2/actions/LandRaiseAction.cpp index e9585e0d7b..e2cc4666fb 100644 --- a/src/openrct2/actions/LandRaiseAction.cpp +++ b/src/openrct2/actions/LandRaiseAction.cpp @@ -63,13 +63,7 @@ GameActions::Result LandRaiseAction::QueryExecute(bool isExecuting) const if (_selectionType >= MAP_SELECT_TYPE_EDGE_0 && _selectionType <= MAP_SELECT_TYPE_EDGE_3) tableRow -= MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1; - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(GetMapSizeMaxXY(), _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(GetMapSizeMaxXY(), _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; + auto validRange = ClampRangeWithinMap(_range); res.Position = { _coords.x, _coords.y, tile_element_height(_coords) }; res.Expenditure = ExpenditureType::Landscaping; diff --git a/src/openrct2/actions/LandSetHeightAction.cpp b/src/openrct2/actions/LandSetHeightAction.cpp index ddaabf6243..c2fdcefcbc 100644 --- a/src/openrct2/actions/LandSetHeightAction.cpp +++ b/src/openrct2/actions/LandSetHeightAction.cpp @@ -183,7 +183,8 @@ rct_string_id LandSetHeightAction::CheckParameters() const return STR_OFF_EDGE_OF_MAP; } - if (_coords.x > GetMapSizeMaxXY() || _coords.y > GetMapSizeMaxXY()) + auto mapSizeMax = GetMapSizeMaxXY(); + if (_coords.x > mapSizeMax.x || _coords.y > mapSizeMax.y) { return STR_OFF_EDGE_OF_MAP; } diff --git a/src/openrct2/actions/LandSetRightsAction.cpp b/src/openrct2/actions/LandSetRightsAction.cpp index 8dac23eaf2..5393d1ca08 100644 --- a/src/openrct2/actions/LandSetRightsAction.cpp +++ b/src/openrct2/actions/LandSetRightsAction.cpp @@ -67,15 +67,7 @@ GameActions::Result LandSetRightsAction::QueryExecute(bool isExecuting) const { auto res = GameActions::Result(); - MapRange normRange = _range.Normalise(); - // Keep big coordinates within map boundaries - auto aX = std::max(32, normRange.GetLeft()); - auto bX = std::min(GetMapSizeMaxXY(), normRange.GetRight()); - auto aY = std::max(32, normRange.GetTop()); - auto bY = std::min(GetMapSizeMaxXY(), normRange.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - + auto validRange = ClampRangeWithinMap(_range.Normalise()); CoordsXYZ centre{ (validRange.GetLeft() + validRange.GetRight()) / 2 + 16, (validRange.GetTop() + validRange.GetBottom()) / 2 + 16, 0 }; centre.z = tile_element_height(centre); diff --git a/src/openrct2/actions/LargeScenerySetColourAction.cpp b/src/openrct2/actions/LargeScenerySetColourAction.cpp index 0848051f1d..255c20af7d 100644 --- a/src/openrct2/actions/LargeScenerySetColourAction.cpp +++ b/src/openrct2/actions/LargeScenerySetColourAction.cpp @@ -53,7 +53,8 @@ GameActions::Result LargeScenerySetColourAction::QueryExecute(bool isExecuting) res.Position.z = tile_element_height(_loc); res.ErrorTitle = STR_CANT_REPAINT_THIS; - if (_loc.x < 0 || _loc.y < 0 || _loc.x > GetMapSizeMaxXY() || _loc.y > GetMapSizeMaxXY()) + auto mapSizeMax = GetMapSizeMaxXY(); + if (_loc.x < 0 || _loc.y < 0 || _loc.x > mapSizeMax.x || _loc.y > mapSizeMax.y) { log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS, STR_NONE); diff --git a/src/openrct2/actions/PlaceParkEntranceAction.cpp b/src/openrct2/actions/PlaceParkEntranceAction.cpp index 8f7823772d..8fb7704430 100644 --- a/src/openrct2/actions/PlaceParkEntranceAction.cpp +++ b/src/openrct2/actions/PlaceParkEntranceAction.cpp @@ -51,8 +51,8 @@ GameActions::Result PlaceParkEntranceAction::Query() const res.Expenditure = ExpenditureType::LandPurchase; res.Position = { _loc.x, _loc.y, _loc.z }; - if (!LocationValid(_loc) || _loc.x <= 32 || _loc.y <= 32 || _loc.x >= (GetMapSizeUnits() - 32) - || _loc.y >= (GetMapSizeUnits() - 32)) + auto mapSizeUnits = GetMapSizeUnits() - CoordsXY{ 32, 32 }; + if (!LocationValid(_loc) || _loc.x <= 32 || _loc.y <= 32 || _loc.x >= mapSizeUnits.x || _loc.y >= mapSizeUnits.y) { return GameActions::Result( GameActions::Status::InvalidParameters, STR_CANT_BUILD_THIS_HERE, STR_TOO_CLOSE_TO_EDGE_OF_MAP); diff --git a/src/openrct2/actions/PlacePeepSpawnAction.cpp b/src/openrct2/actions/PlacePeepSpawnAction.cpp index 140967d7b7..471116395b 100644 --- a/src/openrct2/actions/PlacePeepSpawnAction.cpp +++ b/src/openrct2/actions/PlacePeepSpawnAction.cpp @@ -46,8 +46,9 @@ GameActions::Result PlacePeepSpawnAction::Query() const res.Expenditure = ExpenditureType::LandPurchase; res.Position = _location; - if (!LocationValid(_location) || _location.x <= 16 || _location.y <= 16 || _location.x >= (GetMapSizeUnits() - 16) - || _location.y >= (GetMapSizeUnits() - 16)) + auto mapSizeUnits = GetMapSizeUnits() - CoordsXY{ 16, 16 }; + if (!LocationValid(_location) || _location.x <= 16 || _location.y <= 16 || _location.x >= mapSizeUnits.x + || _location.y >= mapSizeUnits.y) { return GameActions::Result( GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_OFF_EDGE_OF_MAP); diff --git a/src/openrct2/actions/RideDemolishAction.cpp b/src/openrct2/actions/RideDemolishAction.cpp index afe6f3186c..c64170a64b 100644 --- a/src/openrct2/actions/RideDemolishAction.cpp +++ b/src/openrct2/actions/RideDemolishAction.cpp @@ -195,9 +195,9 @@ money32 RideDemolishAction::DemolishTracks() const uint8_t oldpaused = gGamePaused; gGamePaused = 0; - for (TileCoordsXY tilePos = {}; tilePos.x < gMapSize; ++tilePos.x) + for (TileCoordsXY tilePos = {}; tilePos.x < gMapSize.x; ++tilePos.x) { - for (tilePos.y = 0; tilePos.y < gMapSize; ++tilePos.y) + for (tilePos.y = 0; tilePos.y < gMapSize.y; ++tilePos.y) { const auto tileCoords = tilePos.ToCoordsXY(); // Keep retrying a tile coordinate until there are no more items to remove diff --git a/src/openrct2/actions/SetCheatAction.cpp b/src/openrct2/actions/SetCheatAction.cpp index d61d2ad1c8..d271c4c692 100644 --- a/src/openrct2/actions/SetCheatAction.cpp +++ b/src/openrct2/actions/SetCheatAction.cpp @@ -683,12 +683,12 @@ void SetCheatAction::SetStaffSpeed(uint8_t value) const void SetCheatAction::OwnAllLand() const { - const int32_t min = 32; - const int32_t max = GetMapSizeUnits() - 32; + const auto min = CoordsXY{ 32, 32 }; + const auto max = GetMapSizeUnits() - CoordsXY{ 32, 32 }; - for (CoordsXY coords = { min, min }; coords.y <= max; coords.y += COORDS_XY_STEP) + for (CoordsXY coords = min; coords.y <= max.y; coords.y += COORDS_XY_STEP) { - for (coords.x = min; coords.x <= max; coords.x += COORDS_XY_STEP) + for (coords.x = min.x; coords.x <= max.x; coords.x += COORDS_XY_STEP) { auto* surfaceElement = map_get_surface_element_at(coords); if (surfaceElement == nullptr) diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.cpp b/src/openrct2/actions/SmallSceneryPlaceAction.cpp index 30ce122e4f..30abcbb6b4 100644 --- a/src/openrct2/actions/SmallSceneryPlaceAction.cpp +++ b/src/openrct2/actions/SmallSceneryPlaceAction.cpp @@ -103,7 +103,8 @@ GameActions::Result SmallSceneryPlaceAction::Query() const GameActions::Status::NoFreeElements, STR_CANT_POSITION_THIS_HERE, STR_TILE_ELEMENT_LIMIT_REACHED); } - if (!_trackDesignDrawingPreview && (_loc.x > GetMapSizeMaxXY() || _loc.y > GetMapSizeMaxXY())) + auto maxSizeMax = GetMapSizeMaxXY(); + if (!_trackDesignDrawingPreview && (_loc.x > maxSizeMax.x || _loc.y > maxSizeMax.y)) { return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_NONE); } diff --git a/src/openrct2/actions/SurfaceSetStyleAction.cpp b/src/openrct2/actions/SurfaceSetStyleAction.cpp index 0a15ea895f..3656018558 100644 --- a/src/openrct2/actions/SurfaceSetStyleAction.cpp +++ b/src/openrct2/actions/SurfaceSetStyleAction.cpp @@ -39,14 +39,7 @@ GameActions::Result SurfaceSetStyleAction::Query() const res.ErrorTitle = STR_CANT_CHANGE_LAND_TYPE; res.Expenditure = ExpenditureType::Landscaping; - auto normRange = _range.Normalise(); - auto x0 = std::max(normRange.GetLeft(), 32); - auto y0 = std::max(normRange.GetTop(), 32); - auto x1 = std::min(normRange.GetRight(), GetMapSizeMaxXY()); - auto y1 = std::min(normRange.GetBottom(), GetMapSizeMaxXY()); - - MapRange validRange{ x0, y0, x1, y1 }; - + auto validRange = ClampRangeWithinMap(_range.Normalise()); auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) { @@ -158,14 +151,7 @@ GameActions::Result SurfaceSetStyleAction::Execute() const res.ErrorTitle = STR_CANT_CHANGE_LAND_TYPE; res.Expenditure = ExpenditureType::Landscaping; - auto normRange = _range.Normalise(); - auto x0 = std::max(normRange.GetLeft(), 32); - auto y0 = std::max(normRange.GetTop(), 32); - auto x1 = std::min(normRange.GetRight(), GetMapSizeMaxXY()); - auto y1 = std::min(normRange.GetBottom(), GetMapSizeMaxXY()); - - MapRange validRange{ x0, y0, x1, y1 }; - + auto validRange = ClampRangeWithinMap(_range.Normalise()); auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; auto heightMid = tile_element_height({ xMid, yMid }); diff --git a/src/openrct2/actions/WallPlaceAction.cpp b/src/openrct2/actions/WallPlaceAction.cpp index 4ca0298dbd..8987ee24ac 100644 --- a/src/openrct2/actions/WallPlaceAction.cpp +++ b/src/openrct2/actions/WallPlaceAction.cpp @@ -78,6 +78,7 @@ GameActions::Result WallPlaceAction::Query() const return GameActions::Result(GameActions::Status::NotOwned, STR_CANT_BUILD_THIS_HERE, STR_NONE); } + auto mapSizeMax = GetMapSizeMaxXY(); if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsSandboxMode) { if (_loc.z == 0) @@ -92,7 +93,7 @@ GameActions::Result WallPlaceAction::Query() const return GameActions::Result(GameActions::Status::NotOwned, STR_CANT_BUILD_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); } } - else if (!_trackDesignDrawingPreview && (_loc.x > GetMapSizeMaxXY() || _loc.y > GetMapSizeMaxXY())) + else if (!_trackDesignDrawingPreview && (_loc.x > mapSizeMax.x || _loc.y > mapSizeMax.y)) { log_error("Invalid x/y coordinates. x = %d y = %d", _loc.x, _loc.y); return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_BUILD_THIS_HERE, STR_NONE); diff --git a/src/openrct2/actions/WaterLowerAction.cpp b/src/openrct2/actions/WaterLowerAction.cpp index c6f1e2e82d..c3839bb2fe 100644 --- a/src/openrct2/actions/WaterLowerAction.cpp +++ b/src/openrct2/actions/WaterLowerAction.cpp @@ -45,14 +45,7 @@ GameActions::Result WaterLowerAction::QueryExecute(bool isExecuting) const { auto res = GameActions::Result(); - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(GetMapSizeMaxXY(), _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(GetMapSizeMaxXY(), _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - + auto validRange = ClampRangeWithinMap(_range); res.Position.x = ((validRange.GetLeft() + validRange.GetRight()) / 2) + 16; res.Position.y = ((validRange.GetTop() + validRange.GetBottom()) / 2) + 16; int16_t z = tile_element_height(res.Position); diff --git a/src/openrct2/actions/WaterRaiseAction.cpp b/src/openrct2/actions/WaterRaiseAction.cpp index 279c395622..ae3b7b0ab7 100644 --- a/src/openrct2/actions/WaterRaiseAction.cpp +++ b/src/openrct2/actions/WaterRaiseAction.cpp @@ -45,14 +45,7 @@ GameActions::Result WaterRaiseAction::QueryExecute(bool isExecuting) const { auto res = GameActions::Result(); - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(GetMapSizeMaxXY(), _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(GetMapSizeMaxXY(), _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - + auto validRange = ClampRangeWithinMap(_range); res.Position.x = ((validRange.GetLeft() + validRange.GetRight()) / 2) + 16; res.Position.y = ((validRange.GetTop() + validRange.GetBottom()) / 2) + 16; int32_t z = tile_element_height(res.Position); diff --git a/src/openrct2/actions/WaterSetHeightAction.cpp b/src/openrct2/actions/WaterSetHeightAction.cpp index 3e458a6776..ba00851208 100644 --- a/src/openrct2/actions/WaterSetHeightAction.cpp +++ b/src/openrct2/actions/WaterSetHeightAction.cpp @@ -133,7 +133,8 @@ GameActions::Result WaterSetHeightAction::Execute() const rct_string_id WaterSetHeightAction::CheckParameters() const { - if (_coords.x > GetMapSizeMaxXY() || _coords.y > GetMapSizeMaxXY()) + auto mapSizeMax = GetMapSizeMaxXY(); + if (_coords.x > mapSizeMax.x || _coords.y > mapSizeMax.y) { return STR_OFF_EDGE_OF_MAP; } diff --git a/src/openrct2/cmdline/BenchSpriteSort.cpp b/src/openrct2/cmdline/BenchSpriteSort.cpp index 1d193b411d..48d57cb4af 100644 --- a/src/openrct2/cmdline/BenchSpriteSort.cpp +++ b/src/openrct2/cmdline/BenchSpriteSort.cpp @@ -87,9 +87,8 @@ static std::vector extract_paint_session(std::string_view gIntroState = IntroState::None; gScreenFlags = SCREEN_FLAGS_PLAYING; - int32_t mapSize = gMapSize; - int32_t resolutionWidth = (mapSize * 32 * 2); - int32_t resolutionHeight = (mapSize * 32 * 1); + int32_t resolutionWidth = (gMapSize.x * 32 * 2); + int32_t resolutionHeight = (gMapSize.y * 32 * 1); resolutionWidth += 8; resolutionHeight += 128; @@ -103,8 +102,8 @@ static std::vector extract_paint_session(std::string_view viewport.var_11 = 0; viewport.flags = 0; - int32_t customX = (gMapSize / 2) * 32 + 16; - int32_t customY = (gMapSize / 2) * 32 + 16; + int32_t customX = (gMapSize.x / 2) * 32 + 16; + int32_t customY = (gMapSize.y / 2) * 32 + 16; int32_t x = 0, y = 0; int32_t z = tile_element_height({ customX, customY }); diff --git a/src/openrct2/core/DataSerialiserTraits.h b/src/openrct2/core/DataSerialiserTraits.h index 41f11c2a06..7916508cc6 100644 --- a/src/openrct2/core/DataSerialiserTraits.h +++ b/src/openrct2/core/DataSerialiserTraits.h @@ -484,6 +484,27 @@ template<> struct DataSerializerTraits_t } }; +template<> struct DataSerializerTraits_t +{ + static void encode(OpenRCT2::IStream* stream, const TileCoordsXY& coords) + { + stream->WriteValue(ByteSwapBE(coords.x)); + stream->WriteValue(ByteSwapBE(coords.y)); + } + static void decode(OpenRCT2::IStream* stream, TileCoordsXY& coords) + { + auto x = ByteSwapBE(stream->ReadValue()); + auto y = ByteSwapBE(stream->ReadValue()); + coords = TileCoordsXY{ x, y }; + } + static void log(OpenRCT2::IStream* stream, const TileCoordsXY& coords) + { + char msg[128] = {}; + snprintf(msg, sizeof(msg), "TileCoordsXY(x = %d, y = %d)", coords.x, coords.y); + stream->Write(msg, strlen(msg)); + } +}; + template<> struct DataSerializerTraits_t { static void encode(OpenRCT2::IStream* stream, const CoordsXY& coords) diff --git a/src/openrct2/interface/Screenshot.cpp b/src/openrct2/interface/Screenshot.cpp index 93b02f9fce..a303b05cc0 100644 --- a/src/openrct2/interface/Screenshot.cpp +++ b/src/openrct2/interface/Screenshot.cpp @@ -214,10 +214,11 @@ enum class EdgeType BOTTOM }; -static CoordsXY GetEdgeTile(int32_t mapSize, int32_t rotation, EdgeType edgeType, bool visible) +static CoordsXY GetEdgeTile(TileCoordsXY mapSize, int32_t rotation, EdgeType edgeType, bool visible) { + // TODO int32_t lower = (visible ? 1 : 0) * 32; - int32_t upper = (visible ? mapSize - 2 : mapSize - 1) * 32; + int32_t upper = (visible ? mapSize.x - 2 : mapSize.x - 1) * 32; switch (edgeType) { default: @@ -291,12 +292,12 @@ static int32_t GetHighestBaseClearanceZ(const CoordsXY& location) return z; } -static int32_t GetTallestVisibleTileTop(int32_t mapSize, int32_t rotation) +static int32_t GetTallestVisibleTileTop(const TileCoordsXY& mapSize, int32_t rotation) { int32_t minViewY = 0; - for (int32_t y = 1; y < mapSize - 1; y++) + for (int32_t y = 1; y < mapSize.y - 1; y++) { - for (int32_t x = 1; x < mapSize - 1; x++) + for (int32_t x = 1; x < mapSize.x - 1; x++) { auto location = TileCoordsXY(x, y).ToCoordsXY(); int32_t z = GetHighestBaseClearanceZ(location); @@ -335,7 +336,7 @@ static void ReleaseDPI(rct_drawpixelinfo& dpi) dpi.height = 0; } -static rct_viewport GetGiantViewport(int32_t mapSize, int32_t rotation, ZoomLevel zoom) +static rct_viewport GetGiantViewport(const TileCoordsXY& mapSize, int32_t rotation, ZoomLevel zoom) { // Get the tile coordinates of each corner auto leftTileCoords = GetEdgeTile(mapSize, rotation, EdgeType::LEFT, false); @@ -684,11 +685,11 @@ int32_t cmdline_for_screenshot(const char** argv, int32_t argc, ScreenshotOption customRotation = std::atoi(argv[7]) & 3; } - int32_t mapSize = gMapSize; + const auto& mapSize = gMapSize; if (resolutionWidth == 0 || resolutionHeight == 0) { - resolutionWidth = (mapSize * 32 * 2) >> customZoom; - resolutionHeight = (mapSize * 32 * 1) >> customZoom; + resolutionWidth = (mapSize.x * 32 * 2) >> customZoom; + resolutionHeight = (mapSize.y * 32 * 1) >> customZoom; resolutionWidth += 8; resolutionHeight += 128; @@ -701,9 +702,9 @@ int32_t cmdline_for_screenshot(const char** argv, int32_t argc, ScreenshotOption if (customLocation) { if (centreMapX) - customX = (mapSize / 2) * 32 + 16; + customX = (mapSize.x / 2) * 32 + 16; if (centreMapY) - customY = (mapSize / 2) * 32 + 16; + customY = (mapSize.y / 2) * 32 + 16; int32_t z = tile_element_height({ customX, customY }); CoordsXYZ coords3d = { customX, customY, z }; diff --git a/src/openrct2/interface/Viewport.cpp b/src/openrct2/interface/Viewport.cpp index 861af34857..8e4b31c927 100644 --- a/src/openrct2/interface/Viewport.cpp +++ b/src/openrct2/interface/Viewport.cpp @@ -249,8 +249,8 @@ CoordsXYZ viewport_adjust_for_map_height(const ScreenCoordsXY& startCoords) // HACK: This is to prevent the x and y values being set to values outside // of the map. This can happen when the height is larger than the map size. - auto max = GetMapSizeMinus2(); - if (pos.x > max && pos.y > max) + auto mapSizeMinus2 = GetMapSizeMinus2(); + if (pos.x > mapSizeMinus2.x && pos.y > mapSizeMinus2.y) { static constexpr CoordsXY corr[] = { { -1, -1 }, @@ -597,14 +597,15 @@ void viewport_update_position(rct_window* window) } // Clamp to the map maximum value (scenario specific) - if (mapCoord.x > GetMapSizeMinus2()) + auto mapSizeMinus2 = GetMapSizeMinus2(); + if (mapCoord.x > mapSizeMinus2.x) { - mapCoord.x = GetMapSizeMinus2(); + mapCoord.x = mapSizeMinus2.x; at_map_edge = 1; } - if (mapCoord.y > GetMapSizeMinus2()) + if (mapCoord.y > mapSizeMinus2.y) { - mapCoord.y = GetMapSizeMinus2(); + mapCoord.y = mapSizeMinus2.y; at_map_edge = 1; } diff --git a/src/openrct2/network/NetworkServerAdvertiser.cpp b/src/openrct2/network/NetworkServerAdvertiser.cpp index 4c6777e5de..73036fe73b 100644 --- a/src/openrct2/network/NetworkServerAdvertiser.cpp +++ b/src/openrct2/network/NetworkServerAdvertiser.cpp @@ -298,8 +298,9 @@ private: { "players", numPlayers }, }; + json_t mapSize = { { "x", gMapSize.x - 2 }, { "y", gMapSize.y - 2 } }; json_t gameInfo = { - { "mapSize", gMapSize - 2 }, { "day", gDateMonthTicks }, { "month", gDateMonthsElapsed }, + { "mapSize", mapSize }, { "day", gDateMonthTicks }, { "month", gDateMonthsElapsed }, { "guests", gNumGuestsInPark }, { "parkValue", gParkValue }, }; if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) diff --git a/src/openrct2/park/ParkFile.cpp b/src/openrct2/park/ParkFile.cpp index 170ee9f122..b3a86cf73c 100644 --- a/src/openrct2/park/ParkFile.cpp +++ b/src/openrct2/park/ParkFile.cpp @@ -891,8 +891,8 @@ namespace OpenRCT2 auto found = os.ReadWriteChunk( ParkFileChunkType::TILES, [pathToSurfaceMap, pathToQueueSurfaceMap, pathToRailingsMap](OrcaStream::ChunkStream& cs) { - cs.ReadWrite(gMapSize); // x - cs.Write(gMapSize); // y + cs.ReadWrite(gMapSize.x); + cs.ReadWrite(gMapSize.y); if (cs.GetMode() == OrcaStream::Mode::READING) { diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index fa87bad008..da129197a7 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -326,7 +326,7 @@ namespace RCT1 // Do map initialisation, same kind of stuff done when loading scenario editor auto context = OpenRCT2::GetContext(); - context->GetGameState()->InitAll(mapSize); + context->GetGameState()->InitAll({ mapSize, mapSize }); gEditorStep = EditorStep::ObjectSelection; gParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; gScenarioCategory = SCENARIO_CATEGORY_OTHER; diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index a23f5fecbb..011f51ade0 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -379,7 +379,7 @@ namespace RCT2 gCash = ToMoney64(DECRYPT_MONEY(_s6.cash)); // pad_013587FC gParkRatingCasualtyPenalty = _s6.park_rating_casualty_penalty; - gMapSize = _s6.map_size; + gMapSize = { _s6.map_size, _s6.map_size }; gSamePriceThroughoutPark = _s6.same_price_throughout | (static_cast(_s6.same_price_throughout_extended) << 32); _suggestedGuestMaximum = _s6.suggested_max_guests; @@ -1040,7 +1040,7 @@ namespace RCT2 void Initialise() { - OpenRCT2::GetContext()->GetGameState()->InitAll(_s6.map_size); + OpenRCT2::GetContext()->GetGameState()->InitAll({ _s6.map_size, _s6.map_size }); } /** diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 7d5ed7b4a0..954b436506 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -5689,9 +5689,9 @@ void determine_ride_entrance_and_exit_locations() void ride_clear_leftover_entrances(Ride* ride) { - for (TileCoordsXY tilePos = {}; tilePos.x < gMapSize; ++tilePos.x) + for (TileCoordsXY tilePos = {}; tilePos.x < gMapSize.x; ++tilePos.x) { - for (tilePos.y = 0; tilePos.y < gMapSize; ++tilePos.y) + for (tilePos.y = 0; tilePos.y < gMapSize.y; ++tilePos.y) { for (auto* entrance : TileElementsView(tilePos.ToCoordsXY())) { diff --git a/src/openrct2/ride/RideConstruction.cpp b/src/openrct2/ride/RideConstruction.cpp index d8dd456703..8a18168a0d 100644 --- a/src/openrct2/ride/RideConstruction.cpp +++ b/src/openrct2/ride/RideConstruction.cpp @@ -347,9 +347,9 @@ void Ride::RemovePeeps() void ride_clear_blocked_tiles(Ride* ride) { - for (TileCoordsXY tilePos = {}; tilePos.x < gMapSize; ++tilePos.x) + for (TileCoordsXY tilePos = {}; tilePos.x < gMapSize.x; ++tilePos.x) { - for (tilePos.y = 0; tilePos.y < gMapSize; ++tilePos.y) + for (tilePos.y = 0; tilePos.y < gMapSize.y; ++tilePos.y) { for (auto* trackElement : TileElementsView(tilePos.ToCoordsXY())) { diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 1ba3450037..dbd371e252 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -1993,10 +1993,10 @@ static bool TrackDesignPlacePreview(TrackDesignState& tds, TrackDesign* td6, mon uint8_t backup_rotation = _currentTrackPieceDirection; uint32_t backup_park_flags = gParkFlags; gParkFlags &= ~PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; - int32_t mapSize = gMapSize << 4; + auto mapSize = TileCoordsXY{ gMapSize.x / 16, gMapSize.y / 16 }; _currentTrackPieceDirection = 0; - int32_t z = TrackDesignGetZPlacement(tds, td6, GetOrAllocateRide(PreviewRideId), { mapSize, mapSize, 16 }); + int32_t z = TrackDesignGetZPlacement(tds, td6, GetOrAllocateRide(PreviewRideId), { mapSize.x, mapSize.y, 16 }); if (tds.HasScenery) { @@ -2013,7 +2013,7 @@ static bool TrackDesignPlacePreview(TrackDesignState& tds, TrackDesign* td6, mon } auto res = TrackDesignPlaceVirtual( - tds, td6, PTD_OPERATION_PLACE_TRACK_PREVIEW, placeScenery, ride, { mapSize, mapSize, z }); + tds, td6, PTD_OPERATION_PLACE_TRACK_PREVIEW, placeScenery, ride, { mapSize.x, mapSize.y, z }); gParkFlags = backup_park_flags; if (res.Error == GameActions::Status::Ok) @@ -2148,7 +2148,7 @@ static void TrackDesignPreviewClearMap() { auto numTiles = MAXIMUM_MAP_SIZE_TECHNICAL * MAXIMUM_MAP_SIZE_TECHNICAL; - gMapSize = 256; + gMapSize = { 256, 256 }; // Reserve ~8 elements per tile std::vector tileElements; diff --git a/src/openrct2/scripting/Duktape.hpp b/src/openrct2/scripting/Duktape.hpp index a31c5a86de..abf01f670f 100644 --- a/src/openrct2/scripting/Duktape.hpp +++ b/src/openrct2/scripting/Duktape.hpp @@ -336,6 +336,14 @@ namespace OpenRCT2::Scripting return dukCoords.Take(); } + template<> DukValue inline ToDuk(duk_context* ctx, const TileCoordsXY& coords) + { + DukObject dukCoords(ctx); + dukCoords.Set("x", coords.x); + dukCoords.Set("y", coords.y); + return dukCoords.Take(); + } + template<> DukValue inline ToDuk(duk_context* ctx, const ScreenCoordsXY& coords) { DukObject dukCoords(ctx); diff --git a/src/openrct2/scripting/bindings/world/ScMap.cpp b/src/openrct2/scripting/bindings/world/ScMap.cpp index dec9bec14d..ef562464c9 100644 --- a/src/openrct2/scripting/bindings/world/ScMap.cpp +++ b/src/openrct2/scripting/bindings/world/ScMap.cpp @@ -42,7 +42,7 @@ namespace OpenRCT2::Scripting DukValue ScMap::size_get() const { - return ToDuk(_context, CoordsXY{ gMapSize, gMapSize }); + return ToDuk(_context, gMapSize); } int32_t ScMap::numRides_get() const diff --git a/src/openrct2/title/TitleScreen.cpp b/src/openrct2/title/TitleScreen.cpp index 669d53fdaf..8be1139caa 100644 --- a/src/openrct2/title/TitleScreen.cpp +++ b/src/openrct2/title/TitleScreen.cpp @@ -129,7 +129,7 @@ void TitleScreen::Load() GetContext()->GetNetwork().Close(); #endif OpenRCT2::Audio::StopAll(); - GetContext()->GetGameState()->InitAll(150); + GetContext()->GetGameState()->InitAll({ 150, 150 }); viewport_init_all(); context_open_window(WC_MAIN_WINDOW); CreateWindows(); @@ -335,7 +335,7 @@ bool TitleScreen::TryLoadSequence(bool loadPreview) _loadedTitleSequenceId = SIZE_MAX; if (!loadPreview) { - GetContext()->GetGameState()->InitAll(150); + GetContext()->GetGameState()->InitAll({ 150, 150 }); } return false; } diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 37e2598d71..716d28afa5 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -90,7 +90,7 @@ uint8_t gMapSelectArrowDirection; TileCoordsXY gWidePathTileLoopPosition; uint16_t gGrassSceneryTileLoopPosition; -int32_t gMapSize; +TileCoordsXY gMapSize; int32_t gMapBaseZ; std::vector gMapSelectionTiles; @@ -113,7 +113,7 @@ static TilePointerIndex _tileIndexStash; static std::vector _tileElementsStash; static size_t _tileElementsInUse; static size_t _tileElementsInUseStash; -static int32_t _mapSizeStash; +static TileCoordsXY _mapSizeStash; static int32_t _currentRotationStash; void StashMap() @@ -419,7 +419,7 @@ BannerElement* map_get_banner_element_at(const CoordsXYZ& bannerPos, uint8_t pos * * rct2: 0x0068AB4C */ -void map_init(int32_t size) +void map_init(const TileCoordsXY& size) { auto numTiles = MAXIMUM_MAP_SIZE_TECHNICAL * MAXIMUM_MAP_SIZE_TECHNICAL; @@ -792,7 +792,8 @@ bool map_is_location_valid(const CoordsXY& coords) bool map_is_edge(const CoordsXY& coords) { - return (coords.x < 32 || coords.y < 32 || coords.x >= GetMapSizeUnits() || coords.y >= GetMapSizeUnits()); + auto mapSizeUnits = GetMapSizeUnits(); + return (coords.x < 32 || coords.y < 32 || coords.x >= mapSizeUnits.x || coords.y >= mapSizeUnits.y); } bool map_can_build_at(const CoordsXYZ& loc) @@ -1009,8 +1010,9 @@ int32_t tile_element_get_corner_height(const SurfaceElement* surfaceElement, int uint8_t map_get_lowest_land_height(const MapRange& range) { + auto mapSizeMax = GetMapSizeMaxXY(); MapRange validRange = { std::max(range.GetLeft(), 32), std::max(range.GetTop(), 32), - std::min(range.GetRight(), GetMapSizeMaxXY()), std::min(range.GetBottom(), GetMapSizeMaxXY()) }; + std::min(range.GetRight(), mapSizeMax.x), std::min(range.GetBottom(), mapSizeMax.y) }; uint8_t min_height = 0xFF; for (int32_t yi = validRange.GetTop(); yi <= validRange.GetBottom(); yi += COORDS_XY_STEP) @@ -1038,8 +1040,9 @@ uint8_t map_get_lowest_land_height(const MapRange& range) uint8_t map_get_highest_land_height(const MapRange& range) { + auto mapSizeMax = GetMapSizeMaxXY(); MapRange validRange = { std::max(range.GetLeft(), 32), std::max(range.GetTop(), 32), - std::min(range.GetRight(), GetMapSizeMaxXY()), std::min(range.GetBottom(), GetMapSizeMaxXY()) }; + std::min(range.GetRight(), mapSizeMax.x), std::min(range.GetBottom(), mapSizeMax.y) }; uint8_t max_height = 0; for (int32_t yi = validRange.GetTop(); yi <= validRange.GetBottom(); yi += COORDS_XY_STEP) @@ -1333,9 +1336,9 @@ void map_update_tiles() } // Repeat for each 256x256 block on the map - for (int32_t blockY = 0; blockY < gMapSize; blockY += 256) + for (int32_t blockY = 0; blockY < gMapSize.y; blockY += 256) { - for (int32_t blockX = 0; blockX < gMapSize; blockX += 256) + for (int32_t blockX = 0; blockX < gMapSize.x; blockX += 256) { auto mapPos = TileCoordsXY{ blockX + x, blockY + y }.ToCoordsXY(); auto* surfaceElement = map_get_surface_element_at(mapPos); @@ -1406,7 +1409,7 @@ void map_restore_provisional_elements() */ void map_remove_out_of_range_elements() { - int32_t mapMaxXY = GetMapSizeMaxXY(); + auto mapSizeMax = GetMapSizeMaxXY(); // Ensure that we can remove elements // @@ -1416,11 +1419,11 @@ void map_remove_out_of_range_elements() bool buildState = gCheatsBuildInPauseMode; gCheatsBuildInPauseMode = true; - for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_BIG; y += COORDS_XY_STEP) + for (int32_t y = MAXIMUM_MAP_SIZE_BIG - COORDS_XY_STEP; y >= 0; y -= COORDS_XY_STEP) { - for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_BIG; x += COORDS_XY_STEP) + for (int32_t x = MAXIMUM_MAP_SIZE_BIG - COORDS_XY_STEP; x >= 0; x -= COORDS_XY_STEP) { - if (x == 0 || y == 0 || x >= mapMaxXY || y >= mapMaxXY) + if (x == 0 || y == 0 || x >= mapSizeMax.x || y >= mapSizeMax.y) { // Note this purposely does not use LandSetRightsAction as X Y coordinates are outside of normal range. auto surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); @@ -1476,19 +1479,15 @@ static void map_extend_boundary_surface_extend_tile(const SurfaceElement& source } /** - * Copies the terrain and slope from the edge of the map to the new tiles. Used when increasing the size of the map. - * rct2: 0x0068AC15 + * Copies the terrain and slope from the Y edge of the map to the new tiles. Used when increasing the size of the map. */ -void map_extend_boundary_surface() +void map_extend_boundary_surface_y() { - SurfaceElement *existingTileElement, *newTileElement; - int32_t x, y; - - y = gMapSize - 2; - for (x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) + auto y = gMapSize.y - 2; + for (auto x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) { - existingTileElement = map_get_surface_element_at(TileCoordsXY{ x, y - 1 }.ToCoordsXY()); - newTileElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); + auto existingTileElement = map_get_surface_element_at(TileCoordsXY{ x, y - 1 }.ToCoordsXY()); + auto newTileElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); if (existingTileElement != nullptr && newTileElement != nullptr) { @@ -1497,18 +1496,22 @@ void map_extend_boundary_surface() update_park_fences({ x << 5, y << 5 }); } +} - x = gMapSize - 2; - for (y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) +/** + * Copies the terrain and slope from the X edge of the map to the new tiles. Used when increasing the size of the map. + */ +void map_extend_boundary_surface_x() +{ + auto x = gMapSize.x - 2; + for (auto y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) { - existingTileElement = map_get_surface_element_at(TileCoordsXY{ x - 1, y }.ToCoordsXY()); - newTileElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); - + auto existingTileElement = map_get_surface_element_at(TileCoordsXY{ x - 1, y }.ToCoordsXY()); + auto newTileElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); if (existingTileElement != nullptr && newTileElement != nullptr) { map_extend_boundary_surface_extend_tile(*existingTileElement, *newTileElement); } - update_park_fences({ x << 5, y << 5 }); } } @@ -2304,3 +2307,14 @@ void FixLandOwnershipTilesWithOwnership(std::initializer_list tile } } } + +MapRange ClampRangeWithinMap(const MapRange& range) +{ + auto mapSizeMax = GetMapSizeMaxXY(); + auto aX = std::max(32, range.GetLeft()); + auto bX = std::min(mapSizeMax.x, range.GetRight()); + auto aY = std::max(32, range.GetTop()); + auto bY = std::min(mapSizeMax.y, range.GetBottom()); + MapRange validRange = MapRange{ aX, aY, bX, bY }; + return validRange; +} diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 59491ba6f1..1468aac1a6 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -99,20 +99,21 @@ extern const TileCoordsXY TileDirectionDelta[]; extern TileCoordsXY gWidePathTileLoopPosition; extern uint16_t gGrassSceneryTileLoopPosition; -extern int32_t gMapSize; +extern TileCoordsXY gMapSize; extern int32_t gMapBaseZ; -inline int32_t GetMapSizeUnits() +inline CoordsXY GetMapSizeUnits() { - return (gMapSize - 1) * COORDS_XY_STEP; + return { (gMapSize.x - 1) * COORDS_XY_STEP, (gMapSize.y - 1) * COORDS_XY_STEP }; } -inline int32_t GetMapSizeMinus2() +inline CoordsXY GetMapSizeMinus2() { - return (gMapSize * COORDS_XY_STEP) + (8 * COORDS_XY_STEP - 2); + return { (gMapSize.x * COORDS_XY_STEP) + (8 * COORDS_XY_STEP - 2), + (gMapSize.y * COORDS_XY_STEP) + (8 * COORDS_XY_STEP - 2) }; } -inline int32_t GetMapSizeMaxXY() +inline CoordsXY GetMapSizeMaxXY() { - return GetMapSizeUnits() - 1; + return GetMapSizeUnits() - CoordsXY{ 1, 1 }; } extern uint16_t gMapSelectFlags; @@ -150,7 +151,7 @@ void StashMap(); void UnstashMap(); std::vector GetReorganisedTileElementsWithoutGhosts(); -void map_init(int32_t size); +void map_init(const TileCoordsXY& size); void map_count_remaining_land_rights(); void map_strip_ghost_flag_from_elements(); @@ -216,7 +217,8 @@ int32_t map_get_highest_z(const CoordsXY& loc); bool tile_element_wants_path_connection_towards(const TileCoordsXYZD& coords, const TileElement* const elementToBeRemoved); void map_remove_out_of_range_elements(); -void map_extend_boundary_surface(); +void map_extend_boundary_surface_x(); +void map_extend_boundary_surface_y(); bool map_large_scenery_sign_set_colour(const CoordsXYZD& signPos, int32_t sequence, uint8_t mainColour, uint8_t textColour); void wall_remove_at(const CoordsXYRangedZ& wallPos); @@ -259,3 +261,4 @@ uint16_t check_max_allowable_land_rights_for_tile(const CoordsXYZ& tileMapPos); void FixLandOwnershipTiles(std::initializer_list tiles); void FixLandOwnershipTilesWithOwnership( std::initializer_list tiles, uint8_t ownership, bool doNotDowngrade = false); +MapRange ClampRangeWithinMap(const MapRange& range); diff --git a/src/openrct2/world/MapGen.cpp b/src/openrct2/world/MapGen.cpp index 8787e543db..d08004b745 100644 --- a/src/openrct2/world/MapGen.cpp +++ b/src/openrct2/world/MapGen.cpp @@ -119,7 +119,7 @@ void mapgen_generate_blank(mapgen_settings* settings) int32_t x, y; map_clear_all_elements(); - map_init(settings->mapSize); + map_init({ settings->mapSize, settings->mapSize }); for (y = 1; y < settings->mapSize - 1; y++) { for (x = 1; x < settings->mapSize - 1; x++) @@ -167,7 +167,7 @@ void mapgen_generate(mapgen_settings* settings) map_clear_all_elements(); // Initialise the base map - map_init(mapSize); + map_init({ mapSize, mapSize }); for (auto y = 1; y < mapSize - 1; y++) { for (auto x = 1; x < mapSize - 1; x++) @@ -320,9 +320,9 @@ static void mapgen_place_trees() std::vector availablePositions; // Create list of available tiles - for (int32_t y = 1; y < gMapSize - 1; y++) + for (int32_t y = 1; y < gMapSize.y - 1; y++) { - for (int32_t x = 1; x < gMapSize - 1; x++) + for (int32_t x = 1; x < gMapSize.x - 1; x++) { auto* surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); if (surfaceElement == nullptr) @@ -398,13 +398,9 @@ static void mapgen_place_trees() */ static void mapgen_set_water_level(int32_t waterLevel) { - int32_t x, y, mapSize; - - mapSize = gMapSize; - - for (y = 1; y < mapSize - 1; y++) + for (int32_t y = 1; y < gMapSize.y - 1; y++) { - for (x = 1; x < mapSize - 1; x++) + for (int32_t x = 1; x < gMapSize.x - 1; x++) { auto surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); if (surfaceElement != nullptr && surfaceElement->base_height < waterLevel) @@ -781,7 +777,8 @@ void mapgen_generate_from_heightmap(mapgen_settings* settings) // Make a copy of the original height map that we can edit auto dest = _heightMapData.mono_bitmap; - map_init(_heightMapData.width + 2); // + 2 for the black tiles around the map + auto maxSize = static_cast(_heightMapData.width + 2); // + 2 for the black tiles around the map + map_init({ maxSize, maxSize }); if (settings->smooth_height_map) {