mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-23 07:43:01 +01:00
Add FootpathSceneryPlaceAction
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user