From 81307f71dfa015a22a2f852b868d03b6e22eb50a Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Sat, 16 Mar 2019 22:04:58 +0000 Subject: [PATCH 1/7] Implement LandSmoothAction --- src/openrct2-ui/windows/TopToolbar.cpp | 26 +- .../actions/GameActionRegistration.cpp | 2 + src/openrct2/actions/LandSmoothAction.hpp | 628 ++++++++++++++++++ 3 files changed, 645 insertions(+), 11 deletions(-) create mode 100644 src/openrct2/actions/LandSmoothAction.hpp diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 6089a17b6d..a1a02ab3b9 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -2892,13 +2893,15 @@ static money32 selection_raise_land(uint8_t flags) centreX += 16; centreY += 16; - uint32_t xBounds = (gMapSelectPositionA.x & 0xFFFF) | (gMapSelectPositionB.x << 16); - uint32_t yBounds = (gMapSelectPositionA.y & 0xFFFF) | (gMapSelectPositionB.y << 16); - - gGameCommandErrorTitle = STR_CANT_RAISE_LAND_HERE; if (gLandMountainMode) { - return game_do_command(centreX, flags, centreY, xBounds, GAME_COMMAND_EDIT_LAND_SMOOTH, gMapSelectType, yBounds); + auto landSmoothAction = LandSmoothAction( + { centreX, centreY }, + { gMapSelectPositionA.x, gMapSelectPositionA.y, gMapSelectPositionB.x, gMapSelectPositionB.y }, gMapSelectType, + false); + auto res = (flags & GAME_COMMAND_FLAG_APPLY) ? GameActions::Execute(&landSmoothAction) + : GameActions::Query(&landSmoothAction); + return res->Error == GA_ERROR::OK ? res->Cost : MONEY32_UNDEFINED; } else { @@ -2923,14 +2926,15 @@ static money32 selection_lower_land(uint8_t flags) centreX += 16; centreY += 16; - uint32_t xBounds = (gMapSelectPositionA.x & 0xFFFF) | (gMapSelectPositionB.x << 16); - uint32_t yBounds = (gMapSelectPositionA.y & 0xFFFF) | (gMapSelectPositionB.y << 16); - - gGameCommandErrorTitle = STR_CANT_LOWER_LAND_HERE; if (gLandMountainMode) { - return game_do_command( - centreX, flags, centreY, xBounds, GAME_COMMAND_EDIT_LAND_SMOOTH, 0x8000 + gMapSelectType, yBounds); + auto landSmoothAction = LandSmoothAction( + { centreX, centreY }, + { gMapSelectPositionA.x, gMapSelectPositionA.y, gMapSelectPositionB.x, gMapSelectPositionB.y }, gMapSelectType, + true); + auto res = (flags & GAME_COMMAND_FLAG_APPLY) ? GameActions::Execute(&landSmoothAction) + : GameActions::Query(&landSmoothAction); + return res->Error == GA_ERROR::OK ? res->Cost : MONEY32_UNDEFINED; } else { diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index 170ec89a32..f13264d1d8 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -21,6 +21,7 @@ #include "LandLowerAction.hpp" #include "LandRaiseAction.hpp" #include "LandSetHeightAction.hpp" +#include "LandSmoothAction.hpp" #include "LargeSceneryRemoveAction.hpp" #include "LoadOrQuitAction.hpp" #include "MazeSetTrackAction.hpp" @@ -115,6 +116,7 @@ namespace GameActions Register(); Register(); Register(); + Register(); Register(); Register(); Register(); diff --git a/src/openrct2/actions/LandSmoothAction.hpp b/src/openrct2/actions/LandSmoothAction.hpp new file mode 100644 index 0000000000..d96b35f512 --- /dev/null +++ b/src/openrct2/actions/LandSmoothAction.hpp @@ -0,0 +1,628 @@ +/***************************************************************************** + * Copyright (c) 2014-2019 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandSetHeightAction.hpp" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(LandSmoothAction, GAME_COMMAND_EDIT_LAND_SMOOTH, GameActionResult) +{ +private: + CoordsXY _coords; + MapRange _range; + uint8_t _selectionType; + bool _isLowering; + + constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_LOWER_LAND_HERE, STR_CANT_RAISE_LAND_HERE }; + +public: + LandSmoothAction() + { + } + LandSmoothAction(CoordsXY coords, MapRange range, uint8_t selectionType, bool isLowering) + : _coords(coords) + , _range(range) + , _selectionType(selectionType) + , _isLowering(isLowering) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override + { + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType) << DS_TAG(_isLowering); + } + + GameActionResult::Ptr Query() const override + { + return smooth_land(false); + } + + GameActionResult::Ptr Execute() const override + { + return smooth_land(true); + } + +private: + GameActionResult::Ptr QueryExecute(bool isExecuting) const + { + auto res = MakeResult(); + + return res; + } + + money32 smooth_land_tile( + int32_t direction, bool isExecuting, int32_t x, int32_t y, TileElement * tileElement) const + { + int32_t targetBaseZ = tileElement->base_height; + int32_t slope = tileElement->AsSurface()->GetSlope(); + if (_isLowering) + { + slope = tile_element_lower_styles[direction][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ -= 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + else + { + slope = tile_element_raise_styles[direction][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ += 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + + auto landSetHeightAction = LandSetHeightAction({ x, y }, targetBaseZ, slope); + landSetHeightAction.SetFlags(GetFlags()); + auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) + : GameActions::QueryNested(&landSetHeightAction); + + if (res->Error == GA_ERROR::OK) + { + return res->Cost; + } + else + { + return MONEY32_UNDEFINED; + } + } + + money32 smooth_land_row_by_edge( + bool isExecuting, int32_t x, int32_t y, int32_t expectedLandHeight1, int32_t expectedLandHeight2, int32_t stepX, + int32_t stepY, int32_t direction1, int32_t direction2, int32_t checkDirection1, int32_t checkDirection2) const + { + uint8_t shouldContinue = 0xF; + int32_t landChangePerTile = _isLowering ? 2 : -2; + TileElement *tileElement, *nextTileElement; + money32 totalCost = 0; + + // check if we need to start at all + if (!map_is_location_valid({ x, y }) || !map_is_location_valid({ x + stepX, y + stepY })) + { + return 0; + } + tileElement = map_get_surface_element_at({ x, y }); + nextTileElement = map_get_surface_element_at({ x + stepX, y + stepY }); + if (tileElement == nullptr || nextTileElement == nullptr) + { + return 0; + } + if (tile_element_get_corner_height(tileElement, checkDirection1) != expectedLandHeight1 + landChangePerTile) + { + shouldContinue &= ~0x1; + } + if (tile_element_get_corner_height(tileElement, checkDirection2) != expectedLandHeight2 + landChangePerTile) + { + shouldContinue &= ~0x2; + } + if (tile_element_get_corner_height(tileElement, checkDirection1) + != tile_element_get_corner_height(nextTileElement, direction1)) + { + shouldContinue &= ~0x1; + } + if (tile_element_get_corner_height(tileElement, checkDirection2) + != tile_element_get_corner_height(nextTileElement, direction2)) + { + shouldContinue &= ~0x2; + } + while ((shouldContinue & 0x3) != 0) + { + shouldContinue = ((shouldContinue << 2) | 0x3) & shouldContinue; + x += stepX; + y += stepY; + // check if we need to continue after raising the current tile + // this needs to be checked before the tile is changed + if (!map_is_location_valid({ x + stepX, y + stepY })) + { + shouldContinue &= ~0x3; + } + else + { + tileElement = nextTileElement; + nextTileElement = map_get_surface_element_at({ x + stepX, y + stepY }); + if (nextTileElement == nullptr) + { + shouldContinue &= ~0x3; + } + if (tile_element_get_corner_height(tileElement, direction1) + landChangePerTile + != tile_element_get_corner_height(tileElement, checkDirection1)) + { + shouldContinue &= ~0x1; + } + if (tile_element_get_corner_height(tileElement, direction2) + landChangePerTile + != tile_element_get_corner_height(tileElement, checkDirection2)) + { + shouldContinue &= ~0x2; + } + if ((shouldContinue & 0x1) + && tile_element_get_corner_height(tileElement, checkDirection1) + != tile_element_get_corner_height(nextTileElement, direction1)) + { + shouldContinue &= ~0x1; + } + if ((shouldContinue & 0x2) + && tile_element_get_corner_height(tileElement, checkDirection2) + != tile_element_get_corner_height(nextTileElement, direction2)) + { + shouldContinue &= ~0x2; + } + } + expectedLandHeight1 += landChangePerTile; + + // change land of current tile + int32_t targetBaseZ = tileElement->base_height; + int32_t slope = tileElement->AsSurface()->GetSlope(); + int32_t oldSlope = slope; + if (_isLowering) + { + if (shouldContinue & 0x4) + { + slope = tile_element_lower_styles[direction1][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ -= 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + if ((shouldContinue & 0x8) + && map_get_corner_height(tileElement->base_height, oldSlope, direction2) + == map_get_corner_height(targetBaseZ, slope, direction2)) + { + slope = tile_element_lower_styles[direction2][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ -= 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + } + else + { + if (shouldContinue & 0x4) + { + slope = tile_element_raise_styles[direction1][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ += 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + if ((shouldContinue & 0x8) + && map_get_corner_height(tileElement->base_height, oldSlope, direction2) + == map_get_corner_height(targetBaseZ, slope, direction2)) + { + slope = tile_element_raise_styles[direction2][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ += 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + } + auto landSetHeightAction = LandSetHeightAction({ x, y }, targetBaseZ, slope); + landSetHeightAction.SetFlags(GetFlags()); + auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) + : GameActions::QueryNested(&landSetHeightAction); + if (res->Error == GA_ERROR::OK) + { + totalCost += res->Cost; + } + } + return totalCost; + } + + money32 smooth_land_row_by_corner( + bool isExecuting, int32_t x, int32_t y, int32_t expectedLandHeight, int32_t stepX, int32_t stepY, int32_t direction, + int32_t checkDirection) const + { + bool shouldContinue = true; + TileElement *tileElement, *nextTileElement; + money32 totalCost = 0; + money32 result; + int32_t landChangePerTile; + if (stepX == 0 || stepY == 0) + { + landChangePerTile = _isLowering ? 2 : -2; + } + else + { + landChangePerTile = _isLowering ? 4 : -4; + } + + // check if we need to start at all + if (!map_is_location_valid({ x, y }) || !map_is_location_valid({ x + stepX, y + stepY })) + { + return 0; + } + tileElement = map_get_surface_element_at({ x, y }); + nextTileElement = map_get_surface_element_at((x + stepX) >> 5, (y + stepY) >> 5); + if (tileElement == nullptr || nextTileElement == nullptr) + { + return 0; + } + if (tile_element_get_corner_height(tileElement, checkDirection) != expectedLandHeight + (_isLowering ? 2 : -2)) + { + return 0; + } + if (tile_element_get_corner_height(tileElement, checkDirection) + != tile_element_get_corner_height(nextTileElement, direction)) + { + return 0; + } + while (shouldContinue) + { + x += stepX; + y += stepY; + // check if we need to continue after raising the current tile + // this needs to be checked before the tile is changed + if (!map_is_location_valid({ x + stepX, y + stepY })) + { + shouldContinue = false; + } + else + { + tileElement = nextTileElement; + nextTileElement = map_get_surface_element_at((x + stepX) >> 5, (y + stepY) >> 5); + if (nextTileElement == nullptr) + { + shouldContinue = false; + } + if (tile_element_get_corner_height(tileElement, direction) + landChangePerTile + != tile_element_get_corner_height(tileElement, checkDirection)) + { + shouldContinue = false; + } + if (shouldContinue + && tile_element_get_corner_height(tileElement, checkDirection) + != tile_element_get_corner_height(nextTileElement, direction)) + { + shouldContinue = false; + } + } + if (stepX * stepY != 0) + { + totalCost += smooth_land_row_by_corner( + isExecuting, x, y, expectedLandHeight + (landChangePerTile / 2), 0, stepY, direction, checkDirection ^ 3 + ); + totalCost += smooth_land_row_by_corner( + isExecuting, x, y, expectedLandHeight + (landChangePerTile / 2), stepX, 0, direction, checkDirection ^ 1 + ); + } + expectedLandHeight += landChangePerTile; + // change land of current tile + result = smooth_land_tile(direction, isExecuting, x, y, tileElement); + if (result != MONEY32_UNDEFINED) + { + totalCost += result; + } + } + return totalCost; + } + + GameActionResult::Ptr smooth_land(bool isExecuting) const + { + // break up information in command + const bool raiseLand = !_isLowering; + const int32_t selectionType = _selectionType; + const int32_t heightOffset = raiseLand ? 2 : -2; + + auto normRange = _range.Normalise(); + // Cap bounds to map + auto l = std::max(normRange.GetLeft(), 32); + auto t = std::max(normRange.GetTop(), 32); + auto r = std::clamp(normRange.GetRight(), 0, (MAXIMUM_MAP_SIZE_TECHNICAL - 1) * 32); + auto b = std::clamp(normRange.GetBottom(), 0, (MAXIMUM_MAP_SIZE_TECHNICAL - 1) * 32); + auto validRange = MapRange{ l, t, r, b }; + + // Play sound (only once) + int32_t centreZ = tile_element_height(_coords.x, _coords.y) & 0xFFFF; + + + auto res = MakeResult(); + res->ErrorTitle = _ErrorTitles[_isLowering ? 0 : 1]; + res->Position = { _coords.x, _coords.y, centreZ }; + + // Do the smoothing + switch (selectionType) + { + case MAP_SELECT_TYPE_FULL: + { + uint8_t minHeight = heightOffset + map_get_lowest_land_height(validRange.GetLeft(), validRange.GetRight(), validRange.GetTop(), validRange.GetBottom()); + uint8_t maxHeight = heightOffset + + map_get_highest_land_height( + validRange.GetLeft(), validRange.GetRight(), validRange.GetTop(), + validRange.GetBottom()); + + // Smooth the 4 corners + { // top-left + TileElement* tileElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetTop() }); + int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 2), minHeight, maxHeight); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); + } + { // bottom-left + TileElement* tileElement = map_get_surface_element_at( + { validRange.GetLeft(), validRange.GetBottom() }); + int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 3), minHeight, maxHeight); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetBottom(), z, -32, 32, 1, 3); + } + { // bottom-right + TileElement* tileElement = map_get_surface_element_at( + { validRange.GetRight(), validRange.GetBottom() } ); + int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 0), minHeight, maxHeight); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetRight(), validRange.GetBottom(), z, 32, 32, 2, 0); + } + { // top-right + TileElement* tileElement = map_get_surface_element_at({ validRange.GetRight(), validRange.GetTop() }); + int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 1), minHeight, maxHeight); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetRight(), validRange.GetTop(), z, 32, -32, 3, 1); + } + + // Smooth the edges + TileElement* tileElement = nullptr; + int32_t z1, z2; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += 32) + { + tileElement = map_get_surface_element_at({ validRange.GetLeft(), y }); + z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 3), minHeight, maxHeight); + z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 2), minHeight, maxHeight); + res->Cost += smooth_land_row_by_edge(isExecuting, validRange.GetLeft(), y, z1, z2, -32, 0, 0, 1, 3, 2); + + tileElement = map_get_surface_element_at({ validRange.GetRight(), y }); + z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 1), minHeight, maxHeight); + z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 0), minHeight, maxHeight); + res->Cost += smooth_land_row_by_edge(isExecuting, validRange.GetRight(), y, z1, z2, 32, 0, 2, 3, 1, 0); + } + + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += 32) + { + tileElement = map_get_surface_element_at({ x, validRange.GetTop() }); + z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 1), minHeight, maxHeight); + z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 2), minHeight, maxHeight); + res->Cost += smooth_land_row_by_edge(isExecuting, x, validRange.GetTop(), z1, z2, 0, -32, 0, 3, 1, 2); + + tileElement = map_get_surface_element_at({ x, validRange.GetBottom() }); + z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 0), minHeight, maxHeight); + z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 3), minHeight, maxHeight); + res->Cost += smooth_land_row_by_edge(isExecuting, x, validRange.GetBottom(), z1, z2, 0, 32, 1, 2, 0, 3); + } + break; + } + case MAP_SELECT_TYPE_CORNER_0: + case MAP_SELECT_TYPE_CORNER_1: + case MAP_SELECT_TYPE_CORNER_2: + case MAP_SELECT_TYPE_CORNER_3: + { + TileElement* tileElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetTop() }); + uint8_t newBaseZ = tileElement->base_height; + uint8_t newSlope = tileElement->AsSurface()->GetSlope(); + + if (raiseLand) + { + newSlope = tile_element_raise_styles[selectionType][newSlope]; + } + else + { + newSlope = tile_element_lower_styles[selectionType][newSlope]; + } + + if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + newBaseZ += heightOffset; + newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + + // Smooth the corners + int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 32, 2, 0); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 32, 1, 3); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, -32, 3, 1); + + // Smooth the edges + switch (selectionType) + { + case MAP_SELECT_TYPE_CORNER_0: + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 3, 0); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 1, 0); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 0, 3); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 0, 1); + break; + case MAP_SELECT_TYPE_CORNER_1: + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 2, 1); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 0, 1); + z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 1, 2); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 1, 0); + break; + case MAP_SELECT_TYPE_CORNER_2: + z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 1, 2); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 3, 2); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 2, 1); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 2, 3); + break; + case MAP_SELECT_TYPE_CORNER_3: + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 0, 3); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 2, 3); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 3, 0); + z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 3, 2); + break; + } + break; + } + case MAP_SELECT_TYPE_EDGE_0: + case MAP_SELECT_TYPE_EDGE_1: + case MAP_SELECT_TYPE_EDGE_2: + case MAP_SELECT_TYPE_EDGE_3: + { + // TODO: Handle smoothing by edge + // Get the two corners to raise + TileElement* surfaceElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetTop() }); + uint8_t newBaseZ = surfaceElement->base_height; + uint8_t oldSlope = surfaceElement->AsSurface()->GetSlope(); + uint8_t newSlope = oldSlope; + int32_t rowIndex = selectionType - (MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1); + + if (raiseLand) + { + newSlope = tile_element_raise_styles[rowIndex][oldSlope]; + } + else + { + newSlope = tile_element_lower_styles[rowIndex][oldSlope]; + } + + const bool changeBaseHeight = newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + if (changeBaseHeight) + { + newBaseZ += heightOffset; + newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + + const uint8_t edge = selectionType - MAP_SELECT_TYPE_EDGE_0; + + // Table with corners for each edge selection. The first two are the selected corners, the latter two are the + // opposites + static constexpr uint8_t cornerIndices[][4] = { + { 2, 3, 1, 0 }, // MAP_SELECT_TYPE_EDGE_0 + { 3, 0, 2, 1 }, // MAP_SELECT_TYPE_EDGE_1 + { 0, 1, 3, 2 }, // MAP_SELECT_TYPE_EDGE_2 + { 1, 2, 0, 3 }, // MAP_SELECT_TYPE_EDGE_3 + }; + // Big coordinate offsets for the neigbouring tile for the given edge selection + static constexpr sLocationXY8 stepOffsets[] = { + { -32, 0 }, + { 0, 32 }, + { 32, 0 }, + { 0, -32 }, + }; + + // Smooth higher and lower edges + uint8_t c1 = cornerIndices[edge][0]; + uint8_t c2 = cornerIndices[edge][1]; + uint8_t c3 = cornerIndices[edge][2]; + uint8_t c4 = cornerIndices[edge][3]; + uint8_t z1 = map_get_corner_height(newBaseZ, newSlope, c1); + uint8_t z2 = map_get_corner_height(newBaseZ, newSlope, c2); + uint8_t z3 = map_get_corner_height(newBaseZ, newSlope, c3); + uint8_t z4 = map_get_corner_height(newBaseZ, newSlope, c4); + // Smooth the edge at the top of the new slope + res->Cost += smooth_land_row_by_edge( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z1, z2, stepOffsets[edge].x, stepOffsets[edge].y, c3, c4, c1, c2); + // Smooth the edge at the bottom of the new slope + res->Cost += smooth_land_row_by_edge( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z3, z4, -stepOffsets[edge].x, -stepOffsets[edge].y, c1, c2, c3, c4); + + // Smooth corners + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z1, -stepOffsets[edge].y, stepOffsets[edge].x, c2, c1); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z2, stepOffsets[edge].y, -stepOffsets[edge].x, c1, c2); + int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 32, 2, 0); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 32, 1, 3); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, -32, 3, 1); + break; + } + } // switch selectionType + + // Raise / lower the land tool selection area + GameActionResult::Ptr result; + if (raiseLand) + { + auto raiseLandAction = LandRaiseAction( + { _coords.x, _coords.y }, validRange, selectionType); + raiseLandAction.SetFlags(GetFlags()); + result = isExecuting ? GameActions::ExecuteNested(&raiseLandAction) + : GameActions::QueryNested(&raiseLandAction); + } + else + { + auto lowerLandAction = LandLowerAction({ _coords.x, _coords.y }, validRange, selectionType); + lowerLandAction.SetFlags(GetFlags()); + result = isExecuting ? GameActions::ExecuteNested(&lowerLandAction) + : GameActions::QueryNested(&lowerLandAction); + } + if (result->Error != GA_ERROR::OK) + { + return result; + } + + if (isExecuting) + { + audio_play_sound_at_location(SOUND_PLACE_ITEM, _coords.x, _coords.y, centreZ); + } + res->Cost += res->Cost; + + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + + return res; + } +}; From 227786e05b59920859466dd49f6fdec5247a6efc Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Sat, 16 Mar 2019 22:16:56 +0000 Subject: [PATCH 2/7] Remove game command --- src/openrct2/Game.cpp | 2 +- src/openrct2/Game.h | 20 +- src/openrct2/world/Map.cpp | 565 ------------------------------------- src/openrct2/world/Map.h | 1 - 4 files changed, 11 insertions(+), 577 deletions(-) diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 3a0da405de..996f430970 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -1268,7 +1268,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = { game_command_set_staff_name, nullptr, nullptr, - game_command_smooth_land, + nullptr, nullptr, nullptr, nullptr, diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index f62bf9e9d1..b944b2a875 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -44,16 +44,16 @@ enum GAME_COMMAND GAME_COMMAND_SET_STAFF_NAME, // GA GAME_COMMAND_RAISE_LAND, // GA GAME_COMMAND_LOWER_LAND, // GA - GAME_COMMAND_EDIT_LAND_SMOOTH, - GAME_COMMAND_RAISE_WATER, // GA - GAME_COMMAND_LOWER_WATER, // GA - GAME_COMMAND_SET_BRAKES_SPEED, // GA - GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, // GA - GAME_COMMAND_SET_STAFF_PATROL, // GA - GAME_COMMAND_FIRE_STAFF_MEMBER, // GA - GAME_COMMAND_SET_STAFF_ORDERS, // GA - GAME_COMMAND_SET_PARK_NAME, // GA - GAME_COMMAND_SET_PARK_OPEN, // GA + GAME_COMMAND_EDIT_LAND_SMOOTH, // GA + GAME_COMMAND_RAISE_WATER, // GA + GAME_COMMAND_LOWER_WATER, // GA + GAME_COMMAND_SET_BRAKES_SPEED, // GA + GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, // GA + GAME_COMMAND_SET_STAFF_PATROL, // GA + GAME_COMMAND_FIRE_STAFF_MEMBER, // GA + GAME_COMMAND_SET_STAFF_ORDERS, // GA + GAME_COMMAND_SET_PARK_NAME, // GA + GAME_COMMAND_SET_PARK_OPEN, // GA GAME_COMMAND_BUY_LAND_RIGHTS, GAME_COMMAND_PLACE_PARK_ENTRANCE, // GA GAME_COMMAND_REMOVE_PARK_ENTRANCE, // GA diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 94c090c140..3d39d6e68c 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -1080,571 +1080,6 @@ uint8_t map_get_highest_land_height(int32_t xMin, int32_t xMax, int32_t yMin, in return max_height; } -static money32 smooth_land_tile( - int32_t direction, uint8_t flags, int32_t x, int32_t y, TileElement* tileElement, bool raiseLand) -{ - int32_t targetBaseZ = tileElement->base_height; - int32_t slope = tileElement->AsSurface()->GetSlope(); - if (raiseLand) - { - slope = tile_element_raise_styles[direction][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ += 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - else - { - slope = tile_element_lower_styles[direction][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ -= 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - - auto landSetHeightAction = LandSetHeightAction({ x, y }, targetBaseZ, slope); - landSetHeightAction.SetFlags(flags); - auto res = (flags & GAME_COMMAND_FLAG_APPLY) ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); - - if (res->Error == GA_ERROR::OK) - { - return res->Cost; - } - else - { - return MONEY32_UNDEFINED; - } -} - -static money32 smooth_land_row_by_edge( - int32_t flags, int32_t x, int32_t y, int32_t expectedLandHeight1, int32_t expectedLandHeight2, int32_t stepX, int32_t stepY, - int32_t direction1, int32_t direction2, int32_t checkDirection1, int32_t checkDirection2, bool raiseLand) -{ - uint8_t shouldContinue = 0xF; - int32_t landChangePerTile = raiseLand ? -2 : 2; - TileElement *tileElement, *nextTileElement; - money32 totalCost = 0; - - // check if we need to start at all - if (!map_is_location_valid({ x, y }) || !map_is_location_valid({ x + stepX, y + stepY })) - { - return 0; - } - tileElement = map_get_surface_element_at({ x, y }); - nextTileElement = map_get_surface_element_at({ x + stepX, y + stepY }); - if (tileElement == nullptr || nextTileElement == nullptr) - { - return 0; - } - if (tile_element_get_corner_height(tileElement, checkDirection1) != expectedLandHeight1 + (raiseLand ? -2 : 2)) - { - shouldContinue &= ~0x1; - } - if (tile_element_get_corner_height(tileElement, checkDirection2) != expectedLandHeight2 + (raiseLand ? -2 : 2)) - { - shouldContinue &= ~0x2; - } - if (tile_element_get_corner_height(tileElement, checkDirection1) - != tile_element_get_corner_height(nextTileElement, direction1)) - { - shouldContinue &= ~0x1; - } - if (tile_element_get_corner_height(tileElement, checkDirection2) - != tile_element_get_corner_height(nextTileElement, direction2)) - { - shouldContinue &= ~0x2; - } - while ((shouldContinue & 0x3) != 0) - { - shouldContinue = ((shouldContinue << 2) | 0x3) & shouldContinue; - x += stepX; - y += stepY; - // check if we need to continue after raising the current tile - // this needs to be checked before the tile is changed - if (!map_is_location_valid({ x + stepX, y + stepY })) - { - shouldContinue &= ~0x3; - } - else - { - tileElement = nextTileElement; - nextTileElement = map_get_surface_element_at({ x + stepX, y + stepY }); - if (nextTileElement == nullptr) - { - shouldContinue &= ~0x3; - } - if (tile_element_get_corner_height(tileElement, direction1) + landChangePerTile - != tile_element_get_corner_height(tileElement, checkDirection1)) - { - shouldContinue &= ~0x1; - } - if (tile_element_get_corner_height(tileElement, direction2) + landChangePerTile - != tile_element_get_corner_height(tileElement, checkDirection2)) - { - shouldContinue &= ~0x2; - } - if ((shouldContinue & 0x1) - && tile_element_get_corner_height(tileElement, checkDirection1) - != tile_element_get_corner_height(nextTileElement, direction1)) - { - shouldContinue &= ~0x1; - } - if ((shouldContinue & 0x2) - && tile_element_get_corner_height(tileElement, checkDirection2) - != tile_element_get_corner_height(nextTileElement, direction2)) - { - shouldContinue &= ~0x2; - } - } - expectedLandHeight1 += landChangePerTile; - - // change land of current tile - int32_t targetBaseZ = tileElement->base_height; - int32_t slope = tileElement->AsSurface()->GetSlope(); - int32_t oldSlope = slope; - if (raiseLand) - { - if (shouldContinue & 0x4) - { - slope = tile_element_raise_styles[direction1][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ += 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - if ((shouldContinue & 0x8) - && map_get_corner_height(tileElement->base_height, oldSlope, direction2) - == map_get_corner_height(targetBaseZ, slope, direction2)) - { - slope = tile_element_raise_styles[direction2][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ += 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - } - else - { - if (shouldContinue & 0x4) - { - slope = tile_element_lower_styles[direction1][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ -= 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - if ((shouldContinue & 0x8) - && map_get_corner_height(tileElement->base_height, oldSlope, direction2) - == map_get_corner_height(targetBaseZ, slope, direction2)) - { - slope = tile_element_lower_styles[direction2][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ -= 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - } - auto landSetHeightAction = LandSetHeightAction({ x, y }, targetBaseZ, slope); - landSetHeightAction.SetFlags(flags); - auto res = (flags & GAME_COMMAND_FLAG_APPLY) ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); - if (res->Error == GA_ERROR::OK) - { - totalCost += res->Cost; - } - } - return totalCost; -} - -static money32 smooth_land_row_by_corner( - int32_t flags, int32_t x, int32_t y, int32_t expectedLandHeight, int32_t stepX, int32_t stepY, int32_t direction, - int32_t checkDirection, bool raiseLand) -{ - bool shouldContinue = true; - TileElement *tileElement, *nextTileElement; - money32 totalCost = 0; - money32 result; - int32_t landChangePerTile; - if (stepX == 0 || stepY == 0) - { - landChangePerTile = raiseLand ? -2 : 2; - } - else - { - landChangePerTile = raiseLand ? -4 : 4; - } - - // check if we need to start at all - if (!map_is_location_valid({ x, y }) || !map_is_location_valid({ x + stepX, y + stepY })) - { - return 0; - } - tileElement = map_get_surface_element_at({ x, y }); - nextTileElement = map_get_surface_element_at((x + stepX) >> 5, (y + stepY) >> 5); - if (tileElement == nullptr || nextTileElement == nullptr) - { - return 0; - } - if (tile_element_get_corner_height(tileElement, checkDirection) != expectedLandHeight + (raiseLand ? -2 : 2)) - { - return 0; - } - if (tile_element_get_corner_height(tileElement, checkDirection) - != tile_element_get_corner_height(nextTileElement, direction)) - { - return 0; - } - while (shouldContinue) - { - x += stepX; - y += stepY; - // check if we need to continue after raising the current tile - // this needs to be checked before the tile is changed - if (!map_is_location_valid({ x + stepX, y + stepY })) - { - shouldContinue = false; - } - else - { - tileElement = nextTileElement; - nextTileElement = map_get_surface_element_at((x + stepX) >> 5, (y + stepY) >> 5); - if (nextTileElement == nullptr) - { - shouldContinue = false; - } - if (tile_element_get_corner_height(tileElement, direction) + landChangePerTile - != tile_element_get_corner_height(tileElement, checkDirection)) - { - shouldContinue = false; - } - if (shouldContinue - && tile_element_get_corner_height(tileElement, checkDirection) - != tile_element_get_corner_height(nextTileElement, direction)) - { - shouldContinue = false; - } - } - if (stepX * stepY != 0) - { - totalCost += smooth_land_row_by_corner( - flags, x, y, expectedLandHeight + (landChangePerTile / 2), 0, stepY, direction, checkDirection ^ 3, raiseLand); - totalCost += smooth_land_row_by_corner( - flags, x, y, expectedLandHeight + (landChangePerTile / 2), stepX, 0, direction, checkDirection ^ 1, raiseLand); - } - expectedLandHeight += landChangePerTile; - // change land of current tile - result = smooth_land_tile(direction, flags, x, y, tileElement, raiseLand); - if (result != MONEY32_UNDEFINED) - { - totalCost += result; - } - } - return totalCost; -} - -static money32 smooth_land( - int32_t flags, int32_t centreX, int32_t centreY, int32_t mapLeft, int32_t mapTop, int32_t mapRight, int32_t mapBottom, - int32_t command) -{ - // break up information in command - const bool raiseLand = command < 0x7FFF; - const int32_t selectionType = command & 0x7FFF; - const int32_t heightOffset = raiseLand ? 2 : -2; - - // Cap bounds to map - mapLeft = std::max(mapLeft, 32); - mapTop = std::max(mapTop, 32); - mapRight = std::clamp(mapRight, 0, (MAXIMUM_MAP_SIZE_TECHNICAL - 1) * 32); - mapBottom = std::clamp(mapBottom, 0, (MAXIMUM_MAP_SIZE_TECHNICAL - 1) * 32); - - // Play sound (only once) - int32_t centreZ = tile_element_height(centreX, centreY); - if ((flags & GAME_COMMAND_FLAG_APPLY) && gGameCommandNestLevel == 1) - { - audio_play_sound_at_location(SOUND_PLACE_ITEM, centreX, centreY, centreZ); - } - - if (flags & GAME_COMMAND_FLAG_APPLY) - { - LocationXYZ16 coord; - coord.x = centreX + 16; - coord.y = centreY + 16; - coord.z = tile_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - } - - // Do the smoothing - money32 totalCost = 0; - switch (selectionType) - { - case MAP_SELECT_TYPE_FULL: - { - uint8_t minHeight = heightOffset + map_get_lowest_land_height(mapLeft, mapRight, mapTop, mapBottom); - uint8_t maxHeight = heightOffset + map_get_highest_land_height(mapLeft, mapRight, mapTop, mapBottom); - - // Smooth the 4 corners - { // top-left - TileElement* tileElement = map_get_surface_element_at({ mapLeft, mapTop }); - int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 2), minHeight, maxHeight); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, -32, -32, 0, 2, raiseLand); - } - { // bottom-left - TileElement* tileElement = map_get_surface_element_at(mapLeft >> 5, mapBottom >> 5); - int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 3), minHeight, maxHeight); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapBottom, z, -32, 32, 1, 3, raiseLand); - } - { // bottom-right - TileElement* tileElement = map_get_surface_element_at(mapRight >> 5, mapBottom >> 5); - int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 0), minHeight, maxHeight); - totalCost += smooth_land_row_by_corner(flags, mapRight, mapBottom, z, 32, 32, 2, 0, raiseLand); - } - { // top-right - TileElement* tileElement = map_get_surface_element_at(mapRight >> 5, mapTop >> 5); - int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 1), minHeight, maxHeight); - totalCost += smooth_land_row_by_corner(flags, mapRight, mapTop, z, 32, -32, 3, 1, raiseLand); - } - - // Smooth the edges - TileElement* tileElement = nullptr; - int32_t z1, z2; - for (int32_t y = mapTop; y <= mapBottom; y += 32) - { - tileElement = map_get_surface_element_at({ mapLeft, y }); - z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 3), minHeight, maxHeight); - z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 2), minHeight, maxHeight); - totalCost += smooth_land_row_by_edge(flags, mapLeft, y, z1, z2, -32, 0, 0, 1, 3, 2, raiseLand); - - tileElement = map_get_surface_element_at({ mapRight, y }); - z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 1), minHeight, maxHeight); - z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 0), minHeight, maxHeight); - totalCost += smooth_land_row_by_edge(flags, mapRight, y, z1, z2, 32, 0, 2, 3, 1, 0, raiseLand); - } - - for (int32_t x = mapLeft; x <= mapRight; x += 32) - { - tileElement = map_get_surface_element_at({ x, mapTop }); - z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 1), minHeight, maxHeight); - z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 2), minHeight, maxHeight); - totalCost += smooth_land_row_by_edge(flags, x, mapTop, z1, z2, 0, -32, 0, 3, 1, 2, raiseLand); - - tileElement = map_get_surface_element_at({ x, mapBottom }); - z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 0), minHeight, maxHeight); - z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 3), minHeight, maxHeight); - totalCost += smooth_land_row_by_edge(flags, x, mapBottom, z1, z2, 0, 32, 1, 2, 0, 3, raiseLand); - } - break; - } - case MAP_SELECT_TYPE_CORNER_0: - case MAP_SELECT_TYPE_CORNER_1: - case MAP_SELECT_TYPE_CORNER_2: - case MAP_SELECT_TYPE_CORNER_3: - { - TileElement* tileElement = map_get_surface_element_at({ mapLeft, mapTop }); - uint8_t newBaseZ = tileElement->base_height; - uint8_t newSlope = tileElement->AsSurface()->GetSlope(); - - if (raiseLand) - { - newSlope = tile_element_raise_styles[selectionType][newSlope]; - } - else - { - newSlope = tile_element_lower_styles[selectionType][newSlope]; - } - - if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - newBaseZ += heightOffset; - newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - - // Smooth the corners - int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, -32, -32, 0, 2, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 0); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 32, 32, 2, 0, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 3); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, -32, 32, 1, 3, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 1); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 32, -32, 3, 1, raiseLand); - - // Smooth the edges - switch (selectionType) - { - case MAP_SELECT_TYPE_CORNER_0: - z = map_get_corner_height(newBaseZ, newSlope, 0); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 32, 0, 3, 0, raiseLand); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 0, 32, 1, 0, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 3); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, -32, 0, 0, 3, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 1); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 0, -32, 0, 1, raiseLand); - break; - case MAP_SELECT_TYPE_CORNER_1: - z = map_get_corner_height(newBaseZ, newSlope, 1); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 32, 0, 2, 1, raiseLand); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 0, -32, 0, 1, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 2); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, -32, 0, 1, 2, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 0); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 0, 32, 1, 0, raiseLand); - break; - case MAP_SELECT_TYPE_CORNER_2: - z = map_get_corner_height(newBaseZ, newSlope, 2); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, -32, 0, 1, 2, raiseLand); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 0, -32, 3, 2, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 1); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 32, 0, 2, 1, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 3); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 0, 32, 2, 3, raiseLand); - break; - case MAP_SELECT_TYPE_CORNER_3: - z = map_get_corner_height(newBaseZ, newSlope, 3); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, -32, 0, 0, 3, raiseLand); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 0, 32, 2, 3, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 0); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 32, 0, 3, 0, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 2); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 0, -32, 3, 2, raiseLand); - break; - } - break; - } - case MAP_SELECT_TYPE_EDGE_0: - case MAP_SELECT_TYPE_EDGE_1: - case MAP_SELECT_TYPE_EDGE_2: - case MAP_SELECT_TYPE_EDGE_3: - { - // TODO: Handle smoothing by edge - // Get the two corners to raise - TileElement* surfaceElement = map_get_surface_element_at({ mapLeft, mapTop }); - uint8_t newBaseZ = surfaceElement->base_height; - uint8_t oldSlope = surfaceElement->AsSurface()->GetSlope(); - uint8_t newSlope = oldSlope; - int32_t rowIndex = selectionType - (MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1); - - if (raiseLand) - { - newSlope = tile_element_raise_styles[rowIndex][oldSlope]; - } - else - { - newSlope = tile_element_lower_styles[rowIndex][oldSlope]; - } - - const bool changeBaseHeight = newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - if (changeBaseHeight) - { - newBaseZ += heightOffset; - newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - - const uint8_t edge = selectionType - MAP_SELECT_TYPE_EDGE_0; - - // Table with corners for each edge selection. The first two are the selected corners, the latter two are the - // opposites - static constexpr uint8_t cornerIndices[][4] = { - { 2, 3, 1, 0 }, // MAP_SELECT_TYPE_EDGE_0 - { 3, 0, 2, 1 }, // MAP_SELECT_TYPE_EDGE_1 - { 0, 1, 3, 2 }, // MAP_SELECT_TYPE_EDGE_2 - { 1, 2, 0, 3 }, // MAP_SELECT_TYPE_EDGE_3 - }; - // Big coordinate offsets for the neigbouring tile for the given edge selection - static constexpr sLocationXY8 stepOffsets[] = { - { -32, 0 }, - { 0, 32 }, - { 32, 0 }, - { 0, -32 }, - }; - - // Smooth higher and lower edges - uint8_t c1 = cornerIndices[edge][0]; - uint8_t c2 = cornerIndices[edge][1]; - uint8_t c3 = cornerIndices[edge][2]; - uint8_t c4 = cornerIndices[edge][3]; - uint8_t z1 = map_get_corner_height(newBaseZ, newSlope, c1); - uint8_t z2 = map_get_corner_height(newBaseZ, newSlope, c2); - uint8_t z3 = map_get_corner_height(newBaseZ, newSlope, c3); - uint8_t z4 = map_get_corner_height(newBaseZ, newSlope, c4); - // Smooth the edge at the top of the new slope - totalCost += smooth_land_row_by_edge( - flags, mapLeft, mapTop, z1, z2, stepOffsets[edge].x, stepOffsets[edge].y, c3, c4, c1, c2, raiseLand); - // Smooth the edge at the bottom of the new slope - totalCost += smooth_land_row_by_edge( - flags, mapLeft, mapTop, z3, z4, -stepOffsets[edge].x, -stepOffsets[edge].y, c1, c2, c3, c4, raiseLand); - - // Smooth corners - totalCost += smooth_land_row_by_corner( - flags, mapLeft, mapTop, z1, -stepOffsets[edge].y, stepOffsets[edge].x, c2, c1, raiseLand); - totalCost += smooth_land_row_by_corner( - flags, mapLeft, mapTop, z2, stepOffsets[edge].y, -stepOffsets[edge].x, c1, c2, raiseLand); - int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, -32, -32, 0, 2, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 0); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 32, 32, 2, 0, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 3); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, -32, 32, 1, 3, raiseLand); - z = map_get_corner_height(newBaseZ, newSlope, 1); - totalCost += smooth_land_row_by_corner(flags, mapLeft, mapTop, z, 32, -32, 3, 1, raiseLand); - break; - } - } // switch selectionType - - // Raise / lower the land tool selection area - GameActionResult::Ptr res; - if (raiseLand) - { - auto raiseLandAction = LandRaiseAction({ centreX, centreY }, { mapLeft, mapTop, mapRight, mapBottom }, selectionType); - raiseLandAction.SetFlags(flags); - res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&raiseLandAction) - : GameActions::QueryNested(&raiseLandAction); - } - else - { - auto lowerLandAction = LandLowerAction({ centreX, centreY }, { mapLeft, mapTop, mapRight, mapBottom }, selectionType); - lowerLandAction.SetFlags(flags); - res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&lowerLandAction) - : GameActions::QueryNested(&lowerLandAction); - } - if (res->Error != GA_ERROR::OK) - { - return MONEY32_UNDEFINED; - } - - totalCost += res->Cost; - - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - gCommandPosition.x = centreX; - gCommandPosition.y = centreY; - gCommandPosition.z = centreZ; - return totalCost; -} - -/** - * - * rct2: 0x0068BC01 - */ -void game_command_smooth_land( - int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp) -{ - int32_t flags = *ebx & 0xFF; - int32_t centreX = *eax & 0xFFFF; - int32_t centreY = *ecx & 0xFFFF; - int32_t mapLeft = (int16_t)(*edx & 0xFFFF); - int32_t mapTop = (int16_t)(*ebp & 0xFFFF); - int32_t mapRight = (int16_t)(*edx >> 16); - int32_t mapBottom = (int16_t)(*ebp >> 16); - int32_t command = *edi; - *ebx = smooth_land(flags, centreX, centreY, mapLeft, mapTop, mapRight, mapBottom, command); -} - bool map_is_location_at_edge(int32_t x, int32_t y) { return x < 32 || y < 32 || x >= ((MAXIMUM_MAP_SIZE_TECHNICAL - 1) * 32) || y >= ((MAXIMUM_MAP_SIZE_TECHNICAL - 1) * 32); diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 7c7a395a05..64660ef626 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -202,7 +202,6 @@ void game_command_set_large_scenery_colour( int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); void game_command_set_banner_colour( int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); -void game_command_smooth_land(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); void game_command_place_banner( int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); void game_command_place_wall(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); From cc57de791a3c08e76c7c12852dd09187fbf86ec2 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Sat, 16 Mar 2019 22:37:20 +0000 Subject: [PATCH 3/7] Fix formatting. Add correct headers --- src/openrct2/actions/LandSmoothAction.hpp | 123 +++++++++++++--------- 1 file changed, 74 insertions(+), 49 deletions(-) diff --git a/src/openrct2/actions/LandSmoothAction.hpp b/src/openrct2/actions/LandSmoothAction.hpp index d96b35f512..8819356fda 100644 --- a/src/openrct2/actions/LandSmoothAction.hpp +++ b/src/openrct2/actions/LandSmoothAction.hpp @@ -11,6 +11,8 @@ #include "../Context.h" #include "../OpenRCT2.h" +#include "../actions/LandLowerAction.hpp" +#include "../actions/LandRaiseAction.hpp" #include "../actions/LandSetHeightAction.hpp" #include "../audio/audio.h" #include "../interface/Window.h" @@ -77,8 +79,7 @@ private: return res; } - money32 smooth_land_tile( - int32_t direction, bool isExecuting, int32_t x, int32_t y, TileElement * tileElement) const + money32 smooth_land_tile(int32_t direction, bool isExecuting, int32_t x, int32_t y, TileElement* tileElement) const { int32_t targetBaseZ = tileElement->base_height; int32_t slope = tileElement->AsSurface()->GetSlope(); @@ -104,7 +105,7 @@ private: auto landSetHeightAction = LandSetHeightAction({ x, y }, targetBaseZ, slope); landSetHeightAction.SetFlags(GetFlags()); auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); + : GameActions::QueryNested(&landSetHeightAction); if (res->Error == GA_ERROR::OK) { @@ -251,7 +252,7 @@ private: auto landSetHeightAction = LandSetHeightAction({ x, y }, targetBaseZ, slope); landSetHeightAction.SetFlags(GetFlags()); auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); + : GameActions::QueryNested(&landSetHeightAction); if (res->Error == GA_ERROR::OK) { totalCost += res->Cost; @@ -331,11 +332,9 @@ private: if (stepX * stepY != 0) { totalCost += smooth_land_row_by_corner( - isExecuting, x, y, expectedLandHeight + (landChangePerTile / 2), 0, stepY, direction, checkDirection ^ 3 - ); + isExecuting, x, y, expectedLandHeight + (landChangePerTile / 2), 0, stepY, direction, checkDirection ^ 3); totalCost += smooth_land_row_by_corner( - isExecuting, x, y, expectedLandHeight + (landChangePerTile / 2), stepX, 0, direction, checkDirection ^ 1 - ); + isExecuting, x, y, expectedLandHeight + (landChangePerTile / 2), stepX, 0, direction, checkDirection ^ 1); } expectedLandHeight += landChangePerTile; // change land of current tile @@ -366,7 +365,6 @@ private: // Play sound (only once) int32_t centreZ = tile_element_height(_coords.x, _coords.y) & 0xFFFF; - auto res = MakeResult(); res->ErrorTitle = _ErrorTitles[_isLowering ? 0 : 1]; res->Position = { _coords.x, _coords.y, centreZ }; @@ -376,7 +374,10 @@ private: { case MAP_SELECT_TYPE_FULL: { - uint8_t minHeight = heightOffset + map_get_lowest_land_height(validRange.GetLeft(), validRange.GetRight(), validRange.GetTop(), validRange.GetBottom()); + uint8_t minHeight = heightOffset + + map_get_lowest_land_height( + validRange.GetLeft(), validRange.GetRight(), validRange.GetTop(), + validRange.GetBottom()); uint8_t maxHeight = heightOffset + map_get_highest_land_height( validRange.GetLeft(), validRange.GetRight(), validRange.GetTop(), @@ -390,21 +391,22 @@ private: isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); } { // bottom-left - TileElement* tileElement = map_get_surface_element_at( - { validRange.GetLeft(), validRange.GetBottom() }); + TileElement* tileElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetBottom() }); int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 3), minHeight, maxHeight); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetBottom(), z, -32, 32, 1, 3); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetBottom(), z, -32, 32, 1, 3); } { // bottom-right - TileElement* tileElement = map_get_surface_element_at( - { validRange.GetRight(), validRange.GetBottom() } ); + TileElement* tileElement = map_get_surface_element_at({ validRange.GetRight(), validRange.GetBottom() }); int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 0), minHeight, maxHeight); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetRight(), validRange.GetBottom(), z, 32, 32, 2, 0); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetRight(), validRange.GetBottom(), z, 32, 32, 2, 0); } { // top-right TileElement* tileElement = map_get_surface_element_at({ validRange.GetRight(), validRange.GetTop() }); int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 1), minHeight, maxHeight); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetRight(), validRange.GetTop(), z, 32, -32, 3, 1); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetRight(), validRange.GetTop(), z, 32, -32, 3, 1); } // Smooth the edges @@ -463,52 +465,71 @@ private: // Smooth the corners int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); z = map_get_corner_height(newBaseZ, newSlope, 0); res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 32, 2, 0); z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 32, 1, 3); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 32, 1, 3); z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, -32, 3, 1); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, -32, 3, 1); // Smooth the edges switch (selectionType) { case MAP_SELECT_TYPE_CORNER_0: z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 3, 0); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 1, 0); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 3, 0); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 1, 0); z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 0, 3); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 0, 3); z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 0, 1); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 0, 1); break; case MAP_SELECT_TYPE_CORNER_1: z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 2, 1); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 0, 1); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 2, 1); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 0, 1); z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 1, 2); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 1, 2); z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 1, 0); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 1, 0); break; case MAP_SELECT_TYPE_CORNER_2: z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 1, 2); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 3, 2); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 1, 2); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 3, 2); z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 2, 1); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 2, 1); z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 2, 3); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 2, 3); break; case MAP_SELECT_TYPE_CORNER_3: z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 0, 3); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 2, 3); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 0, 3); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 2, 3); z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 3, 0); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 3, 0); z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 3, 2); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 3, 2); break; } break; @@ -571,24 +592,31 @@ private: uint8_t z4 = map_get_corner_height(newBaseZ, newSlope, c4); // Smooth the edge at the top of the new slope res->Cost += smooth_land_row_by_edge( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z1, z2, stepOffsets[edge].x, stepOffsets[edge].y, c3, c4, c1, c2); + isExecuting, validRange.GetLeft(), validRange.GetTop(), z1, z2, stepOffsets[edge].x, stepOffsets[edge].y, + c3, c4, c1, c2); // Smooth the edge at the bottom of the new slope res->Cost += smooth_land_row_by_edge( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z3, z4, -stepOffsets[edge].x, -stepOffsets[edge].y, c1, c2, c3, c4); + isExecuting, validRange.GetLeft(), validRange.GetTop(), z3, z4, -stepOffsets[edge].x, -stepOffsets[edge].y, + c1, c2, c3, c4); // Smooth corners res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z1, -stepOffsets[edge].y, stepOffsets[edge].x, c2, c1); + isExecuting, validRange.GetLeft(), validRange.GetTop(), z1, -stepOffsets[edge].y, stepOffsets[edge].x, c2, + c1); res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z2, stepOffsets[edge].y, -stepOffsets[edge].x, c1, c2); + isExecuting, validRange.GetLeft(), validRange.GetTop(), z2, stepOffsets[edge].y, -stepOffsets[edge].x, c1, + c2); int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); z = map_get_corner_height(newBaseZ, newSlope, 0); res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 32, 2, 0); z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 32, 1, 3); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 32, 1, 3); z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, -32, 3, 1); + res->Cost += smooth_land_row_by_corner( + isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, -32, 3, 1); break; } } // switch selectionType @@ -597,18 +625,15 @@ private: GameActionResult::Ptr result; if (raiseLand) { - auto raiseLandAction = LandRaiseAction( - { _coords.x, _coords.y }, validRange, selectionType); + auto raiseLandAction = LandRaiseAction({ _coords.x, _coords.y }, validRange, selectionType); raiseLandAction.SetFlags(GetFlags()); - result = isExecuting ? GameActions::ExecuteNested(&raiseLandAction) - : GameActions::QueryNested(&raiseLandAction); + result = isExecuting ? GameActions::ExecuteNested(&raiseLandAction) : GameActions::QueryNested(&raiseLandAction); } else { auto lowerLandAction = LandLowerAction({ _coords.x, _coords.y }, validRange, selectionType); lowerLandAction.SetFlags(GetFlags()); - result = isExecuting ? GameActions::ExecuteNested(&lowerLandAction) - : GameActions::QueryNested(&lowerLandAction); + result = isExecuting ? GameActions::ExecuteNested(&lowerLandAction) : GameActions::QueryNested(&lowerLandAction); } if (result->Error != GA_ERROR::OK) { From 95b7a90c556c483d80d53d2a62fe00d394975b12 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Wed, 20 Mar 2019 19:47:07 +0000 Subject: [PATCH 4/7] Refactor function names and variables --- src/openrct2/actions/LandSmoothAction.hpp | 340 +++++++++++----------- 1 file changed, 168 insertions(+), 172 deletions(-) diff --git a/src/openrct2/actions/LandSmoothAction.hpp b/src/openrct2/actions/LandSmoothAction.hpp index 8819356fda..287feb97a4 100644 --- a/src/openrct2/actions/LandSmoothAction.hpp +++ b/src/openrct2/actions/LandSmoothAction.hpp @@ -63,12 +63,12 @@ public: GameActionResult::Ptr Query() const override { - return smooth_land(false); + return SmoothLand(false); } GameActionResult::Ptr Execute() const override { - return smooth_land(true); + return SmoothLand(true); } private: @@ -79,10 +79,11 @@ private: return res; } - money32 smooth_land_tile(int32_t direction, bool isExecuting, int32_t x, int32_t y, TileElement* tileElement) const + GameActionResult::Ptr SmoothLandTile(int32_t direction, bool isExecuting, int32_t x, int32_t y, TileElement* surfaceElement) + const { - int32_t targetBaseZ = tileElement->base_height; - int32_t slope = tileElement->AsSurface()->GetSlope(); + int32_t targetBaseZ = surfaceElement->base_height; + int32_t slope = surfaceElement->AsSurface()->GetSlope(); if (_isLowering) { slope = tile_element_lower_styles[direction][slope]; @@ -107,92 +108,85 @@ private: auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) : GameActions::QueryNested(&landSetHeightAction); - if (res->Error == GA_ERROR::OK) - { - return res->Cost; - } - else - { - return MONEY32_UNDEFINED; - } + return res; } - money32 smooth_land_row_by_edge( - bool isExecuting, int32_t x, int32_t y, int32_t expectedLandHeight1, int32_t expectedLandHeight2, int32_t stepX, - int32_t stepY, int32_t direction1, int32_t direction2, int32_t checkDirection1, int32_t checkDirection2) const + money32 SmoothLandRowByEdge( + bool isExecuting, CoordsXY loc, int32_t expectedLandHeight1, int32_t expectedLandHeight2, int32_t stepX, int32_t stepY, + int32_t direction1, int32_t direction2, int32_t checkDirection1, int32_t checkDirection2) const { uint8_t shouldContinue = 0xF; int32_t landChangePerTile = _isLowering ? 2 : -2; - TileElement *tileElement, *nextTileElement; money32 totalCost = 0; // check if we need to start at all - if (!map_is_location_valid({ x, y }) || !map_is_location_valid({ x + stepX, y + stepY })) + if (!map_is_location_valid(loc) || !map_is_location_valid({ loc.x + stepX, loc.y + stepY })) { return 0; } - tileElement = map_get_surface_element_at({ x, y }); - nextTileElement = map_get_surface_element_at({ x + stepX, y + stepY }); - if (tileElement == nullptr || nextTileElement == nullptr) + auto surfaceElement = map_get_surface_element_at(loc); + auto nextSurfaceElement = map_get_surface_element_at({ loc.x + stepX, loc.y + stepY }); + if (surfaceElement == nullptr || nextSurfaceElement == nullptr) { return 0; } - if (tile_element_get_corner_height(tileElement, checkDirection1) != expectedLandHeight1 + landChangePerTile) + if (tile_element_get_corner_height(surfaceElement, checkDirection1) != expectedLandHeight1 + landChangePerTile) { shouldContinue &= ~0x1; } - if (tile_element_get_corner_height(tileElement, checkDirection2) != expectedLandHeight2 + landChangePerTile) + if (tile_element_get_corner_height(surfaceElement, checkDirection2) != expectedLandHeight2 + landChangePerTile) { shouldContinue &= ~0x2; } - if (tile_element_get_corner_height(tileElement, checkDirection1) - != tile_element_get_corner_height(nextTileElement, direction1)) + if (tile_element_get_corner_height(surfaceElement, checkDirection1) + != tile_element_get_corner_height(nextSurfaceElement, direction1)) { shouldContinue &= ~0x1; } - if (tile_element_get_corner_height(tileElement, checkDirection2) - != tile_element_get_corner_height(nextTileElement, direction2)) + if (tile_element_get_corner_height(surfaceElement, checkDirection2) + != tile_element_get_corner_height(nextSurfaceElement, direction2)) { shouldContinue &= ~0x2; } + auto nextLoc = loc; while ((shouldContinue & 0x3) != 0) { shouldContinue = ((shouldContinue << 2) | 0x3) & shouldContinue; - x += stepX; - y += stepY; + nextLoc.x += stepX; + nextLoc.y += stepY; // check if we need to continue after raising the current tile // this needs to be checked before the tile is changed - if (!map_is_location_valid({ x + stepX, y + stepY })) + if (!map_is_location_valid({ nextLoc.x + stepX, nextLoc.y + stepY })) { shouldContinue &= ~0x3; } else { - tileElement = nextTileElement; - nextTileElement = map_get_surface_element_at({ x + stepX, y + stepY }); - if (nextTileElement == nullptr) + surfaceElement = nextSurfaceElement; + nextSurfaceElement = map_get_surface_element_at({ nextLoc.x + stepX, nextLoc.y + stepY }); + if (nextSurfaceElement == nullptr) { shouldContinue &= ~0x3; } - if (tile_element_get_corner_height(tileElement, direction1) + landChangePerTile - != tile_element_get_corner_height(tileElement, checkDirection1)) + if (tile_element_get_corner_height(surfaceElement, direction1) + landChangePerTile + != tile_element_get_corner_height(surfaceElement, checkDirection1)) { shouldContinue &= ~0x1; } - if (tile_element_get_corner_height(tileElement, direction2) + landChangePerTile - != tile_element_get_corner_height(tileElement, checkDirection2)) + if (tile_element_get_corner_height(surfaceElement, direction2) + landChangePerTile + != tile_element_get_corner_height(surfaceElement, checkDirection2)) { shouldContinue &= ~0x2; } if ((shouldContinue & 0x1) - && tile_element_get_corner_height(tileElement, checkDirection1) - != tile_element_get_corner_height(nextTileElement, direction1)) + && tile_element_get_corner_height(surfaceElement, checkDirection1) + != tile_element_get_corner_height(nextSurfaceElement, direction1)) { shouldContinue &= ~0x1; } if ((shouldContinue & 0x2) - && tile_element_get_corner_height(tileElement, checkDirection2) - != tile_element_get_corner_height(nextTileElement, direction2)) + && tile_element_get_corner_height(surfaceElement, checkDirection2) + != tile_element_get_corner_height(nextSurfaceElement, direction2)) { shouldContinue &= ~0x2; } @@ -200,8 +194,8 @@ private: expectedLandHeight1 += landChangePerTile; // change land of current tile - int32_t targetBaseZ = tileElement->base_height; - int32_t slope = tileElement->AsSurface()->GetSlope(); + int32_t targetBaseZ = surfaceElement->base_height; + int32_t slope = surfaceElement->AsSurface()->GetSlope(); int32_t oldSlope = slope; if (_isLowering) { @@ -215,7 +209,7 @@ private: } } if ((shouldContinue & 0x8) - && map_get_corner_height(tileElement->base_height, oldSlope, direction2) + && map_get_corner_height(surfaceElement->base_height, oldSlope, direction2) == map_get_corner_height(targetBaseZ, slope, direction2)) { slope = tile_element_lower_styles[direction2][slope]; @@ -238,7 +232,7 @@ private: } } if ((shouldContinue & 0x8) - && map_get_corner_height(tileElement->base_height, oldSlope, direction2) + && map_get_corner_height(surfaceElement->base_height, oldSlope, direction2) == map_get_corner_height(targetBaseZ, slope, direction2)) { slope = tile_element_raise_styles[direction2][slope]; @@ -249,7 +243,7 @@ private: } } } - auto landSetHeightAction = LandSetHeightAction({ x, y }, targetBaseZ, slope); + auto landSetHeightAction = LandSetHeightAction(nextLoc, targetBaseZ, slope); landSetHeightAction.SetFlags(GetFlags()); auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) : GameActions::QueryNested(&landSetHeightAction); @@ -261,14 +255,12 @@ private: return totalCost; } - money32 smooth_land_row_by_corner( - bool isExecuting, int32_t x, int32_t y, int32_t expectedLandHeight, int32_t stepX, int32_t stepY, int32_t direction, + money32 SmoothLandRowByCorner( + bool isExecuting, CoordsXY loc, int32_t expectedLandHeight, int32_t stepX, int32_t stepY, int32_t direction, int32_t checkDirection) const { bool shouldContinue = true; - TileElement *tileElement, *nextTileElement; money32 totalCost = 0; - money32 result; int32_t landChangePerTile; if (stepX == 0 || stepY == 0) { @@ -280,74 +272,78 @@ private: } // check if we need to start at all - if (!map_is_location_valid({ x, y }) || !map_is_location_valid({ x + stepX, y + stepY })) + if (!map_is_location_valid(loc) || !map_is_location_valid({ loc.x + stepX, loc.y + stepY })) { return 0; } - tileElement = map_get_surface_element_at({ x, y }); - nextTileElement = map_get_surface_element_at((x + stepX) >> 5, (y + stepY) >> 5); - if (tileElement == nullptr || nextTileElement == nullptr) + auto surfaceElement = map_get_surface_element_at(loc); + auto nextSurfaceElement = map_get_surface_element_at({ loc.x + stepX, loc.y + stepY }); + if (surfaceElement == nullptr || nextSurfaceElement == nullptr) { return 0; } - if (tile_element_get_corner_height(tileElement, checkDirection) != expectedLandHeight + (_isLowering ? 2 : -2)) + if (tile_element_get_corner_height(surfaceElement, checkDirection) != expectedLandHeight + (_isLowering ? 2 : -2)) { return 0; } - if (tile_element_get_corner_height(tileElement, checkDirection) - != tile_element_get_corner_height(nextTileElement, direction)) + if (tile_element_get_corner_height(surfaceElement, checkDirection) + != tile_element_get_corner_height(nextSurfaceElement, direction)) { return 0; } + + auto nextLoc = loc; while (shouldContinue) { - x += stepX; - y += stepY; + nextLoc.x += stepX; + nextLoc.y += stepY; // check if we need to continue after raising the current tile // this needs to be checked before the tile is changed - if (!map_is_location_valid({ x + stepX, y + stepY })) + if (!map_is_location_valid({ nextLoc.x + stepX, nextLoc.y + stepY })) { shouldContinue = false; } else { - tileElement = nextTileElement; - nextTileElement = map_get_surface_element_at((x + stepX) >> 5, (y + stepY) >> 5); - if (nextTileElement == nullptr) + surfaceElement = nextSurfaceElement; + nextSurfaceElement = map_get_surface_element_at({ nextLoc.x + stepX, nextLoc.y + stepY }); + if (nextSurfaceElement == nullptr) { shouldContinue = false; } - if (tile_element_get_corner_height(tileElement, direction) + landChangePerTile - != tile_element_get_corner_height(tileElement, checkDirection)) + if (tile_element_get_corner_height(surfaceElement, direction) + landChangePerTile + != tile_element_get_corner_height(surfaceElement, checkDirection)) { shouldContinue = false; } if (shouldContinue - && tile_element_get_corner_height(tileElement, checkDirection) - != tile_element_get_corner_height(nextTileElement, direction)) + && tile_element_get_corner_height(surfaceElement, checkDirection) + != tile_element_get_corner_height(nextSurfaceElement, direction)) { shouldContinue = false; } } if (stepX * stepY != 0) { - totalCost += smooth_land_row_by_corner( - isExecuting, x, y, expectedLandHeight + (landChangePerTile / 2), 0, stepY, direction, checkDirection ^ 3); - totalCost += smooth_land_row_by_corner( - isExecuting, x, y, expectedLandHeight + (landChangePerTile / 2), stepX, 0, direction, checkDirection ^ 1); + totalCost += SmoothLandRowByCorner( + isExecuting, nextLoc, expectedLandHeight + (landChangePerTile / 2), 0, stepY, direction, + checkDirection ^ 3); + totalCost += SmoothLandRowByCorner( + isExecuting, nextLoc, expectedLandHeight + (landChangePerTile / 2), stepX, 0, direction, + checkDirection ^ 1); } expectedLandHeight += landChangePerTile; // change land of current tile - result = smooth_land_tile(direction, isExecuting, x, y, tileElement); - if (result != MONEY32_UNDEFINED) + auto result = SmoothLandTile(direction, isExecuting, nextLoc.x, nextLoc.y, surfaceElement); + if (result->Error == GA_ERROR::OK) { - totalCost += result; + totalCost += result->Cost; } } return totalCost; } - GameActionResult::Ptr smooth_land(bool isExecuting) const + GameActionResult::Ptr SmoothLand(bool isExecuting) const { // break up information in command const bool raiseLand = !_isLowering; @@ -385,57 +381,57 @@ private: // Smooth the 4 corners { // top-left - TileElement* tileElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetTop() }); - int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 2), minHeight, maxHeight); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); + auto surfaceElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetTop() }); + int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 2), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); } { // bottom-left - TileElement* tileElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetBottom() }); - int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 3), minHeight, maxHeight); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetBottom(), z, -32, 32, 1, 3); + auto surfaceElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetBottom() }); + int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 3), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetBottom() }, z, -32, 32, 1, 3); } { // bottom-right - TileElement* tileElement = map_get_surface_element_at({ validRange.GetRight(), validRange.GetBottom() }); - int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 0), minHeight, maxHeight); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetRight(), validRange.GetBottom(), z, 32, 32, 2, 0); + auto surfaceElement = map_get_surface_element_at({ validRange.GetRight(), validRange.GetBottom() }); + int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 0), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetRight(), validRange.GetBottom() }, z, 32, 32, 2, 0); } { // top-right - TileElement* tileElement = map_get_surface_element_at({ validRange.GetRight(), validRange.GetTop() }); - int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 1), minHeight, maxHeight); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetRight(), validRange.GetTop(), z, 32, -32, 3, 1); + auto surfaceElement = map_get_surface_element_at({ validRange.GetRight(), validRange.GetTop() }); + int32_t z = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 1), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetRight(), validRange.GetTop() }, z, 32, -32, 3, 1); } // Smooth the edges - TileElement* tileElement = nullptr; + TileElement* surfaceElement = nullptr; int32_t z1, z2; for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += 32) { - tileElement = map_get_surface_element_at({ validRange.GetLeft(), y }); - z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 3), minHeight, maxHeight); - z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 2), minHeight, maxHeight); - res->Cost += smooth_land_row_by_edge(isExecuting, validRange.GetLeft(), y, z1, z2, -32, 0, 0, 1, 3, 2); + surfaceElement = map_get_surface_element_at({ validRange.GetLeft(), y }); + z1 = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 3), minHeight, maxHeight); + z2 = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 2), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { validRange.GetLeft(), y }, z1, z2, -32, 0, 0, 1, 3, 2); - tileElement = map_get_surface_element_at({ validRange.GetRight(), y }); - z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 1), minHeight, maxHeight); - z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 0), minHeight, maxHeight); - res->Cost += smooth_land_row_by_edge(isExecuting, validRange.GetRight(), y, z1, z2, 32, 0, 2, 3, 1, 0); + surfaceElement = map_get_surface_element_at({ validRange.GetRight(), y }); + z1 = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 1), minHeight, maxHeight); + z2 = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 0), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { validRange.GetRight(), y }, z1, z2, 32, 0, 2, 3, 1, 0); } for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += 32) { - tileElement = map_get_surface_element_at({ x, validRange.GetTop() }); - z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 1), minHeight, maxHeight); - z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 2), minHeight, maxHeight); - res->Cost += smooth_land_row_by_edge(isExecuting, x, validRange.GetTop(), z1, z2, 0, -32, 0, 3, 1, 2); + surfaceElement = map_get_surface_element_at({ x, validRange.GetTop() }); + z1 = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 1), minHeight, maxHeight); + z2 = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 2), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { x, validRange.GetTop() }, z1, z2, 0, -32, 0, 3, 1, 2); - tileElement = map_get_surface_element_at({ x, validRange.GetBottom() }); - z1 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 0), minHeight, maxHeight); - z2 = std::clamp((uint8_t)tile_element_get_corner_height(tileElement, 3), minHeight, maxHeight); - res->Cost += smooth_land_row_by_edge(isExecuting, x, validRange.GetBottom(), z1, z2, 0, 32, 1, 2, 0, 3); + surfaceElement = map_get_surface_element_at({ x, validRange.GetBottom() }); + z1 = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 0), minHeight, maxHeight); + z2 = std::clamp((uint8_t)tile_element_get_corner_height(surfaceElement, 3), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { x, validRange.GetBottom() }, z1, z2, 0, 32, 1, 2, 0, 3); } break; } @@ -444,9 +440,9 @@ private: case MAP_SELECT_TYPE_CORNER_2: case MAP_SELECT_TYPE_CORNER_3: { - TileElement* tileElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetTop() }); - uint8_t newBaseZ = tileElement->base_height; - uint8_t newSlope = tileElement->AsSurface()->GetSlope(); + auto surfaceElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetTop() }); + uint8_t newBaseZ = surfaceElement->base_height; + uint8_t newSlope = surfaceElement->AsSurface()->GetSlope(); if (raiseLand) { @@ -465,71 +461,71 @@ private: // Smooth the corners int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 32, 2, 0); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 32, 2, 0); z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 32, 1, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 32, 1, 3); z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, -32, 3, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); // Smooth the edges switch (selectionType) { case MAP_SELECT_TYPE_CORNER_0: z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 3, 0); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 1, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 3, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 1, 0); z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 0, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 0, 3); z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 0, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 0, 1); break; case MAP_SELECT_TYPE_CORNER_1: z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 2, 1); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 0, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 2, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 0, 1); z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 1, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 1, 2); z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 1, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 1, 0); break; case MAP_SELECT_TYPE_CORNER_2: z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 1, 2); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 3, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 1, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 3, 2); z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 2, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 2, 1); z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 2, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 2, 3); break; case MAP_SELECT_TYPE_CORNER_3: z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 0, 0, 3); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, 32, 2, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 0, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 2, 3); z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 0, 3, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 3, 0); z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 0, -32, 3, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 3, 2); break; } break; @@ -541,7 +537,7 @@ private: { // TODO: Handle smoothing by edge // Get the two corners to raise - TileElement* surfaceElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetTop() }); + auto surfaceElement = map_get_surface_element_at({ validRange.GetLeft(), validRange.GetTop() }); uint8_t newBaseZ = surfaceElement->base_height; uint8_t oldSlope = surfaceElement->AsSurface()->GetSlope(); uint8_t newSlope = oldSlope; @@ -565,8 +561,8 @@ private: const uint8_t edge = selectionType - MAP_SELECT_TYPE_EDGE_0; - // Table with corners for each edge selection. The first two are the selected corners, the latter two are the - // opposites + // Table with corners for each edge selection. The first two are the selected corners, the latter + // two are the opposites static constexpr uint8_t cornerIndices[][4] = { { 2, 3, 1, 0 }, // MAP_SELECT_TYPE_EDGE_0 { 3, 0, 2, 1 }, // MAP_SELECT_TYPE_EDGE_1 @@ -591,32 +587,32 @@ private: uint8_t z3 = map_get_corner_height(newBaseZ, newSlope, c3); uint8_t z4 = map_get_corner_height(newBaseZ, newSlope, c4); // Smooth the edge at the top of the new slope - res->Cost += smooth_land_row_by_edge( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z1, z2, stepOffsets[edge].x, stepOffsets[edge].y, - c3, c4, c1, c2); + res->Cost += SmoothLandRowByEdge( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z1, z2, stepOffsets[edge].x, + stepOffsets[edge].y, c3, c4, c1, c2); // Smooth the edge at the bottom of the new slope - res->Cost += smooth_land_row_by_edge( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z3, z4, -stepOffsets[edge].x, -stepOffsets[edge].y, - c1, c2, c3, c4); + res->Cost += SmoothLandRowByEdge( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z3, z4, -stepOffsets[edge].x, + -stepOffsets[edge].y, c1, c2, c3, c4); // Smooth corners - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z1, -stepOffsets[edge].y, stepOffsets[edge].x, c2, - c1); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z2, stepOffsets[edge].y, -stepOffsets[edge].x, c1, - c2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z1, -stepOffsets[edge].y, stepOffsets[edge].x, + c2, c1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z2, stepOffsets[edge].y, -stepOffsets[edge].x, + c1, c2); int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, -32, 0, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += smooth_land_row_by_corner(isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, 32, 2, 0); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 32, 2, 0); z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, -32, 32, 1, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 32, 1, 3); z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += smooth_land_row_by_corner( - isExecuting, validRange.GetLeft(), validRange.GetTop(), z, 32, -32, 3, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); break; } } // switch selectionType From 3e7a5bdd7e40f57d0bb9ec235ba5971c353255ce Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Wed, 20 Mar 2019 20:36:20 +0100 Subject: [PATCH 5/7] Add LandSmoothAction.hpp to Xcode project. --- OpenRCT2.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 085105a046..2d374072be 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -118,6 +118,7 @@ 9346F9DB208A191900C77D91 /* GuestPathfinding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9346F9D7208A191900C77D91 /* GuestPathfinding.cpp */; }; 9346F9DC208A191900C77D91 /* GuestPathfinding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9346F9D7208A191900C77D91 /* GuestPathfinding.cpp */; }; 9346F9DD208A191900C77D91 /* GuestPathfinding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9346F9D7208A191900C77D91 /* GuestPathfinding.cpp */; }; + 937A92152242CDAA00B09278 /* LandSmoothAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 937A92142242CDAA00B09278 /* LandSmoothAction.hpp */; }; 939A359A20C12FC800630B3F /* Paint.Litter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 939A359720C12FC700630B3F /* Paint.Litter.cpp */; }; 939A359B20C12FC800630B3F /* Paint.Misc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 939A359820C12FC700630B3F /* Paint.Misc.cpp */; }; 939A359C20C12FC800630B3F /* Paint.Sprite.h in Headers */ = {isa = PBXBuildFile; fileRef = 939A359920C12FC700630B3F /* Paint.Sprite.h */; }; @@ -1240,6 +1241,7 @@ 9350B52720B46E0900897BC5 /* ftbdf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ftbdf.h; sourceTree = ""; }; 9350B52820B46E0900897BC5 /* ftrender.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ftrender.h; sourceTree = ""; }; 9350B52920B46E0900897BC5 /* ft2build.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ft2build.h; sourceTree = ""; }; + 937A92142242CDAA00B09278 /* LandSmoothAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandSmoothAction.hpp; sourceTree = ""; }; 939A359720C12FC700630B3F /* Paint.Litter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Paint.Litter.cpp; sourceTree = ""; }; 939A359820C12FC700630B3F /* Paint.Misc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Paint.Misc.cpp; sourceTree = ""; }; 939A359920C12FC700630B3F /* Paint.Sprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Paint.Sprite.h; sourceTree = ""; }; @@ -2152,6 +2154,7 @@ C9C630BC2235A7F9009AD16E /* WaterRaiseAction.hpp */, C9C630BA2235A7E7009AD16E /* LandLowerAction.hpp */, C9C630B92235A7E7009AD16E /* LandRaiseAction.hpp */, + 937A92142242CDAA00B09278 /* LandSmoothAction.hpp */, 2A61CAFA2229E5C50095AD67 /* RideEntranceExitPlaceAction.hpp */, 2A61CAF82229E59F0095AD67 /* WaterSetHeightAction.hpp */, 2A61CAF42229E5720095AD67 /* FootpathPlaceAction.hpp */, @@ -3520,6 +3523,7 @@ 2ADE2F0A2244187B002598AF /* ParkSetResearchFundingAction.hpp in Headers */, 2ADE2F142244187B002598AF /* FootpathRemoveAction.hpp in Headers */, 2ADE2F1F2244187B002598AF /* BannerSetNameAction.hpp in Headers */, + 937A92152242CDAA00B09278 /* LandSmoothAction.hpp in Headers */, C6352B941F477032006CCEE3 /* PlaceParkEntranceAction.hpp in Headers */, C6352B911F477032006CCEE3 /* GameAction.h in Headers */, 2A43D2BA2225B8D900E8F73B /* RideSetVehiclesAction.hpp in Headers */, From 68bf1bc46409bea7d774adc4067cb2e5e57d001e Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Mon, 25 Mar 2019 18:28:21 +0000 Subject: [PATCH 6/7] Make requested changes --- src/openrct2/actions/LandSmoothAction.hpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/openrct2/actions/LandSmoothAction.hpp b/src/openrct2/actions/LandSmoothAction.hpp index 287feb97a4..289e0a13c0 100644 --- a/src/openrct2/actions/LandSmoothAction.hpp +++ b/src/openrct2/actions/LandSmoothAction.hpp @@ -32,8 +32,8 @@ DEFINE_GAME_ACTION(LandSmoothAction, GAME_COMMAND_EDIT_LAND_SMOOTH, GameActionRe private: CoordsXY _coords; MapRange _range; - uint8_t _selectionType; - bool _isLowering; + uint8_t _selectionType{ 0 }; + bool _isLowering{ false }; constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_LOWER_LAND_HERE, STR_CANT_RAISE_LAND_HERE }; @@ -72,13 +72,6 @@ public: } private: - GameActionResult::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - return res; - } - GameActionResult::Ptr SmoothLandTile(int32_t direction, bool isExecuting, int32_t x, int32_t y, TileElement* surfaceElement) const { @@ -345,7 +338,6 @@ private: GameActionResult::Ptr SmoothLand(bool isExecuting) const { - // break up information in command const bool raiseLand = !_isLowering; const int32_t selectionType = _selectionType; const int32_t heightOffset = raiseLand ? 2 : -2; @@ -358,11 +350,11 @@ private: auto b = std::clamp(normRange.GetBottom(), 0, (MAXIMUM_MAP_SIZE_TECHNICAL - 1) * 32); auto validRange = MapRange{ l, t, r, b }; - // Play sound (only once) int32_t centreZ = tile_element_height(_coords.x, _coords.y) & 0xFFFF; auto res = MakeResult(); res->ErrorTitle = _ErrorTitles[_isLowering ? 0 : 1]; + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; res->Position = { _coords.x, _coords.y, centreZ }; // Do the smoothing @@ -615,6 +607,9 @@ private: isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); break; } + default: + log_error("Invalid map selection %u", _selectionType); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, res->ErrorTitle); } // switch selectionType // Raise / lower the land tool selection area @@ -640,10 +635,7 @@ private: { audio_play_sound_at_location(SOUND_PLACE_ITEM, _coords.x, _coords.y, centreZ); } - res->Cost += res->Cost; - - res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - + res->Cost += result->Cost; return res; } }; From 9b4bc97826e416aac85969e60ae4f0af0162f496 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Wed, 27 Mar 2019 18:49:19 +0000 Subject: [PATCH 7/7] Increment network version --- src/openrct2/network/Network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index c310c5897a..90c27248ee 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -31,7 +31,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 "12" +#define NETWORK_STREAM_VERSION "13" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION static Peep* _pickup_peep = nullptr;