From 61cb84e0ca18f2b0d99b7b88fd493075aaeeaeb9 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Thu, 28 Feb 2019 17:08:58 +0000 Subject: [PATCH] Add WaterSetHeightAction --- .../actions/GameActionRegistration.cpp | 2 + src/openrct2/actions/WaterSetHeightAction.hpp | 161 ++++++++++++++++++ src/openrct2/world/Map.cpp | 30 +++- src/openrct2/world/Map.h | 2 + 4 files changed, 187 insertions(+), 8 deletions(-) create mode 100644 src/openrct2/actions/WaterSetHeightAction.hpp diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index db6a21e0c6..f99e9a3e07 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -47,6 +47,7 @@ #include "TrackPlaceAction.hpp" #include "TrackRemoveAction.hpp" #include "WallRemoveAction.hpp" +#include "WaterSetHeightAction.hpp" namespace GameActions { @@ -91,5 +92,6 @@ namespace GameActions Register(); Register(); Register(); + Register(); } } // namespace GameActions diff --git a/src/openrct2/actions/WaterSetHeightAction.hpp b/src/openrct2/actions/WaterSetHeightAction.hpp new file mode 100644 index 0000000000..22dad6cf5a --- /dev/null +++ b/src/openrct2/actions/WaterSetHeightAction.hpp @@ -0,0 +1,161 @@ +/***************************************************************************** + * Copyright (c) 2014-2018 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 "../world/Surface.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(WaterSetHeightAction, GAME_COMMAND_SET_WATER_HEIGHT, GameActionResult) +{ +private: + CoordsXY _coords; + uint8_t _height; + +public: + WaterSetHeightAction() + { + } + WaterSetHeightAction(CoordsXY coords, uint8_t height) + : _coords(coords) + , _height(height) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override + { + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_height); + } + + GameActionResult::Ptr Query() const override + { + auto res = MakeResult(); + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + res->Position.x = _coords.x + 16; + res->Position.y = _coords.y + 16; + res->Position.z = _height * 8; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode + && gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) + { + return MakeResult(GA_ERROR::DISALLOWED, STR_NONE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); + } + + rct_string_id errorMsg = CheckParameters(); + if (errorMsg != STR_NONE) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_NONE, errorMsg); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(_coords)) + { + return MakeResult(GA_ERROR::DISALLOWED, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + SurfaceElement* surfaceElement = map_get_surface_element_at(_coords)->AsSurface(); + if (surfaceElement == nullptr) + { + log_error("Could not find surface element at: x %u, y %u", _coords.x, _coords.y); + return MakeResult(GA_ERROR::UNKNOWN, STR_NONE); + } + + int32_t zHigh = surfaceElement->base_height; + int32_t zLow = _height; + if (surfaceElement->GetWaterHeight() > 0) + { + zHigh = surfaceElement->GetWaterHeight() * 2; + } + if (zLow > zHigh) + { + int32_t temp = zHigh; + zHigh = zLow; + zLow = temp; + } + + if (!map_can_construct_at(_coords.x, _coords.y, zLow, zHigh, { 0b1111, 0b1111 })) + { + return MakeResult(GA_ERROR::NO_CLEARANCE, STR_NONE, gGameCommandErrorText, gCommonFormatArgs); + } + if (surfaceElement->HasTrackThatNeedsWater()) + { + return MakeResult(GA_ERROR::DISALLOWED, STR_NONE); + } + + res->Cost = 250; + + return res; + } + + GameActionResult::Ptr Execute() const override + { + auto res = MakeResult(); + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + res->Position.x = _coords.x + 16; + res->Position.y = _coords.y + 16; + res->Position.z = _height * 8; + + int32_t surfaceHeight = tile_element_height(_coords.x, _coords.y) & 0xFFFF; + footpath_remove_litter(_coords.x, _coords.y, surfaceHeight); + if (!gCheatsDisableClearanceChecks) + wall_remove_at_z(_coords.x, _coords.y, surfaceHeight); + + + SurfaceElement* surfaceElement = map_get_surface_element_at(_coords)->AsSurface(); + if (surfaceElement == nullptr) + { + log_error("Could not find surface element at: x %u, y %u", _coords.x, _coords.y); + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); + } + + if (_height > surfaceElement->base_height) + { + surfaceElement->SetWaterHeight(_height / 2); + } + else + { + surfaceElement->SetWaterHeight(0); + } + map_invalidate_tile_full(_coords.x, _coords.y); + + res->Cost = 250; + + return res; + } + +private: + rct_string_id CheckParameters() const + { + if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY) + { + return STR_OFF_EDGE_OF_MAP; + } + + if (_height < MINIMUM_WATER_HEIGHT) + { + return STR_TOO_LOW; + } + + if (_height > MAXIMUM_WATER_HEIGHT) + { + return STR_TOO_HIGH; + } + + return STR_NONE; + } +}; diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 5bf41a46d7..cc250437db 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -19,6 +19,7 @@ #include "../actions/LargeSceneryRemoveAction.hpp" #include "../actions/SmallSceneryRemoveAction.hpp" #include "../actions/WallRemoveAction.hpp" +#include "../actions/WaterSetHeightAction.hpp" #include "../audio/audio.h" #include "../config/Config.h" #include "../core/Guard.hpp" @@ -1402,12 +1403,18 @@ money32 raise_water(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t flag height = tile_element->base_height + 2; } - money32 tileCost = game_do_command( - xi, flags, yi, (max_height << 8) + height, GAME_COMMAND_SET_WATER_HEIGHT, 0, 0); - if (tileCost == MONEY32_UNDEFINED) + auto waterSetHeightAction = WaterSetHeightAction({ xi, yi }, height); + waterSetHeightAction.SetFlags(flags); + auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&waterSetHeightAction) + : GameActions::QueryNested(&waterSetHeightAction); + if (res->Error != GA_ERROR::OK) + { + gGameCommandErrorText = res->ErrorMessage; + // set gCommonFormatArguments to res->ErrorArgs return MONEY32_UNDEFINED; + } - cost += tileCost; + cost += res->Cost; waterHeightChanged = true; } } @@ -1490,11 +1497,18 @@ money32 lower_water(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t flag if (height < min_height) continue; height -= 2; - int32_t tileCost = game_do_command( - xi, flags, yi, (min_height << 8) + height, GAME_COMMAND_SET_WATER_HEIGHT, 0, 0); - if (tileCost == MONEY32_UNDEFINED) + auto waterSetHeightAction = WaterSetHeightAction({ xi, yi }, height); + waterSetHeightAction.SetFlags(flags); + auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&waterSetHeightAction) + : GameActions::QueryNested(&waterSetHeightAction); + if (res->Error != GA_ERROR::OK) + { + gGameCommandErrorText = res->ErrorMessage; + // set gCommonFormatArguments to res->ErrorArgs return MONEY32_UNDEFINED; - cost += tileCost; + } + + cost += res->Cost; waterHeightChanged = true; } } diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 454774548a..1a517b1154 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -19,6 +19,8 @@ #define MINIMUM_LAND_HEIGHT 2 #define MAXIMUM_LAND_HEIGHT 142 +#define MINIMUM_WATER_HEIGHT 2 +#define MAXIMUM_WATER_HEIGHT 58 #define MINIMUM_MAP_SIZE_TECHNICAL 15 #define MAXIMUM_MAP_SIZE_TECHNICAL 256