1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-23 07:43:01 +01:00

Add FootpathSceneryPlaceAction

This commit is contained in:
duncanspumpkin
2019-03-01 10:53:52 +00:00
parent ef69c01da5
commit 510d71ab68
5 changed files with 200 additions and 115 deletions

View File

@@ -26,6 +26,7 @@
#include <openrct2/OpenRCT2.h>
#include <openrct2/ParkImporter.h>
#include <openrct2/actions/ClearAction.hpp>
#include <openrct2/actions/FootpathSceneryPlaceAction.hpp>
#include <openrct2/actions/LoadOrQuitAction.hpp>
#include <openrct2/actions/PauseToggleAction.hpp>
#include <openrct2/actions/SmallSceneryPlaceAction.hpp>
@@ -1816,14 +1817,18 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo
}
case SCENERY_TYPE_PATH_ITEM:
{
int32_t flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_PATH_SCENERY | (parameter_1 & 0xFF00);
auto pathItemType = parameter_3 & 0xFF;
int32_t z = (parameter_2 & 0xFF) * 8;
auto footpathSceneryPlaceAction = FootpathSceneryPlaceAction({ gridX, gridY, z }, pathItemType);
gGameCommandErrorTitle = STR_CANT_POSITION_THIS_HERE;
int32_t cost = game_do_command(gridX, flags, gridY, parameter_2, GAME_COMMAND_PLACE_PATH, parameter_3, 0);
if (cost != MONEY32_UNDEFINED)
{
audio_play_sound_at_location(SOUND_PLACE_ITEM, gCommandPosition.x, gCommandPosition.y, gCommandPosition.z);
}
footpathSceneryPlaceAction.SetCallback([](const GameAction* ga, const GameActionResult* result) {
if (result->Error != GA_ERROR::OK)
{
return;
}
audio_play_sound_at_location(SOUND_PLACE_ITEM, result->Position.x, result->Position.y, result->Position.z);
});
auto res = GameActions::Execute(&footpathSceneryPlaceAction);
break;
}
case SCENERY_TYPE_WALL:
@@ -2489,27 +2494,32 @@ static money32 try_place_ghost_scenery(
break;
}
case 1:
{
// Path Bits
// 6e265b
cost = game_do_command(
map_tile.x,
(parameter_1 & 0xFF00)
| (GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5
| GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_PATH_SCENERY),
map_tile.y, parameter_2, GAME_COMMAND_PLACE_PATH, parameter_3, 0);
auto pathItemType = parameter_3 & 0xFF;
int32_t z = (parameter_2 & 0xFF) * 8;
auto footpathSceneryPlaceAction = FootpathSceneryPlaceAction({ map_tile.x, map_tile.y, z }, pathItemType);
footpathSceneryPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED);
footpathSceneryPlaceAction.SetCallback([=](const GameAction* ga, const GameActionResult* result) {
if (result->Error != GA_ERROR::OK)
{
return;
}
gSceneryGhostPosition.x = map_tile.x;
gSceneryGhostPosition.y = map_tile.y;
gSceneryGhostPosition.z = (parameter_2 & 0xFF);
gSceneryPlacePathSlope = ((parameter_1 >> 8) & 0xFF);
gSceneryPlacePathType = ((parameter_2 >> 8) & 0xFF);
gSceneryGhostPathObjectType = parameter_3;
if (cost == MONEY32_UNDEFINED)
return cost;
gSceneryGhostPosition.x = map_tile.x;
gSceneryGhostPosition.y = map_tile.y;
gSceneryGhostPosition.z = (parameter_2 & 0xFF);
gSceneryPlacePathSlope = ((parameter_1 >> 8) & 0xFF);
gSceneryPlacePathType = ((parameter_2 >> 8) & 0xFF);
gSceneryGhostPathObjectType = parameter_3;
gSceneryGhostType |= SCENERY_GHOST_FLAG_1;
gSceneryGhostType |= SCENERY_GHOST_FLAG_1;
});
auto res = GameActions::Execute(&footpathSceneryPlaceAction);
if (res->Error != GA_ERROR::OK)
return MONEY32_UNDEFINED;
break;
}
case 2:
// Walls
// 6e26b0

View File

@@ -24,16 +24,14 @@
DEFINE_GAME_ACTION(FootpathSceneryPlaceAction, GAME_COMMAND_PLACE_FOOTPATH_SCENERY, GameActionResult)
{
private:
int32_t _x;
int32_t _y;
int32_t _z;
CoordsXYZ _loc;
uint8_t _pathItemType;
public:
FootpathSceneryPlaceAction() = default;
FootpathSceneryPlaceAction(int32_t x, int32_t y, int32_t z)
: _x(x)
, _y(y)
, _z(z)
FootpathSceneryPlaceAction(CoordsXYZ loc, uint8_t pathItemType)
: _loc(loc)
, _pathItemType(pathItemType)
{
}
@@ -46,19 +44,164 @@ public:
{
GameAction::Serialise(stream);
stream << DS_TAG(_x) << DS_TAG(_y) << DS_TAG(_z);
stream << DS_TAG(_loc) << DS_TAG(_pathItemType);
}
GameActionResult::Ptr Query() const override
{
GameActionResult::Ptr res = std::make_unique<GameActionResult>();
auto res = MakeResult();
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
res->Position = _loc;
if (!map_is_location_valid({ _loc.x, _loc.y }))
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_OFF_EDGE_OF_MAP);
}
if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode)
&& !map_is_location_owned(_loc.x, _loc.y, _loc.z / 8))
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK);
}
if (_loc.z / 8 < 2)
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_TOO_LOW);
}
if (_loc.z / 8 > 248)
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_TOO_HIGH);
}
auto tileElement = map_get_footpath_element(_loc.x / 32, _loc.y / 32, _loc.z / 8);
auto pathElement = tileElement->AsPath();
if (pathElement == nullptr)
{
log_error("Could not find path element.");
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
}
// No change
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAddition() == _pathItemType
&& !(pathElement->IsBroken()))
{
if (GetFlags() & GAME_COMMAND_FLAG_4)
return MakeResult(GA_ERROR::UNKNOWN, STR_CANT_POSITION_THIS_HERE);
return res;
}
if (_pathItemType != 0)
{
rct_scenery_entry* sceneryEntry = get_footpath_item_entry(_pathItemType - 1);
if (sceneryEntry == nullptr)
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
}
uint16_t sceneryFlags = sceneryEntry->path_bit.flags;
if ((sceneryFlags & PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE) && pathElement->IsSloped())
{
return MakeResult(
GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH);
}
if ((sceneryFlags & PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE) && pathElement->IsQueue())
{
return MakeResult(
GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA);
}
if (!(sceneryFlags & (PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER | PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW))
&& (pathElement->GetEdges()) == 0x0F)
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
}
if ((sceneryFlags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) && !pathElement->IsQueue())
{
return MakeResult(
GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA);
}
res->Cost = sceneryEntry->path_bit.price;
}
if (GetFlags() & GAME_COMMAND_FLAG_4)
return MakeResult(GA_ERROR::UNKNOWN, STR_CANT_POSITION_THIS_HERE);
// Should place a ghost?
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
{
// Check if there is something on the path already
if (pathElement->HasAddition())
{
return MakeResult(GA_ERROR::ITEM_ALREADY_PLACED, STR_CANT_POSITION_THIS_HERE);
}
}
return res;
}
GameActionResult::Ptr Execute() const override
{
GameActionResult::Ptr res = std::make_unique<GameActionResult>();
auto res = MakeResult();
res->Position = _loc;
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
auto tileElement = map_get_footpath_element(_loc.x / 32, _loc.y / 32, _loc.z / 8);
auto pathElement = tileElement->AsPath();
if (pathElement == nullptr)
{
log_error("Could not find path element.");
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
}
// No change
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAddition() == _pathItemType
&& !(pathElement->IsBroken()) && !pathElement->AdditionIsGhost())
{
return res;
}
if (_pathItemType != 0)
{
rct_scenery_entry* sceneryEntry = get_footpath_item_entry(_pathItemType - 1);
if (sceneryEntry == nullptr)
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
}
res->Cost = sceneryEntry->path_bit.price;
}
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
{
pathElement->SetAdditionIsGhost(true);
}
else
{
footpath_interrupt_peeps(_loc.x, _loc.y, _loc.z);
}
if ((_pathItemType != 0 && !(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|| (_pathItemType == 0 && pathElement->AdditionIsGhost()))
{
pathElement->SetAdditionIsGhost(false);
}
pathElement->SetAddition(_pathItemType);
pathElement->SetIsBroken(false);
if (_pathItemType != 0)
{
rct_scenery_entry* scenery_entry = get_footpath_item_entry(_pathItemType - 1);
if (scenery_entry != nullptr && scenery_entry->path_bit.flags & PATH_BIT_FLAG_IS_BIN)
{
pathElement->SetAdditionStatus(255);
}
}
map_invalidate_tile_full(_loc.x, _loc.y);
return res;
}
};

View File

@@ -76,7 +76,14 @@ public:
log_error("Could not find path element.");
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS);
}
if (!pathElement->AdditionIsGhost() && (GetFlags() & GAME_COMMAND_FLAG_GHOST))
{
log_error("Tried to remove non ghost during ghost removal.");
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_REMOVE_THIS);
}
auto res = MakeResult();
res->Position = _loc;
res->Cost = MONEY(0, 0);
return res;
}
@@ -98,7 +105,10 @@ public:
}
pathElement->SetAddition(0);
map_invalidate_tile_full(_loc.x, _loc.y);
auto res = MakeResult();
res->Position = _loc;
res->Cost = MONEY(0, 0);
return res;
}

View File

@@ -153,6 +153,8 @@ const std::array<NetworkAction, NETWORK_PERMISSION_COUNT> NetworkActions::Action
GAME_COMMAND_PLACE_PATH,
GAME_COMMAND_PLACE_PATH_FROM_TRACK,
GAME_COMMAND_REMOVE_PATH,
GAME_COMMAND_PLACE_FOOTPATH_SCENERY,
GAME_COMMAND_REMOVE_FOOTPATH_SCENERY,
},
},
NetworkAction{

View File

@@ -324,87 +324,7 @@ static money32 footpath_element_update(
}
else if (pathItemType != 0)
{
if (!(flags & GAME_COMMAND_FLAG_GHOST) && tileElement->AsPath()->GetAddition() == pathItemType
&& !(tileElement->AsPath()->IsBroken()))
{
if (flags & GAME_COMMAND_FLAG_4)
return MONEY32_UNDEFINED;
return gParkFlags & PARK_FLAGS_NO_MONEY ? 0 : gFootpathPrice;
}
if (pathItemType != 0)
{
rct_scenery_entry* scenery_entry = get_footpath_item_entry(pathItemType - 1);
uint16_t unk6 = scenery_entry->path_bit.flags;
if ((unk6 & PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE) && tileElement->AsPath()->IsSloped())
{
gGameCommandErrorText = STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH;
return MONEY32_UNDEFINED;
}
if ((unk6 & PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE) && tileElement->AsPath()->IsQueue())
{
gGameCommandErrorText = STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA;
return MONEY32_UNDEFINED;
}
if (!(unk6 & (PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER | PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW))
&& (tileElement->AsPath()->GetEdges()) == 0x0F)
{
gGameCommandErrorText = STR_NONE;
return MONEY32_UNDEFINED;
}
if ((unk6 & PATH_BIT_FLAG_IS_QUEUE_SCREEN) && !tileElement->AsPath()->IsQueue())
{
gGameCommandErrorText = STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA;
return MONEY32_UNDEFINED;
}
gFootpathPrice += scenery_entry->path_bit.price;
}
if (flags & GAME_COMMAND_FLAG_4)
return MONEY32_UNDEFINED;
// Should place a ghost?
if (flags & GAME_COMMAND_FLAG_GHOST)
{
// Check if there is something on the path already
if (tileElement->AsPath()->HasAddition())
{
gGameCommandErrorText = STR_NONE;
return MONEY32_UNDEFINED;
}
// There is nothing yet - check if we should place a ghost
if (flags & GAME_COMMAND_FLAG_APPLY)
tileElement->AsPath()->SetAdditionIsGhost(true);
}
if (!(flags & GAME_COMMAND_FLAG_APPLY))
return gParkFlags & PARK_FLAGS_NO_MONEY ? 0 : gFootpathPrice;
if ((pathItemType != 0 && !(flags & GAME_COMMAND_FLAG_GHOST))
|| (pathItemType == 0 && tileElement->AsPath()->AdditionIsGhost()))
{
tileElement->AsPath()->SetAdditionIsGhost(false);
}
tileElement->AsPath()->SetAddition(pathItemType);
tileElement->AsPath()->SetIsBroken(false);
if (pathItemType != 0)
{
rct_scenery_entry* scenery_entry = get_footpath_item_entry(pathItemType - 1);
if (scenery_entry != nullptr && scenery_entry->path_bit.flags & PATH_BIT_FLAG_IS_BIN)
{
tileElement->AsPath()->SetAdditionStatus(255);
}
}
map_invalidate_tile_full(x, y);
return gParkFlags & PARK_FLAGS_NO_MONEY ? 0 : gFootpathPrice;
Guard::Assert(false, "No longer in use. Use FootpathScenery{Place/Remove}Action.");
}
if (flags & GAME_COMMAND_FLAG_4)