diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 240f3ca4db..dd92e78d61 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1056,10 +1057,11 @@ static void repaint_scenery_tool_down(int16_t x, int16_t y, rct_widgetindex widg rct_scenery_entry* scenery_entry = get_banner_entry(banner->type); if (scenery_entry->banner.flags & BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR) { - gGameCommandErrorTitle = STR_CANT_REPAINT_THIS; - game_do_command( - grid_x, 1, grid_y, tile_element->base_height | ((tile_element->AsBanner()->GetPosition() & 0x3) << 8), - GAME_COMMAND_SET_BANNER_COLOUR, 0, gWindowSceneryPrimaryColour | (gWindowScenerySecondaryColour << 8)); + auto repaintScenery = BannerSetColourAction( + { grid_x, grid_y, tile_element->base_height * 8, tile_element->AsBanner()->GetPosition()}, + gWindowSceneryPrimaryColour); + + GameActions::Execute(&repaintScenery); } break; } diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 066e1076f2..a202acf72b 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -643,7 +643,7 @@ void game_log_multiplayer_command(int command, const int* eax, const int* ebx, c format_string(log_msg, 256, STR_LOG_REMOVE_SCENERY, args); network_append_server_log(log_msg); } - else if (command == GAME_COMMAND_SET_BANNER_COLOUR || command == GAME_COMMAND_SET_BANNER_STYLE) + else if (command == GAME_COMMAND_SET_BANNER_STYLE) { // Log editing scenery char* args[1] = { @@ -651,30 +651,6 @@ void game_log_multiplayer_command(int command, const int* eax, const int* ebx, c }; format_string(log_msg, 256, STR_LOG_EDIT_SCENERY, args); network_append_server_log(log_msg); - if (command == GAME_COMMAND_SET_BANNER_NAME || command == GAME_COMMAND_SET_SIGN_NAME) - { - static char banner_name[128]; - - std::fill_n(banner_name, sizeof(banner_name), ' '); - int nameChunkIndex = *eax & 0xFFFF; - - int nameChunkOffset = nameChunkIndex - 1; - if (nameChunkOffset < 0) - nameChunkOffset = 2; - nameChunkOffset *= 12; - nameChunkOffset = std::min(nameChunkOffset, (int32_t)(std::size(banner_name) - 12)); - std::memcpy(banner_name + nameChunkOffset + 0, edx, 4); - std::memcpy(banner_name + nameChunkOffset + 4, ebp, 4); - std::memcpy(banner_name + nameChunkOffset + 8, edi, 4); - banner_name[sizeof(banner_name) - 1] = '\0'; - - char* args_sign[2] = { - (char*)player_name, - (char*)banner_name, - }; - format_string(log_msg, 256, STR_LOG_SET_SIGN_NAME, args_sign); - network_append_server_log(log_msg); - } } } @@ -1292,7 +1268,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = { nullptr, nullptr, nullptr, - game_command_set_banner_colour, + nullptr, game_command_set_land_ownership, nullptr, nullptr, diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index 4e48f867c3..c954315318 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -74,7 +74,7 @@ enum GAME_COMMAND GAME_COMMAND_SET_SCENERY_COLOUR, // GA GAME_COMMAND_SET_WALL_COLOUR, // GA GAME_COMMAND_SET_LARGE_SCENERY_COLOUR, // GA - GAME_COMMAND_SET_BANNER_COLOUR, + GAME_COMMAND_SET_BANNER_COLOUR, // GA GAME_COMMAND_SET_LAND_OWNERSHIP, GAME_COMMAND_CLEAR_SCENERY, // GA GAME_COMMAND_SET_BANNER_NAME, // GA diff --git a/src/openrct2/actions/BannerSetColourAction.hpp b/src/openrct2/actions/BannerSetColourAction.hpp new file mode 100644 index 0000000000..5235d154e4 --- /dev/null +++ b/src/openrct2/actions/BannerSetColourAction.hpp @@ -0,0 +1,110 @@ +/***************************************************************************** + * 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 "../management/Finance.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(BannerSetColourAction, GAME_COMMAND_SET_BANNER_COLOUR, GameActionResult) +{ +private: + CoordsXYZD _loc; + uint8_t _primaryColour; + +public: + BannerSetColourAction() = default; + + BannerSetColourAction(CoordsXYZD loc, uint8_t primaryColour) + : _loc(loc) + , _primaryColour(primaryColour) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED; + } + + void Serialise(DataSerialiser & stream) override + { + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_primaryColour); + } + + GameActionResult::Ptr Query() const override + { + return QueryExecute(false); + } + + GameActionResult::Ptr Execute() const override + { + return QueryExecute(true); + } + +private: + GameActionResult::Ptr QueryExecute(bool isExecuting) const + { + auto res = MakeResult(); + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->ErrorTitle = STR_CANT_REPAINT_THIS; + + if (_loc.x < 0 || _loc.y < 0 || _loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY) + { + log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REPAINT_THIS); + } + + if (_primaryColour > 31) + { + log_error("Invalid primary colour: colour = %u", _primaryColour); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REPAINT_THIS); + } + + if (!map_can_build_at(_loc.x, _loc.y, _loc.z - 16)) + { + return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto bannerElement = map_get_banner_element_at(_loc.x / 32, _loc.y / 32, _loc.z / 8, _loc.direction); + + if (bannerElement == nullptr) + { + log_error( + "Could not find banner at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GA_ERROR::UNKNOWN, STR_CANT_REPAINT_THIS); + } + + auto index = bannerElement->GetIndex(); + if (index > MAX_BANNERS || index == BANNER_INDEX_NULL) + { + log_error("Invalid banner index: index = %u", index); + return MakeResult(GA_ERROR::UNKNOWN, STR_CANT_REPAINT_THIS); + } + + if (isExecuting) + { + auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); + intent.putExtra(INTENT_EXTRA_BANNER_INDEX, index); + context_broadcast_intent(&intent); + + gBanners[index].colour = _primaryColour; + map_invalidate_tile_zoom1(_loc.x, _loc.y, _loc.z, _loc.z + 32); + } + + return res; + } +}; diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index bf29777317..8ebf7cebe0 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -7,6 +7,7 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "BannerSetColourAction.hpp" #include "BannerSetNameAction.hpp" #include "ClearAction.hpp" #include "ClimateSetAction.hpp" @@ -75,6 +76,7 @@ namespace GameActions { void Register() { + Register(); Register(); Register(); Register(); diff --git a/src/openrct2/world/Banner.cpp b/src/openrct2/world/Banner.cpp index 278dd327fd..1162f26470 100644 --- a/src/openrct2/world/Banner.cpp +++ b/src/openrct2/world/Banner.cpp @@ -117,52 +117,6 @@ static money32 BannerRemove(int16_t x, int16_t y, uint8_t baseHeight, uint8_t di return refund; } -static money32 BannerSetColour(int16_t x, int16_t y, uint8_t baseHeight, uint8_t direction, uint8_t colour, uint8_t flags) -{ - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - int32_t z = (baseHeight * 8); - gCommandPosition.x = x + 16; - gCommandPosition.y = y + 16; - gCommandPosition.z = z; - - if (!map_can_build_at(x, y, z - 16)) - { - return MONEY32_UNDEFINED; - } - - if (flags & GAME_COMMAND_FLAG_APPLY) - { - TileElement* tileElement = map_get_first_element_at(x / 32, y / 32); - - bool found = false; - do - { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) - continue; - - if (tileElement->AsBanner()->GetPosition() != direction) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - return MONEY32_UNDEFINED; - } - - auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); - intent.putExtra(INTENT_EXTRA_BANNER_INDEX, tileElement->AsBanner()->GetIndex()); - context_broadcast_intent(&intent); - - gBanners[tileElement->AsBanner()->GetIndex()].colour = colour; - map_invalidate_tile_zoom1(x, y, z, z + 32); - } - - return 0; -} - static money32 BannerPlace( int16_t x, int16_t y, uint8_t pathBaseHeight, uint8_t direction, uint8_t colour, uint8_t type, BannerIndex* bannerIndex, uint8_t flags) @@ -540,17 +494,6 @@ void game_command_remove_banner( *ebx = BannerRemove(*eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, (*edx >> 8) & 0xFF, *ebx & 0xFF); } -/** - * - * rct2: 0x006BA16A - */ -void game_command_set_banner_colour( - int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, [[maybe_unused]] int32_t* edi, - int32_t* ebp) -{ - *ebx = BannerSetColour(*eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, (*edx >> 8) & 0xFF, *ebp & 0xFF, *ebx & 0xFF); -} - /** * * rct2: 0x006B9E6D diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 323c081808..0ca811bcdc 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -191,8 +191,6 @@ void game_command_set_land_ownership( int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); void game_command_remove_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_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_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_large_scenery(