From f6b610c325dea54472ccee905beaefc4e6e0a14c Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Sat, 6 Apr 2019 09:44:07 +0100 Subject: [PATCH 1/5] Implement Banner Place/Remove Actions --- src/openrct2-ui/windows/Banner.cpp | 9 +- src/openrct2-ui/windows/TopToolbar.cpp | 57 +++-- src/openrct2/Game.cpp | 45 +--- src/openrct2/actions/BannerPlaceAction.hpp | 199 ++++++++++++++++++ src/openrct2/actions/BannerRemoveAction.hpp | 155 ++++++++++++++ src/openrct2/actions/FootpathRemoveAction.hpp | 24 ++- .../actions/GameActionRegistration.cpp | 4 + src/openrct2/windows/_legacy.cpp | 13 -- src/openrct2/world/Banner.cpp | 191 ----------------- src/openrct2/world/Banner.h | 2 - src/openrct2/world/Footpath.cpp | 19 -- src/openrct2/world/Footpath.h | 1 - src/openrct2/world/Map.cpp | 10 +- src/openrct2/world/Map.h | 4 - src/openrct2/world/Scenery.cpp | 9 +- 15 files changed, 445 insertions(+), 297 deletions(-) create mode 100644 src/openrct2/actions/BannerPlaceAction.hpp create mode 100644 src/openrct2/actions/BannerRemoveAction.hpp diff --git a/src/openrct2-ui/windows/Banner.cpp b/src/openrct2-ui/windows/Banner.cpp index 3fe1b278f6..08237a7d8f 100644 --- a/src/openrct2-ui/windows/Banner.cpp +++ b/src/openrct2-ui/windows/Banner.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -188,10 +189,12 @@ static void window_banner_mouseup(rct_window* w, rct_widgetindex widgetIndex) window_close(w); break; case WIDX_BANNER_DEMOLISH: - game_do_command( - x, 1, y, tile_element->base_height | (tile_element->AsBanner()->GetPosition() << 8), GAME_COMMAND_REMOVE_BANNER, - 0, 0); + { + auto bannerRemoveAction = BannerRemoveAction( + { x, y, tile_element->base_height * 8, tile_element->AsBanner()->GetPosition() }); + GameActions::Execute(&bannerRemoveAction); break; + } case WIDX_BANNER_TEXT: window_text_input_open( w, WIDX_BANNER_TEXT, STR_BANNER_TEXT, STR_ENTER_BANNER_TEXT, gBanners[w->number].string_idx, 0, 32); diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 855d53d892..c842b743f3 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 @@ -1920,12 +1921,25 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo } case SCENERY_TYPE_BANNER: { - int32_t flags = (parameter_1 & 0xFF00) | GAME_COMMAND_FLAG_APPLY; - - gGameCommandErrorTitle = STR_CANT_POSITION_THIS_HERE; - game_command_callback = game_command_callback_place_banner; - game_do_command( - gridX, flags, gridY, parameter_2, GAME_COMMAND_PLACE_BANNER, parameter_3, gWindowSceneryPrimaryColour); + uint8_t direction = (parameter_2 >> 8) & 0xFF; + CoordsXYZD loc{ gridX, gridY, (parameter_2 & 0xFF) * 16, direction }; + auto primaryColour = gWindowSceneryPrimaryColour; + auto bannerType = (parameter_1 & 0xFF00) >> 8; + auto bannerIndex = create_new_banner(0); + if (bannerIndex == BANNER_INDEX_NULL) + { + context_show_error(STR_CANT_POSITION_THIS_HERE, STR_TOO_MANY_BANNERS_IN_GAME); + break; + } + auto bannerPlaceAction = BannerPlaceAction(loc, bannerType, bannerIndex, primaryColour); + bannerPlaceAction.SetCallback([=](const GameAction* ga, const GameActionResult* result) { + if (result->Error == GA_ERROR::OK) + { + audio_play_sound_at_location(SOUND_PLACE_ITEM, result->Position.x, result->Position.y, result->Position.z); + context_open_detail_window(WD_BANNER, bannerIndex); + } + }); + GameActions::Execute(&bannerPlaceAction); break; } } @@ -2611,20 +2625,35 @@ static money32 try_place_ghost_scenery( break; } case 4: + { // Banners // 6e2612 - cost = game_do_command( - map_tile.x, parameter_1 | 0x69, map_tile.y, parameter_2, GAME_COMMAND_PLACE_BANNER, parameter_3, 0); + uint8_t direction = (parameter_2 >> 8) & 0xFF; + CoordsXYZD loc{ map_tile.x, map_tile.y, (parameter_2 & 0xFF) * 16, direction }; + auto primaryColour = gWindowSceneryPrimaryColour; + auto bannerType = (parameter_1 & 0xFF00) >> 8; + auto bannerIndex = create_new_banner(0); + if (bannerIndex == BANNER_INDEX_NULL) + { + // Silently fail as this is just for the ghost + break; + } + auto bannerPlaceAction = BannerPlaceAction(loc, bannerType, bannerIndex, primaryColour); + bannerPlaceAction.SetFlags( + GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND); + auto res = GameActions::Execute(&bannerPlaceAction); - if (cost == MONEY32_UNDEFINED) - return cost; + if (res->Error != GA_ERROR::OK) + return MONEY32_UNDEFINED; - gSceneryGhostPosition.x = map_tile.x; - gSceneryGhostPosition.y = map_tile.y; - gSceneryGhostPosition.z = (parameter_2 & 0xFF) * 2 + 2; - gSceneryPlaceRotation = ((parameter_2 >> 8) & 0xFF); + gSceneryGhostPosition.x = loc.x; + gSceneryGhostPosition.y = loc.y; + gSceneryGhostPosition.z = loc.z / 8 + 2; + gSceneryPlaceRotation = direction; gSceneryGhostType |= SCENERY_GHOST_FLAG_4; + cost = res->Cost; break; + } } return cost; diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 37830717af..d211f75eae 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -92,7 +92,7 @@ static GAME_COMMAND_CALLBACK_POINTER * const game_command_callback_table[] = { nullptr, nullptr, nullptr, - game_command_callback_place_banner, + nullptr, nullptr, nullptr, game_command_callback_pickup_guest, @@ -407,12 +407,6 @@ int32_t game_do_command_p( // Increment nest count gGameCommandNestLevel++; - // Remove ghost scenery so it doesn't interfere with incoming network command - if ((flags & GAME_COMMAND_FLAG_NETWORKED) && !(flags & GAME_COMMAND_FLAG_GHOST) && (command == GAME_COMMAND_PLACE_BANNER)) - { - scenery_remove_ghost_tool_placement(); - } - if (game_command_playerid == -1) { game_command_playerid = network_get_current_player_id(); @@ -608,39 +602,6 @@ void game_log_multiplayer_command(int command, const int* eax, const int* ebx, c format_string(log_msg, 256, STR_LOG_DEMOLISH_RIDE, args); network_append_server_log(log_msg); } - else if (command == GAME_COMMAND_PLACE_BANNER) - { - uint8_t flags = *ebx & 0xFF; - if (flags & GAME_COMMAND_FLAG_GHOST) - { - // Don't log ghost previews being removed - return; - } - - // Log placing scenery - char* args[1] = { - (char*)player_name, - }; - - format_string(log_msg, 256, STR_LOG_PLACE_SCENERY, args); - network_append_server_log(log_msg); - } - else if (command == GAME_COMMAND_REMOVE_BANNER) - { - uint8_t flags = *ebx & 0xFF; - if (flags & GAME_COMMAND_FLAG_GHOST) - { - // Don't log ghost previews being removed - return; - } - - // Log removing scenery - char* args[1] = { - (char*)player_name, - }; - format_string(log_msg, 256, STR_LOG_REMOVE_SCENERY, args); - network_append_server_log(log_msg); - } } void pause_toggle() @@ -1252,8 +1213,8 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = { game_command_place_track_design, nullptr, game_command_place_maze_design, - game_command_place_banner, - game_command_remove_banner, + nullptr, + nullptr, nullptr, nullptr, nullptr, diff --git a/src/openrct2/actions/BannerPlaceAction.hpp b/src/openrct2/actions/BannerPlaceAction.hpp new file mode 100644 index 0000000000..4aa2317ee6 --- /dev/null +++ b/src/openrct2/actions/BannerPlaceAction.hpp @@ -0,0 +1,199 @@ +/***************************************************************************** + * 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 "../management/Finance.h" +#include "../world/Banner.h" +#include "../world/MapAnimation.h" +#include "../world/Scenery.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(BannerPlaceAction, GAME_COMMAND_PLACE_BANNER, GameActionResult) +{ +private: + CoordsXYZD _loc; + uint8_t _bannerType{ std::numeric_limits::max() }; + uint8_t _bannerIndex{ BANNER_INDEX_NULL }; + uint8_t _primaryColour; + +public: + BannerPlaceAction() = default; + BannerPlaceAction(CoordsXYZD loc, uint8_t bannerType, uint8_t bannerIndex, uint8_t primaryColour) + : _loc(loc) + , _bannerType(bannerType) + , _bannerIndex(bannerIndex) + , _primaryColour(primaryColour) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override + { + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_bannerType) << DS_TAG(_bannerIndex) << DS_TAG(_primaryColour); + } + + GameActionResult::Ptr Query() const override + { + auto res = MakeResult(); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; + + if (!map_check_free_elements_and_reorganise(1)) + { + log_error("No free map elements."); + return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_POSITION_THIS_HERE); + } + + if (!map_is_location_valid({ _loc.x, _loc.y })) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); + } + + auto pathElement = GetValidPathElement(); + + if (pathElement == nullptr) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS); + } + + if (!map_can_build_at(_loc.x, _loc.y, _loc.z)) + { + return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + uint8_t baseHeight = _loc.z / 8 + 2; + BannerElement* existingBannerElement = map_get_banner_element_at(_loc.x / 32, _loc.y / 32, baseHeight, _loc.direction); + if (existingBannerElement != nullptr) + { + return MakeResult(GA_ERROR::ITEM_ALREADY_PLACED, STR_CANT_POSITION_THIS_HERE, STR_BANNER_SIGN_IN_THE_WAY); + } + + if (_bannerIndex == BANNER_INDEX_NULL || _bannerIndex >= MAX_BANNERS) + { + log_error("Invalid banner index, bannerIndex = %u", _bannerIndex); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); + } + + if (gBanners[_bannerIndex].type != BANNER_NULL) + { + log_error("Banner index in use, bannerIndex = %u", _bannerIndex); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); + } + + rct_scenery_entry* bannerEntry = get_banner_entry(_bannerType); + if (bannerEntry == nullptr) + { + log_error("Invalid banner object type. bannerType = ", _bannerType); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); + } + res->Cost = bannerEntry->banner.price; + return res; + } + + GameActionResult::Ptr Execute() const override + { + auto res = MakeResult(); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; + + if (!map_check_free_elements_and_reorganise(1)) + { + log_error("No free map elements."); + return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_POSITION_THIS_HERE); + } + + uint8_t baseHeight = _loc.z / 8 + 2; + + if (_bannerIndex == BANNER_INDEX_NULL || _bannerIndex >= MAX_BANNERS) + { + log_error("Invalid banner index, bannerIndex = %u", _bannerIndex); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); + } + + if (gBanners[_bannerIndex].type != BANNER_NULL) + { + log_error("Banner index in use, bannerIndex = %u", _bannerIndex); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); + } + + TileElement* newTileElement = tile_element_insert(_loc.x / 32, _loc.y / 32, baseHeight, 0); + assert(newTileElement != nullptr); + rct_banner* banner = &gBanners[_bannerIndex]; + + banner->flags = 0; + banner->string_idx = STR_DEFAULT_SIGN; + banner->text_colour = 2; + banner->type = _bannerType; + banner->colour = _primaryColour; + banner->x = _loc.x / 32; + banner->y = _loc.y / 32; + newTileElement->SetType(TILE_ELEMENT_TYPE_BANNER); + BannerElement* bannerElement = newTileElement->AsBanner(); + bannerElement->clearance_height = newTileElement->base_height + 2; + bannerElement->SetPosition(_loc.direction); + bannerElement->ResetAllowedEdges(); + bannerElement->SetIndex(_bannerIndex); + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + bannerElement->SetGhost(true); + } + map_invalidate_tile_full(_loc.x, _loc.y); + map_animation_create(MAP_ANIMATION_TYPE_BANNER, _loc.x, _loc.y, bannerElement->base_height); + + rct_scenery_entry* bannerEntry = get_banner_entry(_bannerType); + if (bannerEntry == nullptr) + { + log_error("Invalid banner object type. bannerType = ", _bannerType); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); + } + res->Cost = bannerEntry->banner.price; + return res; + } + +private: + PathElement* GetValidPathElement() const + { + TileElement* tileElement = map_get_first_element_at(_loc.x / 32, _loc.y / 32); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH) + continue; + + auto pathElement = tileElement->AsPath(); + + if (pathElement->base_height != _loc.z / 8 && pathElement->base_height != _loc.z / 8 - 2) + continue; + + if (!(pathElement->GetEdges() & (1 << _loc.direction))) + continue; + + if (pathElement->IsGhost() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + continue; + + return pathElement; + } while (!(tileElement++)->IsLastForTile()); + return nullptr; + } +}; diff --git a/src/openrct2/actions/BannerRemoveAction.hpp b/src/openrct2/actions/BannerRemoveAction.hpp new file mode 100644 index 0000000000..6ee339b408 --- /dev/null +++ b/src/openrct2/actions/BannerRemoveAction.hpp @@ -0,0 +1,155 @@ +/***************************************************************************** + * 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 "../management/Finance.h" +#include "../world/Banner.h" +#include "../world/MapAnimation.h" +#include "../world/Scenery.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(BannerRemoveAction, GAME_COMMAND_REMOVE_BANNER, GameActionResult) +{ +private: + CoordsXYZD _loc; + +public: + BannerRemoveAction() = default; + BannerRemoveAction(CoordsXYZD loc) + : _loc(loc) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override + { + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); + } + + GameActionResult::Ptr Query() const override + { + 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_REMOVE_THIS; + + if (!map_can_build_at(_loc.x, _loc.y, _loc.z - 16)) + { + return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + BannerElement* bannerElement = GetBannerElementAt(); + if (bannerElement == nullptr) + { + log_error( + "Invalid banner location, x = %d, y = %d, z = %d, direction = %d", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS); + } + + if (bannerElement->GetIndex() >= MAX_BANNERS || bannerElement->GetIndex() == BANNER_INDEX_NULL) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS); + } + + rct_banner* banner = &gBanners[bannerElement->GetIndex()]; + + if (banner == nullptr) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS); + } + + rct_scenery_entry* bannerEntry = get_banner_entry(banner->type); + if (bannerEntry != nullptr) + { + res->Cost = -((bannerEntry->banner.price * 3) / 4); + } + + return res; + } + + GameActionResult::Ptr Execute() const override + { + 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_REMOVE_THIS; + + BannerElement* bannerElement = GetBannerElementAt(); + if (bannerElement == nullptr) + { + log_error( + "Invalid banner location, x = %d, y = %d, z = %d, direction = %d", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS); + } + + if (bannerElement->GetIndex() >= MAX_BANNERS || bannerElement->GetIndex() == BANNER_INDEX_NULL) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS); + } + + rct_banner* banner = &gBanners[bannerElement->GetIndex()]; + + if (banner == nullptr) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS); + } + + rct_scenery_entry* bannerEntry = get_banner_entry(banner->type); + if (bannerEntry != nullptr) + { + res->Cost = -((bannerEntry->banner.price * 3) / 4); + } + + tile_element_remove_banner_entry(reinterpret_cast(bannerElement)); + map_invalidate_tile_zoom1(_loc.x, _loc.y, _loc.z / 8, _loc.z / 8 + 32); + bannerElement->Remove(); + + return res; + } + +private: + BannerElement* GetBannerElementAt() const + { + TileElement* tileElement = map_get_first_element_at(_loc.x / 32, _loc.y / 32); + + // Find the banner element at known z and position + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) + continue; + if (tileElement->base_height != _loc.z / 8) + continue; + if (tileElement->IsGhost() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + continue; + if (tileElement->AsBanner()->GetPosition() != _loc.direction) + continue; + + return tileElement->AsBanner(); + } while (!(tileElement++)->IsLastForTile()); + + return nullptr; + } +}; diff --git a/src/openrct2/actions/FootpathRemoveAction.hpp b/src/openrct2/actions/FootpathRemoveAction.hpp index 8869ed492b..34d8fce962 100644 --- a/src/openrct2/actions/FootpathRemoveAction.hpp +++ b/src/openrct2/actions/FootpathRemoveAction.hpp @@ -19,6 +19,7 @@ #include "../world/Location.hpp" #include "../world/Park.h" #include "../world/Wall.h" +#include "BannerRemoveAction.hpp" #include "GameAction.h" DEFINE_GAME_ACTION(FootpathRemoveAction, GAME_COMMAND_REMOVE_PATH, GameActionResult) @@ -89,7 +90,7 @@ public: if (footpathElement != nullptr) { footpath_queue_chain_reset(); - remove_banners_at_element(_x, _y, footpathElement); + RemoveBannersAtElement(_x, _y, footpathElement); footpath_remove_edges_at(_x, _y, footpathElement); map_invalidate_tile_full(_x, _y); tile_element_remove(footpathElement); @@ -140,4 +141,25 @@ private: money32 cost = -MONEY(10, 00); return cost; } + + /** + * + * rct2: 0x006BA23E + */ + void RemoveBannersAtElement(int32_t x, int32_t y, TileElement * tileElement) const + { + while (!(tileElement++)->IsLastForTile()) + { + if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH) + return; + else if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) + continue; + + auto bannerRemoveAction = BannerRemoveAction( + { x, y, tileElement->base_height * 8, tileElement->AsBanner()->GetPosition() }); + bannerRemoveAction.SetFlags(GetFlags()); + GameActions::ExecuteNested(&bannerRemoveAction); + tileElement--; + } + } }; diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index 2b50cbaaf4..e43fd171c7 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "BannerPlaceAction.hpp" +#include "BannerRemoveAction.hpp" #include "BannerSetColourAction.hpp" #include "BannerSetNameAction.hpp" #include "BannerSetStyleAction.hpp" @@ -79,6 +81,8 @@ namespace GameActions { void Register() { + Register(); + Register(); Register(); Register(); Register(); diff --git a/src/openrct2/windows/_legacy.cpp b/src/openrct2/windows/_legacy.cpp index c00e4026a5..d55d6f7029 100644 --- a/src/openrct2/windows/_legacy.cpp +++ b/src/openrct2/windows/_legacy.cpp @@ -593,19 +593,6 @@ void window_ride_construction_update_active_elements() context_broadcast_intent(&intent); } -void game_command_callback_place_banner( - [[maybe_unused]] int32_t eax, int32_t ebx, [[maybe_unused]] int32_t ecx, [[maybe_unused]] int32_t edx, - [[maybe_unused]] int32_t esi, int32_t edi, [[maybe_unused]] int32_t ebp) -{ - if (ebx != MONEY32_UNDEFINED) - { - int32_t bannerId = edi; - - audio_play_sound_at_location(SOUND_PLACE_ITEM, gCommandPosition.x, gCommandPosition.y, gCommandPosition.z); - context_open_detail_window(WD_BANNER, bannerId); - } -} - /** * * rct2: 0x0066DB3D diff --git a/src/openrct2/world/Banner.cpp b/src/openrct2/world/Banner.cpp index 6390a25eba..af42fc01d4 100644 --- a/src/openrct2/world/Banner.cpp +++ b/src/openrct2/world/Banner.cpp @@ -59,174 +59,6 @@ static uint8_t banner_get_ride_index_at(int32_t x, int32_t y, int32_t z) return resultRideIndex; } -static money32 BannerRemove(int16_t x, int16_t y, uint8_t baseHeight, uint8_t direction, uint8_t flags) -{ - int32_t z = baseHeight * 8; - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - gCommandPosition.x = x + 16; - gCommandPosition.y = y + 16; - gCommandPosition.z = z; - - if (!(flags & GAME_COMMAND_FLAG_GHOST) && game_is_paused() && !gCheatsBuildInPauseMode) - { - gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; - return MONEY32_UNDEFINED; - } - - if (!map_can_build_at(x, y, z - 16)) - { - return MONEY32_UNDEFINED; - } - - // Slight modification to the code so that it now checks height as well - // This was causing a bug with banners on two paths stacked. - BannerElement* tileElement = map_get_banner_element_at(x / 32, y / 32, baseHeight, direction); - if (tileElement == nullptr) - { - return MONEY32_UNDEFINED; - } - - rct_banner* banner = &gBanners[tileElement->GetIndex()]; - rct_scenery_entry* bannerEntry = get_banner_entry(banner->type); - money32 refund = 0; - if (bannerEntry != nullptr) - { - refund = -((bannerEntry->banner.price * 3) / 4); - } - - if (flags & GAME_COMMAND_FLAG_APPLY) - { - if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) - { - LocationXYZ16 coord; - coord.x = x + 16; - coord.y = y + 16; - coord.z = tile_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - } - - tile_element_remove_banner_entry((TileElement*)tileElement); - map_invalidate_tile_zoom1(x, y, z, z + 32); - tileElement->Remove(); - } - - if (gParkFlags & PARK_FLAGS_NO_MONEY) - { - refund = 0; - } - return refund; -} - -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) -{ - gCommandPosition.x = x + 16; - gCommandPosition.y = y + 16; - gCommandPosition.z = pathBaseHeight * 16; - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - if (game_is_paused() && !gCheatsBuildInPauseMode) - { - gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; - return MONEY32_UNDEFINED; - } - - if (!map_check_free_elements_and_reorganise(1)) - { - return MONEY32_UNDEFINED; - } - - if (!map_is_location_valid({ x, y })) - { - return MONEY32_UNDEFINED; - } - - TileElement* tileElement = map_get_first_element_at(x / 32, y / 32); - - bool pathFound = false; - do - { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH) - continue; - - if (tileElement->base_height != pathBaseHeight * 2 && tileElement->base_height != (pathBaseHeight - 1) * 2) - continue; - - if (!(tileElement->AsPath()->GetEdges() & (1 << direction))) - continue; - - pathFound = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!pathFound) - { - gGameCommandErrorText = STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS; - return MONEY32_UNDEFINED; - } - - if (!map_can_build_at(x, y, pathBaseHeight * 16)) - { - return MONEY32_UNDEFINED; - } - - uint8_t baseHeight = (pathBaseHeight + 1) * 2; - BannerElement* bannerElement = map_get_banner_element_at(x / 32, y / 32, baseHeight, direction); - if (bannerElement != nullptr) - { - gGameCommandErrorText = STR_BANNER_SIGN_IN_THE_WAY; - return MONEY32_UNDEFINED; - } - - *bannerIndex = create_new_banner(flags); - if (*bannerIndex == BANNER_INDEX_NULL) - { - return MONEY32_UNDEFINED; - } - - if (flags & GAME_COMMAND_FLAG_APPLY) - { - if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) - { - LocationXYZ16 coord; - coord.x = x + 16; - coord.y = y + 16; - coord.z = tile_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - } - - TileElement* newTileElement = tile_element_insert(x / 32, y / 32, baseHeight, 0); - assert(newTileElement != nullptr); - gBanners[*bannerIndex].type = type; - gBanners[*bannerIndex].colour = colour; - gBanners[*bannerIndex].x = x / 32; - gBanners[*bannerIndex].y = y / 32; - newTileElement->SetType(TILE_ELEMENT_TYPE_BANNER); - newTileElement->clearance_height = newTileElement->base_height + 2; - newTileElement->AsBanner()->SetPosition(direction); - newTileElement->AsBanner()->ResetAllowedEdges(); - newTileElement->AsBanner()->SetIndex(*bannerIndex); - if (flags & GAME_COMMAND_FLAG_GHOST) - { - newTileElement->SetGhost(true); - } - map_invalidate_tile_full(x, y); - map_animation_create(MAP_ANIMATION_TYPE_BANNER, x, y, newTileElement->base_height); - } - - rct_scenery_entry* bannerEntry = get_banner_entry(type); - if (bannerEntry == nullptr) - { - return MONEY32_UNDEFINED; - } - - if (gParkFlags & PARK_FLAGS_NO_MONEY) - { - return 0; - } - return bannerEntry->banner.price; -} - static BannerIndex BannerGetNewIndex() { for (BannerIndex bannerIndex = 0; bannerIndex < MAX_BANNERS; bannerIndex++) @@ -416,29 +248,6 @@ void fix_duplicated_banners() } } -/** - * - * rct2: 0x006BA058 - */ -void game_command_remove_banner( - int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, [[maybe_unused]] int32_t* edi, - [[maybe_unused]] int32_t* ebp) -{ - *ebx = BannerRemove(*eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, (*edx >> 8) & 0xFF, *ebx & 0xFF); -} - -/** - * - * rct2: 0x006B9E6D - */ -void game_command_place_banner( - int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp) -{ - *ebx = BannerPlace( - *eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, (*edx >> 8) & 0xFF, *ebp & 0xFF, (*ebx >> 8) & 0xFF, (BannerIndex*)edi, - *ebx & 0xFF); -} - BannerIndex BannerElement::GetIndex() const { return index; diff --git a/src/openrct2/world/Banner.h b/src/openrct2/world/Banner.h index 51cbb26b80..962bfb119f 100644 --- a/src/openrct2/world/Banner.h +++ b/src/openrct2/world/Banner.h @@ -52,5 +52,3 @@ TileElement* banner_get_tile_element(BannerIndex bannerIndex); uint8_t banner_get_closest_ride_index(int32_t x, int32_t y, int32_t z); void banner_reset_broken_index(); void fix_duplicated_banners(); -void game_command_callback_place_banner( - int32_t eax, int32_t ebx, int32_t ecx, int32_t edx, int32_t esi, int32_t edi, int32_t ebp); diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 95b08537fe..762ed93d09 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -124,25 +124,6 @@ TileElement* map_get_footpath_element(int32_t x, int32_t y, int32_t z) return nullptr; } -/** - * - * rct2: 0x006BA23E - */ -void remove_banners_at_element(int32_t x, int32_t y, TileElement* tileElement) -{ - while (!(tileElement++)->IsLastForTile()) - { - if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH) - return; - else if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) - continue; - - game_do_command( - x, 1, y, tileElement->base_height | tileElement->AsBanner()->GetPosition() << 8, GAME_COMMAND_REMOVE_BANNER, 0, 0); - tileElement--; - } -} - money32 footpath_remove(int32_t x, int32_t y, int32_t z, int32_t flags) { auto action = FootpathRemoveAction(x, y, z); diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index 2575da28f0..8cd5f1967d 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -182,7 +182,6 @@ money32 footpath_remove(int32_t x, int32_t y, int32_t z, int32_t flags); money32 footpath_provisional_set(int32_t type, int32_t x, int32_t y, int32_t z, int32_t slope); void footpath_provisional_remove(); void footpath_provisional_update(); -void remove_banners_at_element(int32_t x, int32_t y, TileElement* tileElement); void footpath_get_coordinates_from_pos( int32_t screenX, int32_t screenY, int32_t* x, int32_t* y, int32_t* direction, TileElement** tileElement); void footpath_bridge_get_info_from_pos( diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 900c88b292..66c5ee7754 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -23,6 +23,7 @@ #include "../actions/SmallSceneryRemoveAction.hpp" #include "../actions/WallRemoveAction.hpp" #include "../actions/WaterSetHeightAction.hpp" +#include "../actions/BannerRemoveAction.hpp" #include "../audio/audio.h" #include "../config/Config.h" #include "../core/Guard.hpp" @@ -1808,11 +1809,12 @@ static void clear_element_at(int32_t x, int32_t y, TileElement** elementPtr) } break; case TILE_ELEMENT_TYPE_BANNER: - gGameCommandErrorTitle = STR_CANT_REMOVE_THIS; - game_do_command( - x, GAME_COMMAND_FLAG_APPLY, y, (element->base_height) | ((element->AsBanner()->GetPosition() & 3) << 8), - GAME_COMMAND_REMOVE_BANNER, 0, 0); + { + auto bannerRemoveAction = BannerRemoveAction( + { x, y, element->base_height * 8, element->AsBanner()->GetPosition() }); + GameActions::Execute(&bannerRemoveAction); break; + } default: tile_element_remove(element); break; diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 3ff6251ed6..b8a6bb281d 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -190,10 +190,6 @@ money32 map_clear_scenery(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_ 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_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_park_entrance( 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_name( diff --git a/src/openrct2/world/Scenery.cpp b/src/openrct2/world/Scenery.cpp index 5d2b0d01b1..a9e97144f7 100644 --- a/src/openrct2/world/Scenery.cpp +++ b/src/openrct2/world/Scenery.cpp @@ -16,6 +16,7 @@ #include "../actions/LargeSceneryRemoveAction.hpp" #include "../actions/SmallSceneryRemoveAction.hpp" #include "../actions/WallRemoveAction.hpp" +#include "../actions/BannerRemoveAction.hpp" #include "../common.h" #include "../localisation/Localisation.h" #include "../network/network.h" @@ -235,9 +236,11 @@ void scenery_remove_ghost_tool_placement() if (gSceneryGhostType & SCENERY_GHOST_FLAG_4) { gSceneryGhostType &= ~SCENERY_GHOST_FLAG_4; - constexpr uint32_t flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED - | GAME_COMMAND_FLAG_NO_SPEND; - game_do_command(x, flags, y, z | (gSceneryPlaceRotation << 8), GAME_COMMAND_REMOVE_BANNER, 0, 0); + + auto removeSceneryAction = BannerRemoveAction({ x, y, z * 8, gSceneryPlaceRotation }); + removeSceneryAction.SetFlags( + GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND); + GameActions::Execute(&removeSceneryAction); } } From d14637e1ca19e258598993232f3b39aa8346c2b7 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Sat, 6 Apr 2019 10:09:18 +0100 Subject: [PATCH 2/5] Fix narrowing and formatting --- src/openrct2-ui/windows/Banner.cpp | 2 +- src/openrct2-ui/windows/TopToolbar.cpp | 6 ++++-- src/openrct2/world/Map.cpp | 2 +- src/openrct2/world/Scenery.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/openrct2-ui/windows/Banner.cpp b/src/openrct2-ui/windows/Banner.cpp index 08237a7d8f..a1597cbe85 100644 --- a/src/openrct2-ui/windows/Banner.cpp +++ b/src/openrct2-ui/windows/Banner.cpp @@ -10,9 +10,9 @@ #include #include #include -#include #include #include +#include #include #include #include diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index c842b743f3..8bf483e0ba 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -1922,7 +1922,8 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo case SCENERY_TYPE_BANNER: { uint8_t direction = (parameter_2 >> 8) & 0xFF; - CoordsXYZD loc{ gridX, gridY, (parameter_2 & 0xFF) * 16, direction }; + int32_t z = (parameter_2 & 0xFF) * 16; + CoordsXYZD loc{ gridX, gridY, z, direction }; auto primaryColour = gWindowSceneryPrimaryColour; auto bannerType = (parameter_1 & 0xFF00) >> 8; auto bannerIndex = create_new_banner(0); @@ -2629,7 +2630,8 @@ static money32 try_place_ghost_scenery( // Banners // 6e2612 uint8_t direction = (parameter_2 >> 8) & 0xFF; - CoordsXYZD loc{ map_tile.x, map_tile.y, (parameter_2 & 0xFF) * 16, direction }; + int32_t z = (parameter_2 & 0xFF) * 16; + CoordsXYZD loc{ map_tile.x, map_tile.y, z, direction }; auto primaryColour = gWindowSceneryPrimaryColour; auto bannerType = (parameter_1 & 0xFF00) >> 8; auto bannerIndex = create_new_banner(0); diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 66c5ee7754..f9ce97242f 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -14,6 +14,7 @@ #include "../Game.h" #include "../Input.h" #include "../OpenRCT2.h" +#include "../actions/BannerRemoveAction.hpp" #include "../actions/FootpathRemoveAction.hpp" #include "../actions/LandLowerAction.hpp" #include "../actions/LandRaiseAction.hpp" @@ -23,7 +24,6 @@ #include "../actions/SmallSceneryRemoveAction.hpp" #include "../actions/WallRemoveAction.hpp" #include "../actions/WaterSetHeightAction.hpp" -#include "../actions/BannerRemoveAction.hpp" #include "../audio/audio.h" #include "../config/Config.h" #include "../core/Guard.hpp" diff --git a/src/openrct2/world/Scenery.cpp b/src/openrct2/world/Scenery.cpp index a9e97144f7..5d2bf86b0b 100644 --- a/src/openrct2/world/Scenery.cpp +++ b/src/openrct2/world/Scenery.cpp @@ -12,11 +12,11 @@ #include "../Cheats.h" #include "../Context.h" #include "../Game.h" +#include "../actions/BannerRemoveAction.hpp" #include "../actions/FootpathSceneryRemoveAction.hpp" #include "../actions/LargeSceneryRemoveAction.hpp" #include "../actions/SmallSceneryRemoveAction.hpp" #include "../actions/WallRemoveAction.hpp" -#include "../actions/BannerRemoveAction.hpp" #include "../common.h" #include "../localisation/Localisation.h" #include "../network/network.h" From 7f42824642a9af2e0bbbd1fb528522d5365548b4 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Sat, 6 Apr 2019 10:10:19 +0100 Subject: [PATCH 3/5] Update game.h --- src/openrct2/Game.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index 612e12f632..2627ab9d37 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -69,8 +69,8 @@ enum GAME_COMMAND GAME_COMMAND_PLACE_TRACK_DESIGN, GAME_COMMAND_START_MARKETING_CAMPAIGN, // GA GAME_COMMAND_PLACE_MAZE_DESIGN, - GAME_COMMAND_PLACE_BANNER, - GAME_COMMAND_REMOVE_BANNER, + GAME_COMMAND_PLACE_BANNER, // GA + GAME_COMMAND_REMOVE_BANNER, // GA GAME_COMMAND_SET_SCENERY_COLOUR, // GA GAME_COMMAND_SET_WALL_COLOUR, // GA GAME_COMMAND_SET_LARGE_SCENERY_COLOUR, // GA From f0df14bb0fc45c94fa4b84e5a3ac083420777316 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Thu, 2 May 2019 17:50:04 +0100 Subject: [PATCH 4/5] Use BannerIndex type --- src/openrct2/actions/BannerPlaceAction.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openrct2/actions/BannerPlaceAction.hpp b/src/openrct2/actions/BannerPlaceAction.hpp index 4aa2317ee6..25354dc617 100644 --- a/src/openrct2/actions/BannerPlaceAction.hpp +++ b/src/openrct2/actions/BannerPlaceAction.hpp @@ -20,12 +20,12 @@ DEFINE_GAME_ACTION(BannerPlaceAction, GAME_COMMAND_PLACE_BANNER, GameActionResul private: CoordsXYZD _loc; uint8_t _bannerType{ std::numeric_limits::max() }; - uint8_t _bannerIndex{ BANNER_INDEX_NULL }; + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; uint8_t _primaryColour; public: BannerPlaceAction() = default; - BannerPlaceAction(CoordsXYZD loc, uint8_t bannerType, uint8_t bannerIndex, uint8_t primaryColour) + BannerPlaceAction(CoordsXYZD loc, uint8_t bannerType, BannerIndex bannerIndex, uint8_t primaryColour) : _loc(loc) , _bannerType(bannerType) , _bannerIndex(bannerIndex) From 48bf5e10f3b50cdbe0fbb17c9d42362219ada8c9 Mon Sep 17 00:00:00 2001 From: Duncan Date: Thu, 2 May 2019 20:20:20 +0100 Subject: [PATCH 5/5] 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 6e890297ff..de7e56f261 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 "21" +#define NETWORK_STREAM_VERSION "22" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION static Peep* _pickup_peep = nullptr;