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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
199
src/openrct2/actions/BannerPlaceAction.hpp
Normal file
199
src/openrct2/actions/BannerPlaceAction.hpp
Normal 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;
|
||||
}
|
||||
};
|
||||
155
src/openrct2/actions/BannerRemoveAction.hpp
Normal file
155
src/openrct2/actions/BannerRemoveAction.hpp
Normal 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;
|
||||
}
|
||||
};
|
||||
@@ -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--;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user