From 2457feb6abec974643e823e702e017e926a3cae8 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Sun, 10 Mar 2019 07:32:22 +0000 Subject: [PATCH] Create surface set style action --- .../actions/GameActionRegistration.cpp | 2 + .../actions/SurfaceSetStyleAction.hpp | 229 ++++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 src/openrct2/actions/SurfaceSetStyleAction.hpp diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index 065612940d..47ee6867af 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -51,6 +51,7 @@ #include "StaffSetCostumeAction.hpp" #include "StaffSetNameAction.hpp" #include "StaffSetOrdersAction.hpp" +#include "SurfaceSetStyleAction.hpp" #include "TrackPlaceAction.hpp" #include "TrackRemoveAction.hpp" #include "TrackSetBrakeSpeedAction.hpp" @@ -97,6 +98,7 @@ namespace GameActions Register(); Register(); Register(); + Register(); Register(); Register(); Register(); diff --git a/src/openrct2/actions/SurfaceSetStyleAction.hpp b/src/openrct2/actions/SurfaceSetStyleAction.hpp new file mode 100644 index 0000000000..f9c772a596 --- /dev/null +++ b/src/openrct2/actions/SurfaceSetStyleAction.hpp @@ -0,0 +1,229 @@ +/***************************************************************************** + * 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 "../Context.h" +#include "../object/ObjectManager.h" +#include "../object/TerrainEdgeObject.h" +#include "../object/TerrainSurfaceObject.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(SurfaceSetStyleAction, GAME_COMMAND_CHANGE_SURFACE_STYLE, GameActionResult) +{ +private: + MapRange _range; + uint8_t _surfaceStyle; + uint8_t _edgeStyle; + +public: + SurfaceSetStyleAction() + { + } + + SurfaceSetStyleAction(MapRange range, uint8_t surfaceStyle, uint8_t edgeStyle) + : _range(range) + , _surfaceStyle(surfaceStyle) + , _edgeStyle(edgeStyle) + { + } + + GameActionResult::Ptr Query() const override + { + auto res = MakeResult(); + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + + auto x0 = std::max(_range.GetLeft(), 32); + auto y0 = std::max(_range.GetTop(), 32); + auto x1 = std::min(_range.GetRight(), (int32_t)gMapSizeMaxXY); + auto y1 = std::min(_range.GetBottom(), (int32_t)gMapSizeMaxXY); + + MapRange validRange{ x0, y0, x1, y1 }; + auto& objManager = GetContext()->GetObjectManager(); + if (_surfaceStyle != 0xFF) + { + if (_surfaceStyle > 0x1F) + { + log_error("Invalid surface style."); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_CHANGE_LAND_TYPE); + } + + const auto surfaceObj = static_cast( + objManager.GetLoadedObject(OBJECT_TYPE_TERRAIN_SURFACE, _surfaceStyle)); + + if (surfaceObj == nullptr) + { + log_error("Invalid surface style."); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_CHANGE_LAND_TYPE); + } + } + + if (_edgeStyle != 0xFF) + { + if (_edgeStyle > 0xF) + { + log_error("Invalid edge style."); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_CHANGE_LAND_TYPE); + } + + const auto edgeObj = static_cast( + objManager.GetLoadedObject(OBJECT_TYPE_TERRAIN_SURFACE, _edgeStyle)); + + if (edgeObj == nullptr) + { + log_error("Invalid edge style."); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_CHANGE_LAND_TYPE); + } + } + + auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; + auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; + auto heightMid = tile_element_height(xMid, yMid) & 0xFFFF; + + res->Position.x = xMid; + res->Position.y = yMid; + res->Position.z = heightMid; + + // Do nothing if not in editor, sandbox mode or landscaping is forbidden + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode + && (gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES)) + { + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_CHANGE_LAND_TYPE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); + } + + money32 surfaceCost = 0; + money32 edgeCost = 0; + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += 32) + { + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += 32) + { + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park({ x, y })) + continue; + } + + auto tileElement = map_get_surface_element_at({ x, y }); + if (tileElement == nullptr) + { + continue; + } + + auto surfaceElement = tileElement->AsSurface(); + if (_surfaceStyle != 0xFF) + { + uint8_t curSurfaceStyle = surfaceElement->GetSurfaceStyle(); + + if (_surfaceStyle != curSurfaceStyle) + { + auto& objManager = GetContext()->GetObjectManager(); + const auto surfaceObj = static_cast( + objManager.GetLoadedObject(OBJECT_TYPE_TERRAIN_SURFACE, _surfaceStyle)); + if (surfaceObj != nullptr) + { + surfaceCost += surfaceObj->Price; + } + } + } + + if (_edgeStyle != 0xFF) + { + uint8_t curEdgeStyle = surfaceElement->GetEdgeStyle(); + + if (_edgeStyle != curEdgeStyle) + { + edgeCost += 100; + } + } + } + } + res->Cost = surfaceCost + edgeCost; + + return res; + } + + GameActionResult::Ptr Execute() const override + { + auto res = MakeResult(); + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + + auto x0 = std::max(_range.GetLeft(), 32); + auto y0 = std::max(_range.GetTop(), 32); + auto x1 = std::min(_range.GetRight(), (int32_t)gMapSizeMaxXY); + auto y1 = std::min(_range.GetBottom(), (int32_t)gMapSizeMaxXY); + + MapRange validRange{ x0, y0, x1, y1 }; + + auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; + auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; + auto heightMid = tile_element_height(xMid, yMid) & 0xFFFF; + + res->Position.x = xMid; + res->Position.y = yMid; + res->Position.z = heightMid; + + money32 surfaceCost = 0; + money32 edgeCost = 0; + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += 32) + { + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += 32) + { + auto tileElement = map_get_surface_element_at({ x, y }); + if (tileElement == nullptr) + { + continue; + } + + auto surfaceElement = tileElement->AsSurface(); + if (_surfaceStyle != 0xFF) + { + uint8_t curSurfaceStyle = surfaceElement->GetSurfaceStyle(); + + if (_surfaceStyle != curSurfaceStyle) + { + auto& objManager = GetContext()->GetObjectManager(); + const auto surfaceObj = static_cast( + objManager.GetLoadedObject(OBJECT_TYPE_TERRAIN_SURFACE, _surfaceStyle)); + if (surfaceObj != nullptr) + { + surfaceCost += surfaceObj->Price; + + surfaceElement->SetSurfaceStyle(_surfaceStyle); + + map_invalidate_tile_full(x, y); + footpath_remove_litter(x, y, tile_element_height(x, y)); + } + } + } + + if (_edgeStyle != 0xFF) + { + uint8_t curEdgeStyle = surfaceElement->GetEdgeStyle(); + + if (_edgeStyle != curEdgeStyle) + { + edgeCost += 100; + + surfaceElement->SetEdgeStyle(_edgeStyle); + map_invalidate_tile_full(x, y); + } + } + + if (surfaceElement->CanGrassGrow() && (surfaceElement->GetGrassLength() & 7) != GRASS_LENGTH_CLEAR_0) + { + surfaceElement->SetGrassLength(GRASS_LENGTH_CLEAR_0); + map_invalidate_tile_full(x, y); + } + } + } + res->Cost = surfaceCost + edgeCost; + + return res; + } +};