From f09b14ef2b9126d8b81b38b48d41289424497031 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 9 Dec 2020 23:39:10 -0700 Subject: [PATCH] Split actions hpp files into separate h and cpp files (#13548) * Split up SmallSceneryPlace/Remove Added undo function for Remove Scenery * Refactor: Balloon and Banner actions hpp=>h/cpp * Refactor: rename all action *.hpp files to *.cpp This is preparation for separation in later commits. Note that without the complete set of commits in this branch, the code will not build. * Refactor Clear, Climate, Custom, and Footpath actions hpp=>h/cpp * VSCode: add src subdirectories to includePath * Refactor Guest actions hpp=>h/cpp * Refactor Land actions hpp=>h/cpp * Refactor LargeScenery actions hpp=>h/cpp * Refactor Load, Maze, Network actions hpp=>h/cpp * Refactor Park actions hpp=>h/cpp * Refactor/style: move private function declarations in actions *.h Previous action .h files included private function declarations with private member variables, before public function declarations. This commit re-orders the header files to the following order: - public member variables - private member variables - public functions - private functions * Refactor Pause action hpp=>h/cpp * Refactor Peep, Place, Player actions hpp=>h/cpp * Refactor Ride actions hpp=>h/cpp * Refactor Scenario, Set*, Sign* actions hpp=>h/cpp * Refactor SmallScenerySetColourAction hpp=>h/cpp * Refactor Staff actions hpp=>h/cpp * Refactor Surface, Tile, Track* actions hpp=>h/cpp * Refactor Wall and Water actions hpp=>h/cpp * Fix various includes and other compile errors Update includes for tests. Move static function declarations to .h files Add explicit includes to various files that were previously implicit (the required header was a nested include in an action hpp file, and the action .h file does not include that header) Move RideSetStatus string enum to the cpp file to avoid unused imports * Xcode: modify project file for actions refactor * Cleanup whitespace and end-of-file newlines Co-authored-by: duncanspumpkin --- .vscode/c_cpp_properties.json | 2 +- OpenRCT2.xcodeproj/project.pbxproj | 795 ++++++++++++++---- src/openrct2-ui/input/KeyboardShortcut.cpp | 4 +- .../interface/ViewportInteraction.cpp | 12 +- src/openrct2-ui/windows/Banner.cpp | 8 +- src/openrct2-ui/windows/Cheats.cpp | 4 +- .../windows/EditorObjectSelection.cpp | 2 +- .../windows/EditorObjectiveOptions.cpp | 2 +- .../windows/EditorScenarioOptions.cpp | 4 +- src/openrct2-ui/windows/Finances.cpp | 4 +- src/openrct2-ui/windows/Footpath.cpp | 2 +- src/openrct2-ui/windows/Guest.cpp | 4 +- src/openrct2-ui/windows/LandRights.cpp | 2 +- src/openrct2-ui/windows/Map.cpp | 9 +- src/openrct2-ui/windows/MazeConstruction.cpp | 2 +- src/openrct2-ui/windows/Multiplayer.cpp | 2 +- src/openrct2-ui/windows/NewCampaign.cpp | 2 +- src/openrct2-ui/windows/Park.cpp | 2 +- src/openrct2-ui/windows/Player.cpp | 4 +- src/openrct2-ui/windows/Research.cpp | 2 +- src/openrct2-ui/windows/Ride.cpp | 10 +- src/openrct2-ui/windows/RideConstruction.cpp | 8 +- src/openrct2-ui/windows/Sign.cpp | 8 +- src/openrct2-ui/windows/Staff.cpp | 8 +- src/openrct2-ui/windows/StaffFirePrompt.cpp | 2 +- src/openrct2-ui/windows/StaffList.cpp | 4 +- src/openrct2-ui/windows/TileInspector.cpp | 2 +- src/openrct2-ui/windows/TitleMenu.cpp | 2 +- src/openrct2-ui/windows/TopToolbar.cpp | 38 +- src/openrct2/Cheats.cpp | 4 +- src/openrct2/Editor.cpp | 4 +- src/openrct2/Game.cpp | 2 +- src/openrct2/ReplayManager.cpp | 12 +- src/openrct2/actions/BalloonPressAction.cpp | 48 ++ src/openrct2/actions/BalloonPressAction.h | 35 + src/openrct2/actions/BalloonPressAction.hpp | 66 -- src/openrct2/actions/BannerPlaceAction.cpp | 182 ++++ src/openrct2/actions/BannerPlaceAction.h | 45 + src/openrct2/actions/BannerPlaceAction.hpp | 207 ----- src/openrct2/actions/BannerRemoveAction.cpp | 137 +++ src/openrct2/actions/BannerRemoveAction.h | 39 + src/openrct2/actions/BannerRemoveAction.hpp | 158 ---- .../actions/BannerSetColourAction.cpp | 94 +++ src/openrct2/actions/BannerSetColourAction.h | 42 + .../actions/BannerSetColourAction.hpp | 117 --- src/openrct2/actions/BannerSetNameAction.cpp | 58 ++ src/openrct2/actions/BannerSetNameAction.h | 38 + src/openrct2/actions/BannerSetNameAction.hpp | 78 -- src/openrct2/actions/BannerSetStyleAction.cpp | 142 ++++ src/openrct2/actions/BannerSetStyleAction.h | 51 ++ src/openrct2/actions/BannerSetStyleAction.hpp | 175 ---- src/openrct2/actions/ClearAction.cpp | 202 +++++ src/openrct2/actions/ClearAction.h | 80 ++ src/openrct2/actions/ClearAction.hpp | 261 ------ src/openrct2/actions/ClimateSetAction.cpp | 41 + ...limateSetAction.hpp => ClimateSetAction.h} | 37 +- src/openrct2/actions/CustomAction.cpp | 34 + .../{CustomAction.hpp => CustomAction.h} | 22 +- .../actions/FootpathAdditionPlaceAction.cpp | 191 +++++ .../actions/FootpathAdditionPlaceAction.h | 38 + .../actions/FootpathAdditionPlaceAction.hpp | 216 ----- .../actions/FootpathAdditionRemoveAction.cpp | 105 +++ .../actions/FootpathAdditionRemoveAction.h | 35 + .../actions/FootpathAdditionRemoveAction.hpp | 125 --- src/openrct2/actions/FootpathPlaceAction.cpp | 450 ++++++++++ src/openrct2/actions/FootpathPlaceAction.h | 52 ++ src/openrct2/actions/FootpathPlaceAction.hpp | 476 ----------- .../actions/FootpathPlaceFromTrackAction.cpp | 252 ++++++ .../actions/FootpathPlaceFromTrackAction.h | 44 + .../actions/FootpathPlaceFromTrackAction.hpp | 279 ------ src/openrct2/actions/FootpathRemoveAction.cpp | 174 ++++ src/openrct2/actions/FootpathRemoveAction.h | 42 + src/openrct2/actions/FootpathRemoveAction.hpp | 195 ----- src/openrct2/actions/GameActionCompat.cpp | 26 +- .../actions/GameActionRegistration.cpp | 158 ++-- src/openrct2/actions/GuestSetFlagsAction.cpp | 51 ++ src/openrct2/actions/GuestSetFlagsAction.h | 39 + src/openrct2/actions/GuestSetFlagsAction.hpp | 73 -- src/openrct2/actions/GuestSetNameAction.cpp | 86 ++ src/openrct2/actions/GuestSetNameAction.h | 48 ++ src/openrct2/actions/GuestSetNameAction.hpp | 117 --- src/openrct2/actions/LandBuyRightsAction.cpp | 149 ++++ src/openrct2/actions/LandBuyRightsAction.h | 56 ++ src/openrct2/actions/LandBuyRightsAction.hpp | 187 ---- src/openrct2/actions/LandLowerAction.cpp | 136 +++ src/openrct2/actions/LandLowerAction.h | 41 + src/openrct2/actions/LandLowerAction.hpp | 161 ---- src/openrct2/actions/LandRaiseAction.cpp | 132 +++ src/openrct2/actions/LandRaiseAction.h | 41 + src/openrct2/actions/LandRaiseAction.hpp | 157 ---- src/openrct2/actions/LandSetHeightAction.cpp | 374 ++++++++ src/openrct2/actions/LandSetHeightAction.h | 66 ++ src/openrct2/actions/LandSetHeightAction.hpp | 415 --------- src/openrct2/actions/LandSetRightsAction.cpp | 193 +++++ src/openrct2/actions/LandSetRightsAction.h | 60 ++ src/openrct2/actions/LandSetRightsAction.hpp | 236 ------ src/openrct2/actions/LandSmoothAction.cpp | 635 ++++++++++++++ src/openrct2/actions/LandSmoothAction.h | 53 ++ src/openrct2/actions/LandSmoothAction.hpp | 672 --------------- .../actions/LargeSceneryPlaceAction.cpp | 359 ++++++++ .../actions/LargeSceneryPlaceAction.h | 83 ++ .../actions/LargeSceneryPlaceAction.hpp | 424 ---------- .../actions/LargeSceneryRemoveAction.cpp | 227 +++++ .../actions/LargeSceneryRemoveAction.h | 42 + .../actions/LargeSceneryRemoveAction.hpp | 248 ------ .../actions/LargeScenerySetColourAction.cpp | 128 +++ .../actions/LargeScenerySetColourAction.h | 44 + .../actions/LargeScenerySetColourAction.hpp | 156 ---- src/openrct2/actions/LoadOrQuitAction.cpp | 44 + ...oadOrQuitAction.hpp => LoadOrQuitAction.h} | 37 +- src/openrct2/actions/MazePlaceTrackAction.cpp | 191 +++++ src/openrct2/actions/MazePlaceTrackAction.h | 34 + src/openrct2/actions/MazePlaceTrackAction.hpp | 210 ----- src/openrct2/actions/MazeSetTrackAction.cpp | 322 +++++++ src/openrct2/actions/MazeSetTrackAction.h | 65 ++ src/openrct2/actions/MazeSetTrackAction.hpp | 370 -------- .../actions/NetworkModifyGroupAction.cpp | 30 + ...pAction.hpp => NetworkModifyGroupAction.h} | 21 +- .../actions/ParkEntranceRemoveAction.cpp | 87 ++ .../actions/ParkEntranceRemoveAction.h | 38 + .../actions/ParkEntranceRemoveAction.hpp | 108 --- src/openrct2/actions/ParkMarketingAction.cpp | 81 ++ src/openrct2/actions/ParkMarketingAction.h | 42 + src/openrct2/actions/ParkMarketingAction.hpp | 105 --- src/openrct2/actions/ParkSetDateAction.cpp | 40 + ...kSetDateAction.hpp => ParkSetDateAction.h} | 31 +- src/openrct2/actions/ParkSetLoanAction.cpp | 56 ++ src/openrct2/actions/ParkSetLoanAction.h | 34 + src/openrct2/actions/ParkSetLoanAction.hpp | 76 -- src/openrct2/actions/ParkSetNameAction.cpp | 56 ++ src/openrct2/actions/ParkSetNameAction.h | 36 + src/openrct2/actions/ParkSetNameAction.hpp | 75 -- .../actions/ParkSetParameterAction.cpp | 64 ++ src/openrct2/actions/ParkSetParameterAction.h | 46 + .../actions/ParkSetParameterAction.hpp | 96 --- .../actions/ParkSetResearchFundingAction.cpp | 43 + ...ion.hpp => ParkSetResearchFundingAction.h} | 34 +- src/openrct2/actions/PauseToggleAction.cpp | 16 + ...seToggleAction.hpp => PauseToggleAction.h} | 6 +- src/openrct2/actions/PeepPickupAction.cpp | 181 ++++ src/openrct2/actions/PeepPickupAction.h | 52 ++ src/openrct2/actions/PeepPickupAction.hpp | 218 ----- .../actions/PlaceParkEntranceAction.cpp | 175 ++++ .../actions/PlaceParkEntranceAction.h | 34 + .../actions/PlaceParkEntranceAction.hpp | 195 ----- src/openrct2/actions/PlacePeepSpawnAction.cpp | 128 +++ src/openrct2/actions/PlacePeepSpawnAction.h | 34 + src/openrct2/actions/PlacePeepSpawnAction.hpp | 147 ---- src/openrct2/actions/PlayerKickAction.cpp | 28 + ...layerKickAction.hpp => PlayerKickAction.h} | 19 +- src/openrct2/actions/PlayerSetGroupAction.cpp | 28 + ...GroupAction.hpp => PlayerSetGroupAction.h} | 19 +- src/openrct2/actions/RideCreateAction.cpp | 270 ++++++ src/openrct2/actions/RideCreateAction.h | 68 ++ src/openrct2/actions/RideCreateAction.hpp | 321 ------- src/openrct2/actions/RideDemolishAction.cpp | 368 ++++++++ src/openrct2/actions/RideDemolishAction.h | 46 + src/openrct2/actions/RideDemolishAction.hpp | 392 --------- .../actions/RideEntranceExitPlaceAction.cpp | 204 +++++ .../actions/RideEntranceExitPlaceAction.h | 85 ++ .../actions/RideEntranceExitPlaceAction.hpp | 274 ------ .../actions/RideEntranceExitRemoveAction.cpp | 180 ++++ .../actions/RideEntranceExitRemoveAction.h | 43 + .../actions/RideEntranceExitRemoveAction.hpp | 206 ----- .../actions/RideSetAppearanceAction.cpp | 138 +++ .../actions/RideSetAppearanceAction.h | 55 ++ .../actions/RideSetAppearanceAction.hpp | 176 ---- src/openrct2/actions/RideSetColourScheme.hpp | 78 -- .../actions/RideSetColourSchemeAction.cpp | 55 ++ .../actions/RideSetColourSchemeAction.h | 40 + src/openrct2/actions/RideSetName.hpp | 110 --- src/openrct2/actions/RideSetNameAction.cpp | 89 ++ src/openrct2/actions/RideSetNameAction.h | 38 + src/openrct2/actions/RideSetPriceAction.cpp | 175 ++++ src/openrct2/actions/RideSetPriceAction.h | 43 + src/openrct2/actions/RideSetPriceAction.hpp | 199 ----- src/openrct2/actions/RideSetSetting.hpp | 324 ------- src/openrct2/actions/RideSetSettingAction.cpp | 281 +++++++ src/openrct2/actions/RideSetSettingAction.h | 62 ++ src/openrct2/actions/RideSetStatus.hpp | 248 ------ src/openrct2/actions/RideSetStatusAction.cpp | 227 +++++ src/openrct2/actions/RideSetStatusAction.h | 38 + src/openrct2/actions/RideSetVehicleAction.cpp | 240 ++++++ src/openrct2/actions/RideSetVehicleAction.h | 57 ++ .../actions/RideSetVehiclesAction.hpp | 278 ------ .../actions/ScenarioSetSettingAction.cpp | 245 ++++++ .../actions/ScenarioSetSettingAction.h | 62 ++ .../actions/ScenarioSetSettingAction.hpp | 293 ------- src/openrct2/actions/SetCheatAction.cpp | 732 ++++++++++++++++ src/openrct2/actions/SetCheatAction.h | 66 ++ src/openrct2/actions/SetCheatAction.hpp | 760 ----------------- .../actions/SetParkEntranceFeeAction.cpp | 45 + .../actions/SetParkEntranceFeeAction.h | 34 + .../actions/SetParkEntranceFeeAction.hpp | 64 -- src/openrct2/actions/SignSetNameAction.cpp | 70 ++ src/openrct2/actions/SignSetNameAction.h | 36 + src/openrct2/actions/SignSetNameAction.hpp | 91 -- src/openrct2/actions/SignSetStyleAction.cpp | 94 +++ src/openrct2/actions/SignSetStyleAction.h | 40 + src/openrct2/actions/SignSetStyleAction.hpp | 119 --- .../actions/SmallSceneryPlaceAction.cpp | 423 ++++++++++ .../actions/SmallSceneryPlaceAction.h | 75 ++ .../actions/SmallSceneryPlaceAction.hpp | 480 ----------- .../actions/SmallSceneryRemoveAction.cpp | 145 ++++ .../actions/SmallSceneryRemoveAction.h | 45 + .../actions/SmallSceneryRemoveAction.hpp | 168 ---- .../actions/SmallScenerySetColourAction.cpp | 90 ++ .../actions/SmallScenerySetColourAction.h | 47 ++ .../actions/SmallScenerySetColourAction.hpp | 121 --- src/openrct2/actions/StaffFireAction.cpp | 50 ++ src/openrct2/actions/StaffFireAction.h | 35 + src/openrct2/actions/StaffFireAction.hpp | 70 -- src/openrct2/actions/StaffHireNewAction.cpp | 305 +++++++ src/openrct2/actions/StaffHireNewAction.h | 71 ++ src/openrct2/actions/StaffHireNewAction.hpp | 354 -------- src/openrct2/actions/StaffSetColourAction.cpp | 58 ++ src/openrct2/actions/StaffSetColourAction.h | 36 + src/openrct2/actions/StaffSetColourAction.hpp | 79 -- .../actions/StaffSetCostumeAction.cpp | 77 ++ src/openrct2/actions/StaffSetCostumeAction.h | 58 ++ .../actions/StaffSetCostumeAction.hpp | 120 --- src/openrct2/actions/StaffSetNameAction.cpp | 80 ++ src/openrct2/actions/StaffSetNameAction.h | 37 + src/openrct2/actions/StaffSetNameAction.hpp | 102 --- src/openrct2/actions/StaffSetOrdersAction.cpp | 63 ++ src/openrct2/actions/StaffSetOrdersAction.h | 37 + src/openrct2/actions/StaffSetOrdersAction.hpp | 85 -- .../actions/StaffSetPatrolAreaAction.cpp | 87 ++ .../actions/StaffSetPatrolAreaAction.h | 37 + .../actions/StaffSetPatrolAreaAction.hpp | 109 --- .../actions/SurfaceSetStyleAction.cpp | 235 ++++++ src/openrct2/actions/SurfaceSetStyleAction.h | 34 + .../actions/SurfaceSetStyleAction.hpp | 255 ------ src/openrct2/actions/TileModifyAction.cpp | 212 +++++ src/openrct2/actions/TileModifyAction.h | 76 ++ src/openrct2/actions/TileModifyAction.hpp | 272 ------ src/openrct2/actions/TrackDesignAction.cpp | 10 +- src/openrct2/actions/TrackPlaceAction.cpp | 670 +++++++++++++++ src/openrct2/actions/TrackPlaceAction.h | 76 ++ src/openrct2/actions/TrackPlaceAction.hpp | 736 ---------------- src/openrct2/actions/TrackRemoveAction.cpp | 505 +++++++++++ src/openrct2/actions/TrackRemoveAction.h | 41 + src/openrct2/actions/TrackRemoveAction.hpp | 533 ------------ .../actions/TrackSetBrakeSpeedAction.cpp | 63 ++ .../actions/TrackSetBrakeSpeedAction.h | 43 + .../actions/TrackSetBrakeSpeedAction.hpp | 87 -- src/openrct2/actions/WallPlaceAction.cpp | 580 +++++++++++++ src/openrct2/actions/WallPlaceAction.h | 127 +++ src/openrct2/actions/WallPlaceAction.hpp | 677 --------------- src/openrct2/actions/WallRemoveAction.cpp | 109 +++ src/openrct2/actions/WallRemoveAction.h | 33 + src/openrct2/actions/WallRemoveAction.hpp | 124 --- src/openrct2/actions/WallSetColourAction.cpp | 132 +++ src/openrct2/actions/WallSetColourAction.h | 41 + src/openrct2/actions/WallSetColourAction.hpp | 162 ---- src/openrct2/actions/WaterLowerAction.cpp | 154 ++++ src/openrct2/actions/WaterLowerAction.h | 38 + src/openrct2/actions/WaterLowerAction.hpp | 173 ---- src/openrct2/actions/WaterRaiseAction.cpp | 163 ++++ src/openrct2/actions/WaterRaiseAction.h | 38 + src/openrct2/actions/WaterRaiseAction.hpp | 183 ---- src/openrct2/actions/WaterSetHeightAction.cpp | 141 ++++ src/openrct2/actions/WaterSetHeightAction.h | 39 + src/openrct2/actions/WaterSetHeightAction.hpp | 163 ---- src/openrct2/interface/InteractiveConsole.cpp | 10 +- src/openrct2/interface/Screenshot.cpp | 3 +- src/openrct2/libopenrct2.vcxproj | 238 ++++-- src/openrct2/management/Research.cpp | 2 +- src/openrct2/network/NetworkBase.cpp | 6 +- src/openrct2/peep/Staff.cpp | 5 +- src/openrct2/rct1/S4Importer.cpp | 2 +- src/openrct2/ride/Ride.cpp | 10 +- src/openrct2/ride/TrackDesign.cpp | 33 +- src/openrct2/ride/Vehicle.cpp | 2 +- src/openrct2/scripting/ScNetwork.hpp | 6 +- src/openrct2/scripting/ScriptEngine.cpp | 6 +- src/openrct2/windows/_legacy.cpp | 2 +- src/openrct2/world/Entrance.cpp | 6 +- src/openrct2/world/Footpath.cpp | 7 +- src/openrct2/world/Map.cpp | 22 +- src/openrct2/world/Park.cpp | 2 +- src/openrct2/world/Scenery.cpp | 10 +- test/tests/PlayTests.cpp | 4 +- 283 files changed, 18390 insertions(+), 16474 deletions(-) create mode 100644 src/openrct2/actions/BalloonPressAction.cpp create mode 100644 src/openrct2/actions/BalloonPressAction.h delete mode 100644 src/openrct2/actions/BalloonPressAction.hpp create mode 100644 src/openrct2/actions/BannerPlaceAction.cpp create mode 100644 src/openrct2/actions/BannerPlaceAction.h delete mode 100644 src/openrct2/actions/BannerPlaceAction.hpp create mode 100644 src/openrct2/actions/BannerRemoveAction.cpp create mode 100644 src/openrct2/actions/BannerRemoveAction.h delete mode 100644 src/openrct2/actions/BannerRemoveAction.hpp create mode 100644 src/openrct2/actions/BannerSetColourAction.cpp create mode 100644 src/openrct2/actions/BannerSetColourAction.h delete mode 100644 src/openrct2/actions/BannerSetColourAction.hpp create mode 100644 src/openrct2/actions/BannerSetNameAction.cpp create mode 100644 src/openrct2/actions/BannerSetNameAction.h delete mode 100644 src/openrct2/actions/BannerSetNameAction.hpp create mode 100644 src/openrct2/actions/BannerSetStyleAction.cpp create mode 100644 src/openrct2/actions/BannerSetStyleAction.h delete mode 100644 src/openrct2/actions/BannerSetStyleAction.hpp create mode 100644 src/openrct2/actions/ClearAction.cpp create mode 100644 src/openrct2/actions/ClearAction.h delete mode 100644 src/openrct2/actions/ClearAction.hpp create mode 100644 src/openrct2/actions/ClimateSetAction.cpp rename src/openrct2/actions/{ClimateSetAction.hpp => ClimateSetAction.h} (51%) create mode 100644 src/openrct2/actions/CustomAction.cpp rename src/openrct2/actions/{CustomAction.hpp => CustomAction.h} (61%) create mode 100644 src/openrct2/actions/FootpathAdditionPlaceAction.cpp create mode 100644 src/openrct2/actions/FootpathAdditionPlaceAction.h delete mode 100644 src/openrct2/actions/FootpathAdditionPlaceAction.hpp create mode 100644 src/openrct2/actions/FootpathAdditionRemoveAction.cpp create mode 100644 src/openrct2/actions/FootpathAdditionRemoveAction.h delete mode 100644 src/openrct2/actions/FootpathAdditionRemoveAction.hpp create mode 100644 src/openrct2/actions/FootpathPlaceAction.cpp create mode 100644 src/openrct2/actions/FootpathPlaceAction.h delete mode 100644 src/openrct2/actions/FootpathPlaceAction.hpp create mode 100644 src/openrct2/actions/FootpathPlaceFromTrackAction.cpp create mode 100644 src/openrct2/actions/FootpathPlaceFromTrackAction.h delete mode 100644 src/openrct2/actions/FootpathPlaceFromTrackAction.hpp create mode 100644 src/openrct2/actions/FootpathRemoveAction.cpp create mode 100644 src/openrct2/actions/FootpathRemoveAction.h delete mode 100644 src/openrct2/actions/FootpathRemoveAction.hpp create mode 100644 src/openrct2/actions/GuestSetFlagsAction.cpp create mode 100644 src/openrct2/actions/GuestSetFlagsAction.h delete mode 100644 src/openrct2/actions/GuestSetFlagsAction.hpp create mode 100644 src/openrct2/actions/GuestSetNameAction.cpp create mode 100644 src/openrct2/actions/GuestSetNameAction.h delete mode 100644 src/openrct2/actions/GuestSetNameAction.hpp create mode 100644 src/openrct2/actions/LandBuyRightsAction.cpp create mode 100644 src/openrct2/actions/LandBuyRightsAction.h delete mode 100644 src/openrct2/actions/LandBuyRightsAction.hpp create mode 100644 src/openrct2/actions/LandLowerAction.cpp create mode 100644 src/openrct2/actions/LandLowerAction.h delete mode 100644 src/openrct2/actions/LandLowerAction.hpp create mode 100644 src/openrct2/actions/LandRaiseAction.cpp create mode 100644 src/openrct2/actions/LandRaiseAction.h delete mode 100644 src/openrct2/actions/LandRaiseAction.hpp create mode 100644 src/openrct2/actions/LandSetHeightAction.cpp create mode 100644 src/openrct2/actions/LandSetHeightAction.h delete mode 100644 src/openrct2/actions/LandSetHeightAction.hpp create mode 100644 src/openrct2/actions/LandSetRightsAction.cpp create mode 100644 src/openrct2/actions/LandSetRightsAction.h delete mode 100644 src/openrct2/actions/LandSetRightsAction.hpp create mode 100644 src/openrct2/actions/LandSmoothAction.cpp create mode 100644 src/openrct2/actions/LandSmoothAction.h delete mode 100644 src/openrct2/actions/LandSmoothAction.hpp create mode 100644 src/openrct2/actions/LargeSceneryPlaceAction.cpp create mode 100644 src/openrct2/actions/LargeSceneryPlaceAction.h delete mode 100644 src/openrct2/actions/LargeSceneryPlaceAction.hpp create mode 100644 src/openrct2/actions/LargeSceneryRemoveAction.cpp create mode 100644 src/openrct2/actions/LargeSceneryRemoveAction.h delete mode 100644 src/openrct2/actions/LargeSceneryRemoveAction.hpp create mode 100644 src/openrct2/actions/LargeScenerySetColourAction.cpp create mode 100644 src/openrct2/actions/LargeScenerySetColourAction.h delete mode 100644 src/openrct2/actions/LargeScenerySetColourAction.hpp create mode 100644 src/openrct2/actions/LoadOrQuitAction.cpp rename src/openrct2/actions/{LoadOrQuitAction.hpp => LoadOrQuitAction.h} (51%) create mode 100644 src/openrct2/actions/MazePlaceTrackAction.cpp create mode 100644 src/openrct2/actions/MazePlaceTrackAction.h delete mode 100644 src/openrct2/actions/MazePlaceTrackAction.hpp create mode 100644 src/openrct2/actions/MazeSetTrackAction.cpp create mode 100644 src/openrct2/actions/MazeSetTrackAction.h delete mode 100644 src/openrct2/actions/MazeSetTrackAction.hpp create mode 100644 src/openrct2/actions/NetworkModifyGroupAction.cpp rename src/openrct2/actions/{NetworkModifyGroupAction.hpp => NetworkModifyGroupAction.h} (71%) create mode 100644 src/openrct2/actions/ParkEntranceRemoveAction.cpp create mode 100644 src/openrct2/actions/ParkEntranceRemoveAction.h delete mode 100644 src/openrct2/actions/ParkEntranceRemoveAction.hpp create mode 100644 src/openrct2/actions/ParkMarketingAction.cpp create mode 100644 src/openrct2/actions/ParkMarketingAction.h delete mode 100644 src/openrct2/actions/ParkMarketingAction.hpp create mode 100644 src/openrct2/actions/ParkSetDateAction.cpp rename src/openrct2/actions/{ParkSetDateAction.hpp => ParkSetDateAction.h} (53%) create mode 100644 src/openrct2/actions/ParkSetLoanAction.cpp create mode 100644 src/openrct2/actions/ParkSetLoanAction.h delete mode 100644 src/openrct2/actions/ParkSetLoanAction.hpp create mode 100644 src/openrct2/actions/ParkSetNameAction.cpp create mode 100644 src/openrct2/actions/ParkSetNameAction.h delete mode 100644 src/openrct2/actions/ParkSetNameAction.hpp create mode 100644 src/openrct2/actions/ParkSetParameterAction.cpp create mode 100644 src/openrct2/actions/ParkSetParameterAction.h delete mode 100644 src/openrct2/actions/ParkSetParameterAction.hpp create mode 100644 src/openrct2/actions/ParkSetResearchFundingAction.cpp rename src/openrct2/actions/{ParkSetResearchFundingAction.hpp => ParkSetResearchFundingAction.h} (51%) create mode 100644 src/openrct2/actions/PauseToggleAction.cpp rename src/openrct2/actions/{PauseToggleAction.hpp => PauseToggleAction.h} (86%) create mode 100644 src/openrct2/actions/PeepPickupAction.cpp create mode 100644 src/openrct2/actions/PeepPickupAction.h delete mode 100644 src/openrct2/actions/PeepPickupAction.hpp create mode 100644 src/openrct2/actions/PlaceParkEntranceAction.cpp create mode 100644 src/openrct2/actions/PlaceParkEntranceAction.h delete mode 100644 src/openrct2/actions/PlaceParkEntranceAction.hpp create mode 100644 src/openrct2/actions/PlacePeepSpawnAction.cpp create mode 100644 src/openrct2/actions/PlacePeepSpawnAction.h delete mode 100644 src/openrct2/actions/PlacePeepSpawnAction.hpp create mode 100644 src/openrct2/actions/PlayerKickAction.cpp rename src/openrct2/actions/{PlayerKickAction.hpp => PlayerKickAction.h} (68%) create mode 100644 src/openrct2/actions/PlayerSetGroupAction.cpp rename src/openrct2/actions/{PlayerSetGroupAction.hpp => PlayerSetGroupAction.h} (67%) create mode 100644 src/openrct2/actions/RideCreateAction.cpp create mode 100644 src/openrct2/actions/RideCreateAction.h delete mode 100644 src/openrct2/actions/RideCreateAction.hpp create mode 100644 src/openrct2/actions/RideDemolishAction.cpp create mode 100644 src/openrct2/actions/RideDemolishAction.h delete mode 100644 src/openrct2/actions/RideDemolishAction.hpp create mode 100644 src/openrct2/actions/RideEntranceExitPlaceAction.cpp create mode 100644 src/openrct2/actions/RideEntranceExitPlaceAction.h delete mode 100644 src/openrct2/actions/RideEntranceExitPlaceAction.hpp create mode 100644 src/openrct2/actions/RideEntranceExitRemoveAction.cpp create mode 100644 src/openrct2/actions/RideEntranceExitRemoveAction.h delete mode 100644 src/openrct2/actions/RideEntranceExitRemoveAction.hpp create mode 100644 src/openrct2/actions/RideSetAppearanceAction.cpp create mode 100644 src/openrct2/actions/RideSetAppearanceAction.h delete mode 100644 src/openrct2/actions/RideSetAppearanceAction.hpp delete mode 100644 src/openrct2/actions/RideSetColourScheme.hpp create mode 100644 src/openrct2/actions/RideSetColourSchemeAction.cpp create mode 100644 src/openrct2/actions/RideSetColourSchemeAction.h delete mode 100644 src/openrct2/actions/RideSetName.hpp create mode 100644 src/openrct2/actions/RideSetNameAction.cpp create mode 100644 src/openrct2/actions/RideSetNameAction.h create mode 100644 src/openrct2/actions/RideSetPriceAction.cpp create mode 100644 src/openrct2/actions/RideSetPriceAction.h delete mode 100644 src/openrct2/actions/RideSetPriceAction.hpp delete mode 100644 src/openrct2/actions/RideSetSetting.hpp create mode 100644 src/openrct2/actions/RideSetSettingAction.cpp create mode 100644 src/openrct2/actions/RideSetSettingAction.h delete mode 100644 src/openrct2/actions/RideSetStatus.hpp create mode 100644 src/openrct2/actions/RideSetStatusAction.cpp create mode 100644 src/openrct2/actions/RideSetStatusAction.h create mode 100644 src/openrct2/actions/RideSetVehicleAction.cpp create mode 100644 src/openrct2/actions/RideSetVehicleAction.h delete mode 100644 src/openrct2/actions/RideSetVehiclesAction.hpp create mode 100644 src/openrct2/actions/ScenarioSetSettingAction.cpp create mode 100644 src/openrct2/actions/ScenarioSetSettingAction.h delete mode 100644 src/openrct2/actions/ScenarioSetSettingAction.hpp create mode 100644 src/openrct2/actions/SetCheatAction.cpp create mode 100644 src/openrct2/actions/SetCheatAction.h delete mode 100644 src/openrct2/actions/SetCheatAction.hpp create mode 100644 src/openrct2/actions/SetParkEntranceFeeAction.cpp create mode 100644 src/openrct2/actions/SetParkEntranceFeeAction.h delete mode 100644 src/openrct2/actions/SetParkEntranceFeeAction.hpp create mode 100644 src/openrct2/actions/SignSetNameAction.cpp create mode 100644 src/openrct2/actions/SignSetNameAction.h delete mode 100644 src/openrct2/actions/SignSetNameAction.hpp create mode 100644 src/openrct2/actions/SignSetStyleAction.cpp create mode 100644 src/openrct2/actions/SignSetStyleAction.h delete mode 100644 src/openrct2/actions/SignSetStyleAction.hpp create mode 100644 src/openrct2/actions/SmallSceneryPlaceAction.cpp create mode 100644 src/openrct2/actions/SmallSceneryPlaceAction.h delete mode 100644 src/openrct2/actions/SmallSceneryPlaceAction.hpp create mode 100644 src/openrct2/actions/SmallSceneryRemoveAction.cpp create mode 100644 src/openrct2/actions/SmallSceneryRemoveAction.h delete mode 100644 src/openrct2/actions/SmallSceneryRemoveAction.hpp create mode 100644 src/openrct2/actions/SmallScenerySetColourAction.cpp create mode 100644 src/openrct2/actions/SmallScenerySetColourAction.h delete mode 100644 src/openrct2/actions/SmallScenerySetColourAction.hpp create mode 100644 src/openrct2/actions/StaffFireAction.cpp create mode 100644 src/openrct2/actions/StaffFireAction.h delete mode 100644 src/openrct2/actions/StaffFireAction.hpp create mode 100644 src/openrct2/actions/StaffHireNewAction.cpp create mode 100644 src/openrct2/actions/StaffHireNewAction.h delete mode 100644 src/openrct2/actions/StaffHireNewAction.hpp create mode 100644 src/openrct2/actions/StaffSetColourAction.cpp create mode 100644 src/openrct2/actions/StaffSetColourAction.h delete mode 100644 src/openrct2/actions/StaffSetColourAction.hpp create mode 100644 src/openrct2/actions/StaffSetCostumeAction.cpp create mode 100644 src/openrct2/actions/StaffSetCostumeAction.h delete mode 100644 src/openrct2/actions/StaffSetCostumeAction.hpp create mode 100644 src/openrct2/actions/StaffSetNameAction.cpp create mode 100644 src/openrct2/actions/StaffSetNameAction.h delete mode 100644 src/openrct2/actions/StaffSetNameAction.hpp create mode 100644 src/openrct2/actions/StaffSetOrdersAction.cpp create mode 100644 src/openrct2/actions/StaffSetOrdersAction.h delete mode 100644 src/openrct2/actions/StaffSetOrdersAction.hpp create mode 100644 src/openrct2/actions/StaffSetPatrolAreaAction.cpp create mode 100644 src/openrct2/actions/StaffSetPatrolAreaAction.h delete mode 100644 src/openrct2/actions/StaffSetPatrolAreaAction.hpp create mode 100644 src/openrct2/actions/SurfaceSetStyleAction.cpp create mode 100644 src/openrct2/actions/SurfaceSetStyleAction.h delete mode 100644 src/openrct2/actions/SurfaceSetStyleAction.hpp create mode 100644 src/openrct2/actions/TileModifyAction.cpp create mode 100644 src/openrct2/actions/TileModifyAction.h delete mode 100644 src/openrct2/actions/TileModifyAction.hpp create mode 100644 src/openrct2/actions/TrackPlaceAction.cpp create mode 100644 src/openrct2/actions/TrackPlaceAction.h delete mode 100644 src/openrct2/actions/TrackPlaceAction.hpp create mode 100644 src/openrct2/actions/TrackRemoveAction.cpp create mode 100644 src/openrct2/actions/TrackRemoveAction.h delete mode 100644 src/openrct2/actions/TrackRemoveAction.hpp create mode 100644 src/openrct2/actions/TrackSetBrakeSpeedAction.cpp create mode 100644 src/openrct2/actions/TrackSetBrakeSpeedAction.h delete mode 100644 src/openrct2/actions/TrackSetBrakeSpeedAction.hpp create mode 100644 src/openrct2/actions/WallPlaceAction.cpp create mode 100644 src/openrct2/actions/WallPlaceAction.h delete mode 100644 src/openrct2/actions/WallPlaceAction.hpp create mode 100644 src/openrct2/actions/WallRemoveAction.cpp create mode 100644 src/openrct2/actions/WallRemoveAction.h delete mode 100644 src/openrct2/actions/WallRemoveAction.hpp create mode 100644 src/openrct2/actions/WallSetColourAction.cpp create mode 100644 src/openrct2/actions/WallSetColourAction.h delete mode 100644 src/openrct2/actions/WallSetColourAction.hpp create mode 100644 src/openrct2/actions/WaterLowerAction.cpp create mode 100644 src/openrct2/actions/WaterLowerAction.h delete mode 100644 src/openrct2/actions/WaterLowerAction.hpp create mode 100644 src/openrct2/actions/WaterRaiseAction.cpp create mode 100644 src/openrct2/actions/WaterRaiseAction.h delete mode 100644 src/openrct2/actions/WaterRaiseAction.hpp create mode 100644 src/openrct2/actions/WaterSetHeightAction.cpp create mode 100644 src/openrct2/actions/WaterSetHeightAction.h delete mode 100644 src/openrct2/actions/WaterSetHeightAction.hpp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 24a763966c..c4d4bb1988 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -6,7 +6,7 @@ "/usr/include", "/usr/local/include", "${workspaceRoot}", - "${workspaceRoot}/src" + "${workspaceRoot}/src/**" ], "defines": [], "intelliSenseMode": "clang-x64", diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 14921b5b34..df74d7f231 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -70,6 +70,164 @@ 662578A625803AA90002C77E /* discord_rpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 662578A525803AA90002C77E /* discord_rpc.h */; }; 662578AD25803CE50002C77E /* libdiscord-rpc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 662578A325803A6C0002C77E /* libdiscord-rpc.a */; }; 662578AE25803D040002C77E /* libdiscord-rpc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 662578A325803A6C0002C77E /* libdiscord-rpc.a */; settings = {ATTRIBUTES = (Required, ); }; }; + 66A10EA2257F1DE100DD651A /* BalloonPressAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EA0257F1DE000DD651A /* BalloonPressAction.cpp */; }; + 66A10EA3257F1DE100DD651A /* BalloonPressAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EA1257F1DE000DD651A /* BalloonPressAction.h */; }; + 66A10EC0257F1DF800DD651A /* BannerPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EA6257F1DF600DD651A /* BannerPlaceAction.cpp */; }; + 66A10EC1257F1DF800DD651A /* FootpathAdditionRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EA7257F1DF600DD651A /* FootpathAdditionRemoveAction.h */; }; + 66A10EC2257F1DF800DD651A /* FootpathRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EA8257F1DF600DD651A /* FootpathRemoveAction.h */; }; + 66A10EC3257F1DF800DD651A /* FootpathPlaceFromTrackAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EA9257F1DF600DD651A /* FootpathPlaceFromTrackAction.cpp */; }; + 66A10EC4257F1DF800DD651A /* FootpathAdditionPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EAA257F1DF600DD651A /* FootpathAdditionPlaceAction.cpp */; }; + 66A10EC5257F1DF800DD651A /* BannerSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EAB257F1DF600DD651A /* BannerSetNameAction.cpp */; }; + 66A10EC6257F1DF800DD651A /* FootpathPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EAC257F1DF600DD651A /* FootpathPlaceAction.h */; }; + 66A10EC7257F1DF800DD651A /* FootpathRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EAD257F1DF700DD651A /* FootpathRemoveAction.cpp */; }; + 66A10EC8257F1DF800DD651A /* BannerPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EAE257F1DF700DD651A /* BannerPlaceAction.h */; }; + 66A10EC9257F1DF800DD651A /* CustomAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EAF257F1DF700DD651A /* CustomAction.h */; }; + 66A10ECA257F1DF800DD651A /* ClimateSetAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EB0257F1DF700DD651A /* ClimateSetAction.h */; }; + 66A10ECB257F1DF800DD651A /* BannerSetStyleAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB1257F1DF700DD651A /* BannerSetStyleAction.cpp */; }; + 66A10ECC257F1DF800DD651A /* ClearAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB2257F1DF700DD651A /* ClearAction.cpp */; }; + 66A10ECD257F1DF800DD651A /* BannerRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB3257F1DF700DD651A /* BannerRemoveAction.cpp */; }; + 66A10ECE257F1DF800DD651A /* BannerSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EB4257F1DF700DD651A /* BannerSetNameAction.h */; }; + 66A10ECF257F1DF800DD651A /* ClimateSetAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB5257F1DF700DD651A /* ClimateSetAction.cpp */; }; + 66A10ED0257F1DF800DD651A /* BannerSetColourAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EB6257F1DF700DD651A /* BannerSetColourAction.h */; }; + 66A10ED1257F1DF800DD651A /* CustomAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB7257F1DF700DD651A /* CustomAction.cpp */; }; + 66A10ED2257F1DF800DD651A /* FootpathAdditionRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB8257F1DF700DD651A /* FootpathAdditionRemoveAction.cpp */; }; + 66A10ED3257F1DF800DD651A /* BannerRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EB9257F1DF700DD651A /* BannerRemoveAction.h */; }; + 66A10ED4257F1DF800DD651A /* ClearAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EBA257F1DF700DD651A /* ClearAction.h */; }; + 66A10ED5257F1DF800DD651A /* BannerSetStyleAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EBB257F1DF700DD651A /* BannerSetStyleAction.h */; }; + 66A10ED6257F1DF800DD651A /* FootpathPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EBC257F1DF800DD651A /* FootpathPlaceAction.cpp */; }; + 66A10ED7257F1DF800DD651A /* FootpathPlaceFromTrackAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EBD257F1DF800DD651A /* FootpathPlaceFromTrackAction.h */; }; + 66A10ED8257F1DF800DD651A /* BannerSetColourAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EBE257F1DF800DD651A /* BannerSetColourAction.cpp */; }; + 66A10ED9257F1DF800DD651A /* FootpathAdditionPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EBF257F1DF800DD651A /* FootpathAdditionPlaceAction.h */; }; + 66A10F4C257F1E1700DD651A /* PlaceParkEntranceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EDC257F1E1000DD651A /* PlaceParkEntranceAction.h */; }; + 66A10F4D257F1E1700DD651A /* StaffSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EDD257F1E1000DD651A /* StaffSetNameAction.h */; }; + 66A10F4E257F1E1700DD651A /* PauseToggleAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EDE257F1E1000DD651A /* PauseToggleAction.h */; }; + 66A10F4F257F1E1700DD651A /* ParkSetDateAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EDF257F1E1000DD651A /* ParkSetDateAction.h */; }; + 66A10F50257F1E1700DD651A /* ParkEntranceRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EE0257F1E1000DD651A /* ParkEntranceRemoveAction.h */; }; + 66A10F51257F1E1700DD651A /* RideDemolishAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EE1257F1E1100DD651A /* RideDemolishAction.h */; }; + 66A10F52257F1E1700DD651A /* StaffSetCostumeAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EE2257F1E1100DD651A /* StaffSetCostumeAction.cpp */; }; + 66A10F53257F1E1700DD651A /* LandLowerAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EE3257F1E1100DD651A /* LandLowerAction.h */; }; + 66A10F54257F1E1700DD651A /* RideSetAppearanceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EE4257F1E1100DD651A /* RideSetAppearanceAction.h */; }; + 66A10F55257F1E1700DD651A /* SurfaceSetStyleAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EE5257F1E1100DD651A /* SurfaceSetStyleAction.cpp */; }; + 66A10F56257F1E1700DD651A /* SmallSceneryRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EE6257F1E1100DD651A /* SmallSceneryRemoveAction.h */; }; + 66A10F57257F1E1700DD651A /* RideSetAppearanceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EE7257F1E1100DD651A /* RideSetAppearanceAction.cpp */; }; + 66A10F58257F1E1700DD651A /* StaffSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EE8257F1E1100DD651A /* StaffSetNameAction.cpp */; }; + 66A10F59257F1E1700DD651A /* SetCheatAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EE9257F1E1100DD651A /* SetCheatAction.cpp */; }; + 66A10F5A257F1E1700DD651A /* GuestSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EEA257F1E1100DD651A /* GuestSetNameAction.h */; }; + 66A10F5B257F1E1700DD651A /* GuestSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EEB257F1E1100DD651A /* GuestSetNameAction.cpp */; }; + 66A10F5C257F1E1700DD651A /* SetParkEntranceFeeAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EEC257F1E1100DD651A /* SetParkEntranceFeeAction.h */; }; + 66A10F5D257F1E1700DD651A /* RideSetStatusAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EED257F1E1100DD651A /* RideSetStatusAction.h */; }; + 66A10F5E257F1E1700DD651A /* LargeSceneryRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EEE257F1E1100DD651A /* LargeSceneryRemoveAction.h */; }; + 66A10F5F257F1E1700DD651A /* SmallScenerySetColourAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EEF257F1E1200DD651A /* SmallScenerySetColourAction.h */; }; + 66A10F60257F1E1700DD651A /* ParkEntranceRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EF0257F1E1200DD651A /* ParkEntranceRemoveAction.cpp */; }; + 66A10F61257F1E1700DD651A /* PlaceParkEntranceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EF1257F1E1200DD651A /* PlaceParkEntranceAction.cpp */; }; + 66A10F62257F1E1700DD651A /* SurfaceSetStyleAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF2257F1E1200DD651A /* SurfaceSetStyleAction.h */; }; + 66A10F63257F1E1700DD651A /* PlayerKickAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF3257F1E1200DD651A /* PlayerKickAction.h */; }; + 66A10F64257F1E1700DD651A /* LandRaiseAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EF4257F1E1200DD651A /* LandRaiseAction.cpp */; }; + 66A10F65257F1E1700DD651A /* TileModifyAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF5257F1E1200DD651A /* TileModifyAction.h */; }; + 66A10F66257F1E1700DD651A /* RideSetVehicleAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EF6257F1E1200DD651A /* RideSetVehicleAction.cpp */; }; + 66A10F67257F1E1700DD651A /* RideEntranceExitPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF7257F1E1200DD651A /* RideEntranceExitPlaceAction.h */; }; + 66A10F68257F1E1800DD651A /* NetworkModifyGroupAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF8257F1E1200DD651A /* NetworkModifyGroupAction.h */; }; + 66A10F69257F1E1800DD651A /* ParkSetLoanAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF9257F1E1200DD651A /* ParkSetLoanAction.h */; }; + 66A10F6A257F1E1800DD651A /* LargeScenerySetColourAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EFA257F1E1200DD651A /* LargeScenerySetColourAction.cpp */; }; + 66A10F6B257F1E1800DD651A /* ParkSetLoanAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EFB257F1E1200DD651A /* ParkSetLoanAction.cpp */; }; + 66A10F6C257F1E1800DD651A /* LoadOrQuitAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EFC257F1E1200DD651A /* LoadOrQuitAction.cpp */; }; + 66A10F6D257F1E1800DD651A /* ParkSetParameterAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EFD257F1E1200DD651A /* ParkSetParameterAction.cpp */; }; + 66A10F6E257F1E1800DD651A /* LandRaiseAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EFE257F1E1200DD651A /* LandRaiseAction.h */; }; + 66A10F6F257F1E1800DD651A /* RideEntranceExitPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EFF257F1E1200DD651A /* RideEntranceExitPlaceAction.cpp */; }; + 66A10F70257F1E1800DD651A /* ParkSetDateAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F00257F1E1300DD651A /* ParkSetDateAction.cpp */; }; + 66A10F71257F1E1800DD651A /* StaffSetColourAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F01257F1E1300DD651A /* StaffSetColourAction.cpp */; }; + 66A10F72257F1E1800DD651A /* PlacePeepSpawnAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F02257F1E1300DD651A /* PlacePeepSpawnAction.h */; }; + 66A10F73257F1E1800DD651A /* LandSetHeightAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F03257F1E1300DD651A /* LandSetHeightAction.h */; }; + 66A10F74257F1E1800DD651A /* RideEntranceExitRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F04257F1E1300DD651A /* RideEntranceExitRemoveAction.h */; }; + 66A10F75257F1E1800DD651A /* RideSetPriceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F05257F1E1300DD651A /* RideSetPriceAction.cpp */; }; + 66A10F76257F1E1800DD651A /* SmallSceneryRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F06257F1E1300DD651A /* SmallSceneryRemoveAction.cpp */; }; + 66A10F77257F1E1800DD651A /* StaffSetOrdersAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F07257F1E1300DD651A /* StaffSetOrdersAction.h */; }; + 66A10F78257F1E1800DD651A /* StaffSetColourAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F08257F1E1300DD651A /* StaffSetColourAction.h */; }; + 66A10F79257F1E1800DD651A /* RideCreateAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F09257F1E1300DD651A /* RideCreateAction.cpp */; }; + 66A10F7A257F1E1800DD651A /* RideSetSettingAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F0A257F1E1300DD651A /* RideSetSettingAction.cpp */; }; + 66A10F7B257F1E1800DD651A /* MazeSetTrackAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F0B257F1E1300DD651A /* MazeSetTrackAction.h */; }; + 66A10F7C257F1E1800DD651A /* StaffHireNewAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F0C257F1E1300DD651A /* StaffHireNewAction.cpp */; }; + 66A10F7D257F1E1800DD651A /* ParkSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F0D257F1E1300DD651A /* ParkSetNameAction.cpp */; }; + 66A10F7E257F1E1800DD651A /* RideSetColourSchemeAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F0E257F1E1300DD651A /* RideSetColourSchemeAction.cpp */; }; + 66A10F7F257F1E1800DD651A /* MazePlaceTrackAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F0F257F1E1300DD651A /* MazePlaceTrackAction.cpp */; }; + 66A10F80257F1E1800DD651A /* NetworkModifyGroupAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F10257F1E1400DD651A /* NetworkModifyGroupAction.cpp */; }; + 66A10F81257F1E1800DD651A /* RideSetVehicleAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F11257F1E1400DD651A /* RideSetVehicleAction.h */; }; + 66A10F82257F1E1800DD651A /* PlayerSetGroupAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F12257F1E1400DD651A /* PlayerSetGroupAction.cpp */; }; + 66A10F83257F1E1800DD651A /* PlayerSetGroupAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F13257F1E1400DD651A /* PlayerSetGroupAction.h */; }; + 66A10F84257F1E1800DD651A /* StaffSetPatrolAreaAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F14257F1E1400DD651A /* StaffSetPatrolAreaAction.h */; }; + 66A10F85257F1E1800DD651A /* LandSetHeightAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F15257F1E1400DD651A /* LandSetHeightAction.cpp */; }; + 66A10F86257F1E1800DD651A /* LoadOrQuitAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F16257F1E1400DD651A /* LoadOrQuitAction.h */; }; + 66A10F87257F1E1800DD651A /* SmallSceneryPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F17257F1E1400DD651A /* SmallSceneryPlaceAction.h */; }; + 66A10F88257F1E1800DD651A /* SignSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F18257F1E1400DD651A /* SignSetNameAction.h */; }; + 66A10F89257F1E1800DD651A /* PauseToggleAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F19257F1E1400DD651A /* PauseToggleAction.cpp */; }; + 66A10F8A257F1E1800DD651A /* ParkSetResearchFundingAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1A257F1E1400DD651A /* ParkSetResearchFundingAction.h */; }; + 66A10F8B257F1E1800DD651A /* LandSmoothAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1B257F1E1400DD651A /* LandSmoothAction.h */; }; + 66A10F8C257F1E1800DD651A /* RideCreateAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1C257F1E1400DD651A /* RideCreateAction.h */; }; + 66A10F8D257F1E1800DD651A /* GuestSetFlagsAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1D257F1E1400DD651A /* GuestSetFlagsAction.h */; }; + 66A10F8E257F1E1800DD651A /* LandSetRightsAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1E257F1E1400DD651A /* LandSetRightsAction.h */; }; + 66A10F8F257F1E1800DD651A /* StaffSetCostumeAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1F257F1E1500DD651A /* StaffSetCostumeAction.h */; }; + 66A10F90257F1E1800DD651A /* MazePlaceTrackAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F20257F1E1500DD651A /* MazePlaceTrackAction.h */; }; + 66A10F91257F1E1800DD651A /* StaffHireNewAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F21257F1E1500DD651A /* StaffHireNewAction.h */; }; + 66A10F92257F1E1800DD651A /* ParkSetParameterAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F22257F1E1500DD651A /* ParkSetParameterAction.h */; }; + 66A10F93257F1E1800DD651A /* LandSmoothAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F23257F1E1500DD651A /* LandSmoothAction.cpp */; }; + 66A10F94257F1E1800DD651A /* StaffSetOrdersAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F24257F1E1500DD651A /* StaffSetOrdersAction.cpp */; }; + 66A10F95257F1E1800DD651A /* GuestSetFlagsAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F25257F1E1500DD651A /* GuestSetFlagsAction.cpp */; }; + 66A10F96257F1E1800DD651A /* SignSetStyleAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F26257F1E1500DD651A /* SignSetStyleAction.h */; }; + 66A10F97257F1E1800DD651A /* SetCheatAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F27257F1E1500DD651A /* SetCheatAction.h */; }; + 66A10F98257F1E1800DD651A /* PlacePeepSpawnAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F28257F1E1500DD651A /* PlacePeepSpawnAction.cpp */; }; + 66A10F99257F1E1800DD651A /* LargeScenerySetColourAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F29257F1E1500DD651A /* LargeScenerySetColourAction.h */; }; + 66A10F9A257F1E1800DD651A /* StaffFireAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F2A257F1E1500DD651A /* StaffFireAction.h */; }; + 66A10F9B257F1E1800DD651A /* ParkSetResearchFundingAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F2B257F1E1500DD651A /* ParkSetResearchFundingAction.cpp */; }; + 66A10F9C257F1E1800DD651A /* PeepPickupAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F2C257F1E1500DD651A /* PeepPickupAction.cpp */; }; + 66A10F9D257F1E1800DD651A /* StaffFireAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F2D257F1E1500DD651A /* StaffFireAction.cpp */; }; + 66A10F9E257F1E1800DD651A /* ParkMarketingAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F2E257F1E1600DD651A /* ParkMarketingAction.cpp */; }; + 66A10F9F257F1E1800DD651A /* LandBuyRightsAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F2F257F1E1600DD651A /* LandBuyRightsAction.h */; }; + 66A10FA0257F1E1800DD651A /* StaffSetPatrolAreaAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F30257F1E1600DD651A /* StaffSetPatrolAreaAction.cpp */; }; + 66A10FA1257F1E1800DD651A /* SmallScenerySetColourAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F31257F1E1600DD651A /* SmallScenerySetColourAction.cpp */; }; + 66A10FA2257F1E1800DD651A /* LargeSceneryPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F32257F1E1600DD651A /* LargeSceneryPlaceAction.h */; }; + 66A10FA3257F1E1800DD651A /* LandLowerAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F33257F1E1600DD651A /* LandLowerAction.cpp */; }; + 66A10FA4257F1E1800DD651A /* RideSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F34257F1E1600DD651A /* RideSetNameAction.cpp */; }; + 66A10FA5257F1E1800DD651A /* RideSetPriceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F35257F1E1600DD651A /* RideSetPriceAction.h */; }; + 66A10FA6257F1E1800DD651A /* ParkMarketingAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F36257F1E1600DD651A /* ParkMarketingAction.h */; }; + 66A10FA7257F1E1800DD651A /* PeepPickupAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F37257F1E1600DD651A /* PeepPickupAction.h */; }; + 66A10FA8257F1E1800DD651A /* RideEntranceExitRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F38257F1E1600DD651A /* RideEntranceExitRemoveAction.cpp */; }; + 66A10FA9257F1E1800DD651A /* ParkSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F39257F1E1600DD651A /* ParkSetNameAction.h */; }; + 66A10FAA257F1E1800DD651A /* SetParkEntranceFeeAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F3A257F1E1600DD651A /* SetParkEntranceFeeAction.cpp */; }; + 66A10FAB257F1E1800DD651A /* LandSetRightsAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F3B257F1E1600DD651A /* LandSetRightsAction.cpp */; }; + 66A10FAC257F1E1800DD651A /* RideSetSettingAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F3C257F1E1600DD651A /* RideSetSettingAction.h */; }; + 66A10FAD257F1E1800DD651A /* TileModifyAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F3D257F1E1700DD651A /* TileModifyAction.cpp */; }; + 66A10FAE257F1E1800DD651A /* SmallSceneryPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F3E257F1E1700DD651A /* SmallSceneryPlaceAction.cpp */; }; + 66A10FAF257F1E1800DD651A /* RideSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F3F257F1E1700DD651A /* RideSetNameAction.h */; }; + 66A10FB0257F1E1800DD651A /* SignSetStyleAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F40257F1E1700DD651A /* SignSetStyleAction.cpp */; }; + 66A10FB1257F1E1800DD651A /* RideDemolishAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F41257F1E1700DD651A /* RideDemolishAction.cpp */; }; + 66A10FB2257F1E1800DD651A /* LargeSceneryRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F42257F1E1700DD651A /* LargeSceneryRemoveAction.cpp */; }; + 66A10FB3257F1E1800DD651A /* MazeSetTrackAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F43257F1E1700DD651A /* MazeSetTrackAction.cpp */; }; + 66A10FB4257F1E1800DD651A /* ScenarioSetSettingAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F44257F1E1700DD651A /* ScenarioSetSettingAction.cpp */; }; + 66A10FB5257F1E1800DD651A /* SignSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F45257F1E1700DD651A /* SignSetNameAction.cpp */; }; + 66A10FB6257F1E1800DD651A /* RideSetColourSchemeAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F46257F1E1700DD651A /* RideSetColourSchemeAction.h */; }; + 66A10FB7257F1E1800DD651A /* LandBuyRightsAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F47257F1E1700DD651A /* LandBuyRightsAction.cpp */; }; + 66A10FB8257F1E1800DD651A /* ScenarioSetSettingAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F48257F1E1700DD651A /* ScenarioSetSettingAction.h */; }; + 66A10FB9257F1E1800DD651A /* RideSetStatusAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F49257F1E1700DD651A /* RideSetStatusAction.cpp */; }; + 66A10FBA257F1E1800DD651A /* PlayerKickAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F4A257F1E1700DD651A /* PlayerKickAction.cpp */; }; + 66A10FBB257F1E1800DD651A /* LargeSceneryPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F4B257F1E1700DD651A /* LargeSceneryPlaceAction.cpp */; }; + 66A10FD0257F1E3000DD651A /* TrackPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FBE257F1E2D00DD651A /* TrackPlaceAction.h */; }; + 66A10FD1257F1E3000DD651A /* WaterRaiseAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FBF257F1E2D00DD651A /* WaterRaiseAction.cpp */; }; + 66A10FD2257F1E3000DD651A /* WallPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC0257F1E2D00DD651A /* WallPlaceAction.h */; }; + 66A10FD3257F1E3000DD651A /* TrackRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC1257F1E2D00DD651A /* TrackRemoveAction.h */; }; + 66A10FD4257F1E3000DD651A /* TrackSetBrakeSpeedAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FC2257F1E2E00DD651A /* TrackSetBrakeSpeedAction.cpp */; }; + 66A10FD5257F1E3000DD651A /* WaterRaiseAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC3257F1E2E00DD651A /* WaterRaiseAction.h */; }; + 66A10FD6257F1E3000DD651A /* WallRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC4257F1E2E00DD651A /* WallRemoveAction.h */; }; + 66A10FD7257F1E3000DD651A /* WaterLowerAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC5257F1E2E00DD651A /* WaterLowerAction.h */; }; + 66A10FD8257F1E3000DD651A /* TrackRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FC6257F1E2E00DD651A /* TrackRemoveAction.cpp */; }; + 66A10FD9257F1E3000DD651A /* WaterSetHeightAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FC7257F1E2E00DD651A /* WaterSetHeightAction.cpp */; }; + 66A10FDA257F1E3000DD651A /* WaterSetHeightAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC8257F1E2F00DD651A /* WaterSetHeightAction.h */; }; + 66A10FDB257F1E3000DD651A /* WallPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FC9257F1E2F00DD651A /* WallPlaceAction.cpp */; }; + 66A10FDC257F1E3000DD651A /* TrackPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FCA257F1E2F00DD651A /* TrackPlaceAction.cpp */; }; + 66A10FDD257F1E3000DD651A /* WallSetColourAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FCB257F1E2F00DD651A /* WallSetColourAction.h */; }; + 66A10FDE257F1E3000DD651A /* WaterLowerAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FCC257F1E2F00DD651A /* WaterLowerAction.cpp */; }; + 66A10FDF257F1E3000DD651A /* TrackSetBrakeSpeedAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FCD257F1E2F00DD651A /* TrackSetBrakeSpeedAction.h */; }; + 66A10FE0257F1E3000DD651A /* WallRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FCE257F1E2F00DD651A /* WallRemoveAction.cpp */; }; + 66A10FE1257F1E3000DD651A /* WallSetColourAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FCF257F1E3000DD651A /* WallSetColourAction.cpp */; }; 9308D9FE209908090079EE96 /* TileElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9308D9FA209908080079EE96 /* TileElement.cpp */; }; 9308D9FF209908090079EE96 /* TileElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9308D9FA209908080079EE96 /* TileElement.cpp */; }; 9308DA00209908090079EE96 /* TileElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9308D9FA209908080079EE96 /* TileElement.cpp */; }; @@ -722,7 +880,6 @@ 4C25596D244A330800CE7E45 /* detail_method.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = detail_method.h; path = src/thirdparty/dukglue/detail_method.h; sourceTree = SOURCE_ROOT; }; 4C25596E244A330800CE7E45 /* dukexception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dukexception.h; path = src/thirdparty/dukglue/dukexception.h; sourceTree = SOURCE_ROOT; }; 4C25596F244A330800CE7E45 /* detail_typeinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = detail_typeinfo.h; path = src/thirdparty/dukglue/detail_typeinfo.h; sourceTree = SOURCE_ROOT; }; - 4C255971244A342900CE7E45 /* CustomAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CustomAction.hpp; sourceTree = ""; }; 4C29DEB2218C6AE500E8707F /* RCT12.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RCT12.cpp; sourceTree = ""; }; 4C358E5021C445F700ADE6BC /* ReplayManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReplayManager.cpp; sourceTree = ""; }; 4C358E5121C445F700ADE6BC /* ReplayManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplayManager.h; sourceTree = ""; }; @@ -976,7 +1133,6 @@ 4CC4B8E91FE00C5D00660D62 /* Input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Input.h; sourceTree = ""; }; 4CC4B8EA1FE00C5D00660D62 /* Intro.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Intro.cpp; sourceTree = ""; }; 4CC4B8EB1FE00C5D00660D62 /* Intro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Intro.h; sourceTree = ""; }; - 4CC5258023A19C1C00D4366D /* MazePlaceTrackAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MazePlaceTrackAction.hpp; sourceTree = ""; }; 4CC5258123A19C2800D4366D /* TrackDesignAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackDesignAction.cpp; sourceTree = ""; }; 4CC5258323A19C2E00D4366D /* TrackDesignAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackDesignAction.h; sourceTree = ""; }; 4CDCB0BC20A9902E00321367 /* ShopItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShopItem.cpp; sourceTree = ""; }; @@ -1004,92 +1160,173 @@ 6341F4E02400AA0F0052902B /* Drawing.Sprite.BMP.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Drawing.Sprite.BMP.cpp; sourceTree = ""; }; 662578A325803A6C0002C77E /* libdiscord-rpc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libdiscord-rpc.a"; path = "discord-rpc/build/src/libdiscord-rpc.a"; sourceTree = ""; }; 662578A525803AA90002C77E /* discord_rpc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = discord_rpc.h; path = "discord-rpc/include/discord_rpc.h"; sourceTree = ""; }; + 66A10EA0257F1DE000DD651A /* BalloonPressAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BalloonPressAction.cpp; sourceTree = ""; }; + 66A10EA1257F1DE000DD651A /* BalloonPressAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BalloonPressAction.h; sourceTree = ""; }; + 66A10EA6257F1DF600DD651A /* BannerPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerPlaceAction.cpp; sourceTree = ""; }; + 66A10EA7257F1DF600DD651A /* FootpathAdditionRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathAdditionRemoveAction.h; sourceTree = ""; }; + 66A10EA8257F1DF600DD651A /* FootpathRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathRemoveAction.h; sourceTree = ""; }; + 66A10EA9257F1DF600DD651A /* FootpathPlaceFromTrackAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathPlaceFromTrackAction.cpp; sourceTree = ""; }; + 66A10EAA257F1DF600DD651A /* FootpathAdditionPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathAdditionPlaceAction.cpp; sourceTree = ""; }; + 66A10EAB257F1DF600DD651A /* BannerSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerSetNameAction.cpp; sourceTree = ""; }; + 66A10EAC257F1DF600DD651A /* FootpathPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathPlaceAction.h; sourceTree = ""; }; + 66A10EAD257F1DF700DD651A /* FootpathRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathRemoveAction.cpp; sourceTree = ""; }; + 66A10EAE257F1DF700DD651A /* BannerPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerPlaceAction.h; sourceTree = ""; }; + 66A10EAF257F1DF700DD651A /* CustomAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomAction.h; sourceTree = ""; }; + 66A10EB0257F1DF700DD651A /* ClimateSetAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClimateSetAction.h; sourceTree = ""; }; + 66A10EB1257F1DF700DD651A /* BannerSetStyleAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerSetStyleAction.cpp; sourceTree = ""; }; + 66A10EB2257F1DF700DD651A /* ClearAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClearAction.cpp; sourceTree = ""; }; + 66A10EB3257F1DF700DD651A /* BannerRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerRemoveAction.cpp; sourceTree = ""; }; + 66A10EB4257F1DF700DD651A /* BannerSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerSetNameAction.h; sourceTree = ""; }; + 66A10EB5257F1DF700DD651A /* ClimateSetAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClimateSetAction.cpp; sourceTree = ""; }; + 66A10EB6257F1DF700DD651A /* BannerSetColourAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerSetColourAction.h; sourceTree = ""; }; + 66A10EB7257F1DF700DD651A /* CustomAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CustomAction.cpp; sourceTree = ""; }; + 66A10EB8257F1DF700DD651A /* FootpathAdditionRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathAdditionRemoveAction.cpp; sourceTree = ""; }; + 66A10EB9257F1DF700DD651A /* BannerRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerRemoveAction.h; sourceTree = ""; }; + 66A10EBA257F1DF700DD651A /* ClearAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClearAction.h; sourceTree = ""; }; + 66A10EBB257F1DF700DD651A /* BannerSetStyleAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerSetStyleAction.h; sourceTree = ""; }; + 66A10EBC257F1DF800DD651A /* FootpathPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathPlaceAction.cpp; sourceTree = ""; }; + 66A10EBD257F1DF800DD651A /* FootpathPlaceFromTrackAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathPlaceFromTrackAction.h; sourceTree = ""; }; + 66A10EBE257F1DF800DD651A /* BannerSetColourAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerSetColourAction.cpp; sourceTree = ""; }; + 66A10EBF257F1DF800DD651A /* FootpathAdditionPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathAdditionPlaceAction.h; sourceTree = ""; }; + 66A10EDC257F1E1000DD651A /* PlaceParkEntranceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlaceParkEntranceAction.h; sourceTree = ""; }; + 66A10EDD257F1E1000DD651A /* StaffSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffSetNameAction.h; sourceTree = ""; }; + 66A10EDE257F1E1000DD651A /* PauseToggleAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PauseToggleAction.h; sourceTree = ""; }; + 66A10EDF257F1E1000DD651A /* ParkSetDateAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkSetDateAction.h; sourceTree = ""; }; + 66A10EE0257F1E1000DD651A /* ParkEntranceRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkEntranceRemoveAction.h; sourceTree = ""; }; + 66A10EE1257F1E1100DD651A /* RideDemolishAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideDemolishAction.h; sourceTree = ""; }; + 66A10EE2257F1E1100DD651A /* StaffSetCostumeAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffSetCostumeAction.cpp; sourceTree = ""; }; + 66A10EE3257F1E1100DD651A /* LandLowerAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandLowerAction.h; sourceTree = ""; }; + 66A10EE4257F1E1100DD651A /* RideSetAppearanceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetAppearanceAction.h; sourceTree = ""; }; + 66A10EE5257F1E1100DD651A /* SurfaceSetStyleAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SurfaceSetStyleAction.cpp; sourceTree = ""; }; + 66A10EE6257F1E1100DD651A /* SmallSceneryRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmallSceneryRemoveAction.h; sourceTree = ""; }; + 66A10EE7257F1E1100DD651A /* RideSetAppearanceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetAppearanceAction.cpp; sourceTree = ""; }; + 66A10EE8257F1E1100DD651A /* StaffSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffSetNameAction.cpp; sourceTree = ""; }; + 66A10EE9257F1E1100DD651A /* SetCheatAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetCheatAction.cpp; sourceTree = ""; }; + 66A10EEA257F1E1100DD651A /* GuestSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GuestSetNameAction.h; sourceTree = ""; }; + 66A10EEB257F1E1100DD651A /* GuestSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GuestSetNameAction.cpp; sourceTree = ""; }; + 66A10EEC257F1E1100DD651A /* SetParkEntranceFeeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SetParkEntranceFeeAction.h; sourceTree = ""; }; + 66A10EED257F1E1100DD651A /* RideSetStatusAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetStatusAction.h; sourceTree = ""; }; + 66A10EEE257F1E1100DD651A /* LargeSceneryRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LargeSceneryRemoveAction.h; sourceTree = ""; }; + 66A10EEF257F1E1200DD651A /* SmallScenerySetColourAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmallScenerySetColourAction.h; sourceTree = ""; }; + 66A10EF0257F1E1200DD651A /* ParkEntranceRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkEntranceRemoveAction.cpp; sourceTree = ""; }; + 66A10EF1257F1E1200DD651A /* PlaceParkEntranceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlaceParkEntranceAction.cpp; sourceTree = ""; }; + 66A10EF2257F1E1200DD651A /* SurfaceSetStyleAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SurfaceSetStyleAction.h; sourceTree = ""; }; + 66A10EF3257F1E1200DD651A /* PlayerKickAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayerKickAction.h; sourceTree = ""; }; + 66A10EF4257F1E1200DD651A /* LandRaiseAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandRaiseAction.cpp; sourceTree = ""; }; + 66A10EF5257F1E1200DD651A /* TileModifyAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TileModifyAction.h; sourceTree = ""; }; + 66A10EF6257F1E1200DD651A /* RideSetVehicleAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetVehicleAction.cpp; sourceTree = ""; }; + 66A10EF7257F1E1200DD651A /* RideEntranceExitPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideEntranceExitPlaceAction.h; sourceTree = ""; }; + 66A10EF8257F1E1200DD651A /* NetworkModifyGroupAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkModifyGroupAction.h; sourceTree = ""; }; + 66A10EF9257F1E1200DD651A /* ParkSetLoanAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkSetLoanAction.h; sourceTree = ""; }; + 66A10EFA257F1E1200DD651A /* LargeScenerySetColourAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LargeScenerySetColourAction.cpp; sourceTree = ""; }; + 66A10EFB257F1E1200DD651A /* ParkSetLoanAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkSetLoanAction.cpp; sourceTree = ""; }; + 66A10EFC257F1E1200DD651A /* LoadOrQuitAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LoadOrQuitAction.cpp; sourceTree = ""; }; + 66A10EFD257F1E1200DD651A /* ParkSetParameterAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkSetParameterAction.cpp; sourceTree = ""; }; + 66A10EFE257F1E1200DD651A /* LandRaiseAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandRaiseAction.h; sourceTree = ""; }; + 66A10EFF257F1E1200DD651A /* RideEntranceExitPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideEntranceExitPlaceAction.cpp; sourceTree = ""; }; + 66A10F00257F1E1300DD651A /* ParkSetDateAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkSetDateAction.cpp; sourceTree = ""; }; + 66A10F01257F1E1300DD651A /* StaffSetColourAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffSetColourAction.cpp; sourceTree = ""; }; + 66A10F02257F1E1300DD651A /* PlacePeepSpawnAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlacePeepSpawnAction.h; sourceTree = ""; }; + 66A10F03257F1E1300DD651A /* LandSetHeightAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandSetHeightAction.h; sourceTree = ""; }; + 66A10F04257F1E1300DD651A /* RideEntranceExitRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideEntranceExitRemoveAction.h; sourceTree = ""; }; + 66A10F05257F1E1300DD651A /* RideSetPriceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetPriceAction.cpp; sourceTree = ""; }; + 66A10F06257F1E1300DD651A /* SmallSceneryRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmallSceneryRemoveAction.cpp; sourceTree = ""; }; + 66A10F07257F1E1300DD651A /* StaffSetOrdersAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffSetOrdersAction.h; sourceTree = ""; }; + 66A10F08257F1E1300DD651A /* StaffSetColourAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffSetColourAction.h; sourceTree = ""; }; + 66A10F09257F1E1300DD651A /* RideCreateAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideCreateAction.cpp; sourceTree = ""; }; + 66A10F0A257F1E1300DD651A /* RideSetSettingAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetSettingAction.cpp; sourceTree = ""; }; + 66A10F0B257F1E1300DD651A /* MazeSetTrackAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MazeSetTrackAction.h; sourceTree = ""; }; + 66A10F0C257F1E1300DD651A /* StaffHireNewAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffHireNewAction.cpp; sourceTree = ""; }; + 66A10F0D257F1E1300DD651A /* ParkSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkSetNameAction.cpp; sourceTree = ""; }; + 66A10F0E257F1E1300DD651A /* RideSetColourSchemeAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetColourSchemeAction.cpp; sourceTree = ""; }; + 66A10F0F257F1E1300DD651A /* MazePlaceTrackAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MazePlaceTrackAction.cpp; sourceTree = ""; }; + 66A10F10257F1E1400DD651A /* NetworkModifyGroupAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkModifyGroupAction.cpp; sourceTree = ""; }; + 66A10F11257F1E1400DD651A /* RideSetVehicleAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetVehicleAction.h; sourceTree = ""; }; + 66A10F12257F1E1400DD651A /* PlayerSetGroupAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlayerSetGroupAction.cpp; sourceTree = ""; }; + 66A10F13257F1E1400DD651A /* PlayerSetGroupAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayerSetGroupAction.h; sourceTree = ""; }; + 66A10F14257F1E1400DD651A /* StaffSetPatrolAreaAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffSetPatrolAreaAction.h; sourceTree = ""; }; + 66A10F15257F1E1400DD651A /* LandSetHeightAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandSetHeightAction.cpp; sourceTree = ""; }; + 66A10F16257F1E1400DD651A /* LoadOrQuitAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadOrQuitAction.h; sourceTree = ""; }; + 66A10F17257F1E1400DD651A /* SmallSceneryPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmallSceneryPlaceAction.h; sourceTree = ""; }; + 66A10F18257F1E1400DD651A /* SignSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignSetNameAction.h; sourceTree = ""; }; + 66A10F19257F1E1400DD651A /* PauseToggleAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PauseToggleAction.cpp; sourceTree = ""; }; + 66A10F1A257F1E1400DD651A /* ParkSetResearchFundingAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkSetResearchFundingAction.h; sourceTree = ""; }; + 66A10F1B257F1E1400DD651A /* LandSmoothAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandSmoothAction.h; sourceTree = ""; }; + 66A10F1C257F1E1400DD651A /* RideCreateAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideCreateAction.h; sourceTree = ""; }; + 66A10F1D257F1E1400DD651A /* GuestSetFlagsAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GuestSetFlagsAction.h; sourceTree = ""; }; + 66A10F1E257F1E1400DD651A /* LandSetRightsAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandSetRightsAction.h; sourceTree = ""; }; + 66A10F1F257F1E1500DD651A /* StaffSetCostumeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffSetCostumeAction.h; sourceTree = ""; }; + 66A10F20257F1E1500DD651A /* MazePlaceTrackAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MazePlaceTrackAction.h; sourceTree = ""; }; + 66A10F21257F1E1500DD651A /* StaffHireNewAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffHireNewAction.h; sourceTree = ""; }; + 66A10F22257F1E1500DD651A /* ParkSetParameterAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkSetParameterAction.h; sourceTree = ""; }; + 66A10F23257F1E1500DD651A /* LandSmoothAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandSmoothAction.cpp; sourceTree = ""; }; + 66A10F24257F1E1500DD651A /* StaffSetOrdersAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffSetOrdersAction.cpp; sourceTree = ""; }; + 66A10F25257F1E1500DD651A /* GuestSetFlagsAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GuestSetFlagsAction.cpp; sourceTree = ""; }; + 66A10F26257F1E1500DD651A /* SignSetStyleAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignSetStyleAction.h; sourceTree = ""; }; + 66A10F27257F1E1500DD651A /* SetCheatAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SetCheatAction.h; sourceTree = ""; }; + 66A10F28257F1E1500DD651A /* PlacePeepSpawnAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlacePeepSpawnAction.cpp; sourceTree = ""; }; + 66A10F29257F1E1500DD651A /* LargeScenerySetColourAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LargeScenerySetColourAction.h; sourceTree = ""; }; + 66A10F2A257F1E1500DD651A /* StaffFireAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffFireAction.h; sourceTree = ""; }; + 66A10F2B257F1E1500DD651A /* ParkSetResearchFundingAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkSetResearchFundingAction.cpp; sourceTree = ""; }; + 66A10F2C257F1E1500DD651A /* PeepPickupAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PeepPickupAction.cpp; sourceTree = ""; }; + 66A10F2D257F1E1500DD651A /* StaffFireAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffFireAction.cpp; sourceTree = ""; }; + 66A10F2E257F1E1600DD651A /* ParkMarketingAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkMarketingAction.cpp; sourceTree = ""; }; + 66A10F2F257F1E1600DD651A /* LandBuyRightsAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandBuyRightsAction.h; sourceTree = ""; }; + 66A10F30257F1E1600DD651A /* StaffSetPatrolAreaAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffSetPatrolAreaAction.cpp; sourceTree = ""; }; + 66A10F31257F1E1600DD651A /* SmallScenerySetColourAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmallScenerySetColourAction.cpp; sourceTree = ""; }; + 66A10F32257F1E1600DD651A /* LargeSceneryPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LargeSceneryPlaceAction.h; sourceTree = ""; }; + 66A10F33257F1E1600DD651A /* LandLowerAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandLowerAction.cpp; sourceTree = ""; }; + 66A10F34257F1E1600DD651A /* RideSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetNameAction.cpp; sourceTree = ""; }; + 66A10F35257F1E1600DD651A /* RideSetPriceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetPriceAction.h; sourceTree = ""; }; + 66A10F36257F1E1600DD651A /* ParkMarketingAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkMarketingAction.h; sourceTree = ""; }; + 66A10F37257F1E1600DD651A /* PeepPickupAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeepPickupAction.h; sourceTree = ""; }; + 66A10F38257F1E1600DD651A /* RideEntranceExitRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideEntranceExitRemoveAction.cpp; sourceTree = ""; }; + 66A10F39257F1E1600DD651A /* ParkSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkSetNameAction.h; sourceTree = ""; }; + 66A10F3A257F1E1600DD651A /* SetParkEntranceFeeAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetParkEntranceFeeAction.cpp; sourceTree = ""; }; + 66A10F3B257F1E1600DD651A /* LandSetRightsAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandSetRightsAction.cpp; sourceTree = ""; }; + 66A10F3C257F1E1600DD651A /* RideSetSettingAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetSettingAction.h; sourceTree = ""; }; + 66A10F3D257F1E1700DD651A /* TileModifyAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileModifyAction.cpp; sourceTree = ""; }; + 66A10F3E257F1E1700DD651A /* SmallSceneryPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmallSceneryPlaceAction.cpp; sourceTree = ""; }; + 66A10F3F257F1E1700DD651A /* RideSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetNameAction.h; sourceTree = ""; }; + 66A10F40257F1E1700DD651A /* SignSetStyleAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SignSetStyleAction.cpp; sourceTree = ""; }; + 66A10F41257F1E1700DD651A /* RideDemolishAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideDemolishAction.cpp; sourceTree = ""; }; + 66A10F42257F1E1700DD651A /* LargeSceneryRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LargeSceneryRemoveAction.cpp; sourceTree = ""; }; + 66A10F43257F1E1700DD651A /* MazeSetTrackAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MazeSetTrackAction.cpp; sourceTree = ""; }; + 66A10F44257F1E1700DD651A /* ScenarioSetSettingAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScenarioSetSettingAction.cpp; sourceTree = ""; }; + 66A10F45257F1E1700DD651A /* SignSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SignSetNameAction.cpp; sourceTree = ""; }; + 66A10F46257F1E1700DD651A /* RideSetColourSchemeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetColourSchemeAction.h; sourceTree = ""; }; + 66A10F47257F1E1700DD651A /* LandBuyRightsAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandBuyRightsAction.cpp; sourceTree = ""; }; + 66A10F48257F1E1700DD651A /* ScenarioSetSettingAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScenarioSetSettingAction.h; sourceTree = ""; }; + 66A10F49257F1E1700DD651A /* RideSetStatusAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetStatusAction.cpp; sourceTree = ""; }; + 66A10F4A257F1E1700DD651A /* PlayerKickAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlayerKickAction.cpp; sourceTree = ""; }; + 66A10F4B257F1E1700DD651A /* LargeSceneryPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LargeSceneryPlaceAction.cpp; sourceTree = ""; }; + 66A10FBE257F1E2D00DD651A /* TrackPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPlaceAction.h; sourceTree = ""; }; + 66A10FBF257F1E2D00DD651A /* WaterRaiseAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WaterRaiseAction.cpp; sourceTree = ""; }; + 66A10FC0257F1E2D00DD651A /* WallPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WallPlaceAction.h; sourceTree = ""; }; + 66A10FC1257F1E2D00DD651A /* TrackRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackRemoveAction.h; sourceTree = ""; }; + 66A10FC2257F1E2E00DD651A /* TrackSetBrakeSpeedAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackSetBrakeSpeedAction.cpp; sourceTree = ""; }; + 66A10FC3257F1E2E00DD651A /* WaterRaiseAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WaterRaiseAction.h; sourceTree = ""; }; + 66A10FC4257F1E2E00DD651A /* WallRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WallRemoveAction.h; sourceTree = ""; }; + 66A10FC5257F1E2E00DD651A /* WaterLowerAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WaterLowerAction.h; sourceTree = ""; }; + 66A10FC6257F1E2E00DD651A /* TrackRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackRemoveAction.cpp; sourceTree = ""; }; + 66A10FC7257F1E2E00DD651A /* WaterSetHeightAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WaterSetHeightAction.cpp; sourceTree = ""; }; + 66A10FC8257F1E2F00DD651A /* WaterSetHeightAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WaterSetHeightAction.h; sourceTree = ""; }; + 66A10FC9257F1E2F00DD651A /* WallPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WallPlaceAction.cpp; sourceTree = ""; }; + 66A10FCA257F1E2F00DD651A /* TrackPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackPlaceAction.cpp; sourceTree = ""; }; + 66A10FCB257F1E2F00DD651A /* WallSetColourAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WallSetColourAction.h; sourceTree = ""; }; + 66A10FCC257F1E2F00DD651A /* WaterLowerAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WaterLowerAction.cpp; sourceTree = ""; }; + 66A10FCD257F1E2F00DD651A /* TrackSetBrakeSpeedAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackSetBrakeSpeedAction.h; sourceTree = ""; }; + 66A10FCE257F1E2F00DD651A /* WallRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WallRemoveAction.cpp; sourceTree = ""; }; + 66A10FCF257F1E3000DD651A /* WallSetColourAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WallSetColourAction.cpp; sourceTree = ""; }; 9308D9FA209908080079EE96 /* TileElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileElement.cpp; sourceTree = ""; }; 9308D9FB209908080079EE96 /* Surface.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Surface.cpp; sourceTree = ""; }; 9308D9FC209908080079EE96 /* TileElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TileElement.h; sourceTree = ""; }; 9308D9FD209908090079EE96 /* Surface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Surface.h; sourceTree = ""; }; 930EEA6924FC00940070314E /* ScenarioSelect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScenarioSelect.cpp; sourceTree = ""; }; - 932A20CD22D73CEE00C57EDB /* GuestSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = GuestSetNameAction.hpp; sourceTree = ""; }; - 932A20CE22D73CEE00C57EDB /* RideSetVehiclesAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetVehiclesAction.hpp; sourceTree = ""; }; 932A20CF22D73CEE00C57EDB /* GameActionCompat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameActionCompat.cpp; sourceTree = ""; }; - 932A20D022D73CEE00C57EDB /* RideSetSetting.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetSetting.hpp; sourceTree = ""; }; - 932A20D122D73CEF00C57EDB /* WallPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WallPlaceAction.hpp; sourceTree = ""; }; - 932A20D222D73CEF00C57EDB /* SmallSceneryRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SmallSceneryRemoveAction.hpp; sourceTree = ""; }; 932A20D322D73CEF00C57EDB /* GameActionRegistration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameActionRegistration.cpp; sourceTree = ""; }; - 932A20D422D73CEF00C57EDB /* RideSetName.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetName.hpp; sourceTree = ""; }; - 932A20D522D73CEF00C57EDB /* PlacePeepSpawnAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PlacePeepSpawnAction.hpp; sourceTree = ""; }; - 932A20D622D73CEF00C57EDB /* LandSetRightsAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandSetRightsAction.hpp; sourceTree = ""; }; - 932A20D722D73CEF00C57EDB /* RideCreateAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideCreateAction.hpp; sourceTree = ""; }; - 932A20D822D73CEF00C57EDB /* ParkEntranceRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkEntranceRemoveAction.hpp; sourceTree = ""; }; - 932A20D922D73CEF00C57EDB /* ParkSetLoanAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkSetLoanAction.hpp; sourceTree = ""; }; - 932A20DA22D73CF000C57EDB /* LandLowerAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandLowerAction.hpp; sourceTree = ""; }; - 932A20DB22D73CF000C57EDB /* FootpathPlaceFromTrackAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FootpathPlaceFromTrackAction.hpp; sourceTree = ""; }; - 932A20DC22D73CF000C57EDB /* PlayerKickAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PlayerKickAction.hpp; sourceTree = ""; }; - 932A20DD22D73CF000C57EDB /* RideDemolishAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideDemolishAction.hpp; sourceTree = ""; }; - 932A20DE22D73CF000C57EDB /* ClimateSetAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ClimateSetAction.hpp; sourceTree = ""; }; - 932A20DF22D73CF000C57EDB /* PauseToggleAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PauseToggleAction.hpp; sourceTree = ""; }; - 932A20E022D73CF000C57EDB /* LargeSceneryPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LargeSceneryPlaceAction.hpp; sourceTree = ""; }; - 932A20E122D73CF000C57EDB /* LandSetHeightAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandSetHeightAction.hpp; sourceTree = ""; }; - 932A20E222D73CF100C57EDB /* StaffSetColourAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetColourAction.hpp; sourceTree = ""; }; - 932A20E322D73CF100C57EDB /* StaffSetCostumeAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetCostumeAction.hpp; sourceTree = ""; }; - 932A20E422D73CF100C57EDB /* StaffSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetNameAction.hpp; sourceTree = ""; }; - 932A20E522D73CF100C57EDB /* BannerPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BannerPlaceAction.hpp; sourceTree = ""; }; - 932A20E622D73CF100C57EDB /* MazeSetTrackAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MazeSetTrackAction.hpp; sourceTree = ""; }; - 932A20E722D73CF100C57EDB /* StaffHireNewAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffHireNewAction.hpp; sourceTree = ""; }; - 932A20E822D73CF100C57EDB /* RideSetPriceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetPriceAction.hpp; sourceTree = ""; }; - 932A20E922D73CF200C57EDB /* WaterLowerAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WaterLowerAction.hpp; sourceTree = ""; }; - 932A20EA22D73CF200C57EDB /* ParkSetParameterAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkSetParameterAction.hpp; sourceTree = ""; }; - 932A20EB22D73CF200C57EDB /* SmallSceneryPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SmallSceneryPlaceAction.hpp; sourceTree = ""; }; - 932A20EC22D73CF200C57EDB /* LargeScenerySetColourAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LargeScenerySetColourAction.hpp; sourceTree = ""; }; - 932A20ED22D73CF200C57EDB /* ParkSetResearchFundingAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkSetResearchFundingAction.hpp; sourceTree = ""; }; - 932A20EE22D73CF200C57EDB /* ScenarioSetSettingAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ScenarioSetSettingAction.hpp; sourceTree = ""; }; - 932A20EF22D73CF200C57EDB /* TrackRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrackRemoveAction.hpp; sourceTree = ""; }; - 932A20F022D73CF300C57EDB /* SignSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SignSetNameAction.hpp; sourceTree = ""; }; - 932A20F122D73CF300C57EDB /* RideEntranceExitRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideEntranceExitRemoveAction.hpp; sourceTree = ""; }; - 932A20F222D73CF300C57EDB /* SetParkEntranceFeeAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SetParkEntranceFeeAction.hpp; sourceTree = ""; }; - 932A20F322D73CF300C57EDB /* FootpathRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FootpathRemoveAction.hpp; sourceTree = ""; }; - 932A20F422D73CF300C57EDB /* RideSetAppearanceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetAppearanceAction.hpp; sourceTree = ""; }; 932A20F522D73CF300C57EDB /* GameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameAction.h; sourceTree = ""; }; - 932A20F622D73CF300C57EDB /* RideEntranceExitPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideEntranceExitPlaceAction.hpp; sourceTree = ""; }; - 932A20F722D73CF300C57EDB /* FootpathPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FootpathPlaceAction.hpp; sourceTree = ""; }; - 932A20F822D73CF400C57EDB /* SignSetStyleAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SignSetStyleAction.hpp; sourceTree = ""; }; - 932A20F922D73CF400C57EDB /* SmallScenerySetColourAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SmallScenerySetColourAction.hpp; sourceTree = ""; }; - 932A20FA22D73CF400C57EDB /* SurfaceSetStyleAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SurfaceSetStyleAction.hpp; sourceTree = ""; }; - 932A20FB22D73CF400C57EDB /* RideSetStatus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetStatus.hpp; sourceTree = ""; }; - 932A20FC22D73CF400C57EDB /* ParkSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkSetNameAction.hpp; sourceTree = ""; }; - 932A20FD22D73CF500C57EDB /* LandBuyRightsAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandBuyRightsAction.hpp; sourceTree = ""; }; - 932A20FE22D73CF500C57EDB /* StaffSetPatrolAreaAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetPatrolAreaAction.hpp; sourceTree = ""; }; - 932A20FF22D73CF500C57EDB /* PeepPickupAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PeepPickupAction.hpp; sourceTree = ""; }; - 932A210022D73CF500C57EDB /* BannerSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BannerSetNameAction.hpp; sourceTree = ""; }; - 932A210122D73CF500C57EDB /* SetCheatAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SetCheatAction.hpp; sourceTree = ""; }; - 932A210222D73CF600C57EDB /* ParkMarketingAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkMarketingAction.hpp; sourceTree = ""; }; - 932A210322D73CF600C57EDB /* StaffSetOrdersAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetOrdersAction.hpp; sourceTree = ""; }; - 932A210422D73CF600C57EDB /* BannerSetColourAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BannerSetColourAction.hpp; sourceTree = ""; }; - 932A210522D73CF600C57EDB /* FootpathSceneryRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FootpathSceneryRemoveAction.hpp; sourceTree = ""; }; - 932A210622D73CF600C57EDB /* GuestSetFlagsAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = GuestSetFlagsAction.hpp; sourceTree = ""; }; - 932A210722D73CF600C57EDB /* TrackPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrackPlaceAction.hpp; sourceTree = ""; }; - 932A210822D73CF700C57EDB /* PlaceParkEntranceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PlaceParkEntranceAction.hpp; sourceTree = ""; }; - 932A210922D73CF700C57EDB /* FootpathSceneryPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FootpathSceneryPlaceAction.hpp; sourceTree = ""; }; - 932A210A22D73CF700C57EDB /* BannerRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BannerRemoveAction.hpp; sourceTree = ""; }; - 932A210B22D73CF700C57EDB /* LandRaiseAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandRaiseAction.hpp; sourceTree = ""; }; - 932A210C22D73CF700C57EDB /* LoadOrQuitAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LoadOrQuitAction.hpp; sourceTree = ""; }; - 932A210D22D73CF700C57EDB /* StaffFireAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffFireAction.hpp; sourceTree = ""; }; - 932A210E22D73CF800C57EDB /* ParkSetDateAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkSetDateAction.hpp; sourceTree = ""; }; - 932A210F22D73CF800C57EDB /* WallSetColourAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WallSetColourAction.hpp; sourceTree = ""; }; - 932A211022D73CF800C57EDB /* WaterSetHeightAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WaterSetHeightAction.hpp; sourceTree = ""; }; - 932A211122D73CF800C57EDB /* RideSetColourScheme.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetColourScheme.hpp; sourceTree = ""; }; - 932A211222D73CF800C57EDB /* WaterRaiseAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WaterRaiseAction.hpp; sourceTree = ""; }; - 932A211322D73CF800C57EDB /* WallRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WallRemoveAction.hpp; sourceTree = ""; }; - 932A211422D73CF800C57EDB /* LandSmoothAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandSmoothAction.hpp; sourceTree = ""; }; - 932A211522D73CF900C57EDB /* BalloonPressAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BalloonPressAction.hpp; sourceTree = ""; }; - 932A211622D73CF900C57EDB /* ClearAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ClearAction.hpp; sourceTree = ""; }; - 932A211722D73CF900C57EDB /* BannerSetStyleAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BannerSetStyleAction.hpp; sourceTree = ""; }; - 932A211822D73CF900C57EDB /* NetworkModifyGroupAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = NetworkModifyGroupAction.hpp; sourceTree = ""; }; - 932A211922D73CF900C57EDB /* PlayerSetGroupAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PlayerSetGroupAction.hpp; sourceTree = ""; }; - 932A211A22D73CFA00C57EDB /* TileModifyAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TileModifyAction.hpp; sourceTree = ""; }; - 932A211B22D73CFA00C57EDB /* TrackSetBrakeSpeedAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrackSetBrakeSpeedAction.hpp; sourceTree = ""; }; 932A211C22D73CFA00C57EDB /* GameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameAction.cpp; sourceTree = ""; }; - 932A211D22D73CFA00C57EDB /* LargeSceneryRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LargeSceneryRemoveAction.hpp; sourceTree = ""; }; 93378D00252B4F550077D2D8 /* JsonFwd.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = JsonFwd.hpp; sourceTree = ""; }; 93378D02252B54140077D2D8 /* json_fwd.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = json_fwd.hpp; path = "build/json-3.9.1/include/nlohmann/json_fwd.hpp"; sourceTree = SOURCE_ROOT; }; 933C55B424B858490057E64B /* SeaDecrypt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SeaDecrypt.cpp; sourceTree = ""; }; @@ -1970,7 +2207,7 @@ 4C25595D244A32E400CE7E45 /* linenoise.hpp */, ); name = thirdparty; - path = openrct2; + path = ../thirdparty; sourceTree = ""; }; 4C25595E244A32EA00CE7E45 /* dukglue */ = { @@ -2303,91 +2540,170 @@ C6352B871F477032006CCEE3 /* actions */ = { isa = PBXGroup; children = ( - 932A211522D73CF900C57EDB /* BalloonPressAction.hpp */, - 932A20E522D73CF100C57EDB /* BannerPlaceAction.hpp */, - 932A210A22D73CF700C57EDB /* BannerRemoveAction.hpp */, - 932A210422D73CF600C57EDB /* BannerSetColourAction.hpp */, - 932A210022D73CF500C57EDB /* BannerSetNameAction.hpp */, - 932A211722D73CF900C57EDB /* BannerSetStyleAction.hpp */, - 932A211622D73CF900C57EDB /* ClearAction.hpp */, - 932A20DE22D73CF000C57EDB /* ClimateSetAction.hpp */, - 4C255971244A342900CE7E45 /* CustomAction.hpp */, - 932A20F722D73CF300C57EDB /* FootpathPlaceAction.hpp */, - 932A20DB22D73CF000C57EDB /* FootpathPlaceFromTrackAction.hpp */, - 932A20F322D73CF300C57EDB /* FootpathRemoveAction.hpp */, - 932A210922D73CF700C57EDB /* FootpathSceneryPlaceAction.hpp */, - 932A210522D73CF600C57EDB /* FootpathSceneryRemoveAction.hpp */, + 66A10EA0257F1DE000DD651A /* BalloonPressAction.cpp */, + 66A10EA1257F1DE000DD651A /* BalloonPressAction.h */, + 66A10EA6257F1DF600DD651A /* BannerPlaceAction.cpp */, + 66A10EAE257F1DF700DD651A /* BannerPlaceAction.h */, + 66A10EB3257F1DF700DD651A /* BannerRemoveAction.cpp */, + 66A10EB9257F1DF700DD651A /* BannerRemoveAction.h */, + 66A10EBE257F1DF800DD651A /* BannerSetColourAction.cpp */, + 66A10EB6257F1DF700DD651A /* BannerSetColourAction.h */, + 66A10EAB257F1DF600DD651A /* BannerSetNameAction.cpp */, + 66A10EB4257F1DF700DD651A /* BannerSetNameAction.h */, + 66A10EB1257F1DF700DD651A /* BannerSetStyleAction.cpp */, + 66A10EBB257F1DF700DD651A /* BannerSetStyleAction.h */, + 66A10EB2257F1DF700DD651A /* ClearAction.cpp */, + 66A10EBA257F1DF700DD651A /* ClearAction.h */, + 66A10EB5257F1DF700DD651A /* ClimateSetAction.cpp */, + 66A10EB0257F1DF700DD651A /* ClimateSetAction.h */, + 66A10EB7257F1DF700DD651A /* CustomAction.cpp */, + 66A10EAF257F1DF700DD651A /* CustomAction.h */, + 66A10EAA257F1DF600DD651A /* FootpathAdditionPlaceAction.cpp */, + 66A10EBF257F1DF800DD651A /* FootpathAdditionPlaceAction.h */, + 66A10EB8257F1DF700DD651A /* FootpathAdditionRemoveAction.cpp */, + 66A10EA7257F1DF600DD651A /* FootpathAdditionRemoveAction.h */, + 66A10EBC257F1DF800DD651A /* FootpathPlaceAction.cpp */, + 66A10EAC257F1DF600DD651A /* FootpathPlaceAction.h */, + 66A10EA9257F1DF600DD651A /* FootpathPlaceFromTrackAction.cpp */, + 66A10EBD257F1DF800DD651A /* FootpathPlaceFromTrackAction.h */, + 66A10EAD257F1DF700DD651A /* FootpathRemoveAction.cpp */, + 66A10EA8257F1DF600DD651A /* FootpathRemoveAction.h */, 932A211C22D73CFA00C57EDB /* GameAction.cpp */, 932A20F522D73CF300C57EDB /* GameAction.h */, 932A20CF22D73CEE00C57EDB /* GameActionCompat.cpp */, 932A20D322D73CEF00C57EDB /* GameActionRegistration.cpp */, - 932A210622D73CF600C57EDB /* GuestSetFlagsAction.hpp */, - 932A20CD22D73CEE00C57EDB /* GuestSetNameAction.hpp */, - 932A20FD22D73CF500C57EDB /* LandBuyRightsAction.hpp */, - 932A20DA22D73CF000C57EDB /* LandLowerAction.hpp */, - 932A210B22D73CF700C57EDB /* LandRaiseAction.hpp */, - 932A20E122D73CF000C57EDB /* LandSetHeightAction.hpp */, - 932A20D622D73CEF00C57EDB /* LandSetRightsAction.hpp */, - 932A211422D73CF800C57EDB /* LandSmoothAction.hpp */, - 932A20E022D73CF000C57EDB /* LargeSceneryPlaceAction.hpp */, - 932A211D22D73CFA00C57EDB /* LargeSceneryRemoveAction.hpp */, - 932A20EC22D73CF200C57EDB /* LargeScenerySetColourAction.hpp */, - 932A210C22D73CF700C57EDB /* LoadOrQuitAction.hpp */, - 4CC5258023A19C1C00D4366D /* MazePlaceTrackAction.hpp */, - 932A20E622D73CF100C57EDB /* MazeSetTrackAction.hpp */, - 932A211822D73CF900C57EDB /* NetworkModifyGroupAction.hpp */, - 932A20D822D73CEF00C57EDB /* ParkEntranceRemoveAction.hpp */, - 932A210222D73CF600C57EDB /* ParkMarketingAction.hpp */, - 932A210E22D73CF800C57EDB /* ParkSetDateAction.hpp */, - 932A20D922D73CEF00C57EDB /* ParkSetLoanAction.hpp */, - 932A20FC22D73CF400C57EDB /* ParkSetNameAction.hpp */, - 932A20EA22D73CF200C57EDB /* ParkSetParameterAction.hpp */, - 932A20ED22D73CF200C57EDB /* ParkSetResearchFundingAction.hpp */, - 932A20DF22D73CF000C57EDB /* PauseToggleAction.hpp */, - 932A20FF22D73CF500C57EDB /* PeepPickupAction.hpp */, - 932A210822D73CF700C57EDB /* PlaceParkEntranceAction.hpp */, - 932A20D522D73CEF00C57EDB /* PlacePeepSpawnAction.hpp */, - 932A20DC22D73CF000C57EDB /* PlayerKickAction.hpp */, - 932A211922D73CF900C57EDB /* PlayerSetGroupAction.hpp */, - 932A20D722D73CEF00C57EDB /* RideCreateAction.hpp */, - 932A20DD22D73CF000C57EDB /* RideDemolishAction.hpp */, - 932A20F622D73CF300C57EDB /* RideEntranceExitPlaceAction.hpp */, - 932A20F122D73CF300C57EDB /* RideEntranceExitRemoveAction.hpp */, - 932A20F422D73CF300C57EDB /* RideSetAppearanceAction.hpp */, - 932A211122D73CF800C57EDB /* RideSetColourScheme.hpp */, - 932A20D422D73CEF00C57EDB /* RideSetName.hpp */, - 932A20E822D73CF100C57EDB /* RideSetPriceAction.hpp */, - 932A20D022D73CEE00C57EDB /* RideSetSetting.hpp */, - 932A20FB22D73CF400C57EDB /* RideSetStatus.hpp */, - 932A20CE22D73CEE00C57EDB /* RideSetVehiclesAction.hpp */, - 932A20EE22D73CF200C57EDB /* ScenarioSetSettingAction.hpp */, - 932A210122D73CF500C57EDB /* SetCheatAction.hpp */, - 932A20F222D73CF300C57EDB /* SetParkEntranceFeeAction.hpp */, - 932A20F022D73CF300C57EDB /* SignSetNameAction.hpp */, - 932A20F822D73CF400C57EDB /* SignSetStyleAction.hpp */, - 932A20EB22D73CF200C57EDB /* SmallSceneryPlaceAction.hpp */, - 932A20D222D73CEF00C57EDB /* SmallSceneryRemoveAction.hpp */, - 932A20F922D73CF400C57EDB /* SmallScenerySetColourAction.hpp */, - 932A210D22D73CF700C57EDB /* StaffFireAction.hpp */, - 932A20E722D73CF100C57EDB /* StaffHireNewAction.hpp */, - 932A20E222D73CF100C57EDB /* StaffSetColourAction.hpp */, - 932A20E322D73CF100C57EDB /* StaffSetCostumeAction.hpp */, - 932A20E422D73CF100C57EDB /* StaffSetNameAction.hpp */, - 932A210322D73CF600C57EDB /* StaffSetOrdersAction.hpp */, - 932A20FE22D73CF500C57EDB /* StaffSetPatrolAreaAction.hpp */, - 932A20FA22D73CF400C57EDB /* SurfaceSetStyleAction.hpp */, - 932A211A22D73CFA00C57EDB /* TileModifyAction.hpp */, + 66A10F25257F1E1500DD651A /* GuestSetFlagsAction.cpp */, + 66A10F1D257F1E1400DD651A /* GuestSetFlagsAction.h */, + 66A10EEB257F1E1100DD651A /* GuestSetNameAction.cpp */, + 66A10EEA257F1E1100DD651A /* GuestSetNameAction.h */, + 66A10F47257F1E1700DD651A /* LandBuyRightsAction.cpp */, + 66A10F2F257F1E1600DD651A /* LandBuyRightsAction.h */, + 66A10F33257F1E1600DD651A /* LandLowerAction.cpp */, + 66A10EE3257F1E1100DD651A /* LandLowerAction.h */, + 66A10EF4257F1E1200DD651A /* LandRaiseAction.cpp */, + 66A10EFE257F1E1200DD651A /* LandRaiseAction.h */, + 66A10F15257F1E1400DD651A /* LandSetHeightAction.cpp */, + 66A10F03257F1E1300DD651A /* LandSetHeightAction.h */, + 66A10F3B257F1E1600DD651A /* LandSetRightsAction.cpp */, + 66A10F1E257F1E1400DD651A /* LandSetRightsAction.h */, + 66A10F23257F1E1500DD651A /* LandSmoothAction.cpp */, + 66A10F1B257F1E1400DD651A /* LandSmoothAction.h */, + 66A10F4B257F1E1700DD651A /* LargeSceneryPlaceAction.cpp */, + 66A10F32257F1E1600DD651A /* LargeSceneryPlaceAction.h */, + 66A10F42257F1E1700DD651A /* LargeSceneryRemoveAction.cpp */, + 66A10EEE257F1E1100DD651A /* LargeSceneryRemoveAction.h */, + 66A10EFA257F1E1200DD651A /* LargeScenerySetColourAction.cpp */, + 66A10F29257F1E1500DD651A /* LargeScenerySetColourAction.h */, + 66A10EFC257F1E1200DD651A /* LoadOrQuitAction.cpp */, + 66A10F16257F1E1400DD651A /* LoadOrQuitAction.h */, + 66A10F0F257F1E1300DD651A /* MazePlaceTrackAction.cpp */, + 66A10F20257F1E1500DD651A /* MazePlaceTrackAction.h */, + 66A10F43257F1E1700DD651A /* MazeSetTrackAction.cpp */, + 66A10F0B257F1E1300DD651A /* MazeSetTrackAction.h */, + 66A10F10257F1E1400DD651A /* NetworkModifyGroupAction.cpp */, + 66A10EF8257F1E1200DD651A /* NetworkModifyGroupAction.h */, + 66A10EF0257F1E1200DD651A /* ParkEntranceRemoveAction.cpp */, + 66A10EE0257F1E1000DD651A /* ParkEntranceRemoveAction.h */, + 66A10F2E257F1E1600DD651A /* ParkMarketingAction.cpp */, + 66A10F36257F1E1600DD651A /* ParkMarketingAction.h */, + 66A10F00257F1E1300DD651A /* ParkSetDateAction.cpp */, + 66A10EDF257F1E1000DD651A /* ParkSetDateAction.h */, + 66A10EFB257F1E1200DD651A /* ParkSetLoanAction.cpp */, + 66A10EF9257F1E1200DD651A /* ParkSetLoanAction.h */, + 66A10F0D257F1E1300DD651A /* ParkSetNameAction.cpp */, + 66A10F39257F1E1600DD651A /* ParkSetNameAction.h */, + 66A10EFD257F1E1200DD651A /* ParkSetParameterAction.cpp */, + 66A10F22257F1E1500DD651A /* ParkSetParameterAction.h */, + 66A10F2B257F1E1500DD651A /* ParkSetResearchFundingAction.cpp */, + 66A10F1A257F1E1400DD651A /* ParkSetResearchFundingAction.h */, + 66A10F19257F1E1400DD651A /* PauseToggleAction.cpp */, + 66A10EDE257F1E1000DD651A /* PauseToggleAction.h */, + 66A10F2C257F1E1500DD651A /* PeepPickupAction.cpp */, + 66A10F37257F1E1600DD651A /* PeepPickupAction.h */, + 66A10EF1257F1E1200DD651A /* PlaceParkEntranceAction.cpp */, + 66A10EDC257F1E1000DD651A /* PlaceParkEntranceAction.h */, + 66A10F28257F1E1500DD651A /* PlacePeepSpawnAction.cpp */, + 66A10F02257F1E1300DD651A /* PlacePeepSpawnAction.h */, + 66A10F4A257F1E1700DD651A /* PlayerKickAction.cpp */, + 66A10EF3257F1E1200DD651A /* PlayerKickAction.h */, + 66A10F12257F1E1400DD651A /* PlayerSetGroupAction.cpp */, + 66A10F13257F1E1400DD651A /* PlayerSetGroupAction.h */, + 66A10F09257F1E1300DD651A /* RideCreateAction.cpp */, + 66A10F1C257F1E1400DD651A /* RideCreateAction.h */, + 66A10F41257F1E1700DD651A /* RideDemolishAction.cpp */, + 66A10EE1257F1E1100DD651A /* RideDemolishAction.h */, + 66A10EFF257F1E1200DD651A /* RideEntranceExitPlaceAction.cpp */, + 66A10EF7257F1E1200DD651A /* RideEntranceExitPlaceAction.h */, + 66A10F38257F1E1600DD651A /* RideEntranceExitRemoveAction.cpp */, + 66A10F04257F1E1300DD651A /* RideEntranceExitRemoveAction.h */, + 66A10EE7257F1E1100DD651A /* RideSetAppearanceAction.cpp */, + 66A10EE4257F1E1100DD651A /* RideSetAppearanceAction.h */, + 66A10F0E257F1E1300DD651A /* RideSetColourSchemeAction.cpp */, + 66A10F46257F1E1700DD651A /* RideSetColourSchemeAction.h */, + 66A10F34257F1E1600DD651A /* RideSetNameAction.cpp */, + 66A10F3F257F1E1700DD651A /* RideSetNameAction.h */, + 66A10F05257F1E1300DD651A /* RideSetPriceAction.cpp */, + 66A10F35257F1E1600DD651A /* RideSetPriceAction.h */, + 66A10F0A257F1E1300DD651A /* RideSetSettingAction.cpp */, + 66A10F3C257F1E1600DD651A /* RideSetSettingAction.h */, + 66A10F49257F1E1700DD651A /* RideSetStatusAction.cpp */, + 66A10EED257F1E1100DD651A /* RideSetStatusAction.h */, + 66A10EF6257F1E1200DD651A /* RideSetVehicleAction.cpp */, + 66A10F11257F1E1400DD651A /* RideSetVehicleAction.h */, + 66A10F44257F1E1700DD651A /* ScenarioSetSettingAction.cpp */, + 66A10F48257F1E1700DD651A /* ScenarioSetSettingAction.h */, + 66A10EE9257F1E1100DD651A /* SetCheatAction.cpp */, + 66A10F27257F1E1500DD651A /* SetCheatAction.h */, + 66A10F3A257F1E1600DD651A /* SetParkEntranceFeeAction.cpp */, + 66A10EEC257F1E1100DD651A /* SetParkEntranceFeeAction.h */, + 66A10F45257F1E1700DD651A /* SignSetNameAction.cpp */, + 66A10F18257F1E1400DD651A /* SignSetNameAction.h */, + 66A10F40257F1E1700DD651A /* SignSetStyleAction.cpp */, + 66A10F26257F1E1500DD651A /* SignSetStyleAction.h */, + 66A10F3E257F1E1700DD651A /* SmallSceneryPlaceAction.cpp */, + 66A10F17257F1E1400DD651A /* SmallSceneryPlaceAction.h */, + 66A10F06257F1E1300DD651A /* SmallSceneryRemoveAction.cpp */, + 66A10EE6257F1E1100DD651A /* SmallSceneryRemoveAction.h */, + 66A10F31257F1E1600DD651A /* SmallScenerySetColourAction.cpp */, + 66A10EEF257F1E1200DD651A /* SmallScenerySetColourAction.h */, + 66A10F2D257F1E1500DD651A /* StaffFireAction.cpp */, + 66A10F2A257F1E1500DD651A /* StaffFireAction.h */, + 66A10F0C257F1E1300DD651A /* StaffHireNewAction.cpp */, + 66A10F21257F1E1500DD651A /* StaffHireNewAction.h */, + 66A10F01257F1E1300DD651A /* StaffSetColourAction.cpp */, + 66A10F08257F1E1300DD651A /* StaffSetColourAction.h */, + 66A10EE2257F1E1100DD651A /* StaffSetCostumeAction.cpp */, + 66A10F1F257F1E1500DD651A /* StaffSetCostumeAction.h */, + 66A10EE8257F1E1100DD651A /* StaffSetNameAction.cpp */, + 66A10EDD257F1E1000DD651A /* StaffSetNameAction.h */, + 66A10F24257F1E1500DD651A /* StaffSetOrdersAction.cpp */, + 66A10F07257F1E1300DD651A /* StaffSetOrdersAction.h */, + 66A10F30257F1E1600DD651A /* StaffSetPatrolAreaAction.cpp */, + 66A10F14257F1E1400DD651A /* StaffSetPatrolAreaAction.h */, + 66A10EE5257F1E1100DD651A /* SurfaceSetStyleAction.cpp */, + 66A10EF2257F1E1200DD651A /* SurfaceSetStyleAction.h */, + 66A10F3D257F1E1700DD651A /* TileModifyAction.cpp */, + 66A10EF5257F1E1200DD651A /* TileModifyAction.h */, 4CC5258123A19C2800D4366D /* TrackDesignAction.cpp */, 4CC5258323A19C2E00D4366D /* TrackDesignAction.h */, - 932A210722D73CF600C57EDB /* TrackPlaceAction.hpp */, - 932A20EF22D73CF200C57EDB /* TrackRemoveAction.hpp */, - 932A211B22D73CFA00C57EDB /* TrackSetBrakeSpeedAction.hpp */, - 932A20D122D73CEF00C57EDB /* WallPlaceAction.hpp */, - 932A211322D73CF800C57EDB /* WallRemoveAction.hpp */, - 932A210F22D73CF800C57EDB /* WallSetColourAction.hpp */, - 932A20E922D73CF200C57EDB /* WaterLowerAction.hpp */, - 932A211222D73CF800C57EDB /* WaterRaiseAction.hpp */, - 932A211022D73CF800C57EDB /* WaterSetHeightAction.hpp */, + 66A10FCA257F1E2F00DD651A /* TrackPlaceAction.cpp */, + 66A10FBE257F1E2D00DD651A /* TrackPlaceAction.h */, + 66A10FC6257F1E2E00DD651A /* TrackRemoveAction.cpp */, + 66A10FC1257F1E2D00DD651A /* TrackRemoveAction.h */, + 66A10FC2257F1E2E00DD651A /* TrackSetBrakeSpeedAction.cpp */, + 66A10FCD257F1E2F00DD651A /* TrackSetBrakeSpeedAction.h */, + 66A10FC9257F1E2F00DD651A /* WallPlaceAction.cpp */, + 66A10FC0257F1E2D00DD651A /* WallPlaceAction.h */, + 66A10FCE257F1E2F00DD651A /* WallRemoveAction.cpp */, + 66A10FC4257F1E2E00DD651A /* WallRemoveAction.h */, + 66A10FCF257F1E3000DD651A /* WallSetColourAction.cpp */, + 66A10FCB257F1E2F00DD651A /* WallSetColourAction.h */, + 66A10FCC257F1E2F00DD651A /* WaterLowerAction.cpp */, + 66A10FC5257F1E2E00DD651A /* WaterLowerAction.h */, + 66A10FBF257F1E2D00DD651A /* WaterRaiseAction.cpp */, + 66A10FC3257F1E2E00DD651A /* WaterRaiseAction.h */, + 66A10FC7257F1E2E00DD651A /* WaterSetHeightAction.cpp */, + 66A10FC8257F1E2F00DD651A /* WaterSetHeightAction.h */, ); path = actions; sourceTree = ""; @@ -2662,8 +2978,7 @@ D43407E11D0E14CE00C2B3D4 /* shaders */, D4EC48E51C2637710024B507 /* sequence */, ); - name = data; - path = ../data; + path = data; sourceTree = ""; }; D4EC48811C2634870024B507 /* include */ = { @@ -3711,60 +4026,139 @@ files = ( 662578A625803AA90002C77E /* discord_rpc.h in Headers */, 93DFD05624521C1A001FCBAF /* ScriptEngine.h in Headers */, + 66A10ED0257F1DF800DD651A /* BannerSetColourAction.h in Headers */, + 66A10EC6257F1DF800DD651A /* FootpathPlaceAction.h in Headers */, + 66A10FA9257F1E1800DD651A /* ParkSetNameAction.h in Headers */, + 66A10F69257F1E1800DD651A /* ParkSetLoanAction.h in Headers */, 2ADE2F3122441905002598AF /* DiscordService.h in Headers */, + 66A10FD2257F1E3000DD651A /* WallPlaceAction.h in Headers */, + 66A10F8C257F1E1800DD651A /* RideCreateAction.h in Headers */, + 66A10F65257F1E1700DD651A /* TileModifyAction.h in Headers */, + 66A10ED4257F1DF800DD651A /* ClearAction.h in Headers */, + 66A10F5F257F1E1700DD651A /* SmallScenerySetColourAction.h in Headers */, + 66A10FA5257F1E1800DD651A /* RideSetPriceAction.h in Headers */, C67B28172002D67A00109C93 /* Viewport.h in Headers */, + 66A10FDD257F1E3000DD651A /* WallSetColourAction.h in Headers */, + 66A10F8D257F1E1800DD651A /* GuestSetFlagsAction.h in Headers */, + 66A10FA7257F1E1800DD651A /* PeepPickupAction.h in Headers */, 939A359C20C12FC800630B3F /* Paint.Sprite.h in Headers */, 93DFD05524521C1A001FCBAF /* ScMap.hpp in Headers */, 9308DA04209908090079EE96 /* TileElement.h in Headers */, C67B28152002D67A00109C93 /* Widget.h in Headers */, + 66A10F99257F1E1800DD651A /* LargeScenerySetColourAction.h in Headers */, 93378D01252B4F550077D2D8 /* JsonFwd.hpp in Headers */, + 66A10F90257F1E1800DD651A /* MazePlaceTrackAction.h in Headers */, + 66A10F6E257F1E1800DD651A /* LandRaiseAction.h in Headers */, + 66A10F78257F1E1800DD651A /* StaffSetColourAction.h in Headers */, + 66A10F67257F1E1700DD651A /* RideEntranceExitPlaceAction.h in Headers */, + 66A10F8A257F1E1800DD651A /* ParkSetResearchFundingAction.h in Headers */, C6352B851F477022006CCEE3 /* DataSerialiserTraits.h in Headers */, + 66A10F50257F1E1700DD651A /* ParkEntranceRemoveAction.h in Headers */, + 66A10F4D257F1E1700DD651A /* StaffSetNameAction.h in Headers */, 93DFD05124521C1A001FCBAF /* ScContext.hpp in Headers */, + 66A10FD6257F1E3000DD651A /* WallRemoveAction.h in Headers */, 939A359F20C12FDE00630B3F /* Paint.Surface.h in Headers */, + 66A10F7B257F1E1800DD651A /* MazeSetTrackAction.h in Headers */, C67B28192002D7F200109C93 /* Window_internal.h in Headers */, + 66A10F53257F1E1700DD651A /* LandLowerAction.h in Headers */, + 66A10F5E257F1E1700DD651A /* LargeSceneryRemoveAction.h in Headers */, + 66A10F5D257F1E1700DD651A /* RideSetStatusAction.h in Headers */, 93DFD05024521C1A001FCBAF /* ScPark.hpp in Headers */, 93B4DC1625487CDF008D63FF /* Formatting.h in Headers */, 93FB271F24ED32B7008241C9 /* json.hpp in Headers */, + 66A10F86257F1E1800DD651A /* LoadOrQuitAction.h in Headers */, 93DFD02E24521BA0001FCBAF /* FileWatcher.h in Headers */, 2ADE2F28224418B2002598AF /* DataSerialiserTag.h in Headers */, + 66A10F74257F1E1800DD651A /* RideEntranceExitRemoveAction.h in Headers */, + 66A10F9A257F1E1800DD651A /* StaffFireAction.h in Headers */, 93DFD04C24521C1A001FCBAF /* ScDisposable.hpp in Headers */, + 66A10FAC257F1E1800DD651A /* RideSetSettingAction.h in Headers */, 2ADE2F2E224418E7002598AF /* ConversionTables.h in Headers */, 933F2CBB20935668001B33FD /* LocalisationService.h in Headers */, + 66A10EC9257F1DF800DD651A /* CustomAction.h in Headers */, + 66A10FDF257F1E3000DD651A /* TrackSetBrakeSpeedAction.h in Headers */, + 66A10F54257F1E1700DD651A /* RideSetAppearanceAction.h in Headers */, C6352B861F477022006CCEE3 /* Endianness.h in Headers */, + 66A10F5A257F1E1700DD651A /* GuestSetNameAction.h in Headers */, + 66A10F87257F1E1800DD651A /* SmallSceneryPlaceAction.h in Headers */, + 66A10ECA257F1DF800DD651A /* ClimateSetAction.h in Headers */, + 66A10F77257F1E1800DD651A /* StaffSetOrdersAction.h in Headers */, 2ADE2F2C224418B2002598AF /* FileIndex.hpp in Headers */, + 66A10FAF257F1E1800DD651A /* RideSetNameAction.h in Headers */, 93DFD04A24521C1A001FCBAF /* ScConfiguration.hpp in Headers */, 93CBA4CC20A7504500867D56 /* ImageImporter.h in Headers */, + 66A10F62257F1E1700DD651A /* SurfaceSetStyleAction.h in Headers */, + 66A10EC1257F1DF800DD651A /* FootpathAdditionRemoveAction.h in Headers */, + 66A10FD0257F1E3000DD651A /* TrackPlaceAction.h in Headers */, + 66A10F4C257F1E1700DD651A /* PlaceParkEntranceAction.h in Headers */, + 66A10F96257F1E1800DD651A /* SignSetStyleAction.h in Headers */, 2ADE2F29224418B2002598AF /* Numerics.hpp in Headers */, 93378D03252B54140077D2D8 /* json_fwd.hpp in Headers */, + 66A10FD5257F1E3000DD651A /* WaterRaiseAction.h in Headers */, 93DFD04924521C1A001FCBAF /* ScTile.hpp in Headers */, 936F412B24CE030F00E07BCF /* NetworkBase.h in Headers */, + 66A10EC2257F1DF800DD651A /* FootpathRemoveAction.h in Headers */, + 66A10EA3257F1DE100DD651A /* BalloonPressAction.h in Headers */, 93DFD04524521C1A001FCBAF /* ScObject.hpp in Headers */, 2ADE2F382244198B002598AF /* SpriteBase.h in Headers */, + 66A10EC8257F1DF800DD651A /* BannerPlaceAction.h in Headers */, C62D838B1FD36D6F008C04F1 /* EditorObjectSelectionSession.h in Headers */, 2ADE2F27224418B2002598AF /* Random.hpp in Headers */, 9344BEF920C1E6180047D165 /* Crypt.h in Headers */, + 66A10F63257F1E1700DD651A /* PlayerKickAction.h in Headers */, + 66A10FD7257F1E3000DD651A /* WaterLowerAction.h in Headers */, 939A35A220C12FFD00630B3F /* InteractiveConsole.h in Headers */, 93CBA4C320A7502E00867D56 /* Imaging.h in Headers */, 93DFD04D24521C1A001FCBAF /* ScEntity.hpp in Headers */, + 66A10F4E257F1E1700DD651A /* PauseToggleAction.h in Headers */, 93DFD04E24521C1A001FCBAF /* Duktape.hpp in Headers */, + 66A10FA2257F1E1800DD651A /* LargeSceneryPlaceAction.h in Headers */, 2ADE2F3622441960002598AF /* RideTypes.h in Headers */, + 66A10F68257F1E1800DD651A /* NetworkModifyGroupAction.h in Headers */, 93DFD05324521C1A001FCBAF /* ScRide.hpp in Headers */, + 66A10F88257F1E1800DD651A /* SignSetNameAction.h in Headers */, 93AE2389252F948A00CD03C3 /* Formatter.h in Headers */, 93DFD05424521C1A001FCBAF /* ScDate.hpp in Headers */, 93FC08FF2418F3ED00CA3054 /* duktape.h in Headers */, 93DFD04F24521C1A001FCBAF /* ScConsole.hpp in Headers */, + 66A10F91257F1E1800DD651A /* StaffHireNewAction.h in Headers */, 9308DA05209908090079EE96 /* Surface.h in Headers */, + 66A10F9F257F1E1800DD651A /* LandBuyRightsAction.h in Headers */, 93DE9753209C3C1000FB1CC8 /* GameState.h in Headers */, + 66A10ED9257F1DF800DD651A /* FootpathAdditionPlaceAction.h in Headers */, 936F412824CE030F00E07BCF /* NetworkClient.h in Headers */, 2ADE2F2A224418B2002598AF /* Meta.hpp in Headers */, 93DFD04624521C1A001FCBAF /* HookEngine.h in Headers */, + 66A10F81257F1E1800DD651A /* RideSetVehicleAction.h in Headers */, + 66A10F83257F1E1800DD651A /* PlayerSetGroupAction.h in Headers */, + 66A10F8E257F1E1800DD651A /* LandSetRightsAction.h in Headers */, 93FC09002418F3ED00CA3054 /* duk_config.h in Headers */, + 66A10FDA257F1E3000DD651A /* WaterSetHeightAction.h in Headers */, + 66A10F51257F1E1700DD651A /* RideDemolishAction.h in Headers */, + 66A10F73257F1E1800DD651A /* LandSetHeightAction.h in Headers */, + 66A10F4F257F1E1700DD651A /* ParkSetDateAction.h in Headers */, + 66A10FD3257F1E3000DD651A /* TrackRemoveAction.h in Headers */, C6352B841F477022006CCEE3 /* DataSerialiser.h in Headers */, 939A35A020C12FDE00630B3F /* Paint.TileElement.h in Headers */, + 66A10ED3257F1DF800DD651A /* BannerRemoveAction.h in Headers */, + 66A10F84257F1E1800DD651A /* StaffSetPatrolAreaAction.h in Headers */, + 66A10F56257F1E1700DD651A /* SmallSceneryRemoveAction.h in Headers */, + 66A10F5C257F1E1700DD651A /* SetParkEntranceFeeAction.h in Headers */, 93DFD04724521C1A001FCBAF /* ScNetwork.hpp in Headers */, + 66A10F8F257F1E1800DD651A /* StaffSetCostumeAction.h in Headers */, + 66A10ED5257F1DF800DD651A /* BannerSetStyleAction.h in Headers */, + 66A10F97257F1E1800DD651A /* SetCheatAction.h in Headers */, + 66A10F92257F1E1800DD651A /* ParkSetParameterAction.h in Headers */, 93DFD04424521C1A001FCBAF /* Plugin.h in Headers */, + 66A10FB6257F1E1800DD651A /* RideSetColourSchemeAction.h in Headers */, + 66A10FA6257F1E1800DD651A /* ParkMarketingAction.h in Headers */, C67B28162002D67A00109C93 /* Window.h in Headers */, + 66A10FB8257F1E1800DD651A /* ScenarioSetSettingAction.h in Headers */, + 66A10F72257F1E1800DD651A /* PlacePeepSpawnAction.h in Headers */, + 66A10ED7257F1DF800DD651A /* FootpathPlaceFromTrackAction.h in Headers */, + 66A10ECE257F1DF800DD651A /* BannerSetNameAction.h in Headers */, 2ADE2F342244191E002598AF /* VirtualFloor.h in Headers */, + 66A10F8B257F1E1800DD651A /* LandSmoothAction.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4243,9 +4637,12 @@ buildActionMask = 2147483647; files = ( F7C44AF82030E8D3007E099F /* AVX2Drawing.cpp in Sources */, + 66A10FAE257F1E1800DD651A /* SmallSceneryPlaceAction.cpp in Sources */, F70839931FFC0B61002DCEFA /* Scenario.cpp in Sources */, C688791C20289B9B0084B384 /* Facility.cpp in Sources */, C688790C20289B9B0084B384 /* CarRide.cpp in Sources */, + 66A10F75257F1E1800DD651A /* RideSetPriceAction.cpp in Sources */, + 66A10F6D257F1E1800DD651A /* ParkSetParameterAction.cpp in Sources */, C688786820289A4A0084B384 /* Util.cpp in Sources */, C688792720289B9B0084B384 /* TopSpin.cpp in Sources */, C688787E20289ADE0084B384 /* Drawing.cpp in Sources */, @@ -4257,18 +4654,22 @@ C688789E20289B200084B384 /* FormatCodes.cpp in Sources */, C688785820289A0A0084B384 /* Balloon.cpp in Sources */, C688788820289ADE0084B384 /* X8DrawingEngine.cpp in Sources */, + 66A10F6A257F1E1800DD651A /* LargeScenerySetColourAction.cpp in Sources */, F775F5381EE3725C001F00E7 /* DummyAudioContext.cpp in Sources */, F775F5351EE35A89001F00E7 /* DummyUiContext.cpp in Sources */, 2A1F4FE1221FF4B0003CA045 /* Audio.cpp in Sources */, C688790920289B9B0084B384 /* WildMouse.cpp in Sources */, C688791420289B9B0084B384 /* Maze.cpp in Sources */, + 66A10ED8257F1DF800DD651A /* BannerSetColourAction.cpp in Sources */, C688784C202899BE0084B384 /* Game.cpp in Sources */, F76C85B41EC4E88300FA49E2 /* AudioMixer.cpp in Sources */, F76C85B71EC4E88300FA49E2 /* NullAudioSource.cpp in Sources */, C68878E720289B9B0084B384 /* Platform.Posix.cpp in Sources */, + 66A10F93257F1E1800DD651A /* LandSmoothAction.cpp in Sources */, C68878CE20289B9B0084B384 /* ObjectList.cpp in Sources */, C688788120289ADE0084B384 /* Line.cpp in Sources */, 93CBA4CA20A7504500867D56 /* ImageImporter.cpp in Sources */, + 66A10F7F257F1E1800DD651A /* MazePlaceTrackAction.cpp in Sources */, C688792520289B9B0084B384 /* RotoDrop.cpp in Sources */, F76C85BA1EC4E88300FA49E2 /* CommandLine.cpp in Sources */, C68878EE20289B9B0084B384 /* BolligerMabillardTrack.cpp in Sources */, @@ -4280,12 +4681,14 @@ F76C85BE1EC4E88300FA49E2 /* ScreenshotCommands.cpp in Sources */, C688786320289A0A0084B384 /* MapHelpers.cpp in Sources */, F76C85BF1EC4E88300FA49E2 /* SpriteCommands.cpp in Sources */, + 66A10F76257F1E1800DD651A /* SmallSceneryRemoveAction.cpp in Sources */, F76C85C01EC4E88300FA49E2 /* UriHandler.cpp in Sources */, C688786220289A0A0084B384 /* MapGen.cpp in Sources */, C68878A820289B2A0084B384 /* NewsItem.cpp in Sources */, 93F76EED20BFF6F900D4512C /* Drawing.Sprite.cpp in Sources */, 933F2CB820935653001B33FD /* LocalisationService.cpp in Sources */, F76C85C41EC4E88300FA49E2 /* Config.cpp in Sources */, + 66A10EC4257F1DF800DD651A /* FootpathAdditionPlaceAction.cpp in Sources */, C688792920289B9B0084B384 /* Chairlift.cpp in Sources */, C68878A020289B200084B384 /* LanguagePack.cpp in Sources */, F76C85C71EC4E88300FA49E2 /* IniReader.cpp in Sources */, @@ -4295,28 +4698,35 @@ 93F76EF220BFF74200D4512C /* Localisation.Date.cpp in Sources */, F76C85CC1EC4E88300FA49E2 /* Context.cpp in Sources */, C68878E220289B9B0084B384 /* Staff.cpp in Sources */, + 66A10F7E257F1E1800DD651A /* RideSetColourSchemeAction.cpp in Sources */, F76C85CF1EC4E88300FA49E2 /* Console.cpp in Sources */, C68878DC20289B9B0084B384 /* Painter.cpp in Sources */, 933C55B524B858490057E64B /* SeaDecrypt.cpp in Sources */, C688790120289B9B0084B384 /* ReverserRollerCoaster.cpp in Sources */, C688786120289A0A0084B384 /* MapAnimation.cpp in Sources */, F76C85D11EC4E88300FA49E2 /* Diagnostics.cpp in Sources */, + 66A10FB0257F1E1800DD651A /* SignSetStyleAction.cpp in Sources */, F76C85D41EC4E88300FA49E2 /* File.cpp in Sources */, C688790220289B9B0084B384 /* SideFrictionRollerCoaster.cpp in Sources */, F76C85D61EC4E88300FA49E2 /* FileScanner.cpp in Sources */, + 66A10F59257F1E1700DD651A /* SetCheatAction.cpp in Sources */, C68878F820289B9B0084B384 /* LayDownRollerCoaster.cpp in Sources */, C6887856202899FA0084B384 /* Scenery.cpp in Sources */, C688785D20289A0A0084B384 /* Footpath.cpp in Sources */, F76C85D91EC4E88300FA49E2 /* Guard.cpp in Sources */, C688790520289B9B0084B384 /* SuspendedSwingingCoaster.cpp in Sources */, C68878E920289B9B0084B384 /* Posix.cpp in Sources */, + 66A10EA2257F1DE100DD651A /* BalloonPressAction.cpp in Sources */, D48AFDB71EF78DBF0081C644 /* BenchGfxCommmands.cpp in Sources */, + 66A10F79257F1E1800DD651A /* RideCreateAction.cpp in Sources */, C688790320289B9B0084B384 /* StandUpRollerCoaster.cpp in Sources */, C62D838A1FD36D6F008C04F1 /* EditorObjectSelectionSession.cpp in Sources */, C6887851202899EA0084B384 /* Wall.cpp in Sources */, F76C85DB1EC4E88300FA49E2 /* IStream.cpp in Sources */, C688785A20289A0A0084B384 /* Climate.cpp in Sources */, + 66A10FA8257F1E1800DD651A /* RideEntranceExitRemoveAction.cpp in Sources */, C68878A920289B2A0084B384 /* Research.cpp in Sources */, + 66A10F61257F1E1700DD651A /* PlaceParkEntranceAction.cpp in Sources */, C6887850202899D40084B384 /* Cheats.cpp in Sources */, C688784D202899C40084B384 /* Diagnostic.cpp in Sources */, C688787020289A6F0084B384 /* VehiclePaint.cpp in Sources */, @@ -4329,11 +4739,15 @@ C68878DE20289B9B0084B384 /* Supports.cpp in Sources */, C688791720289B9B0084B384 /* MiniHelicopters.cpp in Sources */, 93B4DC1525487CDF008D63FF /* Formatting.cpp in Sources */, + 66A10EC3257F1DF800DD651A /* FootpathPlaceFromTrackAction.cpp in Sources */, C688784F202899D00084B384 /* CmdlineSprite.cpp in Sources */, F76C85EE1EC4E88300FA49E2 /* Zip.cpp in Sources */, C688793220289B9B0084B384 /* SplashBoats.cpp in Sources */, + 66A10FB2257F1E1800DD651A /* LargeSceneryRemoveAction.cpp in Sources */, F76C85F91EC4E88300FA49E2 /* Image.cpp in Sources */, C68878FF20289B9B0084B384 /* MultiDimensionRollerCoaster.cpp in Sources */, + 66A10F58257F1E1700DD651A /* StaffSetNameAction.cpp in Sources */, + 66A10F6C257F1E1800DD651A /* LoadOrQuitAction.cpp in Sources */, C688789220289B140084B384 /* FontFamilies.cpp in Sources */, C68878F120289B9B0084B384 /* FlyingRollerCoaster.cpp in Sources */, C688792B20289B9B0084B384 /* MiniatureRailway.cpp in Sources */, @@ -4341,20 +4755,26 @@ F76C85FF1EC4E88300FA49E2 /* Weather.cpp in Sources */, C688785920289A0A0084B384 /* Banner.cpp in Sources */, C68878EC20289B9B0084B384 /* AirPoweredVerticalCoaster.cpp in Sources */, + 66A10FAD257F1E1800DD651A /* TileModifyAction.cpp in Sources */, C688790B20289B9B0084B384 /* WoodenWildMouse.cpp in Sources */, C688792320289B9B0084B384 /* MotionSimulator.cpp in Sources */, 93DE9751209C3C1000FB1CC8 /* GameState.cpp in Sources */, C68878EF20289B9B0084B384 /* CompactInvertedCoaster.cpp in Sources */, C68878E320289B9B0084B384 /* Android.cpp in Sources */, + 66A10F70257F1E1800DD651A /* ParkSetDateAction.cpp in Sources */, F76C86051EC4E88300FA49E2 /* Editor.cpp in Sources */, F76C86071EC4E88300FA49E2 /* FileClassifier.cpp in Sources */, + 66A10FDE257F1E3000DD651A /* WaterLowerAction.cpp in Sources */, C688786920289A660084B384 /* CableLift.cpp in Sources */, C688790020289B9B0084B384 /* ReverseFreefallCoaster.cpp in Sources */, 93F76EF620BFF76E00D4512C /* Paint.Sprite.cpp in Sources */, C6607F481FE2B97E00D3FC0D /* Input.cpp in Sources */, + 66A10ECC257F1DF800DD651A /* ClearAction.cpp in Sources */, + 66A10FDB257F1E3000DD651A /* WallPlaceAction.cpp in Sources */, C688789F20289B200084B384 /* Language.cpp in Sources */, C688791620289B9B0084B384 /* MiniGolf.cpp in Sources */, C688787820289A780084B384 /* Track.cpp in Sources */, + 66A10ED6257F1DF800DD651A /* FootpathPlaceAction.cpp in Sources */, F76C86491EC4E88300FA49E2 /* NetworkAction.cpp in Sources */, C688788020289ADE0084B384 /* LightFX.cpp in Sources */, F76C864B1EC4E88300FA49E2 /* NetworkConnection.cpp in Sources */, @@ -4375,6 +4795,7 @@ 93F76EF520BFF76E00D4512C /* Paint.Peep.cpp in Sources */, C6887857202899FD0084B384 /* Park.cpp in Sources */, F76C86601EC4E88300FA49E2 /* BannerObject.cpp in Sources */, + 66A10FB4257F1E1800DD651A /* ScenarioSetSettingAction.cpp in Sources */, C688792A20289B9B0084B384 /* Lift.cpp in Sources */, F76C86621EC4E88300FA49E2 /* EntranceObject.cpp in Sources */, 93DFD04824521C1A001FCBAF /* HookEngine.cpp in Sources */, @@ -4386,6 +4807,7 @@ 9308DA02209908090079EE96 /* Surface.cpp in Sources */, C68878DD20289B9B0084B384 /* PaintHelpers.cpp in Sources */, F76C86661EC4E88300FA49E2 /* FootpathObject.cpp in Sources */, + 66A10F80257F1E1800DD651A /* NetworkModifyGroupAction.cpp in Sources */, C688793420289B9B0084B384 /* WaterCoaster.cpp in Sources */, F76C86681EC4E88300FA49E2 /* ImageTable.cpp in Sources */, C68878E620289B9B0084B384 /* Platform.Linux.cpp in Sources */, @@ -4395,10 +4817,14 @@ C688788E20289AE70084B384 /* SSE41Drawing.cpp in Sources */, F76C866C1EC4E88400FA49E2 /* Object.cpp in Sources */, F76C866E1EC4E88400FA49E2 /* ObjectFactory.cpp in Sources */, + 66A10FAB257F1E1800DD651A /* LandSetRightsAction.cpp in Sources */, 93FB272124ED3601008241C9 /* Cursors.cpp in Sources */, C68878A220289B200084B384 /* RealNames.cpp in Sources */, + 66A10F94257F1E1800DD651A /* StaffSetOrdersAction.cpp in Sources */, + 66A10EC7257F1DF800DD651A /* FootpathRemoveAction.cpp in Sources */, C688787120289A780084B384 /* Ride.cpp in Sources */, F76C86701EC4E88400FA49E2 /* ObjectManager.cpp in Sources */, + 66A10F52257F1E1700DD651A /* StaffSetCostumeAction.cpp in Sources */, C688791D20289B9B0084B384 /* Shop.cpp in Sources */, F76C86721EC4E88400FA49E2 /* ObjectRepository.cpp in Sources */, F76C86741EC4E88400FA49E2 /* RideObject.cpp in Sources */, @@ -4409,12 +4835,16 @@ C688792420289B9B0084B384 /* SwingingShip.cpp in Sources */, C68878F420289B9B0084B384 /* InvertedHairpinCoaster.cpp in Sources */, C68878A620289B2A0084B384 /* Finance.cpp in Sources */, + 66A10FA4257F1E1800DD651A /* RideSetNameAction.cpp in Sources */, C688788720289ADE0084B384 /* TTFSDLPort.cpp in Sources */, F76C86761EC4E88400FA49E2 /* SceneryGroupObject.cpp in Sources */, + 66A10FB1257F1E1800DD651A /* RideDemolishAction.cpp in Sources */, C68878F620289B9B0084B384 /* InvertedRollerCoaster.cpp in Sources */, + 66A10F55257F1E1700DD651A /* SurfaceSetStyleAction.cpp in Sources */, C68878E420289B9B0084B384 /* Linux.cpp in Sources */, F76C86791EC4E88400FA49E2 /* SmallSceneryObject.cpp in Sources */, 93F9DA3820B46F9D00D1BE92 /* ShopItem.cpp in Sources */, + 66A10ECD257F1DF800DD651A /* BannerRemoveAction.cpp in Sources */, C688787720289A780084B384 /* Station.cpp in Sources */, C68878DF20289B9B0084B384 /* VirtualFloor.cpp in Sources */, C68878CD20289B9B0084B384 /* DefaultObjects.cpp in Sources */, @@ -4424,6 +4854,7 @@ C688790D20289B9B0084B384 /* Circus.cpp in Sources */, C688788F20289B140084B384 /* Chat.cpp in Sources */, C688789A20289B200084B384 /* ConversionTables.cpp in Sources */, + 66A10ED2257F1DF800DD651A /* FootpathAdditionRemoveAction.cpp in Sources */, C688791020289B9B0084B384 /* FerrisWheel.cpp in Sources */, C688791120289B9B0084B384 /* FlyingSaucers.cpp in Sources */, C688784A202899B40084B384 /* input.cpp in Sources */, @@ -4435,28 +4866,46 @@ C68878DB20289B9B0084B384 /* Paint.cpp in Sources */, F76C86811EC4E88400FA49E2 /* WaterObject.cpp in Sources */, F76C86861EC4E88400FA49E2 /* OpenRCT2.cpp in Sources */, + 66A10F89257F1E1800DD651A /* PauseToggleAction.cpp in Sources */, + 66A10F66257F1E1700DD651A /* RideSetVehicleAction.cpp in Sources */, C68878F320289B9B0084B384 /* HeartlineTwisterCoaster.cpp in Sources */, C688788320289ADE0084B384 /* ScrollingText.cpp in Sources */, C68878F720289B9B0084B384 /* JuniorRollerCoaster.cpp in Sources */, + 66A10F6F257F1E1800DD651A /* RideEntranceExitPlaceAction.cpp in Sources */, + 66A10F64257F1E1700DD651A /* LandRaiseAction.cpp in Sources */, + 66A10F7D257F1E1800DD651A /* ParkSetNameAction.cpp in Sources */, C688792020289B9B0084B384 /* GoKarts.cpp in Sources */, + 66A10FD9257F1E3000DD651A /* WaterSetHeightAction.cpp in Sources */, 939A359B20C12FC800630B3F /* Paint.Misc.cpp in Sources */, C688792E20289B9B0084B384 /* BoatHire.cpp in Sources */, F76C869C1EC4E88400FA49E2 /* ParkImporter.cpp in Sources */, F76C86A31EC4E88400FA49E2 /* Crash.cpp in Sources */, + 66A10ED1257F1DF800DD651A /* CustomAction.cpp in Sources */, 2A1F4FE2221FF4B0003CA045 /* macos.mm in Sources */, C688789420289B140084B384 /* Screenshot.cpp in Sources */, 9346F9DC208A191900C77D91 /* GuestPathfinding.cpp in Sources */, C688790620289B9B0084B384 /* TwisterRollerCoaster.cpp in Sources */, C688786720289A4A0084B384 /* SawyerCoding.cpp in Sources */, 93F9DA3B20B4701100D1BE92 /* StdInOutConsole.cpp in Sources */, + 66A10FA1257F1E1800DD651A /* SmallScenerySetColourAction.cpp in Sources */, + 66A10F95257F1E1800DD651A /* GuestSetFlagsAction.cpp in Sources */, + 66A10FB5257F1E1800DD651A /* SignSetNameAction.cpp in Sources */, + 66A10FDC257F1E3000DD651A /* TrackPlaceAction.cpp in Sources */, 9344BEFA20C1E6180047D165 /* Crypt.OpenSSL.cpp in Sources */, + 66A10ECB257F1DF800DD651A /* BannerSetStyleAction.cpp in Sources */, 93F76F0520BFF77B00D4512C /* Paint.TileElement.cpp in Sources */, C68878FE20289B9B0084B384 /* MiniSuspendedCoaster.cpp in Sources */, F76C86AD1EC4E88400FA49E2 /* PlatformEnvironment.cpp in Sources */, + 66A10F6B257F1E1800DD651A /* ParkSetLoanAction.cpp in Sources */, + 66A10FE0257F1E3000DD651A /* WallRemoveAction.cpp in Sources */, + 66A10FBB257F1E1800DD651A /* LargeSceneryPlaceAction.cpp in Sources */, + 66A10F7A257F1E1800DD651A /* RideSetSettingAction.cpp in Sources */, C688791220289B9B0084B384 /* GhostTrain.cpp in Sources */, C688787F20289ADE0084B384 /* Font.cpp in Sources */, 93CBA4C520A7502E00867D56 /* Imaging.cpp in Sources */, F76C86AF1EC4E88400FA49E2 /* S4Importer.cpp in Sources */, + 66A10F7C257F1E1800DD651A /* StaffHireNewAction.cpp in Sources */, + 66A10F85257F1E1800DD651A /* LandSetHeightAction.cpp in Sources */, F76C86B01EC4E88400FA49E2 /* Tables.cpp in Sources */, C688788520289ADE0084B384 /* Text.cpp in Sources */, F76C86B41EC4E88400FA49E2 /* SawyerChunk.cpp in Sources */, @@ -4464,8 +4913,10 @@ C68878E120289B9B0084B384 /* PeepData.cpp in Sources */, F76C86B61EC4E88400FA49E2 /* SawyerChunkReader.cpp in Sources */, F76C86B81EC4E88400FA49E2 /* SawyerChunkWriter.cpp in Sources */, + 66A10FE1257F1E3000DD651A /* WallSetColourAction.cpp in Sources */, C6887855202899F60084B384 /* Particle.cpp in Sources */, C688784E202899CB0084B384 /* Date.cpp in Sources */, + 66A10F9B257F1E1800DD651A /* ParkSetResearchFundingAction.cpp in Sources */, F76C86BA1EC4E88400FA49E2 /* SawyerEncoding.cpp in Sources */, F76C86C31EC4E88400FA49E2 /* S6Exporter.cpp in Sources */, C68878E820289B9B0084B384 /* Platform.Win32.cpp in Sources */, @@ -4477,46 +4928,65 @@ C688790A20289B9B0084B384 /* WoodenRollerCoaster.cpp in Sources */, C688787220289A780084B384 /* MusicList.cpp in Sources */, 93F76F0220BFF77B00D4512C /* Paint.Surface.cpp in Sources */, + 66A10ECF257F1DF800DD651A /* ClimateSetAction.cpp in Sources */, 93DFD02F24521BA0001FCBAF /* FileWatcher.cpp in Sources */, F76C871C1EC4E88400FA49E2 /* TrackDesignRepository.cpp in Sources */, C68878FA20289B9B0084B384 /* LoopingRollerCoaster.cpp in Sources */, + 66A10F57257F1E1700DD651A /* RideSetAppearanceAction.cpp in Sources */, + 66A10FB9257F1E1800DD651A /* RideSetStatusAction.cpp in Sources */, C68878A720289B2A0084B384 /* Marketing.cpp in Sources */, F76C87331EC4E88400FA49E2 /* ScenarioRepository.cpp in Sources */, C68878FB20289B9B0084B384 /* MineRide.cpp in Sources */, + 66A10FD8257F1E3000DD651A /* TrackRemoveAction.cpp in Sources */, 9308D9FF209908090079EE96 /* TileElement.cpp in Sources */, + 66A10FAA257F1E1800DD651A /* SetParkEntranceFeeAction.cpp in Sources */, + 66A10F9E257F1E1800DD651A /* ParkMarketingAction.cpp in Sources */, C688789020289B140084B384 /* Colour.cpp in Sources */, + 66A10FA3257F1E1800DD651A /* LandLowerAction.cpp in Sources */, + 66A10FB7257F1E1800DD651A /* LandBuyRightsAction.cpp in Sources */, C68878EB20289B9B0084B384 /* Windows.cpp in Sources */, C688789920289B140084B384 /* Window.cpp in Sources */, F76C87351EC4E88400FA49E2 /* ScenarioSources.cpp in Sources */, F76C87381EC4E88400FA49E2 /* TitleScreen.cpp in Sources */, F76C873A1EC4E88400FA49E2 /* TitleSequence.cpp in Sources */, + 66A10EC0257F1DF800DD651A /* BannerPlaceAction.cpp in Sources */, C6887852202899ED0084B384 /* TileInspector.cpp in Sources */, F76C873C1EC4E88400FA49E2 /* TitleSequenceManager.cpp in Sources */, + 66A10F9D257F1E1800DD651A /* StaffFireAction.cpp in Sources */, C688793320289B9B0084B384 /* SubmarineRide.cpp in Sources */, 93F76EEE20BFF6F900D4512C /* Drawing.String.cpp in Sources */, C688785C20289A0A0084B384 /* Entrance.cpp in Sources */, C688790E20289B9B0084B384 /* CrookedHouse.cpp in Sources */, C68878F520289B9B0084B384 /* InvertedImpulseCoaster.cpp in Sources */, C688793020289B9B0084B384 /* LogFlume.cpp in Sources */, + 66A10F82257F1E1800DD651A /* PlayerSetGroupAction.cpp in Sources */, 2ADE2F3222441905002598AF /* DiscordService.cpp in Sources */, C688786620289A430084B384 /* Intent.cpp in Sources */, + 66A10FBA257F1E1800DD651A /* PlayerKickAction.cpp in Sources */, C68878E520289B9B0084B384 /* Platform.Android.cpp in Sources */, C68878EA20289B9B0084B384 /* Shared.cpp in Sources */, F76C87451EC4E88400FA49E2 /* Version.cpp in Sources */, 9346F9D9208A191900C77D91 /* Guest.cpp in Sources */, C688789C20289B200084B384 /* Currency.cpp in Sources */, + 66A10F9C257F1E1800DD651A /* PeepPickupAction.cpp in Sources */, C68879A420289C060084B384 /* Platform.macOS.mm in Sources */, + 66A10FA0257F1E1800DD651A /* StaffSetPatrolAreaAction.cpp in Sources */, + 66A10F5B257F1E1700DD651A /* GuestSetNameAction.cpp in Sources */, C688787420289A780084B384 /* TrackDesignSave.cpp in Sources */, C688790F20289B9B0084B384 /* Dodgems.cpp in Sources */, C688791E20289B9B0084B384 /* 3dCinema.cpp in Sources */, C688786420289A0A0084B384 /* MoneyEffect.cpp in Sources */, + 66A10F98257F1E1800DD651A /* PlacePeepSpawnAction.cpp in Sources */, C68878A420289B200084B384 /* UTF8.cpp in Sources */, C688786D20289A6F0084B384 /* TrackPaint.cpp in Sources */, 93F76F0620BFF77B00D4512C /* Paint.Entrance.cpp in Sources */, C688792120289B9B0084B384 /* LaunchedFreefall.cpp in Sources */, + 66A10FD4257F1E3000DD651A /* TrackSetBrakeSpeedAction.cpp in Sources */, C688791920289B9B0084B384 /* ObservationTower.cpp in Sources */, 93F76EF020BFF71700D4512C /* InteractiveConsole.cpp in Sources */, C6887853202899F00084B384 /* Sprite.cpp in Sources */, + 66A10FB3257F1E1800DD651A /* MazeSetTrackAction.cpp in Sources */, + 66A10EC5257F1DF800DD651A /* BannerSetNameAction.cpp in Sources */, C688786F20289A6F0084B384 /* VehicleData.cpp in Sources */, C688786520289A400084B384 /* _legacy.cpp in Sources */, C688785F20289A0A0084B384 /* LargeScenery.cpp in Sources */, @@ -4524,6 +4994,7 @@ C688792220289B9B0084B384 /* MagicCarpet.cpp in Sources */, 93F76F0120BFF77B00D4512C /* Paint.LargeScenery.cpp in Sources */, C688790720289B9B0084B384 /* VerticalDropRollerCoaster.cpp in Sources */, + 66A10F60257F1E1700DD651A /* ParkEntranceRemoveAction.cpp in Sources */, 93F9DA3A20B46FCA00D1BE92 /* SceneryObject.cpp in Sources */, 936F412924CE030F00E07BCF /* NetworkBase.cpp in Sources */, C688787520289A780084B384 /* RideData.cpp in Sources */, @@ -4532,7 +5003,9 @@ C688789320289B140084B384 /* Fonts.cpp in Sources */, C688792F20289B9B0084B384 /* DingySlide.cpp in Sources */, C688787920289A780084B384 /* TrackData.cpp in Sources */, + 66A10F71257F1E1800DD651A /* StaffSetColourAction.cpp in Sources */, C68878F020289B9B0084B384 /* CorkscrewRollerCoaster.cpp in Sources */, + 66A10FD1257F1E3000DD651A /* WaterRaiseAction.cpp in Sources */, C688791820289B9B0084B384 /* MonorailCycles.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/src/openrct2-ui/input/KeyboardShortcut.cpp b/src/openrct2-ui/input/KeyboardShortcut.cpp index 91423ebf3f..cd2452a16a 100644 --- a/src/openrct2-ui/input/KeyboardShortcut.cpp +++ b/src/openrct2-ui/input/KeyboardShortcut.cpp @@ -18,8 +18,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/interface/ViewportInteraction.cpp b/src/openrct2-ui/interface/ViewportInteraction.cpp index cec965f646..7fb5e43d06 100644 --- a/src/openrct2-ui/interface/ViewportInteraction.cpp +++ b/src/openrct2-ui/interface/ViewportInteraction.cpp @@ -18,12 +18,12 @@ #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Banner.cpp b/src/openrct2-ui/windows/Banner.cpp index 97bdecd48f..9b9e00c36c 100644 --- a/src/openrct2-ui/windows/Banner.cpp +++ b/src/openrct2-ui/windows/Banner.cpp @@ -12,10 +12,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Cheats.cpp b/src/openrct2-ui/windows/Cheats.cpp index 236ede7f9f..c4c34a6998 100644 --- a/src/openrct2-ui/windows/Cheats.cpp +++ b/src/openrct2-ui/windows/Cheats.cpp @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index be5bf110a4..d07f5deff1 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp index 79d08975a2..4804273421 100644 --- a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp +++ b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/EditorScenarioOptions.cpp b/src/openrct2-ui/windows/EditorScenarioOptions.cpp index 15abc702ab..9a4d238ef5 100644 --- a/src/openrct2-ui/windows/EditorScenarioOptions.cpp +++ b/src/openrct2-ui/windows/EditorScenarioOptions.cpp @@ -17,8 +17,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Finances.cpp b/src/openrct2-ui/windows/Finances.cpp index 04f13d2e41..27b12f1a97 100644 --- a/src/openrct2-ui/windows/Finances.cpp +++ b/src/openrct2-ui/windows/Finances.cpp @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index a3031d2821..865fdc43e9 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp index a91f79f185..c5c0f46d4a 100644 --- a/src/openrct2-ui/windows/Guest.cpp +++ b/src/openrct2-ui/windows/Guest.cpp @@ -14,8 +14,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/LandRights.cpp b/src/openrct2-ui/windows/LandRights.cpp index 30fb79e5be..60de6b797c 100644 --- a/src/openrct2-ui/windows/LandRights.cpp +++ b/src/openrct2-ui/windows/LandRights.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp index c3cd4ee0de..1539ee2e32 100644 --- a/src/openrct2-ui/windows/Map.cpp +++ b/src/openrct2-ui/windows/Map.cpp @@ -18,12 +18,13 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include +#include #include #include #include diff --git a/src/openrct2-ui/windows/MazeConstruction.cpp b/src/openrct2-ui/windows/MazeConstruction.cpp index 7a649af8a3..32b22622fe 100644 --- a/src/openrct2-ui/windows/MazeConstruction.cpp +++ b/src/openrct2-ui/windows/MazeConstruction.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Multiplayer.cpp b/src/openrct2-ui/windows/Multiplayer.cpp index ca63d3ded6..b38f1116e5 100644 --- a/src/openrct2-ui/windows/Multiplayer.cpp +++ b/src/openrct2-ui/windows/Multiplayer.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/NewCampaign.cpp b/src/openrct2-ui/windows/NewCampaign.cpp index 54c67d1abd..734438d590 100644 --- a/src/openrct2-ui/windows/NewCampaign.cpp +++ b/src/openrct2-ui/windows/NewCampaign.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Park.cpp b/src/openrct2-ui/windows/Park.cpp index 6e405d51a8..6866b57d79 100644 --- a/src/openrct2-ui/windows/Park.cpp +++ b/src/openrct2-ui/windows/Park.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Player.cpp b/src/openrct2-ui/windows/Player.cpp index 13b473b5d3..54bca579b1 100644 --- a/src/openrct2-ui/windows/Player.cpp +++ b/src/openrct2-ui/windows/Player.cpp @@ -13,8 +13,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Research.cpp b/src/openrct2-ui/windows/Research.cpp index a47cb55ca6..1ef336729a 100644 --- a/src/openrct2-ui/windows/Research.cpp +++ b/src/openrct2-ui/windows/Research.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp index afe2655032..6f845c842d 100644 --- a/src/openrct2-ui/windows/Ride.cpp +++ b/src/openrct2-ui/windows/Ride.cpp @@ -23,11 +23,11 @@ #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index 33617dcc35..3c84d635b9 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -17,10 +17,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Sign.cpp b/src/openrct2-ui/windows/Sign.cpp index cd0b8e1c9f..b6f876b8c1 100644 --- a/src/openrct2-ui/windows/Sign.cpp +++ b/src/openrct2-ui/windows/Sign.cpp @@ -12,10 +12,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Staff.cpp b/src/openrct2-ui/windows/Staff.cpp index 2290d4733d..617d502f67 100644 --- a/src/openrct2-ui/windows/Staff.cpp +++ b/src/openrct2-ui/windows/Staff.cpp @@ -16,10 +16,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/StaffFirePrompt.cpp b/src/openrct2-ui/windows/StaffFirePrompt.cpp index 618a3c7755..baae4c9cb0 100644 --- a/src/openrct2-ui/windows/StaffFirePrompt.cpp +++ b/src/openrct2-ui/windows/StaffFirePrompt.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/StaffList.cpp b/src/openrct2-ui/windows/StaffList.cpp index d2fbda0959..213f6f67e8 100644 --- a/src/openrct2-ui/windows/StaffList.cpp +++ b/src/openrct2-ui/windows/StaffList.cpp @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index 36ef268c07..e11f474989 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/TitleMenu.cpp b/src/openrct2-ui/windows/TitleMenu.cpp index fd4bf9eea3..16470bee38 100644 --- a/src/openrct2-ui/windows/TitleMenu.cpp +++ b/src/openrct2-ui/windows/TitleMenu.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 30dea41c29..5a8d7189ed 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -26,25 +26,25 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2/Cheats.cpp b/src/openrct2/Cheats.cpp index 4dd62e43f4..e8458acf61 100644 --- a/src/openrct2/Cheats.cpp +++ b/src/openrct2/Cheats.cpp @@ -10,8 +10,8 @@ #include "Cheats.h" #include "GameState.h" -#include "actions/ParkSetLoanAction.hpp" -#include "actions/SetCheatAction.hpp" +#include "actions/ParkSetLoanAction.h" +#include "actions/SetCheatAction.h" #include "config/Config.h" #include "core/DataSerialiser.h" #include "localisation/Localisation.h" diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index 511e2669bb..2a5264d769 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -16,8 +16,8 @@ #include "GameState.h" #include "OpenRCT2.h" #include "ParkImporter.h" -#include "actions/LandBuyRightsAction.hpp" -#include "actions/LandSetRightsAction.hpp" +#include "actions/LandBuyRightsAction.h" +#include "actions/LandSetRightsAction.h" #include "audio/audio.h" #include "interface/Viewport.h" #include "interface/Window_internal.h" diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 14a76e14b4..b9b0b402eb 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -19,7 +19,7 @@ #include "ParkImporter.h" #include "PlatformEnvironment.h" #include "ReplayManager.h" -#include "actions/LoadOrQuitAction.hpp" +#include "actions/LoadOrQuitAction.h" #include "audio/audio.h" #include "config/Config.h" #include "core/FileScanner.h" diff --git a/src/openrct2/ReplayManager.cpp b/src/openrct2/ReplayManager.cpp index 2b010cca33..2f9577a0d5 100644 --- a/src/openrct2/ReplayManager.cpp +++ b/src/openrct2/ReplayManager.cpp @@ -15,13 +15,13 @@ #include "OpenRCT2.h" #include "ParkImporter.h" #include "PlatformEnvironment.h" -#include "actions/FootpathPlaceAction.hpp" +#include "actions/FootpathPlaceAction.h" #include "actions/GameAction.h" -#include "actions/RideEntranceExitPlaceAction.hpp" -#include "actions/RideSetSetting.hpp" -#include "actions/SetCheatAction.hpp" -#include "actions/TileModifyAction.hpp" -#include "actions/TrackPlaceAction.hpp" +#include "actions/RideEntranceExitPlaceAction.h" +#include "actions/RideSetSettingAction.h" +#include "actions/SetCheatAction.h" +#include "actions/TileModifyAction.h" +#include "actions/TrackPlaceAction.h" #include "config/Config.h" #include "core/DataSerialiser.h" #include "core/Path.hpp" diff --git a/src/openrct2/actions/BalloonPressAction.cpp b/src/openrct2/actions/BalloonPressAction.cpp new file mode 100644 index 0000000000..b32cc5c9b6 --- /dev/null +++ b/src/openrct2/actions/BalloonPressAction.cpp @@ -0,0 +1,48 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "BalloonPressAction.h" + +#include "GameAction.h" + +void BalloonPressAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("id", _spriteIndex); +} + +void BalloonPressAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_spriteIndex); +} + +GameActions::Result::Ptr BalloonPressAction::Query() const +{ + auto balloon = TryGetEntity(_spriteIndex); + if (balloon == nullptr) + { + log_error("Tried getting invalid sprite for balloon: %u", _spriteIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return MakeResult(); +} + +GameActions::Result::Ptr BalloonPressAction::Execute() const +{ + auto balloon = TryGetEntity(_spriteIndex); + if (balloon == nullptr) + { + log_error("Tried getting invalid sprite for balloon: %u", _spriteIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + balloon->Press(); + + return MakeResult(); +} diff --git a/src/openrct2/actions/BalloonPressAction.h b/src/openrct2/actions/BalloonPressAction.h new file mode 100644 index 0000000000..9496b47aa2 --- /dev/null +++ b/src/openrct2/actions/BalloonPressAction.h @@ -0,0 +1,35 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(BalloonPressAction, GAME_COMMAND_BALLOON_PRESS, GameActions::Result) +{ + uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; + +public: + BalloonPressAction() = default; + BalloonPressAction(uint16_t spriteIndex) + : _spriteIndex(spriteIndex) + { + } + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/BalloonPressAction.hpp b/src/openrct2/actions/BalloonPressAction.hpp deleted file mode 100644 index 17a800d197..0000000000 --- a/src/openrct2/actions/BalloonPressAction.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(BalloonPressAction, GAME_COMMAND_BALLOON_PRESS, GameActions::Result) -{ - uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; - -public: - BalloonPressAction() = default; - BalloonPressAction(uint16_t spriteIndex) - : _spriteIndex(spriteIndex) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("id", _spriteIndex); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_spriteIndex); - } - - GameActions::Result::Ptr Query() const override - { - auto balloon = TryGetEntity(_spriteIndex); - if (balloon == nullptr) - { - log_error("Tried getting invalid sprite for balloon: %u", _spriteIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto balloon = TryGetEntity(_spriteIndex); - if (balloon == nullptr) - { - log_error("Tried getting invalid sprite for balloon: %u", _spriteIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - balloon->Press(); - - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/BannerPlaceAction.cpp b/src/openrct2/actions/BannerPlaceAction.cpp new file mode 100644 index 0000000000..4d9910a299 --- /dev/null +++ b/src/openrct2/actions/BannerPlaceAction.cpp @@ -0,0 +1,182 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "BannerPlaceAction.h" + +#include "../management/Finance.h" +#include "../world/Banner.h" +#include "../world/MapAnimation.h" +#include "../world/Scenery.h" +#include "GameAction.h" + +void BannerPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _bannerType); + visitor.Visit("primaryColour", _primaryColour); + _bannerIndex = create_new_banner(0); +} + +void BannerPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_bannerType) << DS_TAG(_bannerIndex) << DS_TAG(_primaryColour); +} + +GameActions::Result::Ptr BannerPlaceAction::Query() const +{ + auto res = MakeResult(); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->Expenditure = ExpenditureType::Landscaping; + res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; + + if (!map_check_free_elements_and_reorganise(1)) + { + log_error("No free map elements."); + return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_POSITION_THIS_HERE); + } + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + auto pathElement = GetValidPathElement(); + + if (pathElement == nullptr) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS); + } + + if (!map_can_build_at(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto baseHeight = _loc.z + PATH_HEIGHT_STEP; + BannerElement* existingBannerElement = map_get_banner_element_at({ _loc.x, _loc.y, baseHeight }, _loc.direction); + if (existingBannerElement != nullptr) + { + return MakeResult(GameActions::Status::ItemAlreadyPlaced, 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(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + auto banner = GetBanner(_bannerIndex); + if (!banner->IsNull()) + { + log_error("Banner index in use, bannerIndex = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, 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(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + res->Cost = bannerEntry->banner.price; + return res; +} + +GameActions::Result::Ptr BannerPlaceAction::Execute() const +{ + auto res = MakeResult(); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->Expenditure = ExpenditureType::Landscaping; + res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; + + if (!map_check_free_elements_and_reorganise(1)) + { + log_error("No free map elements."); + return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_POSITION_THIS_HERE); + } + + if (_bannerIndex == BANNER_INDEX_NULL || _bannerIndex >= MAX_BANNERS) + { + log_error("Invalid banner index, bannerIndex = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, 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(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + auto banner = GetBanner(_bannerIndex); + if (!banner->IsNull()) + { + log_error("Banner index in use, bannerIndex = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + TileElement* newTileElement = tile_element_insert({ _loc, _loc.z + (2 * COORDS_Z_STEP) }, 0b0000); + assert(newTileElement != nullptr); + + banner->flags = 0; + banner->text = {}; + banner->text_colour = 2; + banner->type = _bannerType; // Banner must be deleted after this point in an early return + banner->colour = _primaryColour; + banner->position = TileCoordsXY(_loc); + newTileElement->SetType(TILE_ELEMENT_TYPE_BANNER); + BannerElement* bannerElement = newTileElement->AsBanner(); + bannerElement->SetClearanceZ(_loc.z + PATH_CLEARANCE); + bannerElement->SetPosition(_loc.direction); + bannerElement->ResetAllowedEdges(); + bannerElement->SetIndex(_bannerIndex); + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + bannerElement->SetGhost(true); + } + map_invalidate_tile_full(_loc); + map_animation_create(MAP_ANIMATION_TYPE_BANNER, CoordsXYZ{ _loc, bannerElement->GetBaseZ() }); + + res->Cost = bannerEntry->banner.price; + return res; +} + +PathElement* BannerPlaceAction::GetValidPathElement() const +{ + TileElement* tileElement = map_get_first_element_at(_loc); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH) + continue; + + auto pathElement = tileElement->AsPath(); + + if (pathElement->GetBaseZ() != _loc.z && pathElement->GetBaseZ() != _loc.z - PATH_HEIGHT_STEP) + continue; + + if (!(pathElement->GetEdges() & (1 << _loc.direction))) + continue; + + if (pathElement->IsGhost() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + continue; + + return pathElement; + } while (!(tileElement++)->IsLastForTile()); + return nullptr; +} diff --git a/src/openrct2/actions/BannerPlaceAction.h b/src/openrct2/actions/BannerPlaceAction.h new file mode 100644 index 0000000000..691b7057bc --- /dev/null +++ b/src/openrct2/actions/BannerPlaceAction.h @@ -0,0 +1,45 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(BannerPlaceAction, GAME_COMMAND_PLACE_BANNER, GameActions::Result) +{ +private: + CoordsXYZD _loc; + ObjectEntryIndex _bannerType{ BANNER_NULL }; + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; + uint8_t _primaryColour{}; + +public: + BannerPlaceAction() = default; + BannerPlaceAction(const CoordsXYZD& loc, uint8_t bannerType, BannerIndex bannerIndex, uint8_t primaryColour) + : _loc(loc) + , _bannerType(bannerType) + , _bannerIndex(bannerIndex) + , _primaryColour(primaryColour) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + PathElement* GetValidPathElement() const; +}; diff --git a/src/openrct2/actions/BannerPlaceAction.hpp b/src/openrct2/actions/BannerPlaceAction.hpp deleted file mode 100644 index 4e3ee579fc..0000000000 --- a/src/openrct2/actions/BannerPlaceAction.hpp +++ /dev/null @@ -1,207 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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, GameActions::Result) -{ -private: - CoordsXYZD _loc; - ObjectEntryIndex _bannerType{ BANNER_NULL }; - BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; - uint8_t _primaryColour{}; - -public: - BannerPlaceAction() = default; - BannerPlaceAction(const CoordsXYZD& loc, uint8_t bannerType, BannerIndex bannerIndex, uint8_t primaryColour) - : _loc(loc) - , _bannerType(bannerType) - , _bannerIndex(bannerIndex) - , _primaryColour(primaryColour) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _bannerType); - visitor.Visit("primaryColour", _primaryColour); - _bannerIndex = create_new_banner(0); - } - - 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); - } - - GameActions::Result::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->Expenditure = ExpenditureType::Landscaping; - res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; - - if (!map_check_free_elements_and_reorganise(1)) - { - log_error("No free map elements."); - return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_POSITION_THIS_HERE); - } - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - auto pathElement = GetValidPathElement(); - - if (pathElement == nullptr) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS); - } - - if (!map_can_build_at(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - auto baseHeight = _loc.z + PATH_HEIGHT_STEP; - BannerElement* existingBannerElement = map_get_banner_element_at({ _loc.x, _loc.y, baseHeight }, _loc.direction); - if (existingBannerElement != nullptr) - { - return MakeResult(GameActions::Status::ItemAlreadyPlaced, 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(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - auto banner = GetBanner(_bannerIndex); - if (!banner->IsNull()) - { - log_error("Banner index in use, bannerIndex = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, 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(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - res->Cost = bannerEntry->banner.price; - return res; - } - - GameActions::Result::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->Expenditure = ExpenditureType::Landscaping; - res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; - - if (!map_check_free_elements_and_reorganise(1)) - { - log_error("No free map elements."); - return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_POSITION_THIS_HERE); - } - - if (_bannerIndex == BANNER_INDEX_NULL || _bannerIndex >= MAX_BANNERS) - { - log_error("Invalid banner index, bannerIndex = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, 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(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - auto banner = GetBanner(_bannerIndex); - if (!banner->IsNull()) - { - log_error("Banner index in use, bannerIndex = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - TileElement* newTileElement = tile_element_insert({ _loc, _loc.z + (2 * COORDS_Z_STEP) }, 0b0000); - assert(newTileElement != nullptr); - - banner->flags = 0; - banner->text = {}; - banner->text_colour = 2; - banner->type = _bannerType; // Banner must be deleted after this point in an early return - banner->colour = _primaryColour; - banner->position = TileCoordsXY(_loc); - newTileElement->SetType(TILE_ELEMENT_TYPE_BANNER); - BannerElement* bannerElement = newTileElement->AsBanner(); - bannerElement->SetClearanceZ(_loc.z + PATH_CLEARANCE); - bannerElement->SetPosition(_loc.direction); - bannerElement->ResetAllowedEdges(); - bannerElement->SetIndex(_bannerIndex); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - bannerElement->SetGhost(true); - } - map_invalidate_tile_full(_loc); - map_animation_create(MAP_ANIMATION_TYPE_BANNER, CoordsXYZ{ _loc, bannerElement->GetBaseZ() }); - - res->Cost = bannerEntry->banner.price; - return res; - } - -private: - PathElement* GetValidPathElement() const - { - TileElement* tileElement = map_get_first_element_at(_loc); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH) - continue; - - auto pathElement = tileElement->AsPath(); - - if (pathElement->GetBaseZ() != _loc.z && pathElement->GetBaseZ() != _loc.z - PATH_HEIGHT_STEP) - continue; - - if (!(pathElement->GetEdges() & (1 << _loc.direction))) - continue; - - if (pathElement->IsGhost() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - continue; - - return pathElement; - } while (!(tileElement++)->IsLastForTile()); - return nullptr; - } -}; diff --git a/src/openrct2/actions/BannerRemoveAction.cpp b/src/openrct2/actions/BannerRemoveAction.cpp new file mode 100644 index 0000000000..624f2a799f --- /dev/null +++ b/src/openrct2/actions/BannerRemoveAction.cpp @@ -0,0 +1,137 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "BannerRemoveAction.h" + +#include "../management/Finance.h" +#include "../world/Banner.h" +#include "../world/MapAnimation.h" +#include "../world/Scenery.h" +#include "GameAction.h" + +void BannerRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); +} + +void BannerRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr BannerRemoveAction::Query() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::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 (!LocationValid(_loc) || !map_can_build_at({ _loc.x, _loc.y, _loc.z - 16 })) + { + return MakeResult(GameActions::Status::NotOwned, 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(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + if (bannerElement->GetIndex() >= MAX_BANNERS || bannerElement->GetIndex() == BANNER_INDEX_NULL) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + auto banner = bannerElement->GetBanner(); + if (banner == nullptr) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GameActions::Status::InvalidParameters, 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; +} + +GameActions::Result::Ptr BannerRemoveAction::Execute() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::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(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + if (bannerElement->GetIndex() >= MAX_BANNERS || bannerElement->GetIndex() == BANNER_INDEX_NULL) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + auto banner = bannerElement->GetBanner(); + if (banner == nullptr) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GameActions::Status::InvalidParameters, 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(bannerElement)); + map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 32 }); + bannerElement->Remove(); + + return res; +} + +BannerElement* BannerRemoveAction::GetBannerElementAt() const +{ + TileElement* tileElement = map_get_first_element_at(_loc); + + // Find the banner element at known z and position + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) + continue; + if (tileElement->GetBaseZ() != _loc.z) + 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; +} diff --git a/src/openrct2/actions/BannerRemoveAction.h b/src/openrct2/actions/BannerRemoveAction.h new file mode 100644 index 0000000000..0ddcf555e0 --- /dev/null +++ b/src/openrct2/actions/BannerRemoveAction.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(BannerRemoveAction, GAME_COMMAND_REMOVE_BANNER, GameActions::Result) +{ +private: + CoordsXYZD _loc; + +public: + BannerRemoveAction() = default; + BannerRemoveAction(const CoordsXYZD& loc) + : _loc(loc) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + BannerElement* GetBannerElementAt() const; +}; diff --git a/src/openrct2/actions/BannerRemoveAction.hpp b/src/openrct2/actions/BannerRemoveAction.hpp deleted file mode 100644 index 9edd6b5a49..0000000000 --- a/src/openrct2/actions/BannerRemoveAction.hpp +++ /dev/null @@ -1,158 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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, GameActions::Result) -{ -private: - CoordsXYZD _loc; - -public: - BannerRemoveAction() = default; - BannerRemoveAction(const CoordsXYZD& loc) - : _loc(loc) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::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 (!LocationValid(_loc) || !map_can_build_at({ _loc.x, _loc.y, _loc.z - 16 })) - { - return MakeResult(GameActions::Status::NotOwned, 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(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - if (bannerElement->GetIndex() >= MAX_BANNERS || bannerElement->GetIndex() == BANNER_INDEX_NULL) - { - log_error("Invalid banner index. index = ", bannerElement->GetIndex()); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - auto banner = bannerElement->GetBanner(); - if (banner == nullptr) - { - log_error("Invalid banner index. index = ", bannerElement->GetIndex()); - return MakeResult(GameActions::Status::InvalidParameters, 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; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::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(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - if (bannerElement->GetIndex() >= MAX_BANNERS || bannerElement->GetIndex() == BANNER_INDEX_NULL) - { - log_error("Invalid banner index. index = ", bannerElement->GetIndex()); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - auto banner = bannerElement->GetBanner(); - if (banner == nullptr) - { - log_error("Invalid banner index. index = ", bannerElement->GetIndex()); - return MakeResult(GameActions::Status::InvalidParameters, 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(bannerElement)); - map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 32 }); - bannerElement->Remove(); - - return res; - } - -private: - BannerElement* GetBannerElementAt() const - { - TileElement* tileElement = map_get_first_element_at(_loc); - - // Find the banner element at known z and position - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) - continue; - if (tileElement->GetBaseZ() != _loc.z) - 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; - } -}; diff --git a/src/openrct2/actions/BannerSetColourAction.cpp b/src/openrct2/actions/BannerSetColourAction.cpp new file mode 100644 index 0000000000..51a3dd36df --- /dev/null +++ b/src/openrct2/actions/BannerSetColourAction.cpp @@ -0,0 +1,94 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "BannerSetColourAction.h" + +#include "../Context.h" +#include "../management/Finance.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "GameAction.h" + +void BannerSetColourAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("primaryColour", _primaryColour); +} + +void BannerSetColourAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_primaryColour); +} + +GameActions::Result::Ptr BannerSetColourAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr BannerSetColourAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr BannerSetColourAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->ErrorTitle = STR_CANT_REPAINT_THIS; + + if (!LocationValid(_loc)) + { + log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (_primaryColour > 31) + { + log_error("Invalid primary colour: colour = %u", _primaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (!map_can_build_at({ _loc.x, _loc.y, _loc.z - 16 })) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto bannerElement = map_get_banner_element_at(_loc, _loc.direction); + + if (bannerElement == nullptr) + { + log_error("Could not find banner at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + + auto index = bannerElement->GetIndex(); + if (index >= MAX_BANNERS || index == BANNER_INDEX_NULL) + { + log_error("Invalid banner index: index = %u", index); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + + if (isExecuting) + { + auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); + intent.putExtra(INTENT_EXTRA_BANNER_INDEX, index); + context_broadcast_intent(&intent); + + auto banner = GetBanner(index); + banner->colour = _primaryColour; + map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 32 }); + } + + return res; +} diff --git a/src/openrct2/actions/BannerSetColourAction.h b/src/openrct2/actions/BannerSetColourAction.h new file mode 100644 index 0000000000..94af9b3db8 --- /dev/null +++ b/src/openrct2/actions/BannerSetColourAction.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(BannerSetColourAction, GAME_COMMAND_SET_BANNER_COLOUR, GameActions::Result) +{ +private: + CoordsXYZD _loc; + uint8_t _primaryColour{}; + +public: + BannerSetColourAction() = default; + + BannerSetColourAction(const CoordsXYZD& loc, uint8_t primaryColour) + : _loc(loc) + , _primaryColour(primaryColour) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/BannerSetColourAction.hpp b/src/openrct2/actions/BannerSetColourAction.hpp deleted file mode 100644 index 0e50bdfa55..0000000000 --- a/src/openrct2/actions/BannerSetColourAction.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../management/Finance.h" -#include "../windows/Intent.h" -#include "../world/Banner.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(BannerSetColourAction, GAME_COMMAND_SET_BANNER_COLOUR, GameActions::Result) -{ -private: - CoordsXYZD _loc; - uint8_t _primaryColour{}; - -public: - BannerSetColourAction() = default; - - BannerSetColourAction(const CoordsXYZD& loc, uint8_t primaryColour) - : _loc(loc) - , _primaryColour(primaryColour) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("primaryColour", _primaryColour); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_primaryColour); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - res->ErrorTitle = STR_CANT_REPAINT_THIS; - - if (!LocationValid(_loc)) - { - log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (_primaryColour > 31) - { - log_error("Invalid primary colour: colour = %u", _primaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (!map_can_build_at({ _loc.x, _loc.y, _loc.z - 16 })) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - auto bannerElement = map_get_banner_element_at(_loc, _loc.direction); - - if (bannerElement == nullptr) - { - log_error( - "Could not find banner at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, _loc.direction); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - - auto index = bannerElement->GetIndex(); - if (index >= MAX_BANNERS || index == BANNER_INDEX_NULL) - { - log_error("Invalid banner index: index = %u", index); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - - if (isExecuting) - { - auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); - intent.putExtra(INTENT_EXTRA_BANNER_INDEX, index); - context_broadcast_intent(&intent); - - auto banner = GetBanner(index); - banner->colour = _primaryColour; - map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 32 }); - } - - return res; - } -}; diff --git a/src/openrct2/actions/BannerSetNameAction.cpp b/src/openrct2/actions/BannerSetNameAction.cpp new file mode 100644 index 0000000000..172a4e8ae2 --- /dev/null +++ b/src/openrct2/actions/BannerSetNameAction.cpp @@ -0,0 +1,58 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "BannerSetNameAction.h" + +#include "../Context.h" +#include "../core/String.hpp" +#include "../drawing/Drawing.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../ui/UiContext.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "../world/Sprite.h" +#include "GameAction.h" + +void BannerSetNameAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("id", _bannerIndex); + visitor.Visit("name", _name); +} + +void BannerSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_bannerIndex) << DS_TAG(_name); +} + +GameActions::Result::Ptr BannerSetNameAction::Query() const +{ + if (_bannerIndex >= MAX_BANNERS) + { + log_warning("Invalid game command for setting banner name, banner id = %d", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return MakeResult(); +} + +GameActions::Result::Ptr BannerSetNameAction::Execute() const +{ + auto banner = GetBanner(_bannerIndex); + banner->text = _name; + + auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); + intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); + context_broadcast_intent(&intent); + + scrolling_text_invalidate(); + gfx_invalidate_screen(); + + return MakeResult(); +} diff --git a/src/openrct2/actions/BannerSetNameAction.h b/src/openrct2/actions/BannerSetNameAction.h new file mode 100644 index 0000000000..2678a46c6b --- /dev/null +++ b/src/openrct2/actions/BannerSetNameAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(BannerSetNameAction, GAME_COMMAND_SET_BANNER_NAME, GameActions::Result) +{ +private: + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; + std::string _name; + +public: + BannerSetNameAction() = default; + BannerSetNameAction(BannerIndex bannerIndex, const std::string& name) + : _bannerIndex(bannerIndex) + , _name(name) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/BannerSetNameAction.hpp b/src/openrct2/actions/BannerSetNameAction.hpp deleted file mode 100644 index 267d311e50..0000000000 --- a/src/openrct2/actions/BannerSetNameAction.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../core/String.hpp" -#include "../drawing/Drawing.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../ui/UiContext.h" -#include "../windows/Intent.h" -#include "../world/Banner.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(BannerSetNameAction, GAME_COMMAND_SET_BANNER_NAME, GameActions::Result) -{ -private: - BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; - std::string _name; - -public: - BannerSetNameAction() = default; - BannerSetNameAction(BannerIndex bannerIndex, const std::string& name) - : _bannerIndex(bannerIndex) - , _name(name) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("id", _bannerIndex); - visitor.Visit("name", _name); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_bannerIndex) << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - if (_bannerIndex >= MAX_BANNERS) - { - log_warning("Invalid game command for setting banner name, banner id = %d", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto banner = GetBanner(_bannerIndex); - banner->text = _name; - - auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); - intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); - context_broadcast_intent(&intent); - - scrolling_text_invalidate(); - gfx_invalidate_screen(); - - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/BannerSetStyleAction.cpp b/src/openrct2/actions/BannerSetStyleAction.cpp new file mode 100644 index 0000000000..546812709e --- /dev/null +++ b/src/openrct2/actions/BannerSetStyleAction.cpp @@ -0,0 +1,142 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "BannerSetStyleAction.h" + +#include "../Context.h" +#include "../management/Finance.h" +#include "../util/Util.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "GameAction.h" + +void BannerSetStyleAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("id", _bannerIndex); + visitor.Visit("type", _type); + visitor.Visit("parameter", _parameter); +} + +void BannerSetStyleAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_type) << DS_TAG(_bannerIndex) << DS_TAG(_parameter); +} + +GameActions::Result::Ptr BannerSetStyleAction::Query() const +{ + auto res = MakeResult(); + + if (_bannerIndex >= MAX_BANNERS || _bannerIndex == BANNER_INDEX_NULL) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); + } + + auto banner = GetBanner(_bannerIndex); + + res->Expenditure = ExpenditureType::Landscaping; + auto location = banner->position.ToCoordsXY().ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + + TileElement* tileElement = banner_get_tile_element(_bannerIndex); + + if (tileElement == nullptr) + { + log_error("Could not find banner index = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + switch (_type) + { + case BannerSetStyleType::PrimaryColour: + if (_parameter > 31) + { + log_error("Invalid primary colour: colour = %u", _parameter); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + break; + + case BannerSetStyleType::TextColour: + if (_parameter > 13) + { + log_error("Invalid text colour: colour = %u", _parameter); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + break; + case BannerSetStyleType::NoEntry: + if (tileElement->AsBanner() == nullptr) + { + log_error("Tile element was not a banner."); + return MakeResult(GameActions::Status::Unknown, STR_NONE); + } + break; + default: + log_error("Invalid type: %u", _type); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return res; +} + +GameActions::Result::Ptr BannerSetStyleAction::Execute() const +{ + auto res = MakeResult(); + + auto banner = GetBanner(_bannerIndex); + + res->Expenditure = ExpenditureType::Landscaping; + auto location = banner->position.ToCoordsXY().ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + + TileElement* tileElement = banner_get_tile_element(_bannerIndex); + + if (tileElement == nullptr) + { + log_error("Could not find banner index = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + switch (_type) + { + case BannerSetStyleType::PrimaryColour: + banner->colour = _parameter; + break; + case BannerSetStyleType::TextColour: + banner->text_colour = _parameter; + break; + case BannerSetStyleType::NoEntry: + { + BannerElement* bannerElement = tileElement->AsBanner(); + if (bannerElement == nullptr) + { + log_error("Tile element was not a banner."); + return MakeResult(GameActions::Status::Unknown, STR_NONE); + } + + banner->flags &= ~BANNER_FLAG_NO_ENTRY; + banner->flags |= (_parameter != 0) ? BANNER_FLAG_NO_ENTRY : 0; + uint8_t allowedEdges = 0xF; + if (banner->flags & BANNER_FLAG_NO_ENTRY) + { + allowedEdges &= ~(1 << bannerElement->GetPosition()); + } + bannerElement->SetAllowedEdges(allowedEdges); + break; + } + default: + log_error("Invalid type: %u", _type); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); + intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); + context_broadcast_intent(&intent); + + return res; +} diff --git a/src/openrct2/actions/BannerSetStyleAction.h b/src/openrct2/actions/BannerSetStyleAction.h new file mode 100644 index 0000000000..09b32422c9 --- /dev/null +++ b/src/openrct2/actions/BannerSetStyleAction.h @@ -0,0 +1,51 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +// There is also the BannerSetColourAction that sets primary colour but this action takes banner index rather than x, y, z, +// direction +enum class BannerSetStyleType : uint8_t +{ + PrimaryColour, + TextColour, + NoEntry, + Count +}; + +DEFINE_GAME_ACTION(BannerSetStyleAction, GAME_COMMAND_SET_BANNER_STYLE, GameActions::Result) +{ +private: + BannerSetStyleType _type{ BannerSetStyleType::Count }; + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; + uint8_t _parameter{}; + +public: + BannerSetStyleAction() = default; + + BannerSetStyleAction(BannerSetStyleType type, uint8_t bannerIndex, uint8_t parameter) + : _type(type) + , _bannerIndex(bannerIndex) + , _parameter(parameter) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/BannerSetStyleAction.hpp b/src/openrct2/actions/BannerSetStyleAction.hpp deleted file mode 100644 index 7103804e0c..0000000000 --- a/src/openrct2/actions/BannerSetStyleAction.hpp +++ /dev/null @@ -1,175 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../management/Finance.h" -#include "../util/Util.h" -#include "../windows/Intent.h" -#include "../world/Banner.h" -#include "GameAction.h" - -// There is also the BannerSetColourAction that sets primary colour but this action takes banner index rather than x, y, z, -// direction -enum class BannerSetStyleType : uint8_t -{ - PrimaryColour, - TextColour, - NoEntry, - Count -}; - -DEFINE_GAME_ACTION(BannerSetStyleAction, GAME_COMMAND_SET_BANNER_STYLE, GameActions::Result) -{ -private: - BannerSetStyleType _type{ BannerSetStyleType::Count }; - BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; - uint8_t _parameter{}; - -public: - BannerSetStyleAction() = default; - - BannerSetStyleAction(BannerSetStyleType type, uint8_t bannerIndex, uint8_t parameter) - : _type(type) - , _bannerIndex(bannerIndex) - , _parameter(parameter) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("id", _bannerIndex); - visitor.Visit("type", _type); - visitor.Visit("parameter", _parameter); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_type) << DS_TAG(_bannerIndex) << DS_TAG(_parameter); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - - if (_bannerIndex >= MAX_BANNERS || _bannerIndex == BANNER_INDEX_NULL) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); - } - - auto banner = GetBanner(_bannerIndex); - - res->Expenditure = ExpenditureType::Landscaping; - auto location = banner->position.ToCoordsXY().ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - - TileElement* tileElement = banner_get_tile_element(_bannerIndex); - - if (tileElement == nullptr) - { - log_error("Could not find banner index = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - switch (_type) - { - case BannerSetStyleType::PrimaryColour: - if (_parameter > 31) - { - log_error("Invalid primary colour: colour = %u", _parameter); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - break; - - case BannerSetStyleType::TextColour: - if (_parameter > 13) - { - log_error("Invalid text colour: colour = %u", _parameter); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - break; - case BannerSetStyleType::NoEntry: - if (tileElement->AsBanner() == nullptr) - { - log_error("Tile element was not a banner."); - return MakeResult(GameActions::Status::Unknown, STR_NONE); - } - break; - default: - log_error("Invalid type: %u", _type); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - - auto banner = GetBanner(_bannerIndex); - - res->Expenditure = ExpenditureType::Landscaping; - auto location = banner->position.ToCoordsXY().ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - - TileElement* tileElement = banner_get_tile_element(_bannerIndex); - - if (tileElement == nullptr) - { - log_error("Could not find banner index = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - switch (_type) - { - case BannerSetStyleType::PrimaryColour: - banner->colour = _parameter; - break; - case BannerSetStyleType::TextColour: - banner->text_colour = _parameter; - break; - case BannerSetStyleType::NoEntry: - { - BannerElement* bannerElement = tileElement->AsBanner(); - if (bannerElement == nullptr) - { - log_error("Tile element was not a banner."); - return MakeResult(GameActions::Status::Unknown, STR_NONE); - } - - banner->flags &= ~BANNER_FLAG_NO_ENTRY; - banner->flags |= (_parameter != 0) ? BANNER_FLAG_NO_ENTRY : 0; - uint8_t allowedEdges = 0xF; - if (banner->flags & BANNER_FLAG_NO_ENTRY) - { - allowedEdges &= ~(1 << bannerElement->GetPosition()); - } - bannerElement->SetAllowedEdges(allowedEdges); - break; - } - default: - log_error("Invalid type: %u", _type); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); - intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); - context_broadcast_intent(&intent); - - return res; - } -}; diff --git a/src/openrct2/actions/ClearAction.cpp b/src/openrct2/actions/ClearAction.cpp new file mode 100644 index 0000000000..a6c6148861 --- /dev/null +++ b/src/openrct2/actions/ClearAction.cpp @@ -0,0 +1,202 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "ClearAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/LargeScenery.h" +#include "../world/Location.hpp" +#include "../world/Map.h" +#include "FootpathRemoveAction.h" +#include "LargeSceneryRemoveAction.h" +#include "SmallSceneryRemoveAction.h" +#include "WallRemoveAction.h" + +#include + +void ClearAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range) << DS_TAG(_itemsToClear); +} + +GameActions::Result::Ptr ClearAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr ClearAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr ClearAction::CreateResult() const +{ + auto result = MakeResult(); + result->ErrorTitle = STR_UNABLE_TO_REMOVE_ALL_SCENERY_FROM_HERE; + result->Expenditure = ExpenditureType::Landscaping; + + auto x = (_range.GetLeft() + _range.GetRight()) / 2 + 16; + auto y = (_range.GetTop() + _range.GetBottom()) / 2 + 16; + auto z = tile_element_height({ x, y }); + result->Position = CoordsXYZ(x, y, z); + + return result; +} + +GameActions::Result::Ptr ClearAction::QueryExecute(bool executing) const +{ + auto result = CreateResult(); + + auto noValidTiles = true; + auto error = GameActions::Status::Ok; + rct_string_id errorMessage = STR_NONE; + money32 totalCost = 0; + + auto x0 = std::max(_range.GetLeft(), 32); + auto y0 = std::max(_range.GetTop(), 32); + auto x1 = std::min(_range.GetRight(), static_cast(gMapSizeMaxXY)); + auto y1 = std::min(_range.GetBottom(), static_cast(gMapSizeMaxXY)); + + for (int32_t y = y0; y <= y1; y += COORDS_XY_STEP) + { + for (int32_t x = x0; x <= x1; x += COORDS_XY_STEP) + { + if (LocationValid({ x, y }) && MapCanClearAt({ x, y })) + { + auto cost = ClearSceneryFromTile({ x, y }, executing); + if (cost != MONEY32_UNDEFINED) + { + noValidTiles = false; + totalCost += cost; + } + } + else + { + error = GameActions::Status::NotOwned; + errorMessage = STR_LAND_NOT_OWNED_BY_PARK; + } + } + } + + if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_LARGE) + { + ResetClearLargeSceneryFlag(); + } + + if (noValidTiles) + { + result->Error = error; + result->ErrorMessage = errorMessage; + } + + result->Cost = totalCost; + return result; +} + +money32 ClearAction::ClearSceneryFromTile(const CoordsXY& tilePos, bool executing) const +{ + // Pass down all flags. + TileElement* tileElement = nullptr; + money32 totalCost = 0; + bool tileEdited; + do + { + tileEdited = false; + tileElement = map_get_first_element_at(tilePos); + if (tileElement == nullptr) + return totalCost; + do + { + if (tileElement->IsGhost()) + continue; + + auto type = tileElement->GetType(); + switch (type) + { + case TILE_ELEMENT_TYPE_PATH: + if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_FOOTPATH) + { + auto footpathRemoveAction = FootpathRemoveAction({ tilePos, tileElement->GetBaseZ() }); + footpathRemoveAction.SetFlags(GetFlags()); + + auto res = executing ? GameActions::ExecuteNested(&footpathRemoveAction) + : GameActions::QueryNested(&footpathRemoveAction); + + if (res->Error == GameActions::Status::Ok) + { + totalCost += res->Cost; + tileEdited = executing; + } + } + break; + case TILE_ELEMENT_TYPE_SMALL_SCENERY: + if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_SMALL) + { + auto removeSceneryAction = SmallSceneryRemoveAction( + { tilePos, tileElement->GetBaseZ() }, tileElement->AsSmallScenery()->GetSceneryQuadrant(), + tileElement->AsSmallScenery()->GetEntryIndex()); + removeSceneryAction.SetFlags(GetFlags()); + + auto res = executing ? GameActions::ExecuteNested(&removeSceneryAction) + : GameActions::QueryNested(&removeSceneryAction); + + if (res->Error == GameActions::Status::Ok) + { + totalCost += res->Cost; + tileEdited = executing; + } + } + break; + case TILE_ELEMENT_TYPE_WALL: + if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_SMALL) + { + CoordsXYZD wallLocation = { tilePos, tileElement->GetBaseZ(), tileElement->GetDirection() }; + auto wallRemoveAction = WallRemoveAction(wallLocation); + wallRemoveAction.SetFlags(GetFlags()); + + auto res = executing ? GameActions::ExecuteNested(&wallRemoveAction) + : GameActions::QueryNested(&wallRemoveAction); + + if (res->Error == GameActions::Status::Ok) + { + totalCost += res->Cost; + tileEdited = executing; + } + } + break; + case TILE_ELEMENT_TYPE_LARGE_SCENERY: + if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_LARGE) + { + auto removeSceneryAction = LargeSceneryRemoveAction( + { tilePos, tileElement->GetBaseZ(), tileElement->GetDirection() }, + tileElement->AsLargeScenery()->GetSequenceIndex()); + removeSceneryAction.SetFlags(GetFlags() | GAME_COMMAND_FLAG_PATH_SCENERY); + + auto res = executing ? GameActions::ExecuteNested(&removeSceneryAction) + : GameActions::QueryNested(&removeSceneryAction); + + if (res->Error == GameActions::Status::Ok) + { + totalCost += res->Cost; + tileEdited = executing; + } + } + break; + } + } while (!tileEdited && !(tileElement++)->IsLastForTile()); + } while (tileEdited); + + return totalCost; +} diff --git a/src/openrct2/actions/ClearAction.h b/src/openrct2/actions/ClearAction.h new file mode 100644 index 0000000000..090f6d4daa --- /dev/null +++ b/src/openrct2/actions/ClearAction.h @@ -0,0 +1,80 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../OpenRCT2.h" +#include "../management/Finance.h" +#include "GameAction.h" + +using namespace OpenRCT2; + +using ClearableItems = uint8_t; + +namespace CLEARABLE_ITEMS +{ + constexpr ClearableItems SCENERY_SMALL = 1 << 0; + constexpr ClearableItems SCENERY_LARGE = 1 << 1; + constexpr ClearableItems SCENERY_FOOTPATH = 1 << 2; +} // namespace CLEARABLE_ITEMS + +DEFINE_GAME_ACTION(ClearAction, GAME_COMMAND_CLEAR_SCENERY, GameActions::Result) +{ +private: + MapRange _range; + ClearableItems _itemsToClear{}; + +public: + ClearAction() = default; + ClearAction(MapRange range, ClearableItems itemsToClear) + : _range(range) + , _itemsToClear(itemsToClear) + { + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr CreateResult() const; + GameActions::Result::Ptr QueryExecute(bool executing) const; + money32 ClearSceneryFromTile(const CoordsXY& tilePos, bool executing) const; + + /** + * Function to clear the flag that is set to prevent cost duplication + * when using the clear scenery tool with large scenery. + */ + static void ResetClearLargeSceneryFlag() + { + // TODO: Improve efficiency of this + for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) + { + for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) + { + auto tileElement = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() == TILE_ELEMENT_TYPE_LARGE_SCENERY) + { + tileElement->AsLargeScenery()->SetIsAccounted(false); + } + } while (!(tileElement++)->IsLastForTile()); + } + } + } + + static bool MapCanClearAt(const CoordsXY& location) + { + return (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode + || map_is_location_owned_or_has_rights(location); + } +}; diff --git a/src/openrct2/actions/ClearAction.hpp b/src/openrct2/actions/ClearAction.hpp deleted file mode 100644 index 4e91fe58d4..0000000000 --- a/src/openrct2/actions/ClearAction.hpp +++ /dev/null @@ -1,261 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/LargeScenery.h" -#include "../world/Location.hpp" -#include "../world/Map.h" -#include "FootpathRemoveAction.hpp" -#include "GameAction.h" -#include "LargeSceneryRemoveAction.hpp" -#include "SmallSceneryRemoveAction.hpp" -#include "WallRemoveAction.hpp" - -#include - -using namespace OpenRCT2; - -using ClearableItems = uint8_t; - -namespace CLEARABLE_ITEMS -{ - constexpr ClearableItems SCENERY_SMALL = 1 << 0; - constexpr ClearableItems SCENERY_LARGE = 1 << 1; - constexpr ClearableItems SCENERY_FOOTPATH = 1 << 2; -} // namespace CLEARABLE_ITEMS - -DEFINE_GAME_ACTION(ClearAction, GAME_COMMAND_CLEAR_SCENERY, GameActions::Result) -{ -private: - MapRange _range; - ClearableItems _itemsToClear{}; - -public: - ClearAction() = default; - ClearAction(MapRange range, ClearableItems itemsToClear) - : _range(range) - , _itemsToClear(itemsToClear) - { - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range) << DS_TAG(_itemsToClear); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr CreateResult() const - { - auto result = MakeResult(); - result->ErrorTitle = STR_UNABLE_TO_REMOVE_ALL_SCENERY_FROM_HERE; - result->Expenditure = ExpenditureType::Landscaping; - - auto x = (_range.GetLeft() + _range.GetRight()) / 2 + 16; - auto y = (_range.GetTop() + _range.GetBottom()) / 2 + 16; - auto z = tile_element_height({ x, y }); - result->Position = CoordsXYZ(x, y, z); - - return result; - } - - GameActions::Result::Ptr QueryExecute(bool executing) const - { - auto result = CreateResult(); - - auto noValidTiles = true; - auto error = GameActions::Status::Ok; - rct_string_id errorMessage = STR_NONE; - money32 totalCost = 0; - - auto x0 = std::max(_range.GetLeft(), 32); - auto y0 = std::max(_range.GetTop(), 32); - auto x1 = std::min(_range.GetRight(), static_cast(gMapSizeMaxXY)); - auto y1 = std::min(_range.GetBottom(), static_cast(gMapSizeMaxXY)); - - for (int32_t y = y0; y <= y1; y += COORDS_XY_STEP) - { - for (int32_t x = x0; x <= x1; x += COORDS_XY_STEP) - { - if (LocationValid({ x, y }) && MapCanClearAt({ x, y })) - { - auto cost = ClearSceneryFromTile({ x, y }, executing); - if (cost != MONEY32_UNDEFINED) - { - noValidTiles = false; - totalCost += cost; - } - } - else - { - error = GameActions::Status::NotOwned; - errorMessage = STR_LAND_NOT_OWNED_BY_PARK; - } - } - } - - if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_LARGE) - { - ResetClearLargeSceneryFlag(); - } - - if (noValidTiles) - { - result->Error = error; - result->ErrorMessage = errorMessage; - } - - result->Cost = totalCost; - return result; - } - - money32 ClearSceneryFromTile(const CoordsXY& tilePos, bool executing) const - { - // Pass down all flags. - TileElement* tileElement = nullptr; - money32 totalCost = 0; - bool tileEdited; - do - { - tileEdited = false; - tileElement = map_get_first_element_at(tilePos); - if (tileElement == nullptr) - return totalCost; - do - { - if (tileElement->IsGhost()) - continue; - - auto type = tileElement->GetType(); - switch (type) - { - case TILE_ELEMENT_TYPE_PATH: - if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_FOOTPATH) - { - auto footpathRemoveAction = FootpathRemoveAction({ tilePos, tileElement->GetBaseZ() }); - footpathRemoveAction.SetFlags(GetFlags()); - - auto res = executing ? GameActions::ExecuteNested(&footpathRemoveAction) - : GameActions::QueryNested(&footpathRemoveAction); - - if (res->Error == GameActions::Status::Ok) - { - totalCost += res->Cost; - tileEdited = executing; - } - } - break; - case TILE_ELEMENT_TYPE_SMALL_SCENERY: - if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_SMALL) - { - auto removeSceneryAction = SmallSceneryRemoveAction( - { tilePos, tileElement->GetBaseZ() }, tileElement->AsSmallScenery()->GetSceneryQuadrant(), - tileElement->AsSmallScenery()->GetEntryIndex()); - removeSceneryAction.SetFlags(GetFlags()); - - auto res = executing ? GameActions::ExecuteNested(&removeSceneryAction) - : GameActions::QueryNested(&removeSceneryAction); - - if (res->Error == GameActions::Status::Ok) - { - totalCost += res->Cost; - tileEdited = executing; - } - } - break; - case TILE_ELEMENT_TYPE_WALL: - if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_SMALL) - { - CoordsXYZD wallLocation = { tilePos, tileElement->GetBaseZ(), tileElement->GetDirection() }; - auto wallRemoveAction = WallRemoveAction(wallLocation); - wallRemoveAction.SetFlags(GetFlags()); - - auto res = executing ? GameActions::ExecuteNested(&wallRemoveAction) - : GameActions::QueryNested(&wallRemoveAction); - - if (res->Error == GameActions::Status::Ok) - { - totalCost += res->Cost; - tileEdited = executing; - } - } - break; - case TILE_ELEMENT_TYPE_LARGE_SCENERY: - if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_LARGE) - { - auto removeSceneryAction = LargeSceneryRemoveAction( - { tilePos, tileElement->GetBaseZ(), tileElement->GetDirection() }, - tileElement->AsLargeScenery()->GetSequenceIndex()); - removeSceneryAction.SetFlags(GetFlags() | GAME_COMMAND_FLAG_PATH_SCENERY); - - auto res = executing ? GameActions::ExecuteNested(&removeSceneryAction) - : GameActions::QueryNested(&removeSceneryAction); - - if (res->Error == GameActions::Status::Ok) - { - totalCost += res->Cost; - tileEdited = executing; - } - } - break; - } - } while (!tileEdited && !(tileElement++)->IsLastForTile()); - } while (tileEdited); - - return totalCost; - } - - /** - * Function to clear the flag that is set to prevent cost duplication - * when using the clear scenery tool with large scenery. - */ - static void ResetClearLargeSceneryFlag() - { - // TODO: Improve efficiency of this - for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) - { - for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) - { - auto tileElement = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() == TILE_ELEMENT_TYPE_LARGE_SCENERY) - { - tileElement->AsLargeScenery()->SetIsAccounted(false); - } - } while (!(tileElement++)->IsLastForTile()); - } - } - } - - static bool MapCanClearAt(const CoordsXY& location) - { - return (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode - || map_is_location_owned_or_has_rights(location); - } -}; diff --git a/src/openrct2/actions/ClimateSetAction.cpp b/src/openrct2/actions/ClimateSetAction.cpp new file mode 100644 index 0000000000..90f90a79e6 --- /dev/null +++ b/src/openrct2/actions/ClimateSetAction.cpp @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "ClimateSetAction.h" + +void ClimateSetAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("climate", _climate); +} + +void ClimateSetAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_climate); +} + +GameActions::Result::Ptr ClimateSetAction::Query() const +{ + if (_climate >= ClimateType::Count) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_INVALID_CLIMATE_ID, STR_NONE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr ClimateSetAction::Execute() const +{ + gClimate = ClimateType{ _climate }; + + gfx_invalidate_screen(); + + return std::make_unique(); +} diff --git a/src/openrct2/actions/ClimateSetAction.hpp b/src/openrct2/actions/ClimateSetAction.h similarity index 51% rename from src/openrct2/actions/ClimateSetAction.hpp rename to src/openrct2/actions/ClimateSetAction.h index bcee196ad4..470ffd2e42 100644 --- a/src/openrct2/actions/ClimateSetAction.hpp +++ b/src/openrct2/actions/ClimateSetAction.h @@ -23,41 +23,14 @@ public: : _climate(climate) { } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("climate", _climate); - } + void AcceptParameters(GameActionParameterVisitor & visitor) override; uint16_t GetActionFlags() const override { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + return GameAction::GetActionFlags(); } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_climate); - } - - GameActions::Result::Ptr Query() const override - { - if (_climate >= ClimateType::Count) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_INVALID_CLIMATE_ID, STR_NONE); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - gClimate = ClimateType{ _climate }; - - gfx_invalidate_screen(); - - return std::make_unique(); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/CustomAction.cpp b/src/openrct2/actions/CustomAction.cpp new file mode 100644 index 0000000000..b0c8e142af --- /dev/null +++ b/src/openrct2/actions/CustomAction.cpp @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#ifdef ENABLE_SCRIPTING +# include "CustomAction.h" + +# include "../Context.h" +# include "../scripting/ScriptEngine.h" + +void CustomAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_id) << DS_TAG(_json); +} + +GameActions::Result::Ptr CustomAction::Query() const +{ + auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine(); + return scriptingEngine.QueryOrExecuteCustomGameAction(_id, _json, false); +} + +GameActions::Result::Ptr CustomAction::Execute() const +{ + auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine(); + return scriptingEngine.QueryOrExecuteCustomGameAction(_id, _json, true); +} + +#endif diff --git a/src/openrct2/actions/CustomAction.hpp b/src/openrct2/actions/CustomAction.h similarity index 61% rename from src/openrct2/actions/CustomAction.hpp rename to src/openrct2/actions/CustomAction.h index 0ae306b047..bb51acce21 100644 --- a/src/openrct2/actions/CustomAction.hpp +++ b/src/openrct2/actions/CustomAction.h @@ -11,8 +11,6 @@ #ifdef ENABLE_SCRIPTING -# include "../Context.h" -# include "../scripting/ScriptEngine.h" # include "GameAction.h" DEFINE_GAME_ACTION(CustomAction, GAME_COMMAND_CUSTOM, GameActions::Result) @@ -44,23 +42,9 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_id) << DS_TAG(_json); - } - - GameActions::Result::Ptr Query() const override - { - auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine(); - return scriptingEngine.QueryOrExecuteCustomGameAction(_id, _json, false); - } - - GameActions::Result::Ptr Execute() const override - { - auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine(); - return scriptingEngine.QueryOrExecuteCustomGameAction(_id, _json, true); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; #endif diff --git a/src/openrct2/actions/FootpathAdditionPlaceAction.cpp b/src/openrct2/actions/FootpathAdditionPlaceAction.cpp new file mode 100644 index 0000000000..5cb7056ca1 --- /dev/null +++ b/src/openrct2/actions/FootpathAdditionPlaceAction.cpp @@ -0,0 +1,191 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "FootpathAdditionPlaceAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Wall.h" + +void FootpathAdditionPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _pathItemType); +} + +void FootpathAdditionPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_pathItemType); +} + +GameActions::Result::Ptr FootpathAdditionPlaceAction::Query() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc; + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_OFF_EDGE_OF_MAP); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (_loc.z < FootpathMinHeight) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_LOW); + } + + if (_loc.z > FootpathMaxHeight) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_HIGH); + } + + auto tileElement = map_get_footpath_element(_loc); + if (tileElement == nullptr) + { + log_error("Could not find path element."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + auto pathElement = tileElement->AsPath(); + if (pathElement->IsLevelCrossing(_loc)) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, + STR_CANNOT_BUILD_PATH_ADDITIONS_ON_LEVEL_CROSSINGS); + } + + // No change + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAddition() == _pathItemType && !(pathElement->IsBroken())) + { + return res; + } + + if (_pathItemType != 0) + { + rct_scenery_entry* sceneryEntry = get_footpath_item_entry(_pathItemType - 1); + if (sceneryEntry == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, 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( + GameActions::Status::InvalidParameters, 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( + GameActions::Status::InvalidParameters, 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(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + if ((sceneryFlags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) && !pathElement->IsQueue()) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA); + } + + res->Cost = sceneryEntry->path_bit.price; + } + + // Should place a ghost? + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + // Check if there is something on the path already + if (pathElement->HasAddition()) + { + return MakeResult(GameActions::Status::ItemAlreadyPlaced, STR_CANT_POSITION_THIS_HERE); + } + } + return res; +} + +GameActions::Result::Ptr FootpathAdditionPlaceAction::Execute() const +{ + auto res = MakeResult(); + res->Position = _loc; + res->Expenditure = ExpenditureType::Landscaping; + + auto tileElement = map_get_footpath_element(_loc); + auto pathElement = tileElement->AsPath(); + + if (pathElement == nullptr) + { + log_error("Could not find path element."); + return MakeResult(GameActions::Status::InvalidParameters, 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(GameActions::Status::InvalidParameters, 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); + } + + 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); + return res; +} diff --git a/src/openrct2/actions/FootpathAdditionPlaceAction.h b/src/openrct2/actions/FootpathAdditionPlaceAction.h new file mode 100644 index 0000000000..7a76e9efc6 --- /dev/null +++ b/src/openrct2/actions/FootpathAdditionPlaceAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(FootpathAdditionPlaceAction, GAME_COMMAND_PLACE_FOOTPATH_ADDITION, GameActions::Result) +{ +private: + CoordsXYZ _loc; + ObjectEntryIndex _pathItemType{}; + +public: + FootpathAdditionPlaceAction() = default; + FootpathAdditionPlaceAction(const CoordsXYZ& loc, ObjectEntryIndex pathItemType) + : _loc(loc) + , _pathItemType(pathItemType) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/FootpathAdditionPlaceAction.hpp b/src/openrct2/actions/FootpathAdditionPlaceAction.hpp deleted file mode 100644 index c5c2affc97..0000000000 --- a/src/openrct2/actions/FootpathAdditionPlaceAction.hpp +++ /dev/null @@ -1,216 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Wall.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(FootpathAdditionPlaceAction, GAME_COMMAND_PLACE_FOOTPATH_ADDITION, GameActions::Result) -{ -private: - CoordsXYZ _loc; - ObjectEntryIndex _pathItemType{}; - -public: - FootpathAdditionPlaceAction() = default; - FootpathAdditionPlaceAction(const CoordsXYZ& loc, ObjectEntryIndex pathItemType) - : _loc(loc) - , _pathItemType(pathItemType) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _pathItemType); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_pathItemType); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc; - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_OFF_EDGE_OF_MAP); - } - - if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (_loc.z < FootpathMinHeight) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_LOW); - } - - if (_loc.z > FootpathMaxHeight) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_HIGH); - } - - auto tileElement = map_get_footpath_element(_loc); - if (tileElement == nullptr) - { - log_error("Could not find path element."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - auto pathElement = tileElement->AsPath(); - if (pathElement->IsLevelCrossing(_loc)) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, - STR_CANNOT_BUILD_PATH_ADDITIONS_ON_LEVEL_CROSSINGS); - } - - // No change - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAddition() == _pathItemType - && !(pathElement->IsBroken())) - { - return res; - } - - if (_pathItemType != 0) - { - rct_scenery_entry* sceneryEntry = get_footpath_item_entry(_pathItemType - 1); - if (sceneryEntry == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, 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( - GameActions::Status::InvalidParameters, 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( - GameActions::Status::InvalidParameters, 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(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - if ((sceneryFlags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) && !pathElement->IsQueue()) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, - STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA); - } - - res->Cost = sceneryEntry->path_bit.price; - } - - // Should place a ghost? - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - // Check if there is something on the path already - if (pathElement->HasAddition()) - { - return MakeResult(GameActions::Status::ItemAlreadyPlaced, STR_CANT_POSITION_THIS_HERE); - } - } - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Position = _loc; - res->Expenditure = ExpenditureType::Landscaping; - - auto tileElement = map_get_footpath_element(_loc); - auto pathElement = tileElement->AsPath(); - - if (pathElement == nullptr) - { - log_error("Could not find path element."); - return MakeResult(GameActions::Status::InvalidParameters, 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(GameActions::Status::InvalidParameters, 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); - } - - 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); - return res; - } -}; diff --git a/src/openrct2/actions/FootpathAdditionRemoveAction.cpp b/src/openrct2/actions/FootpathAdditionRemoveAction.cpp new file mode 100644 index 0000000000..9e7c92b2dc --- /dev/null +++ b/src/openrct2/actions/FootpathAdditionRemoveAction.cpp @@ -0,0 +1,105 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "FootpathAdditionRemoveAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Wall.h" + +void FootpathAdditionRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); +} + +void FootpathAdditionRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr FootpathAdditionRemoveAction::Query() const +{ + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_OFF_EDGE_OF_MAP); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (_loc.z < FootpathMinHeight) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_LOW); + } + + if (_loc.z > FootpathMaxHeight) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_HIGH); + } + + auto tileElement = map_get_footpath_element(_loc); + if (tileElement == nullptr) + { + log_warning("Could not find path element."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + auto pathElement = tileElement->AsPath(); + if (pathElement == nullptr) + { + log_warning("Could not find path element."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + if (!pathElement->AdditionIsGhost() && (GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + log_warning("Tried to remove non ghost during ghost removal."); + return MakeResult(GameActions::Status::Disallowed, STR_CANT_REMOVE_THIS); + } + auto res = MakeResult(); + res->Position = _loc; + res->Cost = MONEY(0, 0); + return res; +} + +GameActions::Result::Ptr FootpathAdditionRemoveAction::Execute() const +{ + auto tileElement = map_get_footpath_element(_loc); + auto pathElement = tileElement->AsPath(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_interrupt_peeps(_loc); + } + + if (pathElement == nullptr) + { + log_error("Could not find path element."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + pathElement->SetAddition(0); + map_invalidate_tile_full(_loc); + + auto res = MakeResult(); + res->Position = _loc; + res->Cost = MONEY(0, 0); + return res; +} diff --git a/src/openrct2/actions/FootpathAdditionRemoveAction.h b/src/openrct2/actions/FootpathAdditionRemoveAction.h new file mode 100644 index 0000000000..9ba064aa85 --- /dev/null +++ b/src/openrct2/actions/FootpathAdditionRemoveAction.h @@ -0,0 +1,35 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(FootpathAdditionRemoveAction, GAME_COMMAND_REMOVE_FOOTPATH_ADDITION, GameActions::Result) +{ +private: + CoordsXYZ _loc; + +public: + FootpathAdditionRemoveAction() = default; + FootpathAdditionRemoveAction(const CoordsXYZ& loc) + : _loc(loc) + { + } + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/FootpathAdditionRemoveAction.hpp b/src/openrct2/actions/FootpathAdditionRemoveAction.hpp deleted file mode 100644 index 889f1867f9..0000000000 --- a/src/openrct2/actions/FootpathAdditionRemoveAction.hpp +++ /dev/null @@ -1,125 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Park.h" -#include "../world/Wall.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(FootpathAdditionRemoveAction, GAME_COMMAND_REMOVE_FOOTPATH_ADDITION, GameActions::Result) -{ -private: - CoordsXYZ _loc; - -public: - FootpathAdditionRemoveAction() = default; - - FootpathAdditionRemoveAction(const CoordsXYZ& loc) - : _loc(loc) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_OFF_EDGE_OF_MAP); - } - - if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (_loc.z < FootpathMinHeight) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_LOW); - } - - if (_loc.z > FootpathMaxHeight) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_HIGH); - } - - auto tileElement = map_get_footpath_element(_loc); - if (tileElement == nullptr) - { - log_warning("Could not find path element."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - auto pathElement = tileElement->AsPath(); - if (pathElement == nullptr) - { - log_warning("Could not find path element."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - if (!pathElement->AdditionIsGhost() && (GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - log_warning("Tried to remove non ghost during ghost removal."); - return MakeResult(GameActions::Status::Disallowed, STR_CANT_REMOVE_THIS); - } - auto res = MakeResult(); - res->Position = _loc; - res->Cost = MONEY(0, 0); - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto tileElement = map_get_footpath_element(_loc); - auto pathElement = tileElement->AsPath(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_interrupt_peeps(_loc); - } - - if (pathElement == nullptr) - { - log_error("Could not find path element."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - pathElement->SetAddition(0); - map_invalidate_tile_full(_loc); - - auto res = MakeResult(); - res->Position = _loc; - res->Cost = MONEY(0, 0); - return res; - } -}; diff --git a/src/openrct2/actions/FootpathPlaceAction.cpp b/src/openrct2/actions/FootpathPlaceAction.cpp new file mode 100644 index 0000000000..79a22e4801 --- /dev/null +++ b/src/openrct2/actions/FootpathPlaceAction.cpp @@ -0,0 +1,450 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "FootpathPlaceAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Surface.h" +#include "../world/Wall.h" + +void FootpathPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _type); + visitor.Visit("direction", _direction); + visitor.Visit("slope", _slope); +} + +void FootpathPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_direction); +} + +GameActions::Result::Ptr FootpathPlaceAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc.ToTileCentre(); + + gFootpathGroundFlags = 0; + + if (!LocationValid(_loc) || map_is_edge(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_OFF_EDGE_OF_MAP); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (_slope & SLOPE_IS_IRREGULAR_FLAG) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_SLOPE_UNSUITABLE); + } + + if (_loc.z < FootpathMinHeight) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_LOW); + } + + if (_loc.z > FootpathMaxHeight) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_HIGH); + } + + if (_direction != INVALID_DIRECTION && !direction_valid(_direction)) + { + log_error("Direction invalid. direction = %u", _direction); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); + } + + footpath_provisional_remove(); + auto tileElement = map_get_footpath_element_slope(_loc, _slope); + if (tileElement == nullptr) + { + return ElementInsertQuery(std::move(res)); + } + else + { + return ElementUpdateQuery(tileElement, std::move(res)); + } +} + +GameActions::Result::Ptr FootpathPlaceAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc.ToTileCentre(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_interrupt_peeps(_loc); + } + + gFootpathGroundFlags = 0; + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + if (_direction != INVALID_DIRECTION && !gCheatsDisableClearanceChecks) + { + // It is possible, let's remove walls between the old and new piece of path + auto zLow = _loc.z; + auto zHigh = zLow + PATH_CLEARANCE; + wall_remove_intersecting_walls( + { _loc, zLow, zHigh + ((_slope & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) ? 16 : 0) }, + direction_reverse(_direction)); + wall_remove_intersecting_walls( + { _loc.x - CoordsDirectionDelta[_direction].x, _loc.y - CoordsDirectionDelta[_direction].y, zLow, zHigh }, + _direction); + } + } + + auto tileElement = map_get_footpath_element_slope(_loc, _slope); + if (tileElement == nullptr) + { + return ElementInsertExecute(std::move(res)); + } + else + { + return ElementUpdateExecute(tileElement, std::move(res)); + } +} + +GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateQuery(PathElement* pathElement, GameActions::Result::Ptr res) const +{ + const int32_t newFootpathType = (_type & (FOOTPATH_PROPERTIES_TYPE_MASK >> 4)); + const bool newPathIsQueue = ((_type >> 7) == 1); + if (pathElement->GetSurfaceEntryIndex() != newFootpathType || pathElement->IsQueue() != newPathIsQueue) + { + res->Cost += MONEY(6, 00); + } + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST && !pathElement->IsGhost()) + { + return MakeResult(GameActions::Status::Unknown, STR_CANT_BUILD_FOOTPATH_HERE); + } + return res; +} + +GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateExecute(PathElement* pathElement, GameActions::Result::Ptr res) const +{ + const int32_t newFootpathType = (_type & (FOOTPATH_PROPERTIES_TYPE_MASK >> 4)); + const bool newPathIsQueue = ((_type >> 7) == 1); + if (pathElement->GetSurfaceEntryIndex() != newFootpathType || pathElement->IsQueue() != newPathIsQueue) + { + res->Cost += MONEY(6, 00); + } + + footpath_queue_chain_reset(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) + { + footpath_remove_edges_at(_loc, reinterpret_cast(pathElement)); + } + + pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); + bool isQueue = _type & FOOTPATH_ELEMENT_INSERT_QUEUE; + pathElement->SetIsQueue(isQueue); + + rct_scenery_entry* elem = pathElement->GetAdditionEntry(); + if (elem != nullptr) + { + if (isQueue) + { + // remove any addition that isn't a TV or a lamp + if ((elem->path_bit.flags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) == 0 && (elem->path_bit.flags & PATH_BIT_FLAG_LAMP) == 0) + { + pathElement->SetIsBroken(false); + pathElement->SetAddition(0); + } + } + else + { + // remove all TVs + if ((elem->path_bit.flags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) != 0) + { + pathElement->SetIsBroken(false); + pathElement->SetAddition(0); + } + } + } + + RemoveIntersectingWalls(pathElement); + return res; +} + +GameActions::Result::Ptr FootpathPlaceAction::ElementInsertQuery(GameActions::Result::Ptr res) const +{ + bool entrancePath = false, entranceIsSamePath = false; + + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_BUILD_FOOTPATH_HERE); + } + + res->Cost = MONEY(12, 00); + + QuarterTile quarterTile{ 0b1111, 0 }; + auto zLow = _loc.z; + auto zHigh = zLow + PATH_CLEARANCE; + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); + zHigh += PATH_HEIGHT_STEP; + } + + auto entranceElement = map_get_park_entrance_element_at(_loc, false); + // Make sure the entrance part is the middle + if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) + { + entrancePath = true; + // Make the price the same as replacing a path + if (entranceElement->GetPathType() == (_type & 0xF)) + entranceIsSamePath = true; + else + res->Cost -= MONEY(6, 00); + } + + // Do not attempt to build a crossing with a queue or a sloped. + uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) + ? CREATE_CROSSING_MODE_NONE + : CREATE_CROSSING_MODE_PATH_OVER_TRACK; + if (!entrancePath + && !map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &res->Cost, crossingMode)) + { + return MakeResult( + GameActions::Status::NoClearance, STR_CANT_BUILD_FOOTPATH_HERE, gGameCommandErrorText, gCommonFormatArgs); + } + + gFootpathGroundFlags = gMapGroundFlags; + if (!gCheatsDisableClearanceChecks && (gMapGroundFlags & ELEMENT_IS_UNDERWATER)) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_CANT_BUILD_THIS_UNDERWATER); + } + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); + } + int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); + res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); + + // Prevent the place sound from being spammed + if (entranceIsSamePath) + res->Cost = 0; + + return res; +} + +GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions::Result::Ptr res) const +{ + bool entrancePath = false, entranceIsSamePath = false; + + if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST))) + { + footpath_remove_litter(_loc); + } + + res->Cost = MONEY(12, 00); + + QuarterTile quarterTile{ 0b1111, 0 }; + auto zLow = _loc.z; + auto zHigh = zLow + PATH_CLEARANCE; + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); + zHigh += PATH_HEIGHT_STEP; + } + + auto entranceElement = map_get_park_entrance_element_at(_loc, false); + // Make sure the entrance part is the middle + if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) + { + entrancePath = true; + // Make the price the same as replacing a path + if (entranceElement->GetPathType() == (_type & 0xF)) + entranceIsSamePath = true; + else + res->Cost -= MONEY(6, 00); + } + + // Do not attempt to build a crossing with a queue or a sloped. + uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) + ? CREATE_CROSSING_MODE_NONE + : CREATE_CROSSING_MODE_PATH_OVER_TRACK; + if (!entrancePath + && !map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), + &res->Cost, crossingMode)) + { + return MakeResult( + GameActions::Status::NoClearance, STR_CANT_BUILD_FOOTPATH_HERE, gGameCommandErrorText, gCommonFormatArgs); + } + + gFootpathGroundFlags = gMapGroundFlags; + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); + } + int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); + res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); + + if (entrancePath) + { + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath) + { + // Set the path type but make sure it's not a queue as that will not show up + entranceElement->SetPathType(_type & 0x7F); + map_invalidate_tile_full(_loc); + } + } + else + { + auto tileElement = tile_element_insert(_loc, 0b1111); + assert(tileElement != nullptr); + tileElement->SetType(TILE_ELEMENT_TYPE_PATH); + PathElement* pathElement = tileElement->AsPath(); + pathElement->SetClearanceZ(zHigh); + pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); + pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + pathElement->SetSloped(true); + } + if (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) + { + pathElement->SetIsQueue(true); + } + pathElement->SetAddition(0); + pathElement->SetRideIndex(RIDE_ID_NULL); + pathElement->SetAdditionStatus(255); + pathElement->SetIsBroken(false); + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + pathElement->SetGhost(true); + } + footpath_queue_chain_reset(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) + { + footpath_remove_edges_at(_loc, tileElement); + } + if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + AutomaticallySetPeepSpawn(); + } + + RemoveIntersectingWalls(pathElement); + } + + // Prevent the place sound from being spammed + if (entranceIsSamePath) + res->Cost = 0; + + return res; +} + +/** + * + * rct2: 0x006A65AD + */ +void FootpathPlaceAction::AutomaticallySetPeepSpawn() const +{ + uint8_t direction = 0; + if (_loc.x != 32) + { + direction++; + if (_loc.y != gMapSizeUnits - 32) + { + direction++; + if (_loc.x != gMapSizeUnits - 32) + { + direction++; + if (_loc.y != 32) + return; + } + } + } + + if (gPeepSpawns.empty()) + { + gPeepSpawns.emplace_back(); + } + PeepSpawn* peepSpawn = &gPeepSpawns[0]; + peepSpawn->x = _loc.x + (DirectionOffsets[direction].x * 15) + 16; + peepSpawn->y = _loc.y + (DirectionOffsets[direction].y * 15) + 16; + peepSpawn->direction = direction; + peepSpawn->z = _loc.z; +} + +void FootpathPlaceAction::RemoveIntersectingWalls(PathElement* pathElement) const +{ + if (pathElement->IsSloped() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + auto direction = pathElement->GetSlopeDirection(); + int32_t z = pathElement->GetBaseZ(); + wall_remove_intersecting_walls({ _loc, z, z + (6 * COORDS_Z_STEP) }, direction_reverse(direction)); + wall_remove_intersecting_walls({ _loc, z, z + (6 * COORDS_Z_STEP) }, direction); + // Removing walls may have made the pointer invalid, so find it again + auto tileElement = map_get_footpath_element(CoordsXYZ(_loc, z)); + if (tileElement == nullptr) + { + log_error("Something went wrong. Could not refind footpath."); + return; + } + pathElement = tileElement->AsPath(); + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) + footpath_connect_edges(_loc, reinterpret_cast(pathElement), GetFlags()); + + footpath_update_queue_chains(); + map_invalidate_tile_full(_loc); +} + +PathElement* FootpathPlaceAction::map_get_footpath_element_slope(const CoordsXYZ& footpathPos, int32_t slope) const +{ + TileElement* tileElement; + bool isSloped = slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED; + + tileElement = map_get_first_element_at(footpathPos); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH && tileElement->GetBaseZ() == footpathPos.z + && (tileElement->AsPath()->IsSloped() == isSloped) + && (tileElement->AsPath()->GetSlopeDirection() == (slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK))) + { + return tileElement->AsPath(); + } + } while (!(tileElement++)->IsLastForTile()); + return nullptr; +} diff --git a/src/openrct2/actions/FootpathPlaceAction.h b/src/openrct2/actions/FootpathPlaceAction.h new file mode 100644 index 0000000000..860e482357 --- /dev/null +++ b/src/openrct2/actions/FootpathPlaceAction.h @@ -0,0 +1,52 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/Footpath.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(FootpathPlaceAction, GAME_COMMAND_PLACE_PATH, GameActions::Result) +{ +private: + CoordsXYZ _loc; + uint8_t _slope{}; + ObjectEntryIndex _type{}; + Direction _direction{ INVALID_DIRECTION }; + +public: + FootpathPlaceAction() = default; + FootpathPlaceAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, Direction direction = INVALID_DIRECTION) + : _loc(loc) + , _slope(slope) + , _type(type) + , _direction(direction) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr ElementUpdateQuery(PathElement * pathElement, GameActions::Result::Ptr res) const; + GameActions::Result::Ptr ElementUpdateExecute(PathElement * pathElement, GameActions::Result::Ptr res) const; + GameActions::Result::Ptr ElementInsertQuery(GameActions::Result::Ptr res) const; + GameActions::Result::Ptr ElementInsertExecute(GameActions::Result::Ptr res) const; + void AutomaticallySetPeepSpawn() const; + void RemoveIntersectingWalls(PathElement * pathElement) const; + PathElement* map_get_footpath_element_slope(const CoordsXYZ& footpathPos, int32_t slope) const; +}; diff --git a/src/openrct2/actions/FootpathPlaceAction.hpp b/src/openrct2/actions/FootpathPlaceAction.hpp deleted file mode 100644 index 203bbdb341..0000000000 --- a/src/openrct2/actions/FootpathPlaceAction.hpp +++ /dev/null @@ -1,476 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Surface.h" -#include "../world/Wall.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(FootpathPlaceAction, GAME_COMMAND_PLACE_PATH, GameActions::Result) -{ -private: - CoordsXYZ _loc; - uint8_t _slope{}; - ObjectEntryIndex _type{}; - Direction _direction{ INVALID_DIRECTION }; - -public: - FootpathPlaceAction() = default; - FootpathPlaceAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, Direction direction = INVALID_DIRECTION) - : _loc(loc) - , _slope(slope) - , _type(type) - , _direction(direction) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _type); - visitor.Visit("direction", _direction); - visitor.Visit("slope", _slope); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_direction); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc.ToTileCentre(); - - gFootpathGroundFlags = 0; - - if (!LocationValid(_loc) || map_is_edge(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_OFF_EDGE_OF_MAP); - } - - if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (_slope & SLOPE_IS_IRREGULAR_FLAG) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_SLOPE_UNSUITABLE); - } - - if (_loc.z < FootpathMinHeight) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_LOW); - } - - if (_loc.z > FootpathMaxHeight) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_HIGH); - } - - if (_direction != INVALID_DIRECTION && !direction_valid(_direction)) - { - log_error("Direction invalid. direction = %u", _direction); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); - } - - footpath_provisional_remove(); - auto tileElement = map_get_footpath_element_slope(_loc, _slope); - if (tileElement == nullptr) - { - return ElementInsertQuery(std::move(res)); - } - else - { - return ElementUpdateQuery(tileElement, std::move(res)); - } - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc.ToTileCentre(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_interrupt_peeps(_loc); - } - - gFootpathGroundFlags = 0; - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - if (_direction != INVALID_DIRECTION && !gCheatsDisableClearanceChecks) - { - // It is possible, let's remove walls between the old and new piece of path - auto zLow = _loc.z; - auto zHigh = zLow + PATH_CLEARANCE; - wall_remove_intersecting_walls( - { _loc, zLow, zHigh + ((_slope & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) ? 16 : 0) }, - direction_reverse(_direction)); - wall_remove_intersecting_walls( - { _loc.x - CoordsDirectionDelta[_direction].x, _loc.y - CoordsDirectionDelta[_direction].y, zLow, zHigh }, - _direction); - } - } - - auto tileElement = map_get_footpath_element_slope(_loc, _slope); - if (tileElement == nullptr) - { - return ElementInsertExecute(std::move(res)); - } - else - { - return ElementUpdateExecute(tileElement, std::move(res)); - } - } - -private: - GameActions::Result::Ptr ElementUpdateQuery(PathElement * pathElement, GameActions::Result::Ptr res) const - { - const int32_t newFootpathType = (_type & (FOOTPATH_PROPERTIES_TYPE_MASK >> 4)); - const bool newPathIsQueue = ((_type >> 7) == 1); - if (pathElement->GetSurfaceEntryIndex() != newFootpathType || pathElement->IsQueue() != newPathIsQueue) - { - res->Cost += MONEY(6, 00); - } - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST && !pathElement->IsGhost()) - { - return MakeResult(GameActions::Status::Unknown, STR_CANT_BUILD_FOOTPATH_HERE); - } - return res; - } - - GameActions::Result::Ptr ElementUpdateExecute(PathElement * pathElement, GameActions::Result::Ptr res) const - { - const int32_t newFootpathType = (_type & (FOOTPATH_PROPERTIES_TYPE_MASK >> 4)); - const bool newPathIsQueue = ((_type >> 7) == 1); - if (pathElement->GetSurfaceEntryIndex() != newFootpathType || pathElement->IsQueue() != newPathIsQueue) - { - res->Cost += MONEY(6, 00); - } - - footpath_queue_chain_reset(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) - { - footpath_remove_edges_at(_loc, reinterpret_cast(pathElement)); - } - - pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); - bool isQueue = _type & FOOTPATH_ELEMENT_INSERT_QUEUE; - pathElement->SetIsQueue(isQueue); - - rct_scenery_entry* elem = pathElement->GetAdditionEntry(); - if (elem != nullptr) - { - if (isQueue) - { - // remove any addition that isn't a TV or a lamp - if ((elem->path_bit.flags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) == 0 - && (elem->path_bit.flags & PATH_BIT_FLAG_LAMP) == 0) - { - pathElement->SetIsBroken(false); - pathElement->SetAddition(0); - } - } - else - { - // remove all TVs - if ((elem->path_bit.flags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) != 0) - { - pathElement->SetIsBroken(false); - pathElement->SetAddition(0); - } - } - } - - RemoveIntersectingWalls(pathElement); - return res; - } - - GameActions::Result::Ptr ElementInsertQuery(GameActions::Result::Ptr res) const - { - bool entrancePath = false, entranceIsSamePath = false; - - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_BUILD_FOOTPATH_HERE); - } - - res->Cost = MONEY(12, 00); - - QuarterTile quarterTile{ 0b1111, 0 }; - auto zLow = _loc.z; - auto zHigh = zLow + PATH_CLEARANCE; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); - zHigh += PATH_HEIGHT_STEP; - } - - auto entranceElement = map_get_park_entrance_element_at(_loc, false); - // Make sure the entrance part is the middle - if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) - { - entrancePath = true; - // Make the price the same as replacing a path - if (entranceElement->GetPathType() == (_type & 0xF)) - entranceIsSamePath = true; - else - res->Cost -= MONEY(6, 00); - } - - // Do not attempt to build a crossing with a queue or a sloped. - uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) - ? CREATE_CROSSING_MODE_NONE - : CREATE_CROSSING_MODE_PATH_OVER_TRACK; - if (!entrancePath - && !map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &res->Cost, crossingMode)) - { - return MakeResult( - GameActions::Status::NoClearance, STR_CANT_BUILD_FOOTPATH_HERE, gGameCommandErrorText, gCommonFormatArgs); - } - - gFootpathGroundFlags = gMapGroundFlags; - if (!gCheatsDisableClearanceChecks && (gMapGroundFlags & ELEMENT_IS_UNDERWATER)) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_CANT_BUILD_THIS_UNDERWATER); - } - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); - } - int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); - res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); - - // Prevent the place sound from being spammed - if (entranceIsSamePath) - res->Cost = 0; - - return res; - } - - GameActions::Result::Ptr ElementInsertExecute(GameActions::Result::Ptr res) const - { - bool entrancePath = false, entranceIsSamePath = false; - - if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST))) - { - footpath_remove_litter(_loc); - } - - res->Cost = MONEY(12, 00); - - QuarterTile quarterTile{ 0b1111, 0 }; - auto zLow = _loc.z; - auto zHigh = zLow + PATH_CLEARANCE; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); - zHigh += PATH_HEIGHT_STEP; - } - - auto entranceElement = map_get_park_entrance_element_at(_loc, false); - // Make sure the entrance part is the middle - if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) - { - entrancePath = true; - // Make the price the same as replacing a path - if (entranceElement->GetPathType() == (_type & 0xF)) - entranceIsSamePath = true; - else - res->Cost -= MONEY(6, 00); - } - - // Do not attempt to build a crossing with a queue or a sloped. - uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) - ? CREATE_CROSSING_MODE_NONE - : CREATE_CROSSING_MODE_PATH_OVER_TRACK; - if (!entrancePath - && !map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), - &res->Cost, crossingMode)) - { - return MakeResult( - GameActions::Status::NoClearance, STR_CANT_BUILD_FOOTPATH_HERE, gGameCommandErrorText, gCommonFormatArgs); - } - - gFootpathGroundFlags = gMapGroundFlags; - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); - } - int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); - res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); - - if (entrancePath) - { - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath) - { - // Set the path type but make sure it's not a queue as that will not show up - entranceElement->SetPathType(_type & 0x7F); - map_invalidate_tile_full(_loc); - } - } - else - { - auto tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); - tileElement->SetType(TILE_ELEMENT_TYPE_PATH); - PathElement* pathElement = tileElement->AsPath(); - pathElement->SetClearanceZ(zHigh); - pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); - pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - pathElement->SetSloped(true); - } - if (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) - { - pathElement->SetIsQueue(true); - } - pathElement->SetAddition(0); - pathElement->SetRideIndex(RIDE_ID_NULL); - pathElement->SetAdditionStatus(255); - pathElement->SetIsBroken(false); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - pathElement->SetGhost(true); - } - footpath_queue_chain_reset(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) - { - footpath_remove_edges_at(_loc, tileElement); - } - if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - AutomaticallySetPeepSpawn(); - } - - RemoveIntersectingWalls(pathElement); - } - - // Prevent the place sound from being spammed - if (entranceIsSamePath) - res->Cost = 0; - - return res; - } - /** - * - * rct2: 0x006A65AD - */ - void AutomaticallySetPeepSpawn() const - { - uint8_t direction = 0; - if (_loc.x != 32) - { - direction++; - if (_loc.y != gMapSizeUnits - 32) - { - direction++; - if (_loc.x != gMapSizeUnits - 32) - { - direction++; - if (_loc.y != 32) - return; - } - } - } - - if (gPeepSpawns.empty()) - { - gPeepSpawns.emplace_back(); - } - PeepSpawn* peepSpawn = &gPeepSpawns[0]; - peepSpawn->x = _loc.x + (DirectionOffsets[direction].x * 15) + 16; - peepSpawn->y = _loc.y + (DirectionOffsets[direction].y * 15) + 16; - peepSpawn->direction = direction; - peepSpawn->z = _loc.z; - } - - void RemoveIntersectingWalls(PathElement * pathElement) const - { - if (pathElement->IsSloped() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - auto direction = pathElement->GetSlopeDirection(); - int32_t z = pathElement->GetBaseZ(); - wall_remove_intersecting_walls({ _loc, z, z + (6 * COORDS_Z_STEP) }, direction_reverse(direction)); - wall_remove_intersecting_walls({ _loc, z, z + (6 * COORDS_Z_STEP) }, direction); - // Removing walls may have made the pointer invalid, so find it again - auto tileElement = map_get_footpath_element(CoordsXYZ(_loc, z)); - if (tileElement == nullptr) - { - log_error("Something went wrong. Could not refind footpath."); - return; - } - pathElement = tileElement->AsPath(); - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) - footpath_connect_edges(_loc, reinterpret_cast(pathElement), GetFlags()); - - footpath_update_queue_chains(); - map_invalidate_tile_full(_loc); - } - - PathElement* map_get_footpath_element_slope(const CoordsXYZ& footpathPos, int32_t slope) const - { - TileElement* tileElement; - bool isSloped = slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED; - - tileElement = map_get_first_element_at(footpathPos); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH && tileElement->GetBaseZ() == footpathPos.z - && (tileElement->AsPath()->IsSloped() == isSloped) - && (tileElement->AsPath()->GetSlopeDirection() == (slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK))) - { - return tileElement->AsPath(); - } - } while (!(tileElement++)->IsLastForTile()); - return nullptr; - } -}; diff --git a/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp b/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp new file mode 100644 index 0000000000..ae3d8402b6 --- /dev/null +++ b/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp @@ -0,0 +1,252 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "FootpathPlaceFromTrackAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Surface.h" +#include "../world/Wall.h" + +void FootpathPlaceFromTrackAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_edges); +} + +GameActions::Result::Ptr FootpathPlaceFromTrackAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc.ToTileCentre(); + + gFootpathGroundFlags = 0; + + if (!LocationValid(_loc) || map_is_edge(_loc)) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_OFF_EDGE_OF_MAP); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) + { + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (_loc.z < FootpathMinHeight) + { + return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_LOW); + } + + if (_loc.z > FootpathMaxHeight) + { + return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_HIGH); + } + + return ElementInsertQuery(std::move(res)); +} + +GameActions::Result::Ptr FootpathPlaceFromTrackAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc.ToTileCentre(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_interrupt_peeps(_loc); + } + + gFootpathGroundFlags = 0; + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + return ElementInsertExecute(std::move(res)); +} + +GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertQuery(GameActions::Result::Ptr res) const +{ + bool entrancePath = false, entranceIsSamePath = false; + + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); + } + + res->Cost = MONEY(12, 00); + + QuarterTile quarterTile{ 0b1111, 0 }; + auto zLow = _loc.z; + auto zHigh = zLow + PATH_CLEARANCE; + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); + zHigh += PATH_HEIGHT_STEP; + } + + auto entranceElement = map_get_park_entrance_element_at(_loc, false); + // Make sure the entrance part is the middle + if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) + { + entrancePath = true; + // Make the price the same as replacing a path + if (entranceElement->GetPathType() == (_type & 0xF)) + entranceIsSamePath = true; + else + res->Cost -= MONEY(6, 00); + } + + // Do not attempt to build a crossing with a queue or a sloped. + uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) + ? CREATE_CROSSING_MODE_NONE + : CREATE_CROSSING_MODE_PATH_OVER_TRACK; + if (!entrancePath + && !map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &res->Cost, crossingMode)) + { + return MakeResult( + GameActions::Status::NoClearance, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText, + gCommonFormatArgs); + } + + gFootpathGroundFlags = gMapGroundFlags; + if (!gCheatsDisableClearanceChecks && (gMapGroundFlags & ELEMENT_IS_UNDERWATER)) + { + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_CANT_BUILD_THIS_UNDERWATER); + } + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); + } + int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); + res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); + + // Prevent the place sound from being spammed + if (entranceIsSamePath) + res->Cost = 0; + + return res; +} + +GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(GameActions::Result::Ptr res) const +{ + bool entrancePath = false, entranceIsSamePath = false; + + if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST))) + { + footpath_remove_litter(_loc); + } + + res->Cost = MONEY(12, 00); + + QuarterTile quarterTile{ 0b1111, 0 }; + auto zLow = _loc.z; + auto zHigh = zLow + PATH_CLEARANCE; + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); + zHigh += PATH_HEIGHT_STEP; + } + + auto entranceElement = map_get_park_entrance_element_at(_loc, false); + // Make sure the entrance part is the middle + if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) + { + entrancePath = true; + // Make the price the same as replacing a path + if (entranceElement->GetPathType() == (_type & 0xF)) + entranceIsSamePath = true; + else + res->Cost -= MONEY(6, 00); + } + + // Do not attempt to build a crossing with a queue or a sloped. + uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) + ? CREATE_CROSSING_MODE_NONE + : CREATE_CROSSING_MODE_PATH_OVER_TRACK; + if (!entrancePath + && !map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), + &res->Cost, crossingMode)) + { + return MakeResult( + GameActions::Status::NoClearance, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText, + gCommonFormatArgs); + } + + gFootpathGroundFlags = gMapGroundFlags; + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); + } + int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); + res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); + + if (entrancePath) + { + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath) + { + // Set the path type but make sure it's not a queue as that will not show up + entranceElement->SetPathType(_type & 0x7F); + map_invalidate_tile_full(_loc); + } + } + else + { + auto tileElement = tile_element_insert(_loc, 0b1111); + assert(tileElement != nullptr); + tileElement->SetType(TILE_ELEMENT_TYPE_PATH); + PathElement* pathElement = tileElement->AsPath(); + pathElement->SetClearanceZ(zHigh); + pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); + pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + pathElement->SetSloped(true); + } + if (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) + { + pathElement->SetIsQueue(true); + } + pathElement->SetAddition(0); + pathElement->SetRideIndex(RIDE_ID_NULL); + pathElement->SetAdditionStatus(255); + pathElement->SetIsBroken(false); + pathElement->SetEdges(_edges); + pathElement->SetCorners(0); + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + pathElement->SetGhost(true); + } + map_invalidate_tile_full(_loc); + } + + // Prevent the place sound from being spammed + if (entranceIsSamePath) + res->Cost = 0; + + return res; +} diff --git a/src/openrct2/actions/FootpathPlaceFromTrackAction.h b/src/openrct2/actions/FootpathPlaceFromTrackAction.h new file mode 100644 index 0000000000..9878a91f47 --- /dev/null +++ b/src/openrct2/actions/FootpathPlaceFromTrackAction.h @@ -0,0 +1,44 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(FootpathPlaceFromTrackAction, GAME_COMMAND_PLACE_PATH_FROM_TRACK, GameActions::Result) +{ +private: + CoordsXYZ _loc; + uint8_t _slope{}; + ObjectEntryIndex _type{}; + uint8_t _edges{}; + +public: + FootpathPlaceFromTrackAction() = default; + FootpathPlaceFromTrackAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, uint8_t edges) + : _loc(loc) + , _slope(slope) + , _type(type) + , _edges(edges) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr ElementInsertQuery(GameActions::Result::Ptr res) const; + GameActions::Result::Ptr ElementInsertExecute(GameActions::Result::Ptr res) const; +}; diff --git a/src/openrct2/actions/FootpathPlaceFromTrackAction.hpp b/src/openrct2/actions/FootpathPlaceFromTrackAction.hpp deleted file mode 100644 index 6afeb828c5..0000000000 --- a/src/openrct2/actions/FootpathPlaceFromTrackAction.hpp +++ /dev/null @@ -1,279 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Park.h" -#include "../world/Surface.h" -#include "../world/Wall.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(FootpathPlaceFromTrackAction, GAME_COMMAND_PLACE_PATH_FROM_TRACK, GameActions::Result) -{ -private: - CoordsXYZ _loc; - uint8_t _slope{}; - ObjectEntryIndex _type{}; - uint8_t _edges{}; - -public: - FootpathPlaceFromTrackAction() = default; - FootpathPlaceFromTrackAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, uint8_t edges) - : _loc(loc) - , _slope(slope) - , _type(type) - , _edges(edges) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_edges); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc.ToTileCentre(); - - gFootpathGroundFlags = 0; - - if (!LocationValid(_loc) || map_is_edge(_loc)) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_OFF_EDGE_OF_MAP); - } - - if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) - { - return MakeResult( - GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (_loc.z < FootpathMinHeight) - { - return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_LOW); - } - - if (_loc.z > FootpathMaxHeight) - { - return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_HIGH); - } - - return ElementInsertQuery(std::move(res)); - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc.ToTileCentre(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_interrupt_peeps(_loc); - } - - gFootpathGroundFlags = 0; - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - return ElementInsertExecute(std::move(res)); - } - -private: - GameActions::Result::Ptr ElementInsertQuery(GameActions::Result::Ptr res) const - { - bool entrancePath = false, entranceIsSamePath = false; - - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); - } - - res->Cost = MONEY(12, 00); - - QuarterTile quarterTile{ 0b1111, 0 }; - auto zLow = _loc.z; - auto zHigh = zLow + PATH_CLEARANCE; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); - zHigh += PATH_HEIGHT_STEP; - } - - auto entranceElement = map_get_park_entrance_element_at(_loc, false); - // Make sure the entrance part is the middle - if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) - { - entrancePath = true; - // Make the price the same as replacing a path - if (entranceElement->GetPathType() == (_type & 0xF)) - entranceIsSamePath = true; - else - res->Cost -= MONEY(6, 00); - } - - // Do not attempt to build a crossing with a queue or a sloped. - uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) - ? CREATE_CROSSING_MODE_NONE - : CREATE_CROSSING_MODE_PATH_OVER_TRACK; - if (!entrancePath - && !map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &res->Cost, crossingMode)) - { - return MakeResult( - GameActions::Status::NoClearance, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText, - gCommonFormatArgs); - } - - gFootpathGroundFlags = gMapGroundFlags; - if (!gCheatsDisableClearanceChecks && (gMapGroundFlags & ELEMENT_IS_UNDERWATER)) - { - return MakeResult( - GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, - STR_CANT_BUILD_THIS_UNDERWATER); - } - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); - } - int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); - res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); - - // Prevent the place sound from being spammed - if (entranceIsSamePath) - res->Cost = 0; - - return res; - } - - GameActions::Result::Ptr ElementInsertExecute(GameActions::Result::Ptr res) const - { - bool entrancePath = false, entranceIsSamePath = false; - - if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST))) - { - footpath_remove_litter(_loc); - } - - res->Cost = MONEY(12, 00); - - QuarterTile quarterTile{ 0b1111, 0 }; - auto zLow = _loc.z; - auto zHigh = zLow + PATH_CLEARANCE; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); - zHigh += PATH_HEIGHT_STEP; - } - - auto entranceElement = map_get_park_entrance_element_at(_loc, false); - // Make sure the entrance part is the middle - if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) - { - entrancePath = true; - // Make the price the same as replacing a path - if (entranceElement->GetPathType() == (_type & 0xF)) - entranceIsSamePath = true; - else - res->Cost -= MONEY(6, 00); - } - - // Do not attempt to build a crossing with a queue or a sloped. - uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) - ? CREATE_CROSSING_MODE_NONE - : CREATE_CROSSING_MODE_PATH_OVER_TRACK; - if (!entrancePath - && !map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), - &res->Cost, crossingMode)) - { - return MakeResult( - GameActions::Status::NoClearance, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText, - gCommonFormatArgs); - } - - gFootpathGroundFlags = gMapGroundFlags; - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); - } - int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); - res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); - - if (entrancePath) - { - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath) - { - // Set the path type but make sure it's not a queue as that will not show up - entranceElement->SetPathType(_type & 0x7F); - map_invalidate_tile_full(_loc); - } - } - else - { - auto tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); - tileElement->SetType(TILE_ELEMENT_TYPE_PATH); - PathElement* pathElement = tileElement->AsPath(); - pathElement->SetClearanceZ(zHigh); - pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); - pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - pathElement->SetSloped(true); - } - if (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) - { - pathElement->SetIsQueue(true); - } - pathElement->SetAddition(0); - pathElement->SetRideIndex(RIDE_ID_NULL); - pathElement->SetAdditionStatus(255); - pathElement->SetIsBroken(false); - pathElement->SetEdges(_edges); - pathElement->SetCorners(0); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - pathElement->SetGhost(true); - } - map_invalidate_tile_full(_loc); - } - - // Prevent the place sound from being spammed - if (entranceIsSamePath) - res->Cost = 0; - - return res; - } -}; diff --git a/src/openrct2/actions/FootpathRemoveAction.cpp b/src/openrct2/actions/FootpathRemoveAction.cpp new file mode 100644 index 0000000000..16ad6df3d0 --- /dev/null +++ b/src/openrct2/actions/FootpathRemoveAction.cpp @@ -0,0 +1,174 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "FootpathRemoveAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Wall.h" +#include "BannerRemoveAction.h" + +void FootpathRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); +} + +void FootpathRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr FootpathRemoveAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = { _loc.x + 16, _loc.y + 16, _loc.z }; + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + TileElement* footpathElement = GetFootpathElement(); + if (footpathElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_FOOTPATH_FROM_HERE); + } + + res->Cost = GetRefundPrice(footpathElement); + + return res; +} + +GameActions::Result::Ptr FootpathRemoveAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = { _loc.x + 16, _loc.y + 16, _loc.z }; + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_interrupt_peeps(_loc); + footpath_remove_litter(_loc); + } + + TileElement* footpathElement = GetFootpathElement(); + if (footpathElement != nullptr) + { + footpath_queue_chain_reset(); + auto bannerRes = RemoveBannersAtElement(_loc, footpathElement); + if (bannerRes->Error == GameActions::Status::Ok) + { + res->Cost += bannerRes->Cost; + } + footpath_remove_edges_at(_loc, footpathElement); + map_invalidate_tile_full(_loc); + tile_element_remove(footpathElement); + footpath_update_queue_chains(); + + // Remove the spawn point (if there is one in the current tile) + gPeepSpawns.erase( + std::remove_if( + gPeepSpawns.begin(), gPeepSpawns.end(), + [this](const CoordsXYZ& spawn) { + { + return spawn.ToTileStart() == _loc.ToTileStart(); + } + }), + gPeepSpawns.end()); + } + else + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_FOOTPATH_FROM_HERE); + } + + res->Cost += GetRefundPrice(footpathElement); + + return res; +} + +TileElement* FootpathRemoveAction::GetFootpathElement() const +{ + bool getGhostPath = GetFlags() & GAME_COMMAND_FLAG_GHOST; + + TileElement* tileElement = map_get_footpath_element(_loc); + TileElement* footpathElement = nullptr; + if (tileElement != nullptr) + { + if (getGhostPath && !tileElement->IsGhost()) + { + while (!(tileElement++)->IsLastForTile()) + { + if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH && !tileElement->IsGhost()) + { + continue; + } + footpathElement = tileElement; + break; + } + } + else + { + footpathElement = tileElement; + } + } + + return footpathElement; +} + +money32 FootpathRemoveAction::GetRefundPrice(TileElement* footpathElement) const +{ + money32 cost = -MONEY(10, 00); + return cost; +} + +/** + * + * rct2: 0x006BA23E + */ +GameActions::Result::Ptr FootpathRemoveAction::RemoveBannersAtElement(const CoordsXY& loc, TileElement* tileElement) const +{ + auto result = MakeResult(); + while (!(tileElement++)->IsLastForTile()) + { + if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH) + return result; + else if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) + continue; + + auto bannerRemoveAction = BannerRemoveAction({ loc, tileElement->GetBaseZ(), tileElement->AsBanner()->GetPosition() }); + bool isGhost = tileElement->IsGhost(); + auto bannerFlags = GetFlags() | (isGhost ? static_cast(GAME_COMMAND_FLAG_GHOST) : 0); + bannerRemoveAction.SetFlags(bannerFlags); + auto res = GameActions::ExecuteNested(&bannerRemoveAction); + // Ghost removal is free + if (res->Error == GameActions::Status::Ok && !isGhost) + { + result->Cost += res->Cost; + } + tileElement--; + } + return result; +} diff --git a/src/openrct2/actions/FootpathRemoveAction.h b/src/openrct2/actions/FootpathRemoveAction.h new file mode 100644 index 0000000000..e4a269bd47 --- /dev/null +++ b/src/openrct2/actions/FootpathRemoveAction.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(FootpathRemoveAction, GAME_COMMAND_REMOVE_PATH, GameActions::Result) +{ +private: + CoordsXYZ _loc; + +public: + FootpathRemoveAction() = default; + FootpathRemoveAction(const CoordsXYZ& location) + : _loc(location) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + TileElement* GetFootpathElement() const; + money32 GetRefundPrice(TileElement * footpathElement) const; + GameActions::Result::Ptr RemoveBannersAtElement(const CoordsXY& loc, TileElement* tileElement) const; +}; diff --git a/src/openrct2/actions/FootpathRemoveAction.hpp b/src/openrct2/actions/FootpathRemoveAction.hpp deleted file mode 100644 index 71504c2ea0..0000000000 --- a/src/openrct2/actions/FootpathRemoveAction.hpp +++ /dev/null @@ -1,195 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#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, GameActions::Result) -{ -private: - CoordsXYZ _loc; - -public: - FootpathRemoveAction() = default; - FootpathRemoveAction(const CoordsXYZ& location) - : _loc(location) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = { _loc.x + 16, _loc.y + 16, _loc.z }; - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - TileElement* footpathElement = GetFootpathElement(); - if (footpathElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_FOOTPATH_FROM_HERE); - } - - res->Cost = GetRefundPrice(footpathElement); - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = { _loc.x + 16, _loc.y + 16, _loc.z }; - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_interrupt_peeps(_loc); - footpath_remove_litter(_loc); - } - - TileElement* footpathElement = GetFootpathElement(); - if (footpathElement != nullptr) - { - footpath_queue_chain_reset(); - auto bannerRes = RemoveBannersAtElement(_loc, footpathElement); - if (bannerRes->Error == GameActions::Status::Ok) - { - res->Cost += bannerRes->Cost; - } - footpath_remove_edges_at(_loc, footpathElement); - map_invalidate_tile_full(_loc); - tile_element_remove(footpathElement); - footpath_update_queue_chains(); - - // Remove the spawn point (if there is one in the current tile) - gPeepSpawns.erase( - std::remove_if( - gPeepSpawns.begin(), gPeepSpawns.end(), - [this](const CoordsXYZ& spawn) { - { - return spawn.ToTileStart() == _loc.ToTileStart(); - } - }), - gPeepSpawns.end()); - } - else - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_FOOTPATH_FROM_HERE); - } - - res->Cost += GetRefundPrice(footpathElement); - - return res; - } - -private: - TileElement* GetFootpathElement() const - { - bool getGhostPath = GetFlags() & GAME_COMMAND_FLAG_GHOST; - - TileElement* tileElement = map_get_footpath_element(_loc); - TileElement* footpathElement = nullptr; - if (tileElement != nullptr) - { - if (getGhostPath && !tileElement->IsGhost()) - { - while (!(tileElement++)->IsLastForTile()) - { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH && !tileElement->IsGhost()) - { - continue; - } - footpathElement = tileElement; - break; - } - } - else - { - footpathElement = tileElement; - } - } - - return footpathElement; - } - - money32 GetRefundPrice(TileElement * footpathElement) const - { - money32 cost = -MONEY(10, 00); - return cost; - } - - /** - * - * rct2: 0x006BA23E - */ - GameActions::Result::Ptr RemoveBannersAtElement(const CoordsXY& loc, TileElement* tileElement) const - { - auto result = MakeResult(); - while (!(tileElement++)->IsLastForTile()) - { - if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH) - return result; - else if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) - continue; - - auto bannerRemoveAction = BannerRemoveAction( - { loc, tileElement->GetBaseZ(), tileElement->AsBanner()->GetPosition() }); - bool isGhost = tileElement->IsGhost(); - auto bannerFlags = GetFlags() | (isGhost ? static_cast(GAME_COMMAND_FLAG_GHOST) : 0); - bannerRemoveAction.SetFlags(bannerFlags); - auto res = GameActions::ExecuteNested(&bannerRemoveAction); - // Ghost removal is free - if (res->Error == GameActions::Status::Ok && !isGhost) - { - result->Cost += res->Cost; - } - tileElement--; - } - return result; - } -}; diff --git a/src/openrct2/actions/GameActionCompat.cpp b/src/openrct2/actions/GameActionCompat.cpp index 576778a671..01de237685 100644 --- a/src/openrct2/actions/GameActionCompat.cpp +++ b/src/openrct2/actions/GameActionCompat.cpp @@ -7,18 +7,22 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../peep/Staff.h" +#include "../ride/Track.h" +#include "../world/Entrance.h" +#include "../world/Park.h" #include "GameAction.h" -#include "GuestSetNameAction.hpp" -#include "MazeSetTrackAction.hpp" -#include "PlaceParkEntranceAction.hpp" -#include "PlacePeepSpawnAction.hpp" -#include "RideCreateAction.hpp" -#include "RideDemolishAction.hpp" -#include "RideSetName.hpp" -#include "RideSetStatus.hpp" -#include "SetParkEntranceFeeAction.hpp" -#include "StaffSetNameAction.hpp" -#include "WallRemoveAction.hpp" +#include "GuestSetNameAction.h" +#include "MazeSetTrackAction.h" +#include "PlaceParkEntranceAction.h" +#include "PlacePeepSpawnAction.h" +#include "RideCreateAction.h" +#include "RideDemolishAction.h" +#include "RideSetNameAction.h" +#include "RideSetStatusAction.h" +#include "SetParkEntranceFeeAction.h" +#include "StaffSetNameAction.h" +#include "WallRemoveAction.h" #pragma region PlaceParkEntranceAction /** diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index e50c84153d..872883540c 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -7,87 +7,87 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ -#include "BalloonPressAction.hpp" -#include "BannerPlaceAction.hpp" -#include "BannerRemoveAction.hpp" -#include "BannerSetColourAction.hpp" -#include "BannerSetNameAction.hpp" -#include "BannerSetStyleAction.hpp" -#include "ClearAction.hpp" -#include "ClimateSetAction.hpp" -#include "CustomAction.hpp" -#include "FootpathAdditionPlaceAction.hpp" -#include "FootpathAdditionRemoveAction.hpp" -#include "FootpathPlaceAction.hpp" -#include "FootpathPlaceFromTrackAction.hpp" -#include "FootpathRemoveAction.hpp" +#include "BalloonPressAction.h" +#include "BannerPlaceAction.h" +#include "BannerRemoveAction.h" +#include "BannerSetColourAction.h" +#include "BannerSetNameAction.h" +#include "BannerSetStyleAction.h" +#include "ClearAction.h" +#include "ClimateSetAction.h" +#include "CustomAction.h" +#include "FootpathAdditionPlaceAction.h" +#include "FootpathAdditionRemoveAction.h" +#include "FootpathPlaceAction.h" +#include "FootpathPlaceFromTrackAction.h" +#include "FootpathRemoveAction.h" #include "GameAction.h" -#include "GuestSetFlagsAction.hpp" -#include "GuestSetNameAction.hpp" -#include "LandBuyRightsAction.hpp" -#include "LandLowerAction.hpp" -#include "LandRaiseAction.hpp" -#include "LandSetHeightAction.hpp" -#include "LandSetRightsAction.hpp" -#include "LandSmoothAction.hpp" -#include "LargeSceneryPlaceAction.hpp" -#include "LargeSceneryRemoveAction.hpp" -#include "LargeScenerySetColourAction.hpp" -#include "LoadOrQuitAction.hpp" -#include "MazePlaceTrackAction.hpp" -#include "MazeSetTrackAction.hpp" -#include "NetworkModifyGroupAction.hpp" -#include "ParkEntranceRemoveAction.hpp" -#include "ParkMarketingAction.hpp" -#include "ParkSetDateAction.hpp" -#include "ParkSetLoanAction.hpp" -#include "ParkSetNameAction.hpp" -#include "ParkSetParameterAction.hpp" -#include "ParkSetResearchFundingAction.hpp" -#include "PauseToggleAction.hpp" -#include "PeepPickupAction.hpp" -#include "PlaceParkEntranceAction.hpp" -#include "PlacePeepSpawnAction.hpp" -#include "PlayerKickAction.hpp" -#include "PlayerSetGroupAction.hpp" -#include "RideCreateAction.hpp" -#include "RideDemolishAction.hpp" -#include "RideEntranceExitPlaceAction.hpp" -#include "RideEntranceExitRemoveAction.hpp" -#include "RideSetAppearanceAction.hpp" -#include "RideSetColourScheme.hpp" -#include "RideSetName.hpp" -#include "RideSetPriceAction.hpp" -#include "RideSetSetting.hpp" -#include "RideSetStatus.hpp" -#include "RideSetVehiclesAction.hpp" -#include "ScenarioSetSettingAction.hpp" -#include "SetCheatAction.hpp" -#include "SetParkEntranceFeeAction.hpp" -#include "SignSetNameAction.hpp" -#include "SignSetStyleAction.hpp" -#include "SmallSceneryPlaceAction.hpp" -#include "SmallSceneryRemoveAction.hpp" -#include "SmallScenerySetColourAction.hpp" -#include "StaffFireAction.hpp" -#include "StaffHireNewAction.hpp" -#include "StaffSetColourAction.hpp" -#include "StaffSetCostumeAction.hpp" -#include "StaffSetNameAction.hpp" -#include "StaffSetOrdersAction.hpp" -#include "StaffSetPatrolAreaAction.hpp" -#include "SurfaceSetStyleAction.hpp" -#include "TileModifyAction.hpp" +#include "GuestSetFlagsAction.h" +#include "GuestSetNameAction.h" +#include "LandBuyRightsAction.h" +#include "LandLowerAction.h" +#include "LandRaiseAction.h" +#include "LandSetHeightAction.h" +#include "LandSetRightsAction.h" +#include "LandSmoothAction.h" +#include "LargeSceneryPlaceAction.h" +#include "LargeSceneryRemoveAction.h" +#include "LargeScenerySetColourAction.h" +#include "LoadOrQuitAction.h" +#include "MazePlaceTrackAction.h" +#include "MazeSetTrackAction.h" +#include "NetworkModifyGroupAction.h" +#include "ParkEntranceRemoveAction.h" +#include "ParkMarketingAction.h" +#include "ParkSetDateAction.h" +#include "ParkSetLoanAction.h" +#include "ParkSetNameAction.h" +#include "ParkSetParameterAction.h" +#include "ParkSetResearchFundingAction.h" +#include "PauseToggleAction.h" +#include "PeepPickupAction.h" +#include "PlaceParkEntranceAction.h" +#include "PlacePeepSpawnAction.h" +#include "PlayerKickAction.h" +#include "PlayerSetGroupAction.h" +#include "RideCreateAction.h" +#include "RideDemolishAction.h" +#include "RideEntranceExitPlaceAction.h" +#include "RideEntranceExitRemoveAction.h" +#include "RideSetAppearanceAction.h" +#include "RideSetColourSchemeAction.h" +#include "RideSetNameAction.h" +#include "RideSetPriceAction.h" +#include "RideSetSettingAction.h" +#include "RideSetStatusAction.h" +#include "RideSetVehicleAction.h" +#include "ScenarioSetSettingAction.h" +#include "SetCheatAction.h" +#include "SetParkEntranceFeeAction.h" +#include "SignSetNameAction.h" +#include "SignSetStyleAction.h" +#include "SmallSceneryPlaceAction.h" +#include "SmallSceneryRemoveAction.h" +#include "SmallScenerySetColourAction.h" +#include "StaffFireAction.h" +#include "StaffHireNewAction.h" +#include "StaffSetColourAction.h" +#include "StaffSetCostumeAction.h" +#include "StaffSetNameAction.h" +#include "StaffSetOrdersAction.h" +#include "StaffSetPatrolAreaAction.h" +#include "SurfaceSetStyleAction.h" +#include "TileModifyAction.h" #include "TrackDesignAction.h" -#include "TrackPlaceAction.hpp" -#include "TrackRemoveAction.hpp" -#include "TrackSetBrakeSpeedAction.hpp" -#include "WallPlaceAction.hpp" -#include "WallRemoveAction.hpp" -#include "WallSetColourAction.hpp" -#include "WaterLowerAction.hpp" -#include "WaterRaiseAction.hpp" -#include "WaterSetHeightAction.hpp" +#include "TrackPlaceAction.h" +#include "TrackRemoveAction.h" +#include "TrackSetBrakeSpeedAction.h" +#include "WallPlaceAction.h" +#include "WallRemoveAction.h" +#include "WallSetColourAction.h" +#include "WaterLowerAction.h" +#include "WaterRaiseAction.h" +#include "WaterSetHeightAction.h" namespace GameActions { diff --git a/src/openrct2/actions/GuestSetFlagsAction.cpp b/src/openrct2/actions/GuestSetFlagsAction.cpp new file mode 100644 index 0000000000..2644b04ae1 --- /dev/null +++ b/src/openrct2/actions/GuestSetFlagsAction.cpp @@ -0,0 +1,51 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "GuestSetFlagsAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" + +void GuestSetFlagsAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("peep", _peepId); + visitor.Visit("flags", _newFlags); +} + +void GuestSetFlagsAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_peepId) << DS_TAG(_newFlags); +} + +GameActions::Result::Ptr GuestSetFlagsAction::Query() const +{ + Peep* peep = TryGetEntity(_peepId); + if (peep == nullptr) + { + log_error("Used invalid sprite index for peep: %u", static_cast(_peepId)); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS); + } + return std::make_unique(); +} + +GameActions::Result::Ptr GuestSetFlagsAction::Execute() const +{ + Peep* peep = TryGetEntity(_peepId); + if (peep == nullptr) + { + log_error("Used invalid sprite index for peep: %u", static_cast(_peepId)); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS); + } + + peep->PeepFlags = _newFlags; + + return std::make_unique(); +} diff --git a/src/openrct2/actions/GuestSetFlagsAction.h b/src/openrct2/actions/GuestSetFlagsAction.h new file mode 100644 index 0000000000..6cf9db9290 --- /dev/null +++ b/src/openrct2/actions/GuestSetFlagsAction.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(GuestSetFlagsAction, GAME_COMMAND_GUEST_SET_FLAGS, GameActions::Result) +{ +private: + uint16_t _peepId{ SPRITE_INDEX_NULL }; + uint32_t _newFlags{}; + +public: + GuestSetFlagsAction() = default; + GuestSetFlagsAction(uint16_t peepId, uint32_t flags) + : _peepId(peepId) + , _newFlags(flags) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/GuestSetFlagsAction.hpp b/src/openrct2/actions/GuestSetFlagsAction.hpp deleted file mode 100644 index 4692b7a473..0000000000 --- a/src/openrct2/actions/GuestSetFlagsAction.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../OpenRCT2.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(GuestSetFlagsAction, GAME_COMMAND_GUEST_SET_FLAGS, GameActions::Result) -{ -private: - uint16_t _peepId{ SPRITE_INDEX_NULL }; - uint32_t _newFlags{}; - -public: - GuestSetFlagsAction() = default; - GuestSetFlagsAction(uint16_t peepId, uint32_t flags) - : _peepId(peepId) - , _newFlags(flags) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("peep", _peepId); - visitor.Visit("flags", _newFlags); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_peepId) << DS_TAG(_newFlags); - } - - GameActions::Result::Ptr Query() const override - { - Peep* peep = TryGetEntity(_peepId); - if (peep == nullptr) - { - log_error("Used invalid sprite index for peep: %u", static_cast(_peepId)); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS); - } - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - Peep* peep = TryGetEntity(_peepId); - if (peep == nullptr) - { - log_error("Used invalid sprite index for peep: %u", static_cast(_peepId)); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS); - } - - peep->PeepFlags = _newFlags; - - return std::make_unique(); - } -}; diff --git a/src/openrct2/actions/GuestSetNameAction.cpp b/src/openrct2/actions/GuestSetNameAction.cpp new file mode 100644 index 0000000000..38a4b71841 --- /dev/null +++ b/src/openrct2/actions/GuestSetNameAction.cpp @@ -0,0 +1,86 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "GuestSetNameAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Sprite.h" + +void GuestSetNameAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("peep", _spriteIndex); + visitor.Visit("name", _name); +} + +void GuestSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_spriteIndex) << DS_TAG(_name); +} + +GameActions::Result::Ptr GuestSetNameAction::Query() const +{ + if (_spriteIndex >= MAX_SPRITES) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); + } + + auto guest = TryGetEntity(_spriteIndex); + if (guest == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr GuestSetNameAction::Execute() const +{ + auto guest = TryGetEntity(_spriteIndex); + if (guest == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); + } + + auto curName = guest->GetName(); + if (curName == _name) + { + return std::make_unique(GameActions::Status::Ok, STR_NONE); + } + + if (!guest->SetName(_name)) + { + return std::make_unique(GameActions::Status::Unknown, STR_CANT_NAME_GUEST, STR_NONE); + } + + // Easter egg functions are for guests only + guest->HandleEasterEggName(); + + gfx_invalidate_screen(); + + auto intent = Intent(INTENT_ACTION_REFRESH_GUEST_LIST); + context_broadcast_intent(&intent); + + auto res = std::make_unique(); + res->Position.x = guest->x; + res->Position.y = guest->y; + res->Position.z = guest->z; + return res; +} diff --git a/src/openrct2/actions/GuestSetNameAction.h b/src/openrct2/actions/GuestSetNameAction.h new file mode 100644 index 0000000000..4364a22a39 --- /dev/null +++ b/src/openrct2/actions/GuestSetNameAction.h @@ -0,0 +1,48 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(GuestSetNameAction, GAME_COMMAND_SET_GUEST_NAME, GameActions::Result) +{ +private: + uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; + std::string _name; + +public: + GuestSetNameAction() = default; + GuestSetNameAction(uint16_t spriteIndex, const std::string& name) + : _spriteIndex(spriteIndex) + , _name(name) + { + } + + uint16_t GetSpriteIndex() const + { + return _spriteIndex; + } + + std::string GetGuestName() const + { + return _name; + } + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/GuestSetNameAction.hpp b/src/openrct2/actions/GuestSetNameAction.hpp deleted file mode 100644 index 9403bcc731..0000000000 --- a/src/openrct2/actions/GuestSetNameAction.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(GuestSetNameAction, GAME_COMMAND_SET_GUEST_NAME, GameActions::Result) -{ -private: - uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; - std::string _name; - -public: - GuestSetNameAction() = default; - GuestSetNameAction(uint16_t spriteIndex, const std::string& name) - : _spriteIndex(spriteIndex) - , _name(name) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("peep", _spriteIndex); - visitor.Visit("name", _name); - } - - uint16_t GetSpriteIndex() const - { - return _spriteIndex; - } - - std::string GetGuestName() const - { - return _name; - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_spriteIndex) << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteIndex >= MAX_SPRITES) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); - } - - auto guest = TryGetEntity(_spriteIndex); - if (guest == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto guest = TryGetEntity(_spriteIndex); - if (guest == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); - } - - auto curName = guest->GetName(); - if (curName == _name) - { - return std::make_unique(GameActions::Status::Ok, STR_NONE); - } - - if (!guest->SetName(_name)) - { - return std::make_unique(GameActions::Status::Unknown, STR_CANT_NAME_GUEST, STR_NONE); - } - - // Easter egg functions are for guests only - guest->HandleEasterEggName(); - - gfx_invalidate_screen(); - - auto intent = Intent(INTENT_ACTION_REFRESH_GUEST_LIST); - context_broadcast_intent(&intent); - - auto res = std::make_unique(); - res->Position.x = guest->x; - res->Position.y = guest->y; - res->Position.z = guest->z; - return res; - } -}; diff --git a/src/openrct2/actions/LandBuyRightsAction.cpp b/src/openrct2/actions/LandBuyRightsAction.cpp new file mode 100644 index 0000000000..152f95c9f9 --- /dev/null +++ b/src/openrct2/actions/LandBuyRightsAction.cpp @@ -0,0 +1,149 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "LandBuyRightsAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandSetHeightAction.h" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../util/Util.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandBuyRightsAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range) << DS_TAG(_setting); +} + +GameActions::Result::Ptr LandBuyRightsAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr LandBuyRightsAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr LandBuyRightsAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + + MapRange normRange = _range.Normalise(); + // Keep big coordinates within map boundaries + auto aX = std::max(32, normRange.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, normRange.GetRight()); + auto aY = std::max(32, normRange.GetTop()); + auto bY = std::min(gMapSizeMaxXY, normRange.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + CoordsXYZ centre{ (validRange.GetLeft() + validRange.GetRight()) / 2 + 16, + (validRange.GetTop() + validRange.GetBottom()) / 2 + 16, 0 }; + centre.z = tile_element_height(centre); + + res->Position = centre; + res->Expenditure = ExpenditureType::LandPurchase; + + // Game command modified to accept selection size + for (auto y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (auto x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + auto result = map_buy_land_rights_for_tile({ x, y }, isExecuting); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + } + } + } + if (isExecuting) + { + map_count_remaining_land_rights(); + } + return res; +} + +GameActions::Result::Ptr LandBuyRightsAction::map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const +{ + if (_setting >= LandBuyRightSetting::Count) + { + log_warning("Tried calling buy land rights with an incorrect setting. setting = %u", _setting); + return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[0], STR_NONE); + } + + SurfaceElement* surfaceElement = map_get_surface_element_at(loc); + if (surfaceElement == nullptr) + { + log_error("Could not find surface. x = %d, y = %d", loc.x, loc.y); + return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[EnumValue(_setting)], STR_NONE); + } + + auto res = MakeResult(); + switch (_setting) + { + case LandBuyRightSetting::BuyLand: // 0 + if ((surfaceElement->GetOwnership() & OWNERSHIP_OWNED) != 0) + { // If the land is already owned + return res; + } + + if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 + || (surfaceElement->GetOwnership() & OWNERSHIP_AVAILABLE) == 0) + { + return MakeResult(GameActions::Status::NotOwned, _ErrorTitles[EnumValue(_setting)], STR_LAND_NOT_FOR_SALE); + } + if (isExecuting) + { + surfaceElement->SetOwnership(OWNERSHIP_OWNED); + update_park_fences_around_tile(loc); + } + res->Cost = gLandPrice; + return res; + + case LandBuyRightSetting::BuyConstructionRights: // 2 + if ((surfaceElement->GetOwnership() & (OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)) != 0) + { // If the land or construction rights are already owned + return res; + } + + if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 + || (surfaceElement->GetOwnership() & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) == 0) + { + return MakeResult( + GameActions::Status::NotOwned, _ErrorTitles[EnumValue(_setting)], STR_CONSTRUCTION_RIGHTS_NOT_FOR_SALE); + } + + if (isExecuting) + { + surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED); + uint16_t baseZ = surfaceElement->GetBaseZ(); + map_invalidate_tile({ loc, baseZ, baseZ + 16 }); + } + res->Cost = gConstructionRightsPrice; + return res; + + default: + log_warning("Tried calling buy land rights with an incorrect setting. setting = %u", _setting); + return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[0], STR_NONE); + } +} diff --git a/src/openrct2/actions/LandBuyRightsAction.h b/src/openrct2/actions/LandBuyRightsAction.h new file mode 100644 index 0000000000..45390db603 --- /dev/null +++ b/src/openrct2/actions/LandBuyRightsAction.h @@ -0,0 +1,56 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +enum class LandBuyRightSetting : uint8_t +{ + BuyLand, + BuyConstructionRights, + Count +}; + +DEFINE_GAME_ACTION(LandBuyRightsAction, GAME_COMMAND_BUY_LAND_RIGHTS, GameActions::Result) +{ +private: + MapRange _range; + LandBuyRightSetting _setting{ LandBuyRightSetting::Count }; + + constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_BUY_LAND, STR_CANT_BUY_CONSTRUCTION_RIGHTS_HERE }; + +public: + LandBuyRightsAction() = default; + + LandBuyRightsAction(const MapRange& range, LandBuyRightSetting setting) + : _range(range) + , _setting(setting) + { + } + + LandBuyRightsAction(const CoordsXY& coord, LandBuyRightSetting setting) + : _range(coord.x, coord.y, coord.x, coord.y) + , _setting(setting) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; + GameActions::Result::Ptr map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LandBuyRightsAction.hpp b/src/openrct2/actions/LandBuyRightsAction.hpp deleted file mode 100644 index d6afbe25c6..0000000000 --- a/src/openrct2/actions/LandBuyRightsAction.hpp +++ /dev/null @@ -1,187 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../OpenRCT2.h" -#include "../actions/LandSetHeightAction.hpp" -#include "../audio/audio.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../util/Util.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -enum class LandBuyRightSetting : uint8_t -{ - BuyLand, - BuyConstructionRights, - Count -}; - -DEFINE_GAME_ACTION(LandBuyRightsAction, GAME_COMMAND_BUY_LAND_RIGHTS, GameActions::Result) -{ -private: - MapRange _range; - LandBuyRightSetting _setting{ LandBuyRightSetting::Count }; - - constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_BUY_LAND, STR_CANT_BUY_CONSTRUCTION_RIGHTS_HERE }; - -public: - LandBuyRightsAction() = default; - - LandBuyRightsAction(const MapRange& range, LandBuyRightSetting setting) - : _range(range) - , _setting(setting) - { - } - - LandBuyRightsAction(const CoordsXY& coord, LandBuyRightSetting setting) - : _range(coord.x, coord.y, coord.x, coord.y) - , _setting(setting) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range) << DS_TAG(_setting); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - MapRange normRange = _range.Normalise(); - // Keep big coordinates within map boundaries - auto aX = std::max(32, normRange.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, normRange.GetRight()); - auto aY = std::max(32, normRange.GetTop()); - auto bY = std::min(gMapSizeMaxXY, normRange.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - CoordsXYZ centre{ (validRange.GetLeft() + validRange.GetRight()) / 2 + 16, - (validRange.GetTop() + validRange.GetBottom()) / 2 + 16, 0 }; - centre.z = tile_element_height(centre); - - res->Position = centre; - res->Expenditure = ExpenditureType::LandPurchase; - - // Game command modified to accept selection size - for (auto y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (auto x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - auto result = map_buy_land_rights_for_tile({ x, y }, isExecuting); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - } - } - } - if (isExecuting) - { - map_count_remaining_land_rights(); - } - return res; - } - - GameActions::Result::Ptr map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const - { - if (_setting >= LandBuyRightSetting::Count) - { - log_warning("Tried calling buy land rights with an incorrect setting. setting = %u", _setting); - return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[0], STR_NONE); - } - - SurfaceElement* surfaceElement = map_get_surface_element_at(loc); - if (surfaceElement == nullptr) - { - log_error("Could not find surface. x = %d, y = %d", loc.x, loc.y); - return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[EnumValue(_setting)], STR_NONE); - } - - auto res = MakeResult(); - switch (_setting) - { - case LandBuyRightSetting::BuyLand: // 0 - if ((surfaceElement->GetOwnership() & OWNERSHIP_OWNED) != 0) - { // If the land is already owned - return res; - } - - if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 - || (surfaceElement->GetOwnership() & OWNERSHIP_AVAILABLE) == 0) - { - return MakeResult(GameActions::Status::NotOwned, _ErrorTitles[EnumValue(_setting)], STR_LAND_NOT_FOR_SALE); - } - if (isExecuting) - { - surfaceElement->SetOwnership(OWNERSHIP_OWNED); - update_park_fences_around_tile(loc); - } - res->Cost = gLandPrice; - return res; - - case LandBuyRightSetting::BuyConstructionRights: // 2 - if ((surfaceElement->GetOwnership() & (OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)) != 0) - { // If the land or construction rights are already owned - return res; - } - - if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 - || (surfaceElement->GetOwnership() & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) == 0) - { - return MakeResult( - GameActions::Status::NotOwned, _ErrorTitles[EnumValue(_setting)], STR_CONSTRUCTION_RIGHTS_NOT_FOR_SALE); - } - - if (isExecuting) - { - surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED); - uint16_t baseZ = surfaceElement->GetBaseZ(); - map_invalidate_tile({ loc, baseZ, baseZ + 16 }); - } - res->Cost = gConstructionRightsPrice; - return res; - - default: - log_warning("Tried calling buy land rights with an incorrect setting. setting = %u", _setting); - return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[0], STR_NONE); - } - } -}; diff --git a/src/openrct2/actions/LandLowerAction.cpp b/src/openrct2/actions/LandLowerAction.cpp new file mode 100644 index 0000000000..44bdbcf0ff --- /dev/null +++ b/src/openrct2/actions/LandLowerAction.cpp @@ -0,0 +1,136 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "LandLowerAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandSetHeightAction.h" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandLowerAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType); +} + +GameActions::Result::Ptr LandLowerAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr LandLowerAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr LandLowerAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + size_t tableRow = _selectionType; + + // The selections between MAP_SELECT_TYPE_FULL and MAP_SELECT_TYPE_EDGE_0 are not included in the tables + if (_selectionType >= MAP_SELECT_TYPE_EDGE_0 && _selectionType <= MAP_SELECT_TYPE_EDGE_3) + tableRow -= MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1; + + // Keep big coordinates within map boundaries + auto aX = std::max(32, _range.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); + auto aY = std::max(32, _range.GetTop()); + auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + res->Position = { _coords.x, _coords.y, tile_element_height(_coords) }; + res->Expenditure = ExpenditureType::Landscaping; + + if (isExecuting) + { + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, tile_element_height(_coords) }); + } + + uint8_t maxHeight = map_get_highest_land_height(validRange); + bool withinOwnership = false; + + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + withinOwnership = true; + + uint8_t height = surfaceElement->base_height; + if (surfaceElement->GetSlope() & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) + height += 2; + if (surfaceElement->GetSlope() & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) + height += 2; + + if (height < maxHeight) + continue; + + height = surfaceElement->base_height; + uint8_t currentSlope = surfaceElement->GetSlope(); + uint8_t newSlope = tile_element_lower_styles[tableRow][currentSlope]; + if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + height -= 2; + + newSlope &= TILE_ELEMENT_SURFACE_SLOPE_MASK; + + auto landSetHeightAction = LandSetHeightAction({ x, y }, height, newSlope); + landSetHeightAction.SetFlags(GetFlags()); + auto result = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) + : GameActions::QueryNested(&landSetHeightAction); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + } + else + { + result->ErrorTitle = STR_CANT_LOWER_LAND_HERE; + return result; + } + } + } + + if (!withinOwnership) + { + GameActions::Result::Ptr ownerShipResult = std::make_unique( + GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + ownerShipResult->ErrorTitle = STR_CANT_LOWER_LAND_HERE; + return ownerShipResult; + } + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + return res; +} diff --git a/src/openrct2/actions/LandLowerAction.h b/src/openrct2/actions/LandLowerAction.h new file mode 100644 index 0000000000..27a487b7ef --- /dev/null +++ b/src/openrct2/actions/LandLowerAction.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(LandLowerAction, GAME_COMMAND_LOWER_LAND, GameActions::Result) +{ +private: + CoordsXY _coords; + MapRange _range; + uint8_t _selectionType{}; + +public: + LandLowerAction() = default; + LandLowerAction(const CoordsXY& coords, MapRange range, uint8_t selectionType) + : _coords(coords) + , _range(range) + , _selectionType(selectionType) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LandLowerAction.hpp b/src/openrct2/actions/LandLowerAction.hpp deleted file mode 100644 index fbe53edbad..0000000000 --- a/src/openrct2/actions/LandLowerAction.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../OpenRCT2.h" -#include "../actions/LandSetHeightAction.hpp" -#include "../audio/audio.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LandLowerAction, GAME_COMMAND_LOWER_LAND, GameActions::Result) -{ -private: - CoordsXY _coords; - MapRange _range; - uint8_t _selectionType{}; - -public: - LandLowerAction() = default; - LandLowerAction(const CoordsXY& coords, MapRange range, uint8_t selectionType) - : _coords(coords) - , _range(range) - , _selectionType(selectionType) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - size_t tableRow = _selectionType; - - // The selections between MAP_SELECT_TYPE_FULL and MAP_SELECT_TYPE_EDGE_0 are not included in the tables - if (_selectionType >= MAP_SELECT_TYPE_EDGE_0 && _selectionType <= MAP_SELECT_TYPE_EDGE_3) - tableRow -= MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1; - - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - res->Position = { _coords.x, _coords.y, tile_element_height(_coords) }; - res->Expenditure = ExpenditureType::Landscaping; - - if (isExecuting) - { - OpenRCT2::Audio::Play3D( - OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, tile_element_height(_coords) }); - } - - uint8_t maxHeight = map_get_highest_land_height(validRange); - bool withinOwnership = false; - - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - withinOwnership = true; - - uint8_t height = surfaceElement->base_height; - if (surfaceElement->GetSlope() & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) - height += 2; - if (surfaceElement->GetSlope() & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) - height += 2; - - if (height < maxHeight) - continue; - - height = surfaceElement->base_height; - uint8_t currentSlope = surfaceElement->GetSlope(); - uint8_t newSlope = tile_element_lower_styles[tableRow][currentSlope]; - if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - height -= 2; - - newSlope &= TILE_ELEMENT_SURFACE_SLOPE_MASK; - - auto landSetHeightAction = LandSetHeightAction({ x, y }, height, newSlope); - landSetHeightAction.SetFlags(GetFlags()); - auto result = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - } - else - { - result->ErrorTitle = STR_CANT_LOWER_LAND_HERE; - return result; - } - } - } - - if (!withinOwnership) - { - GameActions::Result::Ptr ownerShipResult = std::make_unique( - GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - ownerShipResult->ErrorTitle = STR_CANT_LOWER_LAND_HERE; - return ownerShipResult; - } - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - return res; - } -}; diff --git a/src/openrct2/actions/LandRaiseAction.cpp b/src/openrct2/actions/LandRaiseAction.cpp new file mode 100644 index 0000000000..05ec2046c6 --- /dev/null +++ b/src/openrct2/actions/LandRaiseAction.cpp @@ -0,0 +1,132 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "LandRaiseAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandSetHeightAction.h" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandRaiseAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType); +} + +GameActions::Result::Ptr LandRaiseAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr LandRaiseAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr LandRaiseAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + size_t tableRow = _selectionType; + + // The selections between MAP_SELECT_TYPE_FULL and MAP_SELECT_TYPE_EDGE_0 are not included in the tables + if (_selectionType >= MAP_SELECT_TYPE_EDGE_0 && _selectionType <= MAP_SELECT_TYPE_EDGE_3) + tableRow -= MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1; + + // Keep big coordinates within map boundaries + auto aX = std::max(32, _range.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); + auto aY = std::max(32, _range.GetTop()); + auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + res->Position = { _coords.x, _coords.y, tile_element_height(_coords) }; + res->Expenditure = ExpenditureType::Landscaping; + + if (isExecuting) + { + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, tile_element_height(_coords) }); + } + + uint8_t minHeight = map_get_lowest_land_height(validRange); + bool withinOwnership = false; + + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + withinOwnership = true; + + uint8_t height = surfaceElement->base_height; + + if (height > minHeight) + continue; + + uint8_t currentSlope = surfaceElement->GetSlope(); + uint8_t newSlope = tile_element_raise_styles[tableRow][currentSlope]; + if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + height += 2; + + newSlope &= TILE_ELEMENT_SURFACE_SLOPE_MASK; + + auto landSetHeightAction = LandSetHeightAction({ x, y }, height, newSlope); + landSetHeightAction.SetFlags(GetFlags()); + auto result = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) + : GameActions::QueryNested(&landSetHeightAction); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + } + else + { + result->ErrorTitle = STR_CANT_RAISE_LAND_HERE; + return result; + } + } + } + + if (!withinOwnership) + { + GameActions::Result::Ptr ownerShipResult = std::make_unique( + GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + ownerShipResult->ErrorTitle = STR_CANT_RAISE_LAND_HERE; + return ownerShipResult; + } + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + return res; +} diff --git a/src/openrct2/actions/LandRaiseAction.h b/src/openrct2/actions/LandRaiseAction.h new file mode 100644 index 0000000000..6fd05c9169 --- /dev/null +++ b/src/openrct2/actions/LandRaiseAction.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(LandRaiseAction, GAME_COMMAND_RAISE_LAND, GameActions::Result) +{ +private: + CoordsXY _coords; + MapRange _range; + uint8_t _selectionType{}; + +public: + LandRaiseAction() = default; + LandRaiseAction(const CoordsXY& coords, MapRange range, uint8_t selectionType) + : _coords(coords) + , _range(range) + , _selectionType(selectionType) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LandRaiseAction.hpp b/src/openrct2/actions/LandRaiseAction.hpp deleted file mode 100644 index ebf293cd17..0000000000 --- a/src/openrct2/actions/LandRaiseAction.hpp +++ /dev/null @@ -1,157 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../OpenRCT2.h" -#include "../actions/LandSetHeightAction.hpp" -#include "../audio/audio.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LandRaiseAction, GAME_COMMAND_RAISE_LAND, GameActions::Result) -{ -private: - CoordsXY _coords; - MapRange _range; - uint8_t _selectionType{}; - -public: - LandRaiseAction() = default; - LandRaiseAction(const CoordsXY& coords, MapRange range, uint8_t selectionType) - : _coords(coords) - , _range(range) - , _selectionType(selectionType) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - size_t tableRow = _selectionType; - - // The selections between MAP_SELECT_TYPE_FULL and MAP_SELECT_TYPE_EDGE_0 are not included in the tables - if (_selectionType >= MAP_SELECT_TYPE_EDGE_0 && _selectionType <= MAP_SELECT_TYPE_EDGE_3) - tableRow -= MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1; - - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - res->Position = { _coords.x, _coords.y, tile_element_height(_coords) }; - res->Expenditure = ExpenditureType::Landscaping; - - if (isExecuting) - { - OpenRCT2::Audio::Play3D( - OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, tile_element_height(_coords) }); - } - - uint8_t minHeight = map_get_lowest_land_height(validRange); - bool withinOwnership = false; - - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - withinOwnership = true; - - uint8_t height = surfaceElement->base_height; - - if (height > minHeight) - continue; - - uint8_t currentSlope = surfaceElement->GetSlope(); - uint8_t newSlope = tile_element_raise_styles[tableRow][currentSlope]; - if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - height += 2; - - newSlope &= TILE_ELEMENT_SURFACE_SLOPE_MASK; - - auto landSetHeightAction = LandSetHeightAction({ x, y }, height, newSlope); - landSetHeightAction.SetFlags(GetFlags()); - auto result = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - } - else - { - result->ErrorTitle = STR_CANT_RAISE_LAND_HERE; - return result; - } - } - } - - if (!withinOwnership) - { - GameActions::Result::Ptr ownerShipResult = std::make_unique( - GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - ownerShipResult->ErrorTitle = STR_CANT_RAISE_LAND_HERE; - return ownerShipResult; - } - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - return res; - } -}; diff --git a/src/openrct2/actions/LandSetHeightAction.cpp b/src/openrct2/actions/LandSetHeightAction.cpp new file mode 100644 index 0000000000..4ffc5f77cf --- /dev/null +++ b/src/openrct2/actions/LandSetHeightAction.cpp @@ -0,0 +1,374 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "LandSetHeightAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/SmallScenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandSetHeightAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_height) << DS_TAG(_style); +} + +GameActions::Result::Ptr LandSetHeightAction::Query() const +{ + if (gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) + { + return std::make_unique(GameActions::Status::Disallowed, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); + } + + rct_string_id errorTitle = CheckParameters(); + if (errorTitle != STR_NONE) + { + return std::make_unique(GameActions::Status::Disallowed, errorTitle); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(_coords)) + { + return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + money32 sceneryRemovalCost = 0; + if (!gCheatsDisableClearanceChecks) + { + if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) + { + // Check for obstructing large trees + TileElement* tileElement = CheckTreeObstructions(); + if (tileElement != nullptr) + { + auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); + map_obstruction_set_error_text(tileElement, *res); + return res; + } + } + sceneryRemovalCost = GetSmallSceneryRemovalCost(); + } + + // Check for ride support limits + if (!gCheatsDisableSupportLimits) + { + errorTitle = CheckRideSupports(); + if (errorTitle != STR_NONE) + { + return std::make_unique(GameActions::Status::Disallowed, errorTitle); + } + } + + auto* surfaceElement = map_get_surface_element_at(_coords); + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + // We need to check if there is _currently_ a level crossing on the tile. + // For that, we need the old height, so we can't use the _height variable. + auto oldCoords = CoordsXYZ{ _coords, surfaceElement->GetBaseZ() }; + auto* pathElement = map_get_footpath_element(oldCoords); + if (pathElement != nullptr && pathElement->AsPath()->IsLevelCrossing(oldCoords)) + { + return MakeResult(GameActions::Status::Disallowed, STR_REMOVE_LEVEL_CROSSING_FIRST); + } + + TileElement* tileElement = CheckFloatingStructures(reinterpret_cast(surfaceElement), _height); + if (tileElement != nullptr) + { + auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); + map_obstruction_set_error_text(tileElement, *res); + return res; + } + + if (!gCheatsDisableClearanceChecks) + { + uint8_t zCorner = _height; + if (_style & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) + { + zCorner += 2; + if (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) + { + zCorner += 2; + } + } + + auto clearResult = MapCanConstructWithClearAt( + { _coords, _height * COORDS_Z_STEP, zCorner * COORDS_Z_STEP }, &map_set_land_height_clear_func, { 0b1111, 0 }, 0, + CREATE_CROSSING_MODE_NONE); + if (clearResult->Error != GameActions::Status::Ok) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_NONE, clearResult->ErrorMessage.GetStringId(), + clearResult->ErrorMessageArgs.data()); + } + + tileElement = CheckUnremovableObstructions(reinterpret_cast(surfaceElement), zCorner); + if (tileElement != nullptr) + { + auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); + map_obstruction_set_error_text(tileElement, *res); + return res; + } + } + auto res = std::make_unique(); + res->Cost = sceneryRemovalCost + GetSurfaceHeightChangeCost(surfaceElement); + res->Expenditure = ExpenditureType::Landscaping; + return res; +} + +GameActions::Result::Ptr LandSetHeightAction::Execute() const +{ + money32 cost = MONEY(0, 0); + auto surfaceHeight = tile_element_height(_coords); + footpath_remove_litter({ _coords, surfaceHeight }); + + if (!gCheatsDisableClearanceChecks) + { + wall_remove_at({ _coords, _height * 8 - 16, _height * 8 + 32 }); + cost += GetSmallSceneryRemovalCost(); + SmallSceneryRemoval(); + } + + auto* surfaceElement = map_get_surface_element_at(_coords); + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + cost += GetSurfaceHeightChangeCost(surfaceElement); + SetSurfaceHeight(reinterpret_cast(surfaceElement)); + + auto res = std::make_unique(); + res->Position = { _coords.x + 16, _coords.y + 16, surfaceHeight }; + res->Cost = cost; + res->Expenditure = ExpenditureType::Landscaping; + return res; +} + +rct_string_id LandSetHeightAction::CheckParameters() const +{ + if (!LocationValid(_coords)) + { + return STR_OFF_EDGE_OF_MAP; + } + + if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY) + { + return STR_OFF_EDGE_OF_MAP; + } + + if (_height < MINIMUM_LAND_HEIGHT) + { + return STR_TOO_LOW; + } + + // Divide by 2 and subtract 7 to get the in-game units. + if (_height > MAXIMUM_LAND_HEIGHT) + { + return STR_TOO_HIGH; + } + else if (_height > MAXIMUM_LAND_HEIGHT - 2 && (_style & TILE_ELEMENT_SURFACE_SLOPE_MASK) != 0) + { + return STR_TOO_HIGH; + } + + if (_height == MAXIMUM_LAND_HEIGHT - 2 && (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG)) + { + return STR_TOO_HIGH; + } + + return STR_NONE; +} + +TileElement* LandSetHeightAction::CheckTreeObstructions() const +{ + TileElement* tileElement = map_get_first_element_at(_coords); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) + continue; + if (_height > tileElement->clearance_height) + continue; + if (_height + 4 < tileElement->base_height) + continue; + rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry(); + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_IS_TREE)) + { + return tileElement; + } + } while (!(tileElement++)->IsLastForTile()); + return nullptr; +} + +money32 LandSetHeightAction::GetSmallSceneryRemovalCost() const +{ + money32 cost{ 0 }; + TileElement* tileElement = map_get_first_element_at(_coords); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) + continue; + if (_height > tileElement->clearance_height) + continue; + if (_height + 4 < tileElement->base_height) + continue; + rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry(); + cost += MONEY(sceneryEntry->small_scenery.removal_price, 0); + } while (!(tileElement++)->IsLastForTile()); + return cost; +} + +void LandSetHeightAction::SmallSceneryRemoval() const +{ + TileElement* tileElement = map_get_first_element_at(_coords); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) + continue; + if (_height > tileElement->clearance_height) + continue; + if (_height + 4 < tileElement->base_height) + continue; + tile_element_remove(tileElement--); + } while (!(tileElement++)->IsLastForTile()); +} + +rct_string_id LandSetHeightAction::CheckRideSupports() const +{ + TileElement* tileElement = map_get_first_element_at(_coords); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK) + { + ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); + auto ride = get_ride(rideIndex); + if (ride != nullptr) + { + rct_ride_entry* rideEntry = ride->GetRideEntry(); + if (rideEntry != nullptr) + { + int32_t maxHeight = rideEntry->max_height; + if (maxHeight == 0) + { + maxHeight = RideTypeDescriptors[ride->type].Heights.MaxHeight; + } + int32_t zDelta = tileElement->clearance_height - _height; + if (zDelta >= 0 && zDelta / 2 > maxHeight) + { + return STR_SUPPORTS_CANT_BE_EXTENDED; + } + } + } + } + } while (!(tileElement++)->IsLastForTile()); + return STR_NONE; +} + +TileElement* LandSetHeightAction::CheckFloatingStructures(TileElement* surfaceElement, uint8_t zCorner) const +{ + if (surfaceElement->AsSurface()->HasTrackThatNeedsWater()) + { + uint32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight(); + if (waterHeight != 0) + { + if (_style & TILE_ELEMENT_SURFACE_SLOPE_MASK) + { + zCorner += 2; + if (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) + { + zCorner += 2; + } + } + if (zCorner > (waterHeight / COORDS_Z_STEP) - 2) + { + return ++surfaceElement; + } + } + } + return nullptr; +} + +TileElement* LandSetHeightAction::CheckUnremovableObstructions(TileElement* surfaceElement, uint8_t zCorner) const +{ + TileElement* tileElement = map_get_first_element_at(_coords); + do + { + if (tileElement == nullptr) + break; + int32_t elementType = tileElement->GetType(); + + // Wall's and Small Scenery are removed and therefore do not need checked + if (elementType == TILE_ELEMENT_TYPE_WALL) + continue; + if (elementType == TILE_ELEMENT_TYPE_SMALL_SCENERY) + continue; + if (tileElement->IsGhost()) + continue; + if (tileElement == surfaceElement) + continue; + if (tileElement > surfaceElement) + { + if (zCorner > tileElement->base_height) + { + return tileElement; + } + continue; + } + if (_height < tileElement->clearance_height) + { + return tileElement; + } + } while (!(tileElement++)->IsLastForTile()); + return nullptr; +} + +money32 LandSetHeightAction::GetSurfaceHeightChangeCost(SurfaceElement* surfaceElement) const +{ + money32 cost{ 0 }; + for (Direction i : ALL_DIRECTIONS) + { + int32_t cornerHeight = tile_element_get_corner_height(surfaceElement, i); + cornerHeight -= map_get_corner_height(_height, _style & TILE_ELEMENT_SURFACE_SLOPE_MASK, i); + cost += MONEY(abs(cornerHeight) * 5 / 2, 0); + } + return cost; +} + +void LandSetHeightAction::SetSurfaceHeight(TileElement* surfaceElement) const +{ + surfaceElement->base_height = _height; + surfaceElement->clearance_height = _height; + surfaceElement->AsSurface()->SetSlope(_style); + int32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight() / COORDS_Z_STEP; + if (waterHeight != 0 && waterHeight <= _height) + { + surfaceElement->AsSurface()->SetWaterHeight(0); + } + + map_invalidate_tile_full(_coords); +} diff --git a/src/openrct2/actions/LandSetHeightAction.h b/src/openrct2/actions/LandSetHeightAction.h new file mode 100644 index 0000000000..2e30e48aa8 --- /dev/null +++ b/src/openrct2/actions/LandSetHeightAction.h @@ -0,0 +1,66 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(LandSetHeightAction, GAME_COMMAND_SET_LAND_HEIGHT, GameActions::Result) +{ +private: + CoordsXY _coords; + uint8_t _height{}; + uint8_t _style{}; + +public: + LandSetHeightAction() = default; + LandSetHeightAction(const CoordsXY& coords, uint8_t height, uint8_t style) + : _coords(coords) + , _height(height) + , _style(style) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + rct_string_id CheckParameters() const; + TileElement* CheckTreeObstructions() const; + money32 GetSmallSceneryRemovalCost() const; + void SmallSceneryRemoval() const; + rct_string_id CheckRideSupports() const; + TileElement* CheckFloatingStructures(TileElement * surfaceElement, uint8_t zCorner) const; + TileElement* CheckUnremovableObstructions(TileElement * surfaceElement, uint8_t zCorner) const; + money32 GetSurfaceHeightChangeCost(SurfaceElement * surfaceElement) const; + void SetSurfaceHeight(TileElement * surfaceElement) const; + + /** + * + * rct2: 0x00663CB9 + */ + static int32_t map_set_land_height_clear_func( + TileElement * *tile_element, [[maybe_unused]] const CoordsXY& coords, [[maybe_unused]] uint8_t flags, + [[maybe_unused]] money32* price) + { + if ((*tile_element)->GetType() == TILE_ELEMENT_TYPE_SURFACE) + return 0; + + if ((*tile_element)->GetType() == TILE_ELEMENT_TYPE_SMALL_SCENERY) + return 0; + + return 1; + } +}; diff --git a/src/openrct2/actions/LandSetHeightAction.hpp b/src/openrct2/actions/LandSetHeightAction.hpp deleted file mode 100644 index bee949649e..0000000000 --- a/src/openrct2/actions/LandSetHeightAction.hpp +++ /dev/null @@ -1,415 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../OpenRCT2.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/SmallScenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LandSetHeightAction, GAME_COMMAND_SET_LAND_HEIGHT, GameActions::Result) -{ -private: - CoordsXY _coords; - uint8_t _height{}; - uint8_t _style{}; - -public: - LandSetHeightAction() = default; - LandSetHeightAction(const CoordsXY& coords, uint8_t height, uint8_t style) - : _coords(coords) - , _height(height) - , _style(style) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_coords) << DS_TAG(_height) << DS_TAG(_style); - } - - GameActions::Result::Ptr Query() const override - { - if (gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) - { - return std::make_unique(GameActions::Status::Disallowed, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); - } - - rct_string_id errorTitle = CheckParameters(); - if (errorTitle != STR_NONE) - { - return std::make_unique(GameActions::Status::Disallowed, errorTitle); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(_coords)) - { - return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - money32 sceneryRemovalCost = 0; - if (!gCheatsDisableClearanceChecks) - { - if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) - { - // Check for obstructing large trees - TileElement* tileElement = CheckTreeObstructions(); - if (tileElement != nullptr) - { - auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); - map_obstruction_set_error_text(tileElement, *res); - return res; - } - } - sceneryRemovalCost = GetSmallSceneryRemovalCost(); - } - - // Check for ride support limits - if (!gCheatsDisableSupportLimits) - { - errorTitle = CheckRideSupports(); - if (errorTitle != STR_NONE) - { - return std::make_unique(GameActions::Status::Disallowed, errorTitle); - } - } - - auto* surfaceElement = map_get_surface_element_at(_coords); - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - // We need to check if there is _currently_ a level crossing on the tile. - // For that, we need the old height, so we can't use the _height variable. - auto oldCoords = CoordsXYZ{ _coords, surfaceElement->GetBaseZ() }; - auto* pathElement = map_get_footpath_element(oldCoords); - if (pathElement != nullptr && pathElement->AsPath()->IsLevelCrossing(oldCoords)) - { - return MakeResult(GameActions::Status::Disallowed, STR_REMOVE_LEVEL_CROSSING_FIRST); - } - - TileElement* tileElement = CheckFloatingStructures(reinterpret_cast(surfaceElement), _height); - if (tileElement != nullptr) - { - auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); - map_obstruction_set_error_text(tileElement, *res); - return res; - } - - if (!gCheatsDisableClearanceChecks) - { - uint8_t zCorner = _height; - if (_style & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) - { - zCorner += 2; - if (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) - { - zCorner += 2; - } - } - - auto clearResult = MapCanConstructWithClearAt( - { _coords, _height * COORDS_Z_STEP, zCorner * COORDS_Z_STEP }, &map_set_land_height_clear_func, { 0b1111, 0 }, - 0, CREATE_CROSSING_MODE_NONE); - if (clearResult->Error != GameActions::Status::Ok) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_NONE, clearResult->ErrorMessage.GetStringId(), - clearResult->ErrorMessageArgs.data()); - } - - tileElement = CheckUnremovableObstructions(reinterpret_cast(surfaceElement), zCorner); - if (tileElement != nullptr) - { - auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); - map_obstruction_set_error_text(tileElement, *res); - return res; - } - } - auto res = std::make_unique(); - res->Cost = sceneryRemovalCost + GetSurfaceHeightChangeCost(surfaceElement); - res->Expenditure = ExpenditureType::Landscaping; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - money32 cost = MONEY(0, 0); - auto surfaceHeight = tile_element_height(_coords); - footpath_remove_litter({ _coords, surfaceHeight }); - - if (!gCheatsDisableClearanceChecks) - { - wall_remove_at({ _coords, _height * 8 - 16, _height * 8 + 32 }); - cost += GetSmallSceneryRemovalCost(); - SmallSceneryRemoval(); - } - - auto* surfaceElement = map_get_surface_element_at(_coords); - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - cost += GetSurfaceHeightChangeCost(surfaceElement); - SetSurfaceHeight(reinterpret_cast(surfaceElement)); - - auto res = std::make_unique(); - res->Position = { _coords.x + 16, _coords.y + 16, surfaceHeight }; - res->Cost = cost; - res->Expenditure = ExpenditureType::Landscaping; - return res; - } - -private: - rct_string_id CheckParameters() const - { - if (!LocationValid(_coords)) - { - return STR_OFF_EDGE_OF_MAP; - } - - if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY) - { - return STR_OFF_EDGE_OF_MAP; - } - - if (_height < MINIMUM_LAND_HEIGHT) - { - return STR_TOO_LOW; - } - - // Divide by 2 and subtract 7 to get the in-game units. - if (_height > MAXIMUM_LAND_HEIGHT) - { - return STR_TOO_HIGH; - } - else if (_height > MAXIMUM_LAND_HEIGHT - 2 && (_style & TILE_ELEMENT_SURFACE_SLOPE_MASK) != 0) - { - return STR_TOO_HIGH; - } - - if (_height == MAXIMUM_LAND_HEIGHT - 2 && (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG)) - { - return STR_TOO_HIGH; - } - - return STR_NONE; - } - - TileElement* CheckTreeObstructions() const - { - TileElement* tileElement = map_get_first_element_at(_coords); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - continue; - if (_height > tileElement->clearance_height) - continue; - if (_height + 4 < tileElement->base_height) - continue; - rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry(); - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_IS_TREE)) - { - return tileElement; - } - } while (!(tileElement++)->IsLastForTile()); - return nullptr; - } - - money32 GetSmallSceneryRemovalCost() const - { - money32 cost{ 0 }; - TileElement* tileElement = map_get_first_element_at(_coords); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - continue; - if (_height > tileElement->clearance_height) - continue; - if (_height + 4 < tileElement->base_height) - continue; - rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry(); - cost += MONEY(sceneryEntry->small_scenery.removal_price, 0); - } while (!(tileElement++)->IsLastForTile()); - return cost; - } - - void SmallSceneryRemoval() const - { - TileElement* tileElement = map_get_first_element_at(_coords); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - continue; - if (_height > tileElement->clearance_height) - continue; - if (_height + 4 < tileElement->base_height) - continue; - tile_element_remove(tileElement--); - } while (!(tileElement++)->IsLastForTile()); - } - - rct_string_id CheckRideSupports() const - { - TileElement* tileElement = map_get_first_element_at(_coords); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK) - { - ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); - auto ride = get_ride(rideIndex); - if (ride != nullptr) - { - rct_ride_entry* rideEntry = ride->GetRideEntry(); - if (rideEntry != nullptr) - { - int32_t maxHeight = rideEntry->max_height; - if (maxHeight == 0) - { - maxHeight = RideTypeDescriptors[ride->type].Heights.MaxHeight; - } - int32_t zDelta = tileElement->clearance_height - _height; - if (zDelta >= 0 && zDelta / 2 > maxHeight) - { - return STR_SUPPORTS_CANT_BE_EXTENDED; - } - } - } - } - } while (!(tileElement++)->IsLastForTile()); - return STR_NONE; - } - - TileElement* CheckFloatingStructures(TileElement * surfaceElement, uint8_t zCorner) const - { - if (surfaceElement->AsSurface()->HasTrackThatNeedsWater()) - { - uint32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight(); - if (waterHeight != 0) - { - if (_style & TILE_ELEMENT_SURFACE_SLOPE_MASK) - { - zCorner += 2; - if (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) - { - zCorner += 2; - } - } - if (zCorner > (waterHeight / COORDS_Z_STEP) - 2) - { - return ++surfaceElement; - } - } - } - return nullptr; - } - - TileElement* CheckUnremovableObstructions(TileElement * surfaceElement, uint8_t zCorner) const - { - TileElement* tileElement = map_get_first_element_at(_coords); - do - { - if (tileElement == nullptr) - break; - int32_t elementType = tileElement->GetType(); - - // Wall's and Small Scenery are removed and therefore do not need checked - if (elementType == TILE_ELEMENT_TYPE_WALL) - continue; - if (elementType == TILE_ELEMENT_TYPE_SMALL_SCENERY) - continue; - if (tileElement->IsGhost()) - continue; - if (tileElement == surfaceElement) - continue; - if (tileElement > surfaceElement) - { - if (zCorner > tileElement->base_height) - { - return tileElement; - } - continue; - } - if (_height < tileElement->clearance_height) - { - return tileElement; - } - } while (!(tileElement++)->IsLastForTile()); - return nullptr; - } - - money32 GetSurfaceHeightChangeCost(SurfaceElement * surfaceElement) const - { - money32 cost{ 0 }; - for (Direction i : ALL_DIRECTIONS) - { - int32_t cornerHeight = tile_element_get_corner_height(surfaceElement, i); - cornerHeight -= map_get_corner_height(_height, _style & TILE_ELEMENT_SURFACE_SLOPE_MASK, i); - cost += MONEY(abs(cornerHeight) * 5 / 2, 0); - } - return cost; - } - - void SetSurfaceHeight(TileElement * surfaceElement) const - { - surfaceElement->base_height = _height; - surfaceElement->clearance_height = _height; - surfaceElement->AsSurface()->SetSlope(_style); - int32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight() / COORDS_Z_STEP; - if (waterHeight != 0 && waterHeight <= _height) - { - surfaceElement->AsSurface()->SetWaterHeight(0); - } - - map_invalidate_tile_full(_coords); - } - - /** - * - * rct2: 0x00663CB9 - */ - static int32_t map_set_land_height_clear_func( - TileElement * *tile_element, [[maybe_unused]] const CoordsXY& coords, [[maybe_unused]] uint8_t flags, - [[maybe_unused]] money32* price) - { - if ((*tile_element)->GetType() == TILE_ELEMENT_TYPE_SURFACE) - return 0; - - if ((*tile_element)->GetType() == TILE_ELEMENT_TYPE_SMALL_SCENERY) - return 0; - - return 1; - } -}; diff --git a/src/openrct2/actions/LandSetRightsAction.cpp b/src/openrct2/actions/LandSetRightsAction.cpp new file mode 100644 index 0000000000..57df0615f2 --- /dev/null +++ b/src/openrct2/actions/LandSetRightsAction.cpp @@ -0,0 +1,193 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "LandSetRightsAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandSetHeightAction.h" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../util/Util.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandSetRightsAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range) << DS_TAG(_setting) << DS_TAG(_ownership); +} + +GameActions::Result::Ptr LandSetRightsAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr LandSetRightsAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr LandSetRightsAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + + MapRange normRange = _range.Normalise(); + // Keep big coordinates within map boundaries + auto aX = std::max(32, normRange.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, normRange.GetRight()); + auto aY = std::max(32, normRange.GetTop()); + auto bY = std::min(gMapSizeMaxXY, normRange.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + CoordsXYZ centre{ (validRange.GetLeft() + validRange.GetRight()) / 2 + 16, + (validRange.GetTop() + validRange.GetBottom()) / 2 + 16, 0 }; + centre.z = tile_element_height(centre); + + res->Position = centre; + res->Expenditure = ExpenditureType::LandPurchase; + + if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) + { + return MakeResult(GameActions::Status::NotInEditorMode, STR_NONE, STR_LAND_NOT_FOR_SALE); + } + + // Game command modified to accept selection size + for (auto y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (auto x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + auto result = map_buy_land_rights_for_tile({ x, y }, isExecuting); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + } + } + } + + if (isExecuting) + { + map_count_remaining_land_rights(); + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, centre); + } + return res; +} + +GameActions::Result::Ptr LandSetRightsAction::map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const +{ + SurfaceElement* surfaceElement = map_get_surface_element_at(loc); + if (surfaceElement == nullptr) + { + log_error("Could not find surface. x = %d, y = %d", loc.x, loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); + } + + auto res = MakeResult(); + switch (_setting) + { + case LandSetRightSetting::UnownLand: + if (isExecuting) + { + surfaceElement->SetOwnership( + surfaceElement->GetOwnership() & ~(OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)); + update_park_fences_around_tile(loc); + } + return res; + case LandSetRightSetting::UnownConstructionRights: + if (isExecuting) + { + surfaceElement->SetOwnership(surfaceElement->GetOwnership() & ~OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED); + uint16_t baseZ = surfaceElement->GetBaseZ(); + map_invalidate_tile({ loc, baseZ, baseZ + 16 }); + } + return res; + case LandSetRightSetting::SetForSale: + if (isExecuting) + { + surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_AVAILABLE); + uint16_t baseZ = surfaceElement->GetBaseZ(); + map_invalidate_tile({ loc, baseZ, baseZ + 16 }); + } + return res; + case LandSetRightSetting::SetConstructionRightsForSale: + if (isExecuting) + { + surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE); + uint16_t baseZ = surfaceElement->GetBaseZ(); + map_invalidate_tile({ loc, baseZ, baseZ + 16 }); + } + return res; + case LandSetRightSetting::SetOwnershipWithChecks: + { + if (_ownership == surfaceElement->GetOwnership()) + { + return res; + } + + TileElement* tileElement = map_get_first_element_at(loc); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() != ENTRANCE_TYPE_PARK_ENTRANCE) + continue; + + // Do not allow ownership of park entrance. + if (_ownership == OWNERSHIP_OWNED || _ownership == OWNERSHIP_AVAILABLE) + return res; + + // Allow construction rights available / for sale on park entrances on surface. + // There is no need to check the height if _ownership is 0 (unowned and no rights available). + if (_ownership == OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED || _ownership == OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) + { + if (tileElement->base_height - 3 > surfaceElement->base_height + || tileElement->base_height < surfaceElement->base_height) + return res; + } + } while (!(tileElement++)->IsLastForTile()); + + res->Cost = gLandPrice; + if (isExecuting) + { + if (_ownership != OWNERSHIP_UNOWNED) + { + gPeepSpawns.erase( + std::remove_if( + gPeepSpawns.begin(), gPeepSpawns.end(), + [x = loc.x, y = loc.y](const auto& spawn) { + return floor2(spawn.x, 32) == x && floor2(spawn.y, 32) == y; + }), + gPeepSpawns.end()); + } + surfaceElement->SetOwnership(_ownership); + update_park_fences_around_tile(loc); + gMapLandRightsUpdateSuccess = true; + } + return res; + } + default: + log_warning("Tried calling set land rights with an incorrect setting. setting = %u", _setting); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); + } +} diff --git a/src/openrct2/actions/LandSetRightsAction.h b/src/openrct2/actions/LandSetRightsAction.h new file mode 100644 index 0000000000..7cfd4c3c18 --- /dev/null +++ b/src/openrct2/actions/LandSetRightsAction.h @@ -0,0 +1,60 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +enum class LandSetRightSetting : uint8_t +{ + UnownLand, + UnownConstructionRights, + SetForSale, + SetConstructionRightsForSale, + SetOwnershipWithChecks, + Count +}; + +DEFINE_GAME_ACTION(LandSetRightsAction, GAME_COMMAND_SET_LAND_OWNERSHIP, GameActions::Result) +{ +private: + MapRange _range; + LandSetRightSetting _setting{ LandSetRightSetting::Count }; + uint8_t _ownership{}; + +public: + LandSetRightsAction() = default; + + LandSetRightsAction(const MapRange& range, LandSetRightSetting setting, uint8_t ownership = 0) + : _range(range) + , _setting(setting) + , _ownership(ownership) + { + } + + LandSetRightsAction(const CoordsXY& coord, LandSetRightSetting setting, uint8_t ownership = 0) + : _range(coord.x, coord.y, coord.x, coord.y) + , _setting(setting) + , _ownership(ownership) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; + GameActions::Result::Ptr map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LandSetRightsAction.hpp b/src/openrct2/actions/LandSetRightsAction.hpp deleted file mode 100644 index 1ffc5dfe40..0000000000 --- a/src/openrct2/actions/LandSetRightsAction.hpp +++ /dev/null @@ -1,236 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../OpenRCT2.h" -#include "../actions/LandSetHeightAction.hpp" -#include "../audio/audio.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../util/Util.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -enum class LandSetRightSetting : uint8_t -{ - UnownLand, - UnownConstructionRights, - SetForSale, - SetConstructionRightsForSale, - SetOwnershipWithChecks, - Count -}; - -DEFINE_GAME_ACTION(LandSetRightsAction, GAME_COMMAND_SET_LAND_OWNERSHIP, GameActions::Result) -{ -private: - MapRange _range; - LandSetRightSetting _setting{ LandSetRightSetting::Count }; - uint8_t _ownership{}; - -public: - LandSetRightsAction() = default; - - LandSetRightsAction(const MapRange& range, LandSetRightSetting setting, uint8_t ownership = 0) - : _range(range) - , _setting(setting) - , _ownership(ownership) - { - } - - LandSetRightsAction(const CoordsXY& coord, LandSetRightSetting setting, uint8_t ownership = 0) - : _range(coord.x, coord.y, coord.x, coord.y) - , _setting(setting) - , _ownership(ownership) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range) << DS_TAG(_setting) << DS_TAG(_ownership); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - MapRange normRange = _range.Normalise(); - // Keep big coordinates within map boundaries - auto aX = std::max(32, normRange.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, normRange.GetRight()); - auto aY = std::max(32, normRange.GetTop()); - auto bY = std::min(gMapSizeMaxXY, normRange.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - CoordsXYZ centre{ (validRange.GetLeft() + validRange.GetRight()) / 2 + 16, - (validRange.GetTop() + validRange.GetBottom()) / 2 + 16, 0 }; - centre.z = tile_element_height(centre); - - res->Position = centre; - res->Expenditure = ExpenditureType::LandPurchase; - - if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) - { - return MakeResult(GameActions::Status::NotInEditorMode, STR_NONE, STR_LAND_NOT_FOR_SALE); - } - - // Game command modified to accept selection size - for (auto y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (auto x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - auto result = map_buy_land_rights_for_tile({ x, y }, isExecuting); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - } - } - } - - if (isExecuting) - { - map_count_remaining_land_rights(); - OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, centre); - } - return res; - } - - GameActions::Result::Ptr map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const - { - SurfaceElement* surfaceElement = map_get_surface_element_at(loc); - if (surfaceElement == nullptr) - { - log_error("Could not find surface. x = %d, y = %d", loc.x, loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); - } - - auto res = MakeResult(); - switch (_setting) - { - case LandSetRightSetting::UnownLand: - if (isExecuting) - { - surfaceElement->SetOwnership( - surfaceElement->GetOwnership() & ~(OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)); - update_park_fences_around_tile(loc); - } - return res; - case LandSetRightSetting::UnownConstructionRights: - if (isExecuting) - { - surfaceElement->SetOwnership(surfaceElement->GetOwnership() & ~OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED); - uint16_t baseZ = surfaceElement->GetBaseZ(); - map_invalidate_tile({ loc, baseZ, baseZ + 16 }); - } - return res; - case LandSetRightSetting::SetForSale: - if (isExecuting) - { - surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_AVAILABLE); - uint16_t baseZ = surfaceElement->GetBaseZ(); - map_invalidate_tile({ loc, baseZ, baseZ + 16 }); - } - return res; - case LandSetRightSetting::SetConstructionRightsForSale: - if (isExecuting) - { - surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE); - uint16_t baseZ = surfaceElement->GetBaseZ(); - map_invalidate_tile({ loc, baseZ, baseZ + 16 }); - } - return res; - case LandSetRightSetting::SetOwnershipWithChecks: - { - if (_ownership == surfaceElement->GetOwnership()) - { - return res; - } - - TileElement* tileElement = map_get_first_element_at(loc); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() != ENTRANCE_TYPE_PARK_ENTRANCE) - continue; - - // Do not allow ownership of park entrance. - if (_ownership == OWNERSHIP_OWNED || _ownership == OWNERSHIP_AVAILABLE) - return res; - - // Allow construction rights available / for sale on park entrances on surface. - // There is no need to check the height if _ownership is 0 (unowned and no rights available). - if (_ownership == OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED - || _ownership == OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) - { - if (tileElement->base_height - 3 > surfaceElement->base_height - || tileElement->base_height < surfaceElement->base_height) - return res; - } - } while (!(tileElement++)->IsLastForTile()); - - res->Cost = gLandPrice; - if (isExecuting) - { - if (_ownership != OWNERSHIP_UNOWNED) - { - gPeepSpawns.erase( - std::remove_if( - gPeepSpawns.begin(), gPeepSpawns.end(), - [x = loc.x, y = loc.y](const auto& spawn) { - return floor2(spawn.x, 32) == x && floor2(spawn.y, 32) == y; - }), - gPeepSpawns.end()); - } - surfaceElement->SetOwnership(_ownership); - update_park_fences_around_tile(loc); - gMapLandRightsUpdateSuccess = true; - } - return res; - } - default: - log_warning("Tried calling set land rights with an incorrect setting. setting = %u", _setting); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); - } - } -}; diff --git a/src/openrct2/actions/LandSmoothAction.cpp b/src/openrct2/actions/LandSmoothAction.cpp new file mode 100644 index 0000000000..2299a7fb44 --- /dev/null +++ b/src/openrct2/actions/LandSmoothAction.cpp @@ -0,0 +1,635 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "LandSmoothAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandLowerAction.h" +#include "../actions/LandRaiseAction.h" +#include "../actions/LandSetHeightAction.h" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandSmoothAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType) << DS_TAG(_isLowering); +} + +GameActions::Result::Ptr LandSmoothAction::Query() const +{ + return SmoothLand(false); +} + +GameActions::Result::Ptr LandSmoothAction::Execute() const +{ + return SmoothLand(true); +} + +GameActions::Result::Ptr LandSmoothAction::SmoothLandTile( + int32_t direction, bool isExecuting, const CoordsXY& loc, SurfaceElement* surfaceElement) const +{ + int32_t targetBaseZ = surfaceElement->base_height; + int32_t slope = surfaceElement->GetSlope(); + if (_isLowering) + { + slope = tile_element_lower_styles[direction][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ -= 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + else + { + slope = tile_element_raise_styles[direction][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ += 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + + auto landSetHeightAction = LandSetHeightAction(loc, targetBaseZ, slope); + landSetHeightAction.SetFlags(GetFlags()); + auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) : GameActions::QueryNested(&landSetHeightAction); + + return res; +} + +money32 LandSmoothAction::SmoothLandRowByEdge( + bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight1, int32_t expectedLandHeight2, int32_t stepX, + int32_t stepY, int32_t direction1, int32_t direction2, int32_t checkDirection1, int32_t checkDirection2) const +{ + uint8_t shouldContinue = 0xF; + int32_t landChangePerTile = _isLowering ? 2 : -2; + money32 totalCost = 0; + + // check if we need to start at all + if (!LocationValid(loc) || !LocationValid({ loc.x + stepX, loc.y + stepY })) + { + return 0; + } + auto surfaceElement = map_get_surface_element_at(loc); + auto nextSurfaceElement = map_get_surface_element_at(CoordsXY{ loc.x + stepX, loc.y + stepY }); + if (surfaceElement == nullptr || nextSurfaceElement == nullptr) + { + return 0; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection1) != expectedLandHeight1 + landChangePerTile) + { + shouldContinue &= ~0x1; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection2) != expectedLandHeight2 + landChangePerTile) + { + shouldContinue &= ~0x2; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection1) + != tile_element_get_corner_height(nextSurfaceElement, direction1)) + { + shouldContinue &= ~0x1; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection2) + != tile_element_get_corner_height(nextSurfaceElement, direction2)) + { + shouldContinue &= ~0x2; + } + auto nextLoc = loc; + while ((shouldContinue & 0x3) != 0) + { + shouldContinue = ((shouldContinue << 2) | 0x3) & shouldContinue; + nextLoc.x += stepX; + nextLoc.y += stepY; + // check if we need to continue after raising the current tile + // this needs to be checked before the tile is changed + if (!LocationValid({ nextLoc.x + stepX, nextLoc.y + stepY })) + { + shouldContinue &= ~0x3; + } + else + { + surfaceElement = nextSurfaceElement; + nextSurfaceElement = map_get_surface_element_at(CoordsXY{ nextLoc.x + stepX, nextLoc.y + stepY }); + if (nextSurfaceElement == nullptr) + { + shouldContinue &= ~0x3; + } + if (tile_element_get_corner_height(surfaceElement, direction1) + landChangePerTile + != tile_element_get_corner_height(surfaceElement, checkDirection1)) + { + shouldContinue &= ~0x1; + } + if (tile_element_get_corner_height(surfaceElement, direction2) + landChangePerTile + != tile_element_get_corner_height(surfaceElement, checkDirection2)) + { + shouldContinue &= ~0x2; + } + if ((shouldContinue & 0x1) + && tile_element_get_corner_height(surfaceElement, checkDirection1) + != tile_element_get_corner_height(nextSurfaceElement, direction1)) + { + shouldContinue &= ~0x1; + } + if ((shouldContinue & 0x2) + && tile_element_get_corner_height(surfaceElement, checkDirection2) + != tile_element_get_corner_height(nextSurfaceElement, direction2)) + { + shouldContinue &= ~0x2; + } + } + expectedLandHeight1 += landChangePerTile; + + // change land of current tile + int32_t targetBaseZ = surfaceElement->base_height; + int32_t slope = surfaceElement->GetSlope(); + int32_t oldSlope = slope; + if (_isLowering) + { + if (shouldContinue & 0x4) + { + slope = tile_element_lower_styles[direction1][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ -= 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + if ((shouldContinue & 0x8) + && map_get_corner_height(surfaceElement->base_height, oldSlope, direction2) + == map_get_corner_height(targetBaseZ, slope, direction2)) + { + slope = tile_element_lower_styles[direction2][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ -= 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + } + else + { + if (shouldContinue & 0x4) + { + slope = tile_element_raise_styles[direction1][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ += 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + if ((shouldContinue & 0x8) + && map_get_corner_height(surfaceElement->base_height, oldSlope, direction2) + == map_get_corner_height(targetBaseZ, slope, direction2)) + { + slope = tile_element_raise_styles[direction2][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ += 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + } + auto landSetHeightAction = LandSetHeightAction(nextLoc, targetBaseZ, slope); + landSetHeightAction.SetFlags(GetFlags()); + auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) + : GameActions::QueryNested(&landSetHeightAction); + if (res->Error == GameActions::Status::Ok) + { + totalCost += res->Cost; + } + } + return totalCost; +} + +money32 LandSmoothAction::SmoothLandRowByCorner( + bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight, int32_t stepX, int32_t stepY, int32_t direction, + int32_t checkDirection) const +{ + bool shouldContinue = true; + money32 totalCost = 0; + int32_t landChangePerTile; + if (stepX == 0 || stepY == 0) + { + landChangePerTile = _isLowering ? 2 : -2; + } + else + { + landChangePerTile = _isLowering ? 4 : -4; + } + + // check if we need to start at all + if (!LocationValid(loc) || !LocationValid({ loc.x + stepX, loc.y + stepY })) + { + return 0; + } + auto surfaceElement = map_get_surface_element_at(loc); + auto nextSurfaceElement = map_get_surface_element_at(CoordsXY{ loc.x + stepX, loc.y + stepY }); + if (surfaceElement == nullptr || nextSurfaceElement == nullptr) + { + return 0; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection) != expectedLandHeight + (_isLowering ? 2 : -2)) + { + return 0; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection) + != tile_element_get_corner_height(nextSurfaceElement, direction)) + { + return 0; + } + + auto nextLoc = loc; + while (shouldContinue) + { + nextLoc.x += stepX; + nextLoc.y += stepY; + // check if we need to continue after raising the current tile + // this needs to be checked before the tile is changed + if (!LocationValid({ nextLoc.x + stepX, nextLoc.y + stepY })) + { + shouldContinue = false; + } + else + { + surfaceElement = nextSurfaceElement; + nextSurfaceElement = map_get_surface_element_at(CoordsXY{ nextLoc.x + stepX, nextLoc.y + stepY }); + if (nextSurfaceElement == nullptr) + { + shouldContinue = false; + } + if (tile_element_get_corner_height(surfaceElement, direction) + landChangePerTile + != tile_element_get_corner_height(surfaceElement, checkDirection)) + { + shouldContinue = false; + } + if (shouldContinue + && tile_element_get_corner_height(surfaceElement, checkDirection) + != tile_element_get_corner_height(nextSurfaceElement, direction)) + { + shouldContinue = false; + } + } + if (stepX * stepY != 0) + { + totalCost += SmoothLandRowByCorner( + isExecuting, nextLoc, expectedLandHeight + (landChangePerTile / 2), 0, stepY, direction, checkDirection ^ 3); + totalCost += SmoothLandRowByCorner( + isExecuting, nextLoc, expectedLandHeight + (landChangePerTile / 2), stepX, 0, direction, checkDirection ^ 1); + } + expectedLandHeight += landChangePerTile; + // change land of current tile + auto result = SmoothLandTile(direction, isExecuting, nextLoc, surfaceElement); + if (result->Error == GameActions::Status::Ok) + { + totalCost += result->Cost; + } + } + return totalCost; +} + +GameActions::Result::Ptr LandSmoothAction::SmoothLand(bool isExecuting) const +{ + const bool raiseLand = !_isLowering; + const int32_t selectionType = _selectionType; + const int32_t heightOffset = raiseLand ? 2 : -2; + + auto normRange = _range.Normalise(); + // Cap bounds to map + auto l = std::max(normRange.GetLeft(), 32); + auto t = std::max(normRange.GetTop(), 32); + auto r = std::clamp(normRange.GetRight(), 0, MAXIMUM_TILE_START_XY); + auto b = std::clamp(normRange.GetBottom(), 0, MAXIMUM_TILE_START_XY); + auto validRange = MapRange{ l, t, r, b }; + + int32_t centreZ = tile_element_height(_coords); + + auto res = MakeResult(); + res->ErrorTitle = _ErrorTitles[_isLowering ? 0 : 1]; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = { _coords.x, _coords.y, centreZ }; + + // Do the smoothing + switch (selectionType) + { + case MAP_SELECT_TYPE_FULL: + { + uint8_t minHeight = heightOffset + map_get_lowest_land_height(validRange); + uint8_t maxHeight = heightOffset + map_get_highest_land_height(validRange); + + // Smooth the 4 corners + { // top-left + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); + if (surfaceElement != nullptr) + { + int32_t z = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); + } + } + { // bottom-left + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetBottom() }); + if (surfaceElement != nullptr) + { + int32_t z = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetBottom() }, z, -32, 32, 1, 3); + } + } + { // bottom-right + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), validRange.GetBottom() }); + if (surfaceElement != nullptr) + { + int32_t z = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetRight(), validRange.GetBottom() }, z, 32, 32, 2, 0); + } + } + { // top-right + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), validRange.GetTop() }); + if (surfaceElement != nullptr) + { + int32_t z = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetRight(), validRange.GetTop() }, z, 32, -32, 3, 1); + } + } + + // Smooth the edges + int32_t z1, z2; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), y }); + if (surfaceElement != nullptr) + { + z1 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); + z2 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { validRange.GetLeft(), y }, z1, z2, -32, 0, 0, 1, 3, 2); + } + + surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), y }); + if (surfaceElement != nullptr) + { + z1 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); + z2 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { validRange.GetRight(), y }, z1, z2, 32, 0, 2, 3, 1, 0); + } + } + + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + auto surfaceElement = map_get_surface_element_at(CoordsXY{ x, validRange.GetTop() }); + if (surfaceElement != nullptr) + { + z1 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); + z2 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { x, validRange.GetTop() }, z1, z2, 0, -32, 0, 3, 1, 2); + } + + surfaceElement = map_get_surface_element_at(CoordsXY{ x, validRange.GetBottom() }); + if (surfaceElement != nullptr) + { + z1 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); + z2 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { x, validRange.GetBottom() }, z1, z2, 0, 32, 1, 2, 0, 3); + } + } + break; + } + case MAP_SELECT_TYPE_CORNER_0: + case MAP_SELECT_TYPE_CORNER_1: + case MAP_SELECT_TYPE_CORNER_2: + case MAP_SELECT_TYPE_CORNER_3: + { + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); + if (surfaceElement == nullptr) + break; + uint8_t newBaseZ = surfaceElement->base_height; + uint8_t newSlope = surfaceElement->GetSlope(); + + if (raiseLand) + { + newSlope = tile_element_raise_styles[selectionType][newSlope]; + } + else + { + newSlope = tile_element_lower_styles[selectionType][newSlope]; + } + + if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + newBaseZ += heightOffset; + newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + + // Smooth the corners + int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 32, 2, 0); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 32, 1, 3); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); + + // Smooth the edges + switch (selectionType) + { + case MAP_SELECT_TYPE_CORNER_0: + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 3, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 1, 0); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 0, 3); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 0, 1); + break; + case MAP_SELECT_TYPE_CORNER_1: + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 2, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 0, 1); + z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 1, 2); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 1, 0); + break; + case MAP_SELECT_TYPE_CORNER_2: + z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 1, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 3, 2); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 2, 1); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 2, 3); + break; + case MAP_SELECT_TYPE_CORNER_3: + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 0, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 2, 3); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 3, 0); + z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 3, 2); + break; + } + break; + } + case MAP_SELECT_TYPE_EDGE_0: + case MAP_SELECT_TYPE_EDGE_1: + case MAP_SELECT_TYPE_EDGE_2: + case MAP_SELECT_TYPE_EDGE_3: + { + // TODO: Handle smoothing by edge + // Get the two corners to raise + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); + if (surfaceElement == nullptr) + break; + uint8_t newBaseZ = surfaceElement->base_height; + uint8_t oldSlope = surfaceElement->GetSlope(); + uint8_t newSlope = oldSlope; + int32_t rowIndex = selectionType - (MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1); + + if (raiseLand) + { + newSlope = tile_element_raise_styles[rowIndex][oldSlope]; + } + else + { + newSlope = tile_element_lower_styles[rowIndex][oldSlope]; + } + + const bool changeBaseHeight = newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + if (changeBaseHeight) + { + newBaseZ += heightOffset; + newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + + const uint8_t edge = selectionType - MAP_SELECT_TYPE_EDGE_0; + + // Table with corners for each edge selection. The first two are the selected corners, the latter + // two are the opposites + static constexpr uint8_t cornerIndices[][4] = { + { 2, 3, 1, 0 }, // MAP_SELECT_TYPE_EDGE_0 + { 3, 0, 2, 1 }, // MAP_SELECT_TYPE_EDGE_1 + { 0, 1, 3, 2 }, // MAP_SELECT_TYPE_EDGE_2 + { 1, 2, 0, 3 }, // MAP_SELECT_TYPE_EDGE_3 + }; + // Big coordinate offsets for the neigbouring tile for the given edge selection + static constexpr CoordsXY stepOffsets[] = { + { -32, 0 }, + { 0, 32 }, + { 32, 0 }, + { 0, -32 }, + }; + + // Smooth higher and lower edges + uint8_t c1 = cornerIndices[edge][0]; + uint8_t c2 = cornerIndices[edge][1]; + uint8_t c3 = cornerIndices[edge][2]; + uint8_t c4 = cornerIndices[edge][3]; + uint8_t z1 = map_get_corner_height(newBaseZ, newSlope, c1); + uint8_t z2 = map_get_corner_height(newBaseZ, newSlope, c2); + uint8_t z3 = map_get_corner_height(newBaseZ, newSlope, c3); + uint8_t z4 = map_get_corner_height(newBaseZ, newSlope, c4); + // Smooth the edge at the top of the new slope + res->Cost += SmoothLandRowByEdge( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z1, z2, stepOffsets[edge].x, stepOffsets[edge].y, + c3, c4, c1, c2); + // Smooth the edge at the bottom of the new slope + res->Cost += SmoothLandRowByEdge( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z3, z4, -stepOffsets[edge].x, -stepOffsets[edge].y, + c1, c2, c3, c4); + + // Smooth corners + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z1, -stepOffsets[edge].y, stepOffsets[edge].x, c2, + c1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z2, stepOffsets[edge].y, -stepOffsets[edge].x, c1, + c2); + int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 32, 2, 0); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 32, 1, 3); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); + break; + } + default: + log_error("Invalid map selection %u", _selectionType); + return MakeResult(GameActions::Status::InvalidParameters, res->ErrorTitle.GetStringId()); + } // switch selectionType + + // Raise / lower the land tool selection area + GameActions::Result::Ptr result; + if (raiseLand) + { + auto raiseLandAction = LandRaiseAction({ _coords.x, _coords.y }, validRange, selectionType); + raiseLandAction.SetFlags(GetFlags()); + result = isExecuting ? GameActions::ExecuteNested(&raiseLandAction) : GameActions::QueryNested(&raiseLandAction); + } + else + { + auto lowerLandAction = LandLowerAction({ _coords.x, _coords.y }, validRange, selectionType); + lowerLandAction.SetFlags(GetFlags()); + result = isExecuting ? GameActions::ExecuteNested(&lowerLandAction) : GameActions::QueryNested(&lowerLandAction); + } + if (result->Error != GameActions::Status::Ok) + { + return result; + } + + if (isExecuting) + { + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, centreZ }); + } + res->Cost += result->Cost; + return res; +} diff --git a/src/openrct2/actions/LandSmoothAction.h b/src/openrct2/actions/LandSmoothAction.h new file mode 100644 index 0000000000..f7f3880465 --- /dev/null +++ b/src/openrct2/actions/LandSmoothAction.h @@ -0,0 +1,53 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(LandSmoothAction, GAME_COMMAND_EDIT_LAND_SMOOTH, GameActions::Result) +{ +private: + CoordsXY _coords; + MapRange _range; + uint8_t _selectionType{}; + bool _isLowering{}; + + constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_LOWER_LAND_HERE, STR_CANT_RAISE_LAND_HERE }; + +public: + LandSmoothAction() = default; + LandSmoothAction(const CoordsXY& coords, MapRange range, uint8_t selectionType, bool isLowering) + : _coords(coords) + , _range(range) + , _selectionType(selectionType) + , _isLowering(isLowering) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr SmoothLandTile( + int32_t direction, bool isExecuting, const CoordsXY& loc, SurfaceElement* surfaceElement) const; + money32 SmoothLandRowByEdge( + bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight1, int32_t expectedLandHeight2, int32_t stepX, + int32_t stepY, int32_t direction1, int32_t direction2, int32_t checkDirection1, int32_t checkDirection2) const; + money32 SmoothLandRowByCorner( + bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight, int32_t stepX, int32_t stepY, int32_t direction, + int32_t checkDirection) const; + GameActions::Result::Ptr SmoothLand(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LandSmoothAction.hpp b/src/openrct2/actions/LandSmoothAction.hpp deleted file mode 100644 index 3a66ba046c..0000000000 --- a/src/openrct2/actions/LandSmoothAction.hpp +++ /dev/null @@ -1,672 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../OpenRCT2.h" -#include "../actions/LandLowerAction.hpp" -#include "../actions/LandRaiseAction.hpp" -#include "../actions/LandSetHeightAction.hpp" -#include "../audio/audio.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LandSmoothAction, GAME_COMMAND_EDIT_LAND_SMOOTH, GameActions::Result) -{ -private: - CoordsXY _coords; - MapRange _range; - uint8_t _selectionType{}; - bool _isLowering{}; - - constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_LOWER_LAND_HERE, STR_CANT_RAISE_LAND_HERE }; - -public: - LandSmoothAction() = default; - LandSmoothAction(const CoordsXY& coords, MapRange range, uint8_t selectionType, bool isLowering) - : _coords(coords) - , _range(range) - , _selectionType(selectionType) - , _isLowering(isLowering) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType) << DS_TAG(_isLowering); - } - - GameActions::Result::Ptr Query() const override - { - return SmoothLand(false); - } - - GameActions::Result::Ptr Execute() const override - { - return SmoothLand(true); - } - -private: - GameActions::Result::Ptr SmoothLandTile( - int32_t direction, bool isExecuting, const CoordsXY& loc, SurfaceElement* surfaceElement) const - { - int32_t targetBaseZ = surfaceElement->base_height; - int32_t slope = surfaceElement->GetSlope(); - if (_isLowering) - { - slope = tile_element_lower_styles[direction][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ -= 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - else - { - slope = tile_element_raise_styles[direction][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ += 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - - auto landSetHeightAction = LandSetHeightAction(loc, targetBaseZ, slope); - landSetHeightAction.SetFlags(GetFlags()); - auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); - - return res; - } - - money32 SmoothLandRowByEdge( - bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight1, int32_t expectedLandHeight2, int32_t stepX, - int32_t stepY, int32_t direction1, int32_t direction2, int32_t checkDirection1, int32_t checkDirection2) const - { - uint8_t shouldContinue = 0xF; - int32_t landChangePerTile = _isLowering ? 2 : -2; - money32 totalCost = 0; - - // check if we need to start at all - if (!LocationValid(loc) || !LocationValid({ loc.x + stepX, loc.y + stepY })) - { - return 0; - } - auto surfaceElement = map_get_surface_element_at(loc); - auto nextSurfaceElement = map_get_surface_element_at(CoordsXY{ loc.x + stepX, loc.y + stepY }); - if (surfaceElement == nullptr || nextSurfaceElement == nullptr) - { - return 0; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection1) != expectedLandHeight1 + landChangePerTile) - { - shouldContinue &= ~0x1; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection2) != expectedLandHeight2 + landChangePerTile) - { - shouldContinue &= ~0x2; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection1) - != tile_element_get_corner_height(nextSurfaceElement, direction1)) - { - shouldContinue &= ~0x1; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection2) - != tile_element_get_corner_height(nextSurfaceElement, direction2)) - { - shouldContinue &= ~0x2; - } - auto nextLoc = loc; - while ((shouldContinue & 0x3) != 0) - { - shouldContinue = ((shouldContinue << 2) | 0x3) & shouldContinue; - nextLoc.x += stepX; - nextLoc.y += stepY; - // check if we need to continue after raising the current tile - // this needs to be checked before the tile is changed - if (!LocationValid({ nextLoc.x + stepX, nextLoc.y + stepY })) - { - shouldContinue &= ~0x3; - } - else - { - surfaceElement = nextSurfaceElement; - nextSurfaceElement = map_get_surface_element_at(CoordsXY{ nextLoc.x + stepX, nextLoc.y + stepY }); - if (nextSurfaceElement == nullptr) - { - shouldContinue &= ~0x3; - } - if (tile_element_get_corner_height(surfaceElement, direction1) + landChangePerTile - != tile_element_get_corner_height(surfaceElement, checkDirection1)) - { - shouldContinue &= ~0x1; - } - if (tile_element_get_corner_height(surfaceElement, direction2) + landChangePerTile - != tile_element_get_corner_height(surfaceElement, checkDirection2)) - { - shouldContinue &= ~0x2; - } - if ((shouldContinue & 0x1) - && tile_element_get_corner_height(surfaceElement, checkDirection1) - != tile_element_get_corner_height(nextSurfaceElement, direction1)) - { - shouldContinue &= ~0x1; - } - if ((shouldContinue & 0x2) - && tile_element_get_corner_height(surfaceElement, checkDirection2) - != tile_element_get_corner_height(nextSurfaceElement, direction2)) - { - shouldContinue &= ~0x2; - } - } - expectedLandHeight1 += landChangePerTile; - - // change land of current tile - int32_t targetBaseZ = surfaceElement->base_height; - int32_t slope = surfaceElement->GetSlope(); - int32_t oldSlope = slope; - if (_isLowering) - { - if (shouldContinue & 0x4) - { - slope = tile_element_lower_styles[direction1][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ -= 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - if ((shouldContinue & 0x8) - && map_get_corner_height(surfaceElement->base_height, oldSlope, direction2) - == map_get_corner_height(targetBaseZ, slope, direction2)) - { - slope = tile_element_lower_styles[direction2][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ -= 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - } - else - { - if (shouldContinue & 0x4) - { - slope = tile_element_raise_styles[direction1][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ += 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - if ((shouldContinue & 0x8) - && map_get_corner_height(surfaceElement->base_height, oldSlope, direction2) - == map_get_corner_height(targetBaseZ, slope, direction2)) - { - slope = tile_element_raise_styles[direction2][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ += 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - } - auto landSetHeightAction = LandSetHeightAction(nextLoc, targetBaseZ, slope); - landSetHeightAction.SetFlags(GetFlags()); - auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); - if (res->Error == GameActions::Status::Ok) - { - totalCost += res->Cost; - } - } - return totalCost; - } - - money32 SmoothLandRowByCorner( - bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight, int32_t stepX, int32_t stepY, int32_t direction, - int32_t checkDirection) const - { - bool shouldContinue = true; - money32 totalCost = 0; - int32_t landChangePerTile; - if (stepX == 0 || stepY == 0) - { - landChangePerTile = _isLowering ? 2 : -2; - } - else - { - landChangePerTile = _isLowering ? 4 : -4; - } - - // check if we need to start at all - if (!LocationValid(loc) || !LocationValid({ loc.x + stepX, loc.y + stepY })) - { - return 0; - } - auto surfaceElement = map_get_surface_element_at(loc); - auto nextSurfaceElement = map_get_surface_element_at(CoordsXY{ loc.x + stepX, loc.y + stepY }); - if (surfaceElement == nullptr || nextSurfaceElement == nullptr) - { - return 0; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection) != expectedLandHeight + (_isLowering ? 2 : -2)) - { - return 0; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection) - != tile_element_get_corner_height(nextSurfaceElement, direction)) - { - return 0; - } - - auto nextLoc = loc; - while (shouldContinue) - { - nextLoc.x += stepX; - nextLoc.y += stepY; - // check if we need to continue after raising the current tile - // this needs to be checked before the tile is changed - if (!LocationValid({ nextLoc.x + stepX, nextLoc.y + stepY })) - { - shouldContinue = false; - } - else - { - surfaceElement = nextSurfaceElement; - nextSurfaceElement = map_get_surface_element_at(CoordsXY{ nextLoc.x + stepX, nextLoc.y + stepY }); - if (nextSurfaceElement == nullptr) - { - shouldContinue = false; - } - if (tile_element_get_corner_height(surfaceElement, direction) + landChangePerTile - != tile_element_get_corner_height(surfaceElement, checkDirection)) - { - shouldContinue = false; - } - if (shouldContinue - && tile_element_get_corner_height(surfaceElement, checkDirection) - != tile_element_get_corner_height(nextSurfaceElement, direction)) - { - shouldContinue = false; - } - } - if (stepX * stepY != 0) - { - totalCost += SmoothLandRowByCorner( - isExecuting, nextLoc, expectedLandHeight + (landChangePerTile / 2), 0, stepY, direction, - checkDirection ^ 3); - totalCost += SmoothLandRowByCorner( - isExecuting, nextLoc, expectedLandHeight + (landChangePerTile / 2), stepX, 0, direction, - checkDirection ^ 1); - } - expectedLandHeight += landChangePerTile; - // change land of current tile - auto result = SmoothLandTile(direction, isExecuting, nextLoc, surfaceElement); - if (result->Error == GameActions::Status::Ok) - { - totalCost += result->Cost; - } - } - return totalCost; - } - - GameActions::Result::Ptr SmoothLand(bool isExecuting) const - { - const bool raiseLand = !_isLowering; - const int32_t selectionType = _selectionType; - const int32_t heightOffset = raiseLand ? 2 : -2; - - auto normRange = _range.Normalise(); - // Cap bounds to map - auto l = std::max(normRange.GetLeft(), 32); - auto t = std::max(normRange.GetTop(), 32); - auto r = std::clamp(normRange.GetRight(), 0, MAXIMUM_TILE_START_XY); - auto b = std::clamp(normRange.GetBottom(), 0, MAXIMUM_TILE_START_XY); - auto validRange = MapRange{ l, t, r, b }; - - int32_t centreZ = tile_element_height(_coords); - - auto res = MakeResult(); - res->ErrorTitle = _ErrorTitles[_isLowering ? 0 : 1]; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = { _coords.x, _coords.y, centreZ }; - - // Do the smoothing - switch (selectionType) - { - case MAP_SELECT_TYPE_FULL: - { - uint8_t minHeight = heightOffset + map_get_lowest_land_height(validRange); - uint8_t maxHeight = heightOffset + map_get_highest_land_height(validRange); - - // Smooth the 4 corners - { // top-left - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); - if (surfaceElement != nullptr) - { - int32_t z = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); - } - } - { // bottom-left - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetBottom() }); - if (surfaceElement != nullptr) - { - int32_t z = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetBottom() }, z, -32, 32, 1, 3); - } - } - { // bottom-right - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), validRange.GetBottom() }); - if (surfaceElement != nullptr) - { - int32_t z = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetRight(), validRange.GetBottom() }, z, 32, 32, 2, 0); - } - } - { // top-right - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), validRange.GetTop() }); - if (surfaceElement != nullptr) - { - int32_t z = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetRight(), validRange.GetTop() }, z, 32, -32, 3, 1); - } - } - - // Smooth the edges - int32_t z1, z2; - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), y }); - if (surfaceElement != nullptr) - { - z1 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); - z2 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); - res->Cost += SmoothLandRowByEdge(isExecuting, { validRange.GetLeft(), y }, z1, z2, -32, 0, 0, 1, 3, 2); - } - - surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), y }); - if (surfaceElement != nullptr) - { - z1 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); - z2 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); - res->Cost += SmoothLandRowByEdge(isExecuting, { validRange.GetRight(), y }, z1, z2, 32, 0, 2, 3, 1, 0); - } - } - - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - auto surfaceElement = map_get_surface_element_at(CoordsXY{ x, validRange.GetTop() }); - if (surfaceElement != nullptr) - { - z1 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); - z2 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); - res->Cost += SmoothLandRowByEdge(isExecuting, { x, validRange.GetTop() }, z1, z2, 0, -32, 0, 3, 1, 2); - } - - surfaceElement = map_get_surface_element_at(CoordsXY{ x, validRange.GetBottom() }); - if (surfaceElement != nullptr) - { - z1 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); - z2 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); - res->Cost += SmoothLandRowByEdge(isExecuting, { x, validRange.GetBottom() }, z1, z2, 0, 32, 1, 2, 0, 3); - } - } - break; - } - case MAP_SELECT_TYPE_CORNER_0: - case MAP_SELECT_TYPE_CORNER_1: - case MAP_SELECT_TYPE_CORNER_2: - case MAP_SELECT_TYPE_CORNER_3: - { - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); - if (surfaceElement == nullptr) - break; - uint8_t newBaseZ = surfaceElement->base_height; - uint8_t newSlope = surfaceElement->GetSlope(); - - if (raiseLand) - { - newSlope = tile_element_raise_styles[selectionType][newSlope]; - } - else - { - newSlope = tile_element_lower_styles[selectionType][newSlope]; - } - - if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - newBaseZ += heightOffset; - newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - - // Smooth the corners - int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); - z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 32, 2, 0); - z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 32, 1, 3); - z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); - - // Smooth the edges - switch (selectionType) - { - case MAP_SELECT_TYPE_CORNER_0: - z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 3, 0); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 1, 0); - z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 0, 3); - z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 0, 1); - break; - case MAP_SELECT_TYPE_CORNER_1: - z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 2, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 0, 1); - z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 1, 2); - z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 1, 0); - break; - case MAP_SELECT_TYPE_CORNER_2: - z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 1, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 3, 2); - z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 2, 1); - z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 2, 3); - break; - case MAP_SELECT_TYPE_CORNER_3: - z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 0, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 2, 3); - z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 3, 0); - z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 3, 2); - break; - } - break; - } - case MAP_SELECT_TYPE_EDGE_0: - case MAP_SELECT_TYPE_EDGE_1: - case MAP_SELECT_TYPE_EDGE_2: - case MAP_SELECT_TYPE_EDGE_3: - { - // TODO: Handle smoothing by edge - // Get the two corners to raise - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); - if (surfaceElement == nullptr) - break; - uint8_t newBaseZ = surfaceElement->base_height; - uint8_t oldSlope = surfaceElement->GetSlope(); - uint8_t newSlope = oldSlope; - int32_t rowIndex = selectionType - (MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1); - - if (raiseLand) - { - newSlope = tile_element_raise_styles[rowIndex][oldSlope]; - } - else - { - newSlope = tile_element_lower_styles[rowIndex][oldSlope]; - } - - const bool changeBaseHeight = newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - if (changeBaseHeight) - { - newBaseZ += heightOffset; - newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - - const uint8_t edge = selectionType - MAP_SELECT_TYPE_EDGE_0; - - // Table with corners for each edge selection. The first two are the selected corners, the latter - // two are the opposites - static constexpr uint8_t cornerIndices[][4] = { - { 2, 3, 1, 0 }, // MAP_SELECT_TYPE_EDGE_0 - { 3, 0, 2, 1 }, // MAP_SELECT_TYPE_EDGE_1 - { 0, 1, 3, 2 }, // MAP_SELECT_TYPE_EDGE_2 - { 1, 2, 0, 3 }, // MAP_SELECT_TYPE_EDGE_3 - }; - // Big coordinate offsets for the neigbouring tile for the given edge selection - static constexpr CoordsXY stepOffsets[] = { - { -32, 0 }, - { 0, 32 }, - { 32, 0 }, - { 0, -32 }, - }; - - // Smooth higher and lower edges - uint8_t c1 = cornerIndices[edge][0]; - uint8_t c2 = cornerIndices[edge][1]; - uint8_t c3 = cornerIndices[edge][2]; - uint8_t c4 = cornerIndices[edge][3]; - uint8_t z1 = map_get_corner_height(newBaseZ, newSlope, c1); - uint8_t z2 = map_get_corner_height(newBaseZ, newSlope, c2); - uint8_t z3 = map_get_corner_height(newBaseZ, newSlope, c3); - uint8_t z4 = map_get_corner_height(newBaseZ, newSlope, c4); - // Smooth the edge at the top of the new slope - res->Cost += SmoothLandRowByEdge( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z1, z2, stepOffsets[edge].x, - stepOffsets[edge].y, c3, c4, c1, c2); - // Smooth the edge at the bottom of the new slope - res->Cost += SmoothLandRowByEdge( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z3, z4, -stepOffsets[edge].x, - -stepOffsets[edge].y, c1, c2, c3, c4); - - // Smooth corners - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z1, -stepOffsets[edge].y, stepOffsets[edge].x, - c2, c1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z2, stepOffsets[edge].y, -stepOffsets[edge].x, - c1, c2); - int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); - z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 32, 2, 0); - z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 32, 1, 3); - z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); - break; - } - default: - log_error("Invalid map selection %u", _selectionType); - return MakeResult(GameActions::Status::InvalidParameters, res->ErrorTitle.GetStringId()); - } // switch selectionType - - // Raise / lower the land tool selection area - GameActions::Result::Ptr result; - if (raiseLand) - { - auto raiseLandAction = LandRaiseAction({ _coords.x, _coords.y }, validRange, selectionType); - raiseLandAction.SetFlags(GetFlags()); - result = isExecuting ? GameActions::ExecuteNested(&raiseLandAction) : GameActions::QueryNested(&raiseLandAction); - } - else - { - auto lowerLandAction = LandLowerAction({ _coords.x, _coords.y }, validRange, selectionType); - lowerLandAction.SetFlags(GetFlags()); - result = isExecuting ? GameActions::ExecuteNested(&lowerLandAction) : GameActions::QueryNested(&lowerLandAction); - } - if (result->Error != GameActions::Status::Ok) - { - return result; - } - - if (isExecuting) - { - OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, centreZ }); - } - res->Cost += result->Cost; - return res; - } -}; diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.cpp b/src/openrct2/actions/LargeSceneryPlaceAction.cpp new file mode 100644 index 0000000000..910b7a4cbc --- /dev/null +++ b/src/openrct2/actions/LargeSceneryPlaceAction.cpp @@ -0,0 +1,359 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "LargeSceneryPlaceAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../object/ObjectLimits.h" +#include "../ride/Ride.h" +#include "../world/Banner.h" +#include "../world/MapAnimation.h" +#include "../world/Surface.h" + +void LargeSceneryPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _sceneryType); + visitor.Visit("primaryColour", _primaryColour); + visitor.Visit("secondaryColour", _secondaryColour); + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); + if (sceneryEntry != nullptr) + { + if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) + { + _bannerId = create_new_banner(0); + } + } +} + +void LargeSceneryPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) << DS_TAG(_bannerId); +} + +GameActions::Result::Ptr LargeSceneryPlaceAction::Query() const +{ + auto res = std::make_unique(); + res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; + res->Expenditure = ExpenditureType::Landscaping; + int16_t surfaceHeight = tile_element_height(_loc); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = surfaceHeight; + res->GroundFlags = 0; + + money32 supportsCost = 0; + + if (_primaryColour > TILE_ELEMENT_COLOUR_MASK || _secondaryColour > TILE_ELEMENT_COLOUR_MASK) + { + log_error( + "Invalid game command for scenery placement, primaryColour = %u, secondaryColour = %u", _primaryColour, + _secondaryColour); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + if (_sceneryType >= MAX_LARGE_SCENERY_OBJECTS) + { + log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); + if (sceneryEntry == nullptr) + { + log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + uint32_t totalNumTiles = GetTotalNumTiles(sceneryEntry->large_scenery.tiles); + int16_t maxHeight = GetMaxSurfaceHeight(sceneryEntry->large_scenery.tiles); + + if (_loc.z != 0) + { + maxHeight = _loc.z; + } + + res->Position.z = maxHeight; + + if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) + { + if (_bannerId == BANNER_INDEX_NULL) + { + log_error("Banner Index not specified."); + return MakeResult(GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); + } + + auto banner = GetBanner(_bannerId); + if (!banner->IsNull()) + { + log_error("No free banners available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + } + + if (!map_check_free_elements_and_reorganise(totalNumTiles)) + { + log_error("No free map elements available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + + uint8_t tileNum = 0; + for (rct_large_scenery_tile* tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; tile++, tileNum++) + { + auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); + + curTile.x += _loc.x; + curTile.y += _loc.y; + + int32_t zLow = tile->z_offset + maxHeight; + int32_t zHigh = tile->z_clearance + zLow; + + QuarterTile quarterTile = QuarterTile{ static_cast(tile->flags >> 12), 0 }.Rotate(_loc.direction); + if (!map_can_construct_with_clear_at( + { curTile, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost, + CREATE_CROSSING_MODE_NONE)) + { + return std::make_unique( + GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); + } + + int32_t tempSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + if (!gCheatsDisableClearanceChecks) + { + if ((gMapGroundFlags & ELEMENT_IS_UNDERWATER) || (gMapGroundFlags & ELEMENT_IS_UNDERGROUND)) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); + } + if (res->GroundFlags && !(res->GroundFlags & tempSceneryGroundFlags)) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); + } + } + + res->GroundFlags = tempSceneryGroundFlags; + + if (!LocationValid(curTile) || curTile.x >= gMapSizeUnits || curTile.y >= gMapSizeUnits) + { + return std::make_unique(GameActions::Status::Disallowed, STR_OFF_EDGE_OF_MAP); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_owned({ curTile, zLow }) && !gCheatsSandboxMode) + { + return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + res->Cost = (sceneryEntry->large_scenery.price * 10) + supportsCost; + return res; +} + +GameActions::Result::Ptr LargeSceneryPlaceAction::Execute() const +{ + auto res = std::make_unique(); + res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; + res->Expenditure = ExpenditureType::Landscaping; + + int16_t surfaceHeight = tile_element_height(_loc); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = surfaceHeight; + res->GroundFlags = 0; + + money32 supportsCost = 0; + + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); + if (sceneryEntry == nullptr) + { + log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + if (sceneryEntry->large_scenery.tiles == nullptr) + { + log_error("Invalid large scenery object, sceneryType = %u", _sceneryType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + uint32_t totalNumTiles = GetTotalNumTiles(sceneryEntry->large_scenery.tiles); + int16_t maxHeight = GetMaxSurfaceHeight(sceneryEntry->large_scenery.tiles); + + if (_loc.z != 0) + { + maxHeight = _loc.z; + } + + res->Position.z = maxHeight; + + if (!map_check_free_elements_and_reorganise(totalNumTiles)) + { + log_error("No free map elements available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + + uint8_t tileNum = 0; + for (rct_large_scenery_tile* tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; tile++, tileNum++) + { + auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); + + curTile.x += _loc.x; + curTile.y += _loc.y; + + int32_t zLow = tile->z_offset + maxHeight; + int32_t zHigh = tile->z_clearance + zLow; + + QuarterTile quarterTile = QuarterTile{ static_cast(tile->flags >> 12), 0 }.Rotate(_loc.direction); + if (!map_can_construct_with_clear_at( + { curTile, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost, + CREATE_CROSSING_MODE_NONE)) + { + return std::make_unique( + GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); + } + + res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter({ curTile, zLow }); + if (!gCheatsDisableClearanceChecks) + { + wall_remove_at({ curTile, zLow, zHigh }); + } + } + + TileElement* newTileElement = tile_element_insert( + CoordsXYZ{ curTile.x, curTile.y, zLow }, quarterTile.GetBaseQuarterOccupied()); + Guard::Assert(newTileElement != nullptr); + map_animation_create(MAP_ANIMATION_TYPE_LARGE_SCENERY, { curTile, zLow }); + newTileElement->SetType(TILE_ELEMENT_TYPE_LARGE_SCENERY); + newTileElement->SetClearanceZ(zHigh); + auto newSceneryElement = newTileElement->AsLargeScenery(); + + SetNewLargeSceneryElement(*newSceneryElement, tileNum); + + if (tileNum == 0) + { + res->tileElement = newTileElement; + } + map_invalidate_tile_full(curTile); + } + + // Allocate banner after all tiles to ensure banner id doesn't need to be freed. + if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) + { + if (_bannerId == BANNER_INDEX_NULL) + { + log_error("No free banners available"); + return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_BANNERS_IN_GAME); + } + + auto banner = GetBanner(_bannerId); + if (!banner->IsNull()) + { + log_error("No free banners available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + + banner->text = {}; + banner->colour = 2; + banner->text_colour = 2; + banner->flags = BANNER_FLAG_IS_LARGE_SCENERY; + banner->type = 0; + banner->position = TileCoordsXY(_loc); + + ride_id_t rideIndex = banner_get_closest_ride_index({ _loc, maxHeight }); + if (rideIndex != RIDE_ID_NULL) + { + banner->ride_index = rideIndex; + banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; + } + } + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + res->Cost = (sceneryEntry->large_scenery.price * 10) + supportsCost; + return res; +} + +int16_t LargeSceneryPlaceAction::GetTotalNumTiles(rct_large_scenery_tile* tiles) const +{ + uint32_t totalNumTiles = 0; + for (rct_large_scenery_tile* tile = tiles; tile->x_offset != -1; tile++) + { + totalNumTiles++; + } + return totalNumTiles; +} + +int16_t LargeSceneryPlaceAction::GetMaxSurfaceHeight(rct_large_scenery_tile* tiles) const +{ + int16_t maxHeight = -1; + for (rct_large_scenery_tile* tile = tiles; tile->x_offset != -1; tile++) + { + auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); + + curTile.x += _loc.x; + curTile.y += _loc.y; + + if (!map_is_location_valid(curTile)) + { + continue; + } + + auto* surfaceElement = map_get_surface_element_at(curTile); + if (surfaceElement == nullptr) + continue; + + int32_t baseZ = surfaceElement->GetBaseZ(); + int32_t slope = surfaceElement->GetSlope(); + + if ((slope & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) != TILE_ELEMENT_SLOPE_FLAT) + { + baseZ += LAND_HEIGHT_STEP; + if (slope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) + { + baseZ += LAND_HEIGHT_STEP; + } + } + + if (baseZ > maxHeight) + { + maxHeight = baseZ; + } + } + return maxHeight; +} + +void LargeSceneryPlaceAction::SetNewLargeSceneryElement(LargeSceneryElement& sceneryElement, uint8_t tileNum) const +{ + sceneryElement.SetDirection(_loc.direction); + sceneryElement.SetEntryIndex(_sceneryType); + sceneryElement.SetSequenceIndex(tileNum); + sceneryElement.SetPrimaryColour(_primaryColour); + sceneryElement.SetSecondaryColour(_secondaryColour); + + if (_bannerId != BANNER_INDEX_NULL) + { + sceneryElement.SetBannerIndex(_bannerId); + } + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + sceneryElement.SetGhost(true); + } +} diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.h b/src/openrct2/actions/LargeSceneryPlaceAction.h new file mode 100644 index 0000000000..f09a801fb5 --- /dev/null +++ b/src/openrct2/actions/LargeSceneryPlaceAction.h @@ -0,0 +1,83 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/LargeScenery.h" +#include "../world/Scenery.h" +#include "GameAction.h" + +class LargeSceneryPlaceActionResult final : public GameActions::Result +{ +public: + LargeSceneryPlaceActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_CANT_POSITION_THIS_HERE) + { + } + LargeSceneryPlaceActionResult(GameActions::Status error) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE) + { + } + LargeSceneryPlaceActionResult(GameActions::Status error, rct_string_id message) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message) + { + } + LargeSceneryPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message, args) + { + } + + uint8_t GroundFlags{ 0 }; + TileElement* tileElement = nullptr; +}; + +DEFINE_GAME_ACTION(LargeSceneryPlaceAction, GAME_COMMAND_PLACE_LARGE_SCENERY, LargeSceneryPlaceActionResult) +{ +private: + CoordsXYZD _loc; + ObjectEntryIndex _sceneryType{ OBJECT_ENTRY_INDEX_NULL }; + uint8_t _primaryColour{}; + uint8_t _secondaryColour{}; + BannerIndex _bannerId{ BANNER_INDEX_NULL }; + +public: + LargeSceneryPlaceAction() = default; + + LargeSceneryPlaceAction(const CoordsXYZD& loc, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) + : _loc(loc) + , _sceneryType(sceneryType) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + { + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); + if (sceneryEntry != nullptr) + { + if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) + { + _bannerId = create_new_banner(0); + } + } + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + int16_t GetTotalNumTiles(rct_large_scenery_tile * tiles) const; + int16_t GetMaxSurfaceHeight(rct_large_scenery_tile * tiles) const; + void SetNewLargeSceneryElement(LargeSceneryElement & sceneryElement, uint8_t tileNum) const; +}; diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.hpp b/src/openrct2/actions/LargeSceneryPlaceAction.hpp deleted file mode 100644 index cb6b6f48cf..0000000000 --- a/src/openrct2/actions/LargeSceneryPlaceAction.hpp +++ /dev/null @@ -1,424 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../object/ObjectLimits.h" -#include "../ride/Ride.h" -#include "../world/Banner.h" -#include "../world/LargeScenery.h" -#include "../world/MapAnimation.h" -#include "../world/Scenery.h" -#include "../world/Surface.h" -#include "GameAction.h" - -class LargeSceneryPlaceActionResult final : public GameActions::Result -{ -public: - LargeSceneryPlaceActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_CANT_POSITION_THIS_HERE) - { - } - LargeSceneryPlaceActionResult(GameActions::Status error) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE) - { - } - LargeSceneryPlaceActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message) - { - } - LargeSceneryPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message, args) - { - } - - uint8_t GroundFlags{ 0 }; - TileElement* tileElement = nullptr; -}; - -DEFINE_GAME_ACTION(LargeSceneryPlaceAction, GAME_COMMAND_PLACE_LARGE_SCENERY, LargeSceneryPlaceActionResult) -{ -private: - CoordsXYZD _loc; - ObjectEntryIndex _sceneryType{ OBJECT_ENTRY_INDEX_NULL }; - uint8_t _primaryColour{}; - uint8_t _secondaryColour{}; - BannerIndex _bannerId{ BANNER_INDEX_NULL }; - -public: - LargeSceneryPlaceAction() = default; - - LargeSceneryPlaceAction(const CoordsXYZD& loc, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) - : _loc(loc) - , _sceneryType(sceneryType) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - { - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); - if (sceneryEntry != nullptr) - { - if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - _bannerId = create_new_banner(0); - } - } - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _sceneryType); - visitor.Visit("primaryColour", _primaryColour); - visitor.Visit("secondaryColour", _secondaryColour); - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); - if (sceneryEntry != nullptr) - { - if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - _bannerId = create_new_banner(0); - } - } - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) - << DS_TAG(_bannerId); - } - - GameActions::Result::Ptr Query() const override - { - auto res = std::make_unique(); - res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; - res->Expenditure = ExpenditureType::Landscaping; - int16_t surfaceHeight = tile_element_height(_loc); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = surfaceHeight; - res->GroundFlags = 0; - - money32 supportsCost = 0; - - if (_primaryColour > TILE_ELEMENT_COLOUR_MASK || _secondaryColour > TILE_ELEMENT_COLOUR_MASK) - { - log_error( - "Invalid game command for scenery placement, primaryColour = %u, secondaryColour = %u", _primaryColour, - _secondaryColour); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - if (_sceneryType >= MAX_LARGE_SCENERY_OBJECTS) - { - log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); - if (sceneryEntry == nullptr) - { - log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - uint32_t totalNumTiles = GetTotalNumTiles(sceneryEntry->large_scenery.tiles); - int16_t maxHeight = GetMaxSurfaceHeight(sceneryEntry->large_scenery.tiles); - - if (_loc.z != 0) - { - maxHeight = _loc.z; - } - - res->Position.z = maxHeight; - - if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - if (_bannerId == BANNER_INDEX_NULL) - { - log_error("Banner Index not specified."); - return MakeResult(GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); - } - - auto banner = GetBanner(_bannerId); - if (!banner->IsNull()) - { - log_error("No free banners available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - } - - if (!map_check_free_elements_and_reorganise(totalNumTiles)) - { - log_error("No free map elements available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - - uint8_t tileNum = 0; - for (rct_large_scenery_tile* tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; tile++, tileNum++) - { - auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); - - curTile.x += _loc.x; - curTile.y += _loc.y; - - int32_t zLow = tile->z_offset + maxHeight; - int32_t zHigh = tile->z_clearance + zLow; - - QuarterTile quarterTile = QuarterTile{ static_cast(tile->flags >> 12), 0 }.Rotate(_loc.direction); - if (!map_can_construct_with_clear_at( - { curTile, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost, - CREATE_CROSSING_MODE_NONE)) - { - return std::make_unique( - GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); - } - - int32_t tempSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - if (!gCheatsDisableClearanceChecks) - { - if ((gMapGroundFlags & ELEMENT_IS_UNDERWATER) || (gMapGroundFlags & ELEMENT_IS_UNDERGROUND)) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); - } - if (res->GroundFlags && !(res->GroundFlags & tempSceneryGroundFlags)) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); - } - } - - res->GroundFlags = tempSceneryGroundFlags; - - if (!LocationValid(curTile) || curTile.x >= gMapSizeUnits || curTile.y >= gMapSizeUnits) - { - return std::make_unique(GameActions::Status::Disallowed, STR_OFF_EDGE_OF_MAP); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_owned({ curTile, zLow }) - && !gCheatsSandboxMode) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - res->Cost = (sceneryEntry->large_scenery.price * 10) + supportsCost; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; - res->Expenditure = ExpenditureType::Landscaping; - - int16_t surfaceHeight = tile_element_height(_loc); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = surfaceHeight; - res->GroundFlags = 0; - - money32 supportsCost = 0; - - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); - if (sceneryEntry == nullptr) - { - log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - if (sceneryEntry->large_scenery.tiles == nullptr) - { - log_error("Invalid large scenery object, sceneryType = %u", _sceneryType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - uint32_t totalNumTiles = GetTotalNumTiles(sceneryEntry->large_scenery.tiles); - int16_t maxHeight = GetMaxSurfaceHeight(sceneryEntry->large_scenery.tiles); - - if (_loc.z != 0) - { - maxHeight = _loc.z; - } - - res->Position.z = maxHeight; - - if (!map_check_free_elements_and_reorganise(totalNumTiles)) - { - log_error("No free map elements available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - - uint8_t tileNum = 0; - for (rct_large_scenery_tile* tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; tile++, tileNum++) - { - auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); - - curTile.x += _loc.x; - curTile.y += _loc.y; - - int32_t zLow = tile->z_offset + maxHeight; - int32_t zHigh = tile->z_clearance + zLow; - - QuarterTile quarterTile = QuarterTile{ static_cast(tile->flags >> 12), 0 }.Rotate(_loc.direction); - if (!map_can_construct_with_clear_at( - { curTile, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost, - CREATE_CROSSING_MODE_NONE)) - { - return std::make_unique( - GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); - } - - res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter({ curTile, zLow }); - if (!gCheatsDisableClearanceChecks) - { - wall_remove_at({ curTile, zLow, zHigh }); - } - } - - TileElement* newTileElement = tile_element_insert( - CoordsXYZ{ curTile.x, curTile.y, zLow }, quarterTile.GetBaseQuarterOccupied()); - Guard::Assert(newTileElement != nullptr); - map_animation_create(MAP_ANIMATION_TYPE_LARGE_SCENERY, { curTile, zLow }); - newTileElement->SetType(TILE_ELEMENT_TYPE_LARGE_SCENERY); - newTileElement->SetClearanceZ(zHigh); - auto newSceneryElement = newTileElement->AsLargeScenery(); - - SetNewLargeSceneryElement(*newSceneryElement, tileNum); - - if (tileNum == 0) - { - res->tileElement = newTileElement; - } - map_invalidate_tile_full(curTile); - } - - // Allocate banner after all tiles to ensure banner id doesn't need to be freed. - if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - if (_bannerId == BANNER_INDEX_NULL) - { - log_error("No free banners available"); - return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_BANNERS_IN_GAME); - } - - auto banner = GetBanner(_bannerId); - if (!banner->IsNull()) - { - log_error("No free banners available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - - banner->text = {}; - banner->colour = 2; - banner->text_colour = 2; - banner->flags = BANNER_FLAG_IS_LARGE_SCENERY; - banner->type = 0; - banner->position = TileCoordsXY(_loc); - - ride_id_t rideIndex = banner_get_closest_ride_index({ _loc, maxHeight }); - if (rideIndex != RIDE_ID_NULL) - { - banner->ride_index = rideIndex; - banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; - } - } - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - res->Cost = (sceneryEntry->large_scenery.price * 10) + supportsCost; - return res; - } - -private: - int16_t GetTotalNumTiles(rct_large_scenery_tile * tiles) const - { - uint32_t totalNumTiles = 0; - for (rct_large_scenery_tile* tile = tiles; tile->x_offset != -1; tile++) - { - totalNumTiles++; - } - return totalNumTiles; - } - - int16_t GetMaxSurfaceHeight(rct_large_scenery_tile * tiles) const - { - int16_t maxHeight = -1; - for (rct_large_scenery_tile* tile = tiles; tile->x_offset != -1; tile++) - { - auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); - - curTile.x += _loc.x; - curTile.y += _loc.y; - - if (!map_is_location_valid(curTile)) - { - continue; - } - - auto* surfaceElement = map_get_surface_element_at(curTile); - if (surfaceElement == nullptr) - continue; - - int32_t baseZ = surfaceElement->GetBaseZ(); - int32_t slope = surfaceElement->GetSlope(); - - if ((slope & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) != TILE_ELEMENT_SLOPE_FLAT) - { - baseZ += LAND_HEIGHT_STEP; - if (slope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) - { - baseZ += LAND_HEIGHT_STEP; - } - } - - if (baseZ > maxHeight) - { - maxHeight = baseZ; - } - } - return maxHeight; - } - - void SetNewLargeSceneryElement(LargeSceneryElement & sceneryElement, uint8_t tileNum) const - { - sceneryElement.SetDirection(_loc.direction); - sceneryElement.SetEntryIndex(_sceneryType); - sceneryElement.SetSequenceIndex(tileNum); - sceneryElement.SetPrimaryColour(_primaryColour); - sceneryElement.SetSecondaryColour(_secondaryColour); - - if (_bannerId != BANNER_INDEX_NULL) - { - sceneryElement.SetBannerIndex(_bannerId); - } - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - sceneryElement.SetGhost(true); - } - } -}; diff --git a/src/openrct2/actions/LargeSceneryRemoveAction.cpp b/src/openrct2/actions/LargeSceneryRemoveAction.cpp new file mode 100644 index 0000000000..f96e7ea160 --- /dev/null +++ b/src/openrct2/actions/LargeSceneryRemoveAction.cpp @@ -0,0 +1,227 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "LargeSceneryRemoveAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../world/Park.h" +#include "../world/SmallScenery.h" +#include "../world/Sprite.h" + +void LargeSceneryRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("tileIndex", _tileIndex); +} + +void LargeSceneryRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_tileIndex); +} + +GameActions::Result::Ptr LargeSceneryRemoveAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + const uint32_t flags = GetFlags(); + + int32_t z = tile_element_height(_loc); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = z; + res->Expenditure = ExpenditureType::Landscaping; + res->Cost = 0; + + TileElement* tileElement = FindLargeSceneryElement(); + if (tileElement == nullptr) + { + log_warning("Invalid game command for scenery removal, x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); + } + + rct_scenery_entry* scenery_entry = tileElement->AsLargeScenery()->GetEntry(); + + auto rotatedOffsets = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[_tileIndex].x_offset, + scenery_entry->large_scenery.tiles[_tileIndex].y_offset } + .Rotate(_loc.direction), + scenery_entry->large_scenery.tiles[_tileIndex].z_offset }; + + auto firstTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedOffsets; + + bool calculate_cost = true; + for (int32_t i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; i++) + { + auto currentTileRotatedOffset = CoordsXYZ{ + CoordsXY{ scenery_entry->large_scenery.tiles[i].x_offset, scenery_entry->large_scenery.tiles[i].y_offset }.Rotate( + _loc.direction), + scenery_entry->large_scenery.tiles[i].z_offset + }; + + auto currentTile = CoordsXYZ{ firstTile.x, firstTile.y, firstTile.z } + currentTileRotatedOffset; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_owned({ currentTile.x, currentTile.y, currentTile.z })) + { + return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + if (!LocationValid(currentTile)) + { + return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + // Prevent duplicate costs when using the clear scenery tool that overlaps multiple large + // scenery tile elements. + if (flags & GAME_COMMAND_FLAG_PATH_SCENERY) + { + if (tileElement->AsLargeScenery()->IsAccounted()) + calculate_cost = false; + + // Sets the flag to prevent this being counted in additional calls + tileElement->AsLargeScenery()->SetIsAccounted(true); + } + } + + if (calculate_cost) + res->Cost = scenery_entry->large_scenery.removal_price * 10; + + return res; +} + +GameActions::Result::Ptr LargeSceneryRemoveAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + const uint32_t flags = GetFlags(); + + int32_t z = tile_element_height(_loc); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = z; + res->Expenditure = ExpenditureType::Landscaping; + res->Cost = 0; + + TileElement* tileElement = FindLargeSceneryElement(); + if (tileElement == nullptr) + { + log_warning("Invalid game command for scenery removal, x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); + } + + tile_element_remove_banner_entry(tileElement); + + rct_scenery_entry* scenery_entry = tileElement->AsLargeScenery()->GetEntry(); + + auto rotatedFirstTile = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[_tileIndex].x_offset, + scenery_entry->large_scenery.tiles[_tileIndex].y_offset } + .Rotate(_loc.direction), + scenery_entry->large_scenery.tiles[_tileIndex].z_offset }; + + auto firstTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedFirstTile; + + for (int32_t i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; i++) + { + auto rotatedCurrentTile = CoordsXYZ{ + CoordsXY{ scenery_entry->large_scenery.tiles[i].x_offset, scenery_entry->large_scenery.tiles[i].y_offset }.Rotate( + _loc.direction), + scenery_entry->large_scenery.tiles[i].z_offset + }; + + auto currentTile = CoordsXYZ{ firstTile.x, firstTile.y, firstTile.z } + rotatedCurrentTile; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_owned({ currentTile.x, currentTile.y, currentTile.z })) + { + return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + TileElement* sceneryElement = map_get_first_element_at(currentTile); + bool element_found = false; + if (sceneryElement != nullptr) + { + do + { + if (sceneryElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) + continue; + + if (sceneryElement->GetDirection() != _loc.direction) + continue; + + if (sceneryElement->AsLargeScenery()->GetSequenceIndex() != i) + continue; + + if (sceneryElement->GetBaseZ() != currentTile.z) + continue; + + // If we are removing ghost elements + if ((flags & GAME_COMMAND_FLAG_GHOST) && sceneryElement->IsGhost() == false) + continue; + + map_invalidate_tile_full(currentTile); + tile_element_remove(sceneryElement); + + element_found = true; + break; + } while (!(sceneryElement++)->IsLastForTile()); + } + + if (element_found == false) + { + log_error("Tile not found when trying to remove element!"); + } + } + + res->Cost = scenery_entry->large_scenery.removal_price * 10; + + return res; +} + +TileElement* LargeSceneryRemoveAction::FindLargeSceneryElement() const +{ + TileElement* tileElement = map_get_first_element_at(_loc); + if (tileElement == nullptr) + return nullptr; + + do + { + if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) + continue; + + if (tileElement->GetBaseZ() != _loc.z) + continue; + + if (tileElement->AsLargeScenery()->GetSequenceIndex() != _tileIndex) + continue; + + if (tileElement->GetDirection() != _loc.direction) + continue; + + // If we are removing ghost elements + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && tileElement->IsGhost() == false) + continue; + + return tileElement; + + } while (!(tileElement++)->IsLastForTile()); + + return nullptr; +} diff --git a/src/openrct2/actions/LargeSceneryRemoveAction.h b/src/openrct2/actions/LargeSceneryRemoveAction.h new file mode 100644 index 0000000000..46a1153072 --- /dev/null +++ b/src/openrct2/actions/LargeSceneryRemoveAction.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(LargeSceneryRemoveAction, GAME_COMMAND_REMOVE_LARGE_SCENERY, GameActions::Result) +{ +private: + CoordsXYZD _loc; + uint16_t _tileIndex{}; + +public: + LargeSceneryRemoveAction() = default; + + LargeSceneryRemoveAction(const CoordsXYZD& location, uint16_t tileIndex) + : _loc(location) + , _tileIndex(tileIndex) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + TileElement* FindLargeSceneryElement() const; +}; diff --git a/src/openrct2/actions/LargeSceneryRemoveAction.hpp b/src/openrct2/actions/LargeSceneryRemoveAction.hpp deleted file mode 100644 index d29e81b479..0000000000 --- a/src/openrct2/actions/LargeSceneryRemoveAction.hpp +++ /dev/null @@ -1,248 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../world/Park.h" -#include "../world/SmallScenery.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LargeSceneryRemoveAction, GAME_COMMAND_REMOVE_LARGE_SCENERY, GameActions::Result) -{ -private: - CoordsXYZD _loc; - uint16_t _tileIndex{}; - -public: - LargeSceneryRemoveAction() = default; - - LargeSceneryRemoveAction(const CoordsXYZD& location, uint16_t tileIndex) - : _loc(location) - , _tileIndex(tileIndex) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("tileIndex", _tileIndex); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_tileIndex); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - const uint32_t flags = GetFlags(); - - int32_t z = tile_element_height(_loc); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = z; - res->Expenditure = ExpenditureType::Landscaping; - res->Cost = 0; - - TileElement* tileElement = FindLargeSceneryElement(); - if (tileElement == nullptr) - { - log_warning("Invalid game command for scenery removal, x = %d, y = %d", _loc.x, _loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); - } - - rct_scenery_entry* scenery_entry = tileElement->AsLargeScenery()->GetEntry(); - - auto rotatedOffsets = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[_tileIndex].x_offset, - scenery_entry->large_scenery.tiles[_tileIndex].y_offset } - .Rotate(_loc.direction), - scenery_entry->large_scenery.tiles[_tileIndex].z_offset }; - - auto firstTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedOffsets; - - bool calculate_cost = true; - for (int32_t i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; i++) - { - auto currentTileRotatedOffset = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[i].x_offset, - scenery_entry->large_scenery.tiles[i].y_offset } - .Rotate(_loc.direction), - scenery_entry->large_scenery.tiles[i].z_offset }; - - auto currentTile = CoordsXYZ{ firstTile.x, firstTile.y, firstTile.z } + currentTileRotatedOffset; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_owned({ currentTile.x, currentTile.y, currentTile.z })) - { - return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - if (!LocationValid(currentTile)) - { - return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - // Prevent duplicate costs when using the clear scenery tool that overlaps multiple large - // scenery tile elements. - if (flags & GAME_COMMAND_FLAG_PATH_SCENERY) - { - if (tileElement->AsLargeScenery()->IsAccounted()) - calculate_cost = false; - - // Sets the flag to prevent this being counted in additional calls - tileElement->AsLargeScenery()->SetIsAccounted(true); - } - } - - if (calculate_cost) - res->Cost = scenery_entry->large_scenery.removal_price * 10; - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - const uint32_t flags = GetFlags(); - - int32_t z = tile_element_height(_loc); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = z; - res->Expenditure = ExpenditureType::Landscaping; - res->Cost = 0; - - TileElement* tileElement = FindLargeSceneryElement(); - if (tileElement == nullptr) - { - log_warning("Invalid game command for scenery removal, x = %d, y = %d", _loc.x, _loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); - } - - tile_element_remove_banner_entry(tileElement); - - rct_scenery_entry* scenery_entry = tileElement->AsLargeScenery()->GetEntry(); - - auto rotatedFirstTile = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[_tileIndex].x_offset, - scenery_entry->large_scenery.tiles[_tileIndex].y_offset } - .Rotate(_loc.direction), - scenery_entry->large_scenery.tiles[_tileIndex].z_offset }; - - auto firstTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedFirstTile; - - for (int32_t i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; i++) - { - auto rotatedCurrentTile = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[i].x_offset, - scenery_entry->large_scenery.tiles[i].y_offset } - .Rotate(_loc.direction), - scenery_entry->large_scenery.tiles[i].z_offset }; - - auto currentTile = CoordsXYZ{ firstTile.x, firstTile.y, firstTile.z } + rotatedCurrentTile; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_owned({ currentTile.x, currentTile.y, currentTile.z })) - { - return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - TileElement* sceneryElement = map_get_first_element_at(currentTile); - bool element_found = false; - if (sceneryElement != nullptr) - { - do - { - if (sceneryElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) - continue; - - if (sceneryElement->GetDirection() != _loc.direction) - continue; - - if (sceneryElement->AsLargeScenery()->GetSequenceIndex() != i) - continue; - - if (sceneryElement->GetBaseZ() != currentTile.z) - continue; - - // If we are removing ghost elements - if ((flags & GAME_COMMAND_FLAG_GHOST) && sceneryElement->IsGhost() == false) - continue; - - map_invalidate_tile_full(currentTile); - tile_element_remove(sceneryElement); - - element_found = true; - break; - } while (!(sceneryElement++)->IsLastForTile()); - } - - if (element_found == false) - { - log_error("Tile not found when trying to remove element!"); - } - } - - res->Cost = scenery_entry->large_scenery.removal_price * 10; - - return res; - } - -private: - TileElement* FindLargeSceneryElement() const - { - TileElement* tileElement = map_get_first_element_at(_loc); - if (tileElement == nullptr) - return nullptr; - - do - { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) - continue; - - if (tileElement->GetBaseZ() != _loc.z) - continue; - - if (tileElement->AsLargeScenery()->GetSequenceIndex() != _tileIndex) - continue; - - if (tileElement->GetDirection() != _loc.direction) - continue; - - // If we are removing ghost elements - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && tileElement->IsGhost() == false) - continue; - - return tileElement; - - } while (!(tileElement++)->IsLastForTile()); - - return nullptr; - } -}; diff --git a/src/openrct2/actions/LargeScenerySetColourAction.cpp b/src/openrct2/actions/LargeScenerySetColourAction.cpp new file mode 100644 index 0000000000..65f96183cc --- /dev/null +++ b/src/openrct2/actions/LargeScenerySetColourAction.cpp @@ -0,0 +1,128 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "LargeScenerySetColourAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../world/Scenery.h" + +void LargeScenerySetColourAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_tileIndex) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour); +} + +GameActions::Result::Ptr LargeScenerySetColourAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr LargeScenerySetColourAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr LargeScenerySetColourAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = tile_element_height(_loc); + res->ErrorTitle = STR_CANT_REPAINT_THIS; + + if (_loc.x < 0 || _loc.y < 0 || _loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY) + { + log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (_primaryColour > 31) + { + log_error("Invalid primary colour: colour = %u", _primaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (_secondaryColour > 31) + { + log_error("Invalid primary colour: colour = %u", _secondaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + auto largeElement = map_get_large_scenery_segment(_loc, _tileIndex); + + if (largeElement == nullptr) + { + log_error( + "Could not find large scenery at: x = %d, y = %d, z = %d, direction = %d, tileIndex = %u", _loc.x, _loc.y, _loc.z, + _loc.direction, _tileIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(largeElement->IsGhost())) + { + return res; + } + + rct_scenery_entry* sceneryEntry = largeElement->GetEntry(); + + if (sceneryEntry == nullptr) + { + log_error("Could not find scenery object. type = %u", largeElement->GetEntryIndex()); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + // Work out the base tile coordinates (Tile with index 0) + auto rotatedBaseCoordsOffset = CoordsXYZ{ CoordsXY{ sceneryEntry->large_scenery.tiles[_tileIndex].x_offset, + sceneryEntry->large_scenery.tiles[_tileIndex].y_offset } + .Rotate(_loc.direction), + sceneryEntry->large_scenery.tiles[_tileIndex].z_offset }; + + auto baseTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedBaseCoordsOffset; + + auto i = 0; + for (auto tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; ++tile, ++i) + { + // Work out the current tile coordinates + auto rotatedTileCoords = CoordsXYZ{ CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction), tile->z_offset }; + auto currentTile = CoordsXYZ{ baseTile.x, baseTile.y, baseTile.z } + rotatedTileCoords; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_owned(currentTile)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + if (!LocationValid(currentTile)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto tileElement = map_get_large_scenery_segment({ currentTile.x, currentTile.y, _loc.z, _loc.direction }, i); + + if (tileElement == nullptr) + { + log_error( + "Large scenery element not found at: x = %d, y = %d, z = %d, direction = %d", _loc.x, _loc.y, _loc.z, + _loc.direction); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + if (isExecuting) + { + tileElement->SetPrimaryColour(_primaryColour); + tileElement->SetSecondaryColour(_secondaryColour); + + map_invalidate_tile_full(currentTile); + } + } + return res; +} diff --git a/src/openrct2/actions/LargeScenerySetColourAction.h b/src/openrct2/actions/LargeScenerySetColourAction.h new file mode 100644 index 0000000000..4329492b98 --- /dev/null +++ b/src/openrct2/actions/LargeScenerySetColourAction.h @@ -0,0 +1,44 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(LargeScenerySetColourAction, GAME_COMMAND_SET_LARGE_SCENERY_COLOUR, GameActions::Result) +{ +private: + CoordsXYZD _loc; + uint8_t _tileIndex{}; + uint8_t _primaryColour{}; + uint8_t _secondaryColour{}; + +public: + LargeScenerySetColourAction() = default; + + LargeScenerySetColourAction(const CoordsXYZD& loc, uint8_t tileIndex, uint8_t primaryColour, uint8_t secondaryColour) + : _loc(loc) + , _tileIndex(tileIndex) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LargeScenerySetColourAction.hpp b/src/openrct2/actions/LargeScenerySetColourAction.hpp deleted file mode 100644 index 1bfdb9c472..0000000000 --- a/src/openrct2/actions/LargeScenerySetColourAction.hpp +++ /dev/null @@ -1,156 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../world/Scenery.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LargeScenerySetColourAction, GAME_COMMAND_SET_LARGE_SCENERY_COLOUR, GameActions::Result) -{ -private: - CoordsXYZD _loc; - uint8_t _tileIndex{}; - uint8_t _primaryColour{}; - uint8_t _secondaryColour{}; - -public: - LargeScenerySetColourAction() = default; - - LargeScenerySetColourAction(const CoordsXYZD& loc, uint8_t tileIndex, uint8_t primaryColour, uint8_t secondaryColour) - : _loc(loc) - , _tileIndex(tileIndex) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_tileIndex) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = tile_element_height(_loc); - res->ErrorTitle = STR_CANT_REPAINT_THIS; - - if (_loc.x < 0 || _loc.y < 0 || _loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY) - { - log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (_primaryColour > 31) - { - log_error("Invalid primary colour: colour = %u", _primaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (_secondaryColour > 31) - { - log_error("Invalid primary colour: colour = %u", _secondaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - auto largeElement = map_get_large_scenery_segment(_loc, _tileIndex); - - if (largeElement == nullptr) - { - log_error( - "Could not find large scenery at: x = %d, y = %d, z = %d, direction = %d, tileIndex = %u", _loc.x, _loc.y, - _loc.z, _loc.direction, _tileIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(largeElement->IsGhost())) - { - return res; - } - - rct_scenery_entry* sceneryEntry = largeElement->GetEntry(); - - if (sceneryEntry == nullptr) - { - log_error("Could not find scenery object. type = %u", largeElement->GetEntryIndex()); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - // Work out the base tile coordinates (Tile with index 0) - auto rotatedBaseCoordsOffset = CoordsXYZ{ CoordsXY{ sceneryEntry->large_scenery.tiles[_tileIndex].x_offset, - sceneryEntry->large_scenery.tiles[_tileIndex].y_offset } - .Rotate(_loc.direction), - sceneryEntry->large_scenery.tiles[_tileIndex].z_offset }; - - auto baseTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedBaseCoordsOffset; - - auto i = 0; - for (auto tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; ++tile, ++i) - { - // Work out the current tile coordinates - auto rotatedTileCoords = CoordsXYZ{ CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction), - tile->z_offset }; - auto currentTile = CoordsXYZ{ baseTile.x, baseTile.y, baseTile.z } + rotatedTileCoords; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_owned(currentTile)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - if (!LocationValid(currentTile)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - auto tileElement = map_get_large_scenery_segment({ currentTile.x, currentTile.y, _loc.z, _loc.direction }, i); - - if (tileElement == nullptr) - { - log_error( - "Large scenery element not found at: x = %d, y = %d, z = %d, direction = %d", _loc.x, _loc.y, _loc.z, - _loc.direction); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - if (isExecuting) - { - tileElement->SetPrimaryColour(_primaryColour); - tileElement->SetSecondaryColour(_secondaryColour); - - map_invalidate_tile_full(currentTile); - } - } - return res; - } -}; diff --git a/src/openrct2/actions/LoadOrQuitAction.cpp b/src/openrct2/actions/LoadOrQuitAction.cpp new file mode 100644 index 0000000000..d238bbba0f --- /dev/null +++ b/src/openrct2/actions/LoadOrQuitAction.cpp @@ -0,0 +1,44 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "LoadOrQuitAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" + +void LoadOrQuitAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_mode) << DS_TAG(_savePromptMode); +} + +GameActions::Result::Ptr LoadOrQuitAction::Query() const +{ + return std::make_unique(); +} + +GameActions::Result::Ptr LoadOrQuitAction::Execute() const +{ + auto mode = static_cast(_mode); + switch (mode) + { + case LoadOrQuitModes::OpenSavePrompt: + gSavePromptMode = _savePromptMode; + context_open_window(WC_SAVE_PROMPT); + break; + case LoadOrQuitModes::CloseSavePrompt: + window_close_by_class(WC_SAVE_PROMPT); + break; + default: + game_load_or_quit_no_save_prompt(); + break; + } + return std::make_unique(); +} diff --git a/src/openrct2/actions/LoadOrQuitAction.hpp b/src/openrct2/actions/LoadOrQuitAction.h similarity index 51% rename from src/openrct2/actions/LoadOrQuitAction.hpp rename to src/openrct2/actions/LoadOrQuitAction.h index effe1b8fd1..d5bec9f38c 100644 --- a/src/openrct2/actions/LoadOrQuitAction.hpp +++ b/src/openrct2/actions/LoadOrQuitAction.h @@ -9,8 +9,6 @@ #pragma once -#include "../Context.h" -#include "../OpenRCT2.h" #include "GameAction.h" enum class LoadOrQuitModes : uint8_t @@ -35,37 +33,10 @@ public: uint16_t GetActionFlags() const override { - return GameAction::GetActionFlags() | GameActions::Flags::ClientOnly | GameActions::Flags::AllowWhilePaused; + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_mode) << DS_TAG(_savePromptMode); - } - - GameActions::Result::Ptr Query() const override - { - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto mode = static_cast(_mode); - switch (mode) - { - case LoadOrQuitModes::OpenSavePrompt: - gSavePromptMode = _savePromptMode; - context_open_window(WC_SAVE_PROMPT); - break; - case LoadOrQuitModes::CloseSavePrompt: - window_close_by_class(WC_SAVE_PROMPT); - break; - default: - game_load_or_quit_no_save_prompt(); - break; - } - return std::make_unique(); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/MazePlaceTrackAction.cpp b/src/openrct2/actions/MazePlaceTrackAction.cpp new file mode 100644 index 0000000000..732129d9da --- /dev/null +++ b/src/openrct2/actions/MazePlaceTrackAction.cpp @@ -0,0 +1,191 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ +#include "MazePlaceTrackAction.h" + +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../ride/TrackData.h" + +void MazePlaceTrackAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("ride", _rideIndex); + visitor.Visit("mazeEntry", _mazeEntry); +} + +void MazePlaceTrackAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_loc) << DS_TAG(_rideIndex) << DS_TAG(_mazeEntry); +} + +GameActions::Result::Ptr MazePlaceTrackAction::Query() const +{ + auto res = std::make_unique(); + + res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; + res->Expenditure = ExpenditureType::RideConstruction; + res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + if (!map_check_free_elements_and_reorganise(1)) + { + res->Error = GameActions::Status::NoFreeElements; + res->ErrorMessage = STR_TILE_ELEMENT_LIMIT_REACHED; + return res; + } + if ((_loc.z & 0xF) != 0) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_CONSTRUCTION_ERR_UNKNOWN; + return res; + } + + if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode)) + { + res->Error = GameActions::Status::NotOwned; + res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; + return res; + } + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; + return res; + } + + auto baseHeight = _loc.z; + auto clearanceHeight = _loc.z + MAZE_CLEARANCE_HEIGHT; + + auto heightDifference = baseHeight - surfaceElement->GetBaseZ(); + if (heightDifference >= 0 && !gCheatsDisableSupportLimits) + { + heightDifference /= COORDS_Z_PER_TINY_Z; + + if (heightDifference > RideTypeDescriptors[RIDE_TYPE_MAZE].Heights.MaxHeight) + { + res->Error = GameActions::Status::TooHigh; + res->ErrorMessage = STR_TOO_HIGH_FOR_SUPPORTS; + return res; + } + } + + money32 clearCost = 0; + + if (!map_can_construct_with_clear_at( + { _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags(), + &clearCost, CREATE_CROSSING_MODE_NONE)) + { + return MakeResult( + GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), gGameCommandErrorText, gCommonFormatArgs); + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorMessage = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; + return res; + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERGROUND) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorMessage = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + return res; + } + + auto ride = get_ride(_rideIndex); + if (ride == nullptr || ride->type == RIDE_TYPE_NULL) + { + res->Error = GameActions::Status::InvalidParameters; + res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; + return res; + } + + money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); + res->Cost = clearCost + price / 2 * 10; + + return res; +} + +GameActions::Result::Ptr MazePlaceTrackAction::Execute() const +{ + auto res = std::make_unique(); + + res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; + res->Expenditure = ExpenditureType::RideConstruction; + res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + res->Error = GameActions::Status::InvalidParameters; + res->ErrorMessage = STR_NONE; + return res; + } + + if (!map_check_free_elements_and_reorganise(1)) + { + res->Error = GameActions::Status::NoFreeElements; + res->ErrorMessage = STR_NONE; + return res; + } + + uint32_t flags = GetFlags(); + if (!(flags & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter(_loc); + wall_remove_at({ _loc.ToTileStart(), _loc.z, _loc.z + 32 }); + } + + auto baseHeight = _loc.z; + auto clearanceHeight = _loc.z + MAZE_CLEARANCE_HEIGHT; + + money32 clearCost = 0; + if (!map_can_construct_with_clear_at( + { _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, + GetFlags() | GAME_COMMAND_FLAG_APPLY, &clearCost, CREATE_CROSSING_MODE_NONE)) + { + return MakeResult( + GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), gGameCommandErrorText, gCommonFormatArgs); + } + + money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); + res->Cost = clearCost + price / 2 * 10; + + auto startLoc = _loc.ToTileStart(); + + auto tileElement = tile_element_insert(_loc, 0b1111); + assert(tileElement != nullptr); + + tileElement->SetClearanceZ(clearanceHeight); + tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); + + tileElement->AsTrack()->SetTrackType(TrackElemType::Maze); + tileElement->AsTrack()->SetRideIndex(_rideIndex); + tileElement->AsTrack()->SetMazeEntry(_mazeEntry); + + if (flags & GAME_COMMAND_FLAG_GHOST) + { + tileElement->SetGhost(true); + } + + map_invalidate_tile_full(startLoc); + + ride->maze_tiles++; + ride->stations[0].SetBaseZ(tileElement->GetBaseZ()); + ride->stations[0].Start = { 0, 0 }; + + if (ride->maze_tiles == 1) + { + ride->overall_view = startLoc; + } + + return res; +} diff --git a/src/openrct2/actions/MazePlaceTrackAction.h b/src/openrct2/actions/MazePlaceTrackAction.h new file mode 100644 index 0000000000..3127a1f75b --- /dev/null +++ b/src/openrct2/actions/MazePlaceTrackAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(MazePlaceTrackAction, GAME_COMMAND_PLACE_MAZE_DESIGN, GameActions::Result) +{ +private: + CoordsXYZ _loc; + NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; + uint16_t _mazeEntry{}; + +public: + MazePlaceTrackAction() = default; + + MazePlaceTrackAction(const CoordsXYZ& location, NetworkRideId_t rideIndex, uint16_t mazeEntry) + : _loc(location) + , _rideIndex(rideIndex) + , _mazeEntry(mazeEntry) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/MazePlaceTrackAction.hpp b/src/openrct2/actions/MazePlaceTrackAction.hpp deleted file mode 100644 index ade7d3761c..0000000000 --- a/src/openrct2/actions/MazePlaceTrackAction.hpp +++ /dev/null @@ -1,210 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../ride/RideData.h" -#include "../ride/TrackData.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(MazePlaceTrackAction, GAME_COMMAND_PLACE_MAZE_DESIGN, GameActions::Result) -{ -private: - CoordsXYZ _loc; - NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; - uint16_t _mazeEntry{}; - -public: - MazePlaceTrackAction() = default; - - MazePlaceTrackAction(const CoordsXYZ& location, NetworkRideId_t rideIndex, uint16_t mazeEntry) - : _loc(location) - , _rideIndex(rideIndex) - , _mazeEntry(mazeEntry) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("ride", _rideIndex); - visitor.Visit("mazeEntry", _mazeEntry); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_loc) << DS_TAG(_rideIndex) << DS_TAG(_mazeEntry); - } - - GameActions::Result::Ptr Query() const override - { - auto res = std::make_unique(); - - res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; - res->Expenditure = ExpenditureType::RideConstruction; - res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - if (!map_check_free_elements_and_reorganise(1)) - { - res->Error = GameActions::Status::NoFreeElements; - res->ErrorMessage = STR_TILE_ELEMENT_LIMIT_REACHED; - return res; - } - if ((_loc.z & 0xF) != 0) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_CONSTRUCTION_ERR_UNKNOWN; - return res; - } - - if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode)) - { - res->Error = GameActions::Status::NotOwned; - res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; - return res; - } - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; - return res; - } - - auto baseHeight = _loc.z; - auto clearanceHeight = _loc.z + MAZE_CLEARANCE_HEIGHT; - - auto heightDifference = baseHeight - surfaceElement->GetBaseZ(); - if (heightDifference >= 0 && !gCheatsDisableSupportLimits) - { - heightDifference /= COORDS_Z_PER_TINY_Z; - - if (heightDifference > RideTypeDescriptors[RIDE_TYPE_MAZE].Heights.MaxHeight) - { - res->Error = GameActions::Status::TooHigh; - res->ErrorMessage = STR_TOO_HIGH_FOR_SUPPORTS; - return res; - } - } - - money32 clearCost = 0; - - if (!map_can_construct_with_clear_at( - { _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, - GetFlags(), &clearCost, CREATE_CROSSING_MODE_NONE)) - { - return MakeResult( - GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), gGameCommandErrorText, gCommonFormatArgs); - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorMessage = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; - return res; - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERGROUND) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorMessage = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; - return res; - } - - auto ride = get_ride(_rideIndex); - if (ride == nullptr || ride->type == RIDE_TYPE_NULL) - { - res->Error = GameActions::Status::InvalidParameters; - res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; - return res; - } - - money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); - res->Cost = clearCost + price / 2 * 10; - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - - res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; - res->Expenditure = ExpenditureType::RideConstruction; - res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - res->Error = GameActions::Status::InvalidParameters; - res->ErrorMessage = STR_NONE; - return res; - } - - if (!map_check_free_elements_and_reorganise(1)) - { - res->Error = GameActions::Status::NoFreeElements; - res->ErrorMessage = STR_NONE; - return res; - } - - uint32_t flags = GetFlags(); - if (!(flags & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter(_loc); - wall_remove_at({ _loc.ToTileStart(), _loc.z, _loc.z + 32 }); - } - - auto baseHeight = _loc.z; - auto clearanceHeight = _loc.z + MAZE_CLEARANCE_HEIGHT; - - money32 clearCost = 0; - if (!map_can_construct_with_clear_at( - { _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, - GetFlags() | GAME_COMMAND_FLAG_APPLY, &clearCost, CREATE_CROSSING_MODE_NONE)) - { - return MakeResult( - GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), gGameCommandErrorText, gCommonFormatArgs); - } - - money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); - res->Cost = clearCost + price / 2 * 10; - - auto startLoc = _loc.ToTileStart(); - - auto tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); - - tileElement->SetClearanceZ(clearanceHeight); - tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); - - tileElement->AsTrack()->SetTrackType(TrackElemType::Maze); - tileElement->AsTrack()->SetRideIndex(_rideIndex); - tileElement->AsTrack()->SetMazeEntry(_mazeEntry); - - if (flags & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } - - map_invalidate_tile_full(startLoc); - - ride->maze_tiles++; - ride->stations[0].SetBaseZ(tileElement->GetBaseZ()); - ride->stations[0].Start = { 0, 0 }; - - if (ride->maze_tiles == 1) - { - ride->overall_view = startLoc; - } - - return res; - } -}; diff --git a/src/openrct2/actions/MazeSetTrackAction.cpp b/src/openrct2/actions/MazeSetTrackAction.cpp new file mode 100644 index 0000000000..36be0f0cf3 --- /dev/null +++ b/src/openrct2/actions/MazeSetTrackAction.cpp @@ -0,0 +1,322 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "MazeSetTrackAction.h" + +#include "../Cheats.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../ride/Track.h" +#include "../ride/TrackData.h" +#include "../world/Footpath.h" +#include "../world/Park.h" + +void MazeSetTrackAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("ride", _rideIndex); + visitor.Visit("mode", _mode); + visitor.Visit("isInitialPlacement", _initialPlacement); +} + +void MazeSetTrackAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_loc) << DS_TAG(_loc.direction) << DS_TAG(_initialPlacement) << DS_TAG(_rideIndex) << DS_TAG(_mode); +} + +GameActions::Result::Ptr MazeSetTrackAction::Query() const +{ + auto res = std::make_unique(); + + res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; + res->Expenditure = ExpenditureType::RideConstruction; + res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + if (!map_check_free_elements_and_reorganise(1)) + { + res->Error = GameActions::Status::NoFreeElements; + res->ErrorMessage = STR_TILE_ELEMENT_LIMIT_REACHED; + return res; + } + if ((_loc.z & 0xF) != 0 && _mode == GC_SET_MAZE_TRACK_BUILD) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_CONSTRUCTION_ERR_UNKNOWN; + return res; + } + + if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode)) + { + res->Error = GameActions::Status::NotOwned; + res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; + return res; + } + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; + return res; + } + + auto baseHeight = _loc.z; + auto clearanceHeight = _loc.z + 32; + + auto heightDifference = baseHeight - surfaceElement->GetBaseZ(); + if (heightDifference >= 0 && !gCheatsDisableSupportLimits) + { + heightDifference /= COORDS_Z_PER_TINY_Z; + + if (heightDifference > RideTypeDescriptors[RIDE_TYPE_MAZE].Heights.MaxHeight) + { + res->Error = GameActions::Status::TooHigh; + res->ErrorMessage = STR_TOO_HIGH_FOR_SUPPORTS; + return res; + } + } + + TileElement* tileElement = map_get_track_element_at_of_type_from_ride(_loc, TrackElemType::Maze, _rideIndex); + if (tileElement == nullptr) + { + if (_mode != GC_SET_MAZE_TRACK_BUILD) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; + return res; + } + auto constructResult = MapCanConstructAt({ _loc.ToTileStart(), baseHeight, clearanceHeight }, { 0b1111, 0 }); + if (constructResult->Error != GameActions::Status::Ok) + { + return MakeResult( + GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), constructResult->ErrorMessage.GetStringId(), + constructResult->ErrorMessageArgs.data()); + } + + if (constructResult->GroundFlags & ELEMENT_IS_UNDERWATER) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorMessage = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; + return res; + } + + if (constructResult->GroundFlags & ELEMENT_IS_UNDERGROUND) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorMessage = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + return res; + } + + auto ride = get_ride(_rideIndex); + if (ride == nullptr || ride->type == RIDE_CRASH_TYPE_NONE) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; + return res; + } + + money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); + res->Cost = price / 2 * 10; + + return res; + } + + return std::make_unique(); +} + +GameActions::Result::Ptr MazeSetTrackAction::Execute() const +{ + auto res = std::make_unique(); + + res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; + res->Expenditure = ExpenditureType::RideConstruction; + res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + res->Error = GameActions::Status::InvalidParameters; + res->ErrorMessage = STR_NONE; + return res; + } + + if (!map_check_free_elements_and_reorganise(1)) + { + res->Error = GameActions::Status::NoFreeElements; + res->ErrorMessage = STR_NONE; + return res; + } + + uint32_t flags = GetFlags(); + if (!(flags & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter(_loc); + wall_remove_at({ _loc.ToTileStart(), _loc.z, _loc.z + 32 }); + } + + auto tileElement = map_get_track_element_at_of_type_from_ride(_loc, TrackElemType::Maze, _rideIndex); + if (tileElement == nullptr) + { + money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); + res->Cost = price / 2 * 10; + + auto startLoc = _loc.ToTileStart(); + + tileElement = tile_element_insert(_loc, 0b1111); + assert(tileElement != nullptr); + + tileElement->SetClearanceZ(_loc.z + MAZE_CLEARANCE_HEIGHT); + tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); + + tileElement->AsTrack()->SetTrackType(TrackElemType::Maze); + tileElement->AsTrack()->SetRideIndex(_rideIndex); + tileElement->AsTrack()->SetMazeEntry(0xFFFF); + + if (flags & GAME_COMMAND_FLAG_GHOST) + { + tileElement->SetGhost(true); + } + + map_invalidate_tile_full(startLoc); + + ride->maze_tiles++; + ride->stations[0].SetBaseZ(tileElement->GetBaseZ()); + ride->stations[0].Start = { 0, 0 }; + + if (_initialPlacement && !(flags & GAME_COMMAND_FLAG_GHOST)) + { + ride->overall_view = startLoc; + } + } + + switch (_mode) + { + case GC_SET_MAZE_TRACK_BUILD: + { + uint8_t segmentOffset = MazeGetSegmentBit(_loc.x, _loc.y); + + tileElement->AsTrack()->MazeEntrySubtract(1 << segmentOffset); + + if (!_initialPlacement) + { + segmentOffset = byte_993CE9[(_loc.direction + segmentOffset)]; + tileElement->AsTrack()->MazeEntrySubtract(1 << segmentOffset); + + uint8_t temp_edx = byte_993CFC[segmentOffset]; + if (temp_edx != 0xFF) + { + auto previousElementLoc = CoordsXY{ _loc }.ToTileStart() - CoordsDirectionDelta[_loc.direction]; + + TileElement* previousTileElement = map_get_track_element_at_of_type_from_ride( + { previousElementLoc, _loc.z }, TrackElemType::Maze, _rideIndex); + + if (previousTileElement != nullptr) + { + previousTileElement->AsTrack()->MazeEntrySubtract(1 << temp_edx); + } + else + { + tileElement->AsTrack()->MazeEntryAdd(1 << segmentOffset); + } + } + } + + break; + } + + case GC_SET_MAZE_TRACK_MOVE: + break; + + case GC_SET_MAZE_TRACK_FILL: + if (!_initialPlacement) + { + auto previousSegment = CoordsXY{ _loc.x - CoordsDirectionDelta[_loc.direction].x / 2, + _loc.y - CoordsDirectionDelta[_loc.direction].y / 2 }; + + tileElement = map_get_track_element_at_of_type_from_ride( + { previousSegment, _loc.z }, TrackElemType::Maze, _rideIndex); + + map_invalidate_tile_full(previousSegment.ToTileStart()); + if (tileElement == nullptr) + { + log_error("No surface found"); + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_NONE; + return res; + } + + uint32_t segmentBit = MazeGetSegmentBit(previousSegment.x, previousSegment.y); + + tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); + segmentBit--; + tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); + segmentBit = (segmentBit - 4) & 0x0F; + tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); + segmentBit = (segmentBit + 3) & 0x0F; + + do + { + tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); + + uint32_t direction1 = byte_993D0C[segmentBit]; + auto nextElementLoc = previousSegment.ToTileStart() + CoordsDirectionDelta[direction1]; + + TileElement* tmp_tileElement = map_get_track_element_at_of_type_from_ride( + { nextElementLoc, _loc.z }, TrackElemType::Maze, _rideIndex); + + if (tmp_tileElement != nullptr) + { + uint8_t edx11 = byte_993CFC[segmentBit]; + tmp_tileElement->AsTrack()->MazeEntryAdd(1 << (edx11)); + } + + segmentBit--; + } while ((segmentBit & 0x3) != 0x3); + } + break; + } + + map_invalidate_tile({ _loc.ToTileStart(), tileElement->GetBaseZ(), tileElement->GetClearanceZ() }); + + if ((tileElement->AsTrack()->GetMazeEntry() & 0x8888) == 0x8888) + { + tile_element_remove(tileElement); + sub_6CB945(ride); + ride->maze_tiles--; + } + + return res; +} + +uint8_t MazeSetTrackAction::MazeGetSegmentBit(uint16_t x, uint16_t y) const +{ + uint8_t minorX = x & 0x1F; // 0 or 16 + uint8_t minorY = y & 0x1F; // 0 or 16 + + if (minorX == 0 && minorY == 0) + { + return 3; + } + + if (minorY == 16 && minorX == 16) + { + return 11; + } + + if (minorY == 0) + { + return 15; + } + + return 7; +} diff --git a/src/openrct2/actions/MazeSetTrackAction.h b/src/openrct2/actions/MazeSetTrackAction.h new file mode 100644 index 0000000000..a983cfd458 --- /dev/null +++ b/src/openrct2/actions/MazeSetTrackAction.h @@ -0,0 +1,65 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" +// clang-format off +/** rct2: 0x00993CE9 */ +static constexpr const uint8_t byte_993CE9[] = { + 0xFF, 0xE0, 0xFF, + 14, 0, 1, 2, + 6, 2, 4, 5, + 9, 10, 6, 8, + 12, 13, 14, 10, +}; + +/** rct2: 0x00993CFC */ +static constexpr const uint8_t byte_993CFC[] = { + 5, 12, 0xFF, 0xFF, + 9, 0, 0xFF, 0xFF, + 13, 4, 0xFF, 0xFF, + 1, 8, 0xFF, 0xFF, +}; + +/** rct2: 0x00993D0C */ +static constexpr const uint8_t byte_993D0C[] = { + 3, 0, 0xFF, 0xFF, + 0, 1, 0xFF, 0xFF, + 1, 2, 0xFF, 0xFF, + 2, 3, 0xFF, 0xFF, +}; +// clang-format on + +DEFINE_GAME_ACTION(MazeSetTrackAction, GAME_COMMAND_SET_MAZE_TRACK, GameActions::Result) +{ +private: + CoordsXYZD _loc; + bool _initialPlacement{}; + NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; + uint8_t _mode{}; + +public: + MazeSetTrackAction() = default; + MazeSetTrackAction(const CoordsXYZD& location, bool initialPlacement, NetworkRideId_t rideIndex, uint8_t mode) + : _loc(location) + , _initialPlacement(initialPlacement) + , _rideIndex(rideIndex) + , _mode(mode) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + uint8_t MazeGetSegmentBit(uint16_t x, uint16_t y) const; +}; diff --git a/src/openrct2/actions/MazeSetTrackAction.hpp b/src/openrct2/actions/MazeSetTrackAction.hpp deleted file mode 100644 index 87076c3f0d..0000000000 --- a/src/openrct2/actions/MazeSetTrackAction.hpp +++ /dev/null @@ -1,370 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../ride/Track.h" -#include "../ride/TrackData.h" -#include "../world/Footpath.h" -#include "../world/Park.h" -#include "GameAction.h" -// clang-format off -/** rct2: 0x00993CE9 */ -static constexpr const uint8_t byte_993CE9[] = { - 0xFF, 0xE0, 0xFF, - 14, 0, 1, 2, - 6, 2, 4, 5, - 9, 10, 6, 8, - 12, 13, 14, 10, -}; - -/** rct2: 0x00993CFC */ -static constexpr const uint8_t byte_993CFC[] = { - 5, 12, 0xFF, 0xFF, - 9, 0, 0xFF, 0xFF, - 13, 4, 0xFF, 0xFF, - 1, 8, 0xFF, 0xFF, -}; - -/** rct2: 0x00993D0C */ -static constexpr const uint8_t byte_993D0C[] = { - 3, 0, 0xFF, 0xFF, - 0, 1, 0xFF, 0xFF, - 1, 2, 0xFF, 0xFF, - 2, 3, 0xFF, 0xFF, -}; -// clang-format on - -DEFINE_GAME_ACTION(MazeSetTrackAction, GAME_COMMAND_SET_MAZE_TRACK, GameActions::Result) -{ -private: - CoordsXYZD _loc; - bool _initialPlacement{}; - NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; - uint8_t _mode{}; - -public: - MazeSetTrackAction() = default; - MazeSetTrackAction(const CoordsXYZD& location, bool initialPlacement, NetworkRideId_t rideIndex, uint8_t mode) - : _loc(location) - , _initialPlacement(initialPlacement) - , _rideIndex(rideIndex) - , _mode(mode) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("ride", _rideIndex); - visitor.Visit("mode", _mode); - visitor.Visit("isInitialPlacement", _initialPlacement); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_loc) << DS_TAG(_loc.direction) << DS_TAG(_initialPlacement) << DS_TAG(_rideIndex) << DS_TAG(_mode); - } - - GameActions::Result::Ptr Query() const override - { - auto res = std::make_unique(); - - res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; - res->Expenditure = ExpenditureType::RideConstruction; - res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - if (!map_check_free_elements_and_reorganise(1)) - { - res->Error = GameActions::Status::NoFreeElements; - res->ErrorMessage = STR_TILE_ELEMENT_LIMIT_REACHED; - return res; - } - if ((_loc.z & 0xF) != 0 && _mode == GC_SET_MAZE_TRACK_BUILD) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_CONSTRUCTION_ERR_UNKNOWN; - return res; - } - - if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode)) - { - res->Error = GameActions::Status::NotOwned; - res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; - return res; - } - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; - return res; - } - - auto baseHeight = _loc.z; - auto clearanceHeight = _loc.z + 32; - - auto heightDifference = baseHeight - surfaceElement->GetBaseZ(); - if (heightDifference >= 0 && !gCheatsDisableSupportLimits) - { - heightDifference /= COORDS_Z_PER_TINY_Z; - - if (heightDifference > RideTypeDescriptors[RIDE_TYPE_MAZE].Heights.MaxHeight) - { - res->Error = GameActions::Status::TooHigh; - res->ErrorMessage = STR_TOO_HIGH_FOR_SUPPORTS; - return res; - } - } - - TileElement* tileElement = map_get_track_element_at_of_type_from_ride(_loc, TrackElemType::Maze, _rideIndex); - if (tileElement == nullptr) - { - if (_mode != GC_SET_MAZE_TRACK_BUILD) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; - return res; - } - auto constructResult = MapCanConstructAt({ _loc.ToTileStart(), baseHeight, clearanceHeight }, { 0b1111, 0 }); - if (constructResult->Error != GameActions::Status::Ok) - { - return MakeResult( - GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), - constructResult->ErrorMessage.GetStringId(), constructResult->ErrorMessageArgs.data()); - } - - if (constructResult->GroundFlags & ELEMENT_IS_UNDERWATER) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorMessage = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; - return res; - } - - if (constructResult->GroundFlags & ELEMENT_IS_UNDERGROUND) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorMessage = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; - return res; - } - - auto ride = get_ride(_rideIndex); - if (ride == nullptr || ride->type == RIDE_CRASH_TYPE_NONE) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; - return res; - } - - money32 price = (( - (RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); - res->Cost = price / 2 * 10; - - return res; - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - - res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; - res->Expenditure = ExpenditureType::RideConstruction; - res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - res->Error = GameActions::Status::InvalidParameters; - res->ErrorMessage = STR_NONE; - return res; - } - - if (!map_check_free_elements_and_reorganise(1)) - { - res->Error = GameActions::Status::NoFreeElements; - res->ErrorMessage = STR_NONE; - return res; - } - - uint32_t flags = GetFlags(); - if (!(flags & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter(_loc); - wall_remove_at({ _loc.ToTileStart(), _loc.z, _loc.z + 32 }); - } - - auto tileElement = map_get_track_element_at_of_type_from_ride(_loc, TrackElemType::Maze, _rideIndex); - if (tileElement == nullptr) - { - money32 price = (( - (RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); - res->Cost = price / 2 * 10; - - auto startLoc = _loc.ToTileStart(); - - tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); - - tileElement->SetClearanceZ(_loc.z + MAZE_CLEARANCE_HEIGHT); - tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); - - tileElement->AsTrack()->SetTrackType(TrackElemType::Maze); - tileElement->AsTrack()->SetRideIndex(_rideIndex); - tileElement->AsTrack()->SetMazeEntry(0xFFFF); - - if (flags & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } - - map_invalidate_tile_full(startLoc); - - ride->maze_tiles++; - ride->stations[0].SetBaseZ(tileElement->GetBaseZ()); - ride->stations[0].Start = { 0, 0 }; - - if (_initialPlacement && !(flags & GAME_COMMAND_FLAG_GHOST)) - { - ride->overall_view = startLoc; - } - } - - switch (_mode) - { - case GC_SET_MAZE_TRACK_BUILD: - { - uint8_t segmentOffset = MazeGetSegmentBit(_loc.x, _loc.y); - - tileElement->AsTrack()->MazeEntrySubtract(1 << segmentOffset); - - if (!_initialPlacement) - { - segmentOffset = byte_993CE9[(_loc.direction + segmentOffset)]; - tileElement->AsTrack()->MazeEntrySubtract(1 << segmentOffset); - - uint8_t temp_edx = byte_993CFC[segmentOffset]; - if (temp_edx != 0xFF) - { - auto previousElementLoc = CoordsXY{ _loc }.ToTileStart() - CoordsDirectionDelta[_loc.direction]; - - TileElement* previousTileElement = map_get_track_element_at_of_type_from_ride( - { previousElementLoc, _loc.z }, TrackElemType::Maze, _rideIndex); - - if (previousTileElement != nullptr) - { - previousTileElement->AsTrack()->MazeEntrySubtract(1 << temp_edx); - } - else - { - tileElement->AsTrack()->MazeEntryAdd(1 << segmentOffset); - } - } - } - - break; - } - - case GC_SET_MAZE_TRACK_MOVE: - break; - - case GC_SET_MAZE_TRACK_FILL: - if (!_initialPlacement) - { - auto previousSegment = CoordsXY{ _loc.x - CoordsDirectionDelta[_loc.direction].x / 2, - _loc.y - CoordsDirectionDelta[_loc.direction].y / 2 }; - - tileElement = map_get_track_element_at_of_type_from_ride( - { previousSegment, _loc.z }, TrackElemType::Maze, _rideIndex); - - map_invalidate_tile_full(previousSegment.ToTileStart()); - if (tileElement == nullptr) - { - log_error("No surface found"); - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_NONE; - return res; - } - - uint32_t segmentBit = MazeGetSegmentBit(previousSegment.x, previousSegment.y); - - tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); - segmentBit--; - tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); - segmentBit = (segmentBit - 4) & 0x0F; - tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); - segmentBit = (segmentBit + 3) & 0x0F; - - do - { - tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); - - uint32_t direction1 = byte_993D0C[segmentBit]; - auto nextElementLoc = previousSegment.ToTileStart() + CoordsDirectionDelta[direction1]; - - TileElement* tmp_tileElement = map_get_track_element_at_of_type_from_ride( - { nextElementLoc, _loc.z }, TrackElemType::Maze, _rideIndex); - - if (tmp_tileElement != nullptr) - { - uint8_t edx11 = byte_993CFC[segmentBit]; - tmp_tileElement->AsTrack()->MazeEntryAdd(1 << (edx11)); - } - - segmentBit--; - } while ((segmentBit & 0x3) != 0x3); - } - break; - } - - map_invalidate_tile({ _loc.ToTileStart(), tileElement->GetBaseZ(), tileElement->GetClearanceZ() }); - - if ((tileElement->AsTrack()->GetMazeEntry() & 0x8888) == 0x8888) - { - tile_element_remove(tileElement); - sub_6CB945(ride); - ride->maze_tiles--; - } - - return res; - } - -private: - uint8_t MazeGetSegmentBit(uint16_t x, uint16_t y) const - { - uint8_t minorX = x & 0x1F; // 0 or 16 - uint8_t minorY = y & 0x1F; // 0 or 16 - - if (minorX == 0 && minorY == 0) - { - return 3; - } - - if (minorY == 16 && minorX == 16) - { - return 11; - } - - if (minorY == 0) - { - return 15; - } - - return 7; - } -}; diff --git a/src/openrct2/actions/NetworkModifyGroupAction.cpp b/src/openrct2/actions/NetworkModifyGroupAction.cpp new file mode 100644 index 0000000000..78005032ac --- /dev/null +++ b/src/openrct2/actions/NetworkModifyGroupAction.cpp @@ -0,0 +1,30 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "NetworkModifyGroupAction.h" + +#include "../network/network.h" +#include "../util/Util.h" + +void NetworkModifyGroupAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_type) << DS_TAG(_groupId) << DS_TAG(_name) << DS_TAG(_permissionIndex) << DS_TAG(_permissionState); +} + +GameActions::Result::Ptr NetworkModifyGroupAction::Query() const +{ + return network_modify_groups(GetPlayer(), _type, _groupId, _name, _permissionIndex, _permissionState, false); +} + +GameActions::Result::Ptr NetworkModifyGroupAction::Execute() const +{ + return network_modify_groups(GetPlayer(), _type, _groupId, _name, _permissionIndex, _permissionState, true); +} diff --git a/src/openrct2/actions/NetworkModifyGroupAction.hpp b/src/openrct2/actions/NetworkModifyGroupAction.h similarity index 71% rename from src/openrct2/actions/NetworkModifyGroupAction.hpp rename to src/openrct2/actions/NetworkModifyGroupAction.h index b11bff56de..f99343c542 100644 --- a/src/openrct2/actions/NetworkModifyGroupAction.hpp +++ b/src/openrct2/actions/NetworkModifyGroupAction.h @@ -9,8 +9,6 @@ #pragma once -#include "../network/network.h" -#include "../util/Util.h" #include "GameAction.h" enum class ModifyGroupType : uint8_t @@ -59,20 +57,7 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_type) << DS_TAG(_groupId) << DS_TAG(_name) << DS_TAG(_permissionIndex) << DS_TAG(_permissionState); - } - - GameActions::Result::Ptr Query() const override - { - return network_modify_groups(GetPlayer(), _type, _groupId, _name, _permissionIndex, _permissionState, false); - } - - GameActions::Result::Ptr Execute() const override - { - return network_modify_groups(GetPlayer(), _type, _groupId, _name, _permissionIndex, _permissionState, true); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/ParkEntranceRemoveAction.cpp b/src/openrct2/actions/ParkEntranceRemoveAction.cpp new file mode 100644 index 0000000000..8ece98d28e --- /dev/null +++ b/src/openrct2/actions/ParkEntranceRemoveAction.cpp @@ -0,0 +1,87 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "ParkEntranceRemoveAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../world/Entrance.h" +#include "../world/Park.h" + +void ParkEntranceRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr ParkEntranceRemoveAction::Query() const +{ + if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) + { + return MakeResult(GameActions::Status::NotInEditorMode, STR_CANT_REMOVE_THIS); + } + + auto res = MakeResult(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = _loc; + res->ErrorTitle = STR_CANT_REMOVE_THIS; + + auto entranceIndex = park_entrance_get_index(_loc); + if (!LocationValid(_loc) || entranceIndex == -1) + { + log_error("Could not find entrance at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + return res; +} + +GameActions::Result::Ptr ParkEntranceRemoveAction::Execute() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = _loc; + res->ErrorTitle = STR_CANT_REMOVE_THIS; + + auto entranceIndex = park_entrance_get_index(_loc); + if (entranceIndex == -1) + { + log_error("Could not find entrance at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + auto direction = (gParkEntrances[entranceIndex].direction - 1) & 3; + + // Centre (sign) + ParkEntranceRemoveSegment(_loc); + + // Left post + ParkEntranceRemoveSegment( + { _loc.x + CoordsDirectionDelta[direction].x, _loc.y + CoordsDirectionDelta[direction].y, _loc.z }); + + // Right post + ParkEntranceRemoveSegment( + { _loc.x - CoordsDirectionDelta[direction].x, _loc.y - CoordsDirectionDelta[direction].y, _loc.z }); + + gParkEntrances.erase(gParkEntrances.begin() + entranceIndex); + return res; +} + +void ParkEntranceRemoveAction::ParkEntranceRemoveSegment(const CoordsXYZ& loc) const +{ + auto entranceElement = map_get_park_entrance_element_at(loc, true); + if (entranceElement == nullptr) + { + return; + } + + map_invalidate_tile({ loc, entranceElement->GetBaseZ(), entranceElement->GetClearanceZ() }); + entranceElement->Remove(); + update_park_fences({ loc.x, loc.y }); +} diff --git a/src/openrct2/actions/ParkEntranceRemoveAction.h b/src/openrct2/actions/ParkEntranceRemoveAction.h new file mode 100644 index 0000000000..e62edfdaae --- /dev/null +++ b/src/openrct2/actions/ParkEntranceRemoveAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(ParkEntranceRemoveAction, GAME_COMMAND_REMOVE_PARK_ENTRANCE, GameActions::Result) +{ +private: + CoordsXYZ _loc; + +public: + ParkEntranceRemoveAction() = default; + + ParkEntranceRemoveAction(const CoordsXYZ& loc) + : _loc(loc) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + void ParkEntranceRemoveSegment(const CoordsXYZ& loc) const; +}; diff --git a/src/openrct2/actions/ParkEntranceRemoveAction.hpp b/src/openrct2/actions/ParkEntranceRemoveAction.hpp deleted file mode 100644 index 04e61d332a..0000000000 --- a/src/openrct2/actions/ParkEntranceRemoveAction.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../world/Entrance.h" -#include "../world/Park.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(ParkEntranceRemoveAction, GAME_COMMAND_REMOVE_PARK_ENTRANCE, GameActions::Result) -{ -private: - CoordsXYZ _loc; - -public: - ParkEntranceRemoveAction() = default; - - ParkEntranceRemoveAction(const CoordsXYZ& loc) - : _loc(loc) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) - { - return MakeResult(GameActions::Status::NotInEditorMode, STR_CANT_REMOVE_THIS); - } - - auto res = MakeResult(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = _loc; - res->ErrorTitle = STR_CANT_REMOVE_THIS; - - auto entranceIndex = park_entrance_get_index(_loc); - if (!LocationValid(_loc) || entranceIndex == -1) - { - log_error("Could not find entrance at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = _loc; - res->ErrorTitle = STR_CANT_REMOVE_THIS; - - auto entranceIndex = park_entrance_get_index(_loc); - if (entranceIndex == -1) - { - log_error("Could not find entrance at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - auto direction = (gParkEntrances[entranceIndex].direction - 1) & 3; - - // Centre (sign) - ParkEntranceRemoveSegment(_loc); - - // Left post - ParkEntranceRemoveSegment( - { _loc.x + CoordsDirectionDelta[direction].x, _loc.y + CoordsDirectionDelta[direction].y, _loc.z }); - - // Right post - ParkEntranceRemoveSegment( - { _loc.x - CoordsDirectionDelta[direction].x, _loc.y - CoordsDirectionDelta[direction].y, _loc.z }); - - gParkEntrances.erase(gParkEntrances.begin() + entranceIndex); - return res; - } - -private: - void ParkEntranceRemoveSegment(const CoordsXYZ& loc) const - { - auto entranceElement = map_get_park_entrance_element_at(loc, true); - if (entranceElement == nullptr) - { - return; - } - - map_invalidate_tile({ loc, entranceElement->GetBaseZ(), entranceElement->GetClearanceZ() }); - entranceElement->Remove(); - update_park_fences({ loc.x, loc.y }); - } -}; diff --git a/src/openrct2/actions/ParkMarketingAction.cpp b/src/openrct2/actions/ParkMarketingAction.cpp new file mode 100644 index 0000000000..1be4e4f2f5 --- /dev/null +++ b/src/openrct2/actions/ParkMarketingAction.cpp @@ -0,0 +1,81 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "ParkMarketingAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../management/Marketing.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" +#include "../world/Park.h" + +#include + +void ParkMarketingAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_type) << DS_TAG(_item) << DS_TAG(_numWeeks); +} + +GameActions::Result::Ptr ParkMarketingAction::Query() const +{ + if (static_cast(_type) >= std::size(AdvertisingCampaignPricePerWeek) || _numWeeks >= 256) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_START_MARKETING_CAMPAIGN); + } + if (gParkFlags & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN) + { + return MakeResult( + GameActions::Status::Disallowed, STR_CANT_START_MARKETING_CAMPAIGN, + STR_MARKETING_CAMPAIGNS_FORBIDDEN_BY_LOCAL_AUTHORITY); + } + + return CreateResult(); +} + +GameActions::Result::Ptr ParkMarketingAction::Execute() const +{ + MarketingCampaign campaign{}; + campaign.Type = _type; + campaign.WeeksLeft = _numWeeks; + campaign.Flags = MarketingCampaignFlags::FIRST_WEEK; + if (campaign.Type == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign.Type == ADVERTISING_CAMPAIGN_RIDE) + { + campaign.RideId = _item; + } + else if (campaign.Type == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) + { + campaign.ShopItemType = ShopItem(_item); + } + marketing_new_campaign(campaign); + + // We are only interested in invalidating the finances (marketing) window + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_CASH)); + + return CreateResult(); +} + +GameActions::Result::Ptr ParkMarketingAction::CreateResult() const +{ + auto result = MakeResult(); + result->ErrorTitle = STR_CANT_START_MARKETING_CAMPAIGN; + result->Expenditure = ExpenditureType::Marketing; + result->Cost = CalculatePrice(); + return result; +} + +money32 ParkMarketingAction::CalculatePrice() const +{ + return _numWeeks * AdvertisingCampaignPricePerWeek[_type]; +} diff --git a/src/openrct2/actions/ParkMarketingAction.h b/src/openrct2/actions/ParkMarketingAction.h new file mode 100644 index 0000000000..205b12a0db --- /dev/null +++ b/src/openrct2/actions/ParkMarketingAction.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(ParkMarketingAction, GAME_COMMAND_START_MARKETING_CAMPAIGN, GameActions::Result) +{ +private: + int32_t _type{}; + int32_t _item{}; + int32_t _numWeeks{}; + +public: + ParkMarketingAction() = default; + ParkMarketingAction(int32_t type, int32_t item, int32_t numWeeks) + : _type(type) + , _item(item) + , _numWeeks(numWeeks) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr CreateResult() const; + money32 CalculatePrice() const; +}; diff --git a/src/openrct2/actions/ParkMarketingAction.hpp b/src/openrct2/actions/ParkMarketingAction.hpp deleted file mode 100644 index 91d7b9e481..0000000000 --- a/src/openrct2/actions/ParkMarketingAction.hpp +++ /dev/null @@ -1,105 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../management/Marketing.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "GameAction.h" - -#include - -DEFINE_GAME_ACTION(ParkMarketingAction, GAME_COMMAND_START_MARKETING_CAMPAIGN, GameActions::Result) -{ -private: - int32_t _type{}; - int32_t _item{}; - int32_t _numWeeks{}; - -public: - ParkMarketingAction() = default; - ParkMarketingAction(int32_t type, int32_t item, int32_t numWeeks) - : _type(type) - , _item(item) - , _numWeeks(numWeeks) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_type) << DS_TAG(_item) << DS_TAG(_numWeeks); - } - - GameActions::Result::Ptr Query() const override - { - if (static_cast(_type) >= std::size(AdvertisingCampaignPricePerWeek) || _numWeeks >= 256) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_START_MARKETING_CAMPAIGN); - } - if (gParkFlags & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN) - { - return MakeResult( - GameActions::Status::Disallowed, STR_CANT_START_MARKETING_CAMPAIGN, - STR_MARKETING_CAMPAIGNS_FORBIDDEN_BY_LOCAL_AUTHORITY); - } - - return CreateResult(); - } - - GameActions::Result::Ptr Execute() const override - { - MarketingCampaign campaign{}; - campaign.Type = _type; - campaign.WeeksLeft = _numWeeks; - campaign.Flags = MarketingCampaignFlags::FIRST_WEEK; - if (campaign.Type == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign.Type == ADVERTISING_CAMPAIGN_RIDE) - { - campaign.RideId = _item; - } - else if (campaign.Type == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) - { - campaign.ShopItemType = ShopItem(_item); - } - marketing_new_campaign(campaign); - - // We are only interested in invalidating the finances (marketing) window - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_CASH)); - - return CreateResult(); - } - -private: - GameActions::Result::Ptr CreateResult() const - { - auto result = MakeResult(); - result->ErrorTitle = STR_CANT_START_MARKETING_CAMPAIGN; - result->Expenditure = ExpenditureType::Marketing; - result->Cost = CalculatePrice(); - return result; - } - - money32 CalculatePrice() const - { - return _numWeeks * AdvertisingCampaignPricePerWeek[_type]; - } -}; diff --git a/src/openrct2/actions/ParkSetDateAction.cpp b/src/openrct2/actions/ParkSetDateAction.cpp new file mode 100644 index 0000000000..8d910c2020 --- /dev/null +++ b/src/openrct2/actions/ParkSetDateAction.cpp @@ -0,0 +1,40 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "ParkSetDateAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" + +void ParkSetDateAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_year) << DS_TAG(_month) << DS_TAG(_day); +} + +GameActions::Result::Ptr ParkSetDateAction::Query() const +{ + if (_year <= 0 || _year > MAX_YEAR || _month <= 0 || _month > MONTH_COUNT || _day <= 0 || _day > 31) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr ParkSetDateAction::Execute() const +{ + date_set(_year, _month, _day); + return MakeResult(); +} diff --git a/src/openrct2/actions/ParkSetDateAction.hpp b/src/openrct2/actions/ParkSetDateAction.h similarity index 53% rename from src/openrct2/actions/ParkSetDateAction.hpp rename to src/openrct2/actions/ParkSetDateAction.h index dbb6d44b2a..b986c1e592 100644 --- a/src/openrct2/actions/ParkSetDateAction.hpp +++ b/src/openrct2/actions/ParkSetDateAction.h @@ -9,13 +9,6 @@ #pragma once -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" #include "GameAction.h" DEFINE_GAME_ACTION(ParkSetDateAction, GAME_COMMAND_SET_DATE, GameActions::Result) @@ -39,25 +32,7 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_year) << DS_TAG(_month) << DS_TAG(_day); - } - - GameActions::Result::Ptr Query() const override - { - if (_year <= 0 || _year > MAX_YEAR || _month <= 0 || _month > MONTH_COUNT || _day <= 0 || _day > 31) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - date_set(_year, _month, _day); - return MakeResult(); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/ParkSetLoanAction.cpp b/src/openrct2/actions/ParkSetLoanAction.cpp new file mode 100644 index 0000000000..6dc4473a8f --- /dev/null +++ b/src/openrct2/actions/ParkSetLoanAction.cpp @@ -0,0 +1,56 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "ParkSetLoanAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" + +void ParkSetLoanAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_value); +} + +GameActions::Result::Ptr ParkSetLoanAction::Query() const +{ + auto currentLoan = gBankLoan; + auto loanDifference = currentLoan - _value; + if (_value > currentLoan) + { + if (_value > gMaxBankLoan) + { + return MakeResult( + GameActions::Status::Disallowed, STR_CANT_BORROW_ANY_MORE_MONEY, STR_BANK_REFUSES_TO_INCREASE_LOAN); + } + } + else + { + if (loanDifference > gCash) + { + return MakeResult(GameActions::Status::InsufficientFunds, STR_CANT_PAY_BACK_LOAN, STR_NOT_ENOUGH_CASH_AVAILABLE); + } + } + return MakeResult(); +} + +GameActions::Result::Ptr ParkSetLoanAction::Execute() const +{ + gCash -= (gBankLoan - _value); + gBankLoan = _value; + + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_CASH)); + return MakeResult(); +} diff --git a/src/openrct2/actions/ParkSetLoanAction.h b/src/openrct2/actions/ParkSetLoanAction.h new file mode 100644 index 0000000000..37f0f47443 --- /dev/null +++ b/src/openrct2/actions/ParkSetLoanAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(ParkSetLoanAction, GAME_COMMAND_SET_CURRENT_LOAN, GameActions::Result) +{ +private: + money32 _value{ MONEY32_UNDEFINED }; + +public: + ParkSetLoanAction() = default; + ParkSetLoanAction(money32 value) + : _value(value) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/ParkSetLoanAction.hpp b/src/openrct2/actions/ParkSetLoanAction.hpp deleted file mode 100644 index 61616daceb..0000000000 --- a/src/openrct2/actions/ParkSetLoanAction.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(ParkSetLoanAction, GAME_COMMAND_SET_CURRENT_LOAN, GameActions::Result) -{ -private: - money32 _value{ MONEY32_UNDEFINED }; - -public: - ParkSetLoanAction() = default; - ParkSetLoanAction(money32 value) - : _value(value) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_value); - } - - GameActions::Result::Ptr Query() const override - { - auto currentLoan = gBankLoan; - auto loanDifference = currentLoan - _value; - if (_value > currentLoan) - { - if (_value > gMaxBankLoan) - { - return MakeResult( - GameActions::Status::Disallowed, STR_CANT_BORROW_ANY_MORE_MONEY, STR_BANK_REFUSES_TO_INCREASE_LOAN); - } - } - else - { - if (loanDifference > gCash) - { - return MakeResult( - GameActions::Status::InsufficientFunds, STR_CANT_PAY_BACK_LOAN, STR_NOT_ENOUGH_CASH_AVAILABLE); - } - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - gCash -= (gBankLoan - _value); - gBankLoan = _value; - - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_CASH)); - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/ParkSetNameAction.cpp b/src/openrct2/actions/ParkSetNameAction.cpp new file mode 100644 index 0000000000..da6c52bc45 --- /dev/null +++ b/src/openrct2/actions/ParkSetNameAction.cpp @@ -0,0 +1,56 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "ParkSetNameAction.h" + +#include "../Context.h" +#include "../GameState.h" +#include "../config/Config.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../localisation/Localisation.h" +#include "../management/Finance.h" +#include "../network/network.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" +#include "../world/Park.h" + +void ParkSetNameAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("name", _name); +} + +void ParkSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_name); +} + +GameActions::Result::Ptr ParkSetNameAction::Query() const +{ + if (_name.empty()) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_RENAME_PARK, STR_INVALID_NAME_FOR_PARK); + } + return MakeResult(); +} + +GameActions::Result::Ptr ParkSetNameAction::Execute() const +{ + // Do a no-op if new name is the same as the current name is the same + auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); + if (_name != park.Name) + { + park.Name = _name; + scrolling_text_invalidate(); + gfx_invalidate_screen(); + } + return MakeResult(); +} diff --git a/src/openrct2/actions/ParkSetNameAction.h b/src/openrct2/actions/ParkSetNameAction.h new file mode 100644 index 0000000000..66775fba35 --- /dev/null +++ b/src/openrct2/actions/ParkSetNameAction.h @@ -0,0 +1,36 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(ParkSetNameAction, GAME_COMMAND_SET_PARK_NAME, GameActions::Result) +{ +private: + std::string _name; + +public: + ParkSetNameAction() = default; + ParkSetNameAction(const std::string& name) + : _name(name) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/ParkSetNameAction.hpp b/src/openrct2/actions/ParkSetNameAction.hpp deleted file mode 100644 index a36dbff702..0000000000 --- a/src/openrct2/actions/ParkSetNameAction.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../GameState.h" -#include "../config/Config.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../localisation/Localisation.h" -#include "../management/Finance.h" -#include "../network/network.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(ParkSetNameAction, GAME_COMMAND_SET_PARK_NAME, GameActions::Result) -{ -private: - std::string _name; - -public: - ParkSetNameAction() = default; - ParkSetNameAction(const std::string& name) - : _name(name) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("name", _name); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - if (_name.empty()) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_RENAME_PARK, STR_INVALID_NAME_FOR_PARK); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - // Do a no-op if new name is the same as the current name is the same - auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); - if (_name != park.Name) - { - park.Name = _name; - scrolling_text_invalidate(); - gfx_invalidate_screen(); - } - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/ParkSetParameterAction.cpp b/src/openrct2/actions/ParkSetParameterAction.cpp new file mode 100644 index 0000000000..ddd5e0a670 --- /dev/null +++ b/src/openrct2/actions/ParkSetParameterAction.cpp @@ -0,0 +1,64 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "ParkSetParameterAction.h" + +#include "../interface/Window.h" +#include "../ride/ShopItem.h" +#include "../util/Util.h" +#include "../world/Park.h" + +void ParkSetParameterAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_parameter) << DS_TAG(_value); +} + +GameActions::Result::Ptr ParkSetParameterAction::Query() const +{ + if (_parameter >= ParkParameter::Count) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto res = MakeResult(); + res->ErrorTitle = _ErrorTitles[EnumValue(_parameter)]; + return res; +} + +GameActions::Result::Ptr ParkSetParameterAction::Execute() const +{ + switch (_parameter) + { + case ParkParameter::Close: + if (gParkFlags & PARK_FLAGS_PARK_OPEN) + { + gParkFlags &= ~PARK_FLAGS_PARK_OPEN; + window_invalidate_by_class(WC_PARK_INFORMATION); + } + break; + case ParkParameter::Open: + if (!(gParkFlags & PARK_FLAGS_PARK_OPEN)) + { + gParkFlags |= PARK_FLAGS_PARK_OPEN; + window_invalidate_by_class(WC_PARK_INFORMATION); + } + break; + case ParkParameter::SamePriceInPark: + gSamePriceThroughoutPark = _value; + window_invalidate_by_class(WC_RIDE); + break; + default: + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto res = MakeResult(); + res->ErrorTitle = _ErrorTitles[EnumValue(_parameter)]; + return res; +} \ No newline at end of file diff --git a/src/openrct2/actions/ParkSetParameterAction.h b/src/openrct2/actions/ParkSetParameterAction.h new file mode 100644 index 0000000000..7de96cefa6 --- /dev/null +++ b/src/openrct2/actions/ParkSetParameterAction.h @@ -0,0 +1,46 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +enum class ParkParameter : uint8_t +{ + Close, + Open, + SamePriceInPark, + Count +}; + +DEFINE_GAME_ACTION(ParkSetParameterAction, GAME_COMMAND_SET_PARK_OPEN, GameActions::Result) +{ +private: + ParkParameter _parameter{ ParkParameter::Count }; + uint64_t _value{}; + + constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_CLOSE_PARK, STR_CANT_OPEN_PARK, STR_NONE, STR_NONE }; + +public: + ParkSetParameterAction() = default; + ParkSetParameterAction(ParkParameter parameter, uint64_t value = 0) + : _parameter(parameter) + , _value(value) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/ParkSetParameterAction.hpp b/src/openrct2/actions/ParkSetParameterAction.hpp deleted file mode 100644 index 2765668fad..0000000000 --- a/src/openrct2/actions/ParkSetParameterAction.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../interface/Window.h" -#include "../ride/ShopItem.h" -#include "../util/Util.h" -#include "../world/Park.h" -#include "GameAction.h" - -enum class ParkParameter : uint8_t -{ - Close, - Open, - SamePriceInPark, - Count -}; - -DEFINE_GAME_ACTION(ParkSetParameterAction, GAME_COMMAND_SET_PARK_OPEN, GameActions::Result) -{ -private: - ParkParameter _parameter{ ParkParameter::Count }; - uint64_t _value{}; - - constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_CLOSE_PARK, STR_CANT_OPEN_PARK, STR_NONE, STR_NONE }; - -public: - ParkSetParameterAction() = default; - ParkSetParameterAction(ParkParameter parameter, uint64_t value = 0) - : _parameter(parameter) - , _value(value) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_parameter) << DS_TAG(_value); - } - - GameActions::Result::Ptr Query() const override - { - if (_parameter >= ParkParameter::Count) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto res = MakeResult(); - res->ErrorTitle = _ErrorTitles[EnumValue(_parameter)]; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - switch (_parameter) - { - case ParkParameter::Close: - if (gParkFlags & PARK_FLAGS_PARK_OPEN) - { - gParkFlags &= ~PARK_FLAGS_PARK_OPEN; - window_invalidate_by_class(WC_PARK_INFORMATION); - } - break; - case ParkParameter::Open: - if (!(gParkFlags & PARK_FLAGS_PARK_OPEN)) - { - gParkFlags |= PARK_FLAGS_PARK_OPEN; - window_invalidate_by_class(WC_PARK_INFORMATION); - } - break; - case ParkParameter::SamePriceInPark: - gSamePriceThroughoutPark = _value; - window_invalidate_by_class(WC_RIDE); - break; - default: - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - break; - } - - auto res = MakeResult(); - res->ErrorTitle = _ErrorTitles[EnumValue(_parameter)]; - return res; - } -}; diff --git a/src/openrct2/actions/ParkSetResearchFundingAction.cpp b/src/openrct2/actions/ParkSetResearchFundingAction.cpp new file mode 100644 index 0000000000..82d8ea2645 --- /dev/null +++ b/src/openrct2/actions/ParkSetResearchFundingAction.cpp @@ -0,0 +1,43 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "ParkSetResearchFundingAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Research.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" + +void ParkSetResearchFundingAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_priorities) << DS_TAG(_fundingAmount); +} + +GameActions::Result::Ptr ParkSetResearchFundingAction::Query() const +{ + if (_fundingAmount >= RESEARCH_FUNDING_COUNT) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return MakeResult(); +} + +GameActions::Result::Ptr ParkSetResearchFundingAction::Execute() const +{ + gResearchPriorities = _priorities; + gResearchFundingLevel = _fundingAmount; + + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_RESEARCH)); + return MakeResult(); +} diff --git a/src/openrct2/actions/ParkSetResearchFundingAction.hpp b/src/openrct2/actions/ParkSetResearchFundingAction.h similarity index 51% rename from src/openrct2/actions/ParkSetResearchFundingAction.hpp rename to src/openrct2/actions/ParkSetResearchFundingAction.h index 711fe3762e..ae1c00c566 100644 --- a/src/openrct2/actions/ParkSetResearchFundingAction.hpp +++ b/src/openrct2/actions/ParkSetResearchFundingAction.h @@ -9,13 +9,6 @@ #pragma once -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Research.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" #include "GameAction.h" DEFINE_GAME_ACTION(ParkSetResearchFundingAction, GAME_COMMAND_SET_RESEARCH_FUNDING, GameActions::Result) @@ -38,28 +31,7 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_priorities) << DS_TAG(_fundingAmount); - } - - GameActions::Result::Ptr Query() const override - { - if (_fundingAmount >= RESEARCH_FUNDING_COUNT) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - gResearchPriorities = _priorities; - gResearchFundingLevel = _fundingAmount; - - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_RESEARCH)); - return MakeResult(); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/PauseToggleAction.cpp b/src/openrct2/actions/PauseToggleAction.cpp new file mode 100644 index 0000000000..467e33b27c --- /dev/null +++ b/src/openrct2/actions/PauseToggleAction.cpp @@ -0,0 +1,16 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "PauseToggleAction.h" + +GameActions::Result::Ptr PauseToggleAction::Execute() const +{ + pause_toggle(); + return std::make_unique(); +} diff --git a/src/openrct2/actions/PauseToggleAction.hpp b/src/openrct2/actions/PauseToggleAction.h similarity index 86% rename from src/openrct2/actions/PauseToggleAction.hpp rename to src/openrct2/actions/PauseToggleAction.h index b25daa5705..6fbb926b6d 100644 --- a/src/openrct2/actions/PauseToggleAction.hpp +++ b/src/openrct2/actions/PauseToggleAction.h @@ -28,10 +28,6 @@ public: return std::make_unique(); } - GameActions::Result::Ptr Execute() const override - { - pause_toggle(); - return std::make_unique(); - } + GameActions::Result::Ptr Execute() const override; }; // clang-format on diff --git a/src/openrct2/actions/PeepPickupAction.cpp b/src/openrct2/actions/PeepPickupAction.cpp new file mode 100644 index 0000000000..4be81c6eeb --- /dev/null +++ b/src/openrct2/actions/PeepPickupAction.cpp @@ -0,0 +1,181 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "PeepPickupAction.h" + +#include "../Input.h" +#include "../network/network.h" +#include "../util/Util.h" + +void PeepPickupAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_type) << DS_TAG(_spriteId) << DS_TAG(_loc) << DS_TAG(_owner); +} + +GameActions::Result::Ptr PeepPickupAction::Query() const +{ + if (_spriteId >= MAX_SPRITES || _spriteId == SPRITE_INDEX_NULL) + { + log_error("Failed to pick up peep for sprite %d", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + + if (!_loc.isNull() && !LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + + auto* const peep = TryGetEntity(_spriteId); + if (!peep || peep->sprite_identifier != SpriteIdentifier::Peep) + { + log_error("Failed to pick up peep for sprite %d", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + + auto res = MakeResult(); + + switch (_type) + { + case PeepPickupType::Pickup: + { + res->Position = { peep->x, peep->y, peep->z }; + if (!peep_can_be_picked_up(peep)) + { + return MakeResult(GameActions::Status::Disallowed, STR_ERR_CANT_PLACE_PERSON_HERE); + } + Peep* existing = network_get_pickup_peep(_owner); + if (existing) + { + // already picking up a peep + PeepPickupAction existingPickupAction{ + PeepPickupType::Cancel, existing->sprite_index, { network_get_pickup_peep_old_x(_owner), 0, 0 }, _owner + }; + auto result = GameActions::QueryNested(&existingPickupAction); + + if (existing == peep) + { + return result; + } + } + } + break; + case PeepPickupType::Cancel: + res->Position = { peep->x, peep->y, peep->z }; + break; + case PeepPickupType::Place: + res->Position = _loc; + if (network_get_pickup_peep(_owner) != peep) + { + return MakeResult(GameActions::Status::Unknown, STR_ERR_CANT_PLACE_PERSON_HERE); + } + + if (auto res2 = peep->Place(TileCoordsXYZ(_loc), false); res2->Error != GameActions::Status::Ok) + { + return res2; + } + break; + default: + log_error("Invalid pickup type: %u", _type); + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + return res; +} + +GameActions::Result::Ptr PeepPickupAction::Execute() const +{ + Peep* const peep = TryGetEntity(_spriteId); + if (!peep || peep->sprite_identifier != SpriteIdentifier::Peep) + { + log_error("Failed to pick up peep for sprite %d", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + + auto res = MakeResult(); + + switch (_type) + { + case PeepPickupType::Pickup: + { + res->Position = { peep->x, peep->y, peep->z }; + + Peep* existing = network_get_pickup_peep(_owner); + if (existing) + { + // already picking up a peep + PeepPickupAction existingPickupAction{ + PeepPickupType::Cancel, existing->sprite_index, { network_get_pickup_peep_old_x(_owner), 0, 0 }, _owner + }; + auto result = GameActions::ExecuteNested(&existingPickupAction); + + if (existing == peep) + { + return result; + } + if (_owner == network_get_current_player_id()) + { + // prevent tool_cancel() + input_set_flag(INPUT_FLAG_TOOL_ACTIVE, false); + } + } + + network_set_pickup_peep(_owner, peep); + network_set_pickup_peep_old_x(_owner, peep->x); + peep->Pickup(); + } + break; + case PeepPickupType::Cancel: + { + res->Position = { peep->x, peep->y, peep->z }; + + Peep* const pickedUpPeep = network_get_pickup_peep(_owner); + if (pickedUpPeep) + { + pickedUpPeep->PickupAbort(_loc.x); + } + + network_set_pickup_peep(_owner, nullptr); + } + break; + case PeepPickupType::Place: + res->Position = _loc; + if (auto res2 = peep->Place(TileCoordsXYZ(_loc), true); res2->Error != GameActions::Status::Ok) + { + return res2; + } + CancelConcurrentPickups(peep); + break; + default: + log_error("Invalid pickup type: %u", _type); + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + return res; +} + +void PeepPickupAction::CancelConcurrentPickups(Peep* pickedPeep) const +{ + // This part is only relevant in multiplayer games. + if (network_get_mode() == NETWORK_MODE_NONE) + return; + + // Not relevant for owner, owner gets to place it normally. + NetworkPlayerId_t currentPlayerId = network_get_current_player_id(); + if (currentPlayerId == _owner) + return; + + Peep* peep = network_get_pickup_peep(network_get_current_player_id()); + if (peep != pickedPeep) + return; + + // By assigning the peep to null before calling tool_cancel we can avoid + // resetting the peep to the initial position. + network_set_pickup_peep(currentPlayerId, nullptr); + tool_cancel(); +} diff --git a/src/openrct2/actions/PeepPickupAction.h b/src/openrct2/actions/PeepPickupAction.h new file mode 100644 index 0000000000..58546696b1 --- /dev/null +++ b/src/openrct2/actions/PeepPickupAction.h @@ -0,0 +1,52 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/Sprite.h" +#include "GameAction.h" + +enum class PeepPickupType : uint8_t +{ + Pickup, + Cancel, + Place, + Count +}; + +DEFINE_GAME_ACTION(PeepPickupAction, GAME_COMMAND_PICKUP_GUEST, GameActions::Result) +{ +private: + PeepPickupType _type{ PeepPickupType::Count }; + uint32_t _spriteId{ SPRITE_INDEX_NULL }; + CoordsXYZ _loc; + NetworkPlayerId_t _owner{ -1 }; + +public: + PeepPickupAction() = default; + PeepPickupAction(PeepPickupType type, uint32_t spriteId, const CoordsXYZ& loc, NetworkPlayerId_t owner) + : _type(type) + , _spriteId(spriteId) + , _loc(loc) + , _owner(owner) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + void CancelConcurrentPickups(Peep * pickedPeep) const; +}; diff --git a/src/openrct2/actions/PeepPickupAction.hpp b/src/openrct2/actions/PeepPickupAction.hpp deleted file mode 100644 index 3bf32f36e7..0000000000 --- a/src/openrct2/actions/PeepPickupAction.hpp +++ /dev/null @@ -1,218 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Input.h" -#include "../network/network.h" -#include "../util/Util.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -enum class PeepPickupType : uint8_t -{ - Pickup, - Cancel, - Place, - Count -}; - -DEFINE_GAME_ACTION(PeepPickupAction, GAME_COMMAND_PICKUP_GUEST, GameActions::Result) -{ -private: - PeepPickupType _type{ PeepPickupType::Count }; - uint32_t _spriteId{ SPRITE_INDEX_NULL }; - CoordsXYZ _loc; - NetworkPlayerId_t _owner{ -1 }; - -public: - PeepPickupAction() = default; - PeepPickupAction(PeepPickupType type, uint32_t spriteId, const CoordsXYZ& loc, NetworkPlayerId_t owner) - : _type(type) - , _spriteId(spriteId) - , _loc(loc) - , _owner(owner) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_type) << DS_TAG(_spriteId) << DS_TAG(_loc) << DS_TAG(_owner); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteId >= MAX_SPRITES || _spriteId == SPRITE_INDEX_NULL) - { - log_error("Failed to pick up peep for sprite %d", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - } - - if (!_loc.isNull() && !LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - } - - auto* const peep = TryGetEntity(_spriteId); - if (!peep || peep->sprite_identifier != SpriteIdentifier::Peep) - { - log_error("Failed to pick up peep for sprite %d", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - } - - auto res = MakeResult(); - - switch (_type) - { - case PeepPickupType::Pickup: - { - res->Position = { peep->x, peep->y, peep->z }; - if (!peep_can_be_picked_up(peep)) - { - return MakeResult(GameActions::Status::Disallowed, STR_ERR_CANT_PLACE_PERSON_HERE); - } - Peep* existing = network_get_pickup_peep(_owner); - if (existing) - { - // already picking up a peep - PeepPickupAction existingPickupAction{ - PeepPickupType::Cancel, existing->sprite_index, { network_get_pickup_peep_old_x(_owner), 0, 0 }, _owner - }; - auto result = GameActions::QueryNested(&existingPickupAction); - - if (existing == peep) - { - return result; - } - } - } - break; - case PeepPickupType::Cancel: - res->Position = { peep->x, peep->y, peep->z }; - break; - case PeepPickupType::Place: - res->Position = _loc; - if (network_get_pickup_peep(_owner) != peep) - { - return MakeResult(GameActions::Status::Unknown, STR_ERR_CANT_PLACE_PERSON_HERE); - } - - if (auto res2 = peep->Place(TileCoordsXYZ(_loc), false); res2->Error != GameActions::Status::Ok) - { - return res2; - } - break; - default: - log_error("Invalid pickup type: %u", _type); - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - break; - } - return res; - } - - GameActions::Result::Ptr Execute() const override - { - Peep* const peep = TryGetEntity(_spriteId); - if (!peep || peep->sprite_identifier != SpriteIdentifier::Peep) - { - log_error("Failed to pick up peep for sprite %d", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - } - - auto res = MakeResult(); - - switch (_type) - { - case PeepPickupType::Pickup: - { - res->Position = { peep->x, peep->y, peep->z }; - - Peep* existing = network_get_pickup_peep(_owner); - if (existing) - { - // already picking up a peep - PeepPickupAction existingPickupAction{ - PeepPickupType::Cancel, existing->sprite_index, { network_get_pickup_peep_old_x(_owner), 0, 0 }, _owner - }; - auto result = GameActions::ExecuteNested(&existingPickupAction); - - if (existing == peep) - { - return result; - } - if (_owner == network_get_current_player_id()) - { - // prevent tool_cancel() - input_set_flag(INPUT_FLAG_TOOL_ACTIVE, false); - } - } - - network_set_pickup_peep(_owner, peep); - network_set_pickup_peep_old_x(_owner, peep->x); - peep->Pickup(); - } - break; - case PeepPickupType::Cancel: - { - res->Position = { peep->x, peep->y, peep->z }; - - Peep* const pickedUpPeep = network_get_pickup_peep(_owner); - if (pickedUpPeep) - { - pickedUpPeep->PickupAbort(_loc.x); - } - - network_set_pickup_peep(_owner, nullptr); - } - break; - case PeepPickupType::Place: - res->Position = _loc; - if (auto res2 = peep->Place(TileCoordsXYZ(_loc), true); res2->Error != GameActions::Status::Ok) - { - return res2; - } - CancelConcurrentPickups(peep); - break; - default: - log_error("Invalid pickup type: %u", _type); - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - break; - } - return res; - } - -private: - void CancelConcurrentPickups(Peep * pickedPeep) const - { - // This part is only relevant in multiplayer games. - if (network_get_mode() == NETWORK_MODE_NONE) - return; - - // Not relevant for owner, owner gets to place it normally. - NetworkPlayerId_t currentPlayerId = network_get_current_player_id(); - if (currentPlayerId == _owner) - return; - - Peep* peep = network_get_pickup_peep(network_get_current_player_id()); - if (peep != pickedPeep) - return; - - // By assigning the peep to null before calling tool_cancel we can avoid - // resetting the peep to the initial position. - network_set_pickup_peep(currentPlayerId, nullptr); - tool_cancel(); - } -}; diff --git a/src/openrct2/actions/PlaceParkEntranceAction.cpp b/src/openrct2/actions/PlaceParkEntranceAction.cpp new file mode 100644 index 0000000000..f452e479fd --- /dev/null +++ b/src/openrct2/actions/PlaceParkEntranceAction.cpp @@ -0,0 +1,175 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "PlaceParkEntranceAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Entrance.h" +#include "../world/Footpath.h" +#include "../world/MapAnimation.h" +#include "../world/Park.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void PlaceParkEntranceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr PlaceParkEntranceAction::Query() const +{ + if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) + { + return std::make_unique( + GameActions::Status::NotInEditorMode, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); + } + + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = { _loc.x, _loc.y, _loc.z }; + + if (!map_check_free_elements_and_reorganise(3)) + { + return std::make_unique( + GameActions::Status::NoFreeElements, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); + } + + if (!LocationValid(_loc) || _loc.x <= 32 || _loc.y <= 32 || _loc.x >= (gMapSizeUnits - 32) + || _loc.y >= (gMapSizeUnits - 32)) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_TOO_CLOSE_TO_EDGE_OF_MAP); + } + + if (gParkEntrances.size() >= MAX_PARK_ENTRANCES) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_ERR_TOO_MANY_PARK_ENTRANCES); + } + + auto zLow = _loc.z; + auto zHigh = zLow + ParkEntranceHeight; + CoordsXYZ entranceLoc = _loc; + for (uint8_t index = 0; index < 3; index++) + { + if (index == 1) + { + entranceLoc += CoordsDirectionDelta[(_loc.direction - 1) & 0x3]; + } + else if (index == 2) + { + entranceLoc.x += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].x * 2; + entranceLoc.y += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].y * 2; + } + + if (auto res2 = MapCanConstructAt({ entranceLoc, zLow, zHigh }, { 0b1111, 0 }); res2->Error != GameActions::Status::Ok) + { + return std::make_unique( + GameActions::Status::NoClearance, STR_CANT_BUILD_PARK_ENTRANCE_HERE, res2->ErrorMessage.GetStringId(), + res2->ErrorMessageArgs.data()); + } + + // Check that entrance element does not already exist at this location + EntranceElement* entranceElement = map_get_park_entrance_element_at(entranceLoc, false); + if (entranceElement != nullptr) + { + return std::make_unique( + GameActions::Status::ItemAlreadyPlaced, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); + } + } + + return res; +} + +GameActions::Result::Ptr PlaceParkEntranceAction::Execute() const +{ + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = CoordsXYZ{ _loc.x, _loc.y, _loc.z }; + + uint32_t flags = GetFlags(); + + CoordsXYZD parkEntrance; + parkEntrance = _loc; + + gParkEntrances.push_back(parkEntrance); + + auto zLow = _loc.z; + auto zHigh = zLow + ParkEntranceHeight; + CoordsXY entranceLoc = { _loc.x, _loc.y }; + for (uint8_t index = 0; index < 3; index++) + { + if (index == 1) + { + entranceLoc.x += CoordsDirectionDelta[(_loc.direction - 1) & 0x3].x; + entranceLoc.y += CoordsDirectionDelta[(_loc.direction - 1) & 0x3].y; + } + else if (index == 2) + { + entranceLoc.x += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].x * 2; + entranceLoc.y += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].y * 2; + } + + if (!(flags & GAME_COMMAND_FLAG_GHOST)) + { + SurfaceElement* surfaceElement = map_get_surface_element_at(entranceLoc); + if (surfaceElement != nullptr) + { + surfaceElement->SetOwnership(OWNERSHIP_UNOWNED); + } + } + + TileElement* newElement = tile_element_insert(CoordsXYZ{ entranceLoc, zLow }, 0b1111); + Guard::Assert(newElement != nullptr); + newElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); + auto entranceElement = newElement->AsEntrance(); + if (entranceElement == nullptr) + { + Guard::Assert(false); + return nullptr; + } + entranceElement->SetClearanceZ(zHigh); + + if (flags & GAME_COMMAND_FLAG_GHOST) + { + newElement->SetGhost(true); + } + + entranceElement->SetDirection(_loc.direction); + entranceElement->SetSequenceIndex(index); + entranceElement->SetEntranceType(ENTRANCE_TYPE_PARK_ENTRANCE); + entranceElement->SetPathType(gFootpathSelectedId); + + if (!(flags & GAME_COMMAND_FLAG_GHOST)) + { + footpath_connect_edges(entranceLoc, newElement, GAME_COMMAND_FLAG_APPLY); + } + + update_park_fences(entranceLoc); + update_park_fences({ entranceLoc.x - COORDS_XY_STEP, entranceLoc.y }); + update_park_fences({ entranceLoc.x + COORDS_XY_STEP, entranceLoc.y }); + update_park_fences({ entranceLoc.x, entranceLoc.y - COORDS_XY_STEP }); + update_park_fences({ entranceLoc.x, entranceLoc.y + COORDS_XY_STEP }); + + map_invalidate_tile({ entranceLoc, newElement->GetBaseZ(), newElement->GetClearanceZ() }); + + if (index == 0) + { + map_animation_create(MAP_ANIMATION_TYPE_PARK_ENTRANCE, { entranceLoc, zLow }); + } + } + + return res; +} diff --git a/src/openrct2/actions/PlaceParkEntranceAction.h b/src/openrct2/actions/PlaceParkEntranceAction.h new file mode 100644 index 0000000000..2c53b8c383 --- /dev/null +++ b/src/openrct2/actions/PlaceParkEntranceAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(PlaceParkEntranceAction, GAME_COMMAND_PLACE_PARK_ENTRANCE, GameActions::Result) +{ +private: + CoordsXYZD _loc; + +public: + PlaceParkEntranceAction() = default; + PlaceParkEntranceAction(const CoordsXYZD& location) + : _loc(location) + { + } + + uint16_t GetActionFlags() const override + { + return GameActionBase::GetActionFlags() | GameActions::Flags::EditorOnly; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/PlaceParkEntranceAction.hpp b/src/openrct2/actions/PlaceParkEntranceAction.hpp deleted file mode 100644 index 1960a50fc2..0000000000 --- a/src/openrct2/actions/PlaceParkEntranceAction.hpp +++ /dev/null @@ -1,195 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Entrance.h" -#include "../world/Footpath.h" -#include "../world/MapAnimation.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(PlaceParkEntranceAction, GAME_COMMAND_PLACE_PARK_ENTRANCE, GameActions::Result) -{ -private: - CoordsXYZD _loc; - -public: - PlaceParkEntranceAction() = default; - PlaceParkEntranceAction(const CoordsXYZD& location) - : _loc(location) - { - } - - uint16_t GetActionFlags() const override - { - return GameActionBase::GetActionFlags() | GameActions::Flags::EditorOnly; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) - { - return std::make_unique( - GameActions::Status::NotInEditorMode, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); - } - - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = { _loc.x, _loc.y, _loc.z }; - - if (!map_check_free_elements_and_reorganise(3)) - { - return std::make_unique( - GameActions::Status::NoFreeElements, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); - } - - if (!LocationValid(_loc) || _loc.x <= 32 || _loc.y <= 32 || _loc.x >= (gMapSizeUnits - 32) - || _loc.y >= (gMapSizeUnits - 32)) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_TOO_CLOSE_TO_EDGE_OF_MAP); - } - - if (gParkEntrances.size() >= MAX_PARK_ENTRANCES) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_ERR_TOO_MANY_PARK_ENTRANCES); - } - - auto zLow = _loc.z; - auto zHigh = zLow + ParkEntranceHeight; - CoordsXYZ entranceLoc = _loc; - for (uint8_t index = 0; index < 3; index++) - { - if (index == 1) - { - entranceLoc += CoordsDirectionDelta[(_loc.direction - 1) & 0x3]; - } - else if (index == 2) - { - entranceLoc.x += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].x * 2; - entranceLoc.y += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].y * 2; - } - - if (auto res2 = MapCanConstructAt({ entranceLoc, zLow, zHigh }, { 0b1111, 0 }); - res2->Error != GameActions::Status::Ok) - { - return std::make_unique( - GameActions::Status::NoClearance, STR_CANT_BUILD_PARK_ENTRANCE_HERE, res2->ErrorMessage.GetStringId(), - res2->ErrorMessageArgs.data()); - } - - // Check that entrance element does not already exist at this location - EntranceElement* entranceElement = map_get_park_entrance_element_at(entranceLoc, false); - if (entranceElement != nullptr) - { - return std::make_unique( - GameActions::Status::ItemAlreadyPlaced, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); - } - } - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = CoordsXYZ{ _loc.x, _loc.y, _loc.z }; - - uint32_t flags = GetFlags(); - - CoordsXYZD parkEntrance; - parkEntrance = _loc; - - gParkEntrances.push_back(parkEntrance); - - auto zLow = _loc.z; - auto zHigh = zLow + ParkEntranceHeight; - CoordsXY entranceLoc = { _loc.x, _loc.y }; - for (uint8_t index = 0; index < 3; index++) - { - if (index == 1) - { - entranceLoc.x += CoordsDirectionDelta[(_loc.direction - 1) & 0x3].x; - entranceLoc.y += CoordsDirectionDelta[(_loc.direction - 1) & 0x3].y; - } - else if (index == 2) - { - entranceLoc.x += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].x * 2; - entranceLoc.y += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].y * 2; - } - - if (!(flags & GAME_COMMAND_FLAG_GHOST)) - { - SurfaceElement* surfaceElement = map_get_surface_element_at(entranceLoc); - if (surfaceElement != nullptr) - { - surfaceElement->SetOwnership(OWNERSHIP_UNOWNED); - } - } - - TileElement* newElement = tile_element_insert(CoordsXYZ{ entranceLoc, zLow }, 0b1111); - Guard::Assert(newElement != nullptr); - newElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); - auto entranceElement = newElement->AsEntrance(); - if (entranceElement == nullptr) - { - Guard::Assert(false); - return nullptr; - } - entranceElement->SetClearanceZ(zHigh); - - if (flags & GAME_COMMAND_FLAG_GHOST) - { - newElement->SetGhost(true); - } - - entranceElement->SetDirection(_loc.direction); - entranceElement->SetSequenceIndex(index); - entranceElement->SetEntranceType(ENTRANCE_TYPE_PARK_ENTRANCE); - entranceElement->SetPathType(gFootpathSelectedId); - - if (!(flags & GAME_COMMAND_FLAG_GHOST)) - { - footpath_connect_edges(entranceLoc, newElement, GAME_COMMAND_FLAG_APPLY); - } - - update_park_fences(entranceLoc); - update_park_fences({ entranceLoc.x - COORDS_XY_STEP, entranceLoc.y }); - update_park_fences({ entranceLoc.x + COORDS_XY_STEP, entranceLoc.y }); - update_park_fences({ entranceLoc.x, entranceLoc.y - COORDS_XY_STEP }); - update_park_fences({ entranceLoc.x, entranceLoc.y + COORDS_XY_STEP }); - - map_invalidate_tile({ entranceLoc, newElement->GetBaseZ(), newElement->GetClearanceZ() }); - - if (index == 0) - { - map_animation_create(MAP_ANIMATION_TYPE_PARK_ENTRANCE, { entranceLoc, zLow }); - } - } - - return res; - } -}; diff --git a/src/openrct2/actions/PlacePeepSpawnAction.cpp b/src/openrct2/actions/PlacePeepSpawnAction.cpp new file mode 100644 index 0000000000..a9bc934acf --- /dev/null +++ b/src/openrct2/actions/PlacePeepSpawnAction.cpp @@ -0,0 +1,128 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "PlacePeepSpawnAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Park.h" +#include "../world/Surface.h" + +void PlacePeepSpawnAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_location.x) << DS_TAG(_location.y) << DS_TAG(_location.z) << DS_TAG(_location.direction); +} + +GameActions::Result::Ptr PlacePeepSpawnAction::Query() const +{ + if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) + { + return std::make_unique( + GameActions::Status::NotInEditorMode, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); + } + + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = _location; + + if (!map_check_free_elements_and_reorganise(3)) + { + return std::make_unique( + GameActions::Status::NoFreeElements, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); + } + + if (!LocationValid(_location) || _location.x <= 16 || _location.y <= 16 || _location.x >= (gMapSizeUnits - 16) + || _location.y >= (gMapSizeUnits - 16)) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_OFF_EDGE_OF_MAP); + } + + // Verify footpath exists at location, and retrieve coordinates + auto pathElement = map_get_path_element_at(TileCoordsXYZ{ _location }); + if (pathElement == nullptr) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS); + } + + // Verify location is unowned + auto surfaceMapElement = map_get_surface_element_at(_location); + if (surfaceMapElement == nullptr) + { + return std::make_unique( + GameActions::Status::Unknown, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); + } + if (surfaceMapElement->GetOwnership() != OWNERSHIP_UNOWNED) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, + STR_ERR_MUST_BE_OUTSIDE_PARK_BOUNDARIES); + } + + return res; +} + +GameActions::Result::Ptr PlacePeepSpawnAction::Execute() const +{ + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = _location; + + // Shift the spawn point to the edge of the tile + auto spawnPos = CoordsXY{ _location.ToTileCentre() } + + CoordsXY{ DirectionOffsets[_location.direction].x * 15, DirectionOffsets[_location.direction].y * 15 }; + + PeepSpawn spawn; + spawn.x = spawnPos.x; + spawn.y = spawnPos.y; + spawn.z = _location.z; + spawn.direction = _location.direction; + + // When attempting to place a peep spawn on a tile that already contains it, + // remove that peep spawn instead. + if (!gPeepSpawns.empty()) + { + // When searching for existing spawns, ignore the direction. + auto foundSpawn = std::find_if(gPeepSpawns.begin(), gPeepSpawns.end(), [spawn](const CoordsXYZ& existingSpawn) { + { + return existingSpawn.ToTileStart() == spawn.ToTileStart(); + } + }); + + if (foundSpawn != std::end(gPeepSpawns)) + { + gPeepSpawns.erase(foundSpawn); + map_invalidate_tile_full(spawn); + return res; + } + } + + // If we have reached our max peep spawns, remove the oldest spawns + while (gPeepSpawns.size() >= MAX_PEEP_SPAWNS) + { + PeepSpawn oldestSpawn = *gPeepSpawns.begin(); + gPeepSpawns.erase(gPeepSpawns.begin()); + map_invalidate_tile_full(oldestSpawn); + } + + // Set peep spawn + gPeepSpawns.push_back(spawn); + + // Invalidate tile + map_invalidate_tile_full(_location); + + return res; +} diff --git a/src/openrct2/actions/PlacePeepSpawnAction.h b/src/openrct2/actions/PlacePeepSpawnAction.h new file mode 100644 index 0000000000..8308936b95 --- /dev/null +++ b/src/openrct2/actions/PlacePeepSpawnAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(PlacePeepSpawnAction, GAME_COMMAND_PLACE_PEEP_SPAWN, GameActions::Result) +{ +private: + CoordsXYZD _location; + +public: + PlacePeepSpawnAction() = default; + PlacePeepSpawnAction(const CoordsXYZD& location) + : _location(location) + { + } + + uint16_t GetActionFlags() const override + { + return GameActionBase::GetActionFlags() | GameActions::Flags::EditorOnly | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/PlacePeepSpawnAction.hpp b/src/openrct2/actions/PlacePeepSpawnAction.hpp deleted file mode 100644 index ba4e3327b7..0000000000 --- a/src/openrct2/actions/PlacePeepSpawnAction.hpp +++ /dev/null @@ -1,147 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Park.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(PlacePeepSpawnAction, GAME_COMMAND_PLACE_PEEP_SPAWN, GameActions::Result) -{ -private: - CoordsXYZD _location; - -public: - PlacePeepSpawnAction() = default; - PlacePeepSpawnAction(const CoordsXYZD& location) - : _location(location) - { - } - - uint16_t GetActionFlags() const override - { - return GameActionBase::GetActionFlags() | GameActions::Flags::EditorOnly | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_location.x) << DS_TAG(_location.y) << DS_TAG(_location.z) << DS_TAG(_location.direction); - } - - GameActions::Result::Ptr Query() const override - { - if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) - { - return std::make_unique( - GameActions::Status::NotInEditorMode, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); - } - - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = _location; - - if (!map_check_free_elements_and_reorganise(3)) - { - return std::make_unique( - GameActions::Status::NoFreeElements, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); - } - - if (!LocationValid(_location) || _location.x <= 16 || _location.y <= 16 || _location.x >= (gMapSizeUnits - 16) - || _location.y >= (gMapSizeUnits - 16)) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_OFF_EDGE_OF_MAP); - } - - // Verify footpath exists at location, and retrieve coordinates - auto pathElement = map_get_path_element_at(TileCoordsXYZ{ _location }); - if (pathElement == nullptr) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS); - } - - // Verify location is unowned - auto surfaceMapElement = map_get_surface_element_at(_location); - if (surfaceMapElement == nullptr) - { - return std::make_unique( - GameActions::Status::Unknown, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); - } - if (surfaceMapElement->GetOwnership() != OWNERSHIP_UNOWNED) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, - STR_ERR_MUST_BE_OUTSIDE_PARK_BOUNDARIES); - } - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = _location; - - // Shift the spawn point to the edge of the tile - auto spawnPos = CoordsXY{ _location.ToTileCentre() } - + CoordsXY{ DirectionOffsets[_location.direction].x * 15, DirectionOffsets[_location.direction].y * 15 }; - - PeepSpawn spawn; - spawn.x = spawnPos.x; - spawn.y = spawnPos.y; - spawn.z = _location.z; - spawn.direction = _location.direction; - - // When attempting to place a peep spawn on a tile that already contains it, - // remove that peep spawn instead. - if (!gPeepSpawns.empty()) - { - // When searching for existing spawns, ignore the direction. - auto foundSpawn = std::find_if(gPeepSpawns.begin(), gPeepSpawns.end(), [spawn](const CoordsXYZ& existingSpawn) { - { - return existingSpawn.ToTileStart() == spawn.ToTileStart(); - } - }); - - if (foundSpawn != std::end(gPeepSpawns)) - { - gPeepSpawns.erase(foundSpawn); - map_invalidate_tile_full(spawn); - return res; - } - } - - // If we have reached our max peep spawns, remove the oldest spawns - while (gPeepSpawns.size() >= MAX_PEEP_SPAWNS) - { - PeepSpawn oldestSpawn = *gPeepSpawns.begin(); - gPeepSpawns.erase(gPeepSpawns.begin()); - map_invalidate_tile_full(oldestSpawn); - } - - // Set peep spawn - gPeepSpawns.push_back(spawn); - - // Invalidate tile - map_invalidate_tile_full(_location); - - return res; - } -}; diff --git a/src/openrct2/actions/PlayerKickAction.cpp b/src/openrct2/actions/PlayerKickAction.cpp new file mode 100644 index 0000000000..b1c260f0d5 --- /dev/null +++ b/src/openrct2/actions/PlayerKickAction.cpp @@ -0,0 +1,28 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "PlayerKickAction.h" + +#include "../network/network.h" + +void PlayerKickAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_playerId); +} +GameActions::Result::Ptr PlayerKickAction::Query() const +{ + return network_kick_player(_playerId, false); +} + +GameActions::Result::Ptr PlayerKickAction::Execute() const +{ + return network_kick_player(_playerId, true); +} diff --git a/src/openrct2/actions/PlayerKickAction.hpp b/src/openrct2/actions/PlayerKickAction.h similarity index 68% rename from src/openrct2/actions/PlayerKickAction.hpp rename to src/openrct2/actions/PlayerKickAction.h index a76f881eb1..129461e840 100644 --- a/src/openrct2/actions/PlayerKickAction.hpp +++ b/src/openrct2/actions/PlayerKickAction.h @@ -9,7 +9,6 @@ #pragma once -#include "../network/network.h" #include "GameAction.h" DEFINE_GAME_ACTION(PlayerKickAction, GAME_COMMAND_KICK_PLAYER, GameActions::Result) @@ -30,19 +29,7 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_playerId); - } - GameActions::Result::Ptr Query() const override - { - return network_kick_player(_playerId, false); - } - - GameActions::Result::Ptr Execute() const override - { - return network_kick_player(_playerId, true); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/PlayerSetGroupAction.cpp b/src/openrct2/actions/PlayerSetGroupAction.cpp new file mode 100644 index 0000000000..94e049aeab --- /dev/null +++ b/src/openrct2/actions/PlayerSetGroupAction.cpp @@ -0,0 +1,28 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "PlayerSetGroupAction.h" + +#include "../network/network.h" + +void PlayerSetGroupAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_playerId) << DS_TAG(_groupId); +} +GameActions::Result::Ptr PlayerSetGroupAction::Query() const +{ + return network_set_player_group(GetPlayer(), _playerId, _groupId, false); +} + +GameActions::Result::Ptr PlayerSetGroupAction::Execute() const +{ + return network_set_player_group(GetPlayer(), _playerId, _groupId, true); +} diff --git a/src/openrct2/actions/PlayerSetGroupAction.hpp b/src/openrct2/actions/PlayerSetGroupAction.h similarity index 67% rename from src/openrct2/actions/PlayerSetGroupAction.hpp rename to src/openrct2/actions/PlayerSetGroupAction.h index ea36d26a7b..e326a3fca3 100644 --- a/src/openrct2/actions/PlayerSetGroupAction.hpp +++ b/src/openrct2/actions/PlayerSetGroupAction.h @@ -9,7 +9,6 @@ #pragma once -#include "../network/network.h" #include "GameAction.h" DEFINE_GAME_ACTION(PlayerSetGroupAction, GAME_COMMAND_SET_PLAYER_GROUP, GameActions::Result) @@ -32,19 +31,7 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_playerId) << DS_TAG(_groupId); - } - GameActions::Result::Ptr Query() const override - { - return network_set_player_group(GetPlayer(), _playerId, _groupId, false); - } - - GameActions::Result::Ptr Execute() const override - { - return network_set_player_group(GetPlayer(), _playerId, _groupId, true); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/RideCreateAction.cpp b/src/openrct2/actions/RideCreateAction.cpp new file mode 100644 index 0000000000..265bb9f806 --- /dev/null +++ b/src/openrct2/actions/RideCreateAction.cpp @@ -0,0 +1,270 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideCreateAction.h" + +#include "../Cheats.h" +#include "../core/Memory.hpp" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Date.h" +#include "../localisation/StringIds.h" +#include "../rct1/RCT1.h" +#include "../ride/Ride.h" +#include "../ride/RideData.h" +#include "../ride/ShopItem.h" +#include "../ride/Station.h" +#include "../scenario/Scenario.h" +#include "../world/Park.h" + +#include + +void RideCreateAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("rideType", _rideType); + visitor.Visit("rideObject", _subType); + visitor.Visit("colour1", _colour1); + visitor.Visit("colour2", _colour2); +} + +void RideCreateAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideType) << DS_TAG(_subType) << DS_TAG(_colour1) << DS_TAG(_colour2); +} + +GameActions::Result::Ptr RideCreateAction::Query() const +{ + auto rideIndex = GetNextFreeRideId(); + if (rideIndex == RIDE_ID_NULL) + { + // No more free slots available. + return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_RIDES); + } + + if (_rideType >= RIDE_TYPE_COUNT) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_RIDE_TYPE); + } + + int32_t rideEntryIndex = ride_get_entry_index(_rideType, _subType); + if (rideEntryIndex >= MAX_RIDE_OBJECTS) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_RIDE_TYPE); + } + + const auto& colourPresets = RideTypeDescriptors[_rideType].ColourPresets; + if (_colour1 >= colourPresets.count) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + rct_ride_entry* rideEntry = get_ride_entry(rideEntryIndex); + if (rideEntry == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list; + if ((presetList->count > 0 && presetList->count != 255) && _colour2 >= presetList->count) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr RideCreateAction::Execute() const +{ + rct_ride_entry* rideEntry; + auto res = MakeResult(); + + int32_t rideEntryIndex = ride_get_entry_index(_rideType, _subType); + auto rideIndex = GetNextFreeRideId(); + + res->rideIndex = rideIndex; + + auto ride = GetOrAllocateRide(rideIndex); + rideEntry = get_ride_entry(rideEntryIndex); + if (rideEntry == nullptr) + { + log_warning("Invalid request for ride %u", rideIndex); + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_UNKNOWN_OBJECT_TYPE; + return res; + } + + ride->id = rideIndex; + ride->type = _rideType; + ride->subtype = rideEntryIndex; + ride->SetColourPreset(_colour1); + ride->overall_view.setNull(); + ride->SetNameToDefault(); + + for (int32_t i = 0; i < MAX_STATIONS; i++) + { + ride->stations[i].Start.setNull(); + ride_clear_entrance_location(ride, i); + ride_clear_exit_location(ride, i); + ride->stations[i].TrainAtStation = RideStation::NO_TRAIN; + ride->stations[i].QueueTime = 0; + } + + for (auto& vehicle : ride->vehicles) + { + vehicle = SPRITE_INDEX_NULL; + } + + ride->status = RIDE_STATUS_CLOSED; + ride->lifecycle_flags = 0; + ride->vehicle_change_timeout = 0; + ride->num_stations = 0; + ride->num_vehicles = 1; + ride->proposed_num_vehicles = 32; + ride->max_trains = 32; + ride->num_cars_per_train = 1; + ride->proposed_num_cars_per_train = 12; + ride->min_waiting_time = 10; + ride->max_waiting_time = 60; + ride->depart_flags = RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH | 3; + if (RideTypeDescriptors[ride->type].Flags & RIDE_TYPE_FLAG_MUSIC_ON_DEFAULT) + { + ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; + } + ride->music = RideTypeDescriptors[ride->type].DefaultMusic; + + const auto& operatingSettings = RideTypeDescriptors[ride->type].OperatingSettings; + ride->operation_option = (operatingSettings.MinValue * 3 + operatingSettings.MaxValue) / 4; + + ride->lift_hill_speed = RideTypeDescriptors[ride->type].LiftData.minimum_speed; + + ride->measurement = {}; + ride->excitement = RIDE_RATING_UNDEFINED; + ride->cur_num_customers = 0; + ride->num_customers_timeout = 0; + ride->chairlift_bullwheel_rotation = 0; + + for (auto& price : ride->price) + { + price = 0; + } + + if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) + { + for (auto i = 0; i < NUM_SHOP_ITEMS_PER_RIDE; i++) + { + ride->price[i] = RideTypeDescriptors[ride->type].DefaultPrices[i]; + } + + if (rideEntry->shop_item[0] == ShopItem::None) + { + if (!park_ride_prices_unlocked()) + { + ride->price[0] = 0; + } + } + else + { + ride->price[0] = GetShopItemDescriptor(rideEntry->shop_item[0]).DefaultPrice; + } + if (rideEntry->shop_item[1] != ShopItem::None) + { + ride->price[1] = GetShopItemDescriptor(rideEntry->shop_item[1]).DefaultPrice; + } + + if (gScenarioObjective.Type == OBJECTIVE_BUILD_THE_BEST) + { + ride->price[0] = 0; + } + + if (ride->type == RIDE_TYPE_TOILETS) + { + if (shop_item_has_common_price(ShopItem::Admission)) + { + money32 price = ride_get_common_price(ride); + if (price != MONEY32_UNDEFINED) + { + ride->price[0] = static_cast(price); + } + } + } + + for (auto i = 0; i < NUM_SHOP_ITEMS_PER_RIDE; i++) + { + if (rideEntry->shop_item[i] != ShopItem::None) + { + if (shop_item_has_common_price(rideEntry->shop_item[i])) + { + money32 price = shop_item_get_common_price(ride, rideEntry->shop_item[i]); + if (price != MONEY32_UNDEFINED) + { + ride->price[i] = static_cast(price); + } + } + } + } + + // Set the on-ride photo price, whether the ride has one or not (except shops). + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP) && shop_item_has_common_price(ShopItem::Photo)) + { + money32 price = shop_item_get_common_price(ride, ShopItem::Photo); + if (price != MONEY32_UNDEFINED) + { + ride->price[1] = static_cast(price); + } + } + } + + std::fill(std::begin(ride->num_customers), std::end(ride->num_customers), 0); + ride->value = RIDE_VALUE_UNDEFINED; + ride->satisfaction = 255; + ride->satisfaction_time_out = 0; + ride->satisfaction_next = 0; + ride->popularity = 255; + ride->popularity_time_out = 0; + ride->popularity_next = 0; + ride->window_invalidate_flags = 0; + ride->total_customers = 0; + ride->total_profit = 0; + ride->num_riders = 0; + ride->slide_in_use = 0; + ride->maze_tiles = 0; + ride->build_date = gDateMonthsElapsed; + ride->music_tune_id = 255; + + ride->breakdown_reason = 255; + ride->upkeep_cost = MONEY16_UNDEFINED; + ride->reliability = RIDE_INITIAL_RELIABILITY; + ride->unreliability_factor = 1; + ride->inspection_interval = RIDE_INSPECTION_EVERY_30_MINUTES; + ride->last_inspection = 0; + ride->downtime = 0; + std::fill_n(ride->downtime_history, sizeof(ride->downtime_history), 0x00); + ride->no_primary_items_sold = 0; + ride->no_secondary_items_sold = 0; + ride->last_crash_type = RIDE_CRASH_TYPE_NONE; + ride->income_per_hour = MONEY32_UNDEFINED; + ride->profit = MONEY32_UNDEFINED; + ride->connected_message_throttle = 0; + ride->entrance_style = 0; + ride->num_block_brakes = 0; + ride->guests_favourite = 0; + + ride->num_circuits = 1; + ride->mode = ride->GetDefaultMode(); + ride->SetMinCarsPerTrain(rideEntry->min_cars_in_train); + ride->SetMaxCarsPerTrain(rideEntry->max_cars_in_train); + ride_set_vehicle_colours_to_random_preset(ride, _colour2); + window_invalidate_by_class(WC_RIDE_LIST); + + res->Expenditure = ExpenditureType::RideConstruction; + + return res; +} \ No newline at end of file diff --git a/src/openrct2/actions/RideCreateAction.h b/src/openrct2/actions/RideCreateAction.h new file mode 100644 index 0000000000..d3e0e59e8f --- /dev/null +++ b/src/openrct2/actions/RideCreateAction.h @@ -0,0 +1,68 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +class RideCreateGameActionResult final : public GameActions::Result +{ +public: + RideCreateGameActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_NONE) + { + } + RideCreateGameActionResult(GameActions::Status error, rct_string_id message) + : GameActions::Result(error, STR_CANT_CREATE_NEW_RIDE_ATTRACTION, message) + { + } + + ride_id_t rideIndex = RIDE_ID_NULL; +}; + +DEFINE_GAME_ACTION(RideCreateAction, GAME_COMMAND_CREATE_RIDE, RideCreateGameActionResult) +{ +private: + int32_t _rideType{ RIDE_ID_NULL }; + ObjectEntryIndex _subType{ RIDE_ENTRY_INDEX_NULL }; + uint8_t _colour1{ 0xFF }; + uint8_t _colour2{ 0xFF }; + +public: + RideCreateAction() = default; + + RideCreateAction(int32_t rideType, ObjectEntryIndex subType, int32_t colour1, int32_t colour2) + : _rideType(rideType) + , _subType(subType) + , _colour1(colour1) + , _colour2(colour2) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + int32_t GetRideType() const + { + return _rideType; + } + + int32_t GetRideObject() const + { + return _subType; + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideCreateAction.hpp b/src/openrct2/actions/RideCreateAction.hpp deleted file mode 100644 index 0509bd36de..0000000000 --- a/src/openrct2/actions/RideCreateAction.hpp +++ /dev/null @@ -1,321 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../core/Memory.hpp" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Date.h" -#include "../localisation/StringIds.h" -#include "../rct1/RCT1.h" -#include "../ride/Ride.h" -#include "../ride/RideData.h" -#include "../ride/ShopItem.h" -#include "../ride/Station.h" -#include "../scenario/Scenario.h" -#include "../world/Park.h" -#include "GameAction.h" - -#include - -class RideCreateGameActionResult final : public GameActions::Result -{ -public: - RideCreateGameActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_NONE) - { - } - RideCreateGameActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_CANT_CREATE_NEW_RIDE_ATTRACTION, message) - { - } - - ride_id_t rideIndex = RIDE_ID_NULL; -}; - -DEFINE_GAME_ACTION(RideCreateAction, GAME_COMMAND_CREATE_RIDE, RideCreateGameActionResult) -{ -private: - int32_t _rideType{ RIDE_ID_NULL }; - ObjectEntryIndex _subType{ RIDE_ENTRY_INDEX_NULL }; - uint8_t _colour1{ 0xFF }; - uint8_t _colour2{ 0xFF }; - -public: - RideCreateAction() = default; - - RideCreateAction(int32_t rideType, ObjectEntryIndex subType, int32_t colour1, int32_t colour2) - : _rideType(rideType) - , _subType(subType) - , _colour1(colour1) - , _colour2(colour2) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("rideType", _rideType); - visitor.Visit("rideObject", _subType); - visitor.Visit("colour1", _colour1); - visitor.Visit("colour2", _colour2); - } - - int32_t GetRideType() const - { - return _rideType; - } - - int32_t GetRideObject() const - { - return _subType; - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideType) << DS_TAG(_subType) << DS_TAG(_colour1) << DS_TAG(_colour2); - } - - GameActions::Result::Ptr Query() const override - { - auto rideIndex = GetNextFreeRideId(); - if (rideIndex == RIDE_ID_NULL) - { - // No more free slots available. - return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_RIDES); - } - - if (_rideType >= RIDE_TYPE_COUNT) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_RIDE_TYPE); - } - - int32_t rideEntryIndex = ride_get_entry_index(_rideType, _subType); - if (rideEntryIndex >= MAX_RIDE_OBJECTS) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_RIDE_TYPE); - } - - const auto& colourPresets = RideTypeDescriptors[_rideType].ColourPresets; - if (_colour1 >= colourPresets.count) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - rct_ride_entry* rideEntry = get_ride_entry(rideEntryIndex); - if (rideEntry == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list; - if ((presetList->count > 0 && presetList->count != 255) && _colour2 >= presetList->count) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - rct_ride_entry* rideEntry; - auto res = MakeResult(); - - int32_t rideEntryIndex = ride_get_entry_index(_rideType, _subType); - auto rideIndex = GetNextFreeRideId(); - - res->rideIndex = rideIndex; - - auto ride = GetOrAllocateRide(rideIndex); - rideEntry = get_ride_entry(rideEntryIndex); - if (rideEntry == nullptr) - { - log_warning("Invalid request for ride %u", rideIndex); - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_UNKNOWN_OBJECT_TYPE; - return res; - } - - ride->id = rideIndex; - ride->type = _rideType; - ride->subtype = rideEntryIndex; - ride->SetColourPreset(_colour1); - ride->overall_view.setNull(); - ride->SetNameToDefault(); - - for (int32_t i = 0; i < MAX_STATIONS; i++) - { - ride->stations[i].Start.setNull(); - ride_clear_entrance_location(ride, i); - ride_clear_exit_location(ride, i); - ride->stations[i].TrainAtStation = RideStation::NO_TRAIN; - ride->stations[i].QueueTime = 0; - } - - for (auto& vehicle : ride->vehicles) - { - vehicle = SPRITE_INDEX_NULL; - } - - ride->status = RIDE_STATUS_CLOSED; - ride->lifecycle_flags = 0; - ride->vehicle_change_timeout = 0; - ride->num_stations = 0; - ride->num_vehicles = 1; - ride->proposed_num_vehicles = 32; - ride->max_trains = 32; - ride->num_cars_per_train = 1; - ride->proposed_num_cars_per_train = 12; - ride->min_waiting_time = 10; - ride->max_waiting_time = 60; - ride->depart_flags = RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH | 3; - if (RideTypeDescriptors[ride->type].Flags & RIDE_TYPE_FLAG_MUSIC_ON_DEFAULT) - { - ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; - } - ride->music = RideTypeDescriptors[ride->type].DefaultMusic; - - const auto& operatingSettings = RideTypeDescriptors[ride->type].OperatingSettings; - ride->operation_option = (operatingSettings.MinValue * 3 + operatingSettings.MaxValue) / 4; - - ride->lift_hill_speed = RideTypeDescriptors[ride->type].LiftData.minimum_speed; - - ride->measurement = {}; - ride->excitement = RIDE_RATING_UNDEFINED; - ride->cur_num_customers = 0; - ride->num_customers_timeout = 0; - ride->chairlift_bullwheel_rotation = 0; - - for (auto& price : ride->price) - { - price = 0; - } - - if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) - { - for (auto i = 0; i < NUM_SHOP_ITEMS_PER_RIDE; i++) - { - ride->price[i] = RideTypeDescriptors[ride->type].DefaultPrices[i]; - } - - if (rideEntry->shop_item[0] == ShopItem::None) - { - if (!park_ride_prices_unlocked()) - { - ride->price[0] = 0; - } - } - else - { - ride->price[0] = GetShopItemDescriptor(rideEntry->shop_item[0]).DefaultPrice; - } - if (rideEntry->shop_item[1] != ShopItem::None) - { - ride->price[1] = GetShopItemDescriptor(rideEntry->shop_item[1]).DefaultPrice; - } - - if (gScenarioObjective.Type == OBJECTIVE_BUILD_THE_BEST) - { - ride->price[0] = 0; - } - - if (ride->type == RIDE_TYPE_TOILETS) - { - if (shop_item_has_common_price(ShopItem::Admission)) - { - money32 price = ride_get_common_price(ride); - if (price != MONEY32_UNDEFINED) - { - ride->price[0] = static_cast(price); - } - } - } - - for (auto i = 0; i < NUM_SHOP_ITEMS_PER_RIDE; i++) - { - if (rideEntry->shop_item[i] != ShopItem::None) - { - if (shop_item_has_common_price(rideEntry->shop_item[i])) - { - money32 price = shop_item_get_common_price(ride, rideEntry->shop_item[i]); - if (price != MONEY32_UNDEFINED) - { - ride->price[i] = static_cast(price); - } - } - } - } - - // Set the on-ride photo price, whether the ride has one or not (except shops). - if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP) && shop_item_has_common_price(ShopItem::Photo)) - { - money32 price = shop_item_get_common_price(ride, ShopItem::Photo); - if (price != MONEY32_UNDEFINED) - { - ride->price[1] = static_cast(price); - } - } - } - - std::fill(std::begin(ride->num_customers), std::end(ride->num_customers), 0); - ride->value = RIDE_VALUE_UNDEFINED; - ride->satisfaction = 255; - ride->satisfaction_time_out = 0; - ride->satisfaction_next = 0; - ride->popularity = 255; - ride->popularity_time_out = 0; - ride->popularity_next = 0; - ride->window_invalidate_flags = 0; - ride->total_customers = 0; - ride->total_profit = 0; - ride->num_riders = 0; - ride->slide_in_use = 0; - ride->maze_tiles = 0; - ride->build_date = gDateMonthsElapsed; - ride->music_tune_id = 255; - - ride->breakdown_reason = 255; - ride->upkeep_cost = MONEY16_UNDEFINED; - ride->reliability = RIDE_INITIAL_RELIABILITY; - ride->unreliability_factor = 1; - ride->inspection_interval = RIDE_INSPECTION_EVERY_30_MINUTES; - ride->last_inspection = 0; - ride->downtime = 0; - std::fill_n(ride->downtime_history, sizeof(ride->downtime_history), 0x00); - ride->no_primary_items_sold = 0; - ride->no_secondary_items_sold = 0; - ride->last_crash_type = RIDE_CRASH_TYPE_NONE; - ride->income_per_hour = MONEY32_UNDEFINED; - ride->profit = MONEY32_UNDEFINED; - ride->connected_message_throttle = 0; - ride->entrance_style = 0; - ride->num_block_brakes = 0; - ride->guests_favourite = 0; - - ride->num_circuits = 1; - ride->mode = ride->GetDefaultMode(); - ride->SetMinCarsPerTrain(rideEntry->min_cars_in_train); - ride->SetMaxCarsPerTrain(rideEntry->max_cars_in_train); - ride_set_vehicle_colours_to_random_preset(ride, _colour2); - window_invalidate_by_class(WC_RIDE_LIST); - - res->Expenditure = ExpenditureType::RideConstruction; - - return res; - } -}; diff --git a/src/openrct2/actions/RideDemolishAction.cpp b/src/openrct2/actions/RideDemolishAction.cpp new file mode 100644 index 0000000000..39ef1781dd --- /dev/null +++ b/src/openrct2/actions/RideDemolishAction.cpp @@ -0,0 +1,368 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideDemolishAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../GameState.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../management/NewsItem.h" +#include "../ride/Ride.h" +#include "../ride/RideData.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Banner.h" +#include "../world/Park.h" +#include "../world/Sprite.h" +#include "MazeSetTrackAction.h" +#include "TrackRemoveAction.h" + +using namespace OpenRCT2; + +void RideDemolishAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("modifyType", _modifyType); +} + +void RideDemolishAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_modifyType); +} + +GameActions::Result::Ptr RideDemolishAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_DEMOLISH_RIDE, STR_NONE); + } + + if (ride->lifecycle_flags & (RIDE_LIFECYCLE_INDESTRUCTIBLE | RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) + && _modifyType == RIDE_MODIFY_DEMOLISH) + { + return std::make_unique( + GameActions::Status::NoClearance, STR_CANT_DEMOLISH_RIDE, + STR_LOCAL_AUTHORITY_FORBIDS_DEMOLITION_OR_MODIFICATIONS_TO_THIS_RIDE); + } + + GameActions::Result::Ptr result = std::make_unique(); + + if (_modifyType == RIDE_MODIFY_RENEW) + { + if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_MUST_BE_CLOSED_FIRST); + } + + if (ride->num_riders > 0) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_RIDE_NOT_YET_EMPTY); + } + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) + || RideTypeDescriptors[ride->type].AvailableBreakdowns == 0) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_CANT_REFURBISH_NOT_NEEDED); + } + + result->ErrorTitle = STR_CANT_REFURBISH_RIDE; + result->Cost = GetRefurbishPrice(ride); + } + + return result; +} + +GameActions::Result::Ptr RideDemolishAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_DEMOLISH_RIDE, STR_NONE); + } + + switch (_modifyType) + { + case RIDE_MODIFY_DEMOLISH: + return DemolishRide(ride); + case RIDE_MODIFY_RENEW: + return RefurbishRide(ride); + } + + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_DO_THIS); +} + +GameActions::Result::Ptr RideDemolishAction::DemolishRide(Ride* ride) const +{ + money32 refundPrice = DemolishTracks(); + + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + ride->StopGuestsQueuing(); + + sub_6CB945(ride); + ride_clear_leftover_entrances(ride); + News::DisableNewsItems(News::ItemType::Ride, _rideIndex); + + for (BannerIndex i = 0; i < MAX_BANNERS; i++) + { + auto banner = GetBanner(i); + if (!banner->IsNull() && banner->flags & BANNER_FLAG_LINKED_TO_RIDE && banner->ride_index == _rideIndex) + { + banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; + banner->text = {}; + } + } + + for (auto peep : EntityList(EntityListId::Peep)) + { + uint8_t ride_id_bit = _rideIndex % 8; + uint8_t ride_id_offset = _rideIndex / 8; + + // clear ride from potentially being in RidesBeenOn + peep->RidesBeenOn[ride_id_offset] &= ~(1 << ride_id_bit); + if (peep->State == PeepState::Watching) + { + if (peep->CurrentRide == _rideIndex) + { + peep->CurrentRide = RIDE_ID_NULL; + if (peep->TimeToStand >= 50) + { + // make peep stop watching the ride + peep->TimeToStand = 50; + } + } + } + + // remove any free voucher for this ride from peep + if (peep->HasItem(ShopItem::Voucher)) + { + if (peep->VoucherType == VOUCHER_TYPE_RIDE_FREE && peep->VoucherRideId == _rideIndex) + { + peep->RemoveItem(ShopItem::Voucher); + } + } + + // remove any photos of this ride from peep + if (peep->HasItem(ShopItem::Photo)) + { + if (peep->Photo1RideRef == _rideIndex) + { + peep->RemoveItem(ShopItem::Photo); + } + } + if (peep->HasItem(ShopItem::Photo2)) + { + if (peep->Photo2RideRef == _rideIndex) + { + peep->RemoveItem(ShopItem::Photo2); + } + } + if (peep->HasItem(ShopItem::Photo3)) + { + if (peep->Photo3RideRef == _rideIndex) + { + peep->RemoveItem(ShopItem::Photo3); + } + } + if (peep->HasItem(ShopItem::Photo4)) + { + if (peep->Photo4RideRef == _rideIndex) + { + peep->RemoveItem(ShopItem::Photo4); + } + } + + if (peep->GuestHeadingToRideId == _rideIndex) + { + peep->GuestHeadingToRideId = RIDE_ID_NULL; + } + if (peep->FavouriteRide == _rideIndex) + { + peep->FavouriteRide = RIDE_ID_NULL; + } + + for (int32_t i = 0; i < PEEP_MAX_THOUGHTS; i++) + { + // Don't touch items after the first NONE thought as they are not valid + // fixes issues with clearing out bad thought data in multiplayer + if (peep->Thoughts[i].type == PeepThoughtType::None) + break; + + if (peep->Thoughts[i].type != PeepThoughtType::None && peep->Thoughts[i].item == _rideIndex) + { + // Clear top thought, push others up + memmove(&peep->Thoughts[i], &peep->Thoughts[i + 1], sizeof(rct_peep_thought) * (PEEP_MAX_THOUGHTS - i - 1)); + peep->Thoughts[PEEP_MAX_THOUGHTS - 1].type = PeepThoughtType::None; + peep->Thoughts[PEEP_MAX_THOUGHTS - 1].item = PEEP_THOUGHT_ITEM_NONE; + // Next iteration, check the new thought at this index + i--; + } + } + } + + MarketingCancelCampaignsForRide(_rideIndex); + + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::RideConstruction; + res->Cost = refundPrice; + + if (!ride->overall_view.isNull()) + { + auto xy = ride->overall_view.ToTileCentre(); + res->Position = { xy, tile_element_height(xy) }; + } + + ride->Delete(); + gParkValue = GetContext()->GetGameState()->GetPark().CalculateParkValue(); + + // Close windows related to the demolished ride + if (!(GetFlags() & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED)) + { + window_close_by_number(WC_RIDE_CONSTRUCTION, _rideIndex); + } + window_close_by_number(WC_RIDE, _rideIndex); + window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, _rideIndex); + window_close_by_class(WC_NEW_CAMPAIGN); + + // Refresh windows that display the ride name + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_RIDE_LIST)); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_GUEST_LIST)); + + scrolling_text_invalidate(); + gfx_invalidate_screen(); + + return res; +} + +money32 RideDemolishAction::MazeRemoveTrack(const CoordsXYZD& coords) const +{ + auto setMazeTrack = MazeSetTrackAction(coords, false, _rideIndex, GC_SET_MAZE_TRACK_FILL); + setMazeTrack.SetFlags(GetFlags()); + + auto execRes = GameActions::ExecuteNested(&setMazeTrack); + if (execRes->Error == GameActions::Status::Ok) + { + return execRes->Cost; + } + + return MONEY32_UNDEFINED; +} + +money32 RideDemolishAction::DemolishTracks() const +{ + money32 refundPrice = 0; + + uint8_t oldpaused = gGamePaused; + gGamePaused = 0; + + tile_element_iterator it; + + tile_element_iterator_begin(&it); + while (tile_element_iterator_next(&it)) + { + if (it.element->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if (it.element->AsTrack()->GetRideIndex() != static_cast(_rideIndex)) + continue; + + auto location = CoordsXYZD(TileCoordsXY(it.x, it.y).ToCoordsXY(), it.element->GetBaseZ(), it.element->GetDirection()); + auto type = it.element->AsTrack()->GetTrackType(); + + if (type != TrackElemType::Maze) + { + auto trackRemoveAction = TrackRemoveAction(type, it.element->AsTrack()->GetSequenceIndex(), location); + trackRemoveAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND); + + auto removRes = GameActions::ExecuteNested(&trackRemoveAction); + + if (removRes->Error != GameActions::Status::Ok) + { + tile_element_remove(it.element); + } + else + { + refundPrice += removRes->Cost; + } + + tile_element_iterator_restart_for_tile(&it); + continue; + } + + static constexpr const CoordsXY DirOffsets[] = { + { 0, 0 }, + { 0, 16 }, + { 16, 16 }, + { 16, 0 }, + }; + + for (Direction dir : ALL_DIRECTIONS) + { + const CoordsXYZ off = { DirOffsets[dir], 0 }; + money32 removePrice = MazeRemoveTrack({ location + off, dir }); + if (removePrice != MONEY32_UNDEFINED) + refundPrice += removePrice; + else + break; + } + + tile_element_iterator_restart_for_tile(&it); + } + + gGamePaused = oldpaused; + return refundPrice; +} + +GameActions::Result::Ptr RideDemolishAction::RefurbishRide(Ride* ride) const +{ + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::RideConstruction; + res->Cost = GetRefurbishPrice(ride); + + ride->Renew(); + + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_EVER_BEEN_OPENED; + ride->last_crash_type = RIDE_CRASH_TYPE_NONE; + + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE | RIDE_INVALIDATE_RIDE_CUSTOMER; + + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + } + + window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, _rideIndex); + + return res; +} + +money32 RideDemolishAction::GetRefurbishPrice(const Ride* ride) const +{ + return -GetRefundPrice(ride) / 2; +} + +money32 RideDemolishAction::GetRefundPrice(const Ride* ride) const +{ + return ride_get_refund_price(ride); +} diff --git a/src/openrct2/actions/RideDemolishAction.h b/src/openrct2/actions/RideDemolishAction.h new file mode 100644 index 0000000000..c911b12808 --- /dev/null +++ b/src/openrct2/actions/RideDemolishAction.h @@ -0,0 +1,46 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(RideDemolishAction, GAME_COMMAND_DEMOLISH_RIDE, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + uint8_t _modifyType{ RIDE_MODIFY_DEMOLISH }; + +public: + RideDemolishAction() = default; + RideDemolishAction(ride_id_t rideIndex, uint8_t modifyType) + : _rideIndex(rideIndex) + , _modifyType(modifyType) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint32_t GetCooldownTime() const override + { + return 1000; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr DemolishRide(Ride * ride) const; + money32 MazeRemoveTrack(const CoordsXYZD& coords) const; + money32 DemolishTracks() const; + GameActions::Result::Ptr RefurbishRide(Ride * ride) const; + money32 GetRefurbishPrice(const Ride* ride) const; + money32 GetRefundPrice(const Ride* ride) const; +}; diff --git a/src/openrct2/actions/RideDemolishAction.hpp b/src/openrct2/actions/RideDemolishAction.hpp deleted file mode 100644 index c28b96e4d6..0000000000 --- a/src/openrct2/actions/RideDemolishAction.hpp +++ /dev/null @@ -1,392 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../Context.h" -#include "../GameState.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../management/NewsItem.h" -#include "../ride/Ride.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../world/Banner.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" -#include "MazeSetTrackAction.hpp" -#include "TrackRemoveAction.hpp" - -using namespace OpenRCT2; - -DEFINE_GAME_ACTION(RideDemolishAction, GAME_COMMAND_DEMOLISH_RIDE, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - uint8_t _modifyType{ RIDE_MODIFY_DEMOLISH }; - -public: - RideDemolishAction() = default; - RideDemolishAction(ride_id_t rideIndex, uint8_t modifyType) - : _rideIndex(rideIndex) - , _modifyType(modifyType) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("modifyType", _modifyType); - } - - uint32_t GetCooldownTime() const override - { - return 1000; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_modifyType); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_DEMOLISH_RIDE, STR_NONE); - } - - if (ride->lifecycle_flags & (RIDE_LIFECYCLE_INDESTRUCTIBLE | RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) - && _modifyType == RIDE_MODIFY_DEMOLISH) - { - return std::make_unique( - GameActions::Status::NoClearance, STR_CANT_DEMOLISH_RIDE, - STR_LOCAL_AUTHORITY_FORBIDS_DEMOLITION_OR_MODIFICATIONS_TO_THIS_RIDE); - } - - GameActions::Result::Ptr result = std::make_unique(); - - if (_modifyType == RIDE_MODIFY_RENEW) - { - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_MUST_BE_CLOSED_FIRST); - } - - if (ride->num_riders > 0) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_RIDE_NOT_YET_EMPTY); - } - - if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) - || RideTypeDescriptors[ride->type].AvailableBreakdowns == 0) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_CANT_REFURBISH_NOT_NEEDED); - } - - result->ErrorTitle = STR_CANT_REFURBISH_RIDE; - result->Cost = GetRefurbishPrice(ride); - } - - return result; - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_DEMOLISH_RIDE, STR_NONE); - } - - switch (_modifyType) - { - case RIDE_MODIFY_DEMOLISH: - return DemolishRide(ride); - case RIDE_MODIFY_RENEW: - return RefurbishRide(ride); - } - - return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_DO_THIS); - } - -private: - GameActions::Result::Ptr DemolishRide(Ride * ride) const - { - money32 refundPrice = DemolishTracks(); - - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - ride->StopGuestsQueuing(); - - sub_6CB945(ride); - ride_clear_leftover_entrances(ride); - News::DisableNewsItems(News::ItemType::Ride, _rideIndex); - - for (BannerIndex i = 0; i < MAX_BANNERS; i++) - { - auto banner = GetBanner(i); - if (!banner->IsNull() && banner->flags & BANNER_FLAG_LINKED_TO_RIDE && banner->ride_index == _rideIndex) - { - banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; - banner->text = {}; - } - } - - for (auto peep : EntityList(EntityListId::Peep)) - { - uint8_t ride_id_bit = _rideIndex % 8; - uint8_t ride_id_offset = _rideIndex / 8; - - // clear ride from potentially being in RidesBeenOn - peep->RidesBeenOn[ride_id_offset] &= ~(1 << ride_id_bit); - if (peep->State == PeepState::Watching) - { - if (peep->CurrentRide == _rideIndex) - { - peep->CurrentRide = RIDE_ID_NULL; - if (peep->TimeToStand >= 50) - { - // make peep stop watching the ride - peep->TimeToStand = 50; - } - } - } - - // remove any free voucher for this ride from peep - if (peep->HasItem(ShopItem::Voucher)) - { - if (peep->VoucherType == VOUCHER_TYPE_RIDE_FREE && peep->VoucherRideId == _rideIndex) - { - peep->RemoveItem(ShopItem::Voucher); - } - } - - // remove any photos of this ride from peep - if (peep->HasItem(ShopItem::Photo)) - { - if (peep->Photo1RideRef == _rideIndex) - { - peep->RemoveItem(ShopItem::Photo); - } - } - if (peep->HasItem(ShopItem::Photo2)) - { - if (peep->Photo2RideRef == _rideIndex) - { - peep->RemoveItem(ShopItem::Photo2); - } - } - if (peep->HasItem(ShopItem::Photo3)) - { - if (peep->Photo3RideRef == _rideIndex) - { - peep->RemoveItem(ShopItem::Photo3); - } - } - if (peep->HasItem(ShopItem::Photo4)) - { - if (peep->Photo4RideRef == _rideIndex) - { - peep->RemoveItem(ShopItem::Photo4); - } - } - - if (peep->GuestHeadingToRideId == _rideIndex) - { - peep->GuestHeadingToRideId = RIDE_ID_NULL; - } - if (peep->FavouriteRide == _rideIndex) - { - peep->FavouriteRide = RIDE_ID_NULL; - } - - for (int32_t i = 0; i < PEEP_MAX_THOUGHTS; i++) - { - // Don't touch items after the first NONE thought as they are not valid - // fixes issues with clearing out bad thought data in multiplayer - if (peep->Thoughts[i].type == PeepThoughtType::None) - break; - - if (peep->Thoughts[i].type != PeepThoughtType::None && peep->Thoughts[i].item == _rideIndex) - { - // Clear top thought, push others up - memmove(&peep->Thoughts[i], &peep->Thoughts[i + 1], sizeof(rct_peep_thought) * (PEEP_MAX_THOUGHTS - i - 1)); - peep->Thoughts[PEEP_MAX_THOUGHTS - 1].type = PeepThoughtType::None; - peep->Thoughts[PEEP_MAX_THOUGHTS - 1].item = PEEP_THOUGHT_ITEM_NONE; - // Next iteration, check the new thought at this index - i--; - } - } - } - - MarketingCancelCampaignsForRide(_rideIndex); - - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::RideConstruction; - res->Cost = refundPrice; - - if (!ride->overall_view.isNull()) - { - auto xy = ride->overall_view.ToTileCentre(); - res->Position = { xy, tile_element_height(xy) }; - } - - ride->Delete(); - gParkValue = GetContext()->GetGameState()->GetPark().CalculateParkValue(); - - // Close windows related to the demolished ride - if (!(GetFlags() & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED)) - { - window_close_by_number(WC_RIDE_CONSTRUCTION, _rideIndex); - } - window_close_by_number(WC_RIDE, _rideIndex); - window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, _rideIndex); - window_close_by_class(WC_NEW_CAMPAIGN); - - // Refresh windows that display the ride name - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_RIDE_LIST)); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_GUEST_LIST)); - - scrolling_text_invalidate(); - gfx_invalidate_screen(); - - return res; - } - - money32 MazeRemoveTrack(const CoordsXYZD& coords) const - { - auto setMazeTrack = MazeSetTrackAction(coords, false, _rideIndex, GC_SET_MAZE_TRACK_FILL); - setMazeTrack.SetFlags(GetFlags()); - - auto execRes = GameActions::ExecuteNested(&setMazeTrack); - if (execRes->Error == GameActions::Status::Ok) - { - return execRes->Cost; - } - - return MONEY32_UNDEFINED; - } - - money32 DemolishTracks() const - { - money32 refundPrice = 0; - - uint8_t oldpaused = gGamePaused; - gGamePaused = 0; - - tile_element_iterator it; - - tile_element_iterator_begin(&it); - while (tile_element_iterator_next(&it)) - { - if (it.element->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if (it.element->AsTrack()->GetRideIndex() != static_cast(_rideIndex)) - continue; - - auto location = CoordsXYZD( - TileCoordsXY(it.x, it.y).ToCoordsXY(), it.element->GetBaseZ(), it.element->GetDirection()); - auto type = it.element->AsTrack()->GetTrackType(); - - if (type != TrackElemType::Maze) - { - auto trackRemoveAction = TrackRemoveAction(type, it.element->AsTrack()->GetSequenceIndex(), location); - trackRemoveAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND); - - auto removRes = GameActions::ExecuteNested(&trackRemoveAction); - - if (removRes->Error != GameActions::Status::Ok) - { - tile_element_remove(it.element); - } - else - { - refundPrice += removRes->Cost; - } - - tile_element_iterator_restart_for_tile(&it); - continue; - } - - static constexpr const CoordsXY DirOffsets[] = { - { 0, 0 }, - { 0, 16 }, - { 16, 16 }, - { 16, 0 }, - }; - - for (Direction dir : ALL_DIRECTIONS) - { - const CoordsXYZ off = { DirOffsets[dir], 0 }; - money32 removePrice = MazeRemoveTrack({ location + off, dir }); - if (removePrice != MONEY32_UNDEFINED) - refundPrice += removePrice; - else - break; - } - - tile_element_iterator_restart_for_tile(&it); - } - - gGamePaused = oldpaused; - return refundPrice; - } - - GameActions::Result::Ptr RefurbishRide(Ride * ride) const - { - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::RideConstruction; - res->Cost = GetRefurbishPrice(ride); - - ride->Renew(); - - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_EVER_BEEN_OPENED; - ride->last_crash_type = RIDE_CRASH_TYPE_NONE; - - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE | RIDE_INVALIDATE_RIDE_CUSTOMER; - - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - } - - window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, _rideIndex); - - return res; - } - - money32 GetRefurbishPrice(const Ride* ride) const - { - return -GetRefundPrice(ride) / 2; - } - - money32 GetRefundPrice(const Ride* ride) const - { - return ride_get_refund_price(ride); - } -}; diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.cpp b/src/openrct2/actions/RideEntranceExitPlaceAction.cpp new file mode 100644 index 0000000000..4f6f2dd5f0 --- /dev/null +++ b/src/openrct2/actions/RideEntranceExitPlaceAction.cpp @@ -0,0 +1,204 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideEntranceExitPlaceAction.h" + +#include "../actions/RideEntranceExitRemoveAction.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../ride/Station.h" +#include "../world/MapAnimation.h" +#include "../world/Sprite.h" + +void RideEntranceExitPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("direction", _direction); + visitor.Visit("ride", _rideIndex); + visitor.Visit("station", _stationNum); + visitor.Visit("isExit", _isExit); +} + +void RideEntranceExitPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_direction) << DS_TAG(_rideIndex) << DS_TAG(_stationNum) << DS_TAG(_isExit); +} + +GameActions::Result::Ptr RideEntranceExitPlaceAction::Query() const +{ + auto errorTitle = _isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION + : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, errorTitle); + } + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %d", static_cast(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, errorTitle); + } + + if (_stationNum >= MAX_STATIONS) + { + log_warning("Invalid station number for ride. stationNum: %u", _stationNum); + return MakeResult(GameActions::Status::InvalidParameters, errorTitle); + } + + if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + { + return MakeResult(GameActions::Status::NotClosed, errorTitle, STR_MUST_BE_CLOSED_FIRST); + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) + { + return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_NOT_ALLOWED_TO_MODIFY_STATION); + } + + const auto location = _isExit ? ride_get_exit_location(ride, _stationNum) : ride_get_entrance_location(ride, _stationNum); + + if (!location.isNull()) + { + auto rideEntranceExitRemove = RideEntranceExitRemoveAction(location.ToCoordsXY(), _rideIndex, _stationNum, _isExit); + rideEntranceExitRemove.SetFlags(GetFlags()); + + auto result = GameActions::QueryNested(&rideEntranceExitRemove); + if (result->Error != GameActions::Status::Ok) + { + return result; + } + } + + auto z = ride->stations[_stationNum].GetBaseZ(); + if (!LocationValid(_loc) || (!gCheatsSandboxMode && !map_is_location_owned({ _loc, z }))) + { + return MakeResult(GameActions::Status::NotOwned, errorTitle); + } + + auto clear_z = z + (_isExit ? RideExitHeight : RideEntranceHeight); + auto cost = MONEY32_UNDEFINED; + if (!map_can_construct_with_clear_at( + { _loc, z, clear_z }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags(), &cost, + CREATE_CROSSING_MODE_NONE)) + { + return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) + { + return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); + } + + if (z > MaxRideEntranceOrExitHeight) + { + return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_TOO_HIGH); + } + + auto res = MakeResult(); + res->Position = { _loc.ToTileCentre(), z }; + res->Expenditure = ExpenditureType::RideConstruction; + return res; +} + +GameActions::Result::Ptr RideEntranceExitPlaceAction::Execute() const +{ + // Remember when in unknown station num mode rideIndex is unknown and z is set + // When in known station num mode rideIndex is known and z is unknown + auto errorTitle = _isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION + : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %d", static_cast(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, errorTitle); + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + } + + const auto location = _isExit ? ride_get_exit_location(ride, _stationNum) : ride_get_entrance_location(ride, _stationNum); + if (!location.isNull()) + { + auto rideEntranceExitRemove = RideEntranceExitRemoveAction(location.ToCoordsXY(), _rideIndex, _stationNum, _isExit); + rideEntranceExitRemove.SetFlags(GetFlags()); + + auto result = GameActions::ExecuteNested(&rideEntranceExitRemove); + if (result->Error != GameActions::Status::Ok) + { + return result; + } + } + + auto z = ride->stations[_stationNum].GetBaseZ(); + if (!(GetFlags() & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter({ _loc, z }); + wall_remove_at_z({ _loc, z }); + } + + auto clear_z = z + (_isExit ? RideExitHeight : RideEntranceHeight); + auto cost = MONEY32_UNDEFINED; + if (!map_can_construct_with_clear_at( + { _loc, z, clear_z }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags() | GAME_COMMAND_FLAG_APPLY, &cost, + CREATE_CROSSING_MODE_NONE)) + { + return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); + } + + auto res = MakeResult(); + res->Position = { _loc.ToTileCentre(), z }; + res->Expenditure = ExpenditureType::RideConstruction; + + TileElement* tileElement = tile_element_insert(CoordsXYZ{ _loc, z }, 0b1111); + assert(tileElement != nullptr); + tileElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); + tileElement->SetDirection(_direction); + tileElement->SetClearanceZ(clear_z); + tileElement->AsEntrance()->SetEntranceType(_isExit ? ENTRANCE_TYPE_RIDE_EXIT : ENTRANCE_TYPE_RIDE_ENTRANCE); + tileElement->AsEntrance()->SetStationIndex(_stationNum); + tileElement->AsEntrance()->SetRideIndex(_rideIndex); + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + tileElement->SetGhost(true); + } + + if (_isExit) + { + ride_set_exit_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, tileElement->GetDirection() })); + } + else + { + ride_set_entrance_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, tileElement->GetDirection() })); + ride->stations[_stationNum].LastPeepInQueue = SPRITE_INDEX_NULL; + ride->stations[_stationNum].QueueLength = 0; + + map_animation_create(MAP_ANIMATION_TYPE_RIDE_ENTRANCE, { _loc, z }); + } + + footpath_queue_chain_reset(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + maze_entrance_hedge_removal({ _loc, tileElement }); + } + + footpath_connect_edges(_loc, tileElement, GetFlags()); + footpath_update_queue_chains(); + + map_invalidate_tile_full(_loc); + + return res; +} diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.h b/src/openrct2/actions/RideEntranceExitPlaceAction.h new file mode 100644 index 0000000000..ba5be6ed22 --- /dev/null +++ b/src/openrct2/actions/RideEntranceExitPlaceAction.h @@ -0,0 +1,85 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/Entrance.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(RideEntranceExitPlaceAction, GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, GameActions::Result) +{ +private: + CoordsXY _loc; + Direction _direction{ INVALID_DIRECTION }; + NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; + StationIndex _stationNum{ STATION_INDEX_NULL }; + bool _isExit{}; + +public: + RideEntranceExitPlaceAction() = default; + + RideEntranceExitPlaceAction( + const CoordsXY& loc, Direction direction, ride_id_t rideIndex, StationIndex stationNum, bool isExit) + : _loc(loc) + , _direction(direction) + , _rideIndex(rideIndex) + , _stationNum(stationNum) + , _isExit(isExit) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + + static GameActions::Result::Ptr TrackPlaceQuery(const CoordsXYZ& loc, const bool isExit) + { + auto errorTitle = isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION + : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, errorTitle); + } + + if (!gCheatsSandboxMode && !map_is_location_owned(loc)) + { + return MakeResult(GameActions::Status::NotOwned, errorTitle); + } + + int16_t baseZ = loc.z; + int16_t clearZ = baseZ + (isExit ? RideExitHeight : RideEntranceHeight); + auto cost = MONEY32_UNDEFINED; + if (!map_can_construct_with_clear_at( + { loc, baseZ, clearZ }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, 0, &cost, CREATE_CROSSING_MODE_NONE)) + { + return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) + { + return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); + } + + if (baseZ > MaxRideEntranceOrExitHeight) + { + return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_TOO_HIGH); + } + auto res = MakeResult(); + res->Position = { loc.ToTileCentre(), tile_element_height(loc) }; + res->Expenditure = ExpenditureType::RideConstruction; + return res; + } +}; diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.hpp b/src/openrct2/actions/RideEntranceExitPlaceAction.hpp deleted file mode 100644 index 0036eb2dd1..0000000000 --- a/src/openrct2/actions/RideEntranceExitPlaceAction.hpp +++ /dev/null @@ -1,274 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../actions/RideEntranceExitRemoveAction.hpp" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../ride/Station.h" -#include "../world/Entrance.h" -#include "../world/MapAnimation.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(RideEntranceExitPlaceAction, GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, GameActions::Result) -{ -private: - CoordsXY _loc; - Direction _direction{ INVALID_DIRECTION }; - NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; - StationIndex _stationNum{ STATION_INDEX_NULL }; - bool _isExit{}; - -public: - RideEntranceExitPlaceAction() = default; - - RideEntranceExitPlaceAction( - const CoordsXY& loc, Direction direction, ride_id_t rideIndex, StationIndex stationNum, bool isExit) - : _loc(loc) - , _direction(direction) - , _rideIndex(rideIndex) - , _stationNum(stationNum) - , _isExit(isExit) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("direction", _direction); - visitor.Visit("ride", _rideIndex); - visitor.Visit("station", _stationNum); - visitor.Visit("isExit", _isExit); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_direction) << DS_TAG(_rideIndex) << DS_TAG(_stationNum) << DS_TAG(_isExit); - } - - GameActions::Result::Ptr Query() const override - { - auto errorTitle = _isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION - : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, errorTitle); - } - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %d", static_cast(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, errorTitle); - } - - if (_stationNum >= MAX_STATIONS) - { - log_warning("Invalid station number for ride. stationNum: %u", _stationNum); - return MakeResult(GameActions::Status::InvalidParameters, errorTitle); - } - - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) - { - return MakeResult(GameActions::Status::NotClosed, errorTitle, STR_MUST_BE_CLOSED_FIRST); - } - - if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) - { - return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_NOT_ALLOWED_TO_MODIFY_STATION); - } - - const auto location = _isExit ? ride_get_exit_location(ride, _stationNum) - : ride_get_entrance_location(ride, _stationNum); - - if (!location.isNull()) - { - auto rideEntranceExitRemove = RideEntranceExitRemoveAction(location.ToCoordsXY(), _rideIndex, _stationNum, _isExit); - rideEntranceExitRemove.SetFlags(GetFlags()); - - auto result = GameActions::QueryNested(&rideEntranceExitRemove); - if (result->Error != GameActions::Status::Ok) - { - return result; - } - } - - auto z = ride->stations[_stationNum].GetBaseZ(); - if (!LocationValid(_loc) || (!gCheatsSandboxMode && !map_is_location_owned({ _loc, z }))) - { - return MakeResult(GameActions::Status::NotOwned, errorTitle); - } - - auto clear_z = z + (_isExit ? RideExitHeight : RideEntranceHeight); - auto cost = MONEY32_UNDEFINED; - if (!map_can_construct_with_clear_at( - { _loc, z, clear_z }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags(), &cost, - CREATE_CROSSING_MODE_NONE)) - { - return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) - { - return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); - } - - if (z > MaxRideEntranceOrExitHeight) - { - return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_TOO_HIGH); - } - - auto res = MakeResult(); - res->Position = { _loc.ToTileCentre(), z }; - res->Expenditure = ExpenditureType::RideConstruction; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - // Remember when in unknown station num mode rideIndex is unknown and z is set - // When in known station num mode rideIndex is known and z is unknown - auto errorTitle = _isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION - : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %d", static_cast(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, errorTitle); - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - } - - const auto location = _isExit ? ride_get_exit_location(ride, _stationNum) - : ride_get_entrance_location(ride, _stationNum); - if (!location.isNull()) - { - auto rideEntranceExitRemove = RideEntranceExitRemoveAction(location.ToCoordsXY(), _rideIndex, _stationNum, _isExit); - rideEntranceExitRemove.SetFlags(GetFlags()); - - auto result = GameActions::ExecuteNested(&rideEntranceExitRemove); - if (result->Error != GameActions::Status::Ok) - { - return result; - } - } - - auto z = ride->stations[_stationNum].GetBaseZ(); - if (!(GetFlags() & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter({ _loc, z }); - wall_remove_at_z({ _loc, z }); - } - - auto clear_z = z + (_isExit ? RideExitHeight : RideEntranceHeight); - auto cost = MONEY32_UNDEFINED; - if (!map_can_construct_with_clear_at( - { _loc, z, clear_z }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags() | GAME_COMMAND_FLAG_APPLY, - &cost, CREATE_CROSSING_MODE_NONE)) - { - return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); - } - - auto res = MakeResult(); - res->Position = { _loc.ToTileCentre(), z }; - res->Expenditure = ExpenditureType::RideConstruction; - - TileElement* tileElement = tile_element_insert(CoordsXYZ{ _loc, z }, 0b1111); - assert(tileElement != nullptr); - tileElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); - tileElement->SetDirection(_direction); - tileElement->SetClearanceZ(clear_z); - tileElement->AsEntrance()->SetEntranceType(_isExit ? ENTRANCE_TYPE_RIDE_EXIT : ENTRANCE_TYPE_RIDE_ENTRANCE); - tileElement->AsEntrance()->SetStationIndex(_stationNum); - tileElement->AsEntrance()->SetRideIndex(_rideIndex); - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } - - if (_isExit) - { - ride_set_exit_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, tileElement->GetDirection() })); - } - else - { - ride_set_entrance_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, tileElement->GetDirection() })); - ride->stations[_stationNum].LastPeepInQueue = SPRITE_INDEX_NULL; - ride->stations[_stationNum].QueueLength = 0; - - map_animation_create(MAP_ANIMATION_TYPE_RIDE_ENTRANCE, { _loc, z }); - } - - footpath_queue_chain_reset(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - maze_entrance_hedge_removal({ _loc, tileElement }); - } - - footpath_connect_edges(_loc, tileElement, GetFlags()); - footpath_update_queue_chains(); - - map_invalidate_tile_full(_loc); - - return res; - } - - static GameActions::Result::Ptr TrackPlaceQuery(const CoordsXYZ& loc, const bool isExit) - { - auto errorTitle = isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION - : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, errorTitle); - } - - if (!gCheatsSandboxMode && !map_is_location_owned(loc)) - { - return MakeResult(GameActions::Status::NotOwned, errorTitle); - } - - int16_t baseZ = loc.z; - int16_t clearZ = baseZ + (isExit ? RideExitHeight : RideEntranceHeight); - auto cost = MONEY32_UNDEFINED; - if (!map_can_construct_with_clear_at( - { loc, baseZ, clearZ }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, 0, &cost, CREATE_CROSSING_MODE_NONE)) - { - return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) - { - return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); - } - - if (baseZ > MaxRideEntranceOrExitHeight) - { - return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_TOO_HIGH); - } - auto res = MakeResult(); - res->Position = { loc.ToTileCentre(), tile_element_height(loc) }; - res->Expenditure = ExpenditureType::RideConstruction; - return res; - } -}; diff --git a/src/openrct2/actions/RideEntranceExitRemoveAction.cpp b/src/openrct2/actions/RideEntranceExitRemoveAction.cpp new file mode 100644 index 0000000000..45eb9dae3e --- /dev/null +++ b/src/openrct2/actions/RideEntranceExitRemoveAction.cpp @@ -0,0 +1,180 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideEntranceExitRemoveAction.h" + +#include "../ride/Ride.h" +#include "../ride/Station.h" +#include "../world/Entrance.h" + +void RideEntranceExitRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("ride", _rideIndex); + visitor.Visit("station", _stationNum); + visitor.Visit("isExit", _isExit); +} + +void RideEntranceExitRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_rideIndex) << DS_TAG(_stationNum) << DS_TAG(_isExit); +} + +GameActions::Result::Ptr RideEntranceExitRemoveAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride id %d for entrance/exit removal", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_MUST_BE_CLOSED_FIRST); + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NOT_ALLOWED_TO_MODIFY_STATION); + } + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); + } + + bool found = false; + TileElement* tileElement = map_get_first_element_at(_loc); + + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) + continue; + + if (tileElement->GetRideIndex() != _rideIndex) + continue; + + if (tileElement->AsEntrance()->GetStationIndex() != _stationNum) + continue; + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(tileElement->IsGhost())) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE && _isExit) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT && !_isExit) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, + static_cast(_rideIndex), _stationNum); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr RideEntranceExitRemoveAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride id %d for entrance/exit removal", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + invalidate_test_results(ride); + } + + bool found = false; + TileElement* tileElement = map_get_first_element_at(_loc); + + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) + continue; + + if (tileElement->GetRideIndex() != _rideIndex) + continue; + + if (tileElement->AsEntrance()->GetStationIndex() != _stationNum) + continue; + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !tileElement->IsGhost()) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE && _isExit) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT && !_isExit) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, + static_cast(_rideIndex), _stationNum); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto res = MakeResult(); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = tile_element_height(res->Position); + + footpath_queue_chain_reset(); + maze_entrance_hedge_replacement({ _loc, tileElement }); + footpath_remove_edges_at(_loc, tileElement); + + tile_element_remove(tileElement); + + if (_isExit) + { + ride_clear_exit_location(ride, _stationNum); + } + else + { + ride_clear_entrance_location(ride, _stationNum); + } + + footpath_update_queue_chains(); + + map_invalidate_tile_full(_loc); + return res; +} diff --git a/src/openrct2/actions/RideEntranceExitRemoveAction.h b/src/openrct2/actions/RideEntranceExitRemoveAction.h new file mode 100644 index 0000000000..21e67eaa71 --- /dev/null +++ b/src/openrct2/actions/RideEntranceExitRemoveAction.h @@ -0,0 +1,43 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(RideEntranceExitRemoveAction, GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, GameActions::Result) +{ +private: + CoordsXY _loc; + NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; + StationIndex _stationNum{ STATION_INDEX_NULL }; + bool _isExit{}; + +public: + RideEntranceExitRemoveAction() = default; + + RideEntranceExitRemoveAction(const CoordsXY& loc, ride_id_t rideIndex, StationIndex stationNum, bool isExit) + : _loc(loc) + , _rideIndex(rideIndex) + , _stationNum(stationNum) + , _isExit(isExit) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideEntranceExitRemoveAction.hpp b/src/openrct2/actions/RideEntranceExitRemoveAction.hpp deleted file mode 100644 index c46cab164c..0000000000 --- a/src/openrct2/actions/RideEntranceExitRemoveAction.hpp +++ /dev/null @@ -1,206 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../ride/Ride.h" -#include "../ride/Station.h" -#include "../world/Entrance.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(RideEntranceExitRemoveAction, GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, GameActions::Result) -{ -private: - CoordsXY _loc; - NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; - StationIndex _stationNum{ STATION_INDEX_NULL }; - bool _isExit{}; - -public: - RideEntranceExitRemoveAction() = default; - - RideEntranceExitRemoveAction(const CoordsXY& loc, ride_id_t rideIndex, StationIndex stationNum, bool isExit) - : _loc(loc) - , _rideIndex(rideIndex) - , _stationNum(stationNum) - , _isExit(isExit) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("ride", _rideIndex); - visitor.Visit("station", _stationNum); - visitor.Visit("isExit", _isExit); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_rideIndex) << DS_TAG(_stationNum) << DS_TAG(_isExit); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride id %d for entrance/exit removal", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_MUST_BE_CLOSED_FIRST); - } - - if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NOT_ALLOWED_TO_MODIFY_STATION); - } - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); - } - - bool found = false; - TileElement* tileElement = map_get_first_element_at(_loc); - - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) - continue; - - if (tileElement->GetRideIndex() != _rideIndex) - continue; - - if (tileElement->AsEntrance()->GetStationIndex() != _stationNum) - continue; - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(tileElement->IsGhost())) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE && _isExit) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT && !_isExit) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, - static_cast(_rideIndex), _stationNum); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride id %d for entrance/exit removal", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - invalidate_test_results(ride); - } - - bool found = false; - TileElement* tileElement = map_get_first_element_at(_loc); - - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) - continue; - - if (tileElement->GetRideIndex() != _rideIndex) - continue; - - if (tileElement->AsEntrance()->GetStationIndex() != _stationNum) - continue; - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !tileElement->IsGhost()) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE && _isExit) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT && !_isExit) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, - static_cast(_rideIndex), _stationNum); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto res = MakeResult(); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = tile_element_height(res->Position); - - footpath_queue_chain_reset(); - maze_entrance_hedge_replacement({ _loc, tileElement }); - footpath_remove_edges_at(_loc, tileElement); - - tile_element_remove(tileElement); - - if (_isExit) - { - ride_clear_exit_location(ride, _stationNum); - } - else - { - ride_clear_entrance_location(ride, _stationNum); - } - - footpath_update_queue_chains(); - - map_invalidate_tile_full(_loc); - return res; - } -}; diff --git a/src/openrct2/actions/RideSetAppearanceAction.cpp b/src/openrct2/actions/RideSetAppearanceAction.cpp new file mode 100644 index 0000000000..b4408e4468 --- /dev/null +++ b/src/openrct2/actions/RideSetAppearanceAction.cpp @@ -0,0 +1,138 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideSetAppearanceAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../ride/Ride.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Park.h" + +void RideSetAppearanceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("type", _type); + visitor.Visit("value", _value); + visitor.Visit("index", _index); +} + +void RideSetAppearanceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_rideIndex) << DS_TAG(_type) << DS_TAG(_value) << DS_TAG(_index); +} + +GameActions::Result::Ptr RideSetAppearanceAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + switch (_type) + { + case RideSetAppearanceType::TrackColourMain: + case RideSetAppearanceType::TrackColourAdditional: + case RideSetAppearanceType::TrackColourSupports: + if (_index >= std::size(ride->track_colour)) + { + log_warning("Invalid game command, index %d out of bounds", _index); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + break; + case RideSetAppearanceType::VehicleColourBody: + case RideSetAppearanceType::VehicleColourTrim: + case RideSetAppearanceType::VehicleColourTernary: + if (_index >= std::size(ride->vehicle_colours)) + { + log_warning("Invalid game command, index %d out of bounds", _index); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + break; + case RideSetAppearanceType::VehicleColourScheme: + case RideSetAppearanceType::EntranceStyle: + break; + default: + log_warning("Invalid game command, type %d not recognised", _type); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetAppearanceAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + switch (_type) + { + case RideSetAppearanceType::TrackColourMain: + ride->track_colour[_index].main = _value; + gfx_invalidate_screen(); + break; + case RideSetAppearanceType::TrackColourAdditional: + ride->track_colour[_index].additional = _value; + gfx_invalidate_screen(); + break; + case RideSetAppearanceType::TrackColourSupports: + ride->track_colour[_index].supports = _value; + gfx_invalidate_screen(); + break; + case RideSetAppearanceType::VehicleColourBody: + ride->vehicle_colours[_index].Body = _value; + ride_update_vehicle_colours(ride); + break; + case RideSetAppearanceType::VehicleColourTrim: + ride->vehicle_colours[_index].Trim = _value; + ride_update_vehicle_colours(ride); + break; + case RideSetAppearanceType::VehicleColourTernary: + ride->vehicle_colours[_index].Ternary = _value; + ride_update_vehicle_colours(ride); + break; + case RideSetAppearanceType::VehicleColourScheme: + ride->colour_scheme_type &= ~(RIDE_COLOUR_SCHEME_DIFFERENT_PER_TRAIN | RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR); + ride->colour_scheme_type |= _value; + for (uint32_t i = 1; i < std::size(ride->vehicle_colours); i++) + { + ride->vehicle_colours[i] = ride->vehicle_colours[0]; + } + ride_update_vehicle_colours(ride); + break; + case RideSetAppearanceType::EntranceStyle: + ride->entrance_style = _value; + gLastEntranceStyle = _value; + gfx_invalidate_screen(); + break; + } + window_invalidate_by_number(WC_RIDE, _rideIndex); + + auto res = std::make_unique(); + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + } + + return res; +} diff --git a/src/openrct2/actions/RideSetAppearanceAction.h b/src/openrct2/actions/RideSetAppearanceAction.h new file mode 100644 index 0000000000..3530a35f96 --- /dev/null +++ b/src/openrct2/actions/RideSetAppearanceAction.h @@ -0,0 +1,55 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +enum class RideSetAppearanceType : uint8_t +{ + TrackColourMain, + TrackColourAdditional, + TrackColourSupports, + MazeStyle = TrackColourSupports, + VehicleColourBody, + VehicleColourTrim, + VehicleColourTernary, + VehicleColourScheme, + EntranceStyle +}; + +DEFINE_GAME_ACTION(RideSetAppearanceAction, GAME_COMMAND_SET_RIDE_APPEARANCE, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + RideSetAppearanceType _type{}; + uint8_t _value{}; + uint32_t _index{}; + +public: + RideSetAppearanceAction() = default; + RideSetAppearanceAction(ride_id_t rideIndex, RideSetAppearanceType type, uint8_t value, uint32_t index) + : _rideIndex(rideIndex) + , _type(type) + , _value(value) + , _index(index) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideSetAppearanceAction.hpp b/src/openrct2/actions/RideSetAppearanceAction.hpp deleted file mode 100644 index 02ffedee8c..0000000000 --- a/src/openrct2/actions/RideSetAppearanceAction.hpp +++ /dev/null @@ -1,176 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../ride/Ride.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../world/Park.h" -#include "GameAction.h" - -enum class RideSetAppearanceType : uint8_t -{ - TrackColourMain, - TrackColourAdditional, - TrackColourSupports, - MazeStyle = TrackColourSupports, - VehicleColourBody, - VehicleColourTrim, - VehicleColourTernary, - VehicleColourScheme, - EntranceStyle -}; - -DEFINE_GAME_ACTION(RideSetAppearanceAction, GAME_COMMAND_SET_RIDE_APPEARANCE, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - RideSetAppearanceType _type{}; - uint8_t _value{}; - uint32_t _index{}; - -public: - RideSetAppearanceAction() = default; - RideSetAppearanceAction(ride_id_t rideIndex, RideSetAppearanceType type, uint8_t value, uint32_t index) - : _rideIndex(rideIndex) - , _type(type) - , _value(value) - , _index(index) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("type", _type); - visitor.Visit("value", _value); - visitor.Visit("index", _index); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_rideIndex) << DS_TAG(_type) << DS_TAG(_value) << DS_TAG(_index); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - switch (_type) - { - case RideSetAppearanceType::TrackColourMain: - case RideSetAppearanceType::TrackColourAdditional: - case RideSetAppearanceType::TrackColourSupports: - if (_index >= std::size(ride->track_colour)) - { - log_warning("Invalid game command, index %d out of bounds", _index); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - break; - case RideSetAppearanceType::VehicleColourBody: - case RideSetAppearanceType::VehicleColourTrim: - case RideSetAppearanceType::VehicleColourTernary: - if (_index >= std::size(ride->vehicle_colours)) - { - log_warning("Invalid game command, index %d out of bounds", _index); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - break; - case RideSetAppearanceType::VehicleColourScheme: - case RideSetAppearanceType::EntranceStyle: - break; - default: - log_warning("Invalid game command, type %d not recognised", _type); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - switch (_type) - { - case RideSetAppearanceType::TrackColourMain: - ride->track_colour[_index].main = _value; - gfx_invalidate_screen(); - break; - case RideSetAppearanceType::TrackColourAdditional: - ride->track_colour[_index].additional = _value; - gfx_invalidate_screen(); - break; - case RideSetAppearanceType::TrackColourSupports: - ride->track_colour[_index].supports = _value; - gfx_invalidate_screen(); - break; - case RideSetAppearanceType::VehicleColourBody: - ride->vehicle_colours[_index].Body = _value; - ride_update_vehicle_colours(ride); - break; - case RideSetAppearanceType::VehicleColourTrim: - ride->vehicle_colours[_index].Trim = _value; - ride_update_vehicle_colours(ride); - break; - case RideSetAppearanceType::VehicleColourTernary: - ride->vehicle_colours[_index].Ternary = _value; - ride_update_vehicle_colours(ride); - break; - case RideSetAppearanceType::VehicleColourScheme: - ride->colour_scheme_type &= ~(RIDE_COLOUR_SCHEME_DIFFERENT_PER_TRAIN | RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR); - ride->colour_scheme_type |= _value; - for (uint32_t i = 1; i < std::size(ride->vehicle_colours); i++) - { - ride->vehicle_colours[i] = ride->vehicle_colours[0]; - } - ride_update_vehicle_colours(ride); - break; - case RideSetAppearanceType::EntranceStyle: - ride->entrance_style = _value; - gLastEntranceStyle = _value; - gfx_invalidate_screen(); - break; - } - window_invalidate_by_number(WC_RIDE, _rideIndex); - - auto res = std::make_unique(); - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - } - - return res; - } -}; diff --git a/src/openrct2/actions/RideSetColourScheme.hpp b/src/openrct2/actions/RideSetColourScheme.hpp deleted file mode 100644 index 470f69dff3..0000000000 --- a/src/openrct2/actions/RideSetColourScheme.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(RideSetColourSchemeAction, GAME_COMMAND_SET_COLOUR_SCHEME, GameActions::Result) -{ -private: - CoordsXYZD _loc; - int32_t _trackType{}; - uint16_t _newColourScheme{}; - -public: - RideSetColourSchemeAction() = default; - RideSetColourSchemeAction(const CoordsXYZD& location, int32_t trackType, uint16_t newColourScheme) - : _loc(location) - , _trackType(trackType) - , _newColourScheme(newColourScheme) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("trackType", _trackType); - visitor.Visit("colourScheme", _newColourScheme); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_trackType) << DS_TAG(_newColourScheme); - } - - GameActions::Result::Ptr Query() const override - { - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); - } - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Expenditure = ExpenditureType::RideConstruction; - res->ErrorTitle = STR_CANT_SET_COLOUR_SCHEME; - - sub_6C683D(_loc, _trackType, _newColourScheme, nullptr, TRACK_ELEMENT_SET_COLOUR_SCHEME); - - return res; - } -}; diff --git a/src/openrct2/actions/RideSetColourSchemeAction.cpp b/src/openrct2/actions/RideSetColourSchemeAction.cpp new file mode 100644 index 0000000000..33a1aeed4e --- /dev/null +++ b/src/openrct2/actions/RideSetColourSchemeAction.cpp @@ -0,0 +1,55 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideSetColourSchemeAction.h" + +#include "../Cheats.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../world/Park.h" +#include "../world/Sprite.h" + +void RideSetColourSchemeAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("trackType", _trackType); + visitor.Visit("colourScheme", _newColourScheme); +} + +void RideSetColourSchemeAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_trackType) << DS_TAG(_newColourScheme); +} + +GameActions::Result::Ptr RideSetColourSchemeAction::Query() const +{ + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); + } + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetColourSchemeAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Expenditure = ExpenditureType::RideConstruction; + res->ErrorTitle = STR_CANT_SET_COLOUR_SCHEME; + + sub_6C683D(_loc, _trackType, _newColourScheme, nullptr, TRACK_ELEMENT_SET_COLOUR_SCHEME); + + return res; +} diff --git a/src/openrct2/actions/RideSetColourSchemeAction.h b/src/openrct2/actions/RideSetColourSchemeAction.h new file mode 100644 index 0000000000..1afd87b396 --- /dev/null +++ b/src/openrct2/actions/RideSetColourSchemeAction.h @@ -0,0 +1,40 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(RideSetColourSchemeAction, GAME_COMMAND_SET_COLOUR_SCHEME, GameActions::Result) +{ +private: + CoordsXYZD _loc; + int32_t _trackType{}; + uint16_t _newColourScheme{}; + +public: + RideSetColourSchemeAction() = default; + RideSetColourSchemeAction(const CoordsXYZD& location, int32_t trackType, uint16_t newColourScheme) + : _loc(location) + , _trackType(trackType) + , _newColourScheme(newColourScheme) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideSetName.hpp b/src/openrct2/actions/RideSetName.hpp deleted file mode 100644 index aad6894eee..0000000000 --- a/src/openrct2/actions/RideSetName.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../ride/Ride.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../world/Park.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(RideSetNameAction, GAME_COMMAND_SET_RIDE_NAME, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - std::string _name; - -public: - RideSetNameAction() = default; - RideSetNameAction(ride_id_t rideIndex, const std::string& name) - : _rideIndex(rideIndex) - , _name(name) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("name", _name); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_NONE); - } - - if (!_name.empty() && Ride::NameExists(_name, ride->id)) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_ERROR_EXISTING_NAME); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_NONE); - } - - if (_name.empty()) - { - ride->SetNameToDefault(); - } - else - { - ride->custom_name = _name; - } - - scrolling_text_invalidate(); - gfx_invalidate_screen(); - - // Refresh windows that display ride name - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_RIDE_LIST)); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_GUEST_LIST)); - - auto res = std::make_unique(); - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - - return res; - } -}; diff --git a/src/openrct2/actions/RideSetNameAction.cpp b/src/openrct2/actions/RideSetNameAction.cpp new file mode 100644 index 0000000000..888c60c23d --- /dev/null +++ b/src/openrct2/actions/RideSetNameAction.cpp @@ -0,0 +1,89 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideSetNameAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../ride/Ride.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Park.h" + +void RideSetNameAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("name", _name); +} + +void RideSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_name); +} + +GameActions::Result::Ptr RideSetNameAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_NONE); + } + + if (!_name.empty() && Ride::NameExists(_name, ride->id)) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_ERROR_EXISTING_NAME); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetNameAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_NONE); + } + + if (_name.empty()) + { + ride->SetNameToDefault(); + } + else + { + ride->custom_name = _name; + } + + scrolling_text_invalidate(); + gfx_invalidate_screen(); + + // Refresh windows that display ride name + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_RIDE_LIST)); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_GUEST_LIST)); + + auto res = std::make_unique(); + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + + return res; +} diff --git a/src/openrct2/actions/RideSetNameAction.h b/src/openrct2/actions/RideSetNameAction.h new file mode 100644 index 0000000000..4dbb4fa967 --- /dev/null +++ b/src/openrct2/actions/RideSetNameAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(RideSetNameAction, GAME_COMMAND_SET_RIDE_NAME, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + std::string _name; + +public: + RideSetNameAction() = default; + RideSetNameAction(ride_id_t rideIndex, const std::string& name) + : _rideIndex(rideIndex) + , _name(name) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideSetPriceAction.cpp b/src/openrct2/actions/RideSetPriceAction.cpp new file mode 100644 index 0000000000..918fb16a97 --- /dev/null +++ b/src/openrct2/actions/RideSetPriceAction.cpp @@ -0,0 +1,175 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideSetPriceAction.h" + +#include "../Cheats.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../ride/RideData.h" +#include "../ride/ShopItem.h" +#include "../world/Park.h" +#include "../world/Sprite.h" + +void RideSetPriceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("price", _price); + visitor.Visit("isPrimaryPrice", _primaryPrice); +} + +void RideSetPriceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_price) << DS_TAG(_primaryPrice); +} + +GameActions::Result::Ptr RideSetPriceAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return res; +} + +GameActions::Result::Ptr RideSetPriceAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Expenditure = ExpenditureType::ParkRideTickets; + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + } + + ShopItem shopItem; + if (_primaryPrice) + { + shopItem = ShopItem::Admission; + if (ride->type != RIDE_TYPE_TOILETS) + { + shopItem = rideEntry->shop_item[0]; + if (shopItem == ShopItem::None) + { + ride->price[0] = _price; + window_invalidate_by_class(WC_RIDE); + return res; + } + } + // Check same price in park flags + if (!shop_item_has_common_price(shopItem)) + { + ride->price[0] = _price; + window_invalidate_by_class(WC_RIDE); + return res; + } + } + else + { + shopItem = rideEntry->shop_item[1]; + if (shopItem == ShopItem::None) + { + shopItem = RideTypeDescriptors[ride->type].PhotoItem; + if ((ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) == 0) + { + ride->price[1] = _price; + window_invalidate_by_class(WC_RIDE); + return res; + } + } + // Check same price in park flags + if (!shop_item_has_common_price(shopItem)) + { + ride->price[1] = _price; + window_invalidate_by_class(WC_RIDE); + return res; + } + } + + // Synchronize prices if enabled. + RideSetCommonPrice(shopItem); + + return res; +} + +void RideSetPriceAction::RideSetCommonPrice(ShopItem shopItem) const +{ + for (auto& ride : GetRideManager()) + { + auto invalidate = false; + auto rideEntry = get_ride_entry(ride.subtype); + if (ride.type == RIDE_TYPE_TOILETS && shopItem == ShopItem::Admission) + { + if (ride.price[0] != _price) + { + ride.price[0] = _price; + invalidate = true; + } + } + else if (rideEntry != nullptr && rideEntry->shop_item[0] == shopItem) + { + if (ride.price[0] != _price) + { + ride.price[0] = _price; + invalidate = true; + } + } + if (rideEntry != nullptr) + { + // If the shop item is the same or an on-ride photo + if (rideEntry->shop_item[1] == shopItem + || (rideEntry->shop_item[1] == ShopItem::None && GetShopItemDescriptor(shopItem).IsPhoto())) + { + if (ride.price[1] != _price) + { + ride.price[1] = _price; + invalidate = true; + } + } + } + if (invalidate) + { + window_invalidate_by_number(WC_RIDE, ride.id); + } + } +} diff --git a/src/openrct2/actions/RideSetPriceAction.h b/src/openrct2/actions/RideSetPriceAction.h new file mode 100644 index 0000000000..1987b68883 --- /dev/null +++ b/src/openrct2/actions/RideSetPriceAction.h @@ -0,0 +1,43 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(RideSetPriceAction, GAME_COMMAND_SET_RIDE_PRICE, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + money16 _price{ MONEY16_UNDEFINED }; + bool _primaryPrice{ true }; + +public: + RideSetPriceAction() = default; + RideSetPriceAction(ride_id_t rideIndex, money16 price, bool primaryPrice) + : _rideIndex(rideIndex) + , _price(price) + , _primaryPrice(primaryPrice) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + void RideSetCommonPrice(ShopItem shopItem) const; +}; diff --git a/src/openrct2/actions/RideSetPriceAction.hpp b/src/openrct2/actions/RideSetPriceAction.hpp deleted file mode 100644 index 6b370821f1..0000000000 --- a/src/openrct2/actions/RideSetPriceAction.hpp +++ /dev/null @@ -1,199 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../ride/RideData.h" -#include "../ride/ShopItem.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(RideSetPriceAction, GAME_COMMAND_SET_RIDE_PRICE, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - money16 _price{ MONEY16_UNDEFINED }; - bool _primaryPrice{ true }; - -public: - RideSetPriceAction() = default; - RideSetPriceAction(ride_id_t rideIndex, money16 price, bool primaryPrice) - : _rideIndex(rideIndex) - , _price(price) - , _primaryPrice(primaryPrice) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("price", _price); - visitor.Visit("isPrimaryPrice", _primaryPrice); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_price) << DS_TAG(_primaryPrice); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Expenditure = ExpenditureType::ParkRideTickets; - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - } - - ShopItem shopItem; - if (_primaryPrice) - { - shopItem = ShopItem::Admission; - if (ride->type != RIDE_TYPE_TOILETS) - { - shopItem = rideEntry->shop_item[0]; - if (shopItem == ShopItem::None) - { - ride->price[0] = _price; - window_invalidate_by_class(WC_RIDE); - return res; - } - } - // Check same price in park flags - if (!shop_item_has_common_price(shopItem)) - { - ride->price[0] = _price; - window_invalidate_by_class(WC_RIDE); - return res; - } - } - else - { - shopItem = rideEntry->shop_item[1]; - if (shopItem == ShopItem::None) - { - shopItem = RideTypeDescriptors[ride->type].PhotoItem; - if ((ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) == 0) - { - ride->price[1] = _price; - window_invalidate_by_class(WC_RIDE); - return res; - } - } - // Check same price in park flags - if (!shop_item_has_common_price(shopItem)) - { - ride->price[1] = _price; - window_invalidate_by_class(WC_RIDE); - return res; - } - } - - // Synchronize prices if enabled. - RideSetCommonPrice(shopItem); - - return res; - } - -private: - void RideSetCommonPrice(ShopItem shopItem) const - { - for (auto& ride : GetRideManager()) - { - auto invalidate = false; - auto rideEntry = get_ride_entry(ride.subtype); - if (ride.type == RIDE_TYPE_TOILETS && shopItem == ShopItem::Admission) - { - if (ride.price[0] != _price) - { - ride.price[0] = _price; - invalidate = true; - } - } - else if (rideEntry != nullptr && rideEntry->shop_item[0] == shopItem) - { - if (ride.price[0] != _price) - { - ride.price[0] = _price; - invalidate = true; - } - } - if (rideEntry != nullptr) - { - // If the shop item is the same or an on-ride photo - if (rideEntry->shop_item[1] == shopItem - || (rideEntry->shop_item[1] == ShopItem::None && GetShopItemDescriptor(shopItem).IsPhoto())) - { - if (ride.price[1] != _price) - { - ride.price[1] = _price; - invalidate = true; - } - } - } - if (invalidate) - { - window_invalidate_by_number(WC_RIDE, ride.id); - } - } - } -}; diff --git a/src/openrct2/actions/RideSetSetting.hpp b/src/openrct2/actions/RideSetSetting.hpp deleted file mode 100644 index 4748483aeb..0000000000 --- a/src/openrct2/actions/RideSetSetting.hpp +++ /dev/null @@ -1,324 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../ride/Ride.h" -#include "../ride/RideData.h" -#include "GameAction.h" - -enum class RideSetSetting : uint8_t -{ - Mode, - Departure, - MinWaitingTime, - MaxWaitingTime, - Operation, - InspectionInterval, - Music, - MusicType, - LiftHillSpeed, - NumCircuits, - RideType, -}; - -DEFINE_GAME_ACTION(RideSetSettingAction, GAME_COMMAND_SET_RIDE_SETTING, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - RideSetSetting _setting{}; - uint8_t _value{}; - -public: - RideSetSettingAction() = default; - RideSetSettingAction(ride_id_t rideIndex, RideSetSetting setting, uint8_t value) - : _rideIndex(rideIndex) - , _setting(setting) - , _value(value) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("setting", _setting); - visitor.Visit("value", _value); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_setting) << DS_TAG(_value); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride: #%d.", static_cast(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - - switch (_setting) - { - case RideSetSetting::Mode: - if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) - { - return MakeResult( - GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE, - STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); - } - - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) - { - return MakeResult( - GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE, STR_MUST_BE_CLOSED_FIRST); - } - - if (!ride_is_mode_valid(ride) && !gCheatsShowAllOperatingModes) - { - log_warning("Invalid ride mode: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::Departure: - break; - case RideSetSetting::MinWaitingTime: - if (_value > 250) - { - log_warning("Invalid minimum waiting time: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::MaxWaitingTime: - if (_value > 250) - { - log_warning("Invalid maximum waiting time: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::Operation: - if (!ride_is_valid_operation_option(ride)) - { - log_warning("Invalid operation option value: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, GetOperationErrorMessage(ride)); - } - break; - case RideSetSetting::InspectionInterval: - if (_value > RIDE_INSPECTION_NEVER) - { - log_warning("Invalid inspection interval: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::Music: - break; - case RideSetSetting::MusicType: - if (_value >= MUSIC_STYLE_COUNT) - { - log_warning("Invalid music style: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::LiftHillSpeed: - if (!ride_is_valid_lift_hill_speed(ride)) - { - log_warning("Invalid lift hill speed: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::NumCircuits: - if (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT && _value > 1) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE, - STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL); - } - - if (!ride_is_valid_num_circuits()) - { - log_warning("Invalid number of circuits: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::RideType: - if (!gCheatsAllowArbitraryRideTypeChanges) - { - log_warning("Arbitary ride type changes not allowed."); - return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - default: - log_warning("Invalid RideSetSetting: %u", static_cast(_setting)); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - break; - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride: #%d.", static_cast(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - - switch (_setting) - { - case RideSetSetting::Mode: - invalidate_test_results(ride); - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - - ride->mode = static_cast(_value); - ride->UpdateMaxVehicles(); - ride->UpdateNumberOfCircuits(); - break; - case RideSetSetting::Departure: - ride->depart_flags = _value; - break; - case RideSetSetting::MinWaitingTime: - ride->min_waiting_time = _value; - ride->max_waiting_time = std::max(_value, ride->max_waiting_time); - break; - case RideSetSetting::MaxWaitingTime: - ride->max_waiting_time = _value; - ride->min_waiting_time = std::min(_value, ride->min_waiting_time); - break; - case RideSetSetting::Operation: - invalidate_test_results(ride); - ride->operation_option = _value; - break; - case RideSetSetting::InspectionInterval: - - if (_value == RIDE_INSPECTION_NEVER) - { - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_DUE_INSPECTION; - } - - ride->inspection_interval = _value; - break; - case RideSetSetting::Music: - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_MUSIC; - if (_value) - { - ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; - } - break; - case RideSetSetting::MusicType: - if (_value != ride->music) - { - ride->music = _value; - ride->music_tune_id = 0xFF; - } - break; - case RideSetSetting::LiftHillSpeed: - if (_value != ride->lift_hill_speed) - { - ride->lift_hill_speed = _value; - invalidate_test_results(ride); - } - break; - case RideSetSetting::NumCircuits: - if (_value != ride->num_circuits) - { - ride->num_circuits = _value; - invalidate_test_results(ride); - } - - break; - case RideSetSetting::RideType: - ride->type = _value; - gfx_invalidate_screen(); - break; - } - - auto res = std::make_unique(); - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - } - window_invalidate_by_number(WC_RIDE, _rideIndex); - return res; - } - -private: - bool ride_is_mode_valid(Ride * ride) const - { - return RideTypeDescriptors[ride->type].RideModes & (1ULL << _value); - } - - bool ride_is_valid_lift_hill_speed(Ride * ride) const - { - int32_t minSpeed = gCheatsFastLiftHill ? 0 : RideTypeDescriptors[ride->type].LiftData.minimum_speed; - int32_t maxSpeed = gCheatsFastLiftHill ? 255 : RideTypeDescriptors[ride->type].LiftData.maximum_speed; - return _value >= minSpeed && _value <= maxSpeed; - } - - bool ride_is_valid_num_circuits() const - { - int32_t minNumCircuits = 1; - int32_t maxNumCircuits = gCheatsFastLiftHill ? 255 : 20; - return _value >= minNumCircuits && _value <= maxNumCircuits; - } - - bool ride_is_valid_operation_option(Ride * ride) const - { - const auto& operatingSettings = RideTypeDescriptors[ride->type].OperatingSettings; - uint8_t minValue = operatingSettings.MinValue; - uint8_t maxValue = operatingSettings.MaxValue; - if (gCheatsFastLiftHill) - { - minValue = 0; - maxValue = 255; - } - - return _value >= minValue && _value <= maxValue; - } - - rct_string_id GetOperationErrorMessage(Ride * ride) const - { - switch (ride->mode) - { - case RideMode::StationToStation: - return STR_CANT_CHANGE_SPEED; - case RideMode::Race: - return STR_CANT_CHANGE_NUMBER_OF_LAPS; - case RideMode::Dodgems: - return STR_CANT_CHANGE_TIME_LIMIT; - case RideMode::Swing: - return STR_CANT_CHANGE_NUMBER_OF_SWINGS; - case RideMode::Rotation: - case RideMode::ForwardRotation: - case RideMode::BackwardRotation: - return STR_CANT_CHANGE_NUMBER_OF_ROTATIONS; - default: - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_VEHICLES)) - { - return STR_CANT_CHANGE_THIS; - } - else - { - return STR_CANT_CHANGE_LAUNCH_SPEED; - } - break; - } - } -}; diff --git a/src/openrct2/actions/RideSetSettingAction.cpp b/src/openrct2/actions/RideSetSettingAction.cpp new file mode 100644 index 0000000000..7d8f401889 --- /dev/null +++ b/src/openrct2/actions/RideSetSettingAction.cpp @@ -0,0 +1,281 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideSetSettingAction.h" + +#include "../ride/Ride.h" +#include "../ride/RideData.h" + +void RideSetSettingAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("setting", _setting); + visitor.Visit("value", _value); +} + +void RideSetSettingAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_setting) << DS_TAG(_value); +} + +GameActions::Result::Ptr RideSetSettingAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride: #%d.", static_cast(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + + switch (_setting) + { + case RideSetSetting::Mode: + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) + { + return MakeResult( + GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); + } + + if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE, STR_MUST_BE_CLOSED_FIRST); + } + + if (!ride_is_mode_valid(ride) && !gCheatsShowAllOperatingModes) + { + log_warning("Invalid ride mode: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::Departure: + break; + case RideSetSetting::MinWaitingTime: + if (_value > 250) + { + log_warning("Invalid minimum waiting time: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::MaxWaitingTime: + if (_value > 250) + { + log_warning("Invalid maximum waiting time: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::Operation: + if (!ride_is_valid_operation_option(ride)) + { + log_warning("Invalid operation option value: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, GetOperationErrorMessage(ride)); + } + break; + case RideSetSetting::InspectionInterval: + if (_value > RIDE_INSPECTION_NEVER) + { + log_warning("Invalid inspection interval: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::Music: + break; + case RideSetSetting::MusicType: + if (_value >= MUSIC_STYLE_COUNT) + { + log_warning("Invalid music style: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::LiftHillSpeed: + if (!ride_is_valid_lift_hill_speed(ride)) + { + log_warning("Invalid lift hill speed: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::NumCircuits: + if (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT && _value > 1) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE, + STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL); + } + + if (!ride_is_valid_num_circuits()) + { + log_warning("Invalid number of circuits: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::RideType: + if (!gCheatsAllowArbitraryRideTypeChanges) + { + log_warning("Arbitary ride type changes not allowed."); + return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + default: + log_warning("Invalid RideSetSetting: %u", static_cast(_setting)); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetSettingAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride: #%d.", static_cast(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + + switch (_setting) + { + case RideSetSetting::Mode: + invalidate_test_results(ride); + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + + ride->mode = static_cast(_value); + ride->UpdateMaxVehicles(); + ride->UpdateNumberOfCircuits(); + break; + case RideSetSetting::Departure: + ride->depart_flags = _value; + break; + case RideSetSetting::MinWaitingTime: + ride->min_waiting_time = _value; + ride->max_waiting_time = std::max(_value, ride->max_waiting_time); + break; + case RideSetSetting::MaxWaitingTime: + ride->max_waiting_time = _value; + ride->min_waiting_time = std::min(_value, ride->min_waiting_time); + break; + case RideSetSetting::Operation: + invalidate_test_results(ride); + ride->operation_option = _value; + break; + case RideSetSetting::InspectionInterval: + + if (_value == RIDE_INSPECTION_NEVER) + { + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_DUE_INSPECTION; + } + + ride->inspection_interval = _value; + break; + case RideSetSetting::Music: + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_MUSIC; + if (_value) + { + ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; + } + break; + case RideSetSetting::MusicType: + if (_value != ride->music) + { + ride->music = _value; + ride->music_tune_id = 0xFF; + } + break; + case RideSetSetting::LiftHillSpeed: + if (_value != ride->lift_hill_speed) + { + ride->lift_hill_speed = _value; + invalidate_test_results(ride); + } + break; + case RideSetSetting::NumCircuits: + if (_value != ride->num_circuits) + { + ride->num_circuits = _value; + invalidate_test_results(ride); + } + + break; + case RideSetSetting::RideType: + ride->type = _value; + gfx_invalidate_screen(); + break; + } + + auto res = std::make_unique(); + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + } + window_invalidate_by_number(WC_RIDE, _rideIndex); + return res; +} + +bool RideSetSettingAction::ride_is_mode_valid(Ride* ride) const +{ + return RideTypeDescriptors[ride->type].RideModes & (1ULL << _value); +} + +bool RideSetSettingAction::ride_is_valid_lift_hill_speed(Ride* ride) const +{ + int32_t minSpeed = gCheatsFastLiftHill ? 0 : RideTypeDescriptors[ride->type].LiftData.minimum_speed; + int32_t maxSpeed = gCheatsFastLiftHill ? 255 : RideTypeDescriptors[ride->type].LiftData.maximum_speed; + return _value >= minSpeed && _value <= maxSpeed; +} + +bool RideSetSettingAction::ride_is_valid_num_circuits() const +{ + int32_t minNumCircuits = 1; + int32_t maxNumCircuits = gCheatsFastLiftHill ? 255 : 20; + return _value >= minNumCircuits && _value <= maxNumCircuits; +} + +bool RideSetSettingAction::ride_is_valid_operation_option(Ride* ride) const +{ + const auto& operatingSettings = RideTypeDescriptors[ride->type].OperatingSettings; + uint8_t minValue = operatingSettings.MinValue; + uint8_t maxValue = operatingSettings.MaxValue; + if (gCheatsFastLiftHill) + { + minValue = 0; + maxValue = 255; + } + + return _value >= minValue && _value <= maxValue; +} + +rct_string_id RideSetSettingAction::GetOperationErrorMessage(Ride* ride) const +{ + switch (ride->mode) + { + case RideMode::StationToStation: + return STR_CANT_CHANGE_SPEED; + case RideMode::Race: + return STR_CANT_CHANGE_NUMBER_OF_LAPS; + case RideMode::Dodgems: + return STR_CANT_CHANGE_TIME_LIMIT; + case RideMode::Swing: + return STR_CANT_CHANGE_NUMBER_OF_SWINGS; + case RideMode::Rotation: + case RideMode::ForwardRotation: + case RideMode::BackwardRotation: + return STR_CANT_CHANGE_NUMBER_OF_ROTATIONS; + default: + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_VEHICLES)) + { + return STR_CANT_CHANGE_THIS; + } + else + { + return STR_CANT_CHANGE_LAUNCH_SPEED; + } + } +} diff --git a/src/openrct2/actions/RideSetSettingAction.h b/src/openrct2/actions/RideSetSettingAction.h new file mode 100644 index 0000000000..6af75ff9ab --- /dev/null +++ b/src/openrct2/actions/RideSetSettingAction.h @@ -0,0 +1,62 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +enum class RideSetSetting : uint8_t +{ + Mode, + Departure, + MinWaitingTime, + MaxWaitingTime, + Operation, + InspectionInterval, + Music, + MusicType, + LiftHillSpeed, + NumCircuits, + RideType, +}; + +DEFINE_GAME_ACTION(RideSetSettingAction, GAME_COMMAND_SET_RIDE_SETTING, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + RideSetSetting _setting{}; + uint8_t _value{}; + +public: + RideSetSettingAction() = default; + RideSetSettingAction(ride_id_t rideIndex, RideSetSetting setting, uint8_t value) + : _rideIndex(rideIndex) + , _setting(setting) + , _value(value) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + bool ride_is_mode_valid(Ride * ride) const; + bool ride_is_valid_lift_hill_speed(Ride * ride) const; + bool ride_is_valid_num_circuits() const; + bool ride_is_valid_operation_option(Ride * ride) const; + rct_string_id GetOperationErrorMessage(Ride * ride) const; +}; diff --git a/src/openrct2/actions/RideSetStatus.hpp b/src/openrct2/actions/RideSetStatus.hpp deleted file mode 100644 index 6fed33f790..0000000000 --- a/src/openrct2/actions/RideSetStatus.hpp +++ /dev/null @@ -1,248 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -static rct_string_id _StatusErrorTitles[] = { - STR_CANT_CLOSE, - STR_CANT_OPEN, - STR_CANT_TEST, - STR_CANT_SIMULATE, -}; - -DEFINE_GAME_ACTION(RideSetStatusAction, GAME_COMMAND_SET_RIDE_STATUS, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - uint8_t _status{ RIDE_STATUS_CLOSED }; - -public: - RideSetStatusAction() = default; - RideSetStatusAction(ride_id_t rideIndex, uint8_t status) - : _rideIndex(rideIndex) - , _status(status) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("status", _status); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_status); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - res->Error = GameActions::Status::InvalidParameters; - res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; - res->ErrorMessage = STR_NONE; - return res; - } - - if (_status >= RIDE_STATUS_COUNT) - { - log_warning("Invalid ride status %u for ride %u", uint32_t(_status), uint32_t(_rideIndex)); - res->Error = GameActions::Status::InvalidParameters; - res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; - res->ErrorMessage = STR_NONE; - return res; - } - - res->ErrorTitle = _StatusErrorTitles[_status]; - - Formatter ft(res->ErrorMessageArgs.data()); - ft.Increment(6); - ride->FormatNameTo(ft); - if (_status != ride->status) - { - if (_status == RIDE_STATUS_SIMULATING && (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) - { - // Simulating will force clear the track, so make sure player can't cheat around a break down - res->Error = GameActions::Status::Disallowed; - res->ErrorMessage = STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING; - return res; - } - else if (_status == RIDE_STATUS_TESTING || _status == RIDE_STATUS_SIMULATING) - { - if (!ride->Test(_status, false)) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = gGameCommandErrorText; - return res; - } - } - else if (_status == RIDE_STATUS_OPEN) - { - if (!ride->Open(false)) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = gGameCommandErrorText; - return res; - } - } - } - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Expenditure = ExpenditureType::RideRunningCosts; - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - res->Error = GameActions::Status::InvalidParameters; - res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; - res->ErrorMessage = STR_NONE; - return res; - } - - res->ErrorTitle = _StatusErrorTitles[_status]; - - Formatter ft(res->ErrorMessageArgs.data()); - ft.Increment(6); - ride->FormatNameTo(ft); - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(res->Position) }; - } - - switch (_status) - { - case RIDE_STATUS_CLOSED: - if (ride->status == _status || ride->status == RIDE_STATUS_SIMULATING) - { - if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) - { - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - } - } - - ride->status = RIDE_STATUS_CLOSED; - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; - ride->race_winner = SPRITE_INDEX_NULL; - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - window_invalidate_by_number(WC_RIDE, _rideIndex); - break; - case RIDE_STATUS_SIMULATING: - { - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - - if (!ride->Test(_status, true)) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = gGameCommandErrorText; - return res; - } - - ride->status = _status; - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; - ride->race_winner = SPRITE_INDEX_NULL; - ride->current_issues = 0; - ride->last_issue_time = 0; - ride->GetMeasurement(); - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - window_invalidate_by_number(WC_RIDE, _rideIndex); - break; - } - case RIDE_STATUS_TESTING: - case RIDE_STATUS_OPEN: - { - if (ride->status == _status) - { - return res; - } - - if (ride->status == RIDE_STATUS_SIMULATING) - { - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - } - - // Fix #3183: Make sure we close the construction window so the ride finishes any editing code before opening - // otherwise vehicles get added to the ride incorrectly (such as to a ghost station) - rct_window* constructionWindow = window_find_by_number(WC_RIDE_CONSTRUCTION, _rideIndex); - if (constructionWindow != nullptr) - { - window_close(constructionWindow); - } - - if (_status == RIDE_STATUS_TESTING) - { - if (!ride->Test(_status, true)) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = gGameCommandErrorText; - return res; - } - } - else if (!ride->Open(true)) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = gGameCommandErrorText; - return res; - } - - ride->race_winner = SPRITE_INDEX_NULL; - ride->status = _status; - ride->current_issues = 0; - ride->last_issue_time = 0; - ride->GetMeasurement(); - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - window_invalidate_by_number(WC_RIDE, _rideIndex); - break; - } - default: - Guard::Assert(false, "Invalid status passed: %u", _status); - break; - } - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); - - return res; - } -}; diff --git a/src/openrct2/actions/RideSetStatusAction.cpp b/src/openrct2/actions/RideSetStatusAction.cpp new file mode 100644 index 0000000000..25242653e8 --- /dev/null +++ b/src/openrct2/actions/RideSetStatusAction.cpp @@ -0,0 +1,227 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideSetStatusAction.h" + +#include "../Cheats.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Park.h" +#include "../world/Sprite.h" + +static rct_string_id _StatusErrorTitles[] = { + STR_CANT_CLOSE, + STR_CANT_OPEN, + STR_CANT_TEST, + STR_CANT_SIMULATE, +}; + +void RideSetStatusAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("status", _status); +} + +void RideSetStatusAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_status); +} + +GameActions::Result::Ptr RideSetStatusAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + res->Error = GameActions::Status::InvalidParameters; + res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; + res->ErrorMessage = STR_NONE; + return res; + } + + if (_status >= RIDE_STATUS_COUNT) + { + log_warning("Invalid ride status %u for ride %u", uint32_t(_status), uint32_t(_rideIndex)); + res->Error = GameActions::Status::InvalidParameters; + res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; + res->ErrorMessage = STR_NONE; + return res; + } + + res->ErrorTitle = _StatusErrorTitles[_status]; + + Formatter ft(res->ErrorMessageArgs.data()); + ft.Increment(6); + ride->FormatNameTo(ft); + if (_status != ride->status) + { + if (_status == RIDE_STATUS_SIMULATING && (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) + { + // Simulating will force clear the track, so make sure player can't cheat around a break down + res->Error = GameActions::Status::Disallowed; + res->ErrorMessage = STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING; + return res; + } + else if (_status == RIDE_STATUS_TESTING || _status == RIDE_STATUS_SIMULATING) + { + if (!ride->Test(_status, false)) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = gGameCommandErrorText; + return res; + } + } + else if (_status == RIDE_STATUS_OPEN) + { + if (!ride->Open(false)) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = gGameCommandErrorText; + return res; + } + } + } + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetStatusAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Expenditure = ExpenditureType::RideRunningCosts; + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + res->Error = GameActions::Status::InvalidParameters; + res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; + res->ErrorMessage = STR_NONE; + return res; + } + + res->ErrorTitle = _StatusErrorTitles[_status]; + + Formatter ft(res->ErrorMessageArgs.data()); + ft.Increment(6); + ride->FormatNameTo(ft); + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(res->Position) }; + } + + switch (_status) + { + case RIDE_STATUS_CLOSED: + if (ride->status == _status || ride->status == RIDE_STATUS_SIMULATING) + { + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) + { + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + } + } + + ride->status = RIDE_STATUS_CLOSED; + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; + ride->race_winner = SPRITE_INDEX_NULL; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + window_invalidate_by_number(WC_RIDE, _rideIndex); + break; + case RIDE_STATUS_SIMULATING: + { + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + + if (!ride->Test(_status, true)) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = gGameCommandErrorText; + return res; + } + + ride->status = _status; + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; + ride->race_winner = SPRITE_INDEX_NULL; + ride->current_issues = 0; + ride->last_issue_time = 0; + ride->GetMeasurement(); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + window_invalidate_by_number(WC_RIDE, _rideIndex); + break; + } + case RIDE_STATUS_TESTING: + case RIDE_STATUS_OPEN: + { + if (ride->status == _status) + { + return res; + } + + if (ride->status == RIDE_STATUS_SIMULATING) + { + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + } + + // Fix #3183: Make sure we close the construction window so the ride finishes any editing code before opening + // otherwise vehicles get added to the ride incorrectly (such as to a ghost station) + rct_window* constructionWindow = window_find_by_number(WC_RIDE_CONSTRUCTION, _rideIndex); + if (constructionWindow != nullptr) + { + window_close(constructionWindow); + } + + if (_status == RIDE_STATUS_TESTING) + { + if (!ride->Test(_status, true)) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = gGameCommandErrorText; + return res; + } + } + else if (!ride->Open(true)) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = gGameCommandErrorText; + return res; + } + + ride->race_winner = SPRITE_INDEX_NULL; + ride->status = _status; + ride->current_issues = 0; + ride->last_issue_time = 0; + ride->GetMeasurement(); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + window_invalidate_by_number(WC_RIDE, _rideIndex); + break; + } + default: + Guard::Assert(false, "Invalid status passed: %u", _status); + break; + } + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); + + return res; +} diff --git a/src/openrct2/actions/RideSetStatusAction.h b/src/openrct2/actions/RideSetStatusAction.h new file mode 100644 index 0000000000..03bc54cd46 --- /dev/null +++ b/src/openrct2/actions/RideSetStatusAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(RideSetStatusAction, GAME_COMMAND_SET_RIDE_STATUS, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + uint8_t _status{ RIDE_STATUS_CLOSED }; + +public: + RideSetStatusAction() = default; + RideSetStatusAction(ride_id_t rideIndex, uint8_t status) + : _rideIndex(rideIndex) + , _status(status) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideSetVehicleAction.cpp b/src/openrct2/actions/RideSetVehicleAction.cpp new file mode 100644 index 0000000000..ce3ac10c52 --- /dev/null +++ b/src/openrct2/actions/RideSetVehicleAction.cpp @@ -0,0 +1,240 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "RideSetVehicleAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Research.h" +#include "../object/ObjectManager.h" +#include "../ride/Ride.h" +#include "../ride/RideData.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../util/Util.h" +#include "../world/Park.h" + +void RideSetVehicleAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("type", _type); + visitor.Visit("value", _value); + visitor.Visit("colour", _colour); +} + +void RideSetVehicleAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_rideIndex) << DS_TAG(_type) << DS_TAG(_value) << DS_TAG(_colour); +} + +GameActions::Result::Ptr RideSetVehicleAction::Query() const +{ + if (_type >= RideSetVehicleType::Count) + { + log_warning("Invalid type. type = %d", _type); + } + auto errTitle = SetVehicleTypeErrorTitle[EnumValue(_type)]; + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) + { + return std::make_unique( + GameActions::Status::Broken, errTitle, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); + } + + if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + { + return std::make_unique(GameActions::Status::NotClosed, errTitle, STR_MUST_BE_CLOSED_FIRST); + } + + switch (_type) + { + case RideSetVehicleType::NumTrains: + case RideSetVehicleType::NumCarsPerTrain: + break; + case RideSetVehicleType::RideEntry: + { + if (!ride_is_vehicle_type_valid(ride)) + { + log_error("Invalid vehicle type. type = %d", _value); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + auto rideEntry = get_ride_entry(_value); + if (rideEntry == nullptr) + { + log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + // Validate preset + vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list; + if (_colour >= presetList->count && _colour != 255 && _colour != 0) + { + log_error("Unknown vehicle colour preset. colour = %d", _colour); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + break; + } + + default: + log_error("Unknown vehicle command. type = %d", _type); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetVehicleAction::Execute() const +{ + auto errTitle = SetVehicleTypeErrorTitle[EnumValue(_type)]; + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + switch (_type) + { + case RideSetVehicleType::NumTrains: + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + ride->vehicle_change_timeout = 100; + + ride->proposed_num_vehicles = _value; + break; + case RideSetVehicleType::NumCarsPerTrain: + { + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + ride->vehicle_change_timeout = 100; + + invalidate_test_results(ride); + auto rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + auto clampValue = _value; + if (!gCheatsDisableTrainLengthLimit) + { + clampValue = std::clamp(clampValue, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train); + } + ride->proposed_num_cars_per_train = clampValue; + break; + } + case RideSetVehicleType::RideEntry: + { + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + ride->vehicle_change_timeout = 100; + + invalidate_test_results(ride); + ride->subtype = _value; + auto rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + ride_set_vehicle_colours_to_random_preset(ride, _colour); + if (!gCheatsDisableTrainLengthLimit) + { + ride->proposed_num_cars_per_train = std::clamp( + ride->proposed_num_cars_per_train, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train); + } + break; + } + + default: + log_error("Unknown vehicle command. type = %d", _type); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + ride->num_circuits = 1; + ride->UpdateMaxVehicles(); + + auto res = std::make_unique(); + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(res->Position) }; + } + + auto intent = Intent(INTENT_ACTION_RIDE_PAINT_RESET_VEHICLE); + intent.putExtra(INTENT_EXTRA_RIDE_ID, _rideIndex); + context_broadcast_intent(&intent); + + gfx_invalidate_screen(); + return res; +} + +bool RideSetVehicleAction::ride_is_vehicle_type_valid(Ride* ride) const +{ + bool selectionShouldBeExpanded; + int32_t rideTypeIterator, rideTypeIteratorMax; + + if (gCheatsShowVehiclesFromOtherTrackTypes + && !( + ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) || ride->type == RIDE_TYPE_MAZE + || ride->type == RIDE_TYPE_MINI_GOLF)) + { + selectionShouldBeExpanded = true; + rideTypeIterator = 0; + rideTypeIteratorMax = RIDE_TYPE_COUNT - 1; + } + else + { + selectionShouldBeExpanded = false; + rideTypeIterator = ride->type; + rideTypeIteratorMax = ride->type; + } + + for (; rideTypeIterator <= rideTypeIteratorMax; rideTypeIterator++) + { + if (selectionShouldBeExpanded) + { + if (ride_type_has_flag(rideTypeIterator, RIDE_TYPE_FLAG_FLAT_RIDE)) + continue; + if (rideTypeIterator == RIDE_TYPE_MAZE || rideTypeIterator == RIDE_TYPE_MINI_GOLF) + continue; + } + + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + auto& rideEntries = objManager.GetAllRideEntries(rideTypeIterator); + for (auto rideEntryIndex : rideEntries) + { + if (rideEntryIndex == _value) + { + if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) + { + return false; + } + + return true; + } + } + } + + return false; +} diff --git a/src/openrct2/actions/RideSetVehicleAction.h b/src/openrct2/actions/RideSetVehicleAction.h new file mode 100644 index 0000000000..1bf36a0136 --- /dev/null +++ b/src/openrct2/actions/RideSetVehicleAction.h @@ -0,0 +1,57 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +enum class RideSetVehicleType : uint8_t +{ + NumTrains, + NumCarsPerTrain, + RideEntry, + Count, +}; + +DEFINE_GAME_ACTION(RideSetVehicleAction, GAME_COMMAND_SET_RIDE_VEHICLES, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + RideSetVehicleType _type{}; + uint8_t _value{}; + uint8_t _colour{}; + + constexpr static rct_string_id SetVehicleTypeErrorTitle[] = { STR_RIDE_SET_VEHICLE_SET_NUM_TRAINS_FAIL, + STR_RIDE_SET_VEHICLE_SET_NUM_CARS_PER_TRAIN_FAIL, + STR_RIDE_SET_VEHICLE_TYPE_FAIL }; + +public: + RideSetVehicleAction() = default; + RideSetVehicleAction(ride_id_t rideIndex, RideSetVehicleType type, uint8_t value, uint8_t colour = 0) + : _rideIndex(rideIndex) + , _type(type) + , _value(value) + , _colour(colour) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + bool ride_is_vehicle_type_valid(Ride * ride) const; +}; diff --git a/src/openrct2/actions/RideSetVehiclesAction.hpp b/src/openrct2/actions/RideSetVehiclesAction.hpp deleted file mode 100644 index 7bbd53e7c6..0000000000 --- a/src/openrct2/actions/RideSetVehiclesAction.hpp +++ /dev/null @@ -1,278 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Research.h" -#include "../object/ObjectManager.h" -#include "../ride/Ride.h" -#include "../ride/RideData.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../util/Util.h" -#include "../world/Park.h" -#include "GameAction.h" - -enum class RideSetVehicleType : uint8_t -{ - NumTrains, - NumCarsPerTrain, - RideEntry, - Count, -}; - -DEFINE_GAME_ACTION(RideSetVehicleAction, GAME_COMMAND_SET_RIDE_VEHICLES, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - RideSetVehicleType _type{}; - uint8_t _value{}; - uint8_t _colour{}; - - constexpr static rct_string_id SetVehicleTypeErrorTitle[] = { STR_RIDE_SET_VEHICLE_SET_NUM_TRAINS_FAIL, - STR_RIDE_SET_VEHICLE_SET_NUM_CARS_PER_TRAIN_FAIL, - STR_RIDE_SET_VEHICLE_TYPE_FAIL }; - -public: - RideSetVehicleAction() = default; - RideSetVehicleAction(ride_id_t rideIndex, RideSetVehicleType type, uint8_t value, uint8_t colour = 0) - : _rideIndex(rideIndex) - , _type(type) - , _value(value) - , _colour(colour) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("type", _type); - visitor.Visit("value", _value); - visitor.Visit("colour", _colour); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_rideIndex) << DS_TAG(_type) << DS_TAG(_value) << DS_TAG(_colour); - } - - GameActions::Result::Ptr Query() const override - { - if (_type >= RideSetVehicleType::Count) - { - log_warning("Invalid type. type = %d", _type); - } - auto errTitle = SetVehicleTypeErrorTitle[EnumValue(_type)]; - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) - { - return std::make_unique( - GameActions::Status::Broken, errTitle, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); - } - - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) - { - return std::make_unique(GameActions::Status::NotClosed, errTitle, STR_MUST_BE_CLOSED_FIRST); - } - - switch (_type) - { - case RideSetVehicleType::NumTrains: - case RideSetVehicleType::NumCarsPerTrain: - break; - case RideSetVehicleType::RideEntry: - { - if (!ride_is_vehicle_type_valid(ride)) - { - log_error("Invalid vehicle type. type = %d", _value); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - auto rideEntry = get_ride_entry(_value); - if (rideEntry == nullptr) - { - log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - // Validate preset - vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list; - if (_colour >= presetList->count && _colour != 255 && _colour != 0) - { - log_error("Unknown vehicle colour preset. colour = %d", _colour); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - break; - } - - default: - log_error("Unknown vehicle command. type = %d", _type); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto errTitle = SetVehicleTypeErrorTitle[EnumValue(_type)]; - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - switch (_type) - { - case RideSetVehicleType::NumTrains: - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - ride->vehicle_change_timeout = 100; - - ride->proposed_num_vehicles = _value; - break; - case RideSetVehicleType::NumCarsPerTrain: - { - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - ride->vehicle_change_timeout = 100; - - invalidate_test_results(ride); - auto rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - auto clampValue = _value; - if (!gCheatsDisableTrainLengthLimit) - { - clampValue = std::clamp(clampValue, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train); - } - ride->proposed_num_cars_per_train = clampValue; - break; - } - case RideSetVehicleType::RideEntry: - { - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - ride->vehicle_change_timeout = 100; - - invalidate_test_results(ride); - ride->subtype = _value; - auto rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - ride_set_vehicle_colours_to_random_preset(ride, _colour); - if (!gCheatsDisableTrainLengthLimit) - { - ride->proposed_num_cars_per_train = std::clamp( - ride->proposed_num_cars_per_train, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train); - } - break; - } - - default: - log_error("Unknown vehicle command. type = %d", _type); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - ride->num_circuits = 1; - ride->UpdateMaxVehicles(); - - auto res = std::make_unique(); - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(res->Position) }; - } - - auto intent = Intent(INTENT_ACTION_RIDE_PAINT_RESET_VEHICLE); - intent.putExtra(INTENT_EXTRA_RIDE_ID, _rideIndex); - context_broadcast_intent(&intent); - - gfx_invalidate_screen(); - return res; - } - -private: - bool ride_is_vehicle_type_valid(Ride * ride) const - { - bool selectionShouldBeExpanded; - int32_t rideTypeIterator, rideTypeIteratorMax; - - if (gCheatsShowVehiclesFromOtherTrackTypes - && !( - ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) || ride->type == RIDE_TYPE_MAZE - || ride->type == RIDE_TYPE_MINI_GOLF)) - { - selectionShouldBeExpanded = true; - rideTypeIterator = 0; - rideTypeIteratorMax = RIDE_TYPE_COUNT - 1; - } - else - { - selectionShouldBeExpanded = false; - rideTypeIterator = ride->type; - rideTypeIteratorMax = ride->type; - } - - for (; rideTypeIterator <= rideTypeIteratorMax; rideTypeIterator++) - { - if (selectionShouldBeExpanded) - { - if (ride_type_has_flag(rideTypeIterator, RIDE_TYPE_FLAG_FLAT_RIDE)) - continue; - if (rideTypeIterator == RIDE_TYPE_MAZE || rideTypeIterator == RIDE_TYPE_MINI_GOLF) - continue; - } - - auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); - auto& rideEntries = objManager.GetAllRideEntries(rideTypeIterator); - for (auto rideEntryIndex : rideEntries) - { - if (rideEntryIndex == _value) - { - if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) - { - return false; - } - - return true; - } - } - } - - return false; - } -}; diff --git a/src/openrct2/actions/ScenarioSetSettingAction.cpp b/src/openrct2/actions/ScenarioSetSettingAction.cpp new file mode 100644 index 0000000000..4ae585d2d4 --- /dev/null +++ b/src/openrct2/actions/ScenarioSetSettingAction.cpp @@ -0,0 +1,245 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "ScenarioSetSettingAction.h" + +#include "../OpenRCT2.h" +#include "../interface/Window.h" +#include "../management/Finance.h" +#include "../peep/Peep.h" +#include "../util/Util.h" +#include "../world/Park.h" + +#include + +void ScenarioSetSettingAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_setting) << DS_TAG(_value); +} + +GameActions::Result::Ptr ScenarioSetSettingAction::Query() const +{ + if (_setting >= ScenarioSetSetting::Count) + { + log_error("Invalid setting: %u", _setting); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr ScenarioSetSettingAction::Execute() const +{ + switch (_setting) + { + case ScenarioSetSetting::NoMoney: + if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) + { + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_NO_MONEY_SCENARIO; + } + else + { + gParkFlags &= ~PARK_FLAGS_NO_MONEY_SCENARIO; + } + } + else + { + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_NO_MONEY; + } + else + { + gParkFlags &= ~PARK_FLAGS_NO_MONEY; + } + // Invalidate all windows that have anything to do with finance + window_invalidate_by_class(WC_RIDE); + window_invalidate_by_class(WC_PEEP); + window_invalidate_by_class(WC_PARK_INFORMATION); + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + window_invalidate_by_class(WC_TOP_TOOLBAR); + } + break; + case ScenarioSetSetting::InitialCash: + gInitialCash = std::clamp(_value, MONEY(0, 00), MONEY(1000000, 00)); + gCash = gInitialCash; + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + break; + case ScenarioSetSetting::InitialLoan: + gBankLoan = std::clamp(_value, MONEY(0, 00), MONEY(5000000, 00)); + gMaxBankLoan = std::max(gBankLoan, gMaxBankLoan); + window_invalidate_by_class(WC_FINANCES); + break; + case ScenarioSetSetting::MaximumLoanSize: + gMaxBankLoan = std::clamp(_value, MONEY(0, 00), MONEY(5000000, 00)); + gBankLoan = std::min(gBankLoan, gMaxBankLoan); + window_invalidate_by_class(WC_FINANCES); + break; + case ScenarioSetSetting::AnnualInterestRate: + gBankLoanInterestRate = std::clamp(_value, 0, 80); + window_invalidate_by_class(WC_FINANCES); + break; + case ScenarioSetSetting::ForbidMarketingCampaigns: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_FORBID_MARKETING_CAMPAIGN; + } + else + { + gParkFlags &= ~PARK_FLAGS_FORBID_MARKETING_CAMPAIGN; + } + break; + case ScenarioSetSetting::AverageCashPerGuest: + gGuestInitialCash = std::clamp(_value, MONEY(0, 00), MONEY(1000, 00)); + break; + case ScenarioSetSetting::GuestInitialHappiness: + gGuestInitialHappiness = std::clamp(_value, 40, 250); + break; + case ScenarioSetSetting::GuestInitialHunger: + gGuestInitialHunger = std::clamp(_value, 40, 250); + break; + case ScenarioSetSetting::GuestInitialThirst: + gGuestInitialThirst = std::clamp(_value, 40, 250); + break; + case ScenarioSetSetting::GuestsPreferLessIntenseRides: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_PREF_LESS_INTENSE_RIDES; + } + else + { + gParkFlags &= ~PARK_FLAGS_PREF_LESS_INTENSE_RIDES; + } + break; + case ScenarioSetSetting::GuestsPreferMoreIntenseRides: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_PREF_MORE_INTENSE_RIDES; + } + else + { + gParkFlags &= ~PARK_FLAGS_PREF_MORE_INTENSE_RIDES; + } + break; + case ScenarioSetSetting::CostToBuyLand: + gLandPrice = std::clamp(_value, MONEY(5, 00), MONEY(200, 00)); + break; + case ScenarioSetSetting::CostToBuyConstructionRights: + gConstructionRightsPrice = std::clamp(_value, MONEY(5, 00), MONEY(200, 00)); + break; + case ScenarioSetSetting::ParkChargeMethod: + if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) + { + if (_value == 0) + { + gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; + gParkEntranceFee = MONEY(0, 00); + } + else if (_value == 1) + { + gParkFlags &= ~PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; + gParkEntranceFee = MONEY(10, 00); + } + else + { + gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags |= PARK_FLAGS_UNLOCK_ALL_PRICES; + gParkEntranceFee = MONEY(10, 00); + } + } + else + { + if (_value == 0) + { + gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; + } + else if (_value == 1) + { + gParkFlags &= ~PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; + } + else + { + gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags |= PARK_FLAGS_UNLOCK_ALL_PRICES; + } + window_invalidate_by_class(WC_PARK_INFORMATION); + window_invalidate_by_class(WC_RIDE); + } + break; + case ScenarioSetSetting::ParkChargeEntryFee: + gParkEntranceFee = std::clamp(_value, MONEY(0, 00), MAX_ENTRANCE_FEE); + window_invalidate_by_class(WC_PARK_INFORMATION); + break; + case ScenarioSetSetting::ForbidTreeRemoval: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_FORBID_TREE_REMOVAL; + } + else + { + gParkFlags &= ~PARK_FLAGS_FORBID_TREE_REMOVAL; + } + break; + case ScenarioSetSetting::ForbidLandscapeChanges: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_FORBID_LANDSCAPE_CHANGES; + } + else + { + gParkFlags &= ~PARK_FLAGS_FORBID_LANDSCAPE_CHANGES; + } + break; + case ScenarioSetSetting::ForbidHighConstruction: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; + } + else + { + gParkFlags &= ~PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; + } + break; + case ScenarioSetSetting::ParkRatingHigherDifficultyLevel: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_DIFFICULT_PARK_RATING; + } + else + { + gParkFlags &= ~PARK_FLAGS_DIFFICULT_PARK_RATING; + } + break; + case ScenarioSetSetting::GuestGenerationHigherDifficultyLevel: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_DIFFICULT_GUEST_GENERATION; + } + else + { + gParkFlags &= ~PARK_FLAGS_DIFFICULT_GUEST_GENERATION; + } + break; + default: + log_error("Invalid setting: %u", _setting); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + window_invalidate_by_class(WC_EDITOR_SCENARIO_OPTIONS); + return MakeResult(); +} diff --git a/src/openrct2/actions/ScenarioSetSettingAction.h b/src/openrct2/actions/ScenarioSetSettingAction.h new file mode 100644 index 0000000000..ea104258ec --- /dev/null +++ b/src/openrct2/actions/ScenarioSetSettingAction.h @@ -0,0 +1,62 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +enum class ScenarioSetSetting : uint8_t +{ + NoMoney, + InitialCash, + InitialLoan, + MaximumLoanSize, + AnnualInterestRate, + ForbidMarketingCampaigns, + AverageCashPerGuest, + GuestInitialHappiness, + GuestInitialHunger, + GuestInitialThirst, + GuestsPreferLessIntenseRides, + GuestsPreferMoreIntenseRides, + CostToBuyLand, + CostToBuyConstructionRights, + ParkChargeMethod, + ParkChargeEntryFee, + ForbidTreeRemoval, + ForbidLandscapeChanges, + ForbidHighConstruction, + ParkRatingHigherDifficultyLevel, + GuestGenerationHigherDifficultyLevel, + Count +}; + +DEFINE_GAME_ACTION(ScenarioSetSettingAction, GAME_COMMAND_EDIT_SCENARIO_OPTIONS, GameActions::Result) +{ +private: + ScenarioSetSetting _setting{ ScenarioSetSetting::Count }; + uint32_t _value{}; + +public: + ScenarioSetSettingAction() = default; + ScenarioSetSettingAction(ScenarioSetSetting setting, uint32_t value) + : _setting(setting) + , _value(value) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/ScenarioSetSettingAction.hpp b/src/openrct2/actions/ScenarioSetSettingAction.hpp deleted file mode 100644 index 132a74dc20..0000000000 --- a/src/openrct2/actions/ScenarioSetSettingAction.hpp +++ /dev/null @@ -1,293 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../OpenRCT2.h" -#include "../interface/Window.h" -#include "../management/Finance.h" -#include "../peep/Peep.h" -#include "../util/Util.h" -#include "../world/Park.h" -#include "GameAction.h" - -#include - -enum class ScenarioSetSetting : uint8_t -{ - NoMoney, - InitialCash, - InitialLoan, - MaximumLoanSize, - AnnualInterestRate, - ForbidMarketingCampaigns, - AverageCashPerGuest, - GuestInitialHappiness, - GuestInitialHunger, - GuestInitialThirst, - GuestsPreferLessIntenseRides, - GuestsPreferMoreIntenseRides, - CostToBuyLand, - CostToBuyConstructionRights, - ParkChargeMethod, - ParkChargeEntryFee, - ForbidTreeRemoval, - ForbidLandscapeChanges, - ForbidHighConstruction, - ParkRatingHigherDifficultyLevel, - GuestGenerationHigherDifficultyLevel, - Count -}; - -DEFINE_GAME_ACTION(ScenarioSetSettingAction, GAME_COMMAND_EDIT_SCENARIO_OPTIONS, GameActions::Result) -{ -private: - ScenarioSetSetting _setting{ ScenarioSetSetting::Count }; - uint32_t _value{}; - -public: - ScenarioSetSettingAction() = default; - ScenarioSetSettingAction(ScenarioSetSetting setting, uint32_t value) - : _setting(setting) - , _value(value) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_setting) << DS_TAG(_value); - } - - GameActions::Result::Ptr Query() const override - { - if (_setting >= ScenarioSetSetting::Count) - { - log_error("Invalid setting: %u", _setting); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - switch (_setting) - { - case ScenarioSetSetting::NoMoney: - if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) - { - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_NO_MONEY_SCENARIO; - } - else - { - gParkFlags &= ~PARK_FLAGS_NO_MONEY_SCENARIO; - } - } - else - { - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_NO_MONEY; - } - else - { - gParkFlags &= ~PARK_FLAGS_NO_MONEY; - } - // Invalidate all windows that have anything to do with finance - window_invalidate_by_class(WC_RIDE); - window_invalidate_by_class(WC_PEEP); - window_invalidate_by_class(WC_PARK_INFORMATION); - window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - window_invalidate_by_class(WC_TOP_TOOLBAR); - } - break; - case ScenarioSetSetting::InitialCash: - gInitialCash = std::clamp(_value, MONEY(0, 00), MONEY(1000000, 00)); - gCash = gInitialCash; - window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - break; - case ScenarioSetSetting::InitialLoan: - gBankLoan = std::clamp(_value, MONEY(0, 00), MONEY(5000000, 00)); - gMaxBankLoan = std::max(gBankLoan, gMaxBankLoan); - window_invalidate_by_class(WC_FINANCES); - break; - case ScenarioSetSetting::MaximumLoanSize: - gMaxBankLoan = std::clamp(_value, MONEY(0, 00), MONEY(5000000, 00)); - gBankLoan = std::min(gBankLoan, gMaxBankLoan); - window_invalidate_by_class(WC_FINANCES); - break; - case ScenarioSetSetting::AnnualInterestRate: - gBankLoanInterestRate = std::clamp(_value, 0, 80); - window_invalidate_by_class(WC_FINANCES); - break; - case ScenarioSetSetting::ForbidMarketingCampaigns: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_FORBID_MARKETING_CAMPAIGN; - } - else - { - gParkFlags &= ~PARK_FLAGS_FORBID_MARKETING_CAMPAIGN; - } - break; - case ScenarioSetSetting::AverageCashPerGuest: - gGuestInitialCash = std::clamp(_value, MONEY(0, 00), MONEY(1000, 00)); - break; - case ScenarioSetSetting::GuestInitialHappiness: - gGuestInitialHappiness = std::clamp(_value, 40, 250); - break; - case ScenarioSetSetting::GuestInitialHunger: - gGuestInitialHunger = std::clamp(_value, 40, 250); - break; - case ScenarioSetSetting::GuestInitialThirst: - gGuestInitialThirst = std::clamp(_value, 40, 250); - break; - case ScenarioSetSetting::GuestsPreferLessIntenseRides: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_PREF_LESS_INTENSE_RIDES; - } - else - { - gParkFlags &= ~PARK_FLAGS_PREF_LESS_INTENSE_RIDES; - } - break; - case ScenarioSetSetting::GuestsPreferMoreIntenseRides: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_PREF_MORE_INTENSE_RIDES; - } - else - { - gParkFlags &= ~PARK_FLAGS_PREF_MORE_INTENSE_RIDES; - } - break; - case ScenarioSetSetting::CostToBuyLand: - gLandPrice = std::clamp(_value, MONEY(5, 00), MONEY(200, 00)); - break; - case ScenarioSetSetting::CostToBuyConstructionRights: - gConstructionRightsPrice = std::clamp(_value, MONEY(5, 00), MONEY(200, 00)); - break; - case ScenarioSetSetting::ParkChargeMethod: - if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) - { - if (_value == 0) - { - gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; - gParkEntranceFee = MONEY(0, 00); - } - else if (_value == 1) - { - gParkFlags &= ~PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; - gParkEntranceFee = MONEY(10, 00); - } - else - { - gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags |= PARK_FLAGS_UNLOCK_ALL_PRICES; - gParkEntranceFee = MONEY(10, 00); - } - } - else - { - if (_value == 0) - { - gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; - } - else if (_value == 1) - { - gParkFlags &= ~PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; - } - else - { - gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags |= PARK_FLAGS_UNLOCK_ALL_PRICES; - } - window_invalidate_by_class(WC_PARK_INFORMATION); - window_invalidate_by_class(WC_RIDE); - } - break; - case ScenarioSetSetting::ParkChargeEntryFee: - gParkEntranceFee = std::clamp(_value, MONEY(0, 00), MAX_ENTRANCE_FEE); - window_invalidate_by_class(WC_PARK_INFORMATION); - break; - case ScenarioSetSetting::ForbidTreeRemoval: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_FORBID_TREE_REMOVAL; - } - else - { - gParkFlags &= ~PARK_FLAGS_FORBID_TREE_REMOVAL; - } - break; - case ScenarioSetSetting::ForbidLandscapeChanges: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_FORBID_LANDSCAPE_CHANGES; - } - else - { - gParkFlags &= ~PARK_FLAGS_FORBID_LANDSCAPE_CHANGES; - } - break; - case ScenarioSetSetting::ForbidHighConstruction: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; - } - else - { - gParkFlags &= ~PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; - } - break; - case ScenarioSetSetting::ParkRatingHigherDifficultyLevel: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_DIFFICULT_PARK_RATING; - } - else - { - gParkFlags &= ~PARK_FLAGS_DIFFICULT_PARK_RATING; - } - break; - case ScenarioSetSetting::GuestGenerationHigherDifficultyLevel: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_DIFFICULT_GUEST_GENERATION; - } - else - { - gParkFlags &= ~PARK_FLAGS_DIFFICULT_GUEST_GENERATION; - } - break; - default: - log_error("Invalid setting: %u", _setting); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - break; - } - window_invalidate_by_class(WC_EDITOR_SCENARIO_OPTIONS); - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/SetCheatAction.cpp b/src/openrct2/actions/SetCheatAction.cpp new file mode 100644 index 0000000000..761116fc57 --- /dev/null +++ b/src/openrct2/actions/SetCheatAction.cpp @@ -0,0 +1,732 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "SetCheatAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../GameState.h" +#include "../config/Config.h" +#include "../core/String.hpp" +#include "../drawing/Drawing.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../network/network.h" +#include "../ride/Ride.h" +#include "../scenario/Scenario.h" +#include "../ui/UiContext.h" +#include "../util/Util.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "../world/Climate.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Map.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" +#include "ParkSetLoanAction.h" +#include "ParkSetParameterAction.h" + +using ParametersRange = std::pair, std::pair>; + +void SetCheatAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("type", _cheatType); + visitor.Visit("param1", _param1); + visitor.Visit("param2", _param2); +} + +void SetCheatAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_cheatType) << DS_TAG(_param1) << DS_TAG(_param2); +} + +GameActions::Result::Ptr SetCheatAction::Query() const +{ + if (static_cast(_cheatType) >= static_cast(CheatType::Count)) + { + MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + ParametersRange validRange = GetParameterRange(static_cast(_cheatType.id)); + + if (_param1 < validRange.first.first || _param1 > validRange.first.second) + { + MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + if (_param2 < validRange.second.first || _param2 > validRange.second.second) + { + MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr SetCheatAction::Execute() const +{ + switch (static_cast(_cheatType.id)) + { + case CheatType::SandboxMode: + gCheatsSandboxMode = _param1 != 0; + window_invalidate_by_class(WC_MAP); + window_invalidate_by_class(WC_FOOTPATH); + break; + case CheatType::DisableClearanceChecks: + gCheatsDisableClearanceChecks = _param1 != 0; + // Required to update the clearance checks overlay on the Cheats button. + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case CheatType::DisableSupportLimits: + gCheatsDisableSupportLimits = _param1 != 0; + break; + case CheatType::ShowAllOperatingModes: + gCheatsShowAllOperatingModes = _param1 != 0; + break; + case CheatType::ShowVehiclesFromOtherTrackTypes: + gCheatsShowVehiclesFromOtherTrackTypes = _param1 != 0; + break; + case CheatType::FastLiftHill: + gCheatsFastLiftHill = _param1 != 0; + break; + case CheatType::DisableBrakesFailure: + gCheatsDisableBrakesFailure = _param1 != 0; + break; + case CheatType::DisableAllBreakdowns: + gCheatsDisableAllBreakdowns = _param1 != 0; + break; + case CheatType::DisableTrainLengthLimit: + gCheatsDisableTrainLengthLimit = _param1 != 0; + break; + case CheatType::EnableChainLiftOnAllTrack: + gCheatsEnableChainLiftOnAllTrack = _param1 != 0; + break; + case CheatType::BuildInPauseMode: + gCheatsBuildInPauseMode = _param1 != 0; + break; + case CheatType::IgnoreRideIntensity: + gCheatsIgnoreRideIntensity = _param1 != 0; + break; + case CheatType::DisableVandalism: + gCheatsDisableVandalism = _param1 != 0; + break; + case CheatType::DisableLittering: + gCheatsDisableLittering = _param1 != 0; + break; + case CheatType::NoMoney: + SetScenarioNoMoney(_param1 != 0); + break; + case CheatType::AddMoney: + AddMoney(_param1); + break; + case CheatType::SetMoney: + SetMoney(_param1); + break; + case CheatType::ClearLoan: + ClearLoan(); + break; + case CheatType::SetGuestParameter: + SetGuestParameter(_param1, _param2); + break; + case CheatType::GenerateGuests: + GenerateGuests(_param1); + break; + case CheatType::RemoveAllGuests: + RemoveAllGuests(); + break; + case CheatType::GiveAllGuests: + GiveObjectToGuests(_param1); + break; + case CheatType::SetGrassLength: + SetGrassLength(_param1); + break; + case CheatType::WaterPlants: + WaterPlants(); + break; + case CheatType::FixVandalism: + FixVandalism(); + break; + case CheatType::RemoveLitter: + RemoveLitter(); + break; + case CheatType::DisablePlantAging: + gCheatsDisablePlantAging = _param1 != 0; + break; + case CheatType::SetStaffSpeed: + SetStaffSpeed(_param1); + break; + case CheatType::RenewRides: + RenewRides(); + break; + case CheatType::MakeDestructible: + MakeDestructible(); + break; + case CheatType::FixRides: + FixBrokenRides(); + break; + case CheatType::ResetCrashStatus: + ResetRideCrashStatus(); + break; + case CheatType::TenMinuteInspections: + Set10MinuteInspection(); + break; + case CheatType::WinScenario: + scenario_success(); + break; + case CheatType::ForceWeather: + // Todo - make sure this is safe + climate_force_weather(WeatherType{ static_cast(_param1) }); + break; + case CheatType::FreezeWeather: + gCheatsFreezeWeather = _param1 != 0; + break; + case CheatType::NeverEndingMarketing: + gCheatsNeverendingMarketing = _param1 != 0; + break; + case CheatType::OpenClosePark: + ParkSetOpen(!park_is_open()); + break; + case CheatType::HaveFun: + gScenarioObjective.Type = OBJECTIVE_HAVE_FUN; + break; + case CheatType::SetForcedParkRating: + set_forced_park_rating(_param1); + break; + case CheatType::AllowArbitraryRideTypeChanges: + gCheatsAllowArbitraryRideTypeChanges = _param1 != 0; + window_invalidate_by_class(WC_RIDE); + break; + case CheatType::OwnAllLand: + OwnAllLand(); + break; + case CheatType::DisableRideValueAging: + gCheatsDisableRideValueAging = _param1 != 0; + break; + case CheatType::IgnoreResearchStatus: + gCheatsIgnoreResearchStatus = _param1 != 0; + break; + case CheatType::EnableAllDrawableTrackPieces: + gCheatsEnableAllDrawableTrackPieces = _param1 != 0; + break; + case CheatType::CreateDucks: + CreateDucks(_param1); + break; + case CheatType::RemoveDucks: + duck_remove_all(); + break; + case CheatType::AllowTrackPlaceInvalidHeights: + gCheatsAllowTrackPlaceInvalidHeights = _param1 != 0; + break; + default: + { + log_error("Unabled cheat: %d", _cheatType.id); + MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + break; + } + + if (network_get_mode() == NETWORK_MODE_NONE) + { + config_save_default(); + } + + window_invalidate_by_class(WC_CHEATS); + return MakeResult(); +} + +ParametersRange SetCheatAction::GetParameterRange(CheatType cheatType) const +{ + switch (static_cast(_cheatType.id)) + { + case CheatType::SandboxMode: + [[fallthrough]]; + case CheatType::DisableClearanceChecks: + [[fallthrough]]; + case CheatType::DisableSupportLimits: + [[fallthrough]]; + case CheatType::ShowAllOperatingModes: + [[fallthrough]]; + case CheatType::ShowVehiclesFromOtherTrackTypes: + [[fallthrough]]; + case CheatType::FastLiftHill: + [[fallthrough]]; + case CheatType::DisableBrakesFailure: + [[fallthrough]]; + case CheatType::DisableAllBreakdowns: + [[fallthrough]]; + case CheatType::DisableTrainLengthLimit: + [[fallthrough]]; + case CheatType::EnableChainLiftOnAllTrack: + [[fallthrough]]; + case CheatType::BuildInPauseMode: + [[fallthrough]]; + case CheatType::IgnoreRideIntensity: + [[fallthrough]]; + case CheatType::DisableVandalism: + [[fallthrough]]; + case CheatType::DisableLittering: + [[fallthrough]]; + case CheatType::NoMoney: + [[fallthrough]]; + case CheatType::DisablePlantAging: + [[fallthrough]]; + case CheatType::FreezeWeather: + [[fallthrough]]; + case CheatType::NeverEndingMarketing: + [[fallthrough]]; + case CheatType::AllowArbitraryRideTypeChanges: + [[fallthrough]]; + case CheatType::DisableRideValueAging: + [[fallthrough]]; + case CheatType::IgnoreResearchStatus: + [[fallthrough]]; + case CheatType::EnableAllDrawableTrackPieces: + [[fallthrough]]; + case CheatType::OpenClosePark: + return { { 0, 1 }, { 0, 0 } }; + case CheatType::AddMoney: + [[fallthrough]]; + case CheatType::SetMoney: + return { { std::numeric_limits::min(), std::numeric_limits::max() }, { 0, 0 } }; + case CheatType::SetGuestParameter: + switch (_param1) + { + case GUEST_PARAMETER_HAPPINESS: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, + { 0, PEEP_MAX_HAPPINESS } }; + case GUEST_PARAMETER_ENERGY: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, + { PEEP_MIN_ENERGY, PEEP_MAX_ENERGY } }; + case GUEST_PARAMETER_HUNGER: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, PEEP_MAX_HUNGER } }; + case GUEST_PARAMETER_THIRST: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, PEEP_MAX_THIRST } }; + case GUEST_PARAMETER_NAUSEA: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, PEEP_MAX_NAUSEA } }; + case GUEST_PARAMETER_NAUSEA_TOLERANCE: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, + { EnumValue(PeepNauseaTolerance::None), EnumValue(PeepNauseaTolerance::High) } }; + case GUEST_PARAMETER_TOILET: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, PEEP_MAX_TOILET } }; + case GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, 255 } }; + default: + return { { 0, 0 }, { 0, 0 } }; + } + case CheatType::GenerateGuests: + return { { 1, 10000 }, { 0, 0 } }; + case CheatType::GiveAllGuests: + return { { OBJECT_MONEY, OBJECT_UMBRELLA }, { 0, 0 } }; + case CheatType::SetGrassLength: + return { { 0, 7 }, { 0, 0 } }; + case CheatType::SetStaffSpeed: + return { { 0, 255 }, { 0, 0 } }; + case CheatType::ForceWeather: + return { { 0, EnumValue(WeatherType::Count) - 1 }, { 0, 0 } }; + case CheatType::SetForcedParkRating: + return { { 0, 999 }, { 0, 0 } }; + case CheatType::CreateDucks: + return { { 0, 100 }, { 0, 0 } }; + default: + return { { 0, 0 }, { 0, 0 } }; + } +} + +void SetCheatAction::SetGrassLength(int32_t length) const +{ + for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) + { + for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) + { + auto surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); + if (surfaceElement == nullptr) + continue; + + if (surfaceElement != nullptr && (surfaceElement->GetOwnership() & OWNERSHIP_OWNED) + && surfaceElement->GetWaterHeight() == 0 && surfaceElement->CanGrassGrow()) + { + surfaceElement->SetGrassLength(length); + } + } + } + + gfx_invalidate_screen(); +} + +void SetCheatAction::WaterPlants() const +{ + tile_element_iterator it; + + tile_element_iterator_begin(&it); + do + { + if (it.element->GetType() == TILE_ELEMENT_TYPE_SMALL_SCENERY) + { + it.element->AsSmallScenery()->SetAge(0); + } + } while (tile_element_iterator_next(&it)); + + gfx_invalidate_screen(); +} + +void SetCheatAction::FixVandalism() const +{ + tile_element_iterator it; + + tile_element_iterator_begin(&it); + do + { + if (it.element->GetType() != TILE_ELEMENT_TYPE_PATH) + continue; + + if (!(it.element)->AsPath()->HasAddition()) + continue; + + it.element->AsPath()->SetIsBroken(false); + } while (tile_element_iterator_next(&it)); + + gfx_invalidate_screen(); +} + +void SetCheatAction::RemoveLitter() const +{ + for (auto litter : EntityList(EntityListId::Litter)) + { + sprite_remove(litter); + } + + tile_element_iterator it; + rct_scenery_entry* sceneryEntry; + + tile_element_iterator_begin(&it); + do + { + if (it.element->GetType() != TILE_ELEMENT_TYPE_PATH) + continue; + + if (!(it.element)->AsPath()->HasAddition()) + continue; + + sceneryEntry = it.element->AsPath()->GetAdditionEntry(); + if (sceneryEntry->path_bit.flags & PATH_BIT_FLAG_IS_BIN) + it.element->AsPath()->SetAdditionStatus(0xFF); + + } while (tile_element_iterator_next(&it)); + + gfx_invalidate_screen(); +} + +void SetCheatAction::FixBrokenRides() const +{ + for (auto& ride : GetRideManager()) + { + if ((ride.mechanic_status != RIDE_MECHANIC_STATUS_FIXING) + && (ride.lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN))) + { + auto mechanic = ride_get_assigned_mechanic(&ride); + if (mechanic != nullptr) + { + mechanic->RemoveFromRide(); + } + + ride_fix_breakdown(&ride, 0); + ride.window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + } + } +} + +void SetCheatAction::RenewRides() const +{ + for (auto& ride : GetRideManager()) + { + ride.Renew(); + } + window_invalidate_by_class(WC_RIDE); +} + +void SetCheatAction::MakeDestructible() const +{ + for (auto& ride : GetRideManager()) + { + ride.lifecycle_flags &= ~RIDE_LIFECYCLE_INDESTRUCTIBLE; + ride.lifecycle_flags &= ~RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK; + } + window_invalidate_by_class(WC_RIDE); +} + +void SetCheatAction::ResetRideCrashStatus() const +{ + for (auto& ride : GetRideManager()) + { + // Reset crash status and history + ride.lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; + ride.last_crash_type = RIDE_CRASH_TYPE_NONE; + } + window_invalidate_by_class(WC_RIDE); +} + +void SetCheatAction::Set10MinuteInspection() const +{ + for (auto& ride : GetRideManager()) + { + // Set inspection interval to 10 minutes + ride.inspection_interval = RIDE_INSPECTION_EVERY_10_MINUTES; + } + window_invalidate_by_class(WC_RIDE); +} + +void SetCheatAction::SetScenarioNoMoney(bool enabled) const +{ + if (enabled) + { + gParkFlags |= PARK_FLAGS_NO_MONEY; + } + else + { + gParkFlags &= ~PARK_FLAGS_NO_MONEY; + } + // Invalidate all windows that have anything to do with finance + window_invalidate_by_class(WC_RIDE); + window_invalidate_by_class(WC_PEEP); + window_invalidate_by_class(WC_PARK_INFORMATION); + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + window_invalidate_by_class(WC_TOP_TOOLBAR); + window_invalidate_by_class(WC_CHEATS); +} + +void SetCheatAction::SetMoney(money32 amount) const +{ + gCash = amount; + + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); +} + +void SetCheatAction::AddMoney(money32 amount) const +{ + gCash = add_clamp_money32(gCash, amount); + + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); +} + +void SetCheatAction::ClearLoan() const +{ + // First give money + AddMoney(gBankLoan); + + // Then pay the loan + auto gameAction = ParkSetLoanAction(MONEY(0, 00)); + GameActions::ExecuteNested(&gameAction); +} + +void SetCheatAction::GenerateGuests(int32_t count) const +{ + auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); + for (int32_t i = 0; i < count; i++) + { + park.GenerateGuest(); + } + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); +} + +void SetCheatAction::SetGuestParameter(int32_t parameter, int32_t value) const +{ + for (auto peep : EntityList(EntityListId::Peep)) + { + switch (parameter) + { + case GUEST_PARAMETER_HAPPINESS: + peep->Happiness = value; + peep->HappinessTarget = value; + // Clear the 'red-faced with anger' status if we're making the guest happy + if (value > 0) + { + peep->PeepFlags &= ~PEEP_FLAGS_ANGRY; + peep->Angriness = 0; + } + break; + case GUEST_PARAMETER_ENERGY: + peep->Energy = value; + peep->EnergyTarget = value; + break; + case GUEST_PARAMETER_HUNGER: + peep->Hunger = value; + break; + case GUEST_PARAMETER_THIRST: + peep->Thirst = value; + break; + case GUEST_PARAMETER_NAUSEA: + peep->Nausea = value; + peep->NauseaTarget = value; + break; + case GUEST_PARAMETER_NAUSEA_TOLERANCE: + peep->NauseaTolerance = static_cast(value); + break; + case GUEST_PARAMETER_TOILET: + peep->Toilet = value; + break; + case GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY: + peep->Intensity = IntensityRange(value, 15); + break; + } + peep->UpdateSpriteType(); + } +} + +void SetCheatAction::GiveObjectToGuests(int32_t object) const +{ + for (auto peep : EntityList(EntityListId::Peep)) + { + switch (object) + { + case OBJECT_MONEY: + peep->CashInPocket = MONEY(1000, 00); + break; + case OBJECT_PARK_MAP: + peep->GiveItem(ShopItem::Map); + break; + case OBJECT_BALLOON: + peep->GiveItem(ShopItem::Balloon); + peep->BalloonColour = scenario_rand_max(COLOUR_COUNT - 1); + peep->UpdateSpriteType(); + break; + case OBJECT_UMBRELLA: + peep->GiveItem(ShopItem::Umbrella); + peep->UmbrellaColour = scenario_rand_max(COLOUR_COUNT - 1); + peep->UpdateSpriteType(); + break; + } + } + window_invalidate_by_class(WC_PEEP); +} + +void SetCheatAction::RemoveAllGuests() const +{ + for (auto& ride : GetRideManager()) + { + ride.num_riders = 0; + + for (size_t stationIndex = 0; stationIndex < MAX_STATIONS; stationIndex++) + { + ride.stations[stationIndex].QueueLength = 0; + ride.stations[stationIndex].LastPeepInQueue = SPRITE_INDEX_NULL; + } + + for (auto trainIndex : ride.vehicles) + { + for (Vehicle* vehicle = TryGetEntity(trainIndex); vehicle != nullptr; + vehicle = TryGetEntity(vehicle->next_vehicle_on_train)) + { + for (auto& peepInTrainIndex : vehicle->peep) + { + auto peep = TryGetEntity(peepInTrainIndex); + if (peep != nullptr) + { + vehicle->mass -= peep->Mass; + } + peepInTrainIndex = SPRITE_INDEX_NULL; + } + + vehicle->num_peeps = 0; + vehicle->next_free_seat = 0; + } + } + } + + // Do not use the FOR_ALL_PEEPS macro for this as next sprite index + // will be fetched on a deleted peep. + for (auto peep : EntityList(EntityListId::Peep)) + { + if (peep->AssignedPeepType == PeepType::Guest) + { + peep->Remove(); + } + } + + window_invalidate_by_class(WC_RIDE); + gfx_invalidate_screen(); +} + +void SetCheatAction::SetStaffSpeed(uint8_t value) const +{ + for (auto peep : EntityList(EntityListId::Peep)) + { + peep->Energy = value; + peep->EnergyTarget = value; + } +} + +void SetCheatAction::OwnAllLand() const +{ + const int32_t min = 32; + const int32_t max = gMapSizeUnits - 32; + + for (CoordsXY coords = { min, min }; coords.y <= max; coords.y += COORDS_XY_STEP) + { + for (coords.x = min; coords.x <= max; coords.x += COORDS_XY_STEP) + { + auto* surfaceElement = map_get_surface_element_at(coords); + if (surfaceElement == nullptr) + continue; + + // Ignore already owned tiles. + if (surfaceElement->GetOwnership() & OWNERSHIP_OWNED) + continue; + + int32_t baseZ = surfaceElement->GetBaseZ(); + int32_t destOwnership = check_max_allowable_land_rights_for_tile({ coords, baseZ }); + + // only own tiles that were not set to 0 + if (destOwnership != OWNERSHIP_UNOWNED) + { + surfaceElement->SetOwnership(destOwnership); + update_park_fences_around_tile(coords); + map_invalidate_tile({ coords, baseZ, baseZ + 16 }); + } + } + } + + // Completely unown peep spawn points + for (const auto& spawn : gPeepSpawns) + { + auto* surfaceElement = map_get_surface_element_at(spawn); + if (surfaceElement != nullptr) + { + surfaceElement->SetOwnership(OWNERSHIP_UNOWNED); + update_park_fences_around_tile(spawn); + uint16_t baseZ = surfaceElement->GetBaseZ(); + map_invalidate_tile({ spawn, baseZ, baseZ + 16 }); + } + } + + map_count_remaining_land_rights(); +} + +void SetCheatAction::ParkSetOpen(bool isOpen) const +{ + auto parkSetParameter = ParkSetParameterAction(isOpen ? ParkParameter::Open : ParkParameter::Close); + GameActions::ExecuteNested(&parkSetParameter); +} + +void SetCheatAction::CreateDucks(int count) const +{ + for (int i = 0; i < count; i++) + { + // 100 attempts at finding some water to create a few ducks at + for (int32_t attempts = 0; attempts < 100; attempts++) + { + if (scenario_create_ducks()) + break; + } + } +} diff --git a/src/openrct2/actions/SetCheatAction.h b/src/openrct2/actions/SetCheatAction.h new file mode 100644 index 0000000000..7b9e7a3614 --- /dev/null +++ b/src/openrct2/actions/SetCheatAction.h @@ -0,0 +1,66 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(SetCheatAction, GAME_COMMAND_CHEAT, GameActions::Result) +{ + using ParametersRange = std::pair, std::pair>; + +private: + NetworkCheatType_t _cheatType{ EnumValue(CheatType::Count) }; + int32_t _param1{}; + int32_t _param2{}; + +public: + SetCheatAction() = default; + SetCheatAction(CheatType cheatType, int32_t param1 = 0, int32_t param2 = 0) + : _cheatType(static_cast(cheatType)) + , _param1(param1) + , _param2(param2) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + ParametersRange GetParameterRange(CheatType cheatType) const; + void SetGrassLength(int32_t length) const; + void WaterPlants() const; + void FixVandalism() const; + void RemoveLitter() const; + void FixBrokenRides() const; + void RenewRides() const; + void MakeDestructible() const; + void ResetRideCrashStatus() const; + void Set10MinuteInspection() const; + void SetScenarioNoMoney(bool enabled) const; + void SetMoney(money32 amount) const; + void AddMoney(money32 amount) const; + void ClearLoan() const; + void GenerateGuests(int32_t count) const; + void SetGuestParameter(int32_t parameter, int32_t value) const; + void GiveObjectToGuests(int32_t object) const; + void RemoveAllGuests() const; + void SetStaffSpeed(uint8_t value) const; + void OwnAllLand() const; + void ParkSetOpen(bool isOpen) const; + void CreateDucks(int count) const; +}; diff --git a/src/openrct2/actions/SetCheatAction.hpp b/src/openrct2/actions/SetCheatAction.hpp deleted file mode 100644 index f3d7b8a9fa..0000000000 --- a/src/openrct2/actions/SetCheatAction.hpp +++ /dev/null @@ -1,760 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../Context.h" -#include "../GameState.h" -#include "../config/Config.h" -#include "../core/String.hpp" -#include "../drawing/Drawing.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../network/network.h" -#include "../ride/Ride.h" -#include "../scenario/Scenario.h" -#include "../ui/UiContext.h" -#include "../util/Util.h" -#include "../windows/Intent.h" -#include "../world/Banner.h" -#include "../world/Climate.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Map.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" -#include "ParkSetLoanAction.hpp" -#include "ParkSetParameterAction.hpp" - -DEFINE_GAME_ACTION(SetCheatAction, GAME_COMMAND_CHEAT, GameActions::Result) -{ - using ParametersRange = std::pair, std::pair>; - -private: - NetworkCheatType_t _cheatType{ EnumValue(CheatType::Count) }; - int32_t _param1{}; - int32_t _param2{}; - -public: - SetCheatAction() = default; - SetCheatAction(CheatType cheatType, int32_t param1 = 0, int32_t param2 = 0) - : _cheatType(static_cast(cheatType)) - , _param1(param1) - , _param2(param2) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("type", _cheatType); - visitor.Visit("param1", _param1); - visitor.Visit("param2", _param2); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_cheatType) << DS_TAG(_param1) << DS_TAG(_param2); - } - - GameActions::Result::Ptr Query() const override - { - if (static_cast(_cheatType) >= static_cast(CheatType::Count)) - { - MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - ParametersRange validRange = GetParameterRange(static_cast(_cheatType.id)); - - if (_param1 < validRange.first.first || _param1 > validRange.first.second) - { - MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - if (_param2 < validRange.second.first || _param2 > validRange.second.second) - { - MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - switch (static_cast(_cheatType.id)) - { - case CheatType::SandboxMode: - gCheatsSandboxMode = _param1 != 0; - window_invalidate_by_class(WC_MAP); - window_invalidate_by_class(WC_FOOTPATH); - break; - case CheatType::DisableClearanceChecks: - gCheatsDisableClearanceChecks = _param1 != 0; - // Required to update the clearance checks overlay on the Cheats button. - window_invalidate_by_class(WC_TOP_TOOLBAR); - break; - case CheatType::DisableSupportLimits: - gCheatsDisableSupportLimits = _param1 != 0; - break; - case CheatType::ShowAllOperatingModes: - gCheatsShowAllOperatingModes = _param1 != 0; - break; - case CheatType::ShowVehiclesFromOtherTrackTypes: - gCheatsShowVehiclesFromOtherTrackTypes = _param1 != 0; - break; - case CheatType::FastLiftHill: - gCheatsFastLiftHill = _param1 != 0; - break; - case CheatType::DisableBrakesFailure: - gCheatsDisableBrakesFailure = _param1 != 0; - break; - case CheatType::DisableAllBreakdowns: - gCheatsDisableAllBreakdowns = _param1 != 0; - break; - case CheatType::DisableTrainLengthLimit: - gCheatsDisableTrainLengthLimit = _param1 != 0; - break; - case CheatType::EnableChainLiftOnAllTrack: - gCheatsEnableChainLiftOnAllTrack = _param1 != 0; - break; - case CheatType::BuildInPauseMode: - gCheatsBuildInPauseMode = _param1 != 0; - break; - case CheatType::IgnoreRideIntensity: - gCheatsIgnoreRideIntensity = _param1 != 0; - break; - case CheatType::DisableVandalism: - gCheatsDisableVandalism = _param1 != 0; - break; - case CheatType::DisableLittering: - gCheatsDisableLittering = _param1 != 0; - break; - case CheatType::NoMoney: - SetScenarioNoMoney(_param1 != 0); - break; - case CheatType::AddMoney: - AddMoney(_param1); - break; - case CheatType::SetMoney: - SetMoney(_param1); - break; - case CheatType::ClearLoan: - ClearLoan(); - break; - case CheatType::SetGuestParameter: - SetGuestParameter(_param1, _param2); - break; - case CheatType::GenerateGuests: - GenerateGuests(_param1); - break; - case CheatType::RemoveAllGuests: - RemoveAllGuests(); - break; - case CheatType::GiveAllGuests: - GiveObjectToGuests(_param1); - break; - case CheatType::SetGrassLength: - SetGrassLength(_param1); - break; - case CheatType::WaterPlants: - WaterPlants(); - break; - case CheatType::FixVandalism: - FixVandalism(); - break; - case CheatType::RemoveLitter: - RemoveLitter(); - break; - case CheatType::DisablePlantAging: - gCheatsDisablePlantAging = _param1 != 0; - break; - case CheatType::SetStaffSpeed: - SetStaffSpeed(_param1); - break; - case CheatType::RenewRides: - RenewRides(); - break; - case CheatType::MakeDestructible: - MakeDestructible(); - break; - case CheatType::FixRides: - FixBrokenRides(); - break; - case CheatType::ResetCrashStatus: - ResetRideCrashStatus(); - break; - case CheatType::TenMinuteInspections: - Set10MinuteInspection(); - break; - case CheatType::WinScenario: - scenario_success(); - break; - case CheatType::ForceWeather: - // Todo - make sure this is safe - climate_force_weather(WeatherType{ static_cast(_param1) }); - break; - case CheatType::FreezeWeather: - gCheatsFreezeWeather = _param1 != 0; - break; - case CheatType::NeverEndingMarketing: - gCheatsNeverendingMarketing = _param1 != 0; - break; - case CheatType::OpenClosePark: - ParkSetOpen(!park_is_open()); - break; - case CheatType::HaveFun: - gScenarioObjective.Type = OBJECTIVE_HAVE_FUN; - break; - case CheatType::SetForcedParkRating: - set_forced_park_rating(_param1); - break; - case CheatType::AllowArbitraryRideTypeChanges: - gCheatsAllowArbitraryRideTypeChanges = _param1 != 0; - window_invalidate_by_class(WC_RIDE); - break; - case CheatType::OwnAllLand: - OwnAllLand(); - break; - case CheatType::DisableRideValueAging: - gCheatsDisableRideValueAging = _param1 != 0; - break; - case CheatType::IgnoreResearchStatus: - gCheatsIgnoreResearchStatus = _param1 != 0; - break; - case CheatType::EnableAllDrawableTrackPieces: - gCheatsEnableAllDrawableTrackPieces = _param1 != 0; - break; - case CheatType::CreateDucks: - CreateDucks(_param1); - break; - case CheatType::RemoveDucks: - duck_remove_all(); - break; - case CheatType::AllowTrackPlaceInvalidHeights: - gCheatsAllowTrackPlaceInvalidHeights = _param1 != 0; - break; - default: - { - log_error("Unabled cheat: %d", _cheatType.id); - MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - break; - } - - if (network_get_mode() == NETWORK_MODE_NONE) - { - config_save_default(); - } - - window_invalidate_by_class(WC_CHEATS); - return MakeResult(); - } - -private: - ParametersRange GetParameterRange(CheatType cheatType) const - { - switch (static_cast(_cheatType.id)) - { - case CheatType::SandboxMode: - [[fallthrough]]; - case CheatType::DisableClearanceChecks: - [[fallthrough]]; - case CheatType::DisableSupportLimits: - [[fallthrough]]; - case CheatType::ShowAllOperatingModes: - [[fallthrough]]; - case CheatType::ShowVehiclesFromOtherTrackTypes: - [[fallthrough]]; - case CheatType::FastLiftHill: - [[fallthrough]]; - case CheatType::DisableBrakesFailure: - [[fallthrough]]; - case CheatType::DisableAllBreakdowns: - [[fallthrough]]; - case CheatType::DisableTrainLengthLimit: - [[fallthrough]]; - case CheatType::EnableChainLiftOnAllTrack: - [[fallthrough]]; - case CheatType::BuildInPauseMode: - [[fallthrough]]; - case CheatType::IgnoreRideIntensity: - [[fallthrough]]; - case CheatType::DisableVandalism: - [[fallthrough]]; - case CheatType::DisableLittering: - [[fallthrough]]; - case CheatType::NoMoney: - [[fallthrough]]; - case CheatType::DisablePlantAging: - [[fallthrough]]; - case CheatType::FreezeWeather: - [[fallthrough]]; - case CheatType::NeverEndingMarketing: - [[fallthrough]]; - case CheatType::AllowArbitraryRideTypeChanges: - [[fallthrough]]; - case CheatType::DisableRideValueAging: - [[fallthrough]]; - case CheatType::IgnoreResearchStatus: - [[fallthrough]]; - case CheatType::EnableAllDrawableTrackPieces: - [[fallthrough]]; - case CheatType::OpenClosePark: - return { { 0, 1 }, { 0, 0 } }; - case CheatType::AddMoney: - [[fallthrough]]; - case CheatType::SetMoney: - return { { std::numeric_limits::min(), std::numeric_limits::max() }, { 0, 0 } }; - case CheatType::SetGuestParameter: - switch (_param1) - { - case GUEST_PARAMETER_HAPPINESS: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { 0, PEEP_MAX_HAPPINESS } }; - case GUEST_PARAMETER_ENERGY: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { PEEP_MIN_ENERGY, PEEP_MAX_ENERGY } }; - case GUEST_PARAMETER_HUNGER: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { 0, PEEP_MAX_HUNGER } }; - case GUEST_PARAMETER_THIRST: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { 0, PEEP_MAX_THIRST } }; - case GUEST_PARAMETER_NAUSEA: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { 0, PEEP_MAX_NAUSEA } }; - case GUEST_PARAMETER_NAUSEA_TOLERANCE: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { EnumValue(PeepNauseaTolerance::None), EnumValue(PeepNauseaTolerance::High) } }; - case GUEST_PARAMETER_TOILET: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { 0, PEEP_MAX_TOILET } }; - case GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, 255 } }; - default: - return { { 0, 0 }, { 0, 0 } }; - } - case CheatType::GenerateGuests: - return { { 1, 10000 }, { 0, 0 } }; - case CheatType::GiveAllGuests: - return { { OBJECT_MONEY, OBJECT_UMBRELLA }, { 0, 0 } }; - case CheatType::SetGrassLength: - return { { 0, 7 }, { 0, 0 } }; - case CheatType::SetStaffSpeed: - return { { 0, 255 }, { 0, 0 } }; - case CheatType::ForceWeather: - return { { 0, EnumValue(WeatherType::Count) - 1 }, { 0, 0 } }; - case CheatType::SetForcedParkRating: - return { { 0, 999 }, { 0, 0 } }; - case CheatType::CreateDucks: - return { { 0, 100 }, { 0, 0 } }; - default: - return { { 0, 0 }, { 0, 0 } }; - } - } - - void SetGrassLength(int32_t length) const - { - for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) - { - for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) - { - auto surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); - if (surfaceElement == nullptr) - continue; - - if (surfaceElement != nullptr && (surfaceElement->GetOwnership() & OWNERSHIP_OWNED) - && surfaceElement->GetWaterHeight() == 0 && surfaceElement->CanGrassGrow()) - { - surfaceElement->SetGrassLength(length); - } - } - } - - gfx_invalidate_screen(); - } - - void WaterPlants() const - { - tile_element_iterator it; - - tile_element_iterator_begin(&it); - do - { - if (it.element->GetType() == TILE_ELEMENT_TYPE_SMALL_SCENERY) - { - it.element->AsSmallScenery()->SetAge(0); - } - } while (tile_element_iterator_next(&it)); - - gfx_invalidate_screen(); - } - - void FixVandalism() const - { - tile_element_iterator it; - - tile_element_iterator_begin(&it); - do - { - if (it.element->GetType() != TILE_ELEMENT_TYPE_PATH) - continue; - - if (!(it.element)->AsPath()->HasAddition()) - continue; - - it.element->AsPath()->SetIsBroken(false); - } while (tile_element_iterator_next(&it)); - - gfx_invalidate_screen(); - } - - void RemoveLitter() const - { - for (auto litter : EntityList(EntityListId::Litter)) - { - sprite_remove(litter); - } - - tile_element_iterator it; - rct_scenery_entry* sceneryEntry; - - tile_element_iterator_begin(&it); - do - { - if (it.element->GetType() != TILE_ELEMENT_TYPE_PATH) - continue; - - if (!(it.element)->AsPath()->HasAddition()) - continue; - - sceneryEntry = it.element->AsPath()->GetAdditionEntry(); - if (sceneryEntry->path_bit.flags & PATH_BIT_FLAG_IS_BIN) - it.element->AsPath()->SetAdditionStatus(0xFF); - - } while (tile_element_iterator_next(&it)); - - gfx_invalidate_screen(); - } - - void FixBrokenRides() const - { - for (auto& ride : GetRideManager()) - { - if ((ride.mechanic_status != RIDE_MECHANIC_STATUS_FIXING) - && (ride.lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN))) - { - auto mechanic = ride_get_assigned_mechanic(&ride); - if (mechanic != nullptr) - { - mechanic->RemoveFromRide(); - } - - ride_fix_breakdown(&ride, 0); - ride.window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - } - } - } - - void RenewRides() const - { - for (auto& ride : GetRideManager()) - { - ride.Renew(); - } - window_invalidate_by_class(WC_RIDE); - } - - void MakeDestructible() const - { - for (auto& ride : GetRideManager()) - { - ride.lifecycle_flags &= ~RIDE_LIFECYCLE_INDESTRUCTIBLE; - ride.lifecycle_flags &= ~RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK; - } - window_invalidate_by_class(WC_RIDE); - } - - void ResetRideCrashStatus() const - { - for (auto& ride : GetRideManager()) - { - // Reset crash status and history - ride.lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; - ride.last_crash_type = RIDE_CRASH_TYPE_NONE; - } - window_invalidate_by_class(WC_RIDE); - } - - void Set10MinuteInspection() const - { - for (auto& ride : GetRideManager()) - { - // Set inspection interval to 10 minutes - ride.inspection_interval = RIDE_INSPECTION_EVERY_10_MINUTES; - } - window_invalidate_by_class(WC_RIDE); - } - - void SetScenarioNoMoney(bool enabled) const - { - if (enabled) - { - gParkFlags |= PARK_FLAGS_NO_MONEY; - } - else - { - gParkFlags &= ~PARK_FLAGS_NO_MONEY; - } - // Invalidate all windows that have anything to do with finance - window_invalidate_by_class(WC_RIDE); - window_invalidate_by_class(WC_PEEP); - window_invalidate_by_class(WC_PARK_INFORMATION); - window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - window_invalidate_by_class(WC_TOP_TOOLBAR); - window_invalidate_by_class(WC_CHEATS); - } - - void SetMoney(money32 amount) const - { - gCash = amount; - - window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - } - - void AddMoney(money32 amount) const - { - gCash = add_clamp_money32(gCash, amount); - - window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - } - - void ClearLoan() const - { - // First give money - AddMoney(gBankLoan); - - // Then pay the loan - auto gameAction = ParkSetLoanAction(MONEY(0, 00)); - GameActions::ExecuteNested(&gameAction); - } - - void GenerateGuests(int32_t count) const - { - auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); - for (int32_t i = 0; i < count; i++) - { - park.GenerateGuest(); - } - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - } - - void SetGuestParameter(int32_t parameter, int32_t value) const - { - for (auto peep : EntityList(EntityListId::Peep)) - { - switch (parameter) - { - case GUEST_PARAMETER_HAPPINESS: - peep->Happiness = value; - peep->HappinessTarget = value; - // Clear the 'red-faced with anger' status if we're making the guest happy - if (value > 0) - { - peep->PeepFlags &= ~PEEP_FLAGS_ANGRY; - peep->Angriness = 0; - } - break; - case GUEST_PARAMETER_ENERGY: - peep->Energy = value; - peep->EnergyTarget = value; - break; - case GUEST_PARAMETER_HUNGER: - peep->Hunger = value; - break; - case GUEST_PARAMETER_THIRST: - peep->Thirst = value; - break; - case GUEST_PARAMETER_NAUSEA: - peep->Nausea = value; - peep->NauseaTarget = value; - break; - case GUEST_PARAMETER_NAUSEA_TOLERANCE: - peep->NauseaTolerance = static_cast(value); - break; - case GUEST_PARAMETER_TOILET: - peep->Toilet = value; - break; - case GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY: - peep->Intensity = IntensityRange(value, 15); - break; - } - peep->UpdateSpriteType(); - } - } - - void GiveObjectToGuests(int32_t object) const - { - for (auto peep : EntityList(EntityListId::Peep)) - { - switch (object) - { - case OBJECT_MONEY: - peep->CashInPocket = MONEY(1000, 00); - break; - case OBJECT_PARK_MAP: - peep->GiveItem(ShopItem::Map); - break; - case OBJECT_BALLOON: - peep->GiveItem(ShopItem::Balloon); - peep->BalloonColour = scenario_rand_max(COLOUR_COUNT - 1); - peep->UpdateSpriteType(); - break; - case OBJECT_UMBRELLA: - peep->GiveItem(ShopItem::Umbrella); - peep->UmbrellaColour = scenario_rand_max(COLOUR_COUNT - 1); - peep->UpdateSpriteType(); - break; - } - } - window_invalidate_by_class(WC_PEEP); - } - - void RemoveAllGuests() const - { - for (auto& ride : GetRideManager()) - { - ride.num_riders = 0; - - for (size_t stationIndex = 0; stationIndex < MAX_STATIONS; stationIndex++) - { - ride.stations[stationIndex].QueueLength = 0; - ride.stations[stationIndex].LastPeepInQueue = SPRITE_INDEX_NULL; - } - - for (auto trainIndex : ride.vehicles) - { - for (Vehicle* vehicle = TryGetEntity(trainIndex); vehicle != nullptr; - vehicle = TryGetEntity(vehicle->next_vehicle_on_train)) - { - for (auto& peepInTrainIndex : vehicle->peep) - { - auto peep = TryGetEntity(peepInTrainIndex); - if (peep != nullptr) - { - vehicle->mass -= peep->Mass; - } - peepInTrainIndex = SPRITE_INDEX_NULL; - } - - vehicle->num_peeps = 0; - vehicle->next_free_seat = 0; - } - } - } - - // Do not use the FOR_ALL_PEEPS macro for this as next sprite index - // will be fetched on a deleted peep. - for (auto peep : EntityList(EntityListId::Peep)) - { - if (peep->AssignedPeepType == PeepType::Guest) - { - peep->Remove(); - } - } - - window_invalidate_by_class(WC_RIDE); - gfx_invalidate_screen(); - } - - void SetStaffSpeed(uint8_t value) const - { - for (auto peep : EntityList(EntityListId::Peep)) - { - peep->Energy = value; - peep->EnergyTarget = value; - } - } - - void OwnAllLand() const - { - const int32_t min = 32; - const int32_t max = gMapSizeUnits - 32; - - for (CoordsXY coords = { min, min }; coords.y <= max; coords.y += COORDS_XY_STEP) - { - for (coords.x = min; coords.x <= max; coords.x += COORDS_XY_STEP) - { - auto* surfaceElement = map_get_surface_element_at(coords); - if (surfaceElement == nullptr) - continue; - - // Ignore already owned tiles. - if (surfaceElement->GetOwnership() & OWNERSHIP_OWNED) - continue; - - int32_t baseZ = surfaceElement->GetBaseZ(); - int32_t destOwnership = check_max_allowable_land_rights_for_tile({ coords, baseZ }); - - // only own tiles that were not set to 0 - if (destOwnership != OWNERSHIP_UNOWNED) - { - surfaceElement->SetOwnership(destOwnership); - update_park_fences_around_tile(coords); - map_invalidate_tile({ coords, baseZ, baseZ + 16 }); - } - } - } - - // Completely unown peep spawn points - for (const auto& spawn : gPeepSpawns) - { - auto* surfaceElement = map_get_surface_element_at(spawn); - if (surfaceElement != nullptr) - { - surfaceElement->SetOwnership(OWNERSHIP_UNOWNED); - update_park_fences_around_tile(spawn); - uint16_t baseZ = surfaceElement->GetBaseZ(); - map_invalidate_tile({ spawn, baseZ, baseZ + 16 }); - } - } - - map_count_remaining_land_rights(); - } - - void ParkSetOpen(bool isOpen) const - { - auto parkSetParameter = ParkSetParameterAction(isOpen ? ParkParameter::Open : ParkParameter::Close); - GameActions::ExecuteNested(&parkSetParameter); - } - - void CreateDucks(int count) const - { - for (int i = 0; i < count; i++) - { - // 100 attempts at finding some water to create a few ducks at - for (int32_t attempts = 0; attempts < 100; attempts++) - { - if (scenario_create_ducks()) - break; - } - } - } -}; diff --git a/src/openrct2/actions/SetParkEntranceFeeAction.cpp b/src/openrct2/actions/SetParkEntranceFeeAction.cpp new file mode 100644 index 0000000000..fa4491aca6 --- /dev/null +++ b/src/openrct2/actions/SetParkEntranceFeeAction.cpp @@ -0,0 +1,45 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "SetParkEntranceFeeAction.h" + +#include "../Cheats.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../world/Park.h" + +void SetParkEntranceFeeAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_fee); +} + +GameActions::Result::Ptr SetParkEntranceFeeAction::Query() const +{ + bool noMoney = (gParkFlags & PARK_FLAGS_NO_MONEY) != 0; + bool forceFreeEntry = !park_entry_price_unlocked(); + if (noMoney || forceFreeEntry) + { + return std::make_unique(GameActions::Status::Disallowed, STR_NONE); + } + if (_fee < MONEY_FREE || _fee > MAX_ENTRANCE_FEE) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + return std::make_unique(); +} + +GameActions::Result::Ptr SetParkEntranceFeeAction::Execute() const +{ + gParkEntranceFee = _fee; + window_invalidate_by_class(WC_PARK_INFORMATION); + return std::make_unique(); +} diff --git a/src/openrct2/actions/SetParkEntranceFeeAction.h b/src/openrct2/actions/SetParkEntranceFeeAction.h new file mode 100644 index 0000000000..cf8478200c --- /dev/null +++ b/src/openrct2/actions/SetParkEntranceFeeAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(SetParkEntranceFeeAction, GAME_COMMAND_SET_PARK_ENTRANCE_FEE, GameActions::Result) +{ +private: + money16 _fee{ MONEY16_UNDEFINED }; + +public: + SetParkEntranceFeeAction() = default; + SetParkEntranceFeeAction(money16 fee) + : _fee(fee) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/SetParkEntranceFeeAction.hpp b/src/openrct2/actions/SetParkEntranceFeeAction.hpp deleted file mode 100644 index c8682e8dbd..0000000000 --- a/src/openrct2/actions/SetParkEntranceFeeAction.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../world/Park.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(SetParkEntranceFeeAction, GAME_COMMAND_SET_PARK_ENTRANCE_FEE, GameActions::Result) -{ -private: - money16 _fee{ MONEY16_UNDEFINED }; - -public: - SetParkEntranceFeeAction() = default; - SetParkEntranceFeeAction(money16 fee) - : _fee(fee) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_fee); - } - - GameActions::Result::Ptr Query() const override - { - bool noMoney = (gParkFlags & PARK_FLAGS_NO_MONEY) != 0; - bool forceFreeEntry = !park_entry_price_unlocked(); - if (noMoney || forceFreeEntry) - { - return std::make_unique(GameActions::Status::Disallowed, STR_NONE); - } - if (_fee < MONEY_FREE || _fee > MAX_ENTRANCE_FEE) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - gParkEntranceFee = _fee; - window_invalidate_by_class(WC_PARK_INFORMATION); - return std::make_unique(); - } -}; diff --git a/src/openrct2/actions/SignSetNameAction.cpp b/src/openrct2/actions/SignSetNameAction.cpp new file mode 100644 index 0000000000..c2e7f850d2 --- /dev/null +++ b/src/openrct2/actions/SignSetNameAction.cpp @@ -0,0 +1,70 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "SignSetNameAction.h" + +#include "../Context.h" +#include "../Diagnostic.h" +#include "../common.h" +#include "../drawing/Drawing.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../ride/Ride.h" +#include "../world/Banner.h" + +#include + +void SignSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_bannerIndex) << DS_TAG(_name); +} + +GameActions::Result::Ptr SignSetNameAction::Query() const +{ + if (_bannerIndex >= MAX_BANNERS) + { + log_warning("Invalid game command for setting sign name, banner id = %d", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return MakeResult(); +} + +GameActions::Result::Ptr SignSetNameAction::Execute() const +{ + auto banner = GetBanner(_bannerIndex); + + if (!_name.empty()) + { + banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; + banner->ride_index = RIDE_ID_NULL; + banner->text = _name; + } + else + { + // If empty name take closest ride name. + ride_id_t rideIndex = banner_get_closest_ride_index({ banner->position.ToCoordsXY(), 16 }); + if (rideIndex == RIDE_ID_NULL) + { + banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; + banner->ride_index = RIDE_ID_NULL; + banner->text = {}; + } + else + { + banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; + banner->ride_index = rideIndex; + banner->text = {}; + } + } + + scrolling_text_invalidate(); + gfx_invalidate_screen(); + return MakeResult(); +} diff --git a/src/openrct2/actions/SignSetNameAction.h b/src/openrct2/actions/SignSetNameAction.h new file mode 100644 index 0000000000..4a828ec8a3 --- /dev/null +++ b/src/openrct2/actions/SignSetNameAction.h @@ -0,0 +1,36 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(SignSetNameAction, GAME_COMMAND_SET_SIGN_NAME, GameActions::Result) +{ +private: + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; + std::string _name; + +public: + SignSetNameAction() = default; + SignSetNameAction(BannerIndex bannerIndex, const std::string& name) + : _bannerIndex(bannerIndex) + , _name(name) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/SignSetNameAction.hpp b/src/openrct2/actions/SignSetNameAction.hpp deleted file mode 100644 index f1aa3c584b..0000000000 --- a/src/openrct2/actions/SignSetNameAction.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../Diagnostic.h" -#include "../common.h" -#include "../drawing/Drawing.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../ride/Ride.h" -#include "../world/Banner.h" -#include "GameAction.h" - -#include - -DEFINE_GAME_ACTION(SignSetNameAction, GAME_COMMAND_SET_SIGN_NAME, GameActions::Result) -{ -private: - BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; - std::string _name; - -public: - SignSetNameAction() = default; - SignSetNameAction(BannerIndex bannerIndex, const std::string& name) - : _bannerIndex(bannerIndex) - , _name(name) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_bannerIndex) << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - if (_bannerIndex >= MAX_BANNERS) - { - log_warning("Invalid game command for setting sign name, banner id = %d", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto banner = GetBanner(_bannerIndex); - - if (!_name.empty()) - { - banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; - banner->ride_index = RIDE_ID_NULL; - banner->text = _name; - } - else - { - // If empty name take closest ride name. - ride_id_t rideIndex = banner_get_closest_ride_index({ banner->position.ToCoordsXY(), 16 }); - if (rideIndex == RIDE_ID_NULL) - { - banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; - banner->ride_index = RIDE_ID_NULL; - banner->text = {}; - } - else - { - banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; - banner->ride_index = rideIndex; - banner->text = {}; - } - } - - scrolling_text_invalidate(); - gfx_invalidate_screen(); - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/SignSetStyleAction.cpp b/src/openrct2/actions/SignSetStyleAction.cpp new file mode 100644 index 0000000000..994af3b9c4 --- /dev/null +++ b/src/openrct2/actions/SignSetStyleAction.cpp @@ -0,0 +1,94 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "SignSetStyleAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../localisation/StringIds.h" +#include "../ui/UiContext.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" + +void SignSetStyleAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_bannerIndex) << DS_TAG(_mainColour) << DS_TAG(_textColour) << DS_TAG(_isLarge); +} + +GameActions::Result::Ptr SignSetStyleAction::Query() const +{ + if (_bannerIndex >= MAX_BANNERS) + { + log_warning("Invalid game command for setting sign style, banner id '%d' out of range", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (_isLarge) + { + TileElement* tileElement = banner_get_tile_element(_bannerIndex); + if (tileElement == nullptr) + { + log_warning("Invalid game command for setting sign style, banner id '%d' not found", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) + { + log_warning("Invalid game command for setting sign style, banner id '%d' is not large", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + } + else + { + WallElement* wallElement = banner_get_scrolling_wall_tile_element(_bannerIndex); + + if (!wallElement) + { + log_warning("Invalid game command for setting sign style, banner id '%d' not found", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + } + + return MakeResult(); +} + +GameActions::Result::Ptr SignSetStyleAction::Execute() const +{ + auto banner = GetBanner(_bannerIndex); + + CoordsXY coords = banner->position.ToCoordsXY(); + + if (_isLarge) + { + TileElement* tileElement = banner_get_tile_element(_bannerIndex); + if (!map_large_scenery_sign_set_colour( + { coords, tileElement->GetBaseZ(), tileElement->GetDirection() }, + tileElement->AsLargeScenery()->GetSequenceIndex(), _mainColour, _textColour)) + { + return MakeResult(GameActions::Status::Unknown, STR_NONE); + } + } + else + { + WallElement* wallElement = banner_get_scrolling_wall_tile_element(_bannerIndex); + + wallElement->SetPrimaryColour(_mainColour); + wallElement->SetSecondaryColour(_textColour); + map_invalidate_tile({ coords, wallElement->GetBaseZ(), wallElement->GetClearanceZ() }); + } + + auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); + intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); + context_broadcast_intent(&intent); + + return MakeResult(); +} diff --git a/src/openrct2/actions/SignSetStyleAction.h b/src/openrct2/actions/SignSetStyleAction.h new file mode 100644 index 0000000000..498ef63b9a --- /dev/null +++ b/src/openrct2/actions/SignSetStyleAction.h @@ -0,0 +1,40 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(SignSetStyleAction, GAME_COMMAND_SET_SIGN_STYLE, GameActions::Result) +{ +private: + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; + uint8_t _mainColour{}; + uint8_t _textColour{}; + bool _isLarge{}; + +public: + SignSetStyleAction() = default; + SignSetStyleAction(BannerIndex bannerIndex, uint8_t mainColour, uint8_t textColour, bool isLarge) + : _bannerIndex(bannerIndex) + , _mainColour(mainColour) + , _textColour(textColour) + , _isLarge(isLarge) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/SignSetStyleAction.hpp b/src/openrct2/actions/SignSetStyleAction.hpp deleted file mode 100644 index d500cdd201..0000000000 --- a/src/openrct2/actions/SignSetStyleAction.hpp +++ /dev/null @@ -1,119 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../localisation/StringIds.h" -#include "../ui/UiContext.h" -#include "../windows/Intent.h" -#include "../world/Banner.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(SignSetStyleAction, GAME_COMMAND_SET_SIGN_STYLE, GameActions::Result) -{ -private: - BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; - uint8_t _mainColour{}; - uint8_t _textColour{}; - bool _isLarge{}; - -public: - SignSetStyleAction() = default; - SignSetStyleAction(BannerIndex bannerIndex, uint8_t mainColour, uint8_t textColour, bool isLarge) - : _bannerIndex(bannerIndex) - , _mainColour(mainColour) - , _textColour(textColour) - , _isLarge(isLarge) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_bannerIndex) << DS_TAG(_mainColour) << DS_TAG(_textColour) << DS_TAG(_isLarge); - } - - GameActions::Result::Ptr Query() const override - { - if (_bannerIndex >= MAX_BANNERS) - { - log_warning("Invalid game command for setting sign style, banner id '%d' out of range", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (_isLarge) - { - TileElement* tileElement = banner_get_tile_element(_bannerIndex); - if (tileElement == nullptr) - { - log_warning("Invalid game command for setting sign style, banner id '%d' not found", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) - { - log_warning("Invalid game command for setting sign style, banner id '%d' is not large", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - } - else - { - WallElement* wallElement = banner_get_scrolling_wall_tile_element(_bannerIndex); - - if (!wallElement) - { - log_warning("Invalid game command for setting sign style, banner id '%d' not found", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto banner = GetBanner(_bannerIndex); - - CoordsXY coords = banner->position.ToCoordsXY(); - - if (_isLarge) - { - TileElement* tileElement = banner_get_tile_element(_bannerIndex); - if (!map_large_scenery_sign_set_colour( - { coords, tileElement->GetBaseZ(), tileElement->GetDirection() }, - tileElement->AsLargeScenery()->GetSequenceIndex(), _mainColour, _textColour)) - { - return MakeResult(GameActions::Status::Unknown, STR_NONE); - } - } - else - { - WallElement* wallElement = banner_get_scrolling_wall_tile_element(_bannerIndex); - - wallElement->SetPrimaryColour(_mainColour); - wallElement->SetSecondaryColour(_textColour); - map_invalidate_tile({ coords, wallElement->GetBaseZ(), wallElement->GetClearanceZ() }); - } - - auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); - intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); - context_broadcast_intent(&intent); - - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.cpp b/src/openrct2/actions/SmallSceneryPlaceAction.cpp new file mode 100644 index 0000000000..0f693cc8f8 --- /dev/null +++ b/src/openrct2/actions/SmallSceneryPlaceAction.cpp @@ -0,0 +1,423 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "SmallSceneryPlaceAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../ride/TrackDesign.h" +#include "../world/MapAnimation.h" +#include "../world/Park.h" +#include "../world/SmallScenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" +#include "../world/TileElement.h" +#include "GameAction.h" +#include "SmallSceneryRemoveAction.h" + +void SmallSceneryPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("quadrant", _quadrant); + visitor.Visit("object", _sceneryType); + visitor.Visit("primaryColour", _primaryColour); + visitor.Visit("secondaryColour", _secondaryColour); +} + +void SmallSceneryPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour); +} + +GameActions::Result::Ptr SmallSceneryPlaceAction::Query() const +{ + bool isOnWater = false; + bool supportsRequired = false; + if (_loc.z != 0) + { + supportsRequired = true; + } + int32_t landHeight = tile_element_height(_loc); + int16_t waterHeight = tile_element_water_height(_loc); + + int32_t surfaceHeight = landHeight; + // If on water + if (waterHeight > 0) + { + surfaceHeight = waterHeight; + } + auto res = std::make_unique(); + auto centre = _loc.ToTileCentre(); + res->Position.x = centre.x; + res->Position.y = centre.y; + res->Position.z = surfaceHeight; + if (_loc.z != 0) + { + surfaceHeight = _loc.z; + res->Position.z = surfaceHeight; + } + + if (!map_check_free_elements_and_reorganise(1)) + { + return std::make_unique(GameActions::Status::NoFreeElements); + } + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters); + } + + if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY)) + { + return std::make_unique(GameActions::Status::InvalidParameters); + } + + rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType); + if (sceneryEntry == nullptr) + { + return std::make_unique(GameActions::Status::InvalidParameters); + } + + auto quadrant = _quadrant; + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE) + || !scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL)) + { + if (scenery_small_entry_has_flag( + sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS)) + { + quadrant = 0; + } + } + + // Check if sub tile height is any different compared to actual surface tile height + auto loc2 = _loc; + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) + { + loc2 = loc2.ToTileCentre(); + } + else + { + loc2.x += SceneryQuadrantOffsets[quadrant & 3].x - 1; + loc2.y += SceneryQuadrantOffsets[quadrant & 3].y - 1; + } + landHeight = tile_element_height(loc2); + waterHeight = tile_element_water_height(loc2); + + surfaceHeight = landHeight; + // If on water + if (waterHeight > 0) + { + // base_height2 is now the water height + surfaceHeight = waterHeight; + if (_loc.z == 0) + { + isOnWater = true; + } + } + auto targetHeight = _loc.z; + if (_loc.z == 0) + { + targetHeight = surfaceHeight; + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode + && !map_is_location_owned({ _loc.x, _loc.y, targetHeight })) + { + return std::make_unique(GameActions::Status::NotOwned, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto* surfaceElement = map_get_surface_element_at(_loc); + + if (surfaceElement != nullptr && !gCheatsDisableClearanceChecks && surfaceElement->GetWaterHeight() > 0) + { + int32_t water_height = surfaceElement->GetWaterHeight() - 1; + if (water_height > targetHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); + } + } + + if (!gCheatsDisableClearanceChecks && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE))) + { + if (isOnWater) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); + } + + if (surfaceElement != nullptr && surfaceElement->GetWaterHeight() > 0) + { + if (surfaceElement->GetWaterHeight() > targetHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); + } + } + } + + if (!gCheatsDisableClearanceChecks && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE)) + && !supportsRequired && !isOnWater && surfaceElement != nullptr + && (surfaceElement->GetSlope() != TILE_ELEMENT_SLOPE_FLAT)) + { + return std::make_unique(GameActions::Status::Disallowed, STR_LEVEL_LAND_REQUIRED); + } + + if (!gCheatsDisableSupportLimits && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE)) + && supportsRequired) + { + if (!isOnWater) + { + if (surfaceElement != nullptr) + { + if (surfaceElement->GetWaterHeight() > 0 || (surfaceElement->GetBaseZ()) != targetHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_LEVEL_LAND_REQUIRED); + } + } + } + else + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); + } + } + + int32_t zLow = targetHeight; + int32_t zHigh = zLow + ceil2(sceneryEntry->small_scenery.height, COORDS_Z_STEP); + uint8_t collisionQuadrants = 0b1111; + auto quadRotation{ 0 }; + if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))) + { + quadRotation = (quadrant ^ 2); + collisionQuadrants = 0b0001; + } + if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE))) + { + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL) + && scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) + { + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) + { + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; + collisionQuadrants = 0b1011; + } + else + { + quadRotation = (quadrant + _loc.direction) & 1; + collisionQuadrants = 0b1010; + } + } + } + else + { + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; + collisionQuadrants = 0b0011; + } + uint8_t supports = 0; + if (!supportsRequired) + { + supports = 0b1111; + } + + QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); + money32 clearCost = 0; + + if (!map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &clearCost, + CREATE_CROSSING_MODE_NONE)) + { + return std::make_unique( + GameActions::Status::Disallowed, gGameCommandErrorText, gCommonFormatArgs); + } + + res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + + res->Expenditure = ExpenditureType::Landscaping; + res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost; + + return res; +} + +GameActions::Result::Ptr SmallSceneryPlaceAction::Execute() const +{ + bool supportsRequired = false; + if (_loc.z != 0) + { + supportsRequired = true; + } + int32_t landHeight = tile_element_height(_loc); + int16_t waterHeight = tile_element_water_height(_loc); + + int32_t surfaceHeight = landHeight; + // If on water + if (waterHeight > 0) + { + surfaceHeight = waterHeight; + } + auto res = std::make_unique(); + auto centre = _loc.ToTileCentre(); + res->Position.x = centre.x; + res->Position.y = centre.y; + res->Position.z = surfaceHeight; + if (_loc.z != 0) + { + surfaceHeight = _loc.z; + res->Position.z = surfaceHeight; + } + + rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType); + if (sceneryEntry == nullptr) + { + return std::make_unique(GameActions::Status::InvalidParameters); + } + + auto quadrant = _quadrant; + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE) + || !scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL)) + { + if (scenery_small_entry_has_flag( + sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS)) + { + quadrant = 0; + } + } + + // Check if sub tile height is any different compared to actual surface tile height + int32_t x2 = _loc.x; + int32_t y2 = _loc.y; + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) + { + x2 += 16; + y2 += 16; + } + else + { + x2 += SceneryQuadrantOffsets[quadrant & 3].x - 1; + y2 += SceneryQuadrantOffsets[quadrant & 3].y - 1; + } + landHeight = tile_element_height({ x2, y2 }); + waterHeight = tile_element_water_height({ x2, y2 }); + + surfaceHeight = landHeight; + // If on water + if (waterHeight > 0) + { + // base_height2 is now the water height + surfaceHeight = waterHeight; + } + auto targetHeight = _loc.z; + if (_loc.z == 0) + { + targetHeight = surfaceHeight; + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter({ _loc, targetHeight }); + if (!gCheatsDisableClearanceChecks && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_NO_WALLS))) + { + wall_remove_at({ _loc, targetHeight, targetHeight + sceneryEntry->small_scenery.height }); + } + } + + int32_t zLow = targetHeight; + int32_t zHigh = zLow + ceil2(sceneryEntry->small_scenery.height, 8); + uint8_t collisionQuadrants = 0b1111; + auto quadRotation{ 0 }; + if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))) + { + quadRotation = (quadrant ^ 2); + collisionQuadrants = 0b0001; + } + if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE))) + { + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL) + && scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) + { + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) + { + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; + collisionQuadrants = 0b1011; + } + else + { + quadRotation = (quadrant + _loc.direction) & 1; + collisionQuadrants = 0b1010; + } + } + } + else + { + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; + collisionQuadrants = 0b0011; + } + uint8_t supports = 0; + if (!supportsRequired) + { + supports = 0b1111; + } + + QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); + money32 clearCost = 0; + + if (!map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags() | GAME_COMMAND_FLAG_APPLY, &clearCost, + CREATE_CROSSING_MODE_NONE)) + { + return std::make_unique( + GameActions::Status::Disallowed, gGameCommandErrorText, gCommonFormatArgs); + } + + res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + + res->Expenditure = ExpenditureType::Landscaping; + res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost; + + TileElement* newElement = tile_element_insert(CoordsXYZ{ _loc, zLow }, quarterTile.GetBaseQuarterOccupied()); + assert(newElement != nullptr); + res->tileElement = newElement; + newElement->SetType(TILE_ELEMENT_TYPE_SMALL_SCENERY); + newElement->SetDirection(_loc.direction); + SmallSceneryElement* sceneryElement = newElement->AsSmallScenery(); + sceneryElement->SetSceneryQuadrant(quadrant); + sceneryElement->SetEntryIndex(_sceneryType); + sceneryElement->SetAge(0); + sceneryElement->SetPrimaryColour(_primaryColour); + sceneryElement->SetSecondaryColour(_secondaryColour); + sceneryElement->SetClearanceZ(sceneryElement->GetBaseZ() + sceneryEntry->small_scenery.height + 7); + + if (supportsRequired) + { + sceneryElement->SetNeedsSupports(); + } + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + sceneryElement->SetGhost(true); + } + + map_invalidate_tile_full(_loc); + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_ANIMATED)) + { + map_animation_create(MAP_ANIMATION_TYPE_SMALL_SCENERY, CoordsXYZ{ _loc, sceneryElement->GetBaseZ() }); + } + + return res; +} diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.h b/src/openrct2/actions/SmallSceneryPlaceAction.h new file mode 100644 index 0000000000..17c14d3cbd --- /dev/null +++ b/src/openrct2/actions/SmallSceneryPlaceAction.h @@ -0,0 +1,75 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/TileElement.h" +#include "GameAction.h" + +class SmallSceneryPlaceActionResult final : public GameActions::Result +{ +public: + SmallSceneryPlaceActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_CANT_POSITION_THIS_HERE) + { + } + SmallSceneryPlaceActionResult(GameActions::Status error) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE) + { + } + SmallSceneryPlaceActionResult(GameActions::Status error, rct_string_id message) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message) + { + } + SmallSceneryPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message, args) + { + } + + uint8_t GroundFlags{ 0 }; + TileElement* tileElement = nullptr; +}; + +DEFINE_GAME_ACTION(SmallSceneryPlaceAction, GAME_COMMAND_PLACE_SCENERY, SmallSceneryPlaceActionResult) +{ +private: + CoordsXYZD _loc; + uint8_t _quadrant{}; + ObjectEntryIndex _sceneryType{}; + uint8_t _primaryColour{}; + uint8_t _secondaryColour{}; + +public: + SmallSceneryPlaceAction() = default; + + SmallSceneryPlaceAction( + const CoordsXYZD& loc, uint8_t quadrant, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) + : _loc(loc) + , _quadrant(quadrant) + , _sceneryType(sceneryType) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + uint32_t GetCooldownTime() const override + { + return 20; + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.hpp b/src/openrct2/actions/SmallSceneryPlaceAction.hpp deleted file mode 100644 index b487e6726d..0000000000 --- a/src/openrct2/actions/SmallSceneryPlaceAction.hpp +++ /dev/null @@ -1,480 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../ride/TrackDesign.h" -#include "../world/MapAnimation.h" -#include "../world/Park.h" -#include "../world/SmallScenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "../world/TileElement.h" -#include "GameAction.h" - -class SmallSceneryPlaceActionResult final : public GameActions::Result -{ -public: - SmallSceneryPlaceActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_CANT_POSITION_THIS_HERE) - { - } - SmallSceneryPlaceActionResult(GameActions::Status error) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE) - { - } - SmallSceneryPlaceActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message) - { - } - SmallSceneryPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message, args) - { - } - - uint8_t GroundFlags{ 0 }; - TileElement* tileElement = nullptr; -}; - -DEFINE_GAME_ACTION(SmallSceneryPlaceAction, GAME_COMMAND_PLACE_SCENERY, SmallSceneryPlaceActionResult) -{ -private: - CoordsXYZD _loc; - uint8_t _quadrant{}; - ObjectEntryIndex _sceneryType{}; - uint8_t _primaryColour{}; - uint8_t _secondaryColour{}; - -public: - SmallSceneryPlaceAction() = default; - - SmallSceneryPlaceAction( - const CoordsXYZD& loc, uint8_t quadrant, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) - : _loc(loc) - , _quadrant(quadrant) - , _sceneryType(sceneryType) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("quadrant", _quadrant); - visitor.Visit("object", _sceneryType); - visitor.Visit("primaryColour", _primaryColour); - visitor.Visit("secondaryColour", _secondaryColour); - } - - uint32_t GetCooldownTime() const override - { - return 20; - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) - << DS_TAG(_secondaryColour); - } - - GameActions::Result::Ptr Query() const override - { - bool isOnWater = false; - bool supportsRequired = false; - if (_loc.z != 0) - { - supportsRequired = true; - } - int32_t landHeight = tile_element_height(_loc); - int16_t waterHeight = tile_element_water_height(_loc); - - int32_t surfaceHeight = landHeight; - // If on water - if (waterHeight > 0) - { - surfaceHeight = waterHeight; - } - auto res = std::make_unique(); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = surfaceHeight; - if (_loc.z != 0) - { - surfaceHeight = _loc.z; - res->Position.z = surfaceHeight; - } - - if (!map_check_free_elements_and_reorganise(1)) - { - return std::make_unique(GameActions::Status::NoFreeElements); - } - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters); - } - - if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY)) - { - return std::make_unique(GameActions::Status::InvalidParameters); - } - - rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType); - if (sceneryEntry == nullptr) - { - return std::make_unique(GameActions::Status::InvalidParameters); - } - - auto quadrant = _quadrant; - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE) - || !scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL)) - { - if (scenery_small_entry_has_flag( - sceneryEntry, - SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS)) - { - quadrant = 0; - } - } - - // Check if sub tile height is any different compared to actual surface tile height - auto loc2 = _loc; - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) - { - loc2 = loc2.ToTileCentre(); - } - else - { - loc2.x += SceneryQuadrantOffsets[quadrant & 3].x - 1; - loc2.y += SceneryQuadrantOffsets[quadrant & 3].y - 1; - } - landHeight = tile_element_height(loc2); - waterHeight = tile_element_water_height(loc2); - - surfaceHeight = landHeight; - // If on water - if (waterHeight > 0) - { - // base_height2 is now the water height - surfaceHeight = waterHeight; - if (_loc.z == 0) - { - isOnWater = true; - } - } - auto targetHeight = _loc.z; - if (_loc.z == 0) - { - targetHeight = surfaceHeight; - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode - && !map_is_location_owned({ _loc.x, _loc.y, targetHeight })) - { - return std::make_unique(GameActions::Status::NotOwned, STR_LAND_NOT_OWNED_BY_PARK); - } - - auto* surfaceElement = map_get_surface_element_at(_loc); - - if (surfaceElement != nullptr && !gCheatsDisableClearanceChecks && surfaceElement->GetWaterHeight() > 0) - { - int32_t water_height = surfaceElement->GetWaterHeight() - 1; - if (water_height > targetHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); - } - } - - if (!gCheatsDisableClearanceChecks && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE))) - { - if (isOnWater) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); - } - - if (surfaceElement != nullptr && surfaceElement->GetWaterHeight() > 0) - { - if (surfaceElement->GetWaterHeight() > targetHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); - } - } - } - - if (!gCheatsDisableClearanceChecks - && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE)) && !supportsRequired - && !isOnWater && surfaceElement != nullptr && (surfaceElement->GetSlope() != TILE_ELEMENT_SLOPE_FLAT)) - { - return std::make_unique(GameActions::Status::Disallowed, STR_LEVEL_LAND_REQUIRED); - } - - if (!gCheatsDisableSupportLimits && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE)) - && supportsRequired) - { - if (!isOnWater) - { - if (surfaceElement != nullptr) - { - if (surfaceElement->GetWaterHeight() > 0 || (surfaceElement->GetBaseZ()) != targetHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_LEVEL_LAND_REQUIRED); - } - } - } - else - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); - } - } - - int32_t zLow = targetHeight; - int32_t zHigh = zLow + ceil2(sceneryEntry->small_scenery.height, COORDS_Z_STEP); - uint8_t collisionQuadrants = 0b1111; - auto quadRotation{ 0 }; - if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))) - { - quadRotation = (quadrant ^ 2); - collisionQuadrants = 0b0001; - } - if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE))) - { - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL) - && scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) - { - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) - { - quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; - collisionQuadrants = 0b1011; - } - else - { - quadRotation = (quadrant + _loc.direction) & 1; - collisionQuadrants = 0b1010; - } - } - } - else - { - quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; - collisionQuadrants = 0b0011; - } - uint8_t supports = 0; - if (!supportsRequired) - { - supports = 0b1111; - } - - QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); - money32 clearCost = 0; - - if (!map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &clearCost, - CREATE_CROSSING_MODE_NONE)) - { - return std::make_unique( - GameActions::Status::Disallowed, gGameCommandErrorText, gCommonFormatArgs); - } - - res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - - res->Expenditure = ExpenditureType::Landscaping; - res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost; - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - bool supportsRequired = false; - if (_loc.z != 0) - { - supportsRequired = true; - } - int32_t landHeight = tile_element_height(_loc); - int16_t waterHeight = tile_element_water_height(_loc); - - int32_t surfaceHeight = landHeight; - // If on water - if (waterHeight > 0) - { - surfaceHeight = waterHeight; - } - auto res = std::make_unique(); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = surfaceHeight; - if (_loc.z != 0) - { - surfaceHeight = _loc.z; - res->Position.z = surfaceHeight; - } - - rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType); - if (sceneryEntry == nullptr) - { - return std::make_unique(GameActions::Status::InvalidParameters); - } - - auto quadrant = _quadrant; - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE) - || !scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL)) - { - if (scenery_small_entry_has_flag( - sceneryEntry, - SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS)) - { - quadrant = 0; - } - } - - // Check if sub tile height is any different compared to actual surface tile height - int32_t x2 = _loc.x; - int32_t y2 = _loc.y; - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) - { - x2 += 16; - y2 += 16; - } - else - { - x2 += SceneryQuadrantOffsets[quadrant & 3].x - 1; - y2 += SceneryQuadrantOffsets[quadrant & 3].y - 1; - } - landHeight = tile_element_height({ x2, y2 }); - waterHeight = tile_element_water_height({ x2, y2 }); - - surfaceHeight = landHeight; - // If on water - if (waterHeight > 0) - { - // base_height2 is now the water height - surfaceHeight = waterHeight; - } - auto targetHeight = _loc.z; - if (_loc.z == 0) - { - targetHeight = surfaceHeight; - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter({ _loc, targetHeight }); - if (!gCheatsDisableClearanceChecks && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_NO_WALLS))) - { - wall_remove_at({ _loc, targetHeight, targetHeight + sceneryEntry->small_scenery.height }); - } - } - - int32_t zLow = targetHeight; - int32_t zHigh = zLow + ceil2(sceneryEntry->small_scenery.height, 8); - uint8_t collisionQuadrants = 0b1111; - auto quadRotation{ 0 }; - if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))) - { - quadRotation = (quadrant ^ 2); - collisionQuadrants = 0b0001; - } - if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE))) - { - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL) - && scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) - { - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) - { - quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; - collisionQuadrants = 0b1011; - } - else - { - quadRotation = (quadrant + _loc.direction) & 1; - collisionQuadrants = 0b1010; - } - } - } - else - { - quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; - collisionQuadrants = 0b0011; - } - uint8_t supports = 0; - if (!supportsRequired) - { - supports = 0b1111; - } - - QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); - money32 clearCost = 0; - - if (!map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags() | GAME_COMMAND_FLAG_APPLY, - &clearCost, CREATE_CROSSING_MODE_NONE)) - { - return std::make_unique( - GameActions::Status::Disallowed, gGameCommandErrorText, gCommonFormatArgs); - } - - res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - - res->Expenditure = ExpenditureType::Landscaping; - res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost; - - TileElement* newElement = tile_element_insert(CoordsXYZ{ _loc, zLow }, quarterTile.GetBaseQuarterOccupied()); - assert(newElement != nullptr); - res->tileElement = newElement; - newElement->SetType(TILE_ELEMENT_TYPE_SMALL_SCENERY); - newElement->SetDirection(_loc.direction); - SmallSceneryElement* sceneryElement = newElement->AsSmallScenery(); - sceneryElement->SetSceneryQuadrant(quadrant); - sceneryElement->SetEntryIndex(_sceneryType); - sceneryElement->SetAge(0); - sceneryElement->SetPrimaryColour(_primaryColour); - sceneryElement->SetSecondaryColour(_secondaryColour); - sceneryElement->SetClearanceZ(sceneryElement->GetBaseZ() + sceneryEntry->small_scenery.height + 7); - - if (supportsRequired) - { - sceneryElement->SetNeedsSupports(); - } - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - sceneryElement->SetGhost(true); - } - - map_invalidate_tile_full(_loc); - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_ANIMATED)) - { - map_animation_create(MAP_ANIMATION_TYPE_SMALL_SCENERY, CoordsXYZ{ _loc, sceneryElement->GetBaseZ() }); - } - - return res; - } -}; diff --git a/src/openrct2/actions/SmallSceneryRemoveAction.cpp b/src/openrct2/actions/SmallSceneryRemoveAction.cpp new file mode 100644 index 0000000000..0da6b1c68f --- /dev/null +++ b/src/openrct2/actions/SmallSceneryRemoveAction.cpp @@ -0,0 +1,145 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "SmallSceneryRemoveAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../world/Park.h" +#include "../world/SmallScenery.h" +#include "../world/Sprite.h" +#include "GameAction.h" +#include "SmallSceneryPlaceAction.h" + +void SmallSceneryRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _sceneryType); + visitor.Visit("quadrant", _quadrant); +} + +void SmallSceneryRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType); +} + +GameActions::Result::Ptr SmallSceneryRemoveAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + rct_scenery_entry* entry = get_small_scenery_entry(_sceneryType); + if (entry == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + res->Cost = entry->small_scenery.removal_price * 10; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsSandboxMode) + { + // Check if allowed to remove item + if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) + { + if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_IS_TREE)) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorTitle = STR_CANT_REMOVE_THIS; + res->ErrorMessage = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY; + return res; + } + } + + // Check if the land is owned + if (!map_is_location_owned(_loc)) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorTitle = STR_CANT_REMOVE_THIS; + res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; + return res; + } + } + + TileElement* tileElement = FindSceneryElement(); + if (tileElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + return res; +} + +GameActions::Result::Ptr SmallSceneryRemoveAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + rct_scenery_entry* entry = get_small_scenery_entry(_sceneryType); + if (entry == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); + } + + res->Cost = entry->small_scenery.removal_price * 10; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc; + + TileElement* tileElement = FindSceneryElement(); + if (tileElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + res->Position.z = tile_element_height(res->Position); + + map_invalidate_tile_full(_loc); + tile_element_remove(tileElement); + + return res; +} + +TileElement* SmallSceneryRemoveAction::FindSceneryElement() const +{ + TileElement* tileElement = map_get_first_element_at(_loc); + if (!tileElement) + return nullptr; + + do + { + if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) + continue; + if ((tileElement->AsSmallScenery()->GetSceneryQuadrant()) != _quadrant) + continue; + if (tileElement->GetBaseZ() != _loc.z) + continue; + if (tileElement->AsSmallScenery()->GetEntryIndex() != _sceneryType) + continue; + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && tileElement->IsGhost() == false) + continue; + + return tileElement; + + } while (!(tileElement++)->IsLastForTile()); + + return nullptr; +} diff --git a/src/openrct2/actions/SmallSceneryRemoveAction.h b/src/openrct2/actions/SmallSceneryRemoveAction.h new file mode 100644 index 0000000000..c9e59ca40c --- /dev/null +++ b/src/openrct2/actions/SmallSceneryRemoveAction.h @@ -0,0 +1,45 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/TileElement.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(SmallSceneryRemoveAction, GAME_COMMAND_REMOVE_SCENERY, GameActions::Result) +{ +private: + CoordsXYZ _loc; + uint8_t _quadrant{}; + ObjectEntryIndex _sceneryType{}; + +public: + SmallSceneryRemoveAction() = default; + + SmallSceneryRemoveAction(const CoordsXYZ& location, uint8_t quadrant, ObjectEntryIndex sceneryType) + : _loc(location) + , _quadrant(quadrant) + , _sceneryType(sceneryType) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + TileElement* FindSceneryElement() const; +}; diff --git a/src/openrct2/actions/SmallSceneryRemoveAction.hpp b/src/openrct2/actions/SmallSceneryRemoveAction.hpp deleted file mode 100644 index f3e05d44c6..0000000000 --- a/src/openrct2/actions/SmallSceneryRemoveAction.hpp +++ /dev/null @@ -1,168 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../world/Park.h" -#include "../world/SmallScenery.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(SmallSceneryRemoveAction, GAME_COMMAND_REMOVE_SCENERY, GameActions::Result) -{ -private: - CoordsXYZ _loc; - uint8_t _quadrant{}; - ObjectEntryIndex _sceneryType{}; - -public: - SmallSceneryRemoveAction() = default; - - SmallSceneryRemoveAction(const CoordsXYZ& location, uint8_t quadrant, ObjectEntryIndex sceneryType) - : _loc(location) - , _quadrant(quadrant) - , _sceneryType(sceneryType) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _sceneryType); - visitor.Visit("quadrant", _quadrant); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - rct_scenery_entry* entry = get_small_scenery_entry(_sceneryType); - if (entry == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - res->Cost = entry->small_scenery.removal_price * 10; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsSandboxMode) - { - // Check if allowed to remove item - if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) - { - if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_IS_TREE)) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorTitle = STR_CANT_REMOVE_THIS; - res->ErrorMessage = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY; - return res; - } - } - - // Check if the land is owned - if (!map_is_location_owned(_loc)) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorTitle = STR_CANT_REMOVE_THIS; - res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; - return res; - } - } - - TileElement* tileElement = FindSceneryElement(); - if (tileElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - rct_scenery_entry* entry = get_small_scenery_entry(_sceneryType); - if (entry == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); - } - - res->Cost = entry->small_scenery.removal_price * 10; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc; - - TileElement* tileElement = FindSceneryElement(); - if (tileElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - res->Position.z = tile_element_height(res->Position); - - map_invalidate_tile_full(_loc); - tile_element_remove(tileElement); - - return res; - } - -private: - TileElement* FindSceneryElement() const - { - TileElement* tileElement = map_get_first_element_at(_loc); - if (!tileElement) - return nullptr; - - do - { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - continue; - if ((tileElement->AsSmallScenery()->GetSceneryQuadrant()) != _quadrant) - continue; - if (tileElement->GetBaseZ() != _loc.z) - continue; - if (tileElement->AsSmallScenery()->GetEntryIndex() != _sceneryType) - continue; - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && tileElement->IsGhost() == false) - continue; - - return tileElement; - - } while (!(tileElement++)->IsLastForTile()); - - return nullptr; - } -}; diff --git a/src/openrct2/actions/SmallScenerySetColourAction.cpp b/src/openrct2/actions/SmallScenerySetColourAction.cpp new file mode 100644 index 0000000000..54bf93496b --- /dev/null +++ b/src/openrct2/actions/SmallScenerySetColourAction.cpp @@ -0,0 +1,90 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "SmallScenerySetColourAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../ride/TrackDesign.h" +#include "../world/MapAnimation.h" +#include "../world/Park.h" +#include "../world/SmallScenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" +#include "../world/TileElement.h" + +void SmallScenerySetColourAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour); +} + +GameActions::Result::Ptr SmallScenerySetColourAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr SmallScenerySetColourAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr SmallScenerySetColourAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->ErrorTitle = STR_CANT_REPAINT_THIS; + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_owned(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + auto sceneryElement = map_get_small_scenery_element_at(_loc, _sceneryType, _quadrant); + + if (sceneryElement == nullptr) + { + log_error("Small scenery not found at: x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(sceneryElement->IsGhost())) + { + return res; + } + + if (isExecuting) + { + sceneryElement->SetPrimaryColour(_primaryColour); + sceneryElement->SetSecondaryColour(_secondaryColour); + + map_invalidate_tile_full(_loc); + } + + return res; +} diff --git a/src/openrct2/actions/SmallScenerySetColourAction.h b/src/openrct2/actions/SmallScenerySetColourAction.h new file mode 100644 index 0000000000..089d5815de --- /dev/null +++ b/src/openrct2/actions/SmallScenerySetColourAction.h @@ -0,0 +1,47 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(SmallScenerySetColourAction, GAME_COMMAND_SET_SCENERY_COLOUR, GameActions::Result) +{ +private: + CoordsXYZ _loc; + uint8_t _quadrant{}; + ObjectEntryIndex _sceneryType{}; + uint8_t _primaryColour{}; + uint8_t _secondaryColour{}; + +public: + SmallScenerySetColourAction() = default; + + SmallScenerySetColourAction( + const CoordsXYZ& loc, uint8_t quadrant, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) + : _loc(loc) + , _quadrant(quadrant) + , _sceneryType(sceneryType) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/SmallScenerySetColourAction.hpp b/src/openrct2/actions/SmallScenerySetColourAction.hpp deleted file mode 100644 index 73ece75cc7..0000000000 --- a/src/openrct2/actions/SmallScenerySetColourAction.hpp +++ /dev/null @@ -1,121 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../ride/TrackDesign.h" -#include "../world/MapAnimation.h" -#include "../world/Park.h" -#include "../world/SmallScenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "../world/TileElement.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(SmallScenerySetColourAction, GAME_COMMAND_SET_SCENERY_COLOUR, GameActions::Result) -{ -private: - CoordsXYZ _loc; - uint8_t _quadrant{}; - ObjectEntryIndex _sceneryType{}; - uint8_t _primaryColour{}; - uint8_t _secondaryColour{}; - -public: - SmallScenerySetColourAction() = default; - - SmallScenerySetColourAction( - const CoordsXYZ& loc, uint8_t quadrant, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) - : _loc(loc) - , _quadrant(quadrant) - , _sceneryType(sceneryType) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) - << DS_TAG(_secondaryColour); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - res->ErrorTitle = STR_CANT_REPAINT_THIS; - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_owned(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - auto sceneryElement = map_get_small_scenery_element_at(_loc, _sceneryType, _quadrant); - - if (sceneryElement == nullptr) - { - log_error("Small scenery not found at: x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(sceneryElement->IsGhost())) - { - return res; - } - - if (isExecuting) - { - sceneryElement->SetPrimaryColour(_primaryColour); - sceneryElement->SetSecondaryColour(_secondaryColour); - - map_invalidate_tile_full(_loc); - } - - return res; - } -}; diff --git a/src/openrct2/actions/StaffFireAction.cpp b/src/openrct2/actions/StaffFireAction.cpp new file mode 100644 index 0000000000..ed96e8bd7a --- /dev/null +++ b/src/openrct2/actions/StaffFireAction.cpp @@ -0,0 +1,50 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "StaffFireAction.h" + +#include "../interface/Window.h" +#include "../peep/Peep.h" + +void StaffFireAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_spriteId); +} + +GameActions::Result::Ptr StaffFireAction::Query() const +{ + if (_spriteId >= MAX_SPRITES) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto staff = TryGetEntity(_spriteId); + if (staff == nullptr) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr StaffFireAction::Execute() const +{ + auto staff = TryGetEntity(_spriteId); + if (staff == nullptr) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + window_close_by_class(WC_FIRE_PROMPT); + peep_sprite_remove(staff); + return MakeResult(); +} diff --git a/src/openrct2/actions/StaffFireAction.h b/src/openrct2/actions/StaffFireAction.h new file mode 100644 index 0000000000..ca3938c738 --- /dev/null +++ b/src/openrct2/actions/StaffFireAction.h @@ -0,0 +1,35 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(StaffFireAction, GAME_COMMAND_FIRE_STAFF_MEMBER, GameActions::Result) +{ +private: + uint16_t _spriteId{ SPRITE_INDEX_NULL }; + +public: + StaffFireAction() = default; + StaffFireAction(uint16_t spriteId) + : _spriteId(spriteId) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffFireAction.hpp b/src/openrct2/actions/StaffFireAction.hpp deleted file mode 100644 index ee29a6d6f5..0000000000 --- a/src/openrct2/actions/StaffFireAction.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../interface/Window.h" -#include "../peep/Peep.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(StaffFireAction, GAME_COMMAND_FIRE_STAFF_MEMBER, GameActions::Result) -{ -private: - uint16_t _spriteId{ SPRITE_INDEX_NULL }; - -public: - StaffFireAction() = default; - StaffFireAction(uint16_t spriteId) - : _spriteId(spriteId) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_spriteId); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteId >= MAX_SPRITES) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto staff = TryGetEntity(_spriteId); - if (staff == nullptr) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto staff = TryGetEntity(_spriteId); - if (staff == nullptr) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - window_close_by_class(WC_FIRE_PROMPT); - peep_sprite_remove(staff); - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/StaffHireNewAction.cpp b/src/openrct2/actions/StaffHireNewAction.cpp new file mode 100644 index 0000000000..99b9b9b8c4 --- /dev/null +++ b/src/openrct2/actions/StaffHireNewAction.cpp @@ -0,0 +1,305 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "StaffHireNewAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../peep/Staff.h" +#include "../ride/Ride.h" +#include "../scenario/Scenario.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Entrance.h" +#include "../world/Park.h" +#include "../world/Sprite.h" + +void StaffHireNewAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("autoPosition", _autoPosition); + visitor.Visit("staffType", _staffType); + visitor.Visit("entertainerType", _entertainerType); + visitor.Visit("staffOrders", _staffOrders); +} + +void StaffHireNewAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_autoPosition) << DS_TAG(_staffType) << DS_TAG(_entertainerType) << DS_TAG(_staffOrders); +} + +GameActions::Result::Ptr StaffHireNewAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr StaffHireNewAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr StaffHireNewAction::QueryExecute(bool execute) const +{ + auto res = std::make_unique(); + + res->Expenditure = ExpenditureType::Wages; + + if (_staffType >= static_cast(StaffType::Count)) + { + // Invalid staff type. + log_error("Tried to use invalid staff type: %u", static_cast(_staffType)); + + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (GetEntityListCount(EntityListId::Free) < 400) + { + return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_PEOPLE_IN_GAME); + } + + if (_staffType == static_cast(StaffType::Entertainer)) + { + if (static_cast(_entertainerType) >= static_cast(EntertainerCostume::Count)) + { + // Invalid entertainer costume + log_error("Tried to use invalid entertainer type: %u", static_cast(_entertainerType)); + + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + uint32_t availableCostumes = staff_get_available_entertainer_costumes(); + if (!(availableCostumes & (1 << static_cast(_entertainerType)))) + { + // Entertainer costume unavailable + log_error("Tried to use unavailable entertainer type: %u", static_cast(_entertainerType)); + + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + } + + // Look for a free slot in the staff modes. + int32_t staffIndex; + for (staffIndex = 0; staffIndex < STAFF_MAX_COUNT; ++staffIndex) + { + if (gStaffModes[staffIndex] == StaffMode::None) + break; + } + + if (staffIndex == STAFF_MAX_COUNT) + { + // Too many staff members exist already. + return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_STAFF_IN_GAME); + } + + Peep* newPeep = &(create_sprite(SpriteIdentifier::Peep)->peep); + if (newPeep == nullptr) + { + // Too many peeps exist already. + return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_PEOPLE_IN_GAME); + } + + if (execute == false) + { + // In query we just want to see if we can obtain a sprite slot. + sprite_remove(newPeep); + } + else + { + newPeep->sprite_identifier = SpriteIdentifier::Peep; + newPeep->WindowInvalidateFlags = 0; + newPeep->Action = PeepActionType::None2; + newPeep->SpecialSprite = 0; + newPeep->ActionSpriteImageOffset = 0; + newPeep->WalkingFrameNum = 0; + newPeep->ActionSpriteType = PeepActionSpriteType::None; + newPeep->PathCheckOptimisation = 0; + newPeep->AssignedPeepType = PeepType::Staff; + newPeep->OutsideOfPark = false; + newPeep->PeepFlags = 0; + newPeep->PaidToEnter = 0; + newPeep->PaidOnRides = 0; + newPeep->PaidOnFood = 0; + newPeep->PaidOnSouvenirs = 0; + newPeep->FavouriteRide = RIDE_ID_NULL; + newPeep->StaffOrders = _staffOrders; + + // We search for the first available Id for a given staff type + uint32_t newStaffId = 0; + for (;;) + { + bool found = false; + ++newStaffId; + for (auto searchPeep : EntityList(EntityListId::Peep)) + { + if (static_cast(searchPeep->AssignedStaffType) != _staffType) + continue; + + if (searchPeep->Id == newStaffId) + { + found = true; + break; + } + } + + if (!found) + break; + } + + newPeep->Id = newStaffId; + newPeep->AssignedStaffType = static_cast(_staffType); + + PeepSpriteType spriteType = spriteTypes[_staffType]; + if (_staffType == static_cast(StaffType::Entertainer)) + { + spriteType = EntertainerCostumeToSprite(_entertainerType); + } + newPeep->Name = nullptr; + newPeep->SpriteType = spriteType; + + const rct_sprite_bounds* spriteBounds = &GetSpriteBounds(spriteType); + newPeep->sprite_width = spriteBounds->sprite_width; + newPeep->sprite_height_negative = spriteBounds->sprite_height_negative; + newPeep->sprite_height_positive = spriteBounds->sprite_height_positive; + + if (_autoPosition) + { + AutoPositionNewStaff(newPeep); + } + else + { + // NOTE: This state is required for the window to act. + newPeep->State = PeepState::Picked; + + newPeep->MoveTo({ newPeep->x, newPeep->y, newPeep->z }); + } + + // Staff uses this + newPeep->AsStaff()->SetHireDate(gDateMonthsElapsed); + newPeep->PathfindGoal.x = 0xFF; + newPeep->PathfindGoal.y = 0xFF; + newPeep->PathfindGoal.z = 0xFF; + newPeep->PathfindGoal.direction = INVALID_DIRECTION; + + uint8_t colour = staff_get_colour(static_cast(_staffType)); + newPeep->TshirtColour = colour; + newPeep->TrousersColour = colour; + + // Staff energy determines their walking speed + newPeep->Energy = 0x60; + newPeep->EnergyTarget = 0x60; + newPeep->StaffMowingTimeout = 0; + + newPeep->StaffId = staffIndex; + + gStaffModes[staffIndex] = StaffMode::Walk; + + for (int32_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++) + { + gStaffPatrolAreas[staffIndex * STAFF_PATROL_AREA_SIZE + i] = 0; + } + + res->peepSriteIndex = newPeep->sprite_index; + } + + return res; +} + +void StaffHireNewAction::AutoPositionNewStaff(Peep* newPeep) const +{ + // Find a location to place new staff member + newPeep->State = PeepState::Falling; + + uint32_t count = 0; + PathElement* guest_tile = nullptr; + + // Count number of walking guests + { + for (auto guest : EntityList(EntityListId::Peep)) + { + if (guest->State == PeepState::Walking) + { + // Check the walking guest's tile. Only count them if they're on a path tile. + guest_tile = map_get_path_element_at(TileCoordsXYZ{ guest->NextLoc }); + if (guest_tile != nullptr) + ++count; + } + } + } + + CoordsXYZ newLocation{}; + if (count > 0) + { + // Place staff at a random guest + uint32_t rand = scenario_rand_max(count); + Guest* chosenGuest = nullptr; + + for (auto guest : EntityList(EntityListId::Peep)) + { + if (guest->State == PeepState::Walking) + { + guest_tile = map_get_path_element_at(TileCoordsXYZ{ guest->NextLoc }); + if (guest_tile != nullptr) + { + if (rand == 0) + { + chosenGuest = guest; + break; + } + --rand; + } + } + } + + if (chosenGuest != nullptr) + { + newLocation.x = chosenGuest->x; + newLocation.y = chosenGuest->y; + newLocation.z = chosenGuest->z; + } + else + { + // User must pick a location + newPeep->State = PeepState::Picked; + newLocation.x = newPeep->x; + newLocation.y = newPeep->y; + newLocation.z = newPeep->z; + } + } + else + { + // No walking guests; pick random park entrance + if (!gParkEntrances.empty()) + { + auto rand = scenario_rand_max(static_cast(gParkEntrances.size())); + const auto& entrance = gParkEntrances[rand]; + auto dir = entrance.direction; + newLocation = entrance; + // TODO: Replace with CoordsDirectionDelta + newLocation.x += 16 + ((dir & 1) == 0 ? ((dir & 2) ? 32 : -32) : 0); + newLocation.y += 16 + ((dir & 1) == 1 ? ((dir & 2) ? -32 : 32) : 0); + } + else + { + // User must pick a location + newPeep->State = PeepState::Picked; + newLocation.x = newPeep->x; + newLocation.y = newPeep->y; + newLocation.z = newPeep->z; + } + } + + newPeep->MoveTo(newLocation + CoordsXYZ{ 0, 0, 16 }); +} diff --git a/src/openrct2/actions/StaffHireNewAction.h b/src/openrct2/actions/StaffHireNewAction.h new file mode 100644 index 0000000000..cf401eec49 --- /dev/null +++ b/src/openrct2/actions/StaffHireNewAction.h @@ -0,0 +1,71 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../peep/Staff.h" +#include "../world/Sprite.h" +#include "GameAction.h" + +/* rct2: 0x009929FC */ +static constexpr const PeepSpriteType spriteTypes[] = { + PeepSpriteType::Handyman, + PeepSpriteType::Mechanic, + PeepSpriteType::Security, + PeepSpriteType::EntertainerPanda, +}; + +class StaffHireNewActionResult final : public GameActions::Result +{ +public: + StaffHireNewActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_CANT_HIRE_NEW_STAFF) + { + } + StaffHireNewActionResult(GameActions::Status error, rct_string_id message) + : GameActions::Result(error, STR_CANT_HIRE_NEW_STAFF, message) + { + } + + uint32_t peepSriteIndex = SPRITE_INDEX_NULL; +}; + +DEFINE_GAME_ACTION(StaffHireNewAction, GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, StaffHireNewActionResult) +{ +private: + bool _autoPosition{}; + uint8_t _staffType{ EnumValue(StaffType::Count) }; + EntertainerCostume _entertainerType{ EntertainerCostume::Count }; + uint32_t _staffOrders{}; + +public: + StaffHireNewAction() = default; + StaffHireNewAction(bool autoPosition, StaffType staffType, EntertainerCostume entertainerType, uint32_t staffOrders) + : _autoPosition(autoPosition) + , _staffType(static_cast(staffType)) + , _entertainerType(entertainerType) + , _staffOrders(staffOrders) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool execute) const; + void AutoPositionNewStaff(Peep * newPeep) const; +}; diff --git a/src/openrct2/actions/StaffHireNewAction.hpp b/src/openrct2/actions/StaffHireNewAction.hpp deleted file mode 100644 index fc119002eb..0000000000 --- a/src/openrct2/actions/StaffHireNewAction.hpp +++ /dev/null @@ -1,354 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../peep/Staff.h" -#include "../ride/Ride.h" -#include "../scenario/Scenario.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../world/Entrance.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -/* rct2: 0x009929FC */ -static constexpr const PeepSpriteType spriteTypes[] = { - PeepSpriteType::Handyman, - PeepSpriteType::Mechanic, - PeepSpriteType::Security, - PeepSpriteType::EntertainerPanda, -}; - -class StaffHireNewActionResult final : public GameActions::Result -{ -public: - StaffHireNewActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_CANT_HIRE_NEW_STAFF) - { - } - StaffHireNewActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_CANT_HIRE_NEW_STAFF, message) - { - } - - uint32_t peepSriteIndex = SPRITE_INDEX_NULL; -}; - -DEFINE_GAME_ACTION(StaffHireNewAction, GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, StaffHireNewActionResult) -{ -private: - bool _autoPosition{}; - uint8_t _staffType{ EnumValue(StaffType::Count) }; - EntertainerCostume _entertainerType{ EntertainerCostume::Count }; - uint32_t _staffOrders{}; - -public: - StaffHireNewAction() = default; - StaffHireNewAction(bool autoPosition, StaffType staffType, EntertainerCostume entertainerType, uint32_t staffOrders) - : _autoPosition(autoPosition) - , _staffType(static_cast(staffType)) - , _entertainerType(entertainerType) - , _staffOrders(staffOrders) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("autoPosition", _autoPosition); - visitor.Visit("staffType", _staffType); - visitor.Visit("entertainerType", _entertainerType); - visitor.Visit("staffOrders", _staffOrders); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_autoPosition) << DS_TAG(_staffType) << DS_TAG(_entertainerType) << DS_TAG(_staffOrders); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool execute) const - { - auto res = std::make_unique(); - - res->Expenditure = ExpenditureType::Wages; - - if (_staffType >= static_cast(StaffType::Count)) - { - // Invalid staff type. - log_error("Tried to use invalid staff type: %u", static_cast(_staffType)); - - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (GetEntityListCount(EntityListId::Free) < 400) - { - return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_PEOPLE_IN_GAME); - } - - if (_staffType == static_cast(StaffType::Entertainer)) - { - if (static_cast(_entertainerType) >= static_cast(EntertainerCostume::Count)) - { - // Invalid entertainer costume - log_error("Tried to use invalid entertainer type: %u", static_cast(_entertainerType)); - - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - uint32_t availableCostumes = staff_get_available_entertainer_costumes(); - if (!(availableCostumes & (1 << static_cast(_entertainerType)))) - { - // Entertainer costume unavailable - log_error("Tried to use unavailable entertainer type: %u", static_cast(_entertainerType)); - - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - } - - // Look for a free slot in the staff modes. - int32_t staffIndex; - for (staffIndex = 0; staffIndex < STAFF_MAX_COUNT; ++staffIndex) - { - if (gStaffModes[staffIndex] == StaffMode::None) - break; - } - - if (staffIndex == STAFF_MAX_COUNT) - { - // Too many staff members exist already. - return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_STAFF_IN_GAME); - } - - Peep* newPeep = &(create_sprite(SpriteIdentifier::Peep)->peep); - if (newPeep == nullptr) - { - // Too many peeps exist already. - return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_PEOPLE_IN_GAME); - } - - if (execute == false) - { - // In query we just want to see if we can obtain a sprite slot. - sprite_remove(newPeep); - } - else - { - newPeep->sprite_identifier = SpriteIdentifier::Peep; - newPeep->WindowInvalidateFlags = 0; - newPeep->Action = PeepActionType::None2; - newPeep->SpecialSprite = 0; - newPeep->ActionSpriteImageOffset = 0; - newPeep->WalkingFrameNum = 0; - newPeep->ActionSpriteType = PeepActionSpriteType::None; - newPeep->PathCheckOptimisation = 0; - newPeep->AssignedPeepType = PeepType::Staff; - newPeep->OutsideOfPark = false; - newPeep->PeepFlags = 0; - newPeep->PaidToEnter = 0; - newPeep->PaidOnRides = 0; - newPeep->PaidOnFood = 0; - newPeep->PaidOnSouvenirs = 0; - newPeep->FavouriteRide = RIDE_ID_NULL; - newPeep->StaffOrders = _staffOrders; - - // We search for the first available Id for a given staff type - uint32_t newStaffId = 0; - for (;;) - { - bool found = false; - ++newStaffId; - for (auto searchPeep : EntityList(EntityListId::Peep)) - { - if (static_cast(searchPeep->AssignedStaffType) != _staffType) - continue; - - if (searchPeep->Id == newStaffId) - { - found = true; - break; - } - } - - if (!found) - break; - } - - newPeep->Id = newStaffId; - newPeep->AssignedStaffType = static_cast(_staffType); - - PeepSpriteType spriteType = spriteTypes[_staffType]; - if (_staffType == static_cast(StaffType::Entertainer)) - { - spriteType = EntertainerCostumeToSprite(_entertainerType); - } - newPeep->Name = nullptr; - newPeep->SpriteType = spriteType; - - const rct_sprite_bounds* spriteBounds = &GetSpriteBounds(spriteType); - newPeep->sprite_width = spriteBounds->sprite_width; - newPeep->sprite_height_negative = spriteBounds->sprite_height_negative; - newPeep->sprite_height_positive = spriteBounds->sprite_height_positive; - - if (_autoPosition) - { - AutoPositionNewStaff(newPeep); - } - else - { - // NOTE: This state is required for the window to act. - newPeep->State = PeepState::Picked; - - newPeep->MoveTo({ newPeep->x, newPeep->y, newPeep->z }); - } - - // Staff uses this - newPeep->AsStaff()->SetHireDate(gDateMonthsElapsed); - newPeep->PathfindGoal.x = 0xFF; - newPeep->PathfindGoal.y = 0xFF; - newPeep->PathfindGoal.z = 0xFF; - newPeep->PathfindGoal.direction = INVALID_DIRECTION; - - uint8_t colour = staff_get_colour(static_cast(_staffType)); - newPeep->TshirtColour = colour; - newPeep->TrousersColour = colour; - - // Staff energy determines their walking speed - newPeep->Energy = 0x60; - newPeep->EnergyTarget = 0x60; - newPeep->StaffMowingTimeout = 0; - - newPeep->StaffId = staffIndex; - - gStaffModes[staffIndex] = StaffMode::Walk; - - for (int32_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++) - { - gStaffPatrolAreas[staffIndex * STAFF_PATROL_AREA_SIZE + i] = 0; - } - - res->peepSriteIndex = newPeep->sprite_index; - } - - return res; - } - - void AutoPositionNewStaff(Peep * newPeep) const - { - // Find a location to place new staff member - newPeep->State = PeepState::Falling; - - uint32_t count = 0; - PathElement* guest_tile = nullptr; - - // Count number of walking guests - { - for (auto guest : EntityList(EntityListId::Peep)) - { - if (guest->State == PeepState::Walking) - { - // Check the walking guest's tile. Only count them if they're on a path tile. - guest_tile = map_get_path_element_at(TileCoordsXYZ{ guest->NextLoc }); - if (guest_tile != nullptr) - ++count; - } - } - } - - CoordsXYZ newLocation{}; - if (count > 0) - { - // Place staff at a random guest - uint32_t rand = scenario_rand_max(count); - Guest* chosenGuest = nullptr; - - for (auto guest : EntityList(EntityListId::Peep)) - { - if (guest->State == PeepState::Walking) - { - guest_tile = map_get_path_element_at(TileCoordsXYZ{ guest->NextLoc }); - if (guest_tile != nullptr) - { - if (rand == 0) - { - chosenGuest = guest; - break; - } - --rand; - } - } - } - - if (chosenGuest != nullptr) - { - newLocation.x = chosenGuest->x; - newLocation.y = chosenGuest->y; - newLocation.z = chosenGuest->z; - } - else - { - // User must pick a location - newPeep->State = PeepState::Picked; - newLocation.x = newPeep->x; - newLocation.y = newPeep->y; - newLocation.z = newPeep->z; - } - } - else - { - // No walking guests; pick random park entrance - if (!gParkEntrances.empty()) - { - auto rand = scenario_rand_max(static_cast(gParkEntrances.size())); - const auto& entrance = gParkEntrances[rand]; - auto dir = entrance.direction; - newLocation = entrance; - // TODO: Replace with CoordsDirectionDelta - newLocation.x += 16 + ((dir & 1) == 0 ? ((dir & 2) ? 32 : -32) : 0); - newLocation.y += 16 + ((dir & 1) == 1 ? ((dir & 2) ? -32 : 32) : 0); - } - else - { - // User must pick a location - newPeep->State = PeepState::Picked; - newLocation.x = newPeep->x; - newLocation.y = newPeep->y; - newLocation.z = newPeep->z; - } - } - - newPeep->MoveTo(newLocation + CoordsXYZ{ 0, 0, 16 }); - } -}; diff --git a/src/openrct2/actions/StaffSetColourAction.cpp b/src/openrct2/actions/StaffSetColourAction.cpp new file mode 100644 index 0000000000..b806ee459c --- /dev/null +++ b/src/openrct2/actions/StaffSetColourAction.cpp @@ -0,0 +1,58 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "StaffSetColourAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../localisation/StringIds.h" +#include "../peep/Staff.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" +#include "../world/Sprite.h" + +void StaffSetColourAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_staffType) << DS_TAG(_colour); +} + +GameActions::Result::Ptr StaffSetColourAction::Query() const +{ + auto staffType = static_cast(_staffType); + if (staffType != StaffType::Handyman && staffType != StaffType::Mechanic && staffType != StaffType::Security) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return MakeResult(); +} + +GameActions::Result::Ptr StaffSetColourAction::Execute() const +{ + // Update global uniform colour property + if (!staff_set_colour(static_cast(_staffType), _colour)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + // Update each staff member's uniform + for (auto peep : EntityList(EntityListId::Peep)) + { + if (peep->AssignedStaffType == static_cast(_staffType)) + { + peep->TshirtColour = _colour; + peep->TrousersColour = _colour; + } + } + + gfx_invalidate_screen(); + return MakeResult(); +} diff --git a/src/openrct2/actions/StaffSetColourAction.h b/src/openrct2/actions/StaffSetColourAction.h new file mode 100644 index 0000000000..4da9ccb82a --- /dev/null +++ b/src/openrct2/actions/StaffSetColourAction.h @@ -0,0 +1,36 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(StaffSetColourAction, GAME_COMMAND_SET_STAFF_COLOUR, GameActions::Result) +{ +private: + uint8_t _staffType{}; + uint8_t _colour{}; + +public: + StaffSetColourAction() = default; + StaffSetColourAction(StaffType staffType, uint8_t colour) + : _staffType(static_cast(staffType)) + , _colour(colour) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffSetColourAction.hpp b/src/openrct2/actions/StaffSetColourAction.hpp deleted file mode 100644 index 18e050b38c..0000000000 --- a/src/openrct2/actions/StaffSetColourAction.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../localisation/StringIds.h" -#include "../peep/Staff.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(StaffSetColourAction, GAME_COMMAND_SET_STAFF_COLOUR, GameActions::Result) -{ -private: - uint8_t _staffType{}; - uint8_t _colour{}; - -public: - StaffSetColourAction() = default; - StaffSetColourAction(StaffType staffType, uint8_t colour) - : _staffType(static_cast(staffType)) - , _colour(colour) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_staffType) << DS_TAG(_colour); - } - - GameActions::Result::Ptr Query() const override - { - auto staffType = static_cast(_staffType); - if (staffType != StaffType::Handyman && staffType != StaffType::Mechanic && staffType != StaffType::Security) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - // Update global uniform colour property - if (!staff_set_colour(static_cast(_staffType), _colour)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - // Update each staff member's uniform - for (auto peep : EntityList(EntityListId::Peep)) - { - if (peep->AssignedStaffType == static_cast(_staffType)) - { - peep->TshirtColour = _colour; - peep->TrousersColour = _colour; - } - } - - gfx_invalidate_screen(); - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/StaffSetCostumeAction.cpp b/src/openrct2/actions/StaffSetCostumeAction.cpp new file mode 100644 index 0000000000..b6434a3296 --- /dev/null +++ b/src/openrct2/actions/StaffSetCostumeAction.cpp @@ -0,0 +1,77 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "StaffSetCostumeAction.h" + +#include "../Context.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../windows/Intent.h" + +void StaffSetCostumeAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_spriteIndex) << DS_TAG(_costume); +} + +GameActions::Result::Ptr StaffSetCostumeAction::Query() const +{ + if (_spriteIndex >= MAX_SPRITES) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto* staff = TryGetEntity(_spriteIndex); + if (staff == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto spriteType = EntertainerCostumeToSprite(_costume); + if (EnumValue(spriteType) > std::size(peep_slow_walking_types)) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + return std::make_unique(); +} + +GameActions::Result::Ptr StaffSetCostumeAction::Execute() const +{ + auto* staff = TryGetEntity(_spriteIndex); + if (staff == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto spriteType = EntertainerCostumeToSprite(_costume); + staff->SpriteType = spriteType; + staff->PeepFlags &= ~PEEP_FLAGS_SLOW_WALK; + if (peep_slow_walking_types[EnumValue(spriteType)]) + { + staff->PeepFlags |= PEEP_FLAGS_SLOW_WALK; + } + staff->ActionFrame = 0; + staff->UpdateCurrentActionSpriteType(); + staff->Invalidate(); + + window_invalidate_by_number(WC_PEEP, _spriteIndex); + auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); + context_broadcast_intent(&intent); + + auto res = std::make_unique(); + res->Position.x = staff->x; + res->Position.y = staff->y; + res->Position.z = staff->z; + return res; +} diff --git a/src/openrct2/actions/StaffSetCostumeAction.h b/src/openrct2/actions/StaffSetCostumeAction.h new file mode 100644 index 0000000000..9bf3178b19 --- /dev/null +++ b/src/openrct2/actions/StaffSetCostumeAction.h @@ -0,0 +1,58 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../peep/Staff.h" +#include "../world/Sprite.h" +#include "GameAction.h" + +/** rct2: 0x00982134 */ +constexpr const bool peep_slow_walking_types[] = { + false, // PeepSpriteType::Normal + false, // PeepSpriteType::Handyman + false, // PeepSpriteType::Mechanic + false, // PeepSpriteType::Security + false, // PeepSpriteType::EntertainerPanda + false, // PeepSpriteType::EntertainerTiger + false, // PeepSpriteType::EntertainerElephant + false, // PeepSpriteType::EntertainerRoman + false, // PeepSpriteType::EntertainerGorilla + false, // PeepSpriteType::EntertainerSnowman + false, // PeepSpriteType::EntertainerKnight + true, // PeepSpriteType::EntertainerAstronaut + false, // PeepSpriteType::EntertainerBandit + false, // PeepSpriteType::EntertainerSheriff + true, // PeepSpriteType::EntertainerPirate + true, // PeepSpriteType::Balloon +}; + +DEFINE_GAME_ACTION(StaffSetCostumeAction, GAME_COMMAND_SET_STAFF_COSTUME, GameActions::Result) +{ +private: + uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; + EntertainerCostume _costume = EntertainerCostume::Count; + +public: + StaffSetCostumeAction() = default; + StaffSetCostumeAction(uint16_t spriteIndex, EntertainerCostume costume) + : _spriteIndex(spriteIndex) + , _costume(costume) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffSetCostumeAction.hpp b/src/openrct2/actions/StaffSetCostumeAction.hpp deleted file mode 100644 index 2d95f031cb..0000000000 --- a/src/openrct2/actions/StaffSetCostumeAction.hpp +++ /dev/null @@ -1,120 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../peep/Staff.h" -#include "../windows/Intent.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -/** rct2: 0x00982134 */ -constexpr const bool peep_slow_walking_types[] = { - false, // PeepSpriteType::Normal - false, // PeepSpriteType::Handyman - false, // PeepSpriteType::Mechanic - false, // PeepSpriteType::Security - false, // PeepSpriteType::EntertainerPanda - false, // PeepSpriteType::EntertainerTiger - false, // PeepSpriteType::EntertainerElephant - false, // PeepSpriteType::EntertainerRoman - false, // PeepSpriteType::EntertainerGorilla - false, // PeepSpriteType::EntertainerSnowman - false, // PeepSpriteType::EntertainerKnight - true, // PeepSpriteType::EntertainerAstronaut - false, // PeepSpriteType::EntertainerBandit - false, // PeepSpriteType::EntertainerSheriff - true, // PeepSpriteType::EntertainerPirate - true, // PeepSpriteType::Balloon -}; - -DEFINE_GAME_ACTION(StaffSetCostumeAction, GAME_COMMAND_SET_STAFF_COSTUME, GameActions::Result) -{ -private: - uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; - EntertainerCostume _costume = EntertainerCostume::Count; - -public: - StaffSetCostumeAction() = default; - StaffSetCostumeAction(uint16_t spriteIndex, EntertainerCostume costume) - : _spriteIndex(spriteIndex) - , _costume(costume) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_spriteIndex) << DS_TAG(_costume); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteIndex >= MAX_SPRITES) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto* staff = TryGetEntity(_spriteIndex); - if (staff == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto spriteType = EntertainerCostumeToSprite(_costume); - if (EnumValue(spriteType) > std::size(peep_slow_walking_types)) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto* staff = TryGetEntity(_spriteIndex); - if (staff == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto spriteType = EntertainerCostumeToSprite(_costume); - staff->SpriteType = spriteType; - staff->PeepFlags &= ~PEEP_FLAGS_SLOW_WALK; - if (peep_slow_walking_types[EnumValue(spriteType)]) - { - staff->PeepFlags |= PEEP_FLAGS_SLOW_WALK; - } - staff->ActionFrame = 0; - staff->UpdateCurrentActionSpriteType(); - staff->Invalidate(); - - window_invalidate_by_number(WC_PEEP, _spriteIndex); - auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); - context_broadcast_intent(&intent); - - auto res = std::make_unique(); - res->Position.x = staff->x; - res->Position.y = staff->y; - res->Position.z = staff->z; - return res; - } -}; diff --git a/src/openrct2/actions/StaffSetNameAction.cpp b/src/openrct2/actions/StaffSetNameAction.cpp new file mode 100644 index 0000000000..2cc09b3685 --- /dev/null +++ b/src/openrct2/actions/StaffSetNameAction.cpp @@ -0,0 +1,80 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "StaffSetNameAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../peep/Staff.h" +#include "../windows/Intent.h" +#include "../world/Park.h" + +void StaffSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_spriteIndex) << DS_TAG(_name); +} + +GameActions::Result::Ptr StaffSetNameAction::Query() const +{ + if (_spriteIndex >= MAX_SPRITES) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); + } + + auto staff = TryGetEntity(_spriteIndex); + if (staff == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr StaffSetNameAction::Execute() const +{ + auto staff = TryGetEntity(_spriteIndex); + if (staff == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); + } + + auto curName = staff->GetName(); + if (curName == _name) + { + return std::make_unique(GameActions::Status::Ok, STR_NONE); + } + + if (!staff->SetName(_name)) + { + return std::make_unique(GameActions::Status::Unknown, STR_CANT_NAME_GUEST, STR_NONE); + } + + gfx_invalidate_screen(); + + auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); + context_broadcast_intent(&intent); + + auto res = std::make_unique(); + res->Position.x = staff->x; + res->Position.y = staff->y; + res->Position.z = staff->z; + return res; +} diff --git a/src/openrct2/actions/StaffSetNameAction.h b/src/openrct2/actions/StaffSetNameAction.h new file mode 100644 index 0000000000..6c4ddff9ac --- /dev/null +++ b/src/openrct2/actions/StaffSetNameAction.h @@ -0,0 +1,37 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(StaffSetNameAction, GAME_COMMAND_SET_STAFF_NAME, GameActions::Result) +{ +private: + uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; + std::string _name; + +public: + StaffSetNameAction() = default; + StaffSetNameAction(uint16_t spriteIndex, const std::string& name) + : _spriteIndex(spriteIndex) + , _name(name) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffSetNameAction.hpp b/src/openrct2/actions/StaffSetNameAction.hpp deleted file mode 100644 index ce02259f6d..0000000000 --- a/src/openrct2/actions/StaffSetNameAction.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../peep/Staff.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(StaffSetNameAction, GAME_COMMAND_SET_STAFF_NAME, GameActions::Result) -{ -private: - uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; - std::string _name; - -public: - StaffSetNameAction() = default; - StaffSetNameAction(uint16_t spriteIndex, const std::string& name) - : _spriteIndex(spriteIndex) - , _name(name) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_spriteIndex) << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteIndex >= MAX_SPRITES) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); - } - - auto staff = TryGetEntity(_spriteIndex); - if (staff == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto staff = TryGetEntity(_spriteIndex); - if (staff == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); - } - - auto curName = staff->GetName(); - if (curName == _name) - { - return std::make_unique(GameActions::Status::Ok, STR_NONE); - } - - if (!staff->SetName(_name)) - { - return std::make_unique(GameActions::Status::Unknown, STR_CANT_NAME_GUEST, STR_NONE); - } - - gfx_invalidate_screen(); - - auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); - context_broadcast_intent(&intent); - - auto res = std::make_unique(); - res->Position.x = staff->x; - res->Position.y = staff->y; - res->Position.z = staff->z; - return res; - } -}; diff --git a/src/openrct2/actions/StaffSetOrdersAction.cpp b/src/openrct2/actions/StaffSetOrdersAction.cpp new file mode 100644 index 0000000000..e07566c724 --- /dev/null +++ b/src/openrct2/actions/StaffSetOrdersAction.cpp @@ -0,0 +1,63 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "StaffSetOrdersAction.h" + +#include "../Context.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../peep/Staff.h" +#include "../windows/Intent.h" + +void StaffSetOrdersAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_spriteIndex) << DS_TAG(_ordersId); +} + +GameActions::Result::Ptr StaffSetOrdersAction::Query() const +{ + if (_spriteIndex >= MAX_SPRITES) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto* staff = TryGetEntity(_spriteIndex); + if (staff == nullptr + || (staff->AssignedStaffType != StaffType::Handyman && staff->AssignedStaffType != StaffType::Mechanic)) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr StaffSetOrdersAction::Execute() const +{ + auto* staff = TryGetEntity(_spriteIndex); + if (staff == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + staff->StaffOrders = _ordersId; + + window_invalidate_by_number(WC_PEEP, _spriteIndex); + auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); + context_broadcast_intent(&intent); + + auto res = std::make_unique(); + res->Position.x = staff->x; + res->Position.y = staff->y; + res->Position.z = staff->z; + return res; +} diff --git a/src/openrct2/actions/StaffSetOrdersAction.h b/src/openrct2/actions/StaffSetOrdersAction.h new file mode 100644 index 0000000000..0c28864141 --- /dev/null +++ b/src/openrct2/actions/StaffSetOrdersAction.h @@ -0,0 +1,37 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(StaffSetOrdersAction, GAME_COMMAND_SET_STAFF_ORDERS, GameActions::Result) +{ +private: + uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; + uint8_t _ordersId{}; + +public: + StaffSetOrdersAction() = default; + StaffSetOrdersAction(uint16_t spriteIndex, uint8_t ordersId) + : _spriteIndex(spriteIndex) + , _ordersId(ordersId) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffSetOrdersAction.hpp b/src/openrct2/actions/StaffSetOrdersAction.hpp deleted file mode 100644 index f9048684a0..0000000000 --- a/src/openrct2/actions/StaffSetOrdersAction.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../peep/Staff.h" -#include "../windows/Intent.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(StaffSetOrdersAction, GAME_COMMAND_SET_STAFF_ORDERS, GameActions::Result) -{ -private: - uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; - uint8_t _ordersId{}; - -public: - StaffSetOrdersAction() = default; - StaffSetOrdersAction(uint16_t spriteIndex, uint8_t ordersId) - : _spriteIndex(spriteIndex) - , _ordersId(ordersId) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_spriteIndex) << DS_TAG(_ordersId); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteIndex >= MAX_SPRITES) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto* staff = TryGetEntity(_spriteIndex); - if (staff == nullptr - || (staff->AssignedStaffType != StaffType::Handyman && staff->AssignedStaffType != StaffType::Mechanic)) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto* staff = TryGetEntity(_spriteIndex); - if (staff == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - staff->StaffOrders = _ordersId; - - window_invalidate_by_number(WC_PEEP, _spriteIndex); - auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); - context_broadcast_intent(&intent); - - auto res = std::make_unique(); - res->Position.x = staff->x; - res->Position.y = staff->y; - res->Position.z = staff->z; - return res; - } -}; diff --git a/src/openrct2/actions/StaffSetPatrolAreaAction.cpp b/src/openrct2/actions/StaffSetPatrolAreaAction.cpp new file mode 100644 index 0000000000..bcf20dad23 --- /dev/null +++ b/src/openrct2/actions/StaffSetPatrolAreaAction.cpp @@ -0,0 +1,87 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "StaffSetPatrolAreaAction.h" + +#include "../interface/Window.h" +#include "../peep/Peep.h" +#include "../peep/Staff.h" + +void StaffSetPatrolAreaAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_spriteId) << DS_TAG(_loc); +} + +GameActions::Result::Ptr StaffSetPatrolAreaAction::Query() const +{ + if (_spriteId >= MAX_SPRITES) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto staff = TryGetEntity(_spriteId); + if (staff == nullptr) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr StaffSetPatrolAreaAction::Execute() const +{ + auto staff = TryGetEntity(_spriteId); + if (staff == nullptr) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + int32_t patrolOffset = staff->StaffId * STAFF_PATROL_AREA_SIZE; + + staff_toggle_patrol_area(staff->StaffId, _loc); + + bool isPatrolling = false; + for (int32_t i = 0; i < 128; i++) + { + if (gStaffPatrolAreas[patrolOffset + i]) + { + isPatrolling = true; + break; + } + } + + if (isPatrolling) + { + gStaffModes[staff->StaffId] = StaffMode::Patrol; + } + else if (gStaffModes[staff->StaffId] == StaffMode::Patrol) + { + gStaffModes[staff->StaffId] = StaffMode::Walk; + } + + for (int32_t y = 0; y < 4 * COORDS_XY_STEP; y += COORDS_XY_STEP) + { + for (int32_t x = 0; x < 4 * COORDS_XY_STEP; x += COORDS_XY_STEP) + { + map_invalidate_tile_full({ (_loc.x & 0x1F80) + x, (_loc.y & 0x1F80) + y }); + } + } + staff_update_greyed_patrol_areas(); + + return MakeResult(); +} diff --git a/src/openrct2/actions/StaffSetPatrolAreaAction.h b/src/openrct2/actions/StaffSetPatrolAreaAction.h new file mode 100644 index 0000000000..e3d7cd2e29 --- /dev/null +++ b/src/openrct2/actions/StaffSetPatrolAreaAction.h @@ -0,0 +1,37 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(StaffSetPatrolAreaAction, GAME_COMMAND_SET_STAFF_PATROL, GameActions::Result) +{ +private: + uint16_t _spriteId{ SPRITE_INDEX_NULL }; + CoordsXY _loc; + +public: + StaffSetPatrolAreaAction() = default; + StaffSetPatrolAreaAction(uint16_t spriteId, const CoordsXY& loc) + : _spriteId(spriteId) + , _loc(loc) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffSetPatrolAreaAction.hpp b/src/openrct2/actions/StaffSetPatrolAreaAction.hpp deleted file mode 100644 index b1cc95110b..0000000000 --- a/src/openrct2/actions/StaffSetPatrolAreaAction.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../interface/Window.h" -#include "../peep/Peep.h" -#include "../peep/Staff.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(StaffSetPatrolAreaAction, GAME_COMMAND_SET_STAFF_PATROL, GameActions::Result) -{ -private: - uint16_t _spriteId{ SPRITE_INDEX_NULL }; - CoordsXY _loc; - -public: - StaffSetPatrolAreaAction() = default; - StaffSetPatrolAreaAction(uint16_t spriteId, const CoordsXY& loc) - : _spriteId(spriteId) - , _loc(loc) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_spriteId) << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteId >= MAX_SPRITES) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto staff = TryGetEntity(_spriteId); - if (staff == nullptr) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto staff = TryGetEntity(_spriteId); - if (staff == nullptr) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - int32_t patrolOffset = staff->StaffId * STAFF_PATROL_AREA_SIZE; - - staff_toggle_patrol_area(staff->StaffId, _loc); - - bool isPatrolling = false; - for (int32_t i = 0; i < 128; i++) - { - if (gStaffPatrolAreas[patrolOffset + i]) - { - isPatrolling = true; - break; - } - } - - if (isPatrolling) - { - gStaffModes[staff->StaffId] = StaffMode::Patrol; - } - else if (gStaffModes[staff->StaffId] == StaffMode::Patrol) - { - gStaffModes[staff->StaffId] = StaffMode::Walk; - } - - for (int32_t y = 0; y < 4 * COORDS_XY_STEP; y += COORDS_XY_STEP) - { - for (int32_t x = 0; x < 4 * COORDS_XY_STEP; x += COORDS_XY_STEP) - { - map_invalidate_tile_full({ (_loc.x & 0x1F80) + x, (_loc.y & 0x1F80) + y }); - } - } - staff_update_greyed_patrol_areas(); - - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/SurfaceSetStyleAction.cpp b/src/openrct2/actions/SurfaceSetStyleAction.cpp new file mode 100644 index 0000000000..3921395eb3 --- /dev/null +++ b/src/openrct2/actions/SurfaceSetStyleAction.cpp @@ -0,0 +1,235 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "SurfaceSetStyleAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../object/ObjectManager.h" +#include "../object/TerrainEdgeObject.h" +#include "../object/TerrainSurfaceObject.h" +#include "../world/Park.h" +#include "../world/Surface.h" +#include "../world/TileElement.h" + +void SurfaceSetStyleAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range) << DS_TAG(_surfaceStyle) << DS_TAG(_edgeStyle); +} + +GameActions::Result::Ptr SurfaceSetStyleAction::Query() const +{ + auto res = MakeResult(); + res->ErrorTitle = STR_CANT_CHANGE_LAND_TYPE; + res->Expenditure = ExpenditureType::Landscaping; + + auto normRange = _range.Normalise(); + auto x0 = std::max(normRange.GetLeft(), 32); + auto y0 = std::max(normRange.GetTop(), 32); + auto x1 = std::min(normRange.GetRight(), static_cast(gMapSizeMaxXY)); + auto y1 = std::min(normRange.GetBottom(), static_cast(gMapSizeMaxXY)); + + MapRange validRange{ x0, y0, x1, y1 }; + + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) + { + if (_surfaceStyle > 0x1F) + { + log_error("Invalid surface style."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); + } + + const auto surfaceObj = static_cast( + objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); + + if (surfaceObj == nullptr) + { + log_error("Invalid surface style."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); + } + } + + if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) + { + if (_edgeStyle > 0xF) + { + log_error("Invalid edge style."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); + } + + const auto edgeObj = static_cast(objManager.GetLoadedObject(ObjectType::TerrainEdge, _edgeStyle)); + + if (edgeObj == nullptr) + { + log_error("Invalid edge style."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); + } + } + + auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; + auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; + auto heightMid = tile_element_height({ xMid, yMid }); + + res->Position.x = xMid; + res->Position.y = yMid; + res->Position.z = heightMid; + + // Do nothing if not in editor, sandbox mode or landscaping is forbidden + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode + && (gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES)) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_LAND_TYPE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); + } + + money32 surfaceCost = 0; + money32 edgeCost = 0; + for (CoordsXY coords = { validRange.GetLeft(), validRange.GetTop() }; coords.x <= validRange.GetRight(); + coords.x += COORDS_XY_STEP) + { + for (coords.y = validRange.GetTop(); coords.y <= validRange.GetBottom(); coords.y += COORDS_XY_STEP) + { + if (!LocationValid(coords)) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(coords)) + continue; + } + + auto surfaceElement = map_get_surface_element_at(coords); + if (surfaceElement == nullptr) + { + continue; + } + + if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) + { + uint8_t curSurfaceStyle = surfaceElement->GetSurfaceStyle(); + + if (_surfaceStyle != curSurfaceStyle) + { + const auto surfaceObject = static_cast( + objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); + if (surfaceObject != nullptr) + { + surfaceCost += surfaceObject->Price; + } + } + } + + if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) + { + uint8_t curEdgeStyle = surfaceElement->GetEdgeStyle(); + + if (_edgeStyle != curEdgeStyle) + { + edgeCost += 100; + } + } + } + } + res->Cost = surfaceCost + edgeCost; + + return res; +} + +GameActions::Result::Ptr SurfaceSetStyleAction::Execute() const +{ + auto res = MakeResult(); + res->ErrorTitle = STR_CANT_CHANGE_LAND_TYPE; + res->Expenditure = ExpenditureType::Landscaping; + + auto normRange = _range.Normalise(); + auto x0 = std::max(normRange.GetLeft(), 32); + auto y0 = std::max(normRange.GetTop(), 32); + auto x1 = std::min(normRange.GetRight(), static_cast(gMapSizeMaxXY)); + auto y1 = std::min(normRange.GetBottom(), static_cast(gMapSizeMaxXY)); + + MapRange validRange{ x0, y0, x1, y1 }; + + auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; + auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; + auto heightMid = tile_element_height({ xMid, yMid }); + + res->Position.x = xMid; + res->Position.y = yMid; + res->Position.z = heightMid; + + money32 surfaceCost = 0; + money32 edgeCost = 0; + for (CoordsXY coords = { validRange.GetLeft(), validRange.GetTop() }; coords.x <= validRange.GetRight(); + coords.x += COORDS_XY_STEP) + { + for (coords.y = validRange.GetTop(); coords.y <= validRange.GetBottom(); coords.y += COORDS_XY_STEP) + { + if (!LocationValid(coords)) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(coords)) + continue; + } + + auto surfaceElement = map_get_surface_element_at(coords); + if (surfaceElement == nullptr) + { + continue; + } + + if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) + { + uint8_t curSurfaceStyle = surfaceElement->GetSurfaceStyle(); + + if (_surfaceStyle != curSurfaceStyle) + { + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + const auto surfaceObject = static_cast( + objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); + if (surfaceObject != nullptr) + { + surfaceCost += surfaceObject->Price; + + surfaceElement->SetSurfaceStyle(_surfaceStyle); + + map_invalidate_tile_full(coords); + footpath_remove_litter({ coords, tile_element_height(coords) }); + } + } + } + + if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) + { + uint8_t curEdgeStyle = surfaceElement->GetEdgeStyle(); + + if (_edgeStyle != curEdgeStyle) + { + edgeCost += 100; + + surfaceElement->SetEdgeStyle(_edgeStyle); + map_invalidate_tile_full(coords); + } + } + + if (surfaceElement->CanGrassGrow() && (surfaceElement->GetGrassLength() & 7) != GRASS_LENGTH_CLEAR_0) + { + surfaceElement->SetGrassLength(GRASS_LENGTH_CLEAR_0); + map_invalidate_tile_full(coords); + } + } + } + res->Cost = surfaceCost + edgeCost; + + return res; +} diff --git a/src/openrct2/actions/SurfaceSetStyleAction.h b/src/openrct2/actions/SurfaceSetStyleAction.h new file mode 100644 index 0000000000..eea5f66d23 --- /dev/null +++ b/src/openrct2/actions/SurfaceSetStyleAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(SurfaceSetStyleAction, GAME_COMMAND_CHANGE_SURFACE_STYLE, GameActions::Result) +{ +private: + MapRange _range; + ObjectEntryIndex _surfaceStyle{}; + ObjectEntryIndex _edgeStyle{}; + +public: + SurfaceSetStyleAction() = default; + + SurfaceSetStyleAction(MapRange range, ObjectEntryIndex surfaceStyle, ObjectEntryIndex edgeStyle) + : _range(range) + , _surfaceStyle(surfaceStyle) + , _edgeStyle(edgeStyle) + { + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/SurfaceSetStyleAction.hpp b/src/openrct2/actions/SurfaceSetStyleAction.hpp deleted file mode 100644 index 7d023d6dc9..0000000000 --- a/src/openrct2/actions/SurfaceSetStyleAction.hpp +++ /dev/null @@ -1,255 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Context.h" -#include "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../object/ObjectManager.h" -#include "../object/TerrainEdgeObject.h" -#include "../object/TerrainSurfaceObject.h" -#include "../world/Park.h" -#include "../world/Surface.h" -#include "../world/TileElement.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(SurfaceSetStyleAction, GAME_COMMAND_CHANGE_SURFACE_STYLE, GameActions::Result) -{ -private: - MapRange _range; - ObjectEntryIndex _surfaceStyle{}; - ObjectEntryIndex _edgeStyle{}; - -public: - SurfaceSetStyleAction() = default; - - SurfaceSetStyleAction(MapRange range, ObjectEntryIndex surfaceStyle, ObjectEntryIndex edgeStyle) - : _range(range) - , _surfaceStyle(surfaceStyle) - , _edgeStyle(edgeStyle) - { - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range) << DS_TAG(_surfaceStyle) << DS_TAG(_edgeStyle); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->ErrorTitle = STR_CANT_CHANGE_LAND_TYPE; - res->Expenditure = ExpenditureType::Landscaping; - - auto normRange = _range.Normalise(); - auto x0 = std::max(normRange.GetLeft(), 32); - auto y0 = std::max(normRange.GetTop(), 32); - auto x1 = std::min(normRange.GetRight(), static_cast(gMapSizeMaxXY)); - auto y1 = std::min(normRange.GetBottom(), static_cast(gMapSizeMaxXY)); - - MapRange validRange{ x0, y0, x1, y1 }; - - auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); - if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) - { - if (_surfaceStyle > 0x1F) - { - log_error("Invalid surface style."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); - } - - const auto surfaceObj = static_cast( - objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); - - if (surfaceObj == nullptr) - { - log_error("Invalid surface style."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); - } - } - - if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) - { - if (_edgeStyle > 0xF) - { - log_error("Invalid edge style."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); - } - - const auto edgeObj = static_cast( - objManager.GetLoadedObject(ObjectType::TerrainEdge, _edgeStyle)); - - if (edgeObj == nullptr) - { - log_error("Invalid edge style."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); - } - } - - auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; - auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; - auto heightMid = tile_element_height({ xMid, yMid }); - - res->Position.x = xMid; - res->Position.y = yMid; - res->Position.z = heightMid; - - // Do nothing if not in editor, sandbox mode or landscaping is forbidden - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode - && (gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES)) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_LAND_TYPE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); - } - - money32 surfaceCost = 0; - money32 edgeCost = 0; - for (CoordsXY coords = { validRange.GetLeft(), validRange.GetTop() }; coords.x <= validRange.GetRight(); - coords.x += COORDS_XY_STEP) - { - for (coords.y = validRange.GetTop(); coords.y <= validRange.GetBottom(); coords.y += COORDS_XY_STEP) - { - if (!LocationValid(coords)) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(coords)) - continue; - } - - auto surfaceElement = map_get_surface_element_at(coords); - if (surfaceElement == nullptr) - { - continue; - } - - if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) - { - uint8_t curSurfaceStyle = surfaceElement->GetSurfaceStyle(); - - if (_surfaceStyle != curSurfaceStyle) - { - const auto surfaceObject = static_cast( - objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); - if (surfaceObject != nullptr) - { - surfaceCost += surfaceObject->Price; - } - } - } - - if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) - { - uint8_t curEdgeStyle = surfaceElement->GetEdgeStyle(); - - if (_edgeStyle != curEdgeStyle) - { - edgeCost += 100; - } - } - } - } - res->Cost = surfaceCost + edgeCost; - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->ErrorTitle = STR_CANT_CHANGE_LAND_TYPE; - res->Expenditure = ExpenditureType::Landscaping; - - auto normRange = _range.Normalise(); - auto x0 = std::max(normRange.GetLeft(), 32); - auto y0 = std::max(normRange.GetTop(), 32); - auto x1 = std::min(normRange.GetRight(), static_cast(gMapSizeMaxXY)); - auto y1 = std::min(normRange.GetBottom(), static_cast(gMapSizeMaxXY)); - - MapRange validRange{ x0, y0, x1, y1 }; - - auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; - auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; - auto heightMid = tile_element_height({ xMid, yMid }); - - res->Position.x = xMid; - res->Position.y = yMid; - res->Position.z = heightMid; - - money32 surfaceCost = 0; - money32 edgeCost = 0; - for (CoordsXY coords = { validRange.GetLeft(), validRange.GetTop() }; coords.x <= validRange.GetRight(); - coords.x += COORDS_XY_STEP) - { - for (coords.y = validRange.GetTop(); coords.y <= validRange.GetBottom(); coords.y += COORDS_XY_STEP) - { - if (!LocationValid(coords)) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(coords)) - continue; - } - - auto surfaceElement = map_get_surface_element_at(coords); - if (surfaceElement == nullptr) - { - continue; - } - - if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) - { - uint8_t curSurfaceStyle = surfaceElement->GetSurfaceStyle(); - - if (_surfaceStyle != curSurfaceStyle) - { - auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); - const auto surfaceObject = static_cast( - objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); - if (surfaceObject != nullptr) - { - surfaceCost += surfaceObject->Price; - - surfaceElement->SetSurfaceStyle(_surfaceStyle); - - map_invalidate_tile_full(coords); - footpath_remove_litter({ coords, tile_element_height(coords) }); - } - } - } - - if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) - { - uint8_t curEdgeStyle = surfaceElement->GetEdgeStyle(); - - if (_edgeStyle != curEdgeStyle) - { - edgeCost += 100; - - surfaceElement->SetEdgeStyle(_edgeStyle); - map_invalidate_tile_full(coords); - } - } - - if (surfaceElement->CanGrassGrow() && (surfaceElement->GetGrassLength() & 7) != GRASS_LENGTH_CLEAR_0) - { - surfaceElement->SetGrassLength(GRASS_LENGTH_CLEAR_0); - map_invalidate_tile_full(coords); - } - } - } - res->Cost = surfaceCost + edgeCost; - - return res; - } -}; diff --git a/src/openrct2/actions/TileModifyAction.cpp b/src/openrct2/actions/TileModifyAction.cpp new file mode 100644 index 0000000000..fc51709ed7 --- /dev/null +++ b/src/openrct2/actions/TileModifyAction.cpp @@ -0,0 +1,212 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "TileModifyAction.h" + +#include "../world/TileInspector.h" + +void TileModifyAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_setting) << DS_TAG(_value1) << DS_TAG(_value2) << DS_TAG(_pasteElement); +} + +GameActions::Result::Ptr TileModifyAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr TileModifyAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr TileModifyAction::QueryExecute(bool isExecuting) const +{ + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); + } + auto res = MakeResult(); + switch (_setting) + { + case TileModifyType::AnyRemove: + { + const auto elementIndex = _value1; + res = tile_inspector_remove_element_at(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::AnySwap: + { + const auto firstIndex = _value1; + const auto secondIndex = _value2; + res = tile_inspector_swap_elements_at(_loc, firstIndex, secondIndex, isExecuting); + break; + } + case TileModifyType::AnyInsertCorrupt: + { + const auto elementIndex = _value1; + res = tile_inspector_insert_corrupt_at(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::AnyRotate: + { + const auto elementIndex = _value1; + res = tile_inspector_rotate_element_at(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::AnyPaste: + { + res = tile_inspector_paste_element_at(_loc, _pasteElement, isExecuting); + break; + } + case TileModifyType::AnySort: + { + res = tile_inspector_sort_elements_at(_loc, isExecuting); + break; + } + case TileModifyType::AnyBaseHeightOffset: + { + const auto elementIndex = _value1; + const auto heightOffset = _value2; + res = tile_inspector_any_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); + break; + } + case TileModifyType::SurfaceShowParkFences: + { + const bool showFences = _value1; + res = tile_inspector_surface_show_park_fences(_loc, showFences, isExecuting); + break; + } + case TileModifyType::SurfaceToggleCorner: + { + const auto cornerIndex = _value1; + res = tile_inspector_surface_toggle_corner(_loc, cornerIndex, isExecuting); + break; + } + case TileModifyType::SurfaceToggleDiagonal: + { + res = tile_inspector_surface_toggle_diagonal(_loc, isExecuting); + break; + } + case TileModifyType::PathSetSlope: + { + const auto elementIndex = _value1; + const bool sloped = _value2; + res = tile_inspector_path_set_sloped(_loc, elementIndex, sloped, isExecuting); + break; + } + case TileModifyType::PathSetBroken: + { + const auto elementIndex = _value1; + const bool broken = _value2; + res = tile_inspector_path_set_broken(_loc, elementIndex, broken, isExecuting); + break; + } + case TileModifyType::PathToggleEdge: + { + const auto elementIndex = _value1; + const auto edgeIndex = _value2; + res = tile_inspector_path_toggle_edge(_loc, elementIndex, edgeIndex, isExecuting); + break; + } + case TileModifyType::EntranceMakeUsable: + { + const auto elementIndex = _value1; + res = tile_inspector_entrance_make_usable(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::WallSetSlope: + { + const auto elementIndex = _value1; + const auto slopeValue = _value2; + res = tile_inspector_wall_set_slope(_loc, elementIndex, slopeValue, isExecuting); + break; + } + case TileModifyType::WallSetAnimationFrame: + { + const auto elementIndex = _value1; + const auto animationFrameOffset = _value2; + res = tile_inspector_wall_animation_frame_offset(_loc, elementIndex, animationFrameOffset, isExecuting); + break; + } + case TileModifyType::TrackBaseHeightOffset: + { + const auto elementIndex = _value1; + const auto heightOffset = _value2; + res = tile_inspector_track_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); + break; + } + case TileModifyType::TrackSetChainBlock: + { + const auto elementIndex = _value1; + const bool setChain = _value2; + res = tile_inspector_track_set_chain(_loc, elementIndex, true, setChain, isExecuting); + break; + } + case TileModifyType::TrackSetChain: + { + const auto elementIndex = _value1; + const bool setChain = _value2; + res = tile_inspector_track_set_chain(_loc, elementIndex, false, setChain, isExecuting); + break; + } + case TileModifyType::TrackSetBlockBrake: + { + const auto elementIndex = _value1; + const bool blockBrake = _value2; + res = tile_inspector_track_set_block_brake(_loc, elementIndex, blockBrake, isExecuting); + break; + } + case TileModifyType::TrackSetIndestructible: + { + const auto elementIndex = _value1; + const bool isIndestructible = _value2; + res = tile_inspector_track_set_indestructible(_loc, elementIndex, isIndestructible, isExecuting); + break; + } + case TileModifyType::ScenerySetQuarterLocation: + { + const auto elementIndex = _value1; + const auto quarterIndex = _value2; + res = tile_inspector_scenery_set_quarter_location(_loc, elementIndex, quarterIndex, isExecuting); + break; + } + case TileModifyType::ScenerySetQuarterCollision: + { + const auto elementIndex = _value1; + const auto quarterIndex = _value2; + res = tile_inspector_scenery_set_quarter_collision(_loc, elementIndex, quarterIndex, isExecuting); + break; + } + case TileModifyType::BannerToggleBlockingEdge: + { + const auto elementIndex = _value1; + const auto edgeIndex = _value2; + res = tile_inspector_banner_toggle_blocking_edge(_loc, elementIndex, edgeIndex, isExecuting); + break; + } + case TileModifyType::CorruptClamp: + { + const auto elementIndex = _value1; + res = tile_inspector_corrupt_clamp(_loc, elementIndex, isExecuting); + break; + } + default: + log_error("invalid instruction"); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + res->Position.x = _loc.x; + res->Position.y = _loc.y; + res->Position.z = tile_element_height(_loc); + + return res; +} diff --git a/src/openrct2/actions/TileModifyAction.h b/src/openrct2/actions/TileModifyAction.h new file mode 100644 index 0000000000..a51e0e53a3 --- /dev/null +++ b/src/openrct2/actions/TileModifyAction.h @@ -0,0 +1,76 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +enum class TileModifyType : uint8_t +{ + AnyRemove, + AnySwap, + AnyInsertCorrupt, + AnyRotate, + AnyPaste, + AnySort, + AnyBaseHeightOffset, + SurfaceShowParkFences, + SurfaceToggleCorner, + SurfaceToggleDiagonal, + PathSetSlope, + PathSetBroken, + PathToggleEdge, + EntranceMakeUsable, + WallSetSlope, + WallSetAnimationFrame, + TrackBaseHeightOffset, + TrackSetChain, + TrackSetChainBlock, + TrackSetBlockBrake, + TrackSetIndestructible, + ScenerySetQuarterLocation, + ScenerySetQuarterCollision, + BannerToggleBlockingEdge, + CorruptClamp, + Count, +}; + +DEFINE_GAME_ACTION(TileModifyAction, GAME_COMMAND_MODIFY_TILE, GameActions::Result) +{ +private: + CoordsXY _loc; + TileModifyType _setting{}; + uint32_t _value1{}; + uint32_t _value2{}; + TileElement _pasteElement{}; + +public: + TileModifyAction() = default; + TileModifyAction( + CoordsXY loc, TileModifyType setting, uint32_t value1 = 0, uint32_t value2 = 0, TileElement pasteElement = {}) + : _loc(loc) + , _setting(setting) + , _value1(value1) + , _value2(value2) + , _pasteElement(pasteElement) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/TileModifyAction.hpp b/src/openrct2/actions/TileModifyAction.hpp deleted file mode 100644 index 26f0e9ec07..0000000000 --- a/src/openrct2/actions/TileModifyAction.hpp +++ /dev/null @@ -1,272 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../world/TileInspector.h" -#include "GameAction.h" - -enum class TileModifyType : uint8_t -{ - AnyRemove, - AnySwap, - AnyInsertCorrupt, - AnyRotate, - AnyPaste, - AnySort, - AnyBaseHeightOffset, - SurfaceShowParkFences, - SurfaceToggleCorner, - SurfaceToggleDiagonal, - PathSetSlope, - PathSetBroken, - PathToggleEdge, - EntranceMakeUsable, - WallSetSlope, - WallSetAnimationFrame, - TrackBaseHeightOffset, - TrackSetChain, - TrackSetChainBlock, - TrackSetBlockBrake, - TrackSetIndestructible, - ScenerySetQuarterLocation, - ScenerySetQuarterCollision, - BannerToggleBlockingEdge, - CorruptClamp, - Count, -}; - -DEFINE_GAME_ACTION(TileModifyAction, GAME_COMMAND_MODIFY_TILE, GameActions::Result) -{ -private: - CoordsXY _loc; - TileModifyType _setting{}; - uint32_t _value1{}; - uint32_t _value2{}; - TileElement _pasteElement{}; - -public: - TileModifyAction() = default; - TileModifyAction( - CoordsXY loc, TileModifyType setting, uint32_t value1 = 0, uint32_t value2 = 0, TileElement pasteElement = {}) - : _loc(loc) - , _setting(setting) - , _value1(value1) - , _value2(value2) - , _pasteElement(pasteElement) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_setting) << DS_TAG(_value1) << DS_TAG(_value2) << DS_TAG(_pasteElement); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); - } - auto res = MakeResult(); - switch (_setting) - { - case TileModifyType::AnyRemove: - { - const auto elementIndex = _value1; - res = tile_inspector_remove_element_at(_loc, elementIndex, isExecuting); - break; - } - case TileModifyType::AnySwap: - { - const auto firstIndex = _value1; - const auto secondIndex = _value2; - res = tile_inspector_swap_elements_at(_loc, firstIndex, secondIndex, isExecuting); - break; - } - case TileModifyType::AnyInsertCorrupt: - { - const auto elementIndex = _value1; - res = tile_inspector_insert_corrupt_at(_loc, elementIndex, isExecuting); - break; - } - case TileModifyType::AnyRotate: - { - const auto elementIndex = _value1; - res = tile_inspector_rotate_element_at(_loc, elementIndex, isExecuting); - break; - } - case TileModifyType::AnyPaste: - { - res = tile_inspector_paste_element_at(_loc, _pasteElement, isExecuting); - break; - } - case TileModifyType::AnySort: - { - res = tile_inspector_sort_elements_at(_loc, isExecuting); - break; - } - case TileModifyType::AnyBaseHeightOffset: - { - const auto elementIndex = _value1; - const auto heightOffset = _value2; - res = tile_inspector_any_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); - break; - } - case TileModifyType::SurfaceShowParkFences: - { - const bool showFences = _value1; - res = tile_inspector_surface_show_park_fences(_loc, showFences, isExecuting); - break; - } - case TileModifyType::SurfaceToggleCorner: - { - const auto cornerIndex = _value1; - res = tile_inspector_surface_toggle_corner(_loc, cornerIndex, isExecuting); - break; - } - case TileModifyType::SurfaceToggleDiagonal: - { - res = tile_inspector_surface_toggle_diagonal(_loc, isExecuting); - break; - } - case TileModifyType::PathSetSlope: - { - const auto elementIndex = _value1; - const bool sloped = _value2; - res = tile_inspector_path_set_sloped(_loc, elementIndex, sloped, isExecuting); - break; - } - case TileModifyType::PathSetBroken: - { - const auto elementIndex = _value1; - const bool broken = _value2; - res = tile_inspector_path_set_broken(_loc, elementIndex, broken, isExecuting); - break; - } - case TileModifyType::PathToggleEdge: - { - const auto elementIndex = _value1; - const auto edgeIndex = _value2; - res = tile_inspector_path_toggle_edge(_loc, elementIndex, edgeIndex, isExecuting); - break; - } - case TileModifyType::EntranceMakeUsable: - { - const auto elementIndex = _value1; - res = tile_inspector_entrance_make_usable(_loc, elementIndex, isExecuting); - break; - } - case TileModifyType::WallSetSlope: - { - const auto elementIndex = _value1; - const auto slopeValue = _value2; - res = tile_inspector_wall_set_slope(_loc, elementIndex, slopeValue, isExecuting); - break; - } - case TileModifyType::WallSetAnimationFrame: - { - const auto elementIndex = _value1; - const auto animationFrameOffset = _value2; - res = tile_inspector_wall_animation_frame_offset(_loc, elementIndex, animationFrameOffset, isExecuting); - break; - } - case TileModifyType::TrackBaseHeightOffset: - { - const auto elementIndex = _value1; - const auto heightOffset = _value2; - res = tile_inspector_track_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); - break; - } - case TileModifyType::TrackSetChainBlock: - { - const auto elementIndex = _value1; - const bool setChain = _value2; - res = tile_inspector_track_set_chain(_loc, elementIndex, true, setChain, isExecuting); - break; - } - case TileModifyType::TrackSetChain: - { - const auto elementIndex = _value1; - const bool setChain = _value2; - res = tile_inspector_track_set_chain(_loc, elementIndex, false, setChain, isExecuting); - break; - } - case TileModifyType::TrackSetBlockBrake: - { - const auto elementIndex = _value1; - const bool blockBrake = _value2; - res = tile_inspector_track_set_block_brake(_loc, elementIndex, blockBrake, isExecuting); - break; - } - case TileModifyType::TrackSetIndestructible: - { - const auto elementIndex = _value1; - const bool isIndestructible = _value2; - res = tile_inspector_track_set_indestructible(_loc, elementIndex, isIndestructible, isExecuting); - break; - } - case TileModifyType::ScenerySetQuarterLocation: - { - const auto elementIndex = _value1; - const auto quarterIndex = _value2; - res = tile_inspector_scenery_set_quarter_location(_loc, elementIndex, quarterIndex, isExecuting); - break; - } - case TileModifyType::ScenerySetQuarterCollision: - { - const auto elementIndex = _value1; - const auto quarterIndex = _value2; - res = tile_inspector_scenery_set_quarter_collision(_loc, elementIndex, quarterIndex, isExecuting); - break; - } - case TileModifyType::BannerToggleBlockingEdge: - { - const auto elementIndex = _value1; - const auto edgeIndex = _value2; - res = tile_inspector_banner_toggle_blocking_edge(_loc, elementIndex, edgeIndex, isExecuting); - break; - } - case TileModifyType::CorruptClamp: - { - const auto elementIndex = _value1; - res = tile_inspector_corrupt_clamp(_loc, elementIndex, isExecuting); - break; - } - default: - log_error("invalid instruction"); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - break; - } - - res->Position.x = _loc.x; - res->Position.y = _loc.y; - res->Position.z = tile_element_height(_loc); - - return res; - } -}; diff --git a/src/openrct2/actions/TrackDesignAction.cpp b/src/openrct2/actions/TrackDesignAction.cpp index aa3df02c0c..a4df7d9f31 100644 --- a/src/openrct2/actions/TrackDesignAction.cpp +++ b/src/openrct2/actions/TrackDesignAction.cpp @@ -15,11 +15,11 @@ #include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" #include "../ride/TrackDesign.h" -#include "RideCreateAction.hpp" -#include "RideDemolishAction.hpp" -#include "RideSetName.hpp" -#include "RideSetSetting.hpp" -#include "RideSetVehiclesAction.hpp" +#include "RideCreateAction.h" +#include "RideDemolishAction.h" +#include "RideSetNameAction.h" +#include "RideSetSettingAction.h" +#include "RideSetVehicleAction.h" static int32_t place_virtual_track( const TrackDesign& td6, uint8_t ptdOperation, bool placeScenery, Ride* ride, const CoordsXYZ& loc) diff --git a/src/openrct2/actions/TrackPlaceAction.cpp b/src/openrct2/actions/TrackPlaceAction.cpp new file mode 100644 index 0000000000..b948a67157 --- /dev/null +++ b/src/openrct2/actions/TrackPlaceAction.cpp @@ -0,0 +1,670 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "TrackPlaceAction.h" + +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../ride/Track.h" +#include "../ride/TrackData.h" +#include "../ride/TrackDesign.h" +#include "../util/Util.h" +#include "../world/MapAnimation.h" +#include "../world/Surface.h" +#include "RideSetSettingAction.h" + +void TrackPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_origin); + visitor.Visit("ride", _rideIndex); + visitor.Visit("trackType", _trackType); + visitor.Visit("brakeSpeed", _brakeSpeed); + visitor.Visit("colour", _colour); + visitor.Visit("seatRotation", _seatRotation); + visitor.Visit("trackPlaceFlags", _trackPlaceFlags); + visitor.Visit("isFromTrackDesign", _fromTrackDesign); +} + +void TrackPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_trackType) << DS_TAG(_origin) << DS_TAG(_brakeSpeed) << DS_TAG(_colour) + << DS_TAG(_seatRotation) << DS_TAG(_trackPlaceFlags); +} + +GameActions::Result::Ptr TrackPlaceAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride for track placement, rideIndex = %d", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid ride subtype for track placement, rideIndex = %d", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (!direction_valid(_origin.direction)) + { + log_warning("Invalid direction for track placement, direction = %d", _origin.direction); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::RideConstruction; + res->Position.x = _origin.x + 16; + res->Position.y = _origin.y + 16; + res->Position.z = _origin.z; + + res->GroundFlags = 0; + + uint32_t rideTypeFlags = RideTypeDescriptors[ride->type].Flags; + + if ((ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) && _trackType == TrackElemType::EndStation) + { + return std::make_unique(GameActions::Status::Disallowed, STR_NOT_ALLOWED_TO_MODIFY_STATION); + } + + if (!(GetActionFlags() & GameActions::Flags::AllowWhilePaused)) + { + if (game_is_paused() && !gCheatsBuildInPauseMode) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED); + } + } + + if (!(rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE)) + { + if (_trackType == TrackElemType::OnRidePhoto) + { + if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_ONLY_ONE_ON_RIDE_PHOTO_PER_RIDE); + } + } + else if (_trackType == TrackElemType::CableLiftHill) + { + if (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_ONLY_ONE_CABLE_LIFT_HILL_PER_RIDE); + } + } + // Backwards steep lift hills are allowed, even on roller coasters that do not support forwards steep lift hills. + if ((_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED) + && !RideTypeDescriptors[ride->type].SupportsTrackPiece(TRACK_LIFT_HILL_STEEP) && !gCheatsEnableChainLiftOnAllTrack) + { + if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_IS_STEEP_UP) + { + return std::make_unique(GameActions::Status::Disallowed, STR_TOO_STEEP_FOR_LIFT_HILL); + } + } + } + + money32 cost = 0; + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, _trackType); + uint32_t numElements = 0; + // First check if any of the track pieces are outside the park + for (; trackBlock->index != 0xFF; trackBlock++) + { + auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), 0 }; + auto tileCoords = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; + + if (!LocationValid(tileCoords) || (!map_is_location_owned(tileCoords) && !gCheatsSandboxMode)) + { + return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + } + numElements++; + } + + if (!map_check_free_elements_and_reorganise(numElements)) + { + log_warning("Not enough free map elments to place track."); + return std::make_unique(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); + } + const uint16_t* trackFlags = (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatTrackFlags : TrackFlags; + if (!gCheatsAllowTrackPlaceInvalidHeights) + { + if (trackFlags[_trackType] & TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT) + { + if ((_origin.z & 0x0F) != 8) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CONSTRUCTION_ERR_UNKNOWN); + } + } + else + { + if ((_origin.z & 0x0F) != 0) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CONSTRUCTION_ERR_UNKNOWN); + } + } + } + + // If that is not the case, then perform the remaining checks + trackBlock = get_track_def_from_ride(ride, _trackType); + + for (int32_t blockIndex = 0; trackBlock->index != 0xFF; trackBlock++, blockIndex++) + { + auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), trackBlock->z }; + auto mapLoc = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; + auto quarterTile = trackBlock->var_08.Rotate(_origin.direction); + + if (mapLoc.z < 16) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_TOO_LOW); + } + + int32_t baseZ = floor2(mapLoc.z, COORDS_Z_STEP); + + int32_t clearanceZ = trackBlock->var_07; + if (trackBlock->flags & RCT_PREVIEW_TRACK_FLAG_IS_VERTICAL + && RideTypeDescriptors[ride->type].Heights.ClearanceHeight > 24) + { + clearanceZ += 24; + } + else + { + clearanceZ += RideTypeDescriptors[ride->type].Heights.ClearanceHeight; + } + + clearanceZ = floor2(clearanceZ, COORDS_Z_STEP) + baseZ; + + if (clearanceZ > MAX_TRACK_HEIGHT) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_TOO_HIGH); + } + + uint8_t crossingMode = (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS) + && _trackType == TrackElemType::Flat) + ? CREATE_CROSSING_MODE_TRACK_OVER_PATH + : CREATE_CROSSING_MODE_NONE; + if (!map_can_construct_with_clear_at( + { mapLoc, baseZ, clearanceZ }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &cost, crossingMode)) + { + return std::make_unique( + GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); + } + + // When building a level crossing, remove any pre-existing path furniture. + if (crossingMode == CREATE_CROSSING_MODE_TRACK_OVER_PATH) + { + auto footpathElement = map_get_footpath_element(mapLoc); + if (footpathElement != nullptr && footpathElement->AsPath()->HasAddition()) + { + footpathElement->AsPath()->SetAddition(0); + } + } + + uint8_t mapGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + if (res->GroundFlags != 0 && (res->GroundFlags & mapGroundFlags) == 0) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); + } + + res->GroundFlags = mapGroundFlags; + if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) + { + if (FlatTrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_ABOVE_GROUND) + { + if (res->GroundFlags & ELEMENT_IS_UNDERGROUND) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + } + } + else + { + if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_ABOVE_GROUND) + { + if (res->GroundFlags & ELEMENT_IS_UNDERGROUND) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + } + } + + if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) + { + if (FlatTrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_UNDERWATER) + { + if (!(gMapGroundFlags & ELEMENT_IS_UNDERWATER)) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_UNDERWATER); + } + } + } + else + { + if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_UNDERWATER) + { // No element has this flag + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_UNDERWATER); + } + } + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER && !gCheatsDisableClearanceChecks) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); + } + + if ((rideTypeFlags & RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER) && !byte_9D8150) + { + auto surfaceElement = map_get_surface_element_at(mapLoc); + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + auto waterHeight = surfaceElement->GetWaterHeight(); + if (waterHeight == 0) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); + } + + if (waterHeight != baseZ) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); + } + waterHeight -= LAND_HEIGHT_STEP; + if (waterHeight == surfaceElement->GetBaseZ()) + { + uint8_t slope = surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP; + if (slope == TILE_ELEMENT_SLOPE_W_CORNER_DN || slope == TILE_ELEMENT_SLOPE_S_CORNER_DN + || slope == TILE_ELEMENT_SLOPE_E_CORNER_DN || slope == TILE_ELEMENT_SLOPE_N_CORNER_DN) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); + } + } + } + + int32_t entranceDirections; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; + } + else + { + entranceDirections = TrackSequenceProperties[_trackType][0]; + } + if ((entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN) && trackBlock->index == 0) + { + if (!track_add_station_element({ mapLoc, baseZ, _origin.direction }, _rideIndex, 0, _fromTrackDesign)) + { + return std::make_unique(GameActions::Status::Unknown, gGameCommandErrorText); + } + } + + // 6c5648 12 push + auto surfaceElement = map_get_surface_element_at(mapLoc); + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (!gCheatsDisableSupportLimits) + { + int32_t ride_height = clearanceZ - surfaceElement->GetBaseZ(); + if (ride_height >= 0) + { + uint16_t maxHeight; + + if (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY) + && rideEntry->max_height != 0) + { + maxHeight = rideEntry->max_height; + } + else + { + maxHeight = RideTypeDescriptors[ride->type].Heights.MaxHeight; + } + + ride_height /= COORDS_Z_PER_TINY_Z; + if (ride_height > maxHeight && !byte_9D8150) + { + return std::make_unique(GameActions::Status::Disallowed, STR_TOO_HIGH_FOR_SUPPORTS); + } + } + } + + int32_t supportHeight = baseZ - surfaceElement->GetBaseZ(); + if (supportHeight < 0) + { + supportHeight = (10 * COORDS_Z_STEP); + } + + cost += ((supportHeight / (2 * COORDS_Z_STEP)) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice) * 5; + } + + money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; + price *= (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatRideTrackPricing[_trackType] : TrackPricing[_trackType]; + + price >>= 16; + res->Cost = cost + ((price / 2) * 10); + return res; +} + +GameActions::Result::Ptr TrackPlaceAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride for track placement, rideIndex = %d", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid ride subtype for track placement, rideIndex = %d", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::RideConstruction; + res->Position.x = _origin.x + 16; + res->Position.y = _origin.y + 16; + res->Position.z = _origin.z; + + res->GroundFlags = 0; + + uint32_t rideTypeFlags = RideTypeDescriptors[ride->type].Flags; + + const uint8_t(*wallEdges)[16]; + if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) + { + wallEdges = &FlatRideTrackSequenceElementAllowedWallEdges[_trackType]; + } + else + { + wallEdges = &TrackSequenceElementAllowedWallEdges[_trackType]; + } + + money32 cost = 0; + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, _trackType); + + trackBlock = get_track_def_from_ride(ride, _trackType); + for (int32_t blockIndex = 0; trackBlock->index != 0xFF; trackBlock++, blockIndex++) + { + auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), trackBlock->z }; + auto mapLoc = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; + + auto quarterTile = trackBlock->var_08.Rotate(_origin.direction); + + int32_t baseZ = floor2(mapLoc.z, COORDS_Z_STEP); + int32_t clearanceZ = trackBlock->var_07; + if (trackBlock->flags & RCT_PREVIEW_TRACK_FLAG_IS_VERTICAL + && RideTypeDescriptors[ride->type].Heights.ClearanceHeight > 24) + { + clearanceZ += 24; + } + else + { + clearanceZ += RideTypeDescriptors[ride->type].Heights.ClearanceHeight; + } + + clearanceZ = floor2(clearanceZ, COORDS_Z_STEP) + baseZ; + const auto mapLocWithClearance = CoordsXYRangedZ(mapLoc, baseZ, clearanceZ); + + uint8_t crossingMode = (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS) + && _trackType == TrackElemType::Flat) + ? CREATE_CROSSING_MODE_TRACK_OVER_PATH + : CREATE_CROSSING_MODE_NONE; + if (!map_can_construct_with_clear_at( + mapLocWithClearance, &map_place_non_scenery_clear_func, quarterTile, GetFlags() | GAME_COMMAND_FLAG_APPLY, + &cost, crossingMode)) + { + return std::make_unique( + GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsDisableClearanceChecks) + { + footpath_remove_litter(mapLoc); + if (rideTypeFlags & RIDE_TYPE_FLAG_TRACK_NO_WALLS) + { + wall_remove_at(mapLocWithClearance); + } + else + { + // Remove walls in the directions this track intersects + uint8_t intersectingDirections = (*wallEdges)[blockIndex]; + intersectingDirections ^= 0x0F; + intersectingDirections = rol4(intersectingDirections, _origin.direction); + for (int32_t i = 0; i < NumOrthogonalDirections; i++) + { + if (intersectingDirections & (1 << i)) + { + wall_remove_intersecting_walls(mapLocWithClearance, i); + } + } + } + } + + uint8_t mapGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + if (res->GroundFlags != 0 && (res->GroundFlags & mapGroundFlags) == 0) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); + } + + res->GroundFlags = mapGroundFlags; + + // 6c5648 12 push + auto surfaceElement = map_get_surface_element_at(mapLoc); + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + int32_t supportHeight = baseZ - surfaceElement->GetBaseZ(); + if (supportHeight < 0) + { + supportHeight = (10 * COORDS_Z_STEP); + } + + cost += ((supportHeight / (2 * COORDS_Z_STEP)) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice) * 5; + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + invalidate_test_results(ride); + switch (_trackType) + { + case TrackElemType::OnRidePhoto: + ride->lifecycle_flags |= RIDE_LIFECYCLE_ON_RIDE_PHOTO; + break; + case TrackElemType::CableLiftHill: + if (trackBlock->index != 0) + break; + ride->lifecycle_flags |= RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED; + ride->CableLiftLoc = mapLoc; + break; + case TrackElemType::BlockBrakes: + { + ride->num_block_brakes++; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_OPERATING; + + RideMode newMode = RideMode::ContinuousCircuitBlockSectioned; + if (ride->type == RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER) + newMode = RideMode::PoweredLaunchBlockSectioned; + + auto rideSetSetting = RideSetSettingAction(ride->id, RideSetSetting::Mode, static_cast(newMode)); + GameActions::ExecuteNested(&rideSetSetting); + break; + } + } + + if (trackBlock->index == 0) + { + switch (_trackType) + { + case TrackElemType::Up25ToFlat: + case TrackElemType::Up60ToFlat: + case TrackElemType::DiagUp25ToFlat: + case TrackElemType::DiagUp60ToFlat: + if (!(_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED)) + break; + [[fallthrough]]; + case TrackElemType::CableLiftHill: + ride->num_block_brakes++; + break; + } + } + } + + int32_t entranceDirections = 0; + if (!ride->overall_view.isNull()) + { + if (!(GetFlags() & GAME_COMMAND_FLAG_NO_SPEND)) + { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; + } + else + { + entranceDirections = TrackSequenceProperties[_trackType][0]; + } + } + } + + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN || ride->overall_view.isNull()) + { + ride->overall_view = mapLoc; + } + + auto tileElement = tile_element_insert(mapLoc, quarterTile.GetBaseQuarterOccupied()); + assert(tileElement != nullptr); + tileElement->SetClearanceZ(clearanceZ); + tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); + tileElement->SetDirection(_origin.direction); + if (_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED) + { + tileElement->AsTrack()->SetHasChain(true); + } + + tileElement->AsTrack()->SetSequenceIndex(trackBlock->index); + tileElement->AsTrack()->SetRideIndex(_rideIndex); + tileElement->AsTrack()->SetTrackType(_trackType); + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + tileElement->SetGhost(true); + } + + switch (_trackType) + { + case TrackElemType::Waterfall: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_WATERFALL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + break; + case TrackElemType::Rapids: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_RAPIDS, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + break; + case TrackElemType::Whirlpool: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + break; + case TrackElemType::SpinningTunnel: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + break; + } + if (TrackTypeHasSpeedSetting(_trackType)) + { + tileElement->AsTrack()->SetBrakeBoosterSpeed(_brakeSpeed); + } + else + { + tileElement->AsTrack()->SetSeatRotation(_seatRotation); + } + + if (_trackPlaceFlags & RIDE_TYPE_ALTERNATIVE_TRACK_TYPE) + { + tileElement->AsTrack()->SetInverted(true); + } + tileElement->AsTrack()->SetColourScheme(_colour); + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; + } + else + { + entranceDirections = TrackSequenceProperties[_trackType][0]; + } + + if (entranceDirections & TRACK_SEQUENCE_FLAG_CONNECTS_TO_PATH) + { + uint8_t availableDirections = entranceDirections & 0x0F; + if (availableDirections != 0) + { + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsDisableClearanceChecks) + { + for (int32_t chosenDirection = bitscanforward(availableDirections); chosenDirection != -1; + chosenDirection = bitscanforward(availableDirections)) + { + availableDirections &= ~(1 << chosenDirection); + CoordsXY tempLoc{ mapLoc.x, mapLoc.y }; + int32_t tempDirection = (_origin.direction + chosenDirection) & 3; + tempLoc.x += CoordsDirectionDelta[tempDirection].x; + tempLoc.y += CoordsDirectionDelta[tempDirection].y; + tempDirection = direction_reverse(tempDirection); + wall_remove_intersecting_walls({ tempLoc, baseZ, clearanceZ }, tempDirection & 3); + } + } + } + } + + // If the placed tile is a station modify station properties. + // Don't do this if the ride is simulating and the tile is a ghost to prevent desyncs. + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN + && !(ride->status == RIDE_STATUS_SIMULATING && GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + if (trackBlock->index == 0) + { + track_add_station_element({ mapLoc, _origin.direction }, _rideIndex, GAME_COMMAND_FLAG_APPLY, _fromTrackDesign); + } + sub_6CB945(ride); + ride->UpdateMaxVehicles(); + } + + if (rideTypeFlags & RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER) + { + auto* waterSurfaceElement = map_get_surface_element_at(mapLoc); + if (waterSurfaceElement != nullptr) + { + waterSurfaceElement->SetHasTrackThatNeedsWater(true); + tileElement = reinterpret_cast(waterSurfaceElement); + } + } + + if (!gCheatsDisableClearanceChecks || !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_connect_edges(mapLoc, tileElement, GetFlags()); + } + map_invalidate_tile_full(mapLoc); + } + + money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; + price *= (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatRideTrackPricing[_trackType] : TrackPricing[_trackType]; + + price >>= 16; + res->Cost = cost + ((price / 2) * 10); + return res; +} diff --git a/src/openrct2/actions/TrackPlaceAction.h b/src/openrct2/actions/TrackPlaceAction.h new file mode 100644 index 0000000000..5f74f1c8e3 --- /dev/null +++ b/src/openrct2/actions/TrackPlaceAction.h @@ -0,0 +1,76 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +class TrackPlaceActionResult final : public GameActions::Result +{ +public: + TrackPlaceActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE) + { + } + TrackPlaceActionResult(GameActions::Status error) + : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE) + { + } + TrackPlaceActionResult(GameActions::Status error, rct_string_id message) + : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message) + { + } + TrackPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) + : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message, args) + { + } + + uint8_t GroundFlags{ 0 }; +}; + +DEFINE_GAME_ACTION(TrackPlaceAction, GAME_COMMAND_PLACE_TRACK, TrackPlaceActionResult) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + int32_t _trackType{}; + CoordsXYZD _origin; + int32_t _brakeSpeed{}; + int32_t _colour{}; + int32_t _seatRotation{}; + int32_t _trackPlaceFlags{}; + bool _fromTrackDesign{}; + +public: + TrackPlaceAction() = default; + TrackPlaceAction( + NetworkRideId_t rideIndex, int32_t trackType, const CoordsXYZD& origin, int32_t brakeSpeed, int32_t colour, + int32_t seatRotation, int32_t liftHillAndAlternativeState, bool fromTrackDesign) + : _rideIndex(rideIndex) + , _trackType(trackType) + , _origin(origin) + , _brakeSpeed(brakeSpeed) + , _colour(colour) + , _seatRotation(seatRotation) + , _trackPlaceFlags(liftHillAndAlternativeState) + , _fromTrackDesign(fromTrackDesign) + { + _origin.direction &= 3; + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override final + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/TrackPlaceAction.hpp b/src/openrct2/actions/TrackPlaceAction.hpp deleted file mode 100644 index 417a7a60fb..0000000000 --- a/src/openrct2/actions/TrackPlaceAction.hpp +++ /dev/null @@ -1,736 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../ride/RideData.h" -#include "../ride/Track.h" -#include "../ride/TrackData.h" -#include "../ride/TrackDesign.h" -#include "../util/Util.h" -#include "../world/MapAnimation.h" -#include "../world/Surface.h" -#include "GameAction.h" -#include "RideSetSetting.hpp" - -class TrackPlaceActionResult final : public GameActions::Result -{ -public: - TrackPlaceActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE) - { - } - TrackPlaceActionResult(GameActions::Status error) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE) - { - } - TrackPlaceActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message) - { - } - TrackPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message, args) - { - } - - uint8_t GroundFlags{ 0 }; -}; - -DEFINE_GAME_ACTION(TrackPlaceAction, GAME_COMMAND_PLACE_TRACK, TrackPlaceActionResult) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - int32_t _trackType{}; - CoordsXYZD _origin; - int32_t _brakeSpeed{}; - int32_t _colour{}; - int32_t _seatRotation{}; - int32_t _trackPlaceFlags{}; - bool _fromTrackDesign{}; - -public: - TrackPlaceAction() = default; - TrackPlaceAction( - NetworkRideId_t rideIndex, int32_t trackType, const CoordsXYZD& origin, int32_t brakeSpeed, int32_t colour, - int32_t seatRotation, int32_t liftHillAndAlternativeState, bool fromTrackDesign) - : _rideIndex(rideIndex) - , _trackType(trackType) - , _origin(origin) - , _brakeSpeed(brakeSpeed) - , _colour(colour) - , _seatRotation(seatRotation) - , _trackPlaceFlags(liftHillAndAlternativeState) - , _fromTrackDesign(fromTrackDesign) - { - _origin.direction &= 3; - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_origin); - visitor.Visit("ride", _rideIndex); - visitor.Visit("trackType", _trackType); - visitor.Visit("brakeSpeed", _brakeSpeed); - visitor.Visit("colour", _colour); - visitor.Visit("seatRotation", _seatRotation); - visitor.Visit("trackPlaceFlags", _trackPlaceFlags); - visitor.Visit("isFromTrackDesign", _fromTrackDesign); - } - - uint16_t GetActionFlags() const override final - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_trackType) << DS_TAG(_origin) << DS_TAG(_brakeSpeed) << DS_TAG(_colour) - << DS_TAG(_seatRotation) << DS_TAG(_trackPlaceFlags); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride for track placement, rideIndex = %d", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid ride subtype for track placement, rideIndex = %d", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (!direction_valid(_origin.direction)) - { - log_warning("Invalid direction for track placement, direction = %d", _origin.direction); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::RideConstruction; - res->Position.x = _origin.x + 16; - res->Position.y = _origin.y + 16; - res->Position.z = _origin.z; - - res->GroundFlags = 0; - - uint32_t rideTypeFlags = RideTypeDescriptors[ride->type].Flags; - - if ((ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) && _trackType == TrackElemType::EndStation) - { - return std::make_unique(GameActions::Status::Disallowed, STR_NOT_ALLOWED_TO_MODIFY_STATION); - } - - if (!(GetActionFlags() & GameActions::Flags::AllowWhilePaused)) - { - if (game_is_paused() && !gCheatsBuildInPauseMode) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED); - } - } - - if (!(rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE)) - { - if (_trackType == TrackElemType::OnRidePhoto) - { - if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_ONLY_ONE_ON_RIDE_PHOTO_PER_RIDE); - } - } - else if (_trackType == TrackElemType::CableLiftHill) - { - if (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_ONLY_ONE_CABLE_LIFT_HILL_PER_RIDE); - } - } - // Backwards steep lift hills are allowed, even on roller coasters that do not support forwards steep lift hills. - if ((_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED) - && !RideTypeDescriptors[ride->type].SupportsTrackPiece(TRACK_LIFT_HILL_STEEP) - && !gCheatsEnableChainLiftOnAllTrack) - { - if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_IS_STEEP_UP) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_TOO_STEEP_FOR_LIFT_HILL); - } - } - } - - money32 cost = 0; - const rct_preview_track* trackBlock = get_track_def_from_ride(ride, _trackType); - uint32_t numElements = 0; - // First check if any of the track pieces are outside the park - for (; trackBlock->index != 0xFF; trackBlock++) - { - auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), 0 }; - auto tileCoords = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; - - if (!LocationValid(tileCoords) || (!map_is_location_owned(tileCoords) && !gCheatsSandboxMode)) - { - return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - } - numElements++; - } - - if (!map_check_free_elements_and_reorganise(numElements)) - { - log_warning("Not enough free map elments to place track."); - return std::make_unique( - GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); - } - const uint16_t* trackFlags = (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatTrackFlags : TrackFlags; - if (!gCheatsAllowTrackPlaceInvalidHeights) - { - if (trackFlags[_trackType] & TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT) - { - if ((_origin.z & 0x0F) != 8) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CONSTRUCTION_ERR_UNKNOWN); - } - } - else - { - if ((_origin.z & 0x0F) != 0) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CONSTRUCTION_ERR_UNKNOWN); - } - } - } - - // If that is not the case, then perform the remaining checks - trackBlock = get_track_def_from_ride(ride, _trackType); - - for (int32_t blockIndex = 0; trackBlock->index != 0xFF; trackBlock++, blockIndex++) - { - auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), trackBlock->z }; - auto mapLoc = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; - auto quarterTile = trackBlock->var_08.Rotate(_origin.direction); - - if (mapLoc.z < 16) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_TOO_LOW); - } - - int32_t baseZ = floor2(mapLoc.z, COORDS_Z_STEP); - - int32_t clearanceZ = trackBlock->var_07; - if (trackBlock->flags & RCT_PREVIEW_TRACK_FLAG_IS_VERTICAL - && RideTypeDescriptors[ride->type].Heights.ClearanceHeight > 24) - { - clearanceZ += 24; - } - else - { - clearanceZ += RideTypeDescriptors[ride->type].Heights.ClearanceHeight; - } - - clearanceZ = floor2(clearanceZ, COORDS_Z_STEP) + baseZ; - - if (clearanceZ > MAX_TRACK_HEIGHT) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_TOO_HIGH); - } - - uint8_t crossingMode = (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS) - && _trackType == TrackElemType::Flat) - ? CREATE_CROSSING_MODE_TRACK_OVER_PATH - : CREATE_CROSSING_MODE_NONE; - if (!map_can_construct_with_clear_at( - { mapLoc, baseZ, clearanceZ }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &cost, - crossingMode)) - { - return std::make_unique( - GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); - } - - // When building a level crossing, remove any pre-existing path furniture. - if (crossingMode == CREATE_CROSSING_MODE_TRACK_OVER_PATH) - { - auto footpathElement = map_get_footpath_element(mapLoc); - if (footpathElement != nullptr && footpathElement->AsPath()->HasAddition()) - { - footpathElement->AsPath()->SetAddition(0); - } - } - - uint8_t mapGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - if (res->GroundFlags != 0 && (res->GroundFlags & mapGroundFlags) == 0) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); - } - - res->GroundFlags = mapGroundFlags; - if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) - { - if (FlatTrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_ABOVE_GROUND) - { - if (res->GroundFlags & ELEMENT_IS_UNDERGROUND) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - } - } - else - { - if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_ABOVE_GROUND) - { - if (res->GroundFlags & ELEMENT_IS_UNDERGROUND) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - } - } - - if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) - { - if (FlatTrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_UNDERWATER) - { - if (!(gMapGroundFlags & ELEMENT_IS_UNDERWATER)) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_UNDERWATER); - } - } - } - else - { - if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_UNDERWATER) - { // No element has this flag - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_UNDERWATER); - } - } - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER && !gCheatsDisableClearanceChecks) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); - } - - if ((rideTypeFlags & RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER) && !byte_9D8150) - { - auto surfaceElement = map_get_surface_element_at(mapLoc); - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - auto waterHeight = surfaceElement->GetWaterHeight(); - if (waterHeight == 0) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); - } - - if (waterHeight != baseZ) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); - } - waterHeight -= LAND_HEIGHT_STEP; - if (waterHeight == surfaceElement->GetBaseZ()) - { - uint8_t slope = surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP; - if (slope == TILE_ELEMENT_SLOPE_W_CORNER_DN || slope == TILE_ELEMENT_SLOPE_S_CORNER_DN - || slope == TILE_ELEMENT_SLOPE_E_CORNER_DN || slope == TILE_ELEMENT_SLOPE_N_CORNER_DN) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); - } - } - } - - int32_t entranceDirections; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; - } - else - { - entranceDirections = TrackSequenceProperties[_trackType][0]; - } - if ((entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN) && trackBlock->index == 0) - { - if (!track_add_station_element({ mapLoc, baseZ, _origin.direction }, _rideIndex, 0, _fromTrackDesign)) - { - return std::make_unique(GameActions::Status::Unknown, gGameCommandErrorText); - } - } - - // 6c5648 12 push - auto surfaceElement = map_get_surface_element_at(mapLoc); - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (!gCheatsDisableSupportLimits) - { - int32_t ride_height = clearanceZ - surfaceElement->GetBaseZ(); - if (ride_height >= 0) - { - uint16_t maxHeight; - - if (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY) - && rideEntry->max_height != 0) - { - maxHeight = rideEntry->max_height; - } - else - { - maxHeight = RideTypeDescriptors[ride->type].Heights.MaxHeight; - } - - ride_height /= COORDS_Z_PER_TINY_Z; - if (ride_height > maxHeight && !byte_9D8150) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_TOO_HIGH_FOR_SUPPORTS); - } - } - } - - int32_t supportHeight = baseZ - surfaceElement->GetBaseZ(); - if (supportHeight < 0) - { - supportHeight = (10 * COORDS_Z_STEP); - } - - cost += ((supportHeight / (2 * COORDS_Z_STEP)) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice) * 5; - } - - money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; - price *= (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatRideTrackPricing[_trackType] : TrackPricing[_trackType]; - - price >>= 16; - res->Cost = cost + ((price / 2) * 10); - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride for track placement, rideIndex = %d", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid ride subtype for track placement, rideIndex = %d", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::RideConstruction; - res->Position.x = _origin.x + 16; - res->Position.y = _origin.y + 16; - res->Position.z = _origin.z; - - res->GroundFlags = 0; - - uint32_t rideTypeFlags = RideTypeDescriptors[ride->type].Flags; - - const uint8_t(*wallEdges)[16]; - if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) - { - wallEdges = &FlatRideTrackSequenceElementAllowedWallEdges[_trackType]; - } - else - { - wallEdges = &TrackSequenceElementAllowedWallEdges[_trackType]; - } - - money32 cost = 0; - const rct_preview_track* trackBlock = get_track_def_from_ride(ride, _trackType); - - trackBlock = get_track_def_from_ride(ride, _trackType); - for (int32_t blockIndex = 0; trackBlock->index != 0xFF; trackBlock++, blockIndex++) - { - auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), trackBlock->z }; - auto mapLoc = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; - - auto quarterTile = trackBlock->var_08.Rotate(_origin.direction); - - int32_t baseZ = floor2(mapLoc.z, COORDS_Z_STEP); - int32_t clearanceZ = trackBlock->var_07; - if (trackBlock->flags & RCT_PREVIEW_TRACK_FLAG_IS_VERTICAL - && RideTypeDescriptors[ride->type].Heights.ClearanceHeight > 24) - { - clearanceZ += 24; - } - else - { - clearanceZ += RideTypeDescriptors[ride->type].Heights.ClearanceHeight; - } - - clearanceZ = floor2(clearanceZ, COORDS_Z_STEP) + baseZ; - const auto mapLocWithClearance = CoordsXYRangedZ(mapLoc, baseZ, clearanceZ); - - uint8_t crossingMode = (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS) - && _trackType == TrackElemType::Flat) - ? CREATE_CROSSING_MODE_TRACK_OVER_PATH - : CREATE_CROSSING_MODE_NONE; - if (!map_can_construct_with_clear_at( - mapLocWithClearance, &map_place_non_scenery_clear_func, quarterTile, GetFlags() | GAME_COMMAND_FLAG_APPLY, - &cost, crossingMode)) - { - return std::make_unique( - GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsDisableClearanceChecks) - { - footpath_remove_litter(mapLoc); - if (rideTypeFlags & RIDE_TYPE_FLAG_TRACK_NO_WALLS) - { - wall_remove_at(mapLocWithClearance); - } - else - { - // Remove walls in the directions this track intersects - uint8_t intersectingDirections = (*wallEdges)[blockIndex]; - intersectingDirections ^= 0x0F; - intersectingDirections = rol4(intersectingDirections, _origin.direction); - for (int32_t i = 0; i < NumOrthogonalDirections; i++) - { - if (intersectingDirections & (1 << i)) - { - wall_remove_intersecting_walls(mapLocWithClearance, i); - } - } - } - } - - uint8_t mapGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - if (res->GroundFlags != 0 && (res->GroundFlags & mapGroundFlags) == 0) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); - } - - res->GroundFlags = mapGroundFlags; - - // 6c5648 12 push - auto surfaceElement = map_get_surface_element_at(mapLoc); - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - int32_t supportHeight = baseZ - surfaceElement->GetBaseZ(); - if (supportHeight < 0) - { - supportHeight = (10 * COORDS_Z_STEP); - } - - cost += ((supportHeight / (2 * COORDS_Z_STEP)) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice) * 5; - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - invalidate_test_results(ride); - switch (_trackType) - { - case TrackElemType::OnRidePhoto: - ride->lifecycle_flags |= RIDE_LIFECYCLE_ON_RIDE_PHOTO; - break; - case TrackElemType::CableLiftHill: - if (trackBlock->index != 0) - break; - ride->lifecycle_flags |= RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED; - ride->CableLiftLoc = mapLoc; - break; - case TrackElemType::BlockBrakes: - { - ride->num_block_brakes++; - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_OPERATING; - - RideMode newMode = RideMode::ContinuousCircuitBlockSectioned; - if (ride->type == RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER) - newMode = RideMode::PoweredLaunchBlockSectioned; - - auto rideSetSetting = RideSetSettingAction( - ride->id, RideSetSetting::Mode, static_cast(newMode)); - GameActions::ExecuteNested(&rideSetSetting); - break; - } - } - - if (trackBlock->index == 0) - { - switch (_trackType) - { - case TrackElemType::Up25ToFlat: - case TrackElemType::Up60ToFlat: - case TrackElemType::DiagUp25ToFlat: - case TrackElemType::DiagUp60ToFlat: - if (!(_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED)) - break; - [[fallthrough]]; - case TrackElemType::CableLiftHill: - ride->num_block_brakes++; - break; - } - } - } - - int32_t entranceDirections = 0; - if (!ride->overall_view.isNull()) - { - if (!(GetFlags() & GAME_COMMAND_FLAG_NO_SPEND)) - { - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; - } - else - { - entranceDirections = TrackSequenceProperties[_trackType][0]; - } - } - } - - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN || ride->overall_view.isNull()) - { - ride->overall_view = mapLoc; - } - - auto tileElement = tile_element_insert(mapLoc, quarterTile.GetBaseQuarterOccupied()); - assert(tileElement != nullptr); - tileElement->SetClearanceZ(clearanceZ); - tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); - tileElement->SetDirection(_origin.direction); - if (_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED) - { - tileElement->AsTrack()->SetHasChain(true); - } - - tileElement->AsTrack()->SetSequenceIndex(trackBlock->index); - tileElement->AsTrack()->SetRideIndex(_rideIndex); - tileElement->AsTrack()->SetTrackType(_trackType); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } - - switch (_trackType) - { - case TrackElemType::Waterfall: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_WATERFALL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); - break; - case TrackElemType::Rapids: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_RAPIDS, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); - break; - case TrackElemType::Whirlpool: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); - break; - case TrackElemType::SpinningTunnel: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); - break; - } - if (TrackTypeHasSpeedSetting(_trackType)) - { - tileElement->AsTrack()->SetBrakeBoosterSpeed(_brakeSpeed); - } - else - { - tileElement->AsTrack()->SetSeatRotation(_seatRotation); - } - - if (_trackPlaceFlags & RIDE_TYPE_ALTERNATIVE_TRACK_TYPE) - { - tileElement->AsTrack()->SetInverted(true); - } - tileElement->AsTrack()->SetColourScheme(_colour); - - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; - } - else - { - entranceDirections = TrackSequenceProperties[_trackType][0]; - } - - if (entranceDirections & TRACK_SEQUENCE_FLAG_CONNECTS_TO_PATH) - { - uint8_t availableDirections = entranceDirections & 0x0F; - if (availableDirections != 0) - { - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsDisableClearanceChecks) - { - for (int32_t chosenDirection = bitscanforward(availableDirections); chosenDirection != -1; - chosenDirection = bitscanforward(availableDirections)) - { - availableDirections &= ~(1 << chosenDirection); - CoordsXY tempLoc{ mapLoc.x, mapLoc.y }; - int32_t tempDirection = (_origin.direction + chosenDirection) & 3; - tempLoc.x += CoordsDirectionDelta[tempDirection].x; - tempLoc.y += CoordsDirectionDelta[tempDirection].y; - tempDirection = direction_reverse(tempDirection); - wall_remove_intersecting_walls({ tempLoc, baseZ, clearanceZ }, tempDirection & 3); - } - } - } - } - - // If the placed tile is a station modify station properties. - // Don't do this if the ride is simulating and the tile is a ghost to prevent desyncs. - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN - && !(ride->status == RIDE_STATUS_SIMULATING && GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - if (trackBlock->index == 0) - { - track_add_station_element( - { mapLoc, _origin.direction }, _rideIndex, GAME_COMMAND_FLAG_APPLY, _fromTrackDesign); - } - sub_6CB945(ride); - ride->UpdateMaxVehicles(); - } - - if (rideTypeFlags & RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER) - { - auto* waterSurfaceElement = map_get_surface_element_at(mapLoc); - if (waterSurfaceElement != nullptr) - { - waterSurfaceElement->SetHasTrackThatNeedsWater(true); - tileElement = reinterpret_cast(waterSurfaceElement); - } - } - - if (!gCheatsDisableClearanceChecks || !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_connect_edges(mapLoc, tileElement, GetFlags()); - } - map_invalidate_tile_full(mapLoc); - } - - money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; - price *= (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatRideTrackPricing[_trackType] : TrackPricing[_trackType]; - - price >>= 16; - res->Cost = cost + ((price / 2) * 10); - return res; - } -}; diff --git a/src/openrct2/actions/TrackRemoveAction.cpp b/src/openrct2/actions/TrackRemoveAction.cpp new file mode 100644 index 0000000000..bab512fa74 --- /dev/null +++ b/src/openrct2/actions/TrackRemoveAction.cpp @@ -0,0 +1,505 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "TrackRemoveAction.h" + +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../ride/Track.h" +#include "../ride/TrackData.h" +#include "../ride/TrackDesign.h" +#include "../util/Util.h" +#include "../world/MapAnimation.h" +#include "../world/Surface.h" +#include "RideSetSettingAction.h" + +void TrackRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_origin); + visitor.Visit("trackType", _trackType); + visitor.Visit("sequence", _sequence); +} + +void TrackRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_trackType) << DS_TAG(_sequence) << DS_TAG(_origin); +} + +GameActions::Result::Ptr TrackRemoveAction::Query() const +{ + auto res = MakeResult(); + res->Position.x = _origin.x + 16; + res->Position.y = _origin.y + 16; + res->Position.z = _origin.z; + res->Expenditure = ExpenditureType::RideConstruction; + + // Stations require some massaging of the track type for comparing + auto comparableTrackType = _trackType; + switch (_trackType) + { + case TrackElemType::BeginStation: + case TrackElemType::MiddleStation: + comparableTrackType = TrackElemType::EndStation; + break; + } + + bool found = false; + bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; + TileElement* tileElement = map_get_first_element_at(_origin); + + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetBaseZ() != _origin.z) + continue; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if ((tileElement->GetDirection()) != _origin.direction) + continue; + + if (tileElement->AsTrack()->GetSequenceIndex() != _sequence) + continue; + + if (tileElement->IsGhost() != isGhost) + continue; + + auto tileTrackType = tileElement->AsTrack()->GetTrackType(); + switch (tileTrackType) + { + case TrackElemType::BeginStation: + case TrackElemType::MiddleStation: + tileTrackType = TrackElemType::EndStation; + break; + } + + if (tileTrackType != comparableTrackType) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", _origin.x, _origin.y, _origin.z, + _origin.direction, _sequence); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + if (tileElement->AsTrack()->IsIndestructible()) + { + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, + STR_YOU_ARE_NOT_ALLOWED_TO_REMOVE_THIS_SECTION); + } + + ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); + auto trackType = tileElement->AsTrack()->GetTrackType(); + + auto ride = get_ride(rideIndex); + if (ride == nullptr) + { + log_warning("Ride not found. ride index = %d.", rideIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + if (ride->type >= RIDE_TYPE_COUNT) + { + log_warning("Ride type not found. ride type = %d.", ride->type); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, trackType); + trackBlock += tileElement->AsTrack()->GetSequenceIndex(); + + auto startLoc = _origin; + startLoc.direction = tileElement->GetDirection(); + + auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; + startLoc.x -= rotatedTrack.x; + startLoc.y -= rotatedTrack.y; + startLoc.z -= rotatedTrack.z; + res->Position.x = startLoc.x; + res->Position.y = startLoc.y; + res->Position.z = startLoc.z; + + money32 cost = 0; + + trackBlock = get_track_def_from_ride(ride, trackType); + for (; trackBlock->index != 255; trackBlock++) + { + rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; + auto mapLoc = CoordsXYZ{ startLoc.x, startLoc.y, startLoc.z } + rotatedTrack; + + if (!LocationValid(mapLoc)) + { + return MakeResult( + GameActions::Status::NotOwned, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + map_invalidate_tile_full(mapLoc); + + found = false; + tileElement = map_get_first_element_at(mapLoc); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetBaseZ() != mapLoc.z) + continue; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if (tileElement->GetDirection() != _origin.direction) + continue; + + if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) + continue; + + if (tileElement->AsTrack()->GetTrackType() != trackType) + continue; + + if (tileElement->IsGhost() != isGhost) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", mapLoc.x, mapLoc.y, mapLoc.z, + _origin.direction, trackBlock->index); + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + int32_t entranceDirections; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + entranceDirections = FlatRideTrackSequenceProperties[trackType][0]; + } + else + { + entranceDirections = TrackSequenceProperties[trackType][0]; + } + + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN && (tileElement->AsTrack()->GetSequenceIndex() == 0)) + { + if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, 0)) + { + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); + } + } + + auto* surfaceElement = map_get_surface_element_at(mapLoc); + if (surfaceElement == nullptr) + { + log_warning("Surface Element not found. x = %d, y = %d", mapLoc.x, mapLoc.y); + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + int8_t _support_height = tileElement->base_height - surfaceElement->base_height; + if (_support_height < 0) + { + _support_height = 10; + } + + cost += (_support_height / 2) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice; + } + + money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + price *= FlatRideTrackPricing[trackType]; + } + else + { + price *= TrackPricing[trackType]; + } + price >>= 16; + price = (price + cost) / 2; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) + price *= -7; + else + price *= -10; + + res->Cost = price; + return res; +} + +GameActions::Result::Ptr TrackRemoveAction::Execute() const +{ + auto res = MakeResult(); + res->Position.x = _origin.x + 16; + res->Position.y = _origin.y + 16; + res->Position.z = _origin.z; + res->Expenditure = ExpenditureType::RideConstruction; + + // Stations require some massaging of the track type for comparing + auto comparableTrackType = _trackType; + switch (_trackType) + { + case TrackElemType::BeginStation: + case TrackElemType::MiddleStation: + comparableTrackType = TrackElemType::EndStation; + break; + } + + bool found = false; + bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; + TileElement* tileElement = map_get_first_element_at(_origin); + + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetBaseZ() != _origin.z) + continue; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if ((tileElement->GetDirection()) != _origin.direction) + continue; + + if (tileElement->AsTrack()->GetSequenceIndex() != _sequence) + continue; + + if (tileElement->IsGhost() != isGhost) + continue; + + auto tileTrackType = tileElement->AsTrack()->GetTrackType(); + switch (tileTrackType) + { + case TrackElemType::BeginStation: + case TrackElemType::MiddleStation: + tileTrackType = TrackElemType::EndStation; + break; + } + + if (tileTrackType != comparableTrackType) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", _origin.x, _origin.y, _origin.z, + _origin.direction, _sequence); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); + auto trackType = tileElement->AsTrack()->GetTrackType(); + bool isLiftHill = tileElement->AsTrack()->HasChain(); + + auto ride = get_ride(rideIndex); + if (ride == nullptr) + { + log_warning("Ride not found. ride index = %d.", rideIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, trackType); + trackBlock += tileElement->AsTrack()->GetSequenceIndex(); + + auto startLoc = _origin; + startLoc.direction = tileElement->GetDirection(); + + auto rotatedTrackLoc = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; + startLoc.x -= rotatedTrackLoc.x; + startLoc.y -= rotatedTrackLoc.y; + startLoc.z -= rotatedTrackLoc.z; + res->Position.x = startLoc.x; + res->Position.y = startLoc.y; + res->Position.z = startLoc.z; + money32 cost = 0; + + trackBlock = get_track_def_from_ride(ride, trackType); + for (; trackBlock->index != 255; trackBlock++) + { + rotatedTrackLoc = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; + auto mapLoc = CoordsXYZ{ startLoc.x, startLoc.y, startLoc.z } + rotatedTrackLoc; + + map_invalidate_tile_full(mapLoc); + + found = false; + tileElement = map_get_first_element_at(mapLoc); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetBaseZ() != mapLoc.z) + continue; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if (tileElement->GetDirection() != _origin.direction) + continue; + + if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) + continue; + + if (tileElement->AsTrack()->GetTrackType() != trackType) + continue; + + if (tileElement->IsGhost() != isGhost) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", mapLoc.x, mapLoc.y, mapLoc.z, + _origin.direction, trackBlock->index); + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + int32_t entranceDirections; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + entranceDirections = FlatRideTrackSequenceProperties[trackType][0]; + } + else + { + entranceDirections = TrackSequenceProperties[trackType][0]; + } + + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN && (tileElement->AsTrack()->GetSequenceIndex() == 0)) + { + if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, 0)) + { + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); + } + } + + auto* surfaceElement = map_get_surface_element_at(mapLoc); + if (surfaceElement == nullptr) + { + log_warning("Surface Element not found. x = %d, y = %d", mapLoc.x, mapLoc.y); + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + int8_t _support_height = tileElement->base_height - surfaceElement->base_height; + if (_support_height < 0) + { + _support_height = 10; + } + + cost += (_support_height / 2) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice; + + // If the removed tile is a station modify station properties. + // Don't do this if the ride is simulating and the tile is a ghost to prevent desyncs. + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN + && !(ride->status == RIDE_STATUS_SIMULATING && tileElement->Flags & TILE_ELEMENT_FLAG_GHOST) + && (tileElement->AsTrack()->GetSequenceIndex() == 0)) + { + if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, GAME_COMMAND_FLAG_APPLY)) + { + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); + } + } + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER)) + { + surfaceElement->SetHasTrackThatNeedsWater(false); + } + + invalidate_test_results(ride); + footpath_queue_chain_reset(); + if (!gCheatsDisableClearanceChecks || !(tileElement->IsGhost())) + { + footpath_remove_edges_at(mapLoc, tileElement); + } + tile_element_remove(tileElement); + sub_6CB945(ride); + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + ride->UpdateMaxVehicles(); + } + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + switch (trackType) + { + case TrackElemType::OnRidePhoto: + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_ON_RIDE_PHOTO; + break; + case TrackElemType::CableLiftHill: + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED; + break; + case TrackElemType::BlockBrakes: + ride->num_block_brakes--; + if (ride->num_block_brakes == 0) + { + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_OPERATING; + RideMode newMode = RideMode::ContinuousCircuit; + if (ride->type == RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER) + { + newMode = RideMode::PoweredLaunch; + } + + auto rideSetSetting = RideSetSettingAction(ride->id, RideSetSetting::Mode, static_cast(newMode)); + GameActions::ExecuteNested(&rideSetSetting); + } + + break; + } + + switch (trackType) + { + case TrackElemType::Up25ToFlat: + case TrackElemType::Up60ToFlat: + case TrackElemType::DiagUp25ToFlat: + case TrackElemType::DiagUp60ToFlat: + if (!isLiftHill) + break; + [[fallthrough]]; + case TrackElemType::CableLiftHill: + ride->num_block_brakes--; + break; + } + } + + money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + price *= FlatRideTrackPricing[trackType]; + } + else + { + price *= TrackPricing[trackType]; + } + price >>= 16; + price = (price + cost) / 2; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) + price *= -7; + else + price *= -10; + + res->Cost = price; + return res; +} diff --git a/src/openrct2/actions/TrackRemoveAction.h b/src/openrct2/actions/TrackRemoveAction.h new file mode 100644 index 0000000000..f950d27f07 --- /dev/null +++ b/src/openrct2/actions/TrackRemoveAction.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(TrackRemoveAction, GAME_COMMAND_REMOVE_TRACK, GameActions::Result) +{ +private: + int32_t _trackType{}; + int32_t _sequence{}; + CoordsXYZD _origin; + +public: + TrackRemoveAction() = default; + TrackRemoveAction(int32_t trackType, int32_t sequence, const CoordsXYZD& origin) + : _trackType(trackType) + , _sequence(sequence) + , _origin(origin) + { + _origin.direction &= 3; + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override final + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/TrackRemoveAction.hpp b/src/openrct2/actions/TrackRemoveAction.hpp deleted file mode 100644 index 44bfa30ede..0000000000 --- a/src/openrct2/actions/TrackRemoveAction.hpp +++ /dev/null @@ -1,533 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../ride/RideData.h" -#include "../ride/Track.h" -#include "../ride/TrackData.h" -#include "../ride/TrackDesign.h" -#include "../util/Util.h" -#include "../world/MapAnimation.h" -#include "../world/Surface.h" -#include "GameAction.h" -#include "RideSetSetting.hpp" - -DEFINE_GAME_ACTION(TrackRemoveAction, GAME_COMMAND_REMOVE_TRACK, GameActions::Result) -{ -private: - int32_t _trackType{}; - int32_t _sequence{}; - CoordsXYZD _origin; - -public: - TrackRemoveAction() = default; - TrackRemoveAction(int32_t trackType, int32_t sequence, const CoordsXYZD& origin) - : _trackType(trackType) - , _sequence(sequence) - , _origin(origin) - { - _origin.direction &= 3; - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_origin); - visitor.Visit("trackType", _trackType); - visitor.Visit("sequence", _sequence); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_trackType) << DS_TAG(_sequence) << DS_TAG(_origin); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->Position.x = _origin.x + 16; - res->Position.y = _origin.y + 16; - res->Position.z = _origin.z; - res->Expenditure = ExpenditureType::RideConstruction; - - // Stations require some massaging of the track type for comparing - auto comparableTrackType = _trackType; - switch (_trackType) - { - case TrackElemType::BeginStation: - case TrackElemType::MiddleStation: - comparableTrackType = TrackElemType::EndStation; - break; - } - - bool found = false; - bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; - TileElement* tileElement = map_get_first_element_at(_origin); - - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != _origin.z) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if ((tileElement->GetDirection()) != _origin.direction) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != _sequence) - continue; - - if (tileElement->IsGhost() != isGhost) - continue; - - auto tileTrackType = tileElement->AsTrack()->GetTrackType(); - switch (tileTrackType) - { - case TrackElemType::BeginStation: - case TrackElemType::MiddleStation: - tileTrackType = TrackElemType::EndStation; - break; - } - - if (tileTrackType != comparableTrackType) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", _origin.x, _origin.y, _origin.z, - _origin.direction, _sequence); - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - if (tileElement->AsTrack()->IsIndestructible()) - { - return MakeResult( - GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, - STR_YOU_ARE_NOT_ALLOWED_TO_REMOVE_THIS_SECTION); - } - - ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); - auto trackType = tileElement->AsTrack()->GetTrackType(); - - auto ride = get_ride(rideIndex); - if (ride == nullptr) - { - log_warning("Ride not found. ride index = %d.", rideIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - if (ride->type >= RIDE_TYPE_COUNT) - { - log_warning("Ride type not found. ride type = %d.", ride->type); - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - const rct_preview_track* trackBlock = get_track_def_from_ride(ride, trackType); - trackBlock += tileElement->AsTrack()->GetSequenceIndex(); - - auto startLoc = _origin; - startLoc.direction = tileElement->GetDirection(); - - auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; - startLoc.x -= rotatedTrack.x; - startLoc.y -= rotatedTrack.y; - startLoc.z -= rotatedTrack.z; - res->Position.x = startLoc.x; - res->Position.y = startLoc.y; - res->Position.z = startLoc.z; - - money32 cost = 0; - - trackBlock = get_track_def_from_ride(ride, trackType); - for (; trackBlock->index != 255; trackBlock++) - { - rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; - auto mapLoc = CoordsXYZ{ startLoc.x, startLoc.y, startLoc.z } + rotatedTrack; - - if (!LocationValid(mapLoc)) - { - return MakeResult( - GameActions::Status::NotOwned, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - map_invalidate_tile_full(mapLoc); - - found = false; - tileElement = map_get_first_element_at(mapLoc); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != mapLoc.z) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if (tileElement->GetDirection() != _origin.direction) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) - continue; - - if (tileElement->AsTrack()->GetTrackType() != trackType) - continue; - - if (tileElement->IsGhost() != isGhost) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", mapLoc.x, mapLoc.y, mapLoc.z, - _origin.direction, trackBlock->index); - return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - int32_t entranceDirections; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - entranceDirections = FlatRideTrackSequenceProperties[trackType][0]; - } - else - { - entranceDirections = TrackSequenceProperties[trackType][0]; - } - - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN && (tileElement->AsTrack()->GetSequenceIndex() == 0)) - { - if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, 0)) - { - return MakeResult( - GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); - } - } - - auto* surfaceElement = map_get_surface_element_at(mapLoc); - if (surfaceElement == nullptr) - { - log_warning("Surface Element not found. x = %d, y = %d", mapLoc.x, mapLoc.y); - return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - int8_t _support_height = tileElement->base_height - surfaceElement->base_height; - if (_support_height < 0) - { - _support_height = 10; - } - - cost += (_support_height / 2) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice; - } - - money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - price *= FlatRideTrackPricing[trackType]; - } - else - { - price *= TrackPricing[trackType]; - } - price >>= 16; - price = (price + cost) / 2; - if (ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) - price *= -7; - else - price *= -10; - - res->Cost = price; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Position.x = _origin.x + 16; - res->Position.y = _origin.y + 16; - res->Position.z = _origin.z; - res->Expenditure = ExpenditureType::RideConstruction; - - // Stations require some massaging of the track type for comparing - auto comparableTrackType = _trackType; - switch (_trackType) - { - case TrackElemType::BeginStation: - case TrackElemType::MiddleStation: - comparableTrackType = TrackElemType::EndStation; - break; - } - - bool found = false; - bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; - TileElement* tileElement = map_get_first_element_at(_origin); - - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != _origin.z) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if ((tileElement->GetDirection()) != _origin.direction) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != _sequence) - continue; - - if (tileElement->IsGhost() != isGhost) - continue; - - auto tileTrackType = tileElement->AsTrack()->GetTrackType(); - switch (tileTrackType) - { - case TrackElemType::BeginStation: - case TrackElemType::MiddleStation: - tileTrackType = TrackElemType::EndStation; - break; - } - - if (tileTrackType != comparableTrackType) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", _origin.x, _origin.y, _origin.z, - _origin.direction, _sequence); - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); - auto trackType = tileElement->AsTrack()->GetTrackType(); - bool isLiftHill = tileElement->AsTrack()->HasChain(); - - auto ride = get_ride(rideIndex); - if (ride == nullptr) - { - log_warning("Ride not found. ride index = %d.", rideIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - const rct_preview_track* trackBlock = get_track_def_from_ride(ride, trackType); - trackBlock += tileElement->AsTrack()->GetSequenceIndex(); - - auto startLoc = _origin; - startLoc.direction = tileElement->GetDirection(); - - auto rotatedTrackLoc = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; - startLoc.x -= rotatedTrackLoc.x; - startLoc.y -= rotatedTrackLoc.y; - startLoc.z -= rotatedTrackLoc.z; - res->Position.x = startLoc.x; - res->Position.y = startLoc.y; - res->Position.z = startLoc.z; - money32 cost = 0; - - trackBlock = get_track_def_from_ride(ride, trackType); - for (; trackBlock->index != 255; trackBlock++) - { - rotatedTrackLoc = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; - auto mapLoc = CoordsXYZ{ startLoc.x, startLoc.y, startLoc.z } + rotatedTrackLoc; - - map_invalidate_tile_full(mapLoc); - - found = false; - tileElement = map_get_first_element_at(mapLoc); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != mapLoc.z) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if (tileElement->GetDirection() != _origin.direction) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) - continue; - - if (tileElement->AsTrack()->GetTrackType() != trackType) - continue; - - if (tileElement->IsGhost() != isGhost) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", mapLoc.x, mapLoc.y, mapLoc.z, - _origin.direction, trackBlock->index); - return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - int32_t entranceDirections; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - entranceDirections = FlatRideTrackSequenceProperties[trackType][0]; - } - else - { - entranceDirections = TrackSequenceProperties[trackType][0]; - } - - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN && (tileElement->AsTrack()->GetSequenceIndex() == 0)) - { - if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, 0)) - { - return MakeResult( - GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); - } - } - - auto* surfaceElement = map_get_surface_element_at(mapLoc); - if (surfaceElement == nullptr) - { - log_warning("Surface Element not found. x = %d, y = %d", mapLoc.x, mapLoc.y); - return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - int8_t _support_height = tileElement->base_height - surfaceElement->base_height; - if (_support_height < 0) - { - _support_height = 10; - } - - cost += (_support_height / 2) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice; - - // If the removed tile is a station modify station properties. - // Don't do this if the ride is simulating and the tile is a ghost to prevent desyncs. - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN - && !(ride->status == RIDE_STATUS_SIMULATING && tileElement->Flags & TILE_ELEMENT_FLAG_GHOST) - && (tileElement->AsTrack()->GetSequenceIndex() == 0)) - { - if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, GAME_COMMAND_FLAG_APPLY)) - { - return MakeResult( - GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); - } - } - - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER)) - { - surfaceElement->SetHasTrackThatNeedsWater(false); - } - - invalidate_test_results(ride); - footpath_queue_chain_reset(); - if (!gCheatsDisableClearanceChecks || !(tileElement->IsGhost())) - { - footpath_remove_edges_at(mapLoc, tileElement); - } - tile_element_remove(tileElement); - sub_6CB945(ride); - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - ride->UpdateMaxVehicles(); - } - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - switch (trackType) - { - case TrackElemType::OnRidePhoto: - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_ON_RIDE_PHOTO; - break; - case TrackElemType::CableLiftHill: - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED; - break; - case TrackElemType::BlockBrakes: - ride->num_block_brakes--; - if (ride->num_block_brakes == 0) - { - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_OPERATING; - RideMode newMode = RideMode::ContinuousCircuit; - if (ride->type == RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER) - { - newMode = RideMode::PoweredLaunch; - } - - auto rideSetSetting = RideSetSettingAction( - ride->id, RideSetSetting::Mode, static_cast(newMode)); - GameActions::ExecuteNested(&rideSetSetting); - } - - break; - } - - switch (trackType) - { - case TrackElemType::Up25ToFlat: - case TrackElemType::Up60ToFlat: - case TrackElemType::DiagUp25ToFlat: - case TrackElemType::DiagUp60ToFlat: - if (!isLiftHill) - break; - [[fallthrough]]; - case TrackElemType::CableLiftHill: - ride->num_block_brakes--; - break; - } - } - - money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - price *= FlatRideTrackPricing[trackType]; - } - else - { - price *= TrackPricing[trackType]; - } - price >>= 16; - price = (price + cost) / 2; - if (ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) - price *= -7; - else - price *= -10; - - res->Cost = price; - return res; - } -}; diff --git a/src/openrct2/actions/TrackSetBrakeSpeedAction.cpp b/src/openrct2/actions/TrackSetBrakeSpeedAction.cpp new file mode 100644 index 0000000000..cdf6658a81 --- /dev/null +++ b/src/openrct2/actions/TrackSetBrakeSpeedAction.cpp @@ -0,0 +1,63 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "TrackSetBrakeSpeedAction.h" + +#include "../management/Finance.h" + +void TrackSetBrakeSpeedAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("trackType", _trackType); + visitor.Visit("brakeSpeed", _brakeSpeed); +} + +void TrackSetBrakeSpeedAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_loc) << DS_TAG(_trackType) << DS_TAG(_brakeSpeed); +} + +GameActions::Result::Ptr TrackSetBrakeSpeedAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr TrackSetBrakeSpeedAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr TrackSetBrakeSpeedAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + + res->Position = _loc; + res->Position.x += 16; + res->Position.y += 16; + res->Expenditure = ExpenditureType::RideConstruction; + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_NONE); + } + + TileElement* tileElement = map_get_track_element_at_of_type(_loc, _trackType); + if (tileElement == nullptr) + { + log_warning("Invalid game command for setting brakes speed. x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (isExecuting) + { + tileElement->AsTrack()->SetBrakeBoosterSpeed(_brakeSpeed); + } + return res; +} diff --git a/src/openrct2/actions/TrackSetBrakeSpeedAction.h b/src/openrct2/actions/TrackSetBrakeSpeedAction.h new file mode 100644 index 0000000000..22515b55f5 --- /dev/null +++ b/src/openrct2/actions/TrackSetBrakeSpeedAction.h @@ -0,0 +1,43 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(TrackSetBrakeSpeedAction, GAME_COMMAND_SET_BRAKES_SPEED, GameActions::Result) +{ +private: + CoordsXYZ _loc; + track_type_t _trackType{}; + uint8_t _brakeSpeed{}; + +public: + TrackSetBrakeSpeedAction() = default; + TrackSetBrakeSpeedAction(const CoordsXYZ& loc, track_type_t trackType, uint8_t brakeSpeed) + : _loc(loc) + , _trackType(trackType) + , _brakeSpeed(brakeSpeed) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override final + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/TrackSetBrakeSpeedAction.hpp b/src/openrct2/actions/TrackSetBrakeSpeedAction.hpp deleted file mode 100644 index bd7dbe7d3f..0000000000 --- a/src/openrct2/actions/TrackSetBrakeSpeedAction.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "GameAction.h" - -DEFINE_GAME_ACTION(TrackSetBrakeSpeedAction, GAME_COMMAND_SET_BRAKES_SPEED, GameActions::Result) -{ -private: - CoordsXYZ _loc; - track_type_t _trackType{}; - uint8_t _brakeSpeed{}; - -public: - TrackSetBrakeSpeedAction() = default; - TrackSetBrakeSpeedAction(const CoordsXYZ& loc, track_type_t trackType, uint8_t brakeSpeed) - : _loc(loc) - , _trackType(trackType) - , _brakeSpeed(brakeSpeed) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("trackType", _trackType); - visitor.Visit("brakeSpeed", _brakeSpeed); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_loc) << DS_TAG(_trackType) << DS_TAG(_brakeSpeed); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - res->Position = _loc; - res->Position.x += 16; - res->Position.y += 16; - res->Expenditure = ExpenditureType::RideConstruction; - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_NONE); - } - - TileElement* tileElement = map_get_track_element_at_of_type(_loc, _trackType); - if (tileElement == nullptr) - { - log_warning("Invalid game command for setting brakes speed. x = %d, y = %d", _loc.x, _loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (isExecuting) - { - tileElement->AsTrack()->SetBrakeBoosterSpeed(_brakeSpeed); - } - return res; - } -}; diff --git a/src/openrct2/actions/WallPlaceAction.cpp b/src/openrct2/actions/WallPlaceAction.cpp new file mode 100644 index 0000000000..707a7cf5ad --- /dev/null +++ b/src/openrct2/actions/WallPlaceAction.cpp @@ -0,0 +1,580 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "WallPlaceAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../ride/Track.h" +#include "../ride/TrackDesign.h" +#include "../world/Banner.h" +#include "../world/LargeScenery.h" +#include "../world/MapAnimation.h" +#include "../world/SmallScenery.h" +#include "../world/Surface.h" +#include "../world/Wall.h" + +void WallPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _wallType); + visitor.Visit("edge", _edge); + visitor.Visit("primaryColour", _primaryColour); + visitor.Visit("secondaryColour", _secondaryColour); + visitor.Visit("tertiaryColour", _tertiaryColour); + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_wallType); + if (sceneryEntry != nullptr) + { + if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) + { + _bannerId = create_new_banner(0); + } + } +} + +void WallPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_wallType) << DS_TAG(_loc) << DS_TAG(_edge) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) + << DS_TAG(_tertiaryColour) << DS_TAG(_bannerId); +} + +GameActions::Result::Ptr WallPlaceAction::Query() const +{ + auto res = std::make_unique(); + res->ErrorTitle = STR_CANT_BUILD_PARK_ENTRANCE_HERE; + res->Position = _loc; + + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x += 16; + res->Position.y += 16; + + if (_loc.z == 0) + { + res->Position.z = tile_element_height(res->Position); + } + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::NotOwned); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsSandboxMode) + { + if (_loc.z == 0) + { + if (!map_is_location_in_park(_loc)) + { + return std::make_unique(GameActions::Status::NotOwned); + } + } + else if (!map_is_location_owned(_loc)) + { + return std::make_unique(GameActions::Status::NotOwned); + } + } + else if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY)) + { + log_error("Invalid x/y coordinates. x = %d y = %d", _loc.x, _loc.y); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + if (_edge > 3) + { + return std::make_unique(GameActions::Status::InvalidParameters); + } + + uint8_t edgeSlope = 0; + auto targetHeight = _loc.z; + if (targetHeight == 0) + { + auto* surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); + return std::make_unique(GameActions::Status::InvalidParameters); + } + targetHeight = surfaceElement->GetBaseZ(); + + uint8_t slope = surfaceElement->GetSlope(); + edgeSlope = LandSlopeToWallSlope[slope][_edge & 3]; + if (edgeSlope & EDGE_SLOPE_ELEVATED) + { + targetHeight += 16; + edgeSlope &= ~EDGE_SLOPE_ELEVATED; + } + } + + auto* surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + if (surfaceElement->GetWaterHeight() > 0) + { + uint16_t waterHeight = surfaceElement->GetWaterHeight(); + + if (targetHeight < waterHeight && !gCheatsDisableClearanceChecks) + { + return std::make_unique(GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); + } + } + + if (targetHeight < surfaceElement->GetBaseZ() && !gCheatsDisableClearanceChecks) + { + return std::make_unique(GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + + if (!(edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS))) + { + uint8_t newEdge = (_edge + 2) & 3; + uint8_t newBaseHeight = surfaceElement->base_height; + newBaseHeight += 2; + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + if (targetHeight / 8 < newBaseHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + + if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) + { + newEdge = (newEdge - 1) & 3; + + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + newEdge = (newEdge + 2) & 3; + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + newBaseHeight += 2; + if (targetHeight / 8 < newBaseHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + newBaseHeight -= 2; + } + } + } + } + + newEdge = (_edge + 3) & 3; + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + if (targetHeight / 8 < newBaseHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + + if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) + { + newEdge = (newEdge - 1) & 3; + + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + newEdge = (newEdge + 2) & 3; + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + newBaseHeight += 2; + if (targetHeight / 8 < newBaseHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + } + } + } + } + } + + rct_scenery_entry* wallEntry = get_wall_entry(_wallType); + + if (wallEntry == nullptr) + { + log_error("Wall Type not found %d", _wallType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + if (wallEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) + { + if (_bannerId == BANNER_INDEX_NULL) + { + log_error("Banner Index not specified."); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); + } + + auto banner = GetBanner(_bannerId); + if (!banner->IsNull()) + { + log_error("No free banners available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + } + + uint8_t clearanceHeight = targetHeight / 8; + if (edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) + { + if (wallEntry->wall.flags & WALL_SCENERY_CANT_BUILD_ON_SLOPE) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_ERR_UNABLE_TO_BUILD_THIS_ON_SLOPE); + } + clearanceHeight += 2; + } + clearanceHeight += wallEntry->wall.height; + + bool wallAcrossTrack = false; + if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsDisableClearanceChecks) + { + auto result = WallCheckObstruction(wallEntry, targetHeight / 8, clearanceHeight, &wallAcrossTrack); + if (result->Error != GameActions::Status::Ok) + { + return result; + } + } + + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); + } + + res->Cost = wallEntry->wall.price; + return res; +} + +GameActions::Result::Ptr WallPlaceAction::Execute() const +{ + auto res = std::make_unique(); + res->ErrorTitle = STR_CANT_BUILD_PARK_ENTRANCE_HERE; + res->Position = _loc; + + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x += 16; + res->Position.y += 16; + + if (res->Position.z == 0) + { + res->Position.z = tile_element_height(res->Position); + } + + uint8_t edgeSlope = 0; + auto targetHeight = _loc.z; + if (targetHeight == 0) + { + auto* surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); + return std::make_unique(GameActions::Status::InvalidParameters); + } + targetHeight = surfaceElement->GetBaseZ(); + + uint8_t slope = surfaceElement->GetSlope(); + edgeSlope = LandSlopeToWallSlope[slope][_edge & 3]; + if (edgeSlope & EDGE_SLOPE_ELEVATED) + { + targetHeight += 16; + edgeSlope &= ~EDGE_SLOPE_ELEVATED; + } + } + auto targetLoc = CoordsXYZ(_loc, targetHeight); + + rct_scenery_entry* wallEntry = get_wall_entry(_wallType); + + if (wallEntry == nullptr) + { + log_error("Wall Type not found %d", _wallType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + uint8_t clearanceHeight = targetHeight / COORDS_Z_STEP; + if (edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) + { + clearanceHeight += 2; + } + clearanceHeight += wallEntry->wall.height; + + bool wallAcrossTrack = false; + if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsDisableClearanceChecks) + { + auto result = WallCheckObstruction(wallEntry, targetHeight / COORDS_Z_STEP, clearanceHeight, &wallAcrossTrack); + if (result->Error != GameActions::Status::Ok) + { + return result; + } + } + + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); + } + + if (wallEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) + { + if (_bannerId == BANNER_INDEX_NULL) + { + log_error("Banner Index not specified."); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); + } + + auto banner = GetBanner(_bannerId); + if (!banner->IsNull()) + { + log_error("No free banners available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + + banner->text = {}; + banner->colour = COLOUR_WHITE; + banner->text_colour = COLOUR_WHITE; + banner->flags = BANNER_FLAG_IS_WALL; + banner->type = 0; // Banner must be deleted after this point in an early return + banner->position = TileCoordsXY(_loc); + + ride_id_t rideIndex = banner_get_closest_ride_index(targetLoc); + if (rideIndex != RIDE_ID_NULL) + { + banner->ride_index = rideIndex; + banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; + } + } + + TileElement* tileElement = tile_element_insert(targetLoc, 0b0000); + assert(tileElement != nullptr); + + map_animation_create(MAP_ANIMATION_TYPE_WALL, targetLoc); + + tileElement->SetType(TILE_ELEMENT_TYPE_WALL); + WallElement* wallElement = tileElement->AsWall(); + wallElement->clearance_height = clearanceHeight; + wallElement->SetDirection(_edge); + wallElement->SetSlope(edgeSlope); + + wallElement->SetPrimaryColour(_primaryColour); + wallElement->SetSecondaryColour(_secondaryColour); + + if (wallAcrossTrack) + { + wallElement->SetAcrossTrack(true); + } + + wallElement->SetEntryIndex(_wallType); + if (_bannerId != BANNER_INDEX_NULL) + { + wallElement->SetBannerIndex(_bannerId); + } + + if (wallEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) + { + wallElement->SetTertiaryColour(_tertiaryColour); + } + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + wallElement->SetGhost(true); + } + + res->tileElement = tileElement; + map_invalidate_tile_zoom1({ _loc, wallElement->GetBaseZ(), wallElement->GetBaseZ() + 72 }); + + res->Cost = wallEntry->wall.price; + return res; +} + +/** + * + * rct2: 0x006E5CBA + */ +bool WallPlaceAction::WallCheckObstructionWithTrack( + rct_scenery_entry* wall, int32_t z0, TrackElement* trackElement, bool* wallAcrossTrack) const +{ + track_type_t trackType = trackElement->GetTrackType(); + int32_t sequence = trackElement->GetSequenceIndex(); + int32_t direction = (_edge - trackElement->GetDirection()) & TILE_ELEMENT_DIRECTION_MASK; + auto ride = get_ride(trackElement->GetRideIndex()); + if (ride == nullptr) + { + return false; + } + + if (TrackIsAllowedWallEdges(ride->type, trackType, sequence, direction)) + { + return true; + } + + if (!(wall->wall.flags & WALL_SCENERY_IS_DOOR)) + { + return false; + } + + if (!(RideTypeDescriptors[ride->type].Flags & RIDE_TYPE_FLAG_ALLOW_DOORS_ON_TRACK)) + { + return false; + } + + *wallAcrossTrack = true; + if (z0 & 1) + { + return false; + } + + int32_t z; + if (sequence == 0) + { + if (TrackSequenceProperties[trackType][0] & TRACK_SEQUENCE_FLAG_DISALLOW_DOORS) + { + return false; + } + + if (TrackDefinitions[trackType].bank_start == 0) + { + if (!(TrackCoordinates[trackType].rotation_begin & 4)) + { + direction = direction_reverse(trackElement->GetDirection()); + if (direction == _edge) + { + const rct_preview_track* trackBlock = &TrackBlocks[trackType][sequence]; + z = TrackCoordinates[trackType].z_begin; + z = trackElement->base_height + ((z - trackBlock->z) * 8); + if (z == z0) + { + return true; + } + } + } + } + } + + const rct_preview_track* trackBlock = &TrackBlocks[trackType][sequence + 1]; + if (trackBlock->index != 0xFF) + { + return false; + } + + if (TrackDefinitions[trackType].bank_end != 0) + { + return false; + } + + direction = TrackCoordinates[trackType].rotation_end; + if (direction & 4) + { + return false; + } + + direction = (trackElement->GetDirection() + TrackCoordinates[trackType].rotation_end) & TILE_ELEMENT_DIRECTION_MASK; + if (direction != _edge) + { + return false; + } + + trackBlock = &TrackBlocks[trackType][sequence]; + z = TrackCoordinates[trackType].z_end; + z = trackElement->base_height + ((z - trackBlock->z) * 8); + return z == z0; +} + +/** + * + * rct2: 0x006E5C1A + */ +GameActions::Result::Ptr WallPlaceAction::WallCheckObstruction( + rct_scenery_entry* wall, int32_t z0, int32_t z1, bool* wallAcrossTrack) const +{ + int32_t entryType, sequence; + rct_scenery_entry* entry; + rct_large_scenery_tile* tile; + + *wallAcrossTrack = false; + gMapGroundFlags = ELEMENT_IS_ABOVE_GROUND; + if (map_is_location_at_edge(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_OFF_EDGE_OF_MAP); + } + + TileElement* tileElement = map_get_first_element_at(_loc); + do + { + if (tileElement == nullptr) + break; + int32_t elementType = tileElement->GetType(); + if (elementType == TILE_ELEMENT_TYPE_SURFACE) + continue; + if (tileElement->IsGhost()) + continue; + if (z0 >= tileElement->clearance_height) + continue; + if (z1 <= tileElement->base_height) + continue; + if (elementType == TILE_ELEMENT_TYPE_WALL) + { + int32_t direction = tileElement->GetDirection(); + if (_edge == direction) + { + auto res = MakeResult(GameActions::Status::NoClearance, STR_NONE); + map_obstruction_set_error_text(tileElement, *res); + return res; + } + continue; + } + if (tileElement->GetOccupiedQuadrants() == 0) + continue; + auto res = MakeResult(GameActions::Status::NoClearance, STR_NONE); + switch (elementType) + { + case TILE_ELEMENT_TYPE_ENTRANCE: + map_obstruction_set_error_text(tileElement, *res); + return res; + case TILE_ELEMENT_TYPE_PATH: + if (tileElement->AsPath()->GetEdges() & (1 << _edge)) + { + map_obstruction_set_error_text(tileElement, *res); + return res; + } + break; + case TILE_ELEMENT_TYPE_LARGE_SCENERY: + entryType = tileElement->AsLargeScenery()->GetEntryIndex(); + sequence = tileElement->AsLargeScenery()->GetSequenceIndex(); + entry = get_large_scenery_entry(entryType); + tile = &entry->large_scenery.tiles[sequence]; + { + int32_t direction = ((_edge - tileElement->GetDirection()) & TILE_ELEMENT_DIRECTION_MASK) + 8; + if (!(tile->flags & (1 << direction))) + { + map_obstruction_set_error_text(tileElement, *res); + return res; + } + } + break; + case TILE_ELEMENT_TYPE_SMALL_SCENERY: + entry = tileElement->AsSmallScenery()->GetEntry(); + if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_NO_WALLS)) + { + map_obstruction_set_error_text(tileElement, *res); + return res; + } + break; + case TILE_ELEMENT_TYPE_TRACK: + if (!WallCheckObstructionWithTrack(wall, z0, tileElement->AsTrack(), wallAcrossTrack)) + { + return res; + } + break; + } + } while (!(tileElement++)->IsLastForTile()); + + return MakeResult(); +} diff --git a/src/openrct2/actions/WallPlaceAction.h b/src/openrct2/actions/WallPlaceAction.h new file mode 100644 index 0000000000..bdf98917a2 --- /dev/null +++ b/src/openrct2/actions/WallPlaceAction.h @@ -0,0 +1,127 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "../ride/RideData.h" +#include "../ride/TrackData.h" +#include "../world/Scenery.h" +#include "GameAction.h" + +class WallPlaceActionResult final : public GameActions::Result +{ +public: + WallPlaceActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_CANT_BUILD_PARK_ENTRANCE_HERE) + { + } + + WallPlaceActionResult(GameActions::Status err) + : GameActions::Result(err, STR_CANT_BUILD_PARK_ENTRANCE_HERE) + { + } + + WallPlaceActionResult(GameActions::Status err, rct_string_id msg) + : GameActions::Result(err, STR_CANT_BUILD_PARK_ENTRANCE_HERE, msg) + { + } + + WallPlaceActionResult(GameActions::Status error, rct_string_id msg, uint8_t* args) + : GameActions::Result(error, STR_CANT_BUILD_PARK_ENTRANCE_HERE, msg, args) + { + } + + TileElement* tileElement = nullptr; +}; + +DEFINE_GAME_ACTION(WallPlaceAction, GAME_COMMAND_PLACE_WALL, WallPlaceActionResult) +{ +private: + ObjectEntryIndex _wallType{ OBJECT_ENTRY_INDEX_NULL }; + CoordsXYZ _loc; + Direction _edge{ INVALID_DIRECTION }; + int32_t _primaryColour{ COLOUR_BLACK }; + int32_t _secondaryColour{ COLOUR_BLACK }; + int32_t _tertiaryColour{ COLOUR_BLACK }; + BannerIndex _bannerId{ BANNER_INDEX_NULL }; + +public: + WallPlaceAction() = default; + + WallPlaceAction( + ObjectEntryIndex wallType, const CoordsXYZ& loc, uint8_t edge, int32_t primaryColour, int32_t secondaryColour, + int32_t tertiaryColour) + : _wallType(wallType) + , _loc(loc) + , _edge(edge) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + , _tertiaryColour(tertiaryColour) + { + rct_scenery_entry* sceneryEntry = get_wall_entry(_wallType); + if (sceneryEntry != nullptr) + { + if (sceneryEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) + { + _bannerId = create_new_banner(0); + } + } + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override final + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + /** + * + * rct2: 0x006E5CBA + */ + bool WallCheckObstructionWithTrack(rct_scenery_entry * wall, int32_t z0, TrackElement * trackElement, bool* wallAcrossTrack) + const; + /** + * + * rct2: 0x006E5C1A + */ + GameActions::Result::Ptr WallCheckObstruction(rct_scenery_entry * wall, int32_t z0, int32_t z1, bool* wallAcrossTrack) + const; + + /** + * Gets whether the given track type can have a wall placed on the edge of the given direction. + * Some thin tracks for example are allowed to have walls either side of the track, but wider tracks can not. + */ + static bool TrackIsAllowedWallEdges(uint8_t rideType, uint8_t trackType, uint8_t trackSequence, uint8_t direction) + { + if (!ride_type_has_flag(rideType, RIDE_TYPE_FLAG_TRACK_NO_WALLS)) + { + if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + if (FlatRideTrackSequenceElementAllowedWallEdges[trackType][trackSequence] & (1 << direction)) + { + return true; + } + } + else + { + if (TrackSequenceElementAllowedWallEdges[trackType][trackSequence] & (1 << direction)) + { + return true; + } + } + } + return false; + } +}; diff --git a/src/openrct2/actions/WallPlaceAction.hpp b/src/openrct2/actions/WallPlaceAction.hpp deleted file mode 100644 index 33b01f3bd8..0000000000 --- a/src/openrct2/actions/WallPlaceAction.hpp +++ /dev/null @@ -1,677 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../ride/Track.h" -#include "../ride/TrackData.h" -#include "../ride/TrackDesign.h" -#include "../world/Banner.h" -#include "../world/LargeScenery.h" -#include "../world/MapAnimation.h" -#include "../world/Scenery.h" -#include "../world/SmallScenery.h" -#include "../world/Surface.h" -#include "../world/Wall.h" -#include "GameAction.h" - -class WallPlaceActionResult final : public GameActions::Result -{ -public: - WallPlaceActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_CANT_BUILD_PARK_ENTRANCE_HERE) - { - } - - WallPlaceActionResult(GameActions::Status err) - : GameActions::Result(err, STR_CANT_BUILD_PARK_ENTRANCE_HERE) - { - } - - WallPlaceActionResult(GameActions::Status err, rct_string_id msg) - : GameActions::Result(err, STR_CANT_BUILD_PARK_ENTRANCE_HERE, msg) - { - } - - WallPlaceActionResult(GameActions::Status error, rct_string_id msg, uint8_t* args) - : GameActions::Result(error, STR_CANT_BUILD_PARK_ENTRANCE_HERE, msg, args) - { - } - - TileElement* tileElement = nullptr; -}; - -DEFINE_GAME_ACTION(WallPlaceAction, GAME_COMMAND_PLACE_WALL, WallPlaceActionResult) -{ -private: - ObjectEntryIndex _wallType{ OBJECT_ENTRY_INDEX_NULL }; - CoordsXYZ _loc; - Direction _edge{ INVALID_DIRECTION }; - int32_t _primaryColour{ COLOUR_BLACK }; - int32_t _secondaryColour{ COLOUR_BLACK }; - int32_t _tertiaryColour{ COLOUR_BLACK }; - BannerIndex _bannerId{ BANNER_INDEX_NULL }; - -public: - WallPlaceAction() = default; - - WallPlaceAction( - ObjectEntryIndex wallType, const CoordsXYZ& loc, uint8_t edge, int32_t primaryColour, int32_t secondaryColour, - int32_t tertiaryColour) - : _wallType(wallType) - , _loc(loc) - , _edge(edge) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - , _tertiaryColour(tertiaryColour) - { - rct_scenery_entry* sceneryEntry = get_wall_entry(_wallType); - if (sceneryEntry != nullptr) - { - if (sceneryEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) - { - _bannerId = create_new_banner(0); - } - } - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _wallType); - visitor.Visit("edge", _edge); - visitor.Visit("primaryColour", _primaryColour); - visitor.Visit("secondaryColour", _secondaryColour); - visitor.Visit("tertiaryColour", _tertiaryColour); - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_wallType); - if (sceneryEntry != nullptr) - { - if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - _bannerId = create_new_banner(0); - } - } - } - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_wallType) << DS_TAG(_loc) << DS_TAG(_edge) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) - << DS_TAG(_tertiaryColour) << DS_TAG(_bannerId); - } - - GameActions::Result::Ptr Query() const override - { - auto res = std::make_unique(); - res->ErrorTitle = STR_CANT_BUILD_PARK_ENTRANCE_HERE; - res->Position = _loc; - - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x += 16; - res->Position.y += 16; - - if (_loc.z == 0) - { - res->Position.z = tile_element_height(res->Position); - } - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::NotOwned); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) - && !gCheatsSandboxMode) - { - if (_loc.z == 0) - { - if (!map_is_location_in_park(_loc)) - { - return std::make_unique(GameActions::Status::NotOwned); - } - } - else if (!map_is_location_owned(_loc)) - { - return std::make_unique(GameActions::Status::NotOwned); - } - } - else if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY)) - { - log_error("Invalid x/y coordinates. x = %d y = %d", _loc.x, _loc.y); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - if (_edge > 3) - { - return std::make_unique(GameActions::Status::InvalidParameters); - } - - uint8_t edgeSlope = 0; - auto targetHeight = _loc.z; - if (targetHeight == 0) - { - auto* surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); - return std::make_unique(GameActions::Status::InvalidParameters); - } - targetHeight = surfaceElement->GetBaseZ(); - - uint8_t slope = surfaceElement->GetSlope(); - edgeSlope = LandSlopeToWallSlope[slope][_edge & 3]; - if (edgeSlope & EDGE_SLOPE_ELEVATED) - { - targetHeight += 16; - edgeSlope &= ~EDGE_SLOPE_ELEVATED; - } - } - - auto* surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - if (surfaceElement->GetWaterHeight() > 0) - { - uint16_t waterHeight = surfaceElement->GetWaterHeight(); - - if (targetHeight < waterHeight && !gCheatsDisableClearanceChecks) - { - return std::make_unique(GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); - } - } - - if (targetHeight < surfaceElement->GetBaseZ() && !gCheatsDisableClearanceChecks) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - - if (!(edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS))) - { - uint8_t newEdge = (_edge + 2) & 3; - uint8_t newBaseHeight = surfaceElement->base_height; - newBaseHeight += 2; - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - if (targetHeight / 8 < newBaseHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - - if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) - { - newEdge = (newEdge - 1) & 3; - - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - newEdge = (newEdge + 2) & 3; - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - newBaseHeight += 2; - if (targetHeight / 8 < newBaseHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - newBaseHeight -= 2; - } - } - } - } - - newEdge = (_edge + 3) & 3; - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - if (targetHeight / 8 < newBaseHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - - if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) - { - newEdge = (newEdge - 1) & 3; - - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - newEdge = (newEdge + 2) & 3; - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - newBaseHeight += 2; - if (targetHeight / 8 < newBaseHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - } - } - } - } - } - - rct_scenery_entry* wallEntry = get_wall_entry(_wallType); - - if (wallEntry == nullptr) - { - log_error("Wall Type not found %d", _wallType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - if (wallEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) - { - if (_bannerId == BANNER_INDEX_NULL) - { - log_error("Banner Index not specified."); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); - } - - auto banner = GetBanner(_bannerId); - if (!banner->IsNull()) - { - log_error("No free banners available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - } - - uint8_t clearanceHeight = targetHeight / 8; - if (edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) - { - if (wallEntry->wall.flags & WALL_SCENERY_CANT_BUILD_ON_SLOPE) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_ERR_UNABLE_TO_BUILD_THIS_ON_SLOPE); - } - clearanceHeight += 2; - } - clearanceHeight += wallEntry->wall.height; - - bool wallAcrossTrack = false; - if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsDisableClearanceChecks) - { - auto result = WallCheckObstruction(wallEntry, targetHeight / 8, clearanceHeight, &wallAcrossTrack); - if (result->Error != GameActions::Status::Ok) - { - return result; - } - } - - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); - } - - res->Cost = wallEntry->wall.price; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - res->ErrorTitle = STR_CANT_BUILD_PARK_ENTRANCE_HERE; - res->Position = _loc; - - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x += 16; - res->Position.y += 16; - - if (res->Position.z == 0) - { - res->Position.z = tile_element_height(res->Position); - } - - uint8_t edgeSlope = 0; - auto targetHeight = _loc.z; - if (targetHeight == 0) - { - auto* surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); - return std::make_unique(GameActions::Status::InvalidParameters); - } - targetHeight = surfaceElement->GetBaseZ(); - - uint8_t slope = surfaceElement->GetSlope(); - edgeSlope = LandSlopeToWallSlope[slope][_edge & 3]; - if (edgeSlope & EDGE_SLOPE_ELEVATED) - { - targetHeight += 16; - edgeSlope &= ~EDGE_SLOPE_ELEVATED; - } - } - auto targetLoc = CoordsXYZ(_loc, targetHeight); - - rct_scenery_entry* wallEntry = get_wall_entry(_wallType); - - if (wallEntry == nullptr) - { - log_error("Wall Type not found %d", _wallType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - uint8_t clearanceHeight = targetHeight / COORDS_Z_STEP; - if (edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) - { - clearanceHeight += 2; - } - clearanceHeight += wallEntry->wall.height; - - bool wallAcrossTrack = false; - if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsDisableClearanceChecks) - { - auto result = WallCheckObstruction(wallEntry, targetHeight / COORDS_Z_STEP, clearanceHeight, &wallAcrossTrack); - if (result->Error != GameActions::Status::Ok) - { - return result; - } - } - - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); - } - - if (wallEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) - { - if (_bannerId == BANNER_INDEX_NULL) - { - log_error("Banner Index not specified."); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); - } - - auto banner = GetBanner(_bannerId); - if (!banner->IsNull()) - { - log_error("No free banners available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - - banner->text = {}; - banner->colour = COLOUR_WHITE; - banner->text_colour = COLOUR_WHITE; - banner->flags = BANNER_FLAG_IS_WALL; - banner->type = 0; // Banner must be deleted after this point in an early return - banner->position = TileCoordsXY(_loc); - - ride_id_t rideIndex = banner_get_closest_ride_index(targetLoc); - if (rideIndex != RIDE_ID_NULL) - { - banner->ride_index = rideIndex; - banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; - } - } - - TileElement* tileElement = tile_element_insert(targetLoc, 0b0000); - assert(tileElement != nullptr); - - map_animation_create(MAP_ANIMATION_TYPE_WALL, targetLoc); - - tileElement->SetType(TILE_ELEMENT_TYPE_WALL); - WallElement* wallElement = tileElement->AsWall(); - wallElement->clearance_height = clearanceHeight; - wallElement->SetDirection(_edge); - wallElement->SetSlope(edgeSlope); - - wallElement->SetPrimaryColour(_primaryColour); - wallElement->SetSecondaryColour(_secondaryColour); - - if (wallAcrossTrack) - { - wallElement->SetAcrossTrack(true); - } - - wallElement->SetEntryIndex(_wallType); - if (_bannerId != BANNER_INDEX_NULL) - { - wallElement->SetBannerIndex(_bannerId); - } - - if (wallEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) - { - wallElement->SetTertiaryColour(_tertiaryColour); - } - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - wallElement->SetGhost(true); - } - - res->tileElement = tileElement; - map_invalidate_tile_zoom1({ _loc, wallElement->GetBaseZ(), wallElement->GetBaseZ() + 72 }); - - res->Cost = wallEntry->wall.price; - return res; - } - -private: - /** - * - * rct2: 0x006E5CBA - */ - bool WallCheckObstructionWithTrack(rct_scenery_entry * wall, int32_t z0, TrackElement * trackElement, bool* wallAcrossTrack) - const - { - track_type_t trackType = trackElement->GetTrackType(); - int32_t sequence = trackElement->GetSequenceIndex(); - int32_t direction = (_edge - trackElement->GetDirection()) & TILE_ELEMENT_DIRECTION_MASK; - auto ride = get_ride(trackElement->GetRideIndex()); - if (ride == nullptr) - { - return false; - } - - if (TrackIsAllowedWallEdges(ride->type, trackType, sequence, direction)) - { - return true; - } - - if (!(wall->wall.flags & WALL_SCENERY_IS_DOOR)) - { - return false; - } - - if (!(RideTypeDescriptors[ride->type].Flags & RIDE_TYPE_FLAG_ALLOW_DOORS_ON_TRACK)) - { - return false; - } - - *wallAcrossTrack = true; - if (z0 & 1) - { - return false; - } - - int32_t z; - if (sequence == 0) - { - if (TrackSequenceProperties[trackType][0] & TRACK_SEQUENCE_FLAG_DISALLOW_DOORS) - { - return false; - } - - if (TrackDefinitions[trackType].bank_start == 0) - { - if (!(TrackCoordinates[trackType].rotation_begin & 4)) - { - direction = direction_reverse(trackElement->GetDirection()); - if (direction == _edge) - { - const rct_preview_track* trackBlock = &TrackBlocks[trackType][sequence]; - z = TrackCoordinates[trackType].z_begin; - z = trackElement->base_height + ((z - trackBlock->z) * 8); - if (z == z0) - { - return true; - } - } - } - } - } - - const rct_preview_track* trackBlock = &TrackBlocks[trackType][sequence + 1]; - if (trackBlock->index != 0xFF) - { - return false; - } - - if (TrackDefinitions[trackType].bank_end != 0) - { - return false; - } - - direction = TrackCoordinates[trackType].rotation_end; - if (direction & 4) - { - return false; - } - - direction = (trackElement->GetDirection() + TrackCoordinates[trackType].rotation_end) & TILE_ELEMENT_DIRECTION_MASK; - if (direction != _edge) - { - return false; - } - - trackBlock = &TrackBlocks[trackType][sequence]; - z = TrackCoordinates[trackType].z_end; - z = trackElement->base_height + ((z - trackBlock->z) * 8); - return z == z0; - } - - /** - * - * rct2: 0x006E5C1A - */ - GameActions::Result::Ptr WallCheckObstruction(rct_scenery_entry * wall, int32_t z0, int32_t z1, bool* wallAcrossTrack) const - { - int32_t entryType, sequence; - rct_scenery_entry* entry; - rct_large_scenery_tile* tile; - - *wallAcrossTrack = false; - gMapGroundFlags = ELEMENT_IS_ABOVE_GROUND; - if (map_is_location_at_edge(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_OFF_EDGE_OF_MAP); - } - - TileElement* tileElement = map_get_first_element_at(_loc); - do - { - if (tileElement == nullptr) - break; - int32_t elementType = tileElement->GetType(); - if (elementType == TILE_ELEMENT_TYPE_SURFACE) - continue; - if (tileElement->IsGhost()) - continue; - if (z0 >= tileElement->clearance_height) - continue; - if (z1 <= tileElement->base_height) - continue; - if (elementType == TILE_ELEMENT_TYPE_WALL) - { - int32_t direction = tileElement->GetDirection(); - if (_edge == direction) - { - auto res = MakeResult(GameActions::Status::NoClearance, STR_NONE); - map_obstruction_set_error_text(tileElement, *res); - return res; - } - continue; - } - if (tileElement->GetOccupiedQuadrants() == 0) - continue; - auto res = MakeResult(GameActions::Status::NoClearance, STR_NONE); - switch (elementType) - { - case TILE_ELEMENT_TYPE_ENTRANCE: - map_obstruction_set_error_text(tileElement, *res); - return res; - case TILE_ELEMENT_TYPE_PATH: - if (tileElement->AsPath()->GetEdges() & (1 << _edge)) - { - map_obstruction_set_error_text(tileElement, *res); - return res; - } - break; - case TILE_ELEMENT_TYPE_LARGE_SCENERY: - entryType = tileElement->AsLargeScenery()->GetEntryIndex(); - sequence = tileElement->AsLargeScenery()->GetSequenceIndex(); - entry = get_large_scenery_entry(entryType); - tile = &entry->large_scenery.tiles[sequence]; - { - int32_t direction = ((_edge - tileElement->GetDirection()) & TILE_ELEMENT_DIRECTION_MASK) + 8; - if (!(tile->flags & (1 << direction))) - { - map_obstruction_set_error_text(tileElement, *res); - return res; - } - } - break; - case TILE_ELEMENT_TYPE_SMALL_SCENERY: - entry = tileElement->AsSmallScenery()->GetEntry(); - if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_NO_WALLS)) - { - map_obstruction_set_error_text(tileElement, *res); - return res; - } - break; - case TILE_ELEMENT_TYPE_TRACK: - if (!WallCheckObstructionWithTrack(wall, z0, tileElement->AsTrack(), wallAcrossTrack)) - { - return res; - } - break; - } - } while (!(tileElement++)->IsLastForTile()); - - return MakeResult(); - } - - /** - * Gets whether the given track type can have a wall placed on the edge of the given direction. - * Some thin tracks for example are allowed to have walls either side of the track, but wider tracks can not. - */ - static bool TrackIsAllowedWallEdges(uint8_t rideType, uint8_t trackType, uint8_t trackSequence, uint8_t direction) - { - if (!ride_type_has_flag(rideType, RIDE_TYPE_FLAG_TRACK_NO_WALLS)) - { - if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - if (FlatRideTrackSequenceElementAllowedWallEdges[trackType][trackSequence] & (1 << direction)) - { - return true; - } - } - else - { - if (TrackSequenceElementAllowedWallEdges[trackType][trackSequence] & (1 << direction)) - { - return true; - } - } - } - return false; - } -}; diff --git a/src/openrct2/actions/WallRemoveAction.cpp b/src/openrct2/actions/WallRemoveAction.cpp new file mode 100644 index 0000000000..258b19a2a6 --- /dev/null +++ b/src/openrct2/actions/WallRemoveAction.cpp @@ -0,0 +1,109 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "WallRemoveAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Location.hpp" +#include "../world/Wall.h" + +void WallRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); +} + +void WallRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr WallRemoveAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + + if (!LocationValid(_loc)) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + const bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; + if (!isGhost && !(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(_loc)) + { + return std::make_unique( + GameActions::Status::NotOwned, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + TileElement* wallElement = GetFirstWallElementAt(_loc, isGhost); + if (wallElement == nullptr) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + res->Cost = 0; + return res; +} + +GameActions::Result::Ptr WallRemoveAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + + const bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; + + TileElement* wallElement = GetFirstWallElementAt(_loc, isGhost); + if (wallElement == nullptr) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = tile_element_height(res->Position); + + tile_element_remove_banner_entry(wallElement); + map_invalidate_tile_zoom1({ _loc, wallElement->GetBaseZ(), (wallElement->GetBaseZ()) + 72 }); + tile_element_remove(wallElement); + + return res; +} + +TileElement* WallRemoveAction::GetFirstWallElementAt(const CoordsXYZD& location, bool isGhost) const +{ + TileElement* tileElement = map_get_first_element_at(location); + if (!tileElement) + return nullptr; + + do + { + if (tileElement->GetType() != TILE_ELEMENT_TYPE_WALL) + continue; + if (tileElement->GetBaseZ() != location.z) + continue; + if (tileElement->GetDirection() != location.direction) + continue; + if (tileElement->IsGhost() != isGhost) + continue; + + return tileElement; + } while (!(tileElement++)->IsLastForTile()); + return nullptr; +} diff --git a/src/openrct2/actions/WallRemoveAction.h b/src/openrct2/actions/WallRemoveAction.h new file mode 100644 index 0000000000..26d12a7672 --- /dev/null +++ b/src/openrct2/actions/WallRemoveAction.h @@ -0,0 +1,33 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(WallRemoveAction, GAME_COMMAND_REMOVE_WALL, GameActions::Result) +{ +private: + CoordsXYZD _loc; + +public: + WallRemoveAction() = default; + WallRemoveAction(const CoordsXYZD& loc) + : _loc(loc) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + TileElement* GetFirstWallElementAt(const CoordsXYZD& location, bool isGhost) const; +}; diff --git a/src/openrct2/actions/WallRemoveAction.hpp b/src/openrct2/actions/WallRemoveAction.hpp deleted file mode 100644 index 79227447b4..0000000000 --- a/src/openrct2/actions/WallRemoveAction.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Location.hpp" -#include "../world/Wall.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(WallRemoveAction, GAME_COMMAND_REMOVE_WALL, GameActions::Result) -{ -private: - CoordsXYZD _loc; - -public: - WallRemoveAction() = default; - WallRemoveAction(const CoordsXYZD& loc) - : _loc(loc) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - - if (!LocationValid(_loc)) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - const bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; - if (!isGhost && !(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(_loc)) - { - return std::make_unique( - GameActions::Status::NotOwned, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - TileElement* wallElement = GetFirstWallElementAt(_loc, isGhost); - if (wallElement == nullptr) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - res->Cost = 0; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - - const bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; - - TileElement* wallElement = GetFirstWallElementAt(_loc, isGhost); - if (wallElement == nullptr) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = tile_element_height(res->Position); - - tile_element_remove_banner_entry(wallElement); - map_invalidate_tile_zoom1({ _loc, wallElement->GetBaseZ(), (wallElement->GetBaseZ()) + 72 }); - tile_element_remove(wallElement); - - return res; - } - -private: - TileElement* GetFirstWallElementAt(const CoordsXYZD& location, bool isGhost) const - { - TileElement* tileElement = map_get_first_element_at(location); - if (!tileElement) - return nullptr; - - do - { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_WALL) - continue; - if (tileElement->GetBaseZ() != location.z) - continue; - if (tileElement->GetDirection() != location.direction) - continue; - if (tileElement->IsGhost() != isGhost) - continue; - - return tileElement; - } while (!(tileElement++)->IsLastForTile()); - return nullptr; - } -}; diff --git a/src/openrct2/actions/WallSetColourAction.cpp b/src/openrct2/actions/WallSetColourAction.cpp new file mode 100644 index 0000000000..f150aae7bb --- /dev/null +++ b/src/openrct2/actions/WallSetColourAction.cpp @@ -0,0 +1,132 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "WallSetColourAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../ride/Track.h" +#include "../ride/TrackData.h" +#include "../world/Banner.h" +#include "../world/LargeScenery.h" +#include "../world/MapAnimation.h" +#include "../world/Scenery.h" +#include "../world/SmallScenery.h" +#include "../world/Surface.h" + +void WallSetColourAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) << DS_TAG(_tertiaryColour); +} + +GameActions::Result::Ptr WallSetColourAction::Query() const +{ + auto res = MakeResult(); + res->ErrorTitle = STR_CANT_REPAINT_THIS; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + + res->Expenditure = ExpenditureType::Landscaping; + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_in_park(_loc) && !gCheatsSandboxMode) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto wallElement = map_get_wall_element_at(_loc); + if (wallElement == nullptr) + { + log_error( + "Could not find wall element at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(wallElement->IsGhost())) + { + return res; + } + + rct_scenery_entry* sceneryEntry = wallElement->GetEntry(); + if (sceneryEntry == nullptr) + { + log_error("Could not find wall object"); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + + if (_primaryColour > 31) + { + log_error("Primary colour invalid: colour = %d", _primaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (_secondaryColour > 31) + { + log_error("Secondary colour invalid: colour = %d", _secondaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) + { + if (_tertiaryColour > 31) + { + log_error("Tertiary colour invalid: colour = %d", _tertiaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + } + return res; +} + +GameActions::Result::Ptr WallSetColourAction::Execute() const +{ + auto res = MakeResult(); + res->ErrorTitle = STR_CANT_REPAINT_THIS; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->Expenditure = ExpenditureType::Landscaping; + + auto wallElement = map_get_wall_element_at(_loc); + if (wallElement == nullptr) + { + log_error( + "Could not find wall element at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(wallElement->IsGhost())) + { + return res; + } + + rct_scenery_entry* sceneryEntry = wallElement->GetEntry(); + if (sceneryEntry == nullptr) + { + log_error("Could not find wall object"); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + + wallElement->SetPrimaryColour(_primaryColour); + wallElement->SetSecondaryColour(_secondaryColour); + + if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) + { + wallElement->SetTertiaryColour(_tertiaryColour); + } + map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 72 }); + + return res; +} diff --git a/src/openrct2/actions/WallSetColourAction.h b/src/openrct2/actions/WallSetColourAction.h new file mode 100644 index 0000000000..3a83ea7218 --- /dev/null +++ b/src/openrct2/actions/WallSetColourAction.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(WallSetColourAction, GAME_COMMAND_SET_WALL_COLOUR, GameActions::Result) +{ +private: + CoordsXYZD _loc; + int32_t _primaryColour{}; + int32_t _secondaryColour{}; + int32_t _tertiaryColour{}; + +public: + WallSetColourAction() = default; + + WallSetColourAction(const CoordsXYZD& loc, int32_t primaryColour, int32_t secondaryColour, int32_t tertiaryColour) + : _loc(loc) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + , _tertiaryColour(tertiaryColour) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/WallSetColourAction.hpp b/src/openrct2/actions/WallSetColourAction.hpp deleted file mode 100644 index 99e91cc6c0..0000000000 --- a/src/openrct2/actions/WallSetColourAction.hpp +++ /dev/null @@ -1,162 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../ride/Track.h" -#include "../ride/TrackData.h" -#include "../world/Banner.h" -#include "../world/LargeScenery.h" -#include "../world/MapAnimation.h" -#include "../world/Scenery.h" -#include "../world/SmallScenery.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(WallSetColourAction, GAME_COMMAND_SET_WALL_COLOUR, GameActions::Result) -{ -private: - CoordsXYZD _loc; - int32_t _primaryColour{}; - int32_t _secondaryColour{}; - int32_t _tertiaryColour{}; - -public: - WallSetColourAction() = default; - - WallSetColourAction(const CoordsXYZD& loc, int32_t primaryColour, int32_t secondaryColour, int32_t tertiaryColour) - : _loc(loc) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - , _tertiaryColour(tertiaryColour) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) << DS_TAG(_tertiaryColour); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->ErrorTitle = STR_CANT_REPAINT_THIS; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - - res->Expenditure = ExpenditureType::Landscaping; - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_in_park(_loc) && !gCheatsSandboxMode) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - auto wallElement = map_get_wall_element_at(_loc); - if (wallElement == nullptr) - { - log_error( - "Could not find wall element at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, - _loc.direction); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(wallElement->IsGhost())) - { - return res; - } - - rct_scenery_entry* sceneryEntry = wallElement->GetEntry(); - if (sceneryEntry == nullptr) - { - log_error("Could not find wall object"); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - - if (_primaryColour > 31) - { - log_error("Primary colour invalid: colour = %d", _primaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (_secondaryColour > 31) - { - log_error("Secondary colour invalid: colour = %d", _secondaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) - { - if (_tertiaryColour > 31) - { - log_error("Tertiary colour invalid: colour = %d", _tertiaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - } - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->ErrorTitle = STR_CANT_REPAINT_THIS; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - res->Expenditure = ExpenditureType::Landscaping; - - auto wallElement = map_get_wall_element_at(_loc); - if (wallElement == nullptr) - { - log_error( - "Could not find wall element at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, - _loc.direction); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(wallElement->IsGhost())) - { - return res; - } - - rct_scenery_entry* sceneryEntry = wallElement->GetEntry(); - if (sceneryEntry == nullptr) - { - log_error("Could not find wall object"); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - - wallElement->SetPrimaryColour(_primaryColour); - wallElement->SetSecondaryColour(_secondaryColour); - - if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) - { - wallElement->SetTertiaryColour(_tertiaryColour); - } - map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 72 }); - - return res; - } - -private: -}; diff --git a/src/openrct2/actions/WaterLowerAction.cpp b/src/openrct2/actions/WaterLowerAction.cpp new file mode 100644 index 0000000000..fe3670148d --- /dev/null +++ b/src/openrct2/actions/WaterLowerAction.cpp @@ -0,0 +1,154 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "WaterLowerAction.h" + +#include "../OpenRCT2.h" +#include "../audio/audio.h" +#include "WaterSetHeightAction.h" + +void WaterLowerAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range); +} + +GameActions::Result::Ptr WaterLowerAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr WaterLowerAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr WaterLowerAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + + // Keep big coordinates within map boundaries + auto aX = std::max(32, _range.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); + auto aY = std::max(32, _range.GetTop()); + auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + res->Position.x = ((validRange.GetLeft() + validRange.GetRight()) / 2) + 16; + res->Position.y = ((validRange.GetTop() + validRange.GetBottom()) / 2) + 16; + int16_t z = tile_element_height(res->Position); + int16_t waterHeight = tile_element_water_height(res->Position); + if (waterHeight != 0) + { + z = waterHeight; + } + res->Position.z = z; + res->Expenditure = ExpenditureType::Landscaping; + + uint8_t minHeight = GetLowestHeight(validRange); + bool hasChanged = false; + bool withinOwnership = false; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + withinOwnership = true; + + uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; + if (height == 0) + continue; + + if (height < minHeight) + continue; + + height -= 2; + auto waterSetHeightAction = WaterSetHeightAction({ x, y }, height); + waterSetHeightAction.SetFlags(GetFlags()); + auto result = isExecuting ? GameActions::ExecuteNested(&waterSetHeightAction) + : GameActions::QueryNested(&waterSetHeightAction); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + hasChanged = true; + } + else + { + result->ErrorTitle = STR_CANT_LOWER_WATER_LEVEL_HERE; + return result; + } + } + } + + if (!withinOwnership) + { + GameActions::Result::Ptr ownerShipResult = std::make_unique( + GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + ownerShipResult->ErrorTitle = STR_CANT_LOWER_WATER_LEVEL_HERE; + return ownerShipResult; + } + + if (isExecuting && hasChanged) + { + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::LayingOutWater, res->Position); + } + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + return res; +} + +uint8_t WaterLowerAction::GetLowestHeight(MapRange validRange) const +{ + // The lowest height to lower the water to is the highest water level in the selection + uint8_t minHeight{ 0 }; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; + if (height == 0) + continue; + + if (height > minHeight) + { + minHeight = height; + } + } + } + + return minHeight; +} diff --git a/src/openrct2/actions/WaterLowerAction.h b/src/openrct2/actions/WaterLowerAction.h new file mode 100644 index 0000000000..6d4a9a0d11 --- /dev/null +++ b/src/openrct2/actions/WaterLowerAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(WaterLowerAction, GAME_COMMAND_LOWER_WATER, GameActions::Result) +{ +private: + MapRange _range; + +public: + WaterLowerAction() = default; + WaterLowerAction(MapRange range) + : _range(range) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; + uint8_t GetLowestHeight(MapRange validRange) const; +}; diff --git a/src/openrct2/actions/WaterLowerAction.hpp b/src/openrct2/actions/WaterLowerAction.hpp deleted file mode 100644 index 9591e90cba..0000000000 --- a/src/openrct2/actions/WaterLowerAction.hpp +++ /dev/null @@ -1,173 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../audio/audio.h" -#include "GameAction.h" -#include "WaterSetHeightAction.hpp" - -DEFINE_GAME_ACTION(WaterLowerAction, GAME_COMMAND_LOWER_WATER, GameActions::Result) -{ -private: - MapRange _range; - -public: - WaterLowerAction() = default; - WaterLowerAction(MapRange range) - : _range(range) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - res->Position.x = ((validRange.GetLeft() + validRange.GetRight()) / 2) + 16; - res->Position.y = ((validRange.GetTop() + validRange.GetBottom()) / 2) + 16; - int16_t z = tile_element_height(res->Position); - int16_t waterHeight = tile_element_water_height(res->Position); - if (waterHeight != 0) - { - z = waterHeight; - } - res->Position.z = z; - res->Expenditure = ExpenditureType::Landscaping; - - uint8_t minHeight = GetLowestHeight(validRange); - bool hasChanged = false; - bool withinOwnership = false; - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - - auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - withinOwnership = true; - - uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; - if (height == 0) - continue; - - if (height < minHeight) - continue; - - height -= 2; - auto waterSetHeightAction = WaterSetHeightAction({ x, y }, height); - waterSetHeightAction.SetFlags(GetFlags()); - auto result = isExecuting ? GameActions::ExecuteNested(&waterSetHeightAction) - : GameActions::QueryNested(&waterSetHeightAction); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - hasChanged = true; - } - else - { - result->ErrorTitle = STR_CANT_LOWER_WATER_LEVEL_HERE; - return result; - } - } - } - - if (!withinOwnership) - { - GameActions::Result::Ptr ownerShipResult = std::make_unique( - GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - ownerShipResult->ErrorTitle = STR_CANT_LOWER_WATER_LEVEL_HERE; - return ownerShipResult; - } - - if (isExecuting && hasChanged) - { - OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::LayingOutWater, res->Position); - } - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - return res; - } - -private: - uint8_t GetLowestHeight(MapRange validRange) const - { - // The lowest height to lower the water to is the highest water level in the selection - uint8_t minHeight{ 0 }; - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - - auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; - if (height == 0) - continue; - - if (height > minHeight) - { - minHeight = height; - } - } - } - - return minHeight; - } -}; diff --git a/src/openrct2/actions/WaterRaiseAction.cpp b/src/openrct2/actions/WaterRaiseAction.cpp new file mode 100644 index 0000000000..5503f7a0ba --- /dev/null +++ b/src/openrct2/actions/WaterRaiseAction.cpp @@ -0,0 +1,163 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "WaterRaiseAction.h" + +#include "../OpenRCT2.h" +#include "../audio/audio.h" +#include "WaterSetHeightAction.h" + +void WaterRaiseAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range); +} + +GameActions::Result::Ptr WaterRaiseAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr WaterRaiseAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr WaterRaiseAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + + // Keep big coordinates within map boundaries + auto aX = std::max(32, _range.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); + auto aY = std::max(32, _range.GetTop()); + auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + res->Position.x = ((validRange.GetLeft() + validRange.GetRight()) / 2) + 16; + res->Position.y = ((validRange.GetTop() + validRange.GetBottom()) / 2) + 16; + int32_t z = tile_element_height(res->Position); + int16_t waterHeight = tile_element_water_height(res->Position); + if (waterHeight != 0) + { + z = waterHeight; + } + res->Position.z = z; + res->Expenditure = ExpenditureType::Landscaping; + + auto maxHeight = GetHighestHeight(validRange) / COORDS_Z_STEP; + bool hasChanged = false; + bool withinOwnership = false; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + + auto surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + withinOwnership = true; + + uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; + + if (surfaceElement->base_height > maxHeight) + continue; + + if (height != 0) + { + if (height > maxHeight) + continue; + height += 2; + } + else + { + height = surfaceElement->base_height + 2; + } + auto waterSetHeightAction = WaterSetHeightAction({ x, y }, height); + waterSetHeightAction.SetFlags(GetFlags()); + auto result = isExecuting ? GameActions::ExecuteNested(&waterSetHeightAction) + : GameActions::QueryNested(&waterSetHeightAction); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + hasChanged = true; + } + else + { + result->ErrorTitle = STR_CANT_RAISE_WATER_LEVEL_HERE; + return result; + } + } + } + + if (!withinOwnership) + { + GameActions::Result::Ptr ownerShipResult = std::make_unique( + GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + ownerShipResult->ErrorTitle = STR_CANT_RAISE_WATER_LEVEL_HERE; + return ownerShipResult; + } + + if (isExecuting && hasChanged) + { + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::LayingOutWater, res->Position); + } + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + return res; +} + +uint16_t WaterRaiseAction::GetHighestHeight(MapRange validRange) const +{ + // The highest height to raise the water to is the lowest water level in the selection + uint16_t maxHeight = 255 * COORDS_Z_STEP; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + auto height = surfaceElement->GetBaseZ(); + if (surfaceElement->GetWaterHeight() > 0) + { + height = surfaceElement->GetWaterHeight(); + } + + if (maxHeight > height) + { + maxHeight = height; + } + } + } + + return maxHeight; +} diff --git a/src/openrct2/actions/WaterRaiseAction.h b/src/openrct2/actions/WaterRaiseAction.h new file mode 100644 index 0000000000..08d10818e9 --- /dev/null +++ b/src/openrct2/actions/WaterRaiseAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(WaterRaiseAction, GAME_COMMAND_RAISE_WATER, GameActions::Result) +{ +private: + MapRange _range; + +public: + WaterRaiseAction() = default; + WaterRaiseAction(MapRange range) + : _range(range) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; + uint16_t GetHighestHeight(MapRange validRange) const; +}; diff --git a/src/openrct2/actions/WaterRaiseAction.hpp b/src/openrct2/actions/WaterRaiseAction.hpp deleted file mode 100644 index f18019bd24..0000000000 --- a/src/openrct2/actions/WaterRaiseAction.hpp +++ /dev/null @@ -1,183 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../audio/audio.h" -#include "GameAction.h" -#include "WaterSetHeightAction.hpp" - -DEFINE_GAME_ACTION(WaterRaiseAction, GAME_COMMAND_RAISE_WATER, GameActions::Result) -{ -private: - MapRange _range; - -public: - WaterRaiseAction() = default; - WaterRaiseAction(MapRange range) - : _range(range) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - res->Position.x = ((validRange.GetLeft() + validRange.GetRight()) / 2) + 16; - res->Position.y = ((validRange.GetTop() + validRange.GetBottom()) / 2) + 16; - int32_t z = tile_element_height(res->Position); - int16_t waterHeight = tile_element_water_height(res->Position); - if (waterHeight != 0) - { - z = waterHeight; - } - res->Position.z = z; - res->Expenditure = ExpenditureType::Landscaping; - - auto maxHeight = GetHighestHeight(validRange) / COORDS_Z_STEP; - bool hasChanged = false; - bool withinOwnership = false; - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - - auto surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - withinOwnership = true; - - uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; - - if (surfaceElement->base_height > maxHeight) - continue; - - if (height != 0) - { - if (height > maxHeight) - continue; - height += 2; - } - else - { - height = surfaceElement->base_height + 2; - } - auto waterSetHeightAction = WaterSetHeightAction({ x, y }, height); - waterSetHeightAction.SetFlags(GetFlags()); - auto result = isExecuting ? GameActions::ExecuteNested(&waterSetHeightAction) - : GameActions::QueryNested(&waterSetHeightAction); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - hasChanged = true; - } - else - { - result->ErrorTitle = STR_CANT_RAISE_WATER_LEVEL_HERE; - return result; - } - } - } - - if (!withinOwnership) - { - GameActions::Result::Ptr ownerShipResult = std::make_unique( - GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - ownerShipResult->ErrorTitle = STR_CANT_RAISE_WATER_LEVEL_HERE; - return ownerShipResult; - } - - if (isExecuting && hasChanged) - { - OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::LayingOutWater, res->Position); - } - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - return res; - } - -private: - uint16_t GetHighestHeight(MapRange validRange) const - { - // The highest height to raise the water to is the lowest water level in the selection - uint16_t maxHeight = 255 * COORDS_Z_STEP; - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - - auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - auto height = surfaceElement->GetBaseZ(); - if (surfaceElement->GetWaterHeight() > 0) - { - height = surfaceElement->GetWaterHeight(); - } - - if (maxHeight > height) - { - maxHeight = height; - } - } - } - - return maxHeight; - } -}; diff --git a/src/openrct2/actions/WaterSetHeightAction.cpp b/src/openrct2/actions/WaterSetHeightAction.cpp new file mode 100644 index 0000000000..3942c3167e --- /dev/null +++ b/src/openrct2/actions/WaterSetHeightAction.cpp @@ -0,0 +1,141 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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. + *****************************************************************************/ + +#include "WaterSetHeightAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../world/Park.h" +#include "../world/Surface.h" + +void WaterSetHeightAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_height); +} + +GameActions::Result::Ptr WaterSetHeightAction::Query() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position = { _coords, _height * COORDS_Z_STEP }; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode + && gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) + { + return MakeResult(GameActions::Status::Disallowed, STR_NONE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); + } + + rct_string_id errorMsg = CheckParameters(); + if (errorMsg != STR_NONE) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, errorMsg); + } + + if (!LocationValid(_coords)) + { + return MakeResult(GameActions::Status::NotOwned, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(_coords)) + { + return MakeResult(GameActions::Status::Disallowed, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + SurfaceElement* surfaceElement = map_get_surface_element_at(_coords); + if (surfaceElement == nullptr) + { + log_error("Could not find surface element at: x %u, y %u", _coords.x, _coords.y); + return MakeResult(GameActions::Status::Unknown, STR_NONE); + } + + int32_t zHigh = surfaceElement->GetBaseZ(); + int32_t zLow = _height * COORDS_Z_STEP; + if (surfaceElement->GetWaterHeight() > 0) + { + zHigh = surfaceElement->GetWaterHeight(); + } + if (zLow > zHigh) + { + int32_t temp = zHigh; + zHigh = zLow; + zLow = temp; + } + + if (auto res2 = MapCanConstructAt({ _coords, zLow, zHigh }, { 0b1111, 0b1111 }); res2->Error != GameActions::Status::Ok) + { + return MakeResult( + GameActions::Status::NoClearance, STR_NONE, res2->ErrorMessage.GetStringId(), res2->ErrorMessageArgs.data()); + } + if (surfaceElement->HasTrackThatNeedsWater()) + { + return MakeResult(GameActions::Status::Disallowed, STR_NONE); + } + + res->Cost = 250; + + return res; +} + +GameActions::Result::Ptr WaterSetHeightAction::Execute() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position = { _coords, _height * COORDS_Z_STEP }; + + int32_t surfaceHeight = tile_element_height(_coords); + footpath_remove_litter({ _coords, surfaceHeight }); + if (!gCheatsDisableClearanceChecks) + wall_remove_at_z({ _coords, surfaceHeight }); + + SurfaceElement* surfaceElement = map_get_surface_element_at(_coords); + if (surfaceElement == nullptr) + { + log_error("Could not find surface element at: x %u, y %u", _coords.x, _coords.y); + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + } + + if (_height > surfaceElement->base_height) + { + surfaceElement->SetWaterHeight(_height * COORDS_Z_STEP); + } + else + { + surfaceElement->SetWaterHeight(0); + } + map_invalidate_tile_full(_coords); + + res->Cost = 250; + + return res; +} + +rct_string_id WaterSetHeightAction::CheckParameters() const +{ + if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY) + { + return STR_OFF_EDGE_OF_MAP; + } + + if (_height < MINIMUM_WATER_HEIGHT) + { + return STR_TOO_LOW; + } + + if (_height > MAXIMUM_WATER_HEIGHT) + { + return STR_TOO_HIGH; + } + + return STR_NONE; +} diff --git a/src/openrct2/actions/WaterSetHeightAction.h b/src/openrct2/actions/WaterSetHeightAction.h new file mode 100644 index 0000000000..7cfdbbe14c --- /dev/null +++ b/src/openrct2/actions/WaterSetHeightAction.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 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 "GameAction.h" + +DEFINE_GAME_ACTION(WaterSetHeightAction, GAME_COMMAND_SET_WATER_HEIGHT, GameActions::Result) +{ +private: + CoordsXY _coords; + uint8_t _height{}; + +public: + WaterSetHeightAction() = default; + WaterSetHeightAction(const CoordsXY& coords, uint8_t height) + : _coords(coords) + , _height(height) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + rct_string_id CheckParameters() const; +}; diff --git a/src/openrct2/actions/WaterSetHeightAction.hpp b/src/openrct2/actions/WaterSetHeightAction.hpp deleted file mode 100644 index 423b4c372b..0000000000 --- a/src/openrct2/actions/WaterSetHeightAction.hpp +++ /dev/null @@ -1,163 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 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 "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../world/Park.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(WaterSetHeightAction, GAME_COMMAND_SET_WATER_HEIGHT, GameActions::Result) -{ -private: - CoordsXY _coords; - uint8_t _height{}; - -public: - WaterSetHeightAction() = default; - WaterSetHeightAction(const CoordsXY& coords, uint8_t height) - : _coords(coords) - , _height(height) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_coords) << DS_TAG(_height); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position = { _coords, _height * COORDS_Z_STEP }; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode - && gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) - { - return MakeResult(GameActions::Status::Disallowed, STR_NONE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); - } - - rct_string_id errorMsg = CheckParameters(); - if (errorMsg != STR_NONE) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, errorMsg); - } - - if (!LocationValid(_coords)) - { - return MakeResult(GameActions::Status::NotOwned, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(_coords)) - { - return MakeResult(GameActions::Status::Disallowed, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - SurfaceElement* surfaceElement = map_get_surface_element_at(_coords); - if (surfaceElement == nullptr) - { - log_error("Could not find surface element at: x %u, y %u", _coords.x, _coords.y); - return MakeResult(GameActions::Status::Unknown, STR_NONE); - } - - int32_t zHigh = surfaceElement->GetBaseZ(); - int32_t zLow = _height * COORDS_Z_STEP; - if (surfaceElement->GetWaterHeight() > 0) - { - zHigh = surfaceElement->GetWaterHeight(); - } - if (zLow > zHigh) - { - int32_t temp = zHigh; - zHigh = zLow; - zLow = temp; - } - - if (auto res2 = MapCanConstructAt({ _coords, zLow, zHigh }, { 0b1111, 0b1111 }); res2->Error != GameActions::Status::Ok) - { - return MakeResult( - GameActions::Status::NoClearance, STR_NONE, res2->ErrorMessage.GetStringId(), res2->ErrorMessageArgs.data()); - } - if (surfaceElement->HasTrackThatNeedsWater()) - { - return MakeResult(GameActions::Status::Disallowed, STR_NONE); - } - - res->Cost = 250; - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position = { _coords, _height * COORDS_Z_STEP }; - - int32_t surfaceHeight = tile_element_height(_coords); - footpath_remove_litter({ _coords, surfaceHeight }); - if (!gCheatsDisableClearanceChecks) - wall_remove_at_z({ _coords, surfaceHeight }); - - SurfaceElement* surfaceElement = map_get_surface_element_at(_coords); - if (surfaceElement == nullptr) - { - log_error("Could not find surface element at: x %u, y %u", _coords.x, _coords.y); - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - } - - if (_height > surfaceElement->base_height) - { - surfaceElement->SetWaterHeight(_height * COORDS_Z_STEP); - } - else - { - surfaceElement->SetWaterHeight(0); - } - map_invalidate_tile_full(_coords); - - res->Cost = 250; - - return res; - } - -private: - rct_string_id CheckParameters() const - { - if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY) - { - return STR_OFF_EDGE_OF_MAP; - } - - if (_height < MINIMUM_WATER_HEIGHT) - { - return STR_TOO_LOW; - } - - if (_height > MAXIMUM_WATER_HEIGHT) - { - return STR_TOO_HIGH; - } - - return STR_NONE; - } -}; diff --git a/src/openrct2/interface/InteractiveConsole.cpp b/src/openrct2/interface/InteractiveConsole.cpp index 6526bcebc4..f762d76fd3 100644 --- a/src/openrct2/interface/InteractiveConsole.cpp +++ b/src/openrct2/interface/InteractiveConsole.cpp @@ -16,11 +16,11 @@ #include "../PlatformEnvironment.h" #include "../ReplayManager.h" #include "../Version.h" -#include "../actions/ClimateSetAction.hpp" -#include "../actions/RideSetPriceAction.hpp" -#include "../actions/RideSetSetting.hpp" -#include "../actions/SetCheatAction.hpp" -#include "../actions/StaffSetCostumeAction.hpp" +#include "../actions/ClimateSetAction.h" +#include "../actions/RideSetPriceAction.h" +#include "../actions/RideSetSettingAction.h" +#include "../actions/SetCheatAction.h" +#include "../actions/StaffSetCostumeAction.h" #include "../config/Config.h" #include "../core/Guard.hpp" #include "../core/Path.hpp" diff --git a/src/openrct2/interface/Screenshot.cpp b/src/openrct2/interface/Screenshot.cpp index 9370a1e94a..0c90e69f29 100644 --- a/src/openrct2/interface/Screenshot.cpp +++ b/src/openrct2/interface/Screenshot.cpp @@ -11,9 +11,10 @@ #include "../Context.h" #include "../Game.h" +#include "../GameState.h" #include "../Intro.h" #include "../OpenRCT2.h" -#include "../actions/SetCheatAction.hpp" +#include "../actions/SetCheatAction.h" #include "../audio/audio.h" #include "../core/Console.hpp" #include "../core/Imaging.h" diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 4f655f918d..43d1df1f5f 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -1,4 +1,3 @@ - ..\..\ @@ -53,87 +52,87 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + @@ -461,10 +460,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openrct2/management/Research.cpp b/src/openrct2/management/Research.cpp index b480943546..6e0e937168 100644 --- a/src/openrct2/management/Research.cpp +++ b/src/openrct2/management/Research.cpp @@ -11,7 +11,7 @@ #include "../Game.h" #include "../OpenRCT2.h" -#include "../actions/ParkSetResearchFundingAction.hpp" +#include "../actions/ParkSetResearchFundingAction.h" #include "../config/Config.h" #include "../core/Guard.hpp" #include "../core/Memory.hpp" diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index c8adb289ee..143bf3a8fe 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -14,9 +14,9 @@ #include "../GameStateSnapshots.h" #include "../OpenRCT2.h" #include "../PlatformEnvironment.h" -#include "../actions/LoadOrQuitAction.hpp" -#include "../actions/NetworkModifyGroupAction.hpp" -#include "../actions/PeepPickupAction.hpp" +#include "../actions/LoadOrQuitAction.h" +#include "../actions/NetworkModifyGroupAction.h" +#include "../actions/PeepPickupAction.h" #include "../core/Guard.hpp" #include "../core/Json.hpp" #include "../platform/Platform2.h" diff --git a/src/openrct2/peep/Staff.cpp b/src/openrct2/peep/Staff.cpp index 4be4313d67..2be4377529 100644 --- a/src/openrct2/peep/Staff.cpp +++ b/src/openrct2/peep/Staff.cpp @@ -12,8 +12,8 @@ #include "../Context.h" #include "../Game.h" #include "../Input.h" -#include "../actions/StaffHireNewAction.hpp" -#include "../actions/StaffSetOrdersAction.hpp" +#include "../actions/StaffHireNewAction.h" +#include "../actions/StaffSetOrdersAction.h" #include "../audio/audio.h" #include "../config/Config.h" #include "../interface/Viewport.h" @@ -31,6 +31,7 @@ #include "../ride/Track.h" #include "../scenario/Scenario.h" #include "../util/Util.h" +#include "../windows/Intent.h" #include "../world/Entrance.h" #include "../world/Footpath.h" #include "../world/Scenery.h" diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 5752ed82e5..cc917f964f 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -13,7 +13,7 @@ #include "../Game.h" #include "../GameState.h" #include "../ParkImporter.h" -#include "../actions/WallPlaceAction.hpp" +#include "../actions/WallPlaceAction.h" #include "../audio/audio.h" #include "../core/Collections.hpp" #include "../core/Console.hpp" diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 4b37886a04..3a9e7ee5b7 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -15,11 +15,11 @@ #include "../Game.h" #include "../Input.h" #include "../OpenRCT2.h" -#include "../actions/RideEntranceExitRemoveAction.hpp" -#include "../actions/RideSetSetting.hpp" -#include "../actions/RideSetStatus.hpp" -#include "../actions/RideSetVehiclesAction.hpp" -#include "../actions/TrackRemoveAction.hpp" +#include "../actions/RideEntranceExitRemoveAction.h" +#include "../actions/RideSetSettingAction.h" +#include "../actions/RideSetStatusAction.h" +#include "../actions/RideSetVehicleAction.h" +#include "../actions/TrackRemoveAction.h" #include "../audio/AudioMixer.h" #include "../audio/audio.h" #include "../common.h" diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 94d3967321..f21dc29267 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -10,25 +10,26 @@ #include "TrackDesign.h" #include "../Cheats.h" +#include "../Context.h" #include "../Game.h" #include "../OpenRCT2.h" #include "../TrackImporter.h" -#include "../actions/FootpathPlaceFromTrackAction.hpp" -#include "../actions/FootpathRemoveAction.hpp" -#include "../actions/LargeSceneryPlaceAction.hpp" -#include "../actions/LargeSceneryRemoveAction.hpp" -#include "../actions/MazePlaceTrackAction.hpp" -#include "../actions/RideCreateAction.hpp" -#include "../actions/RideEntranceExitPlaceAction.hpp" -#include "../actions/RideSetName.hpp" -#include "../actions/RideSetSetting.hpp" -#include "../actions/RideSetVehiclesAction.hpp" -#include "../actions/SmallSceneryPlaceAction.hpp" -#include "../actions/SmallSceneryRemoveAction.hpp" -#include "../actions/TrackPlaceAction.hpp" -#include "../actions/TrackRemoveAction.hpp" -#include "../actions/WallPlaceAction.hpp" -#include "../actions/WallRemoveAction.hpp" +#include "../actions/FootpathPlaceFromTrackAction.h" +#include "../actions/FootpathRemoveAction.h" +#include "../actions/LargeSceneryPlaceAction.h" +#include "../actions/LargeSceneryRemoveAction.h" +#include "../actions/MazePlaceTrackAction.h" +#include "../actions/RideCreateAction.h" +#include "../actions/RideEntranceExitPlaceAction.h" +#include "../actions/RideSetNameAction.h" +#include "../actions/RideSetSettingAction.h" +#include "../actions/RideSetVehicleAction.h" +#include "../actions/SmallSceneryPlaceAction.h" +#include "../actions/SmallSceneryRemoveAction.h" +#include "../actions/TrackPlaceAction.h" +#include "../actions/TrackRemoveAction.h" +#include "../actions/WallPlaceAction.h" +#include "../actions/WallRemoveAction.h" #include "../audio/audio.h" #include "../core/DataSerialiser.h" #include "../core/File.h" diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index 97d2a58dac..989d817869 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -13,7 +13,7 @@ #include "../Editor.h" #include "../Game.h" #include "../OpenRCT2.h" -#include "../actions/RideSetStatus.hpp" +#include "../actions/RideSetStatusAction.h" #include "../audio/AudioMixer.h" #include "../audio/audio.h" #include "../config/Config.h" diff --git a/src/openrct2/scripting/ScNetwork.hpp b/src/openrct2/scripting/ScNetwork.hpp index f2e67683fb..bd183c6549 100644 --- a/src/openrct2/scripting/ScNetwork.hpp +++ b/src/openrct2/scripting/ScNetwork.hpp @@ -12,9 +12,9 @@ #ifdef ENABLE_SCRIPTING # include "../Context.h" -# include "../actions/NetworkModifyGroupAction.hpp" -# include "../actions/PlayerKickAction.hpp" -# include "../actions/PlayerSetGroupAction.hpp" +# include "../actions/NetworkModifyGroupAction.h" +# include "../actions/PlayerKickAction.h" +# include "../actions/PlayerSetGroupAction.h" # include "../network/NetworkAction.h" # include "../network/network.h" # include "Duktape.hpp" diff --git a/src/openrct2/scripting/ScriptEngine.cpp b/src/openrct2/scripting/ScriptEngine.cpp index 635ee06f61..18dc9d1530 100644 --- a/src/openrct2/scripting/ScriptEngine.cpp +++ b/src/openrct2/scripting/ScriptEngine.cpp @@ -12,10 +12,10 @@ # include "ScriptEngine.h" # include "../PlatformEnvironment.h" -# include "../actions/CustomAction.hpp" +# include "../actions/CustomAction.h" # include "../actions/GameAction.h" -# include "../actions/RideCreateAction.hpp" -# include "../actions/StaffHireNewAction.hpp" +# include "../actions/RideCreateAction.h" +# include "../actions/StaffHireNewAction.h" # include "../config/Config.h" # include "../core/File.h" # include "../core/FileScanner.h" diff --git a/src/openrct2/windows/_legacy.cpp b/src/openrct2/windows/_legacy.cpp index a6f914e387..214ddb023f 100644 --- a/src/openrct2/windows/_legacy.cpp +++ b/src/openrct2/windows/_legacy.cpp @@ -11,7 +11,7 @@ #include "../Context.h" #include "../Game.h" #include "../Input.h" -#include "../actions/TrackPlaceAction.hpp" +#include "../actions/TrackPlaceAction.h" #include "../audio/audio.h" #include "../interface/Viewport.h" #include "../network/network.h" diff --git a/src/openrct2/world/Entrance.cpp b/src/openrct2/world/Entrance.cpp index ab0ca323a5..b5fbc0b81f 100644 --- a/src/openrct2/world/Entrance.cpp +++ b/src/openrct2/world/Entrance.cpp @@ -12,9 +12,9 @@ #include "../Cheats.h" #include "../Game.h" #include "../OpenRCT2.h" -#include "../actions/ParkEntranceRemoveAction.hpp" -#include "../actions/RideEntranceExitPlaceAction.hpp" -#include "../actions/RideEntranceExitRemoveAction.hpp" +#include "../actions/ParkEntranceRemoveAction.h" +#include "../actions/RideEntranceExitPlaceAction.h" +#include "../actions/RideEntranceExitRemoveAction.h" #include "../localisation/StringIds.h" #include "../management/Finance.h" #include "../network/network.h" diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 24ba945fa8..e740f4812e 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -11,9 +11,9 @@ #include "../Context.h" #include "../Game.h" #include "../OpenRCT2.h" -#include "../actions/FootpathPlaceAction.hpp" -#include "../actions/FootpathRemoveAction.hpp" -#include "../actions/LandSetRightsAction.hpp" +#include "../actions/FootpathPlaceAction.h" +#include "../actions/FootpathRemoveAction.h" +#include "../actions/LandSetRightsAction.h" #include "../core/Guard.hpp" #include "../interface/Window_internal.h" #include "../localisation/Localisation.h" @@ -23,6 +23,7 @@ #include "../object/ObjectList.h" #include "../object/ObjectManager.h" #include "../paint/VirtualFloor.h" +#include "../ride/RideData.h" #include "../ride/Station.h" #include "../ride/Track.h" #include "../ride/TrackData.h" diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 12c79af0ef..574c6403eb 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -14,17 +14,17 @@ #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" -#include "../actions/LandSetHeightAction.hpp" -#include "../actions/LandSetRightsAction.hpp" -#include "../actions/LargeSceneryRemoveAction.hpp" -#include "../actions/ParkEntranceRemoveAction.hpp" -#include "../actions/SmallSceneryRemoveAction.hpp" -#include "../actions/WallRemoveAction.hpp" -#include "../actions/WaterSetHeightAction.hpp" +#include "../actions/BannerRemoveAction.h" +#include "../actions/FootpathRemoveAction.h" +#include "../actions/LandLowerAction.h" +#include "../actions/LandRaiseAction.h" +#include "../actions/LandSetHeightAction.h" +#include "../actions/LandSetRightsAction.h" +#include "../actions/LargeSceneryRemoveAction.h" +#include "../actions/ParkEntranceRemoveAction.h" +#include "../actions/SmallSceneryRemoveAction.h" +#include "../actions/WallRemoveAction.h" +#include "../actions/WaterSetHeightAction.h" #include "../audio/audio.h" #include "../config/Config.h" #include "../core/Guard.hpp" diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 4ce607a269..50816d93c6 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -15,7 +15,7 @@ #include "../Game.h" #include "../GameState.h" #include "../OpenRCT2.h" -#include "../actions/ParkSetParameterAction.hpp" +#include "../actions/ParkSetParameterAction.h" #include "../config/Config.h" #include "../core/Memory.hpp" #include "../interface/Colour.h" diff --git a/src/openrct2/world/Scenery.cpp b/src/openrct2/world/Scenery.cpp index 6503b0ffed..5240a7fdff 100644 --- a/src/openrct2/world/Scenery.cpp +++ b/src/openrct2/world/Scenery.cpp @@ -12,11 +12,11 @@ #include "../Cheats.h" #include "../Context.h" #include "../Game.h" -#include "../actions/BannerRemoveAction.hpp" -#include "../actions/FootpathAdditionRemoveAction.hpp" -#include "../actions/LargeSceneryRemoveAction.hpp" -#include "../actions/SmallSceneryRemoveAction.hpp" -#include "../actions/WallRemoveAction.hpp" +#include "../actions/BannerRemoveAction.h" +#include "../actions/FootpathAdditionRemoveAction.h" +#include "../actions/LargeSceneryRemoveAction.h" +#include "../actions/SmallSceneryRemoveAction.h" +#include "../actions/WallRemoveAction.h" #include "../common.h" #include "../localisation/Localisation.h" #include "../network/network.h" diff --git a/test/tests/PlayTests.cpp b/test/tests/PlayTests.cpp index ae6e58f096..c73dfc4526 100644 --- a/test/tests/PlayTests.cpp +++ b/test/tests/PlayTests.cpp @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include