1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-21 05:53:02 +01:00

Merge pull request #9059 from duncanspumpkin/banner_ga

Implement Banner Place/Remove Actions
This commit is contained in:
Duncan
2019-05-02 21:32:51 +01:00
committed by GitHub
16 changed files with 449 additions and 299 deletions

View File

@@ -12,6 +12,7 @@
#include <openrct2-ui/interface/Widget.h>
#include <openrct2-ui/windows/Window.h>
#include <openrct2/Game.h>
#include <openrct2/actions/BannerRemoveAction.hpp>
#include <openrct2/actions/BannerSetColourAction.hpp>
#include <openrct2/actions/BannerSetNameAction.hpp>
#include <openrct2/actions/BannerSetStyleAction.hpp>
@@ -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);

View File

@@ -25,6 +25,7 @@
#include <openrct2/Input.h>
#include <openrct2/OpenRCT2.h>
#include <openrct2/ParkImporter.h>
#include <openrct2/actions/BannerPlaceAction.hpp>
#include <openrct2/actions/BannerSetColourAction.hpp>
#include <openrct2/actions/ClearAction.hpp>
#include <openrct2/actions/FootpathSceneryPlaceAction.hpp>
@@ -1920,12 +1921,26 @@ 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;
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);
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 +2626,36 @@ 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;
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);
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;

View File

@@ -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,

View File

@@ -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

View File

@@ -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<uint8_t>::max() };
BannerIndex _bannerIndex{ BANNER_INDEX_NULL };
uint8_t _primaryColour;
public:
BannerPlaceAction() = default;
BannerPlaceAction(CoordsXYZD loc, uint8_t bannerType, BannerIndex 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;
}
};

View File

@@ -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<TileElement*>(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;
}
};

View File

@@ -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--;
}
}
};

View File

@@ -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<BannerPlaceAction>();
Register<BannerRemoveAction>();
Register<BannerSetColourAction>();
Register<BannerSetNameAction>();
Register<BannerSetStyleAction>();

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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(

View File

@@ -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"
@@ -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;

View File

@@ -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(

View File

@@ -12,6 +12,7 @@
#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"
@@ -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);
}
}