mirror of https://github.com/OpenRCT2/OpenRCT2.git
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 <duncans_pumpkin@hotmail.co.uk>
This commit is contained in:
parent
5a849ededf
commit
f09b14ef2b
|
@ -6,7 +6,7 @@
|
|||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/src"
|
||||
"${workspaceRoot}/src/**"
|
||||
],
|
||||
"defines": [],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,8 +18,8 @@
|
|||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/actions/LoadOrQuitAction.hpp>
|
||||
#include <openrct2/actions/SetCheatAction.hpp>
|
||||
#include <openrct2/actions/LoadOrQuitAction.h>
|
||||
#include <openrct2/actions/SetCheatAction.h>
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/interface/Chat.h>
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
#include <openrct2/GameState.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/actions/BalloonPressAction.hpp>
|
||||
#include <openrct2/actions/FootpathAdditionRemoveAction.hpp>
|
||||
#include <openrct2/actions/LargeSceneryRemoveAction.hpp>
|
||||
#include <openrct2/actions/ParkEntranceRemoveAction.hpp>
|
||||
#include <openrct2/actions/SmallSceneryRemoveAction.hpp>
|
||||
#include <openrct2/actions/WallRemoveAction.hpp>
|
||||
#include <openrct2/actions/BalloonPressAction.h>
|
||||
#include <openrct2/actions/FootpathAdditionRemoveAction.h>
|
||||
#include <openrct2/actions/LargeSceneryRemoveAction.h>
|
||||
#include <openrct2/actions/ParkEntranceRemoveAction.h>
|
||||
#include <openrct2/actions/SmallSceneryRemoveAction.h>
|
||||
#include <openrct2/actions/WallRemoveAction.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/ride/Ride.h>
|
||||
#include <openrct2/ride/RideData.h>
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
#include <openrct2-ui/interface/Widget.h>
|
||||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/actions/BannerRemoveAction.hpp>
|
||||
#include <openrct2/actions/BannerSetColourAction.hpp>
|
||||
#include <openrct2/actions/BannerSetNameAction.hpp>
|
||||
#include <openrct2/actions/BannerSetStyleAction.hpp>
|
||||
#include <openrct2/actions/BannerRemoveAction.h>
|
||||
#include <openrct2/actions/BannerSetColourAction.h>
|
||||
#include <openrct2/actions/BannerSetNameAction.h>
|
||||
#include <openrct2/actions/BannerSetStyleAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/sprites.h>
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/actions/ParkSetDateAction.hpp>
|
||||
#include <openrct2/actions/SetCheatAction.hpp>
|
||||
#include <openrct2/actions/ParkSetDateAction.h>
|
||||
#include <openrct2/actions/SetCheatAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/localisation/Date.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <openrct2/EditorObjectSelectionSession.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/actions/LoadOrQuitAction.hpp>
|
||||
#include <openrct2/actions/LoadOrQuitAction.h>
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/core/String.hpp>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <openrct2/Context.h>
|
||||
#include <openrct2/GameState.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/actions/ParkSetNameAction.hpp>
|
||||
#include <openrct2/actions/ParkSetNameAction.h>
|
||||
#include <openrct2/core/String.hpp>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/drawing/Font.h>
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
#include <openrct2/Editor.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/actions/ClimateSetAction.hpp>
|
||||
#include <openrct2/actions/ScenarioSetSettingAction.hpp>
|
||||
#include <openrct2/actions/ClimateSetAction.h>
|
||||
#include <openrct2/actions/ScenarioSetSettingAction.h>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/interface/Colour.h>
|
||||
#include <openrct2/localisation/StringIds.h>
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/GameState.h>
|
||||
#include <openrct2/actions/ParkSetLoanAction.hpp>
|
||||
#include <openrct2/actions/ParkSetResearchFundingAction.hpp>
|
||||
#include <openrct2/actions/ParkSetLoanAction.h>
|
||||
#include <openrct2/actions/ParkSetResearchFundingAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/localisation/Date.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/actions/FootpathPlaceAction.hpp>
|
||||
#include <openrct2/actions/FootpathPlaceAction.h>
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/object/ObjectLimits.h>
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#include <openrct2/Game.h>
|
||||
#include <openrct2/GameState.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/actions/GuestSetFlagsAction.hpp>
|
||||
#include <openrct2/actions/PeepPickupAction.hpp>
|
||||
#include <openrct2/actions/GuestSetFlagsAction.h>
|
||||
#include <openrct2/actions/PeepPickupAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/management/Marketing.h>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/actions/LandBuyRightsAction.hpp>
|
||||
#include <openrct2/actions/LandBuyRightsAction.h>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/world/Park.h>
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/actions/LandSetRightsAction.hpp>
|
||||
#include <openrct2/actions/PlaceParkEntranceAction.hpp>
|
||||
#include <openrct2/actions/PlacePeepSpawnAction.hpp>
|
||||
#include <openrct2/actions/SurfaceSetStyleAction.hpp>
|
||||
#include <openrct2/actions/LandSetRightsAction.h>
|
||||
#include <openrct2/actions/PlaceParkEntranceAction.h>
|
||||
#include <openrct2/actions/PlacePeepSpawnAction.h>
|
||||
#include <openrct2/actions/SurfaceSetStyleAction.h>
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/ride/RideData.h>
|
||||
#include <openrct2/ride/Track.h>
|
||||
#include <openrct2/world/Entrance.h>
|
||||
#include <openrct2/world/Footpath.h>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/actions/RideEntranceExitPlaceAction.hpp>
|
||||
#include <openrct2/actions/RideEntranceExitPlaceAction.h>
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <openrct2-ui/interface/Widget.h>
|
||||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/actions/NetworkModifyGroupAction.hpp>
|
||||
#include <openrct2/actions/NetworkModifyGroupAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <openrct2-ui/interface/Widget.h>
|
||||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/actions/ParkMarketingAction.hpp>
|
||||
#include <openrct2/actions/ParkMarketingAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <openrct2/Game.h>
|
||||
#include <openrct2/GameState.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/actions/ParkSetNameAction.hpp>
|
||||
#include <openrct2/actions/ParkSetNameAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/localisation/Date.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/actions/PlayerKickAction.hpp>
|
||||
#include <openrct2/actions/PlayerSetGroupAction.hpp>
|
||||
#include <openrct2/actions/PlayerKickAction.h>
|
||||
#include <openrct2/actions/PlayerSetGroupAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/interface/Colour.h>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <openrct2-ui/interface/Widget.h>
|
||||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/actions/ParkSetResearchFundingAction.hpp>
|
||||
#include <openrct2/actions/ParkSetResearchFundingAction.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/management/Finance.h>
|
||||
#include <openrct2/management/NewsItem.h>
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
#include <openrct2/Input.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/actions/GameAction.h>
|
||||
#include <openrct2/actions/ParkSetParameterAction.hpp>
|
||||
#include <openrct2/actions/RideSetAppearanceAction.hpp>
|
||||
#include <openrct2/actions/RideSetColourScheme.hpp>
|
||||
#include <openrct2/actions/RideSetPriceAction.hpp>
|
||||
#include <openrct2/actions/RideSetSetting.hpp>
|
||||
#include <openrct2/actions/ParkSetParameterAction.h>
|
||||
#include <openrct2/actions/RideSetAppearanceAction.h>
|
||||
#include <openrct2/actions/RideSetColourSchemeAction.h>
|
||||
#include <openrct2/actions/RideSetPriceAction.h>
|
||||
#include <openrct2/actions/RideSetSettingAction.h>
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/core/String.hpp>
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/actions/RideEntranceExitPlaceAction.hpp>
|
||||
#include <openrct2/actions/TrackPlaceAction.hpp>
|
||||
#include <openrct2/actions/TrackRemoveAction.hpp>
|
||||
#include <openrct2/actions/TrackSetBrakeSpeedAction.hpp>
|
||||
#include <openrct2/actions/RideEntranceExitPlaceAction.h>
|
||||
#include <openrct2/actions/TrackPlaceAction.h>
|
||||
#include <openrct2/actions/TrackRemoveAction.h>
|
||||
#include <openrct2/actions/TrackSetBrakeSpeedAction.h>
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
#include <openrct2-ui/interface/Widget.h>
|
||||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/actions/LargeSceneryRemoveAction.hpp>
|
||||
#include <openrct2/actions/SignSetNameAction.hpp>
|
||||
#include <openrct2/actions/SignSetStyleAction.hpp>
|
||||
#include <openrct2/actions/WallRemoveAction.hpp>
|
||||
#include <openrct2/actions/LargeSceneryRemoveAction.h>
|
||||
#include <openrct2/actions/SignSetNameAction.h>
|
||||
#include <openrct2/actions/SignSetStyleAction.h>
|
||||
#include <openrct2/actions/WallRemoveAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/localisation/StringIds.h>
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/actions/PeepPickupAction.hpp>
|
||||
#include <openrct2/actions/StaffSetCostumeAction.hpp>
|
||||
#include <openrct2/actions/StaffSetOrdersAction.hpp>
|
||||
#include <openrct2/actions/StaffSetPatrolAreaAction.hpp>
|
||||
#include <openrct2/actions/PeepPickupAction.h>
|
||||
#include <openrct2/actions/StaffSetCostumeAction.h>
|
||||
#include <openrct2/actions/StaffSetOrdersAction.h>
|
||||
#include <openrct2/actions/StaffSetPatrolAreaAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/management/Finance.h>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <openrct2-ui/interface/Widget.h>
|
||||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/actions/StaffFireAction.hpp>
|
||||
#include <openrct2/actions/StaffFireAction.h>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/interface/Colour.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/actions/StaffFireAction.hpp>
|
||||
#include <openrct2/actions/StaffSetColourAction.hpp>
|
||||
#include <openrct2/actions/StaffFireAction.h>
|
||||
#include <openrct2/actions/StaffSetColourAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/actions/TileModifyAction.hpp>
|
||||
#include <openrct2/actions/TileModifyAction.h>
|
||||
#include <openrct2/common.h>
|
||||
#include <openrct2/core/Guard.hpp>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <openrct2/Input.h>
|
||||
#include <openrct2/ParkImporter.h>
|
||||
#include <openrct2/PlatformEnvironment.h>
|
||||
#include <openrct2/actions/LoadOrQuitAction.hpp>
|
||||
#include <openrct2/actions/LoadOrQuitAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/sprites.h>
|
||||
|
|
|
@ -26,25 +26,25 @@
|
|||
#include <openrct2/Input.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/ParkImporter.h>
|
||||
#include <openrct2/actions/BannerPlaceAction.hpp>
|
||||
#include <openrct2/actions/BannerSetColourAction.hpp>
|
||||
#include <openrct2/actions/ClearAction.hpp>
|
||||
#include <openrct2/actions/FootpathAdditionPlaceAction.hpp>
|
||||
#include <openrct2/actions/LandLowerAction.hpp>
|
||||
#include <openrct2/actions/LandRaiseAction.hpp>
|
||||
#include <openrct2/actions/LandSmoothAction.hpp>
|
||||
#include <openrct2/actions/LargeSceneryPlaceAction.hpp>
|
||||
#include <openrct2/actions/LargeScenerySetColourAction.hpp>
|
||||
#include <openrct2/actions/LoadOrQuitAction.hpp>
|
||||
#include <openrct2/actions/PauseToggleAction.hpp>
|
||||
#include <openrct2/actions/SetCheatAction.hpp>
|
||||
#include <openrct2/actions/SmallSceneryPlaceAction.hpp>
|
||||
#include <openrct2/actions/SmallScenerySetColourAction.hpp>
|
||||
#include <openrct2/actions/SurfaceSetStyleAction.hpp>
|
||||
#include <openrct2/actions/WallPlaceAction.hpp>
|
||||
#include <openrct2/actions/WallSetColourAction.hpp>
|
||||
#include <openrct2/actions/WaterLowerAction.hpp>
|
||||
#include <openrct2/actions/WaterRaiseAction.hpp>
|
||||
#include <openrct2/actions/BannerPlaceAction.h>
|
||||
#include <openrct2/actions/BannerSetColourAction.h>
|
||||
#include <openrct2/actions/ClearAction.h>
|
||||
#include <openrct2/actions/FootpathAdditionPlaceAction.h>
|
||||
#include <openrct2/actions/LandLowerAction.h>
|
||||
#include <openrct2/actions/LandRaiseAction.h>
|
||||
#include <openrct2/actions/LandSmoothAction.h>
|
||||
#include <openrct2/actions/LargeSceneryPlaceAction.h>
|
||||
#include <openrct2/actions/LargeScenerySetColourAction.h>
|
||||
#include <openrct2/actions/LoadOrQuitAction.h>
|
||||
#include <openrct2/actions/PauseToggleAction.h>
|
||||
#include <openrct2/actions/SetCheatAction.h>
|
||||
#include <openrct2/actions/SmallSceneryPlaceAction.h>
|
||||
#include <openrct2/actions/SmallScenerySetColourAction.h>
|
||||
#include <openrct2/actions/SurfaceSetStyleAction.h>
|
||||
#include <openrct2/actions/WallPlaceAction.h>
|
||||
#include <openrct2/actions/WallSetColourAction.h>
|
||||
#include <openrct2/actions/WaterLowerAction.h>
|
||||
#include <openrct2/actions/WaterRaiseAction.h>
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/interface/Chat.h>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<Balloon>(_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<Balloon>(_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();
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<Balloon>(_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<Balloon>(_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();
|
||||
}
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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<TileElement*>(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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<TileElement*>(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;
|
||||
}
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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 <algorithm>
|
||||
|
||||
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<int32_t>(gMapSizeMaxXY));
|
||||
auto y1 = std::min(_range.GetBottom(), static_cast<int32_t>(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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
|
@ -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 <algorithm>
|
||||
|
||||
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<int32_t>(gMapSizeMaxXY));
|
||||
auto y1 = std::min(_range.GetBottom(), static_cast<int32_t>(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);
|
||||
}
|
||||
};
|
|
@ -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::Result>(GameActions::Status::InvalidParameters, STR_INVALID_CLIMATE_ID, STR_NONE);
|
||||
}
|
||||
|
||||
return std::make_unique<GameActions::Result>();
|
||||
}
|
||||
|
||||
GameActions::Result::Ptr ClimateSetAction::Execute() const
|
||||
{
|
||||
gClimate = ClimateType{ _climate };
|
||||
|
||||
gfx_invalidate_screen();
|
||||
|
||||
return std::make_unique<GameActions::Result>();
|
||||
}
|
|
@ -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::Result>(
|
||||
GameActions::Status::InvalidParameters, STR_INVALID_CLIMATE_ID, STR_NONE);
|
||||
}
|
||||
|
||||
return std::make_unique<GameActions::Result>();
|
||||
}
|
||||
|
||||
GameActions::Result::Ptr Execute() const override
|
||||
{
|
||||
gClimate = ClimateType{ _climate };
|
||||
|
||||
gfx_invalidate_screen();
|
||||
|
||||
return std::make_unique<GameActions::Result>();
|
||||
}
|
||||
void Serialise(DataSerialiser & stream) override;
|
||||
GameActions::Result::Ptr Query() const override;
|
||||
GameActions::Result::Ptr Execute() const override;
|
||||
};
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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<GameActions::Result>();
|
||||
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<GameActions::Result>();
|
||||
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<TileElement*>(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<TileElement*>(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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<GameActions::Result>();
|
||||
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<GameActions::Result>();
|
||||
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<TileElement*>(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<TileElement*>(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;
|
||||
}
|
||||
};
|
|
@ -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<GameActions::Result>();
|
||||
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<GameActions::Result>();
|
||||
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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<GameActions::Result>();
|
||||
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<GameActions::Result>();
|
||||
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;
|
||||
}
|
||||
};
|
|
@ -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<GameActions::Result>();
|
||||
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<GameActions::Result>();
|
||||
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<uint32_t>(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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<GameActions::Result>();
|
||||
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<GameActions::Result>();
|
||||
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<uint32_t>(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;
|
||||
}
|
||||
};
|
|
@ -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
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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<Peep>(_peepId);
|
||||
if (peep == nullptr)
|
||||
{
|
||||
log_error("Used invalid sprite index for peep: %u", static_cast<uint32_t>(_peepId));
|
||||
return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS);
|
||||
}
|
||||
return std::make_unique<GameActions::Result>();
|
||||
}
|
||||
|
||||
GameActions::Result::Ptr GuestSetFlagsAction::Execute() const
|
||||
{
|
||||
Peep* peep = TryGetEntity<Peep>(_peepId);
|
||||
if (peep == nullptr)
|
||||
{
|
||||
log_error("Used invalid sprite index for peep: %u", static_cast<uint32_t>(_peepId));
|
||||
return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS);
|
||||
}
|
||||
|
||||
peep->PeepFlags = _newFlags;
|
||||
|
||||
return std::make_unique<GameActions::Result>();
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<Peep>(_peepId);
|
||||
if (peep == nullptr)
|
||||
{
|
||||
log_error("Used invalid sprite index for peep: %u", static_cast<uint32_t>(_peepId));
|
||||
return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS);
|
||||
}
|
||||
return std::make_unique<GameActions::Result>();
|
||||
}
|
||||
|
||||
GameActions::Result::Ptr Execute() const override
|
||||
{
|
||||
Peep* peep = TryGetEntity<Peep>(_peepId);
|
||||
if (peep == nullptr)
|
||||
{
|
||||
log_error("Used invalid sprite index for peep: %u", static_cast<uint32_t>(_peepId));
|
||||
return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS);
|
||||
}
|
||||
|
||||
peep->PeepFlags = _newFlags;
|
||||
|
||||
return std::make_unique<GameActions::Result>();
|
||||
}
|
||||
};
|
|
@ -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::Result>(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE);
|
||||
}
|
||||
|
||||
auto guest = TryGetEntity<Guest>(_spriteIndex);
|
||||
if (guest == nullptr)
|
||||
{
|
||||
log_warning("Invalid game command for sprite %u", _spriteIndex);
|
||||
return std::make_unique<GameActions::Result>(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE);
|
||||
}
|
||||
|
||||
return std::make_unique<GameActions::Result>();
|
||||
}
|
||||
|
||||
GameActions::Result::Ptr GuestSetNameAction::Execute() const
|
||||
{
|
||||
auto guest = TryGetEntity<Guest>(_spriteIndex);
|
||||
if (guest == nullptr)
|
||||
{
|
||||
log_warning("Invalid game command for sprite %u", _spriteIndex);
|
||||
return std::make_unique<GameActions::Result>(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE);
|
||||
}
|
||||
|
||||
auto curName = guest->GetName();
|
||||
if (curName == _name)
|
||||
{
|
||||
return std::make_unique<GameActions::Result>(GameActions::Status::Ok, STR_NONE);
|
||||
}
|
||||
|
||||
if (!guest->SetName(_name))
|
||||
{
|
||||
return std::make_unique<GameActions::Result>(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<GameActions::Result>();
|
||||
res->Position.x = guest->x;
|
||||
res->Position.y = guest->y;
|
||||
res->Position.z = guest->z;
|
||||
return res;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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::Result>(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE);
|
||||
}
|
||||
|
||||
auto guest = TryGetEntity<Guest>(_spriteIndex);
|
||||
if (guest == nullptr)
|
||||
{
|
||||
log_warning("Invalid game command for sprite %u", _spriteIndex);
|
||||
return std::make_unique<GameActions::Result>(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE);
|
||||
}
|
||||
|
||||
return std::make_unique<GameActions::Result>();
|
||||
}
|
||||
|
||||
GameActions::Result::Ptr Execute() const override
|
||||
{
|
||||
auto guest = TryGetEntity<Guest>(_spriteIndex);
|
||||
if (guest == nullptr)
|
||||
{
|
||||
log_warning("Invalid game command for sprite %u", _spriteIndex);
|
||||
return std::make_unique<GameActions::Result>(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE);
|
||||
}
|
||||
|
||||
auto curName = guest->GetName();
|
||||
if (curName == _name)
|
||||
{
|
||||
return std::make_unique<GameActions::Result>(GameActions::Status::Ok, STR_NONE);
|
||||
}
|
||||
|
||||
if (!guest->SetName(_name))
|
||||
{
|
||||
return std::make_unique<GameActions::Result>(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<GameActions::Result>();
|
||||
res->Position.x = guest->x;
|
||||
res->Position.y = guest->y;
|
||||
res->Position.z = guest->z;
|
||||
return res;
|
||||
}
|
||||
};
|
|
@ -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<decltype(normRange.GetLeft())>(32, normRange.GetLeft());
|
||||
auto bX = std::min<decltype(normRange.GetRight())>(gMapSizeMaxXY, normRange.GetRight());
|
||||
auto aY = std::max<decltype(normRange.GetTop())>(32, normRange.GetTop());
|
||||
auto bY = std::min<decltype(normRange.GetBottom())>(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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<decltype(normRange.GetLeft())>(32, normRange.GetLeft());
|
||||
auto bX = std::min<decltype(normRange.GetRight())>(gMapSizeMaxXY, normRange.GetRight());
|
||||
auto aY = std::max<decltype(normRange.GetTop())>(32, normRange.GetTop());
|
||||
auto bY = std::min<decltype(normRange.GetBottom())>(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);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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<decltype(_range.GetLeft())>(32, _range.GetLeft());
|
||||
auto bX = std::min<decltype(_range.GetRight())>(gMapSizeMaxXY, _range.GetRight());
|
||||
auto aY = std::max<decltype(_range.GetTop())>(32, _range.GetTop());
|
||||
auto bY = std::min<decltype(_range.GetBottom())>(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::Result>(
|
||||
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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<decltype(_range.GetLeft())>(32, _range.GetLeft());
|
||||
auto bX = std::min<decltype(_range.GetRight())>(gMapSizeMaxXY, _range.GetRight());
|
||||
auto aY = std::max<decltype(_range.GetTop())>(32, _range.GetTop());
|
||||
auto bY = std::min<decltype(_range.GetBottom())>(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::Result>(
|
||||
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;
|
||||
}
|
||||
};
|
|
@ -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<decltype(_range.GetLeft())>(32, _range.GetLeft());
|
||||
auto bX = std::min<decltype(_range.GetRight())>(gMapSizeMaxXY, _range.GetRight());
|
||||
auto aY = std::max<decltype(_range.GetTop())>(32, _range.GetTop());
|
||||
auto bY = std::min<decltype(_range.GetBottom())>(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::Result>(
|
||||
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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<decltype(_range.GetLeft())>(32, _range.GetLeft());
|
||||
auto bX = std::min<decltype(_range.GetRight())>(gMapSizeMaxXY, _range.GetRight());
|
||||
auto aY = std::max<decltype(_range.GetTop())>(32, _range.GetTop());
|
||||
auto bY = std::min<decltype(_range.GetBottom())>(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::Result>(
|
||||
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;
|
||||
}
|
||||
};
|
|
@ -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::Result>(GameActions::Status::Disallowed, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY);
|
||||
}
|
||||
|
||||
rct_string_id errorTitle = CheckParameters();
|
||||
if (errorTitle != STR_NONE)
|
||||
{
|
||||
return std::make_unique<GameActions::Result>(GameActions::Status::Disallowed, errorTitle);
|
||||
}
|
||||
|
||||
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode)
|
||||
{
|
||||
if (!map_is_location_in_park(_coords))
|
||||
{
|
||||
return std::make_unique<GameActions::Result>(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::Result>(GameActions::Status::Disallowed, errorTitle);
|
||||
}
|
||||
}
|
||||
|
||||
auto* surfaceElement = map_get_surface_element_at(_coords);
|
||||
if (surfaceElement == nullptr)
|
||||
return std::make_unique<GameActions::Result>(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<TileElement*>(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::Result>(
|
||||
GameActions::Status::Disallowed, STR_NONE, clearResult->ErrorMessage.GetStringId(),
|
||||
clearResult->ErrorMessageArgs.data());
|
||||
}
|
||||
|
||||
tileElement = CheckUnremovableObstructions(reinterpret_cast<TileElement*>(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<GameActions::Result>();
|
||||
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::Result>(GameActions::Status::Unknown, STR_NONE);
|
||||
|
||||
cost += GetSurfaceHeightChangeCost(surfaceElement);
|
||||
SetSurfaceHeight(reinterpret_cast<TileElement*>(surfaceElement));
|
||||
|
||||
auto res = std::make_unique<GameActions::Result>();
|
||||
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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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::Result>(GameActions::Status::Disallowed, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY);
|
||||
}
|
||||
|
||||
rct_string_id errorTitle = CheckParameters();
|
||||
if (errorTitle != STR_NONE)
|
||||
{
|
||||
return std::make_unique<GameActions::Result>(GameActions::Status::Disallowed, errorTitle);
|
||||
}
|
||||
|
||||
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode)
|
||||
{
|
||||
if (!map_is_location_in_park(_coords))
|
||||
{
|
||||
return std::make_unique<GameActions::Result>(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::Result>(GameActions::Status::Disallowed, errorTitle);
|
||||
}
|
||||
}
|
||||
|
||||
auto* surfaceElement = map_get_surface_element_at(_coords);
|
||||
if (surfaceElement == nullptr)
|
||||
return std::make_unique<GameActions::Result>(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<TileElement*>(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::Result>(
|
||||
GameActions::Status::Disallowed, STR_NONE, clearResult->ErrorMessage.GetStringId(),
|
||||
clearResult->ErrorMessageArgs.data());
|
||||
}
|
||||
|
||||
tileElement = CheckUnremovableObstructions(reinterpret_cast<TileElement*>(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<GameActions::Result>();
|
||||
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::Result>(GameActions::Status::Unknown, STR_NONE);
|
||||
|
||||
cost += GetSurfaceHeightChangeCost(surfaceElement);
|
||||
SetSurfaceHeight(reinterpret_cast<TileElement*>(surfaceElement));
|
||||
|
||||
auto res = std::make_unique<GameActions::Result>();
|
||||
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;
|
||||
}
|
||||
};
|
|
@ -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<decltype(normRange.GetLeft())>(32, normRange.GetLeft());
|
||||
auto bX = std::min<decltype(normRange.GetRight())>(gMapSizeMaxXY, normRange.GetRight());
|
||||
auto aY = std::max<decltype(normRange.GetTop())>(32, normRange.GetTop());
|
||||
auto bY = std::min<decltype(normRange.GetBottom())>(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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<decltype(normRange.GetLeft())>(32, normRange.GetLeft());
|
||||
auto bX = std::min<decltype(normRange.GetRight())>(gMapSizeMaxXY, normRange.GetRight());
|
||||
auto aY = std::max<decltype(normRange.GetTop())>(32, normRange.GetTop());
|
||||
auto bY = std::min<decltype(normRange.GetBottom())>(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);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight);
|
||||
z2 = std::clamp(
|
||||
static_cast<uint8_t>(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<uint8_t>(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight);
|
||||
z2 = std::clamp(
|
||||
static_cast<uint8_t>(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<uint8_t>(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight);
|
||||
z2 = std::clamp(
|
||||
static_cast<uint8_t>(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<uint8_t>(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight);
|
||||
z2 = std::clamp(
|
||||
static_cast<uint8_t>(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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight);
|
||||
z2 = std::clamp(
|
||||
static_cast<uint8_t>(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<uint8_t>(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight);
|
||||
z2 = std::clamp(
|
||||
static_cast<uint8_t>(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<uint8_t>(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight);
|
||||
z2 = std::clamp(
|
||||
static_cast<uint8_t>(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<uint8_t>(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight);
|
||||
z2 = std::clamp(
|
||||
static_cast<uint8_t>(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;
|
||||
}
|
||||
};
|
|
@ -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<LargeSceneryPlaceActionResult>();
|
||||
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<LargeSceneryPlaceActionResult>(GameActions::Status::InvalidParameters);
|
||||
}
|
||||
|
||||
if (_sceneryType >= MAX_LARGE_SCENERY_OBJECTS)
|
||||
{
|
||||
log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType);
|
||||
return std::make_unique<LargeSceneryPlaceActionResult>(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<LargeSceneryPlaceActionResult>(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<LargeSceneryPlaceActionResult>(GameActions::Status::NoFreeElements);
|
||||
}
|
||||
}
|
||||
|
||||
if (!map_check_free_elements_and_reorganise(totalNumTiles))
|
||||
{
|
||||
log_error("No free map elements available");
|
||||
return std::make_unique<LargeSceneryPlaceActionResult>(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<uint8_t>(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<LargeSceneryPlaceActionResult>(
|
||||
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<LargeSceneryPlaceActionResult>(
|
||||
GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER);
|
||||
}
|
||||
if (res->GroundFlags && !(res->GroundFlags & tempSceneryGroundFlags))
|
||||
{
|
||||
return std::make_unique<LargeSceneryPlaceActionResult>(
|
||||
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<LargeSceneryPlaceActionResult>(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<LargeSceneryPlaceActionResult>(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<LargeSceneryPlaceActionResult>();
|
||||
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<LargeSceneryPlaceActionResult>(GameActions::Status::InvalidParameters);
|
||||
}
|
||||
|
||||
if (sceneryEntry->large_scenery.tiles == nullptr)
|
||||
{
|
||||
log_error("Invalid large scenery object, sceneryType = %u", _sceneryType);
|
||||
return std::make_unique<LargeSceneryPlaceActionResult>(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<LargeSceneryPlaceActionResult>(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<uint8_t>(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<LargeSceneryPlaceActionResult>(
|
||||
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<LargeSceneryPlaceActionResult>(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);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue