1 /*****************************************************************************
2 * Copyright (c) 2014-2020 OpenRCT2 developers
3 *
4 * For a complete list of all authors, please refer to contributors.md
5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6 *
7 * OpenRCT2 is licensed under the GNU General Public License version 3.
8 *****************************************************************************/
9
10 #include "FootpathRemoveAction.h"
11
12 #include "../Cheats.h"
13 #include "../OpenRCT2.h"
14 #include "../core/MemoryStream.h"
15 #include "../interface/Window.h"
16 #include "../localisation/StringIds.h"
17 #include "../management/Finance.h"
18 #include "../world/Footpath.h"
19 #include "../world/Location.hpp"
20 #include "../world/Park.h"
21 #include "../world/Wall.h"
22 #include "BannerRemoveAction.h"
23
FootpathRemoveAction(const CoordsXYZ & location)24 FootpathRemoveAction::FootpathRemoveAction(const CoordsXYZ& location)
25 : _loc(location)
26 {
27 }
28
AcceptParameters(GameActionParameterVisitor & visitor)29 void FootpathRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor)
30 {
31 visitor.Visit(_loc);
32 }
33
GetActionFlags() const34 uint16_t FootpathRemoveAction::GetActionFlags() const
35 {
36 return GameAction::GetActionFlags();
37 }
38
Serialise(DataSerialiser & stream)39 void FootpathRemoveAction::Serialise(DataSerialiser& stream)
40 {
41 GameAction::Serialise(stream);
42
43 stream << DS_TAG(_loc);
44 }
45
Query() const46 GameActions::Result::Ptr FootpathRemoveAction::Query() const
47 {
48 GameActions::Result::Ptr res = std::make_unique<GameActions::Result>();
49 res->Cost = 0;
50 res->Expenditure = ExpenditureType::Landscaping;
51 res->Position = { _loc.x + 16, _loc.y + 16, _loc.z };
52
53 if (!LocationValid(_loc))
54 {
55 return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK);
56 }
57
58 if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc))
59 {
60 return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK);
61 }
62
63 TileElement* footpathElement = GetFootpathElement();
64 if (footpathElement == nullptr)
65 {
66 return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_NONE);
67 }
68
69 res->Cost = GetRefundPrice(footpathElement);
70
71 return res;
72 }
73
Execute() const74 GameActions::Result::Ptr FootpathRemoveAction::Execute() const
75 {
76 GameActions::Result::Ptr res = std::make_unique<GameActions::Result>();
77 res->Cost = 0;
78 res->Expenditure = ExpenditureType::Landscaping;
79 res->Position = { _loc.x + 16, _loc.y + 16, _loc.z };
80
81 if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
82 {
83 footpath_interrupt_peeps(_loc);
84 footpath_remove_litter(_loc);
85 }
86
87 TileElement* footpathElement = GetFootpathElement();
88 if (footpathElement != nullptr)
89 {
90 footpath_queue_chain_reset();
91 auto bannerRes = RemoveBannersAtElement(_loc, footpathElement);
92 if (bannerRes->Error == GameActions::Status::Ok)
93 {
94 res->Cost += bannerRes->Cost;
95 }
96 footpath_remove_edges_at(_loc, footpathElement);
97 map_invalidate_tile_full(_loc);
98 tile_element_remove(footpathElement);
99 footpath_update_queue_chains();
100
101 // Remove the spawn point (if there is one in the current tile)
102 gPeepSpawns.erase(
103 std::remove_if(
104 gPeepSpawns.begin(), gPeepSpawns.end(),
105 [this](const CoordsXYZ& spawn) {
106 {
107 return spawn.ToTileStart() == _loc.ToTileStart();
108 }
109 }),
110 gPeepSpawns.end());
111 }
112 else
113 {
114 return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_NONE);
115 }
116
117 res->Cost += GetRefundPrice(footpathElement);
118
119 return res;
120 }
121
GetFootpathElement() const122 TileElement* FootpathRemoveAction::GetFootpathElement() const
123 {
124 bool getGhostPath = GetFlags() & GAME_COMMAND_FLAG_GHOST;
125
126 TileElement* tileElement = map_get_footpath_element(_loc);
127 TileElement* footpathElement = nullptr;
128 if (tileElement != nullptr)
129 {
130 if (getGhostPath && !tileElement->IsGhost())
131 {
132 while (!(tileElement++)->IsLastForTile())
133 {
134 if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH && !tileElement->IsGhost())
135 {
136 continue;
137 }
138 footpathElement = tileElement;
139 break;
140 }
141 }
142 else
143 {
144 footpathElement = tileElement;
145 }
146 }
147
148 return footpathElement;
149 }
150
GetRefundPrice(TileElement * footpathElement) const151 money32 FootpathRemoveAction::GetRefundPrice(TileElement* footpathElement) const
152 {
153 money32 cost = -MONEY(10, 00);
154 return cost;
155 }
156
157 /**
158 *
159 * rct2: 0x006BA23E
160 */
RemoveBannersAtElement(const CoordsXY & loc,TileElement * tileElement) const161 GameActions::Result::Ptr FootpathRemoveAction::RemoveBannersAtElement(const CoordsXY& loc, TileElement* tileElement) const
162 {
163 auto result = MakeResult();
164 while (!(tileElement++)->IsLastForTile())
165 {
166 if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH)
167 return result;
168
169 if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER)
170 continue;
171
172 auto bannerRemoveAction = BannerRemoveAction({ loc, tileElement->GetBaseZ(), tileElement->AsBanner()->GetPosition() });
173 bool isGhost = tileElement->IsGhost();
174 auto bannerFlags = GetFlags() | (isGhost ? static_cast<uint32_t>(GAME_COMMAND_FLAG_GHOST) : 0);
175 bannerRemoveAction.SetFlags(bannerFlags);
176 auto res = GameActions::ExecuteNested(&bannerRemoveAction);
177 // Ghost removal is free
178 if (res->Error == GameActions::Status::Ok && !isGhost)
179 {
180 result->Cost += res->Cost;
181 }
182 tileElement--;
183 }
184 return result;
185 }
186