diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 24a763966c..c4d4bb1988 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -6,7 +6,7 @@ "/usr/include", "/usr/local/include", "${workspaceRoot}", - "${workspaceRoot}/src" + "${workspaceRoot}/src/**" ], "defines": [], "intelliSenseMode": "clang-x64", diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 14921b5b34..df74d7f231 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -70,6 +70,164 @@ 662578A625803AA90002C77E /* discord_rpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 662578A525803AA90002C77E /* discord_rpc.h */; }; 662578AD25803CE50002C77E /* libdiscord-rpc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 662578A325803A6C0002C77E /* libdiscord-rpc.a */; }; 662578AE25803D040002C77E /* libdiscord-rpc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 662578A325803A6C0002C77E /* libdiscord-rpc.a */; settings = {ATTRIBUTES = (Required, ); }; }; + 66A10EA2257F1DE100DD651A /* BalloonPressAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EA0257F1DE000DD651A /* BalloonPressAction.cpp */; }; + 66A10EA3257F1DE100DD651A /* BalloonPressAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EA1257F1DE000DD651A /* BalloonPressAction.h */; }; + 66A10EC0257F1DF800DD651A /* BannerPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EA6257F1DF600DD651A /* BannerPlaceAction.cpp */; }; + 66A10EC1257F1DF800DD651A /* FootpathAdditionRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EA7257F1DF600DD651A /* FootpathAdditionRemoveAction.h */; }; + 66A10EC2257F1DF800DD651A /* FootpathRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EA8257F1DF600DD651A /* FootpathRemoveAction.h */; }; + 66A10EC3257F1DF800DD651A /* FootpathPlaceFromTrackAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EA9257F1DF600DD651A /* FootpathPlaceFromTrackAction.cpp */; }; + 66A10EC4257F1DF800DD651A /* FootpathAdditionPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EAA257F1DF600DD651A /* FootpathAdditionPlaceAction.cpp */; }; + 66A10EC5257F1DF800DD651A /* BannerSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EAB257F1DF600DD651A /* BannerSetNameAction.cpp */; }; + 66A10EC6257F1DF800DD651A /* FootpathPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EAC257F1DF600DD651A /* FootpathPlaceAction.h */; }; + 66A10EC7257F1DF800DD651A /* FootpathRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EAD257F1DF700DD651A /* FootpathRemoveAction.cpp */; }; + 66A10EC8257F1DF800DD651A /* BannerPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EAE257F1DF700DD651A /* BannerPlaceAction.h */; }; + 66A10EC9257F1DF800DD651A /* CustomAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EAF257F1DF700DD651A /* CustomAction.h */; }; + 66A10ECA257F1DF800DD651A /* ClimateSetAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EB0257F1DF700DD651A /* ClimateSetAction.h */; }; + 66A10ECB257F1DF800DD651A /* BannerSetStyleAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB1257F1DF700DD651A /* BannerSetStyleAction.cpp */; }; + 66A10ECC257F1DF800DD651A /* ClearAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB2257F1DF700DD651A /* ClearAction.cpp */; }; + 66A10ECD257F1DF800DD651A /* BannerRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB3257F1DF700DD651A /* BannerRemoveAction.cpp */; }; + 66A10ECE257F1DF800DD651A /* BannerSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EB4257F1DF700DD651A /* BannerSetNameAction.h */; }; + 66A10ECF257F1DF800DD651A /* ClimateSetAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB5257F1DF700DD651A /* ClimateSetAction.cpp */; }; + 66A10ED0257F1DF800DD651A /* BannerSetColourAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EB6257F1DF700DD651A /* BannerSetColourAction.h */; }; + 66A10ED1257F1DF800DD651A /* CustomAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB7257F1DF700DD651A /* CustomAction.cpp */; }; + 66A10ED2257F1DF800DD651A /* FootpathAdditionRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EB8257F1DF700DD651A /* FootpathAdditionRemoveAction.cpp */; }; + 66A10ED3257F1DF800DD651A /* BannerRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EB9257F1DF700DD651A /* BannerRemoveAction.h */; }; + 66A10ED4257F1DF800DD651A /* ClearAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EBA257F1DF700DD651A /* ClearAction.h */; }; + 66A10ED5257F1DF800DD651A /* BannerSetStyleAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EBB257F1DF700DD651A /* BannerSetStyleAction.h */; }; + 66A10ED6257F1DF800DD651A /* FootpathPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EBC257F1DF800DD651A /* FootpathPlaceAction.cpp */; }; + 66A10ED7257F1DF800DD651A /* FootpathPlaceFromTrackAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EBD257F1DF800DD651A /* FootpathPlaceFromTrackAction.h */; }; + 66A10ED8257F1DF800DD651A /* BannerSetColourAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EBE257F1DF800DD651A /* BannerSetColourAction.cpp */; }; + 66A10ED9257F1DF800DD651A /* FootpathAdditionPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EBF257F1DF800DD651A /* FootpathAdditionPlaceAction.h */; }; + 66A10F4C257F1E1700DD651A /* PlaceParkEntranceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EDC257F1E1000DD651A /* PlaceParkEntranceAction.h */; }; + 66A10F4D257F1E1700DD651A /* StaffSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EDD257F1E1000DD651A /* StaffSetNameAction.h */; }; + 66A10F4E257F1E1700DD651A /* PauseToggleAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EDE257F1E1000DD651A /* PauseToggleAction.h */; }; + 66A10F4F257F1E1700DD651A /* ParkSetDateAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EDF257F1E1000DD651A /* ParkSetDateAction.h */; }; + 66A10F50257F1E1700DD651A /* ParkEntranceRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EE0257F1E1000DD651A /* ParkEntranceRemoveAction.h */; }; + 66A10F51257F1E1700DD651A /* RideDemolishAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EE1257F1E1100DD651A /* RideDemolishAction.h */; }; + 66A10F52257F1E1700DD651A /* StaffSetCostumeAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EE2257F1E1100DD651A /* StaffSetCostumeAction.cpp */; }; + 66A10F53257F1E1700DD651A /* LandLowerAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EE3257F1E1100DD651A /* LandLowerAction.h */; }; + 66A10F54257F1E1700DD651A /* RideSetAppearanceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EE4257F1E1100DD651A /* RideSetAppearanceAction.h */; }; + 66A10F55257F1E1700DD651A /* SurfaceSetStyleAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EE5257F1E1100DD651A /* SurfaceSetStyleAction.cpp */; }; + 66A10F56257F1E1700DD651A /* SmallSceneryRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EE6257F1E1100DD651A /* SmallSceneryRemoveAction.h */; }; + 66A10F57257F1E1700DD651A /* RideSetAppearanceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EE7257F1E1100DD651A /* RideSetAppearanceAction.cpp */; }; + 66A10F58257F1E1700DD651A /* StaffSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EE8257F1E1100DD651A /* StaffSetNameAction.cpp */; }; + 66A10F59257F1E1700DD651A /* SetCheatAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EE9257F1E1100DD651A /* SetCheatAction.cpp */; }; + 66A10F5A257F1E1700DD651A /* GuestSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EEA257F1E1100DD651A /* GuestSetNameAction.h */; }; + 66A10F5B257F1E1700DD651A /* GuestSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EEB257F1E1100DD651A /* GuestSetNameAction.cpp */; }; + 66A10F5C257F1E1700DD651A /* SetParkEntranceFeeAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EEC257F1E1100DD651A /* SetParkEntranceFeeAction.h */; }; + 66A10F5D257F1E1700DD651A /* RideSetStatusAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EED257F1E1100DD651A /* RideSetStatusAction.h */; }; + 66A10F5E257F1E1700DD651A /* LargeSceneryRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EEE257F1E1100DD651A /* LargeSceneryRemoveAction.h */; }; + 66A10F5F257F1E1700DD651A /* SmallScenerySetColourAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EEF257F1E1200DD651A /* SmallScenerySetColourAction.h */; }; + 66A10F60257F1E1700DD651A /* ParkEntranceRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EF0257F1E1200DD651A /* ParkEntranceRemoveAction.cpp */; }; + 66A10F61257F1E1700DD651A /* PlaceParkEntranceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EF1257F1E1200DD651A /* PlaceParkEntranceAction.cpp */; }; + 66A10F62257F1E1700DD651A /* SurfaceSetStyleAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF2257F1E1200DD651A /* SurfaceSetStyleAction.h */; }; + 66A10F63257F1E1700DD651A /* PlayerKickAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF3257F1E1200DD651A /* PlayerKickAction.h */; }; + 66A10F64257F1E1700DD651A /* LandRaiseAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EF4257F1E1200DD651A /* LandRaiseAction.cpp */; }; + 66A10F65257F1E1700DD651A /* TileModifyAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF5257F1E1200DD651A /* TileModifyAction.h */; }; + 66A10F66257F1E1700DD651A /* RideSetVehicleAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EF6257F1E1200DD651A /* RideSetVehicleAction.cpp */; }; + 66A10F67257F1E1700DD651A /* RideEntranceExitPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF7257F1E1200DD651A /* RideEntranceExitPlaceAction.h */; }; + 66A10F68257F1E1800DD651A /* NetworkModifyGroupAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF8257F1E1200DD651A /* NetworkModifyGroupAction.h */; }; + 66A10F69257F1E1800DD651A /* ParkSetLoanAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EF9257F1E1200DD651A /* ParkSetLoanAction.h */; }; + 66A10F6A257F1E1800DD651A /* LargeScenerySetColourAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EFA257F1E1200DD651A /* LargeScenerySetColourAction.cpp */; }; + 66A10F6B257F1E1800DD651A /* ParkSetLoanAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EFB257F1E1200DD651A /* ParkSetLoanAction.cpp */; }; + 66A10F6C257F1E1800DD651A /* LoadOrQuitAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EFC257F1E1200DD651A /* LoadOrQuitAction.cpp */; }; + 66A10F6D257F1E1800DD651A /* ParkSetParameterAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EFD257F1E1200DD651A /* ParkSetParameterAction.cpp */; }; + 66A10F6E257F1E1800DD651A /* LandRaiseAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10EFE257F1E1200DD651A /* LandRaiseAction.h */; }; + 66A10F6F257F1E1800DD651A /* RideEntranceExitPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10EFF257F1E1200DD651A /* RideEntranceExitPlaceAction.cpp */; }; + 66A10F70257F1E1800DD651A /* ParkSetDateAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F00257F1E1300DD651A /* ParkSetDateAction.cpp */; }; + 66A10F71257F1E1800DD651A /* StaffSetColourAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F01257F1E1300DD651A /* StaffSetColourAction.cpp */; }; + 66A10F72257F1E1800DD651A /* PlacePeepSpawnAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F02257F1E1300DD651A /* PlacePeepSpawnAction.h */; }; + 66A10F73257F1E1800DD651A /* LandSetHeightAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F03257F1E1300DD651A /* LandSetHeightAction.h */; }; + 66A10F74257F1E1800DD651A /* RideEntranceExitRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F04257F1E1300DD651A /* RideEntranceExitRemoveAction.h */; }; + 66A10F75257F1E1800DD651A /* RideSetPriceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F05257F1E1300DD651A /* RideSetPriceAction.cpp */; }; + 66A10F76257F1E1800DD651A /* SmallSceneryRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F06257F1E1300DD651A /* SmallSceneryRemoveAction.cpp */; }; + 66A10F77257F1E1800DD651A /* StaffSetOrdersAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F07257F1E1300DD651A /* StaffSetOrdersAction.h */; }; + 66A10F78257F1E1800DD651A /* StaffSetColourAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F08257F1E1300DD651A /* StaffSetColourAction.h */; }; + 66A10F79257F1E1800DD651A /* RideCreateAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F09257F1E1300DD651A /* RideCreateAction.cpp */; }; + 66A10F7A257F1E1800DD651A /* RideSetSettingAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F0A257F1E1300DD651A /* RideSetSettingAction.cpp */; }; + 66A10F7B257F1E1800DD651A /* MazeSetTrackAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F0B257F1E1300DD651A /* MazeSetTrackAction.h */; }; + 66A10F7C257F1E1800DD651A /* StaffHireNewAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F0C257F1E1300DD651A /* StaffHireNewAction.cpp */; }; + 66A10F7D257F1E1800DD651A /* ParkSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F0D257F1E1300DD651A /* ParkSetNameAction.cpp */; }; + 66A10F7E257F1E1800DD651A /* RideSetColourSchemeAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F0E257F1E1300DD651A /* RideSetColourSchemeAction.cpp */; }; + 66A10F7F257F1E1800DD651A /* MazePlaceTrackAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F0F257F1E1300DD651A /* MazePlaceTrackAction.cpp */; }; + 66A10F80257F1E1800DD651A /* NetworkModifyGroupAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F10257F1E1400DD651A /* NetworkModifyGroupAction.cpp */; }; + 66A10F81257F1E1800DD651A /* RideSetVehicleAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F11257F1E1400DD651A /* RideSetVehicleAction.h */; }; + 66A10F82257F1E1800DD651A /* PlayerSetGroupAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F12257F1E1400DD651A /* PlayerSetGroupAction.cpp */; }; + 66A10F83257F1E1800DD651A /* PlayerSetGroupAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F13257F1E1400DD651A /* PlayerSetGroupAction.h */; }; + 66A10F84257F1E1800DD651A /* StaffSetPatrolAreaAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F14257F1E1400DD651A /* StaffSetPatrolAreaAction.h */; }; + 66A10F85257F1E1800DD651A /* LandSetHeightAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F15257F1E1400DD651A /* LandSetHeightAction.cpp */; }; + 66A10F86257F1E1800DD651A /* LoadOrQuitAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F16257F1E1400DD651A /* LoadOrQuitAction.h */; }; + 66A10F87257F1E1800DD651A /* SmallSceneryPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F17257F1E1400DD651A /* SmallSceneryPlaceAction.h */; }; + 66A10F88257F1E1800DD651A /* SignSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F18257F1E1400DD651A /* SignSetNameAction.h */; }; + 66A10F89257F1E1800DD651A /* PauseToggleAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F19257F1E1400DD651A /* PauseToggleAction.cpp */; }; + 66A10F8A257F1E1800DD651A /* ParkSetResearchFundingAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1A257F1E1400DD651A /* ParkSetResearchFundingAction.h */; }; + 66A10F8B257F1E1800DD651A /* LandSmoothAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1B257F1E1400DD651A /* LandSmoothAction.h */; }; + 66A10F8C257F1E1800DD651A /* RideCreateAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1C257F1E1400DD651A /* RideCreateAction.h */; }; + 66A10F8D257F1E1800DD651A /* GuestSetFlagsAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1D257F1E1400DD651A /* GuestSetFlagsAction.h */; }; + 66A10F8E257F1E1800DD651A /* LandSetRightsAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1E257F1E1400DD651A /* LandSetRightsAction.h */; }; + 66A10F8F257F1E1800DD651A /* StaffSetCostumeAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F1F257F1E1500DD651A /* StaffSetCostumeAction.h */; }; + 66A10F90257F1E1800DD651A /* MazePlaceTrackAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F20257F1E1500DD651A /* MazePlaceTrackAction.h */; }; + 66A10F91257F1E1800DD651A /* StaffHireNewAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F21257F1E1500DD651A /* StaffHireNewAction.h */; }; + 66A10F92257F1E1800DD651A /* ParkSetParameterAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F22257F1E1500DD651A /* ParkSetParameterAction.h */; }; + 66A10F93257F1E1800DD651A /* LandSmoothAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F23257F1E1500DD651A /* LandSmoothAction.cpp */; }; + 66A10F94257F1E1800DD651A /* StaffSetOrdersAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F24257F1E1500DD651A /* StaffSetOrdersAction.cpp */; }; + 66A10F95257F1E1800DD651A /* GuestSetFlagsAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F25257F1E1500DD651A /* GuestSetFlagsAction.cpp */; }; + 66A10F96257F1E1800DD651A /* SignSetStyleAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F26257F1E1500DD651A /* SignSetStyleAction.h */; }; + 66A10F97257F1E1800DD651A /* SetCheatAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F27257F1E1500DD651A /* SetCheatAction.h */; }; + 66A10F98257F1E1800DD651A /* PlacePeepSpawnAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F28257F1E1500DD651A /* PlacePeepSpawnAction.cpp */; }; + 66A10F99257F1E1800DD651A /* LargeScenerySetColourAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F29257F1E1500DD651A /* LargeScenerySetColourAction.h */; }; + 66A10F9A257F1E1800DD651A /* StaffFireAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F2A257F1E1500DD651A /* StaffFireAction.h */; }; + 66A10F9B257F1E1800DD651A /* ParkSetResearchFundingAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F2B257F1E1500DD651A /* ParkSetResearchFundingAction.cpp */; }; + 66A10F9C257F1E1800DD651A /* PeepPickupAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F2C257F1E1500DD651A /* PeepPickupAction.cpp */; }; + 66A10F9D257F1E1800DD651A /* StaffFireAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F2D257F1E1500DD651A /* StaffFireAction.cpp */; }; + 66A10F9E257F1E1800DD651A /* ParkMarketingAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F2E257F1E1600DD651A /* ParkMarketingAction.cpp */; }; + 66A10F9F257F1E1800DD651A /* LandBuyRightsAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F2F257F1E1600DD651A /* LandBuyRightsAction.h */; }; + 66A10FA0257F1E1800DD651A /* StaffSetPatrolAreaAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F30257F1E1600DD651A /* StaffSetPatrolAreaAction.cpp */; }; + 66A10FA1257F1E1800DD651A /* SmallScenerySetColourAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F31257F1E1600DD651A /* SmallScenerySetColourAction.cpp */; }; + 66A10FA2257F1E1800DD651A /* LargeSceneryPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F32257F1E1600DD651A /* LargeSceneryPlaceAction.h */; }; + 66A10FA3257F1E1800DD651A /* LandLowerAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F33257F1E1600DD651A /* LandLowerAction.cpp */; }; + 66A10FA4257F1E1800DD651A /* RideSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F34257F1E1600DD651A /* RideSetNameAction.cpp */; }; + 66A10FA5257F1E1800DD651A /* RideSetPriceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F35257F1E1600DD651A /* RideSetPriceAction.h */; }; + 66A10FA6257F1E1800DD651A /* ParkMarketingAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F36257F1E1600DD651A /* ParkMarketingAction.h */; }; + 66A10FA7257F1E1800DD651A /* PeepPickupAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F37257F1E1600DD651A /* PeepPickupAction.h */; }; + 66A10FA8257F1E1800DD651A /* RideEntranceExitRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F38257F1E1600DD651A /* RideEntranceExitRemoveAction.cpp */; }; + 66A10FA9257F1E1800DD651A /* ParkSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F39257F1E1600DD651A /* ParkSetNameAction.h */; }; + 66A10FAA257F1E1800DD651A /* SetParkEntranceFeeAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F3A257F1E1600DD651A /* SetParkEntranceFeeAction.cpp */; }; + 66A10FAB257F1E1800DD651A /* LandSetRightsAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F3B257F1E1600DD651A /* LandSetRightsAction.cpp */; }; + 66A10FAC257F1E1800DD651A /* RideSetSettingAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F3C257F1E1600DD651A /* RideSetSettingAction.h */; }; + 66A10FAD257F1E1800DD651A /* TileModifyAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F3D257F1E1700DD651A /* TileModifyAction.cpp */; }; + 66A10FAE257F1E1800DD651A /* SmallSceneryPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F3E257F1E1700DD651A /* SmallSceneryPlaceAction.cpp */; }; + 66A10FAF257F1E1800DD651A /* RideSetNameAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F3F257F1E1700DD651A /* RideSetNameAction.h */; }; + 66A10FB0257F1E1800DD651A /* SignSetStyleAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F40257F1E1700DD651A /* SignSetStyleAction.cpp */; }; + 66A10FB1257F1E1800DD651A /* RideDemolishAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F41257F1E1700DD651A /* RideDemolishAction.cpp */; }; + 66A10FB2257F1E1800DD651A /* LargeSceneryRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F42257F1E1700DD651A /* LargeSceneryRemoveAction.cpp */; }; + 66A10FB3257F1E1800DD651A /* MazeSetTrackAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F43257F1E1700DD651A /* MazeSetTrackAction.cpp */; }; + 66A10FB4257F1E1800DD651A /* ScenarioSetSettingAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F44257F1E1700DD651A /* ScenarioSetSettingAction.cpp */; }; + 66A10FB5257F1E1800DD651A /* SignSetNameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F45257F1E1700DD651A /* SignSetNameAction.cpp */; }; + 66A10FB6257F1E1800DD651A /* RideSetColourSchemeAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F46257F1E1700DD651A /* RideSetColourSchemeAction.h */; }; + 66A10FB7257F1E1800DD651A /* LandBuyRightsAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F47257F1E1700DD651A /* LandBuyRightsAction.cpp */; }; + 66A10FB8257F1E1800DD651A /* ScenarioSetSettingAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10F48257F1E1700DD651A /* ScenarioSetSettingAction.h */; }; + 66A10FB9257F1E1800DD651A /* RideSetStatusAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F49257F1E1700DD651A /* RideSetStatusAction.cpp */; }; + 66A10FBA257F1E1800DD651A /* PlayerKickAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F4A257F1E1700DD651A /* PlayerKickAction.cpp */; }; + 66A10FBB257F1E1800DD651A /* LargeSceneryPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10F4B257F1E1700DD651A /* LargeSceneryPlaceAction.cpp */; }; + 66A10FD0257F1E3000DD651A /* TrackPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FBE257F1E2D00DD651A /* TrackPlaceAction.h */; }; + 66A10FD1257F1E3000DD651A /* WaterRaiseAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FBF257F1E2D00DD651A /* WaterRaiseAction.cpp */; }; + 66A10FD2257F1E3000DD651A /* WallPlaceAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC0257F1E2D00DD651A /* WallPlaceAction.h */; }; + 66A10FD3257F1E3000DD651A /* TrackRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC1257F1E2D00DD651A /* TrackRemoveAction.h */; }; + 66A10FD4257F1E3000DD651A /* TrackSetBrakeSpeedAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FC2257F1E2E00DD651A /* TrackSetBrakeSpeedAction.cpp */; }; + 66A10FD5257F1E3000DD651A /* WaterRaiseAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC3257F1E2E00DD651A /* WaterRaiseAction.h */; }; + 66A10FD6257F1E3000DD651A /* WallRemoveAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC4257F1E2E00DD651A /* WallRemoveAction.h */; }; + 66A10FD7257F1E3000DD651A /* WaterLowerAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC5257F1E2E00DD651A /* WaterLowerAction.h */; }; + 66A10FD8257F1E3000DD651A /* TrackRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FC6257F1E2E00DD651A /* TrackRemoveAction.cpp */; }; + 66A10FD9257F1E3000DD651A /* WaterSetHeightAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FC7257F1E2E00DD651A /* WaterSetHeightAction.cpp */; }; + 66A10FDA257F1E3000DD651A /* WaterSetHeightAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FC8257F1E2F00DD651A /* WaterSetHeightAction.h */; }; + 66A10FDB257F1E3000DD651A /* WallPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FC9257F1E2F00DD651A /* WallPlaceAction.cpp */; }; + 66A10FDC257F1E3000DD651A /* TrackPlaceAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FCA257F1E2F00DD651A /* TrackPlaceAction.cpp */; }; + 66A10FDD257F1E3000DD651A /* WallSetColourAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FCB257F1E2F00DD651A /* WallSetColourAction.h */; }; + 66A10FDE257F1E3000DD651A /* WaterLowerAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FCC257F1E2F00DD651A /* WaterLowerAction.cpp */; }; + 66A10FDF257F1E3000DD651A /* TrackSetBrakeSpeedAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A10FCD257F1E2F00DD651A /* TrackSetBrakeSpeedAction.h */; }; + 66A10FE0257F1E3000DD651A /* WallRemoveAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FCE257F1E2F00DD651A /* WallRemoveAction.cpp */; }; + 66A10FE1257F1E3000DD651A /* WallSetColourAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 66A10FCF257F1E3000DD651A /* WallSetColourAction.cpp */; }; 9308D9FE209908090079EE96 /* TileElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9308D9FA209908080079EE96 /* TileElement.cpp */; }; 9308D9FF209908090079EE96 /* TileElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9308D9FA209908080079EE96 /* TileElement.cpp */; }; 9308DA00209908090079EE96 /* TileElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9308D9FA209908080079EE96 /* TileElement.cpp */; }; @@ -722,7 +880,6 @@ 4C25596D244A330800CE7E45 /* detail_method.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = detail_method.h; path = src/thirdparty/dukglue/detail_method.h; sourceTree = SOURCE_ROOT; }; 4C25596E244A330800CE7E45 /* dukexception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dukexception.h; path = src/thirdparty/dukglue/dukexception.h; sourceTree = SOURCE_ROOT; }; 4C25596F244A330800CE7E45 /* detail_typeinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = detail_typeinfo.h; path = src/thirdparty/dukglue/detail_typeinfo.h; sourceTree = SOURCE_ROOT; }; - 4C255971244A342900CE7E45 /* CustomAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CustomAction.hpp; sourceTree = ""; }; 4C29DEB2218C6AE500E8707F /* RCT12.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RCT12.cpp; sourceTree = ""; }; 4C358E5021C445F700ADE6BC /* ReplayManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReplayManager.cpp; sourceTree = ""; }; 4C358E5121C445F700ADE6BC /* ReplayManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplayManager.h; sourceTree = ""; }; @@ -976,7 +1133,6 @@ 4CC4B8E91FE00C5D00660D62 /* Input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Input.h; sourceTree = ""; }; 4CC4B8EA1FE00C5D00660D62 /* Intro.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Intro.cpp; sourceTree = ""; }; 4CC4B8EB1FE00C5D00660D62 /* Intro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Intro.h; sourceTree = ""; }; - 4CC5258023A19C1C00D4366D /* MazePlaceTrackAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MazePlaceTrackAction.hpp; sourceTree = ""; }; 4CC5258123A19C2800D4366D /* TrackDesignAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackDesignAction.cpp; sourceTree = ""; }; 4CC5258323A19C2E00D4366D /* TrackDesignAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackDesignAction.h; sourceTree = ""; }; 4CDCB0BC20A9902E00321367 /* ShopItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShopItem.cpp; sourceTree = ""; }; @@ -1004,92 +1160,173 @@ 6341F4E02400AA0F0052902B /* Drawing.Sprite.BMP.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Drawing.Sprite.BMP.cpp; sourceTree = ""; }; 662578A325803A6C0002C77E /* libdiscord-rpc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libdiscord-rpc.a"; path = "discord-rpc/build/src/libdiscord-rpc.a"; sourceTree = ""; }; 662578A525803AA90002C77E /* discord_rpc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = discord_rpc.h; path = "discord-rpc/include/discord_rpc.h"; sourceTree = ""; }; + 66A10EA0257F1DE000DD651A /* BalloonPressAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BalloonPressAction.cpp; sourceTree = ""; }; + 66A10EA1257F1DE000DD651A /* BalloonPressAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BalloonPressAction.h; sourceTree = ""; }; + 66A10EA6257F1DF600DD651A /* BannerPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerPlaceAction.cpp; sourceTree = ""; }; + 66A10EA7257F1DF600DD651A /* FootpathAdditionRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathAdditionRemoveAction.h; sourceTree = ""; }; + 66A10EA8257F1DF600DD651A /* FootpathRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathRemoveAction.h; sourceTree = ""; }; + 66A10EA9257F1DF600DD651A /* FootpathPlaceFromTrackAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathPlaceFromTrackAction.cpp; sourceTree = ""; }; + 66A10EAA257F1DF600DD651A /* FootpathAdditionPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathAdditionPlaceAction.cpp; sourceTree = ""; }; + 66A10EAB257F1DF600DD651A /* BannerSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerSetNameAction.cpp; sourceTree = ""; }; + 66A10EAC257F1DF600DD651A /* FootpathPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathPlaceAction.h; sourceTree = ""; }; + 66A10EAD257F1DF700DD651A /* FootpathRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathRemoveAction.cpp; sourceTree = ""; }; + 66A10EAE257F1DF700DD651A /* BannerPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerPlaceAction.h; sourceTree = ""; }; + 66A10EAF257F1DF700DD651A /* CustomAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomAction.h; sourceTree = ""; }; + 66A10EB0257F1DF700DD651A /* ClimateSetAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClimateSetAction.h; sourceTree = ""; }; + 66A10EB1257F1DF700DD651A /* BannerSetStyleAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerSetStyleAction.cpp; sourceTree = ""; }; + 66A10EB2257F1DF700DD651A /* ClearAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClearAction.cpp; sourceTree = ""; }; + 66A10EB3257F1DF700DD651A /* BannerRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerRemoveAction.cpp; sourceTree = ""; }; + 66A10EB4257F1DF700DD651A /* BannerSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerSetNameAction.h; sourceTree = ""; }; + 66A10EB5257F1DF700DD651A /* ClimateSetAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClimateSetAction.cpp; sourceTree = ""; }; + 66A10EB6257F1DF700DD651A /* BannerSetColourAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerSetColourAction.h; sourceTree = ""; }; + 66A10EB7257F1DF700DD651A /* CustomAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CustomAction.cpp; sourceTree = ""; }; + 66A10EB8257F1DF700DD651A /* FootpathAdditionRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathAdditionRemoveAction.cpp; sourceTree = ""; }; + 66A10EB9257F1DF700DD651A /* BannerRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerRemoveAction.h; sourceTree = ""; }; + 66A10EBA257F1DF700DD651A /* ClearAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClearAction.h; sourceTree = ""; }; + 66A10EBB257F1DF700DD651A /* BannerSetStyleAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerSetStyleAction.h; sourceTree = ""; }; + 66A10EBC257F1DF800DD651A /* FootpathPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathPlaceAction.cpp; sourceTree = ""; }; + 66A10EBD257F1DF800DD651A /* FootpathPlaceFromTrackAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathPlaceFromTrackAction.h; sourceTree = ""; }; + 66A10EBE257F1DF800DD651A /* BannerSetColourAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerSetColourAction.cpp; sourceTree = ""; }; + 66A10EBF257F1DF800DD651A /* FootpathAdditionPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathAdditionPlaceAction.h; sourceTree = ""; }; + 66A10EDC257F1E1000DD651A /* PlaceParkEntranceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlaceParkEntranceAction.h; sourceTree = ""; }; + 66A10EDD257F1E1000DD651A /* StaffSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffSetNameAction.h; sourceTree = ""; }; + 66A10EDE257F1E1000DD651A /* PauseToggleAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PauseToggleAction.h; sourceTree = ""; }; + 66A10EDF257F1E1000DD651A /* ParkSetDateAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkSetDateAction.h; sourceTree = ""; }; + 66A10EE0257F1E1000DD651A /* ParkEntranceRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkEntranceRemoveAction.h; sourceTree = ""; }; + 66A10EE1257F1E1100DD651A /* RideDemolishAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideDemolishAction.h; sourceTree = ""; }; + 66A10EE2257F1E1100DD651A /* StaffSetCostumeAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffSetCostumeAction.cpp; sourceTree = ""; }; + 66A10EE3257F1E1100DD651A /* LandLowerAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandLowerAction.h; sourceTree = ""; }; + 66A10EE4257F1E1100DD651A /* RideSetAppearanceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetAppearanceAction.h; sourceTree = ""; }; + 66A10EE5257F1E1100DD651A /* SurfaceSetStyleAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SurfaceSetStyleAction.cpp; sourceTree = ""; }; + 66A10EE6257F1E1100DD651A /* SmallSceneryRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmallSceneryRemoveAction.h; sourceTree = ""; }; + 66A10EE7257F1E1100DD651A /* RideSetAppearanceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetAppearanceAction.cpp; sourceTree = ""; }; + 66A10EE8257F1E1100DD651A /* StaffSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffSetNameAction.cpp; sourceTree = ""; }; + 66A10EE9257F1E1100DD651A /* SetCheatAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetCheatAction.cpp; sourceTree = ""; }; + 66A10EEA257F1E1100DD651A /* GuestSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GuestSetNameAction.h; sourceTree = ""; }; + 66A10EEB257F1E1100DD651A /* GuestSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GuestSetNameAction.cpp; sourceTree = ""; }; + 66A10EEC257F1E1100DD651A /* SetParkEntranceFeeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SetParkEntranceFeeAction.h; sourceTree = ""; }; + 66A10EED257F1E1100DD651A /* RideSetStatusAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetStatusAction.h; sourceTree = ""; }; + 66A10EEE257F1E1100DD651A /* LargeSceneryRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LargeSceneryRemoveAction.h; sourceTree = ""; }; + 66A10EEF257F1E1200DD651A /* SmallScenerySetColourAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmallScenerySetColourAction.h; sourceTree = ""; }; + 66A10EF0257F1E1200DD651A /* ParkEntranceRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkEntranceRemoveAction.cpp; sourceTree = ""; }; + 66A10EF1257F1E1200DD651A /* PlaceParkEntranceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlaceParkEntranceAction.cpp; sourceTree = ""; }; + 66A10EF2257F1E1200DD651A /* SurfaceSetStyleAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SurfaceSetStyleAction.h; sourceTree = ""; }; + 66A10EF3257F1E1200DD651A /* PlayerKickAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayerKickAction.h; sourceTree = ""; }; + 66A10EF4257F1E1200DD651A /* LandRaiseAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandRaiseAction.cpp; sourceTree = ""; }; + 66A10EF5257F1E1200DD651A /* TileModifyAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TileModifyAction.h; sourceTree = ""; }; + 66A10EF6257F1E1200DD651A /* RideSetVehicleAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetVehicleAction.cpp; sourceTree = ""; }; + 66A10EF7257F1E1200DD651A /* RideEntranceExitPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideEntranceExitPlaceAction.h; sourceTree = ""; }; + 66A10EF8257F1E1200DD651A /* NetworkModifyGroupAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkModifyGroupAction.h; sourceTree = ""; }; + 66A10EF9257F1E1200DD651A /* ParkSetLoanAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkSetLoanAction.h; sourceTree = ""; }; + 66A10EFA257F1E1200DD651A /* LargeScenerySetColourAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LargeScenerySetColourAction.cpp; sourceTree = ""; }; + 66A10EFB257F1E1200DD651A /* ParkSetLoanAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkSetLoanAction.cpp; sourceTree = ""; }; + 66A10EFC257F1E1200DD651A /* LoadOrQuitAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LoadOrQuitAction.cpp; sourceTree = ""; }; + 66A10EFD257F1E1200DD651A /* ParkSetParameterAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkSetParameterAction.cpp; sourceTree = ""; }; + 66A10EFE257F1E1200DD651A /* LandRaiseAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandRaiseAction.h; sourceTree = ""; }; + 66A10EFF257F1E1200DD651A /* RideEntranceExitPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideEntranceExitPlaceAction.cpp; sourceTree = ""; }; + 66A10F00257F1E1300DD651A /* ParkSetDateAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkSetDateAction.cpp; sourceTree = ""; }; + 66A10F01257F1E1300DD651A /* StaffSetColourAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffSetColourAction.cpp; sourceTree = ""; }; + 66A10F02257F1E1300DD651A /* PlacePeepSpawnAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlacePeepSpawnAction.h; sourceTree = ""; }; + 66A10F03257F1E1300DD651A /* LandSetHeightAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandSetHeightAction.h; sourceTree = ""; }; + 66A10F04257F1E1300DD651A /* RideEntranceExitRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideEntranceExitRemoveAction.h; sourceTree = ""; }; + 66A10F05257F1E1300DD651A /* RideSetPriceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetPriceAction.cpp; sourceTree = ""; }; + 66A10F06257F1E1300DD651A /* SmallSceneryRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmallSceneryRemoveAction.cpp; sourceTree = ""; }; + 66A10F07257F1E1300DD651A /* StaffSetOrdersAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffSetOrdersAction.h; sourceTree = ""; }; + 66A10F08257F1E1300DD651A /* StaffSetColourAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffSetColourAction.h; sourceTree = ""; }; + 66A10F09257F1E1300DD651A /* RideCreateAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideCreateAction.cpp; sourceTree = ""; }; + 66A10F0A257F1E1300DD651A /* RideSetSettingAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetSettingAction.cpp; sourceTree = ""; }; + 66A10F0B257F1E1300DD651A /* MazeSetTrackAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MazeSetTrackAction.h; sourceTree = ""; }; + 66A10F0C257F1E1300DD651A /* StaffHireNewAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffHireNewAction.cpp; sourceTree = ""; }; + 66A10F0D257F1E1300DD651A /* ParkSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkSetNameAction.cpp; sourceTree = ""; }; + 66A10F0E257F1E1300DD651A /* RideSetColourSchemeAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetColourSchemeAction.cpp; sourceTree = ""; }; + 66A10F0F257F1E1300DD651A /* MazePlaceTrackAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MazePlaceTrackAction.cpp; sourceTree = ""; }; + 66A10F10257F1E1400DD651A /* NetworkModifyGroupAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkModifyGroupAction.cpp; sourceTree = ""; }; + 66A10F11257F1E1400DD651A /* RideSetVehicleAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetVehicleAction.h; sourceTree = ""; }; + 66A10F12257F1E1400DD651A /* PlayerSetGroupAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlayerSetGroupAction.cpp; sourceTree = ""; }; + 66A10F13257F1E1400DD651A /* PlayerSetGroupAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayerSetGroupAction.h; sourceTree = ""; }; + 66A10F14257F1E1400DD651A /* StaffSetPatrolAreaAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffSetPatrolAreaAction.h; sourceTree = ""; }; + 66A10F15257F1E1400DD651A /* LandSetHeightAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandSetHeightAction.cpp; sourceTree = ""; }; + 66A10F16257F1E1400DD651A /* LoadOrQuitAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadOrQuitAction.h; sourceTree = ""; }; + 66A10F17257F1E1400DD651A /* SmallSceneryPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmallSceneryPlaceAction.h; sourceTree = ""; }; + 66A10F18257F1E1400DD651A /* SignSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignSetNameAction.h; sourceTree = ""; }; + 66A10F19257F1E1400DD651A /* PauseToggleAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PauseToggleAction.cpp; sourceTree = ""; }; + 66A10F1A257F1E1400DD651A /* ParkSetResearchFundingAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkSetResearchFundingAction.h; sourceTree = ""; }; + 66A10F1B257F1E1400DD651A /* LandSmoothAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandSmoothAction.h; sourceTree = ""; }; + 66A10F1C257F1E1400DD651A /* RideCreateAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideCreateAction.h; sourceTree = ""; }; + 66A10F1D257F1E1400DD651A /* GuestSetFlagsAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GuestSetFlagsAction.h; sourceTree = ""; }; + 66A10F1E257F1E1400DD651A /* LandSetRightsAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandSetRightsAction.h; sourceTree = ""; }; + 66A10F1F257F1E1500DD651A /* StaffSetCostumeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffSetCostumeAction.h; sourceTree = ""; }; + 66A10F20257F1E1500DD651A /* MazePlaceTrackAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MazePlaceTrackAction.h; sourceTree = ""; }; + 66A10F21257F1E1500DD651A /* StaffHireNewAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffHireNewAction.h; sourceTree = ""; }; + 66A10F22257F1E1500DD651A /* ParkSetParameterAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkSetParameterAction.h; sourceTree = ""; }; + 66A10F23257F1E1500DD651A /* LandSmoothAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandSmoothAction.cpp; sourceTree = ""; }; + 66A10F24257F1E1500DD651A /* StaffSetOrdersAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffSetOrdersAction.cpp; sourceTree = ""; }; + 66A10F25257F1E1500DD651A /* GuestSetFlagsAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GuestSetFlagsAction.cpp; sourceTree = ""; }; + 66A10F26257F1E1500DD651A /* SignSetStyleAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignSetStyleAction.h; sourceTree = ""; }; + 66A10F27257F1E1500DD651A /* SetCheatAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SetCheatAction.h; sourceTree = ""; }; + 66A10F28257F1E1500DD651A /* PlacePeepSpawnAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlacePeepSpawnAction.cpp; sourceTree = ""; }; + 66A10F29257F1E1500DD651A /* LargeScenerySetColourAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LargeScenerySetColourAction.h; sourceTree = ""; }; + 66A10F2A257F1E1500DD651A /* StaffFireAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaffFireAction.h; sourceTree = ""; }; + 66A10F2B257F1E1500DD651A /* ParkSetResearchFundingAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkSetResearchFundingAction.cpp; sourceTree = ""; }; + 66A10F2C257F1E1500DD651A /* PeepPickupAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PeepPickupAction.cpp; sourceTree = ""; }; + 66A10F2D257F1E1500DD651A /* StaffFireAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffFireAction.cpp; sourceTree = ""; }; + 66A10F2E257F1E1600DD651A /* ParkMarketingAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkMarketingAction.cpp; sourceTree = ""; }; + 66A10F2F257F1E1600DD651A /* LandBuyRightsAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LandBuyRightsAction.h; sourceTree = ""; }; + 66A10F30257F1E1600DD651A /* StaffSetPatrolAreaAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaffSetPatrolAreaAction.cpp; sourceTree = ""; }; + 66A10F31257F1E1600DD651A /* SmallScenerySetColourAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmallScenerySetColourAction.cpp; sourceTree = ""; }; + 66A10F32257F1E1600DD651A /* LargeSceneryPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LargeSceneryPlaceAction.h; sourceTree = ""; }; + 66A10F33257F1E1600DD651A /* LandLowerAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandLowerAction.cpp; sourceTree = ""; }; + 66A10F34257F1E1600DD651A /* RideSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetNameAction.cpp; sourceTree = ""; }; + 66A10F35257F1E1600DD651A /* RideSetPriceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetPriceAction.h; sourceTree = ""; }; + 66A10F36257F1E1600DD651A /* ParkMarketingAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkMarketingAction.h; sourceTree = ""; }; + 66A10F37257F1E1600DD651A /* PeepPickupAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeepPickupAction.h; sourceTree = ""; }; + 66A10F38257F1E1600DD651A /* RideEntranceExitRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideEntranceExitRemoveAction.cpp; sourceTree = ""; }; + 66A10F39257F1E1600DD651A /* ParkSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParkSetNameAction.h; sourceTree = ""; }; + 66A10F3A257F1E1600DD651A /* SetParkEntranceFeeAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetParkEntranceFeeAction.cpp; sourceTree = ""; }; + 66A10F3B257F1E1600DD651A /* LandSetRightsAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandSetRightsAction.cpp; sourceTree = ""; }; + 66A10F3C257F1E1600DD651A /* RideSetSettingAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetSettingAction.h; sourceTree = ""; }; + 66A10F3D257F1E1700DD651A /* TileModifyAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileModifyAction.cpp; sourceTree = ""; }; + 66A10F3E257F1E1700DD651A /* SmallSceneryPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmallSceneryPlaceAction.cpp; sourceTree = ""; }; + 66A10F3F257F1E1700DD651A /* RideSetNameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetNameAction.h; sourceTree = ""; }; + 66A10F40257F1E1700DD651A /* SignSetStyleAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SignSetStyleAction.cpp; sourceTree = ""; }; + 66A10F41257F1E1700DD651A /* RideDemolishAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideDemolishAction.cpp; sourceTree = ""; }; + 66A10F42257F1E1700DD651A /* LargeSceneryRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LargeSceneryRemoveAction.cpp; sourceTree = ""; }; + 66A10F43257F1E1700DD651A /* MazeSetTrackAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MazeSetTrackAction.cpp; sourceTree = ""; }; + 66A10F44257F1E1700DD651A /* ScenarioSetSettingAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScenarioSetSettingAction.cpp; sourceTree = ""; }; + 66A10F45257F1E1700DD651A /* SignSetNameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SignSetNameAction.cpp; sourceTree = ""; }; + 66A10F46257F1E1700DD651A /* RideSetColourSchemeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideSetColourSchemeAction.h; sourceTree = ""; }; + 66A10F47257F1E1700DD651A /* LandBuyRightsAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LandBuyRightsAction.cpp; sourceTree = ""; }; + 66A10F48257F1E1700DD651A /* ScenarioSetSettingAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScenarioSetSettingAction.h; sourceTree = ""; }; + 66A10F49257F1E1700DD651A /* RideSetStatusAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideSetStatusAction.cpp; sourceTree = ""; }; + 66A10F4A257F1E1700DD651A /* PlayerKickAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlayerKickAction.cpp; sourceTree = ""; }; + 66A10F4B257F1E1700DD651A /* LargeSceneryPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LargeSceneryPlaceAction.cpp; sourceTree = ""; }; + 66A10FBE257F1E2D00DD651A /* TrackPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPlaceAction.h; sourceTree = ""; }; + 66A10FBF257F1E2D00DD651A /* WaterRaiseAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WaterRaiseAction.cpp; sourceTree = ""; }; + 66A10FC0257F1E2D00DD651A /* WallPlaceAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WallPlaceAction.h; sourceTree = ""; }; + 66A10FC1257F1E2D00DD651A /* TrackRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackRemoveAction.h; sourceTree = ""; }; + 66A10FC2257F1E2E00DD651A /* TrackSetBrakeSpeedAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackSetBrakeSpeedAction.cpp; sourceTree = ""; }; + 66A10FC3257F1E2E00DD651A /* WaterRaiseAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WaterRaiseAction.h; sourceTree = ""; }; + 66A10FC4257F1E2E00DD651A /* WallRemoveAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WallRemoveAction.h; sourceTree = ""; }; + 66A10FC5257F1E2E00DD651A /* WaterLowerAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WaterLowerAction.h; sourceTree = ""; }; + 66A10FC6257F1E2E00DD651A /* TrackRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackRemoveAction.cpp; sourceTree = ""; }; + 66A10FC7257F1E2E00DD651A /* WaterSetHeightAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WaterSetHeightAction.cpp; sourceTree = ""; }; + 66A10FC8257F1E2F00DD651A /* WaterSetHeightAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WaterSetHeightAction.h; sourceTree = ""; }; + 66A10FC9257F1E2F00DD651A /* WallPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WallPlaceAction.cpp; sourceTree = ""; }; + 66A10FCA257F1E2F00DD651A /* TrackPlaceAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackPlaceAction.cpp; sourceTree = ""; }; + 66A10FCB257F1E2F00DD651A /* WallSetColourAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WallSetColourAction.h; sourceTree = ""; }; + 66A10FCC257F1E2F00DD651A /* WaterLowerAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WaterLowerAction.cpp; sourceTree = ""; }; + 66A10FCD257F1E2F00DD651A /* TrackSetBrakeSpeedAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackSetBrakeSpeedAction.h; sourceTree = ""; }; + 66A10FCE257F1E2F00DD651A /* WallRemoveAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WallRemoveAction.cpp; sourceTree = ""; }; + 66A10FCF257F1E3000DD651A /* WallSetColourAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WallSetColourAction.cpp; sourceTree = ""; }; 9308D9FA209908080079EE96 /* TileElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileElement.cpp; sourceTree = ""; }; 9308D9FB209908080079EE96 /* Surface.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Surface.cpp; sourceTree = ""; }; 9308D9FC209908080079EE96 /* TileElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TileElement.h; sourceTree = ""; }; 9308D9FD209908090079EE96 /* Surface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Surface.h; sourceTree = ""; }; 930EEA6924FC00940070314E /* ScenarioSelect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScenarioSelect.cpp; sourceTree = ""; }; - 932A20CD22D73CEE00C57EDB /* GuestSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = GuestSetNameAction.hpp; sourceTree = ""; }; - 932A20CE22D73CEE00C57EDB /* RideSetVehiclesAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetVehiclesAction.hpp; sourceTree = ""; }; 932A20CF22D73CEE00C57EDB /* GameActionCompat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameActionCompat.cpp; sourceTree = ""; }; - 932A20D022D73CEE00C57EDB /* RideSetSetting.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetSetting.hpp; sourceTree = ""; }; - 932A20D122D73CEF00C57EDB /* WallPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WallPlaceAction.hpp; sourceTree = ""; }; - 932A20D222D73CEF00C57EDB /* SmallSceneryRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SmallSceneryRemoveAction.hpp; sourceTree = ""; }; 932A20D322D73CEF00C57EDB /* GameActionRegistration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameActionRegistration.cpp; sourceTree = ""; }; - 932A20D422D73CEF00C57EDB /* RideSetName.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetName.hpp; sourceTree = ""; }; - 932A20D522D73CEF00C57EDB /* PlacePeepSpawnAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PlacePeepSpawnAction.hpp; sourceTree = ""; }; - 932A20D622D73CEF00C57EDB /* LandSetRightsAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandSetRightsAction.hpp; sourceTree = ""; }; - 932A20D722D73CEF00C57EDB /* RideCreateAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideCreateAction.hpp; sourceTree = ""; }; - 932A20D822D73CEF00C57EDB /* ParkEntranceRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkEntranceRemoveAction.hpp; sourceTree = ""; }; - 932A20D922D73CEF00C57EDB /* ParkSetLoanAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkSetLoanAction.hpp; sourceTree = ""; }; - 932A20DA22D73CF000C57EDB /* LandLowerAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandLowerAction.hpp; sourceTree = ""; }; - 932A20DB22D73CF000C57EDB /* FootpathPlaceFromTrackAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FootpathPlaceFromTrackAction.hpp; sourceTree = ""; }; - 932A20DC22D73CF000C57EDB /* PlayerKickAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PlayerKickAction.hpp; sourceTree = ""; }; - 932A20DD22D73CF000C57EDB /* RideDemolishAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideDemolishAction.hpp; sourceTree = ""; }; - 932A20DE22D73CF000C57EDB /* ClimateSetAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ClimateSetAction.hpp; sourceTree = ""; }; - 932A20DF22D73CF000C57EDB /* PauseToggleAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PauseToggleAction.hpp; sourceTree = ""; }; - 932A20E022D73CF000C57EDB /* LargeSceneryPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LargeSceneryPlaceAction.hpp; sourceTree = ""; }; - 932A20E122D73CF000C57EDB /* LandSetHeightAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandSetHeightAction.hpp; sourceTree = ""; }; - 932A20E222D73CF100C57EDB /* StaffSetColourAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetColourAction.hpp; sourceTree = ""; }; - 932A20E322D73CF100C57EDB /* StaffSetCostumeAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetCostumeAction.hpp; sourceTree = ""; }; - 932A20E422D73CF100C57EDB /* StaffSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetNameAction.hpp; sourceTree = ""; }; - 932A20E522D73CF100C57EDB /* BannerPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BannerPlaceAction.hpp; sourceTree = ""; }; - 932A20E622D73CF100C57EDB /* MazeSetTrackAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MazeSetTrackAction.hpp; sourceTree = ""; }; - 932A20E722D73CF100C57EDB /* StaffHireNewAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffHireNewAction.hpp; sourceTree = ""; }; - 932A20E822D73CF100C57EDB /* RideSetPriceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetPriceAction.hpp; sourceTree = ""; }; - 932A20E922D73CF200C57EDB /* WaterLowerAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WaterLowerAction.hpp; sourceTree = ""; }; - 932A20EA22D73CF200C57EDB /* ParkSetParameterAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkSetParameterAction.hpp; sourceTree = ""; }; - 932A20EB22D73CF200C57EDB /* SmallSceneryPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SmallSceneryPlaceAction.hpp; sourceTree = ""; }; - 932A20EC22D73CF200C57EDB /* LargeScenerySetColourAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LargeScenerySetColourAction.hpp; sourceTree = ""; }; - 932A20ED22D73CF200C57EDB /* ParkSetResearchFundingAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkSetResearchFundingAction.hpp; sourceTree = ""; }; - 932A20EE22D73CF200C57EDB /* ScenarioSetSettingAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ScenarioSetSettingAction.hpp; sourceTree = ""; }; - 932A20EF22D73CF200C57EDB /* TrackRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrackRemoveAction.hpp; sourceTree = ""; }; - 932A20F022D73CF300C57EDB /* SignSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SignSetNameAction.hpp; sourceTree = ""; }; - 932A20F122D73CF300C57EDB /* RideEntranceExitRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideEntranceExitRemoveAction.hpp; sourceTree = ""; }; - 932A20F222D73CF300C57EDB /* SetParkEntranceFeeAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SetParkEntranceFeeAction.hpp; sourceTree = ""; }; - 932A20F322D73CF300C57EDB /* FootpathRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FootpathRemoveAction.hpp; sourceTree = ""; }; - 932A20F422D73CF300C57EDB /* RideSetAppearanceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetAppearanceAction.hpp; sourceTree = ""; }; 932A20F522D73CF300C57EDB /* GameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameAction.h; sourceTree = ""; }; - 932A20F622D73CF300C57EDB /* RideEntranceExitPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideEntranceExitPlaceAction.hpp; sourceTree = ""; }; - 932A20F722D73CF300C57EDB /* FootpathPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FootpathPlaceAction.hpp; sourceTree = ""; }; - 932A20F822D73CF400C57EDB /* SignSetStyleAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SignSetStyleAction.hpp; sourceTree = ""; }; - 932A20F922D73CF400C57EDB /* SmallScenerySetColourAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SmallScenerySetColourAction.hpp; sourceTree = ""; }; - 932A20FA22D73CF400C57EDB /* SurfaceSetStyleAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SurfaceSetStyleAction.hpp; sourceTree = ""; }; - 932A20FB22D73CF400C57EDB /* RideSetStatus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetStatus.hpp; sourceTree = ""; }; - 932A20FC22D73CF400C57EDB /* ParkSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkSetNameAction.hpp; sourceTree = ""; }; - 932A20FD22D73CF500C57EDB /* LandBuyRightsAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandBuyRightsAction.hpp; sourceTree = ""; }; - 932A20FE22D73CF500C57EDB /* StaffSetPatrolAreaAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetPatrolAreaAction.hpp; sourceTree = ""; }; - 932A20FF22D73CF500C57EDB /* PeepPickupAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PeepPickupAction.hpp; sourceTree = ""; }; - 932A210022D73CF500C57EDB /* BannerSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BannerSetNameAction.hpp; sourceTree = ""; }; - 932A210122D73CF500C57EDB /* SetCheatAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SetCheatAction.hpp; sourceTree = ""; }; - 932A210222D73CF600C57EDB /* ParkMarketingAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkMarketingAction.hpp; sourceTree = ""; }; - 932A210322D73CF600C57EDB /* StaffSetOrdersAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetOrdersAction.hpp; sourceTree = ""; }; - 932A210422D73CF600C57EDB /* BannerSetColourAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BannerSetColourAction.hpp; sourceTree = ""; }; - 932A210522D73CF600C57EDB /* FootpathSceneryRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FootpathSceneryRemoveAction.hpp; sourceTree = ""; }; - 932A210622D73CF600C57EDB /* GuestSetFlagsAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = GuestSetFlagsAction.hpp; sourceTree = ""; }; - 932A210722D73CF600C57EDB /* TrackPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrackPlaceAction.hpp; sourceTree = ""; }; - 932A210822D73CF700C57EDB /* PlaceParkEntranceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PlaceParkEntranceAction.hpp; sourceTree = ""; }; - 932A210922D73CF700C57EDB /* FootpathSceneryPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FootpathSceneryPlaceAction.hpp; sourceTree = ""; }; - 932A210A22D73CF700C57EDB /* BannerRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BannerRemoveAction.hpp; sourceTree = ""; }; - 932A210B22D73CF700C57EDB /* LandRaiseAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandRaiseAction.hpp; sourceTree = ""; }; - 932A210C22D73CF700C57EDB /* LoadOrQuitAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LoadOrQuitAction.hpp; sourceTree = ""; }; - 932A210D22D73CF700C57EDB /* StaffFireAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffFireAction.hpp; sourceTree = ""; }; - 932A210E22D73CF800C57EDB /* ParkSetDateAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkSetDateAction.hpp; sourceTree = ""; }; - 932A210F22D73CF800C57EDB /* WallSetColourAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WallSetColourAction.hpp; sourceTree = ""; }; - 932A211022D73CF800C57EDB /* WaterSetHeightAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WaterSetHeightAction.hpp; sourceTree = ""; }; - 932A211122D73CF800C57EDB /* RideSetColourScheme.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetColourScheme.hpp; sourceTree = ""; }; - 932A211222D73CF800C57EDB /* WaterRaiseAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WaterRaiseAction.hpp; sourceTree = ""; }; - 932A211322D73CF800C57EDB /* WallRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WallRemoveAction.hpp; sourceTree = ""; }; - 932A211422D73CF800C57EDB /* LandSmoothAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LandSmoothAction.hpp; sourceTree = ""; }; - 932A211522D73CF900C57EDB /* BalloonPressAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BalloonPressAction.hpp; sourceTree = ""; }; - 932A211622D73CF900C57EDB /* ClearAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ClearAction.hpp; sourceTree = ""; }; - 932A211722D73CF900C57EDB /* BannerSetStyleAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BannerSetStyleAction.hpp; sourceTree = ""; }; - 932A211822D73CF900C57EDB /* NetworkModifyGroupAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = NetworkModifyGroupAction.hpp; sourceTree = ""; }; - 932A211922D73CF900C57EDB /* PlayerSetGroupAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PlayerSetGroupAction.hpp; sourceTree = ""; }; - 932A211A22D73CFA00C57EDB /* TileModifyAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TileModifyAction.hpp; sourceTree = ""; }; - 932A211B22D73CFA00C57EDB /* TrackSetBrakeSpeedAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrackSetBrakeSpeedAction.hpp; sourceTree = ""; }; 932A211C22D73CFA00C57EDB /* GameAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameAction.cpp; sourceTree = ""; }; - 932A211D22D73CFA00C57EDB /* LargeSceneryRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LargeSceneryRemoveAction.hpp; sourceTree = ""; }; 93378D00252B4F550077D2D8 /* JsonFwd.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = JsonFwd.hpp; sourceTree = ""; }; 93378D02252B54140077D2D8 /* json_fwd.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = json_fwd.hpp; path = "build/json-3.9.1/include/nlohmann/json_fwd.hpp"; sourceTree = SOURCE_ROOT; }; 933C55B424B858490057E64B /* SeaDecrypt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SeaDecrypt.cpp; sourceTree = ""; }; @@ -1970,7 +2207,7 @@ 4C25595D244A32E400CE7E45 /* linenoise.hpp */, ); name = thirdparty; - path = openrct2; + path = ../thirdparty; sourceTree = ""; }; 4C25595E244A32EA00CE7E45 /* dukglue */ = { @@ -2303,91 +2540,170 @@ C6352B871F477032006CCEE3 /* actions */ = { isa = PBXGroup; children = ( - 932A211522D73CF900C57EDB /* BalloonPressAction.hpp */, - 932A20E522D73CF100C57EDB /* BannerPlaceAction.hpp */, - 932A210A22D73CF700C57EDB /* BannerRemoveAction.hpp */, - 932A210422D73CF600C57EDB /* BannerSetColourAction.hpp */, - 932A210022D73CF500C57EDB /* BannerSetNameAction.hpp */, - 932A211722D73CF900C57EDB /* BannerSetStyleAction.hpp */, - 932A211622D73CF900C57EDB /* ClearAction.hpp */, - 932A20DE22D73CF000C57EDB /* ClimateSetAction.hpp */, - 4C255971244A342900CE7E45 /* CustomAction.hpp */, - 932A20F722D73CF300C57EDB /* FootpathPlaceAction.hpp */, - 932A20DB22D73CF000C57EDB /* FootpathPlaceFromTrackAction.hpp */, - 932A20F322D73CF300C57EDB /* FootpathRemoveAction.hpp */, - 932A210922D73CF700C57EDB /* FootpathSceneryPlaceAction.hpp */, - 932A210522D73CF600C57EDB /* FootpathSceneryRemoveAction.hpp */, + 66A10EA0257F1DE000DD651A /* BalloonPressAction.cpp */, + 66A10EA1257F1DE000DD651A /* BalloonPressAction.h */, + 66A10EA6257F1DF600DD651A /* BannerPlaceAction.cpp */, + 66A10EAE257F1DF700DD651A /* BannerPlaceAction.h */, + 66A10EB3257F1DF700DD651A /* BannerRemoveAction.cpp */, + 66A10EB9257F1DF700DD651A /* BannerRemoveAction.h */, + 66A10EBE257F1DF800DD651A /* BannerSetColourAction.cpp */, + 66A10EB6257F1DF700DD651A /* BannerSetColourAction.h */, + 66A10EAB257F1DF600DD651A /* BannerSetNameAction.cpp */, + 66A10EB4257F1DF700DD651A /* BannerSetNameAction.h */, + 66A10EB1257F1DF700DD651A /* BannerSetStyleAction.cpp */, + 66A10EBB257F1DF700DD651A /* BannerSetStyleAction.h */, + 66A10EB2257F1DF700DD651A /* ClearAction.cpp */, + 66A10EBA257F1DF700DD651A /* ClearAction.h */, + 66A10EB5257F1DF700DD651A /* ClimateSetAction.cpp */, + 66A10EB0257F1DF700DD651A /* ClimateSetAction.h */, + 66A10EB7257F1DF700DD651A /* CustomAction.cpp */, + 66A10EAF257F1DF700DD651A /* CustomAction.h */, + 66A10EAA257F1DF600DD651A /* FootpathAdditionPlaceAction.cpp */, + 66A10EBF257F1DF800DD651A /* FootpathAdditionPlaceAction.h */, + 66A10EB8257F1DF700DD651A /* FootpathAdditionRemoveAction.cpp */, + 66A10EA7257F1DF600DD651A /* FootpathAdditionRemoveAction.h */, + 66A10EBC257F1DF800DD651A /* FootpathPlaceAction.cpp */, + 66A10EAC257F1DF600DD651A /* FootpathPlaceAction.h */, + 66A10EA9257F1DF600DD651A /* FootpathPlaceFromTrackAction.cpp */, + 66A10EBD257F1DF800DD651A /* FootpathPlaceFromTrackAction.h */, + 66A10EAD257F1DF700DD651A /* FootpathRemoveAction.cpp */, + 66A10EA8257F1DF600DD651A /* FootpathRemoveAction.h */, 932A211C22D73CFA00C57EDB /* GameAction.cpp */, 932A20F522D73CF300C57EDB /* GameAction.h */, 932A20CF22D73CEE00C57EDB /* GameActionCompat.cpp */, 932A20D322D73CEF00C57EDB /* GameActionRegistration.cpp */, - 932A210622D73CF600C57EDB /* GuestSetFlagsAction.hpp */, - 932A20CD22D73CEE00C57EDB /* GuestSetNameAction.hpp */, - 932A20FD22D73CF500C57EDB /* LandBuyRightsAction.hpp */, - 932A20DA22D73CF000C57EDB /* LandLowerAction.hpp */, - 932A210B22D73CF700C57EDB /* LandRaiseAction.hpp */, - 932A20E122D73CF000C57EDB /* LandSetHeightAction.hpp */, - 932A20D622D73CEF00C57EDB /* LandSetRightsAction.hpp */, - 932A211422D73CF800C57EDB /* LandSmoothAction.hpp */, - 932A20E022D73CF000C57EDB /* LargeSceneryPlaceAction.hpp */, - 932A211D22D73CFA00C57EDB /* LargeSceneryRemoveAction.hpp */, - 932A20EC22D73CF200C57EDB /* LargeScenerySetColourAction.hpp */, - 932A210C22D73CF700C57EDB /* LoadOrQuitAction.hpp */, - 4CC5258023A19C1C00D4366D /* MazePlaceTrackAction.hpp */, - 932A20E622D73CF100C57EDB /* MazeSetTrackAction.hpp */, - 932A211822D73CF900C57EDB /* NetworkModifyGroupAction.hpp */, - 932A20D822D73CEF00C57EDB /* ParkEntranceRemoveAction.hpp */, - 932A210222D73CF600C57EDB /* ParkMarketingAction.hpp */, - 932A210E22D73CF800C57EDB /* ParkSetDateAction.hpp */, - 932A20D922D73CEF00C57EDB /* ParkSetLoanAction.hpp */, - 932A20FC22D73CF400C57EDB /* ParkSetNameAction.hpp */, - 932A20EA22D73CF200C57EDB /* ParkSetParameterAction.hpp */, - 932A20ED22D73CF200C57EDB /* ParkSetResearchFundingAction.hpp */, - 932A20DF22D73CF000C57EDB /* PauseToggleAction.hpp */, - 932A20FF22D73CF500C57EDB /* PeepPickupAction.hpp */, - 932A210822D73CF700C57EDB /* PlaceParkEntranceAction.hpp */, - 932A20D522D73CEF00C57EDB /* PlacePeepSpawnAction.hpp */, - 932A20DC22D73CF000C57EDB /* PlayerKickAction.hpp */, - 932A211922D73CF900C57EDB /* PlayerSetGroupAction.hpp */, - 932A20D722D73CEF00C57EDB /* RideCreateAction.hpp */, - 932A20DD22D73CF000C57EDB /* RideDemolishAction.hpp */, - 932A20F622D73CF300C57EDB /* RideEntranceExitPlaceAction.hpp */, - 932A20F122D73CF300C57EDB /* RideEntranceExitRemoveAction.hpp */, - 932A20F422D73CF300C57EDB /* RideSetAppearanceAction.hpp */, - 932A211122D73CF800C57EDB /* RideSetColourScheme.hpp */, - 932A20D422D73CEF00C57EDB /* RideSetName.hpp */, - 932A20E822D73CF100C57EDB /* RideSetPriceAction.hpp */, - 932A20D022D73CEE00C57EDB /* RideSetSetting.hpp */, - 932A20FB22D73CF400C57EDB /* RideSetStatus.hpp */, - 932A20CE22D73CEE00C57EDB /* RideSetVehiclesAction.hpp */, - 932A20EE22D73CF200C57EDB /* ScenarioSetSettingAction.hpp */, - 932A210122D73CF500C57EDB /* SetCheatAction.hpp */, - 932A20F222D73CF300C57EDB /* SetParkEntranceFeeAction.hpp */, - 932A20F022D73CF300C57EDB /* SignSetNameAction.hpp */, - 932A20F822D73CF400C57EDB /* SignSetStyleAction.hpp */, - 932A20EB22D73CF200C57EDB /* SmallSceneryPlaceAction.hpp */, - 932A20D222D73CEF00C57EDB /* SmallSceneryRemoveAction.hpp */, - 932A20F922D73CF400C57EDB /* SmallScenerySetColourAction.hpp */, - 932A210D22D73CF700C57EDB /* StaffFireAction.hpp */, - 932A20E722D73CF100C57EDB /* StaffHireNewAction.hpp */, - 932A20E222D73CF100C57EDB /* StaffSetColourAction.hpp */, - 932A20E322D73CF100C57EDB /* StaffSetCostumeAction.hpp */, - 932A20E422D73CF100C57EDB /* StaffSetNameAction.hpp */, - 932A210322D73CF600C57EDB /* StaffSetOrdersAction.hpp */, - 932A20FE22D73CF500C57EDB /* StaffSetPatrolAreaAction.hpp */, - 932A20FA22D73CF400C57EDB /* SurfaceSetStyleAction.hpp */, - 932A211A22D73CFA00C57EDB /* TileModifyAction.hpp */, + 66A10F25257F1E1500DD651A /* GuestSetFlagsAction.cpp */, + 66A10F1D257F1E1400DD651A /* GuestSetFlagsAction.h */, + 66A10EEB257F1E1100DD651A /* GuestSetNameAction.cpp */, + 66A10EEA257F1E1100DD651A /* GuestSetNameAction.h */, + 66A10F47257F1E1700DD651A /* LandBuyRightsAction.cpp */, + 66A10F2F257F1E1600DD651A /* LandBuyRightsAction.h */, + 66A10F33257F1E1600DD651A /* LandLowerAction.cpp */, + 66A10EE3257F1E1100DD651A /* LandLowerAction.h */, + 66A10EF4257F1E1200DD651A /* LandRaiseAction.cpp */, + 66A10EFE257F1E1200DD651A /* LandRaiseAction.h */, + 66A10F15257F1E1400DD651A /* LandSetHeightAction.cpp */, + 66A10F03257F1E1300DD651A /* LandSetHeightAction.h */, + 66A10F3B257F1E1600DD651A /* LandSetRightsAction.cpp */, + 66A10F1E257F1E1400DD651A /* LandSetRightsAction.h */, + 66A10F23257F1E1500DD651A /* LandSmoothAction.cpp */, + 66A10F1B257F1E1400DD651A /* LandSmoothAction.h */, + 66A10F4B257F1E1700DD651A /* LargeSceneryPlaceAction.cpp */, + 66A10F32257F1E1600DD651A /* LargeSceneryPlaceAction.h */, + 66A10F42257F1E1700DD651A /* LargeSceneryRemoveAction.cpp */, + 66A10EEE257F1E1100DD651A /* LargeSceneryRemoveAction.h */, + 66A10EFA257F1E1200DD651A /* LargeScenerySetColourAction.cpp */, + 66A10F29257F1E1500DD651A /* LargeScenerySetColourAction.h */, + 66A10EFC257F1E1200DD651A /* LoadOrQuitAction.cpp */, + 66A10F16257F1E1400DD651A /* LoadOrQuitAction.h */, + 66A10F0F257F1E1300DD651A /* MazePlaceTrackAction.cpp */, + 66A10F20257F1E1500DD651A /* MazePlaceTrackAction.h */, + 66A10F43257F1E1700DD651A /* MazeSetTrackAction.cpp */, + 66A10F0B257F1E1300DD651A /* MazeSetTrackAction.h */, + 66A10F10257F1E1400DD651A /* NetworkModifyGroupAction.cpp */, + 66A10EF8257F1E1200DD651A /* NetworkModifyGroupAction.h */, + 66A10EF0257F1E1200DD651A /* ParkEntranceRemoveAction.cpp */, + 66A10EE0257F1E1000DD651A /* ParkEntranceRemoveAction.h */, + 66A10F2E257F1E1600DD651A /* ParkMarketingAction.cpp */, + 66A10F36257F1E1600DD651A /* ParkMarketingAction.h */, + 66A10F00257F1E1300DD651A /* ParkSetDateAction.cpp */, + 66A10EDF257F1E1000DD651A /* ParkSetDateAction.h */, + 66A10EFB257F1E1200DD651A /* ParkSetLoanAction.cpp */, + 66A10EF9257F1E1200DD651A /* ParkSetLoanAction.h */, + 66A10F0D257F1E1300DD651A /* ParkSetNameAction.cpp */, + 66A10F39257F1E1600DD651A /* ParkSetNameAction.h */, + 66A10EFD257F1E1200DD651A /* ParkSetParameterAction.cpp */, + 66A10F22257F1E1500DD651A /* ParkSetParameterAction.h */, + 66A10F2B257F1E1500DD651A /* ParkSetResearchFundingAction.cpp */, + 66A10F1A257F1E1400DD651A /* ParkSetResearchFundingAction.h */, + 66A10F19257F1E1400DD651A /* PauseToggleAction.cpp */, + 66A10EDE257F1E1000DD651A /* PauseToggleAction.h */, + 66A10F2C257F1E1500DD651A /* PeepPickupAction.cpp */, + 66A10F37257F1E1600DD651A /* PeepPickupAction.h */, + 66A10EF1257F1E1200DD651A /* PlaceParkEntranceAction.cpp */, + 66A10EDC257F1E1000DD651A /* PlaceParkEntranceAction.h */, + 66A10F28257F1E1500DD651A /* PlacePeepSpawnAction.cpp */, + 66A10F02257F1E1300DD651A /* PlacePeepSpawnAction.h */, + 66A10F4A257F1E1700DD651A /* PlayerKickAction.cpp */, + 66A10EF3257F1E1200DD651A /* PlayerKickAction.h */, + 66A10F12257F1E1400DD651A /* PlayerSetGroupAction.cpp */, + 66A10F13257F1E1400DD651A /* PlayerSetGroupAction.h */, + 66A10F09257F1E1300DD651A /* RideCreateAction.cpp */, + 66A10F1C257F1E1400DD651A /* RideCreateAction.h */, + 66A10F41257F1E1700DD651A /* RideDemolishAction.cpp */, + 66A10EE1257F1E1100DD651A /* RideDemolishAction.h */, + 66A10EFF257F1E1200DD651A /* RideEntranceExitPlaceAction.cpp */, + 66A10EF7257F1E1200DD651A /* RideEntranceExitPlaceAction.h */, + 66A10F38257F1E1600DD651A /* RideEntranceExitRemoveAction.cpp */, + 66A10F04257F1E1300DD651A /* RideEntranceExitRemoveAction.h */, + 66A10EE7257F1E1100DD651A /* RideSetAppearanceAction.cpp */, + 66A10EE4257F1E1100DD651A /* RideSetAppearanceAction.h */, + 66A10F0E257F1E1300DD651A /* RideSetColourSchemeAction.cpp */, + 66A10F46257F1E1700DD651A /* RideSetColourSchemeAction.h */, + 66A10F34257F1E1600DD651A /* RideSetNameAction.cpp */, + 66A10F3F257F1E1700DD651A /* RideSetNameAction.h */, + 66A10F05257F1E1300DD651A /* RideSetPriceAction.cpp */, + 66A10F35257F1E1600DD651A /* RideSetPriceAction.h */, + 66A10F0A257F1E1300DD651A /* RideSetSettingAction.cpp */, + 66A10F3C257F1E1600DD651A /* RideSetSettingAction.h */, + 66A10F49257F1E1700DD651A /* RideSetStatusAction.cpp */, + 66A10EED257F1E1100DD651A /* RideSetStatusAction.h */, + 66A10EF6257F1E1200DD651A /* RideSetVehicleAction.cpp */, + 66A10F11257F1E1400DD651A /* RideSetVehicleAction.h */, + 66A10F44257F1E1700DD651A /* ScenarioSetSettingAction.cpp */, + 66A10F48257F1E1700DD651A /* ScenarioSetSettingAction.h */, + 66A10EE9257F1E1100DD651A /* SetCheatAction.cpp */, + 66A10F27257F1E1500DD651A /* SetCheatAction.h */, + 66A10F3A257F1E1600DD651A /* SetParkEntranceFeeAction.cpp */, + 66A10EEC257F1E1100DD651A /* SetParkEntranceFeeAction.h */, + 66A10F45257F1E1700DD651A /* SignSetNameAction.cpp */, + 66A10F18257F1E1400DD651A /* SignSetNameAction.h */, + 66A10F40257F1E1700DD651A /* SignSetStyleAction.cpp */, + 66A10F26257F1E1500DD651A /* SignSetStyleAction.h */, + 66A10F3E257F1E1700DD651A /* SmallSceneryPlaceAction.cpp */, + 66A10F17257F1E1400DD651A /* SmallSceneryPlaceAction.h */, + 66A10F06257F1E1300DD651A /* SmallSceneryRemoveAction.cpp */, + 66A10EE6257F1E1100DD651A /* SmallSceneryRemoveAction.h */, + 66A10F31257F1E1600DD651A /* SmallScenerySetColourAction.cpp */, + 66A10EEF257F1E1200DD651A /* SmallScenerySetColourAction.h */, + 66A10F2D257F1E1500DD651A /* StaffFireAction.cpp */, + 66A10F2A257F1E1500DD651A /* StaffFireAction.h */, + 66A10F0C257F1E1300DD651A /* StaffHireNewAction.cpp */, + 66A10F21257F1E1500DD651A /* StaffHireNewAction.h */, + 66A10F01257F1E1300DD651A /* StaffSetColourAction.cpp */, + 66A10F08257F1E1300DD651A /* StaffSetColourAction.h */, + 66A10EE2257F1E1100DD651A /* StaffSetCostumeAction.cpp */, + 66A10F1F257F1E1500DD651A /* StaffSetCostumeAction.h */, + 66A10EE8257F1E1100DD651A /* StaffSetNameAction.cpp */, + 66A10EDD257F1E1000DD651A /* StaffSetNameAction.h */, + 66A10F24257F1E1500DD651A /* StaffSetOrdersAction.cpp */, + 66A10F07257F1E1300DD651A /* StaffSetOrdersAction.h */, + 66A10F30257F1E1600DD651A /* StaffSetPatrolAreaAction.cpp */, + 66A10F14257F1E1400DD651A /* StaffSetPatrolAreaAction.h */, + 66A10EE5257F1E1100DD651A /* SurfaceSetStyleAction.cpp */, + 66A10EF2257F1E1200DD651A /* SurfaceSetStyleAction.h */, + 66A10F3D257F1E1700DD651A /* TileModifyAction.cpp */, + 66A10EF5257F1E1200DD651A /* TileModifyAction.h */, 4CC5258123A19C2800D4366D /* TrackDesignAction.cpp */, 4CC5258323A19C2E00D4366D /* TrackDesignAction.h */, - 932A210722D73CF600C57EDB /* TrackPlaceAction.hpp */, - 932A20EF22D73CF200C57EDB /* TrackRemoveAction.hpp */, - 932A211B22D73CFA00C57EDB /* TrackSetBrakeSpeedAction.hpp */, - 932A20D122D73CEF00C57EDB /* WallPlaceAction.hpp */, - 932A211322D73CF800C57EDB /* WallRemoveAction.hpp */, - 932A210F22D73CF800C57EDB /* WallSetColourAction.hpp */, - 932A20E922D73CF200C57EDB /* WaterLowerAction.hpp */, - 932A211222D73CF800C57EDB /* WaterRaiseAction.hpp */, - 932A211022D73CF800C57EDB /* WaterSetHeightAction.hpp */, + 66A10FCA257F1E2F00DD651A /* TrackPlaceAction.cpp */, + 66A10FBE257F1E2D00DD651A /* TrackPlaceAction.h */, + 66A10FC6257F1E2E00DD651A /* TrackRemoveAction.cpp */, + 66A10FC1257F1E2D00DD651A /* TrackRemoveAction.h */, + 66A10FC2257F1E2E00DD651A /* TrackSetBrakeSpeedAction.cpp */, + 66A10FCD257F1E2F00DD651A /* TrackSetBrakeSpeedAction.h */, + 66A10FC9257F1E2F00DD651A /* WallPlaceAction.cpp */, + 66A10FC0257F1E2D00DD651A /* WallPlaceAction.h */, + 66A10FCE257F1E2F00DD651A /* WallRemoveAction.cpp */, + 66A10FC4257F1E2E00DD651A /* WallRemoveAction.h */, + 66A10FCF257F1E3000DD651A /* WallSetColourAction.cpp */, + 66A10FCB257F1E2F00DD651A /* WallSetColourAction.h */, + 66A10FCC257F1E2F00DD651A /* WaterLowerAction.cpp */, + 66A10FC5257F1E2E00DD651A /* WaterLowerAction.h */, + 66A10FBF257F1E2D00DD651A /* WaterRaiseAction.cpp */, + 66A10FC3257F1E2E00DD651A /* WaterRaiseAction.h */, + 66A10FC7257F1E2E00DD651A /* WaterSetHeightAction.cpp */, + 66A10FC8257F1E2F00DD651A /* WaterSetHeightAction.h */, ); path = actions; sourceTree = ""; @@ -2662,8 +2978,7 @@ D43407E11D0E14CE00C2B3D4 /* shaders */, D4EC48E51C2637710024B507 /* sequence */, ); - name = data; - path = ../data; + path = data; sourceTree = ""; }; D4EC48811C2634870024B507 /* include */ = { @@ -3711,60 +4026,139 @@ files = ( 662578A625803AA90002C77E /* discord_rpc.h in Headers */, 93DFD05624521C1A001FCBAF /* ScriptEngine.h in Headers */, + 66A10ED0257F1DF800DD651A /* BannerSetColourAction.h in Headers */, + 66A10EC6257F1DF800DD651A /* FootpathPlaceAction.h in Headers */, + 66A10FA9257F1E1800DD651A /* ParkSetNameAction.h in Headers */, + 66A10F69257F1E1800DD651A /* ParkSetLoanAction.h in Headers */, 2ADE2F3122441905002598AF /* DiscordService.h in Headers */, + 66A10FD2257F1E3000DD651A /* WallPlaceAction.h in Headers */, + 66A10F8C257F1E1800DD651A /* RideCreateAction.h in Headers */, + 66A10F65257F1E1700DD651A /* TileModifyAction.h in Headers */, + 66A10ED4257F1DF800DD651A /* ClearAction.h in Headers */, + 66A10F5F257F1E1700DD651A /* SmallScenerySetColourAction.h in Headers */, + 66A10FA5257F1E1800DD651A /* RideSetPriceAction.h in Headers */, C67B28172002D67A00109C93 /* Viewport.h in Headers */, + 66A10FDD257F1E3000DD651A /* WallSetColourAction.h in Headers */, + 66A10F8D257F1E1800DD651A /* GuestSetFlagsAction.h in Headers */, + 66A10FA7257F1E1800DD651A /* PeepPickupAction.h in Headers */, 939A359C20C12FC800630B3F /* Paint.Sprite.h in Headers */, 93DFD05524521C1A001FCBAF /* ScMap.hpp in Headers */, 9308DA04209908090079EE96 /* TileElement.h in Headers */, C67B28152002D67A00109C93 /* Widget.h in Headers */, + 66A10F99257F1E1800DD651A /* LargeScenerySetColourAction.h in Headers */, 93378D01252B4F550077D2D8 /* JsonFwd.hpp in Headers */, + 66A10F90257F1E1800DD651A /* MazePlaceTrackAction.h in Headers */, + 66A10F6E257F1E1800DD651A /* LandRaiseAction.h in Headers */, + 66A10F78257F1E1800DD651A /* StaffSetColourAction.h in Headers */, + 66A10F67257F1E1700DD651A /* RideEntranceExitPlaceAction.h in Headers */, + 66A10F8A257F1E1800DD651A /* ParkSetResearchFundingAction.h in Headers */, C6352B851F477022006CCEE3 /* DataSerialiserTraits.h in Headers */, + 66A10F50257F1E1700DD651A /* ParkEntranceRemoveAction.h in Headers */, + 66A10F4D257F1E1700DD651A /* StaffSetNameAction.h in Headers */, 93DFD05124521C1A001FCBAF /* ScContext.hpp in Headers */, + 66A10FD6257F1E3000DD651A /* WallRemoveAction.h in Headers */, 939A359F20C12FDE00630B3F /* Paint.Surface.h in Headers */, + 66A10F7B257F1E1800DD651A /* MazeSetTrackAction.h in Headers */, C67B28192002D7F200109C93 /* Window_internal.h in Headers */, + 66A10F53257F1E1700DD651A /* LandLowerAction.h in Headers */, + 66A10F5E257F1E1700DD651A /* LargeSceneryRemoveAction.h in Headers */, + 66A10F5D257F1E1700DD651A /* RideSetStatusAction.h in Headers */, 93DFD05024521C1A001FCBAF /* ScPark.hpp in Headers */, 93B4DC1625487CDF008D63FF /* Formatting.h in Headers */, 93FB271F24ED32B7008241C9 /* json.hpp in Headers */, + 66A10F86257F1E1800DD651A /* LoadOrQuitAction.h in Headers */, 93DFD02E24521BA0001FCBAF /* FileWatcher.h in Headers */, 2ADE2F28224418B2002598AF /* DataSerialiserTag.h in Headers */, + 66A10F74257F1E1800DD651A /* RideEntranceExitRemoveAction.h in Headers */, + 66A10F9A257F1E1800DD651A /* StaffFireAction.h in Headers */, 93DFD04C24521C1A001FCBAF /* ScDisposable.hpp in Headers */, + 66A10FAC257F1E1800DD651A /* RideSetSettingAction.h in Headers */, 2ADE2F2E224418E7002598AF /* ConversionTables.h in Headers */, 933F2CBB20935668001B33FD /* LocalisationService.h in Headers */, + 66A10EC9257F1DF800DD651A /* CustomAction.h in Headers */, + 66A10FDF257F1E3000DD651A /* TrackSetBrakeSpeedAction.h in Headers */, + 66A10F54257F1E1700DD651A /* RideSetAppearanceAction.h in Headers */, C6352B861F477022006CCEE3 /* Endianness.h in Headers */, + 66A10F5A257F1E1700DD651A /* GuestSetNameAction.h in Headers */, + 66A10F87257F1E1800DD651A /* SmallSceneryPlaceAction.h in Headers */, + 66A10ECA257F1DF800DD651A /* ClimateSetAction.h in Headers */, + 66A10F77257F1E1800DD651A /* StaffSetOrdersAction.h in Headers */, 2ADE2F2C224418B2002598AF /* FileIndex.hpp in Headers */, + 66A10FAF257F1E1800DD651A /* RideSetNameAction.h in Headers */, 93DFD04A24521C1A001FCBAF /* ScConfiguration.hpp in Headers */, 93CBA4CC20A7504500867D56 /* ImageImporter.h in Headers */, + 66A10F62257F1E1700DD651A /* SurfaceSetStyleAction.h in Headers */, + 66A10EC1257F1DF800DD651A /* FootpathAdditionRemoveAction.h in Headers */, + 66A10FD0257F1E3000DD651A /* TrackPlaceAction.h in Headers */, + 66A10F4C257F1E1700DD651A /* PlaceParkEntranceAction.h in Headers */, + 66A10F96257F1E1800DD651A /* SignSetStyleAction.h in Headers */, 2ADE2F29224418B2002598AF /* Numerics.hpp in Headers */, 93378D03252B54140077D2D8 /* json_fwd.hpp in Headers */, + 66A10FD5257F1E3000DD651A /* WaterRaiseAction.h in Headers */, 93DFD04924521C1A001FCBAF /* ScTile.hpp in Headers */, 936F412B24CE030F00E07BCF /* NetworkBase.h in Headers */, + 66A10EC2257F1DF800DD651A /* FootpathRemoveAction.h in Headers */, + 66A10EA3257F1DE100DD651A /* BalloonPressAction.h in Headers */, 93DFD04524521C1A001FCBAF /* ScObject.hpp in Headers */, 2ADE2F382244198B002598AF /* SpriteBase.h in Headers */, + 66A10EC8257F1DF800DD651A /* BannerPlaceAction.h in Headers */, C62D838B1FD36D6F008C04F1 /* EditorObjectSelectionSession.h in Headers */, 2ADE2F27224418B2002598AF /* Random.hpp in Headers */, 9344BEF920C1E6180047D165 /* Crypt.h in Headers */, + 66A10F63257F1E1700DD651A /* PlayerKickAction.h in Headers */, + 66A10FD7257F1E3000DD651A /* WaterLowerAction.h in Headers */, 939A35A220C12FFD00630B3F /* InteractiveConsole.h in Headers */, 93CBA4C320A7502E00867D56 /* Imaging.h in Headers */, 93DFD04D24521C1A001FCBAF /* ScEntity.hpp in Headers */, + 66A10F4E257F1E1700DD651A /* PauseToggleAction.h in Headers */, 93DFD04E24521C1A001FCBAF /* Duktape.hpp in Headers */, + 66A10FA2257F1E1800DD651A /* LargeSceneryPlaceAction.h in Headers */, 2ADE2F3622441960002598AF /* RideTypes.h in Headers */, + 66A10F68257F1E1800DD651A /* NetworkModifyGroupAction.h in Headers */, 93DFD05324521C1A001FCBAF /* ScRide.hpp in Headers */, + 66A10F88257F1E1800DD651A /* SignSetNameAction.h in Headers */, 93AE2389252F948A00CD03C3 /* Formatter.h in Headers */, 93DFD05424521C1A001FCBAF /* ScDate.hpp in Headers */, 93FC08FF2418F3ED00CA3054 /* duktape.h in Headers */, 93DFD04F24521C1A001FCBAF /* ScConsole.hpp in Headers */, + 66A10F91257F1E1800DD651A /* StaffHireNewAction.h in Headers */, 9308DA05209908090079EE96 /* Surface.h in Headers */, + 66A10F9F257F1E1800DD651A /* LandBuyRightsAction.h in Headers */, 93DE9753209C3C1000FB1CC8 /* GameState.h in Headers */, + 66A10ED9257F1DF800DD651A /* FootpathAdditionPlaceAction.h in Headers */, 936F412824CE030F00E07BCF /* NetworkClient.h in Headers */, 2ADE2F2A224418B2002598AF /* Meta.hpp in Headers */, 93DFD04624521C1A001FCBAF /* HookEngine.h in Headers */, + 66A10F81257F1E1800DD651A /* RideSetVehicleAction.h in Headers */, + 66A10F83257F1E1800DD651A /* PlayerSetGroupAction.h in Headers */, + 66A10F8E257F1E1800DD651A /* LandSetRightsAction.h in Headers */, 93FC09002418F3ED00CA3054 /* duk_config.h in Headers */, + 66A10FDA257F1E3000DD651A /* WaterSetHeightAction.h in Headers */, + 66A10F51257F1E1700DD651A /* RideDemolishAction.h in Headers */, + 66A10F73257F1E1800DD651A /* LandSetHeightAction.h in Headers */, + 66A10F4F257F1E1700DD651A /* ParkSetDateAction.h in Headers */, + 66A10FD3257F1E3000DD651A /* TrackRemoveAction.h in Headers */, C6352B841F477022006CCEE3 /* DataSerialiser.h in Headers */, 939A35A020C12FDE00630B3F /* Paint.TileElement.h in Headers */, + 66A10ED3257F1DF800DD651A /* BannerRemoveAction.h in Headers */, + 66A10F84257F1E1800DD651A /* StaffSetPatrolAreaAction.h in Headers */, + 66A10F56257F1E1700DD651A /* SmallSceneryRemoveAction.h in Headers */, + 66A10F5C257F1E1700DD651A /* SetParkEntranceFeeAction.h in Headers */, 93DFD04724521C1A001FCBAF /* ScNetwork.hpp in Headers */, + 66A10F8F257F1E1800DD651A /* StaffSetCostumeAction.h in Headers */, + 66A10ED5257F1DF800DD651A /* BannerSetStyleAction.h in Headers */, + 66A10F97257F1E1800DD651A /* SetCheatAction.h in Headers */, + 66A10F92257F1E1800DD651A /* ParkSetParameterAction.h in Headers */, 93DFD04424521C1A001FCBAF /* Plugin.h in Headers */, + 66A10FB6257F1E1800DD651A /* RideSetColourSchemeAction.h in Headers */, + 66A10FA6257F1E1800DD651A /* ParkMarketingAction.h in Headers */, C67B28162002D67A00109C93 /* Window.h in Headers */, + 66A10FB8257F1E1800DD651A /* ScenarioSetSettingAction.h in Headers */, + 66A10F72257F1E1800DD651A /* PlacePeepSpawnAction.h in Headers */, + 66A10ED7257F1DF800DD651A /* FootpathPlaceFromTrackAction.h in Headers */, + 66A10ECE257F1DF800DD651A /* BannerSetNameAction.h in Headers */, 2ADE2F342244191E002598AF /* VirtualFloor.h in Headers */, + 66A10F8B257F1E1800DD651A /* LandSmoothAction.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4243,9 +4637,12 @@ buildActionMask = 2147483647; files = ( F7C44AF82030E8D3007E099F /* AVX2Drawing.cpp in Sources */, + 66A10FAE257F1E1800DD651A /* SmallSceneryPlaceAction.cpp in Sources */, F70839931FFC0B61002DCEFA /* Scenario.cpp in Sources */, C688791C20289B9B0084B384 /* Facility.cpp in Sources */, C688790C20289B9B0084B384 /* CarRide.cpp in Sources */, + 66A10F75257F1E1800DD651A /* RideSetPriceAction.cpp in Sources */, + 66A10F6D257F1E1800DD651A /* ParkSetParameterAction.cpp in Sources */, C688786820289A4A0084B384 /* Util.cpp in Sources */, C688792720289B9B0084B384 /* TopSpin.cpp in Sources */, C688787E20289ADE0084B384 /* Drawing.cpp in Sources */, @@ -4257,18 +4654,22 @@ C688789E20289B200084B384 /* FormatCodes.cpp in Sources */, C688785820289A0A0084B384 /* Balloon.cpp in Sources */, C688788820289ADE0084B384 /* X8DrawingEngine.cpp in Sources */, + 66A10F6A257F1E1800DD651A /* LargeScenerySetColourAction.cpp in Sources */, F775F5381EE3725C001F00E7 /* DummyAudioContext.cpp in Sources */, F775F5351EE35A89001F00E7 /* DummyUiContext.cpp in Sources */, 2A1F4FE1221FF4B0003CA045 /* Audio.cpp in Sources */, C688790920289B9B0084B384 /* WildMouse.cpp in Sources */, C688791420289B9B0084B384 /* Maze.cpp in Sources */, + 66A10ED8257F1DF800DD651A /* BannerSetColourAction.cpp in Sources */, C688784C202899BE0084B384 /* Game.cpp in Sources */, F76C85B41EC4E88300FA49E2 /* AudioMixer.cpp in Sources */, F76C85B71EC4E88300FA49E2 /* NullAudioSource.cpp in Sources */, C68878E720289B9B0084B384 /* Platform.Posix.cpp in Sources */, + 66A10F93257F1E1800DD651A /* LandSmoothAction.cpp in Sources */, C68878CE20289B9B0084B384 /* ObjectList.cpp in Sources */, C688788120289ADE0084B384 /* Line.cpp in Sources */, 93CBA4CA20A7504500867D56 /* ImageImporter.cpp in Sources */, + 66A10F7F257F1E1800DD651A /* MazePlaceTrackAction.cpp in Sources */, C688792520289B9B0084B384 /* RotoDrop.cpp in Sources */, F76C85BA1EC4E88300FA49E2 /* CommandLine.cpp in Sources */, C68878EE20289B9B0084B384 /* BolligerMabillardTrack.cpp in Sources */, @@ -4280,12 +4681,14 @@ F76C85BE1EC4E88300FA49E2 /* ScreenshotCommands.cpp in Sources */, C688786320289A0A0084B384 /* MapHelpers.cpp in Sources */, F76C85BF1EC4E88300FA49E2 /* SpriteCommands.cpp in Sources */, + 66A10F76257F1E1800DD651A /* SmallSceneryRemoveAction.cpp in Sources */, F76C85C01EC4E88300FA49E2 /* UriHandler.cpp in Sources */, C688786220289A0A0084B384 /* MapGen.cpp in Sources */, C68878A820289B2A0084B384 /* NewsItem.cpp in Sources */, 93F76EED20BFF6F900D4512C /* Drawing.Sprite.cpp in Sources */, 933F2CB820935653001B33FD /* LocalisationService.cpp in Sources */, F76C85C41EC4E88300FA49E2 /* Config.cpp in Sources */, + 66A10EC4257F1DF800DD651A /* FootpathAdditionPlaceAction.cpp in Sources */, C688792920289B9B0084B384 /* Chairlift.cpp in Sources */, C68878A020289B200084B384 /* LanguagePack.cpp in Sources */, F76C85C71EC4E88300FA49E2 /* IniReader.cpp in Sources */, @@ -4295,28 +4698,35 @@ 93F76EF220BFF74200D4512C /* Localisation.Date.cpp in Sources */, F76C85CC1EC4E88300FA49E2 /* Context.cpp in Sources */, C68878E220289B9B0084B384 /* Staff.cpp in Sources */, + 66A10F7E257F1E1800DD651A /* RideSetColourSchemeAction.cpp in Sources */, F76C85CF1EC4E88300FA49E2 /* Console.cpp in Sources */, C68878DC20289B9B0084B384 /* Painter.cpp in Sources */, 933C55B524B858490057E64B /* SeaDecrypt.cpp in Sources */, C688790120289B9B0084B384 /* ReverserRollerCoaster.cpp in Sources */, C688786120289A0A0084B384 /* MapAnimation.cpp in Sources */, F76C85D11EC4E88300FA49E2 /* Diagnostics.cpp in Sources */, + 66A10FB0257F1E1800DD651A /* SignSetStyleAction.cpp in Sources */, F76C85D41EC4E88300FA49E2 /* File.cpp in Sources */, C688790220289B9B0084B384 /* SideFrictionRollerCoaster.cpp in Sources */, F76C85D61EC4E88300FA49E2 /* FileScanner.cpp in Sources */, + 66A10F59257F1E1700DD651A /* SetCheatAction.cpp in Sources */, C68878F820289B9B0084B384 /* LayDownRollerCoaster.cpp in Sources */, C6887856202899FA0084B384 /* Scenery.cpp in Sources */, C688785D20289A0A0084B384 /* Footpath.cpp in Sources */, F76C85D91EC4E88300FA49E2 /* Guard.cpp in Sources */, C688790520289B9B0084B384 /* SuspendedSwingingCoaster.cpp in Sources */, C68878E920289B9B0084B384 /* Posix.cpp in Sources */, + 66A10EA2257F1DE100DD651A /* BalloonPressAction.cpp in Sources */, D48AFDB71EF78DBF0081C644 /* BenchGfxCommmands.cpp in Sources */, + 66A10F79257F1E1800DD651A /* RideCreateAction.cpp in Sources */, C688790320289B9B0084B384 /* StandUpRollerCoaster.cpp in Sources */, C62D838A1FD36D6F008C04F1 /* EditorObjectSelectionSession.cpp in Sources */, C6887851202899EA0084B384 /* Wall.cpp in Sources */, F76C85DB1EC4E88300FA49E2 /* IStream.cpp in Sources */, C688785A20289A0A0084B384 /* Climate.cpp in Sources */, + 66A10FA8257F1E1800DD651A /* RideEntranceExitRemoveAction.cpp in Sources */, C68878A920289B2A0084B384 /* Research.cpp in Sources */, + 66A10F61257F1E1700DD651A /* PlaceParkEntranceAction.cpp in Sources */, C6887850202899D40084B384 /* Cheats.cpp in Sources */, C688784D202899C40084B384 /* Diagnostic.cpp in Sources */, C688787020289A6F0084B384 /* VehiclePaint.cpp in Sources */, @@ -4329,11 +4739,15 @@ C68878DE20289B9B0084B384 /* Supports.cpp in Sources */, C688791720289B9B0084B384 /* MiniHelicopters.cpp in Sources */, 93B4DC1525487CDF008D63FF /* Formatting.cpp in Sources */, + 66A10EC3257F1DF800DD651A /* FootpathPlaceFromTrackAction.cpp in Sources */, C688784F202899D00084B384 /* CmdlineSprite.cpp in Sources */, F76C85EE1EC4E88300FA49E2 /* Zip.cpp in Sources */, C688793220289B9B0084B384 /* SplashBoats.cpp in Sources */, + 66A10FB2257F1E1800DD651A /* LargeSceneryRemoveAction.cpp in Sources */, F76C85F91EC4E88300FA49E2 /* Image.cpp in Sources */, C68878FF20289B9B0084B384 /* MultiDimensionRollerCoaster.cpp in Sources */, + 66A10F58257F1E1700DD651A /* StaffSetNameAction.cpp in Sources */, + 66A10F6C257F1E1800DD651A /* LoadOrQuitAction.cpp in Sources */, C688789220289B140084B384 /* FontFamilies.cpp in Sources */, C68878F120289B9B0084B384 /* FlyingRollerCoaster.cpp in Sources */, C688792B20289B9B0084B384 /* MiniatureRailway.cpp in Sources */, @@ -4341,20 +4755,26 @@ F76C85FF1EC4E88300FA49E2 /* Weather.cpp in Sources */, C688785920289A0A0084B384 /* Banner.cpp in Sources */, C68878EC20289B9B0084B384 /* AirPoweredVerticalCoaster.cpp in Sources */, + 66A10FAD257F1E1800DD651A /* TileModifyAction.cpp in Sources */, C688790B20289B9B0084B384 /* WoodenWildMouse.cpp in Sources */, C688792320289B9B0084B384 /* MotionSimulator.cpp in Sources */, 93DE9751209C3C1000FB1CC8 /* GameState.cpp in Sources */, C68878EF20289B9B0084B384 /* CompactInvertedCoaster.cpp in Sources */, C68878E320289B9B0084B384 /* Android.cpp in Sources */, + 66A10F70257F1E1800DD651A /* ParkSetDateAction.cpp in Sources */, F76C86051EC4E88300FA49E2 /* Editor.cpp in Sources */, F76C86071EC4E88300FA49E2 /* FileClassifier.cpp in Sources */, + 66A10FDE257F1E3000DD651A /* WaterLowerAction.cpp in Sources */, C688786920289A660084B384 /* CableLift.cpp in Sources */, C688790020289B9B0084B384 /* ReverseFreefallCoaster.cpp in Sources */, 93F76EF620BFF76E00D4512C /* Paint.Sprite.cpp in Sources */, C6607F481FE2B97E00D3FC0D /* Input.cpp in Sources */, + 66A10ECC257F1DF800DD651A /* ClearAction.cpp in Sources */, + 66A10FDB257F1E3000DD651A /* WallPlaceAction.cpp in Sources */, C688789F20289B200084B384 /* Language.cpp in Sources */, C688791620289B9B0084B384 /* MiniGolf.cpp in Sources */, C688787820289A780084B384 /* Track.cpp in Sources */, + 66A10ED6257F1DF800DD651A /* FootpathPlaceAction.cpp in Sources */, F76C86491EC4E88300FA49E2 /* NetworkAction.cpp in Sources */, C688788020289ADE0084B384 /* LightFX.cpp in Sources */, F76C864B1EC4E88300FA49E2 /* NetworkConnection.cpp in Sources */, @@ -4375,6 +4795,7 @@ 93F76EF520BFF76E00D4512C /* Paint.Peep.cpp in Sources */, C6887857202899FD0084B384 /* Park.cpp in Sources */, F76C86601EC4E88300FA49E2 /* BannerObject.cpp in Sources */, + 66A10FB4257F1E1800DD651A /* ScenarioSetSettingAction.cpp in Sources */, C688792A20289B9B0084B384 /* Lift.cpp in Sources */, F76C86621EC4E88300FA49E2 /* EntranceObject.cpp in Sources */, 93DFD04824521C1A001FCBAF /* HookEngine.cpp in Sources */, @@ -4386,6 +4807,7 @@ 9308DA02209908090079EE96 /* Surface.cpp in Sources */, C68878DD20289B9B0084B384 /* PaintHelpers.cpp in Sources */, F76C86661EC4E88300FA49E2 /* FootpathObject.cpp in Sources */, + 66A10F80257F1E1800DD651A /* NetworkModifyGroupAction.cpp in Sources */, C688793420289B9B0084B384 /* WaterCoaster.cpp in Sources */, F76C86681EC4E88300FA49E2 /* ImageTable.cpp in Sources */, C68878E620289B9B0084B384 /* Platform.Linux.cpp in Sources */, @@ -4395,10 +4817,14 @@ C688788E20289AE70084B384 /* SSE41Drawing.cpp in Sources */, F76C866C1EC4E88400FA49E2 /* Object.cpp in Sources */, F76C866E1EC4E88400FA49E2 /* ObjectFactory.cpp in Sources */, + 66A10FAB257F1E1800DD651A /* LandSetRightsAction.cpp in Sources */, 93FB272124ED3601008241C9 /* Cursors.cpp in Sources */, C68878A220289B200084B384 /* RealNames.cpp in Sources */, + 66A10F94257F1E1800DD651A /* StaffSetOrdersAction.cpp in Sources */, + 66A10EC7257F1DF800DD651A /* FootpathRemoveAction.cpp in Sources */, C688787120289A780084B384 /* Ride.cpp in Sources */, F76C86701EC4E88400FA49E2 /* ObjectManager.cpp in Sources */, + 66A10F52257F1E1700DD651A /* StaffSetCostumeAction.cpp in Sources */, C688791D20289B9B0084B384 /* Shop.cpp in Sources */, F76C86721EC4E88400FA49E2 /* ObjectRepository.cpp in Sources */, F76C86741EC4E88400FA49E2 /* RideObject.cpp in Sources */, @@ -4409,12 +4835,16 @@ C688792420289B9B0084B384 /* SwingingShip.cpp in Sources */, C68878F420289B9B0084B384 /* InvertedHairpinCoaster.cpp in Sources */, C68878A620289B2A0084B384 /* Finance.cpp in Sources */, + 66A10FA4257F1E1800DD651A /* RideSetNameAction.cpp in Sources */, C688788720289ADE0084B384 /* TTFSDLPort.cpp in Sources */, F76C86761EC4E88400FA49E2 /* SceneryGroupObject.cpp in Sources */, + 66A10FB1257F1E1800DD651A /* RideDemolishAction.cpp in Sources */, C68878F620289B9B0084B384 /* InvertedRollerCoaster.cpp in Sources */, + 66A10F55257F1E1700DD651A /* SurfaceSetStyleAction.cpp in Sources */, C68878E420289B9B0084B384 /* Linux.cpp in Sources */, F76C86791EC4E88400FA49E2 /* SmallSceneryObject.cpp in Sources */, 93F9DA3820B46F9D00D1BE92 /* ShopItem.cpp in Sources */, + 66A10ECD257F1DF800DD651A /* BannerRemoveAction.cpp in Sources */, C688787720289A780084B384 /* Station.cpp in Sources */, C68878DF20289B9B0084B384 /* VirtualFloor.cpp in Sources */, C68878CD20289B9B0084B384 /* DefaultObjects.cpp in Sources */, @@ -4424,6 +4854,7 @@ C688790D20289B9B0084B384 /* Circus.cpp in Sources */, C688788F20289B140084B384 /* Chat.cpp in Sources */, C688789A20289B200084B384 /* ConversionTables.cpp in Sources */, + 66A10ED2257F1DF800DD651A /* FootpathAdditionRemoveAction.cpp in Sources */, C688791020289B9B0084B384 /* FerrisWheel.cpp in Sources */, C688791120289B9B0084B384 /* FlyingSaucers.cpp in Sources */, C688784A202899B40084B384 /* input.cpp in Sources */, @@ -4435,28 +4866,46 @@ C68878DB20289B9B0084B384 /* Paint.cpp in Sources */, F76C86811EC4E88400FA49E2 /* WaterObject.cpp in Sources */, F76C86861EC4E88400FA49E2 /* OpenRCT2.cpp in Sources */, + 66A10F89257F1E1800DD651A /* PauseToggleAction.cpp in Sources */, + 66A10F66257F1E1700DD651A /* RideSetVehicleAction.cpp in Sources */, C68878F320289B9B0084B384 /* HeartlineTwisterCoaster.cpp in Sources */, C688788320289ADE0084B384 /* ScrollingText.cpp in Sources */, C68878F720289B9B0084B384 /* JuniorRollerCoaster.cpp in Sources */, + 66A10F6F257F1E1800DD651A /* RideEntranceExitPlaceAction.cpp in Sources */, + 66A10F64257F1E1700DD651A /* LandRaiseAction.cpp in Sources */, + 66A10F7D257F1E1800DD651A /* ParkSetNameAction.cpp in Sources */, C688792020289B9B0084B384 /* GoKarts.cpp in Sources */, + 66A10FD9257F1E3000DD651A /* WaterSetHeightAction.cpp in Sources */, 939A359B20C12FC800630B3F /* Paint.Misc.cpp in Sources */, C688792E20289B9B0084B384 /* BoatHire.cpp in Sources */, F76C869C1EC4E88400FA49E2 /* ParkImporter.cpp in Sources */, F76C86A31EC4E88400FA49E2 /* Crash.cpp in Sources */, + 66A10ED1257F1DF800DD651A /* CustomAction.cpp in Sources */, 2A1F4FE2221FF4B0003CA045 /* macos.mm in Sources */, C688789420289B140084B384 /* Screenshot.cpp in Sources */, 9346F9DC208A191900C77D91 /* GuestPathfinding.cpp in Sources */, C688790620289B9B0084B384 /* TwisterRollerCoaster.cpp in Sources */, C688786720289A4A0084B384 /* SawyerCoding.cpp in Sources */, 93F9DA3B20B4701100D1BE92 /* StdInOutConsole.cpp in Sources */, + 66A10FA1257F1E1800DD651A /* SmallScenerySetColourAction.cpp in Sources */, + 66A10F95257F1E1800DD651A /* GuestSetFlagsAction.cpp in Sources */, + 66A10FB5257F1E1800DD651A /* SignSetNameAction.cpp in Sources */, + 66A10FDC257F1E3000DD651A /* TrackPlaceAction.cpp in Sources */, 9344BEFA20C1E6180047D165 /* Crypt.OpenSSL.cpp in Sources */, + 66A10ECB257F1DF800DD651A /* BannerSetStyleAction.cpp in Sources */, 93F76F0520BFF77B00D4512C /* Paint.TileElement.cpp in Sources */, C68878FE20289B9B0084B384 /* MiniSuspendedCoaster.cpp in Sources */, F76C86AD1EC4E88400FA49E2 /* PlatformEnvironment.cpp in Sources */, + 66A10F6B257F1E1800DD651A /* ParkSetLoanAction.cpp in Sources */, + 66A10FE0257F1E3000DD651A /* WallRemoveAction.cpp in Sources */, + 66A10FBB257F1E1800DD651A /* LargeSceneryPlaceAction.cpp in Sources */, + 66A10F7A257F1E1800DD651A /* RideSetSettingAction.cpp in Sources */, C688791220289B9B0084B384 /* GhostTrain.cpp in Sources */, C688787F20289ADE0084B384 /* Font.cpp in Sources */, 93CBA4C520A7502E00867D56 /* Imaging.cpp in Sources */, F76C86AF1EC4E88400FA49E2 /* S4Importer.cpp in Sources */, + 66A10F7C257F1E1800DD651A /* StaffHireNewAction.cpp in Sources */, + 66A10F85257F1E1800DD651A /* LandSetHeightAction.cpp in Sources */, F76C86B01EC4E88400FA49E2 /* Tables.cpp in Sources */, C688788520289ADE0084B384 /* Text.cpp in Sources */, F76C86B41EC4E88400FA49E2 /* SawyerChunk.cpp in Sources */, @@ -4464,8 +4913,10 @@ C68878E120289B9B0084B384 /* PeepData.cpp in Sources */, F76C86B61EC4E88400FA49E2 /* SawyerChunkReader.cpp in Sources */, F76C86B81EC4E88400FA49E2 /* SawyerChunkWriter.cpp in Sources */, + 66A10FE1257F1E3000DD651A /* WallSetColourAction.cpp in Sources */, C6887855202899F60084B384 /* Particle.cpp in Sources */, C688784E202899CB0084B384 /* Date.cpp in Sources */, + 66A10F9B257F1E1800DD651A /* ParkSetResearchFundingAction.cpp in Sources */, F76C86BA1EC4E88400FA49E2 /* SawyerEncoding.cpp in Sources */, F76C86C31EC4E88400FA49E2 /* S6Exporter.cpp in Sources */, C68878E820289B9B0084B384 /* Platform.Win32.cpp in Sources */, @@ -4477,46 +4928,65 @@ C688790A20289B9B0084B384 /* WoodenRollerCoaster.cpp in Sources */, C688787220289A780084B384 /* MusicList.cpp in Sources */, 93F76F0220BFF77B00D4512C /* Paint.Surface.cpp in Sources */, + 66A10ECF257F1DF800DD651A /* ClimateSetAction.cpp in Sources */, 93DFD02F24521BA0001FCBAF /* FileWatcher.cpp in Sources */, F76C871C1EC4E88400FA49E2 /* TrackDesignRepository.cpp in Sources */, C68878FA20289B9B0084B384 /* LoopingRollerCoaster.cpp in Sources */, + 66A10F57257F1E1700DD651A /* RideSetAppearanceAction.cpp in Sources */, + 66A10FB9257F1E1800DD651A /* RideSetStatusAction.cpp in Sources */, C68878A720289B2A0084B384 /* Marketing.cpp in Sources */, F76C87331EC4E88400FA49E2 /* ScenarioRepository.cpp in Sources */, C68878FB20289B9B0084B384 /* MineRide.cpp in Sources */, + 66A10FD8257F1E3000DD651A /* TrackRemoveAction.cpp in Sources */, 9308D9FF209908090079EE96 /* TileElement.cpp in Sources */, + 66A10FAA257F1E1800DD651A /* SetParkEntranceFeeAction.cpp in Sources */, + 66A10F9E257F1E1800DD651A /* ParkMarketingAction.cpp in Sources */, C688789020289B140084B384 /* Colour.cpp in Sources */, + 66A10FA3257F1E1800DD651A /* LandLowerAction.cpp in Sources */, + 66A10FB7257F1E1800DD651A /* LandBuyRightsAction.cpp in Sources */, C68878EB20289B9B0084B384 /* Windows.cpp in Sources */, C688789920289B140084B384 /* Window.cpp in Sources */, F76C87351EC4E88400FA49E2 /* ScenarioSources.cpp in Sources */, F76C87381EC4E88400FA49E2 /* TitleScreen.cpp in Sources */, F76C873A1EC4E88400FA49E2 /* TitleSequence.cpp in Sources */, + 66A10EC0257F1DF800DD651A /* BannerPlaceAction.cpp in Sources */, C6887852202899ED0084B384 /* TileInspector.cpp in Sources */, F76C873C1EC4E88400FA49E2 /* TitleSequenceManager.cpp in Sources */, + 66A10F9D257F1E1800DD651A /* StaffFireAction.cpp in Sources */, C688793320289B9B0084B384 /* SubmarineRide.cpp in Sources */, 93F76EEE20BFF6F900D4512C /* Drawing.String.cpp in Sources */, C688785C20289A0A0084B384 /* Entrance.cpp in Sources */, C688790E20289B9B0084B384 /* CrookedHouse.cpp in Sources */, C68878F520289B9B0084B384 /* InvertedImpulseCoaster.cpp in Sources */, C688793020289B9B0084B384 /* LogFlume.cpp in Sources */, + 66A10F82257F1E1800DD651A /* PlayerSetGroupAction.cpp in Sources */, 2ADE2F3222441905002598AF /* DiscordService.cpp in Sources */, C688786620289A430084B384 /* Intent.cpp in Sources */, + 66A10FBA257F1E1800DD651A /* PlayerKickAction.cpp in Sources */, C68878E520289B9B0084B384 /* Platform.Android.cpp in Sources */, C68878EA20289B9B0084B384 /* Shared.cpp in Sources */, F76C87451EC4E88400FA49E2 /* Version.cpp in Sources */, 9346F9D9208A191900C77D91 /* Guest.cpp in Sources */, C688789C20289B200084B384 /* Currency.cpp in Sources */, + 66A10F9C257F1E1800DD651A /* PeepPickupAction.cpp in Sources */, C68879A420289C060084B384 /* Platform.macOS.mm in Sources */, + 66A10FA0257F1E1800DD651A /* StaffSetPatrolAreaAction.cpp in Sources */, + 66A10F5B257F1E1700DD651A /* GuestSetNameAction.cpp in Sources */, C688787420289A780084B384 /* TrackDesignSave.cpp in Sources */, C688790F20289B9B0084B384 /* Dodgems.cpp in Sources */, C688791E20289B9B0084B384 /* 3dCinema.cpp in Sources */, C688786420289A0A0084B384 /* MoneyEffect.cpp in Sources */, + 66A10F98257F1E1800DD651A /* PlacePeepSpawnAction.cpp in Sources */, C68878A420289B200084B384 /* UTF8.cpp in Sources */, C688786D20289A6F0084B384 /* TrackPaint.cpp in Sources */, 93F76F0620BFF77B00D4512C /* Paint.Entrance.cpp in Sources */, C688792120289B9B0084B384 /* LaunchedFreefall.cpp in Sources */, + 66A10FD4257F1E3000DD651A /* TrackSetBrakeSpeedAction.cpp in Sources */, C688791920289B9B0084B384 /* ObservationTower.cpp in Sources */, 93F76EF020BFF71700D4512C /* InteractiveConsole.cpp in Sources */, C6887853202899F00084B384 /* Sprite.cpp in Sources */, + 66A10FB3257F1E1800DD651A /* MazeSetTrackAction.cpp in Sources */, + 66A10EC5257F1DF800DD651A /* BannerSetNameAction.cpp in Sources */, C688786F20289A6F0084B384 /* VehicleData.cpp in Sources */, C688786520289A400084B384 /* _legacy.cpp in Sources */, C688785F20289A0A0084B384 /* LargeScenery.cpp in Sources */, @@ -4524,6 +4994,7 @@ C688792220289B9B0084B384 /* MagicCarpet.cpp in Sources */, 93F76F0120BFF77B00D4512C /* Paint.LargeScenery.cpp in Sources */, C688790720289B9B0084B384 /* VerticalDropRollerCoaster.cpp in Sources */, + 66A10F60257F1E1700DD651A /* ParkEntranceRemoveAction.cpp in Sources */, 93F9DA3A20B46FCA00D1BE92 /* SceneryObject.cpp in Sources */, 936F412924CE030F00E07BCF /* NetworkBase.cpp in Sources */, C688787520289A780084B384 /* RideData.cpp in Sources */, @@ -4532,7 +5003,9 @@ C688789320289B140084B384 /* Fonts.cpp in Sources */, C688792F20289B9B0084B384 /* DingySlide.cpp in Sources */, C688787920289A780084B384 /* TrackData.cpp in Sources */, + 66A10F71257F1E1800DD651A /* StaffSetColourAction.cpp in Sources */, C68878F020289B9B0084B384 /* CorkscrewRollerCoaster.cpp in Sources */, + 66A10FD1257F1E3000DD651A /* WaterRaiseAction.cpp in Sources */, C688791820289B9B0084B384 /* MonorailCycles.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/src/openrct2-ui/input/KeyboardShortcut.cpp b/src/openrct2-ui/input/KeyboardShortcut.cpp index 91423ebf3f..cd2452a16a 100644 --- a/src/openrct2-ui/input/KeyboardShortcut.cpp +++ b/src/openrct2-ui/input/KeyboardShortcut.cpp @@ -18,8 +18,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/interface/ViewportInteraction.cpp b/src/openrct2-ui/interface/ViewportInteraction.cpp index cec965f646..7fb5e43d06 100644 --- a/src/openrct2-ui/interface/ViewportInteraction.cpp +++ b/src/openrct2-ui/interface/ViewportInteraction.cpp @@ -18,12 +18,12 @@ #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Banner.cpp b/src/openrct2-ui/windows/Banner.cpp index 97bdecd48f..9b9e00c36c 100644 --- a/src/openrct2-ui/windows/Banner.cpp +++ b/src/openrct2-ui/windows/Banner.cpp @@ -12,10 +12,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Cheats.cpp b/src/openrct2-ui/windows/Cheats.cpp index 236ede7f9f..c4c34a6998 100644 --- a/src/openrct2-ui/windows/Cheats.cpp +++ b/src/openrct2-ui/windows/Cheats.cpp @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index be5bf110a4..d07f5deff1 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp index 79d08975a2..4804273421 100644 --- a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp +++ b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/EditorScenarioOptions.cpp b/src/openrct2-ui/windows/EditorScenarioOptions.cpp index 15abc702ab..9a4d238ef5 100644 --- a/src/openrct2-ui/windows/EditorScenarioOptions.cpp +++ b/src/openrct2-ui/windows/EditorScenarioOptions.cpp @@ -17,8 +17,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Finances.cpp b/src/openrct2-ui/windows/Finances.cpp index 04f13d2e41..27b12f1a97 100644 --- a/src/openrct2-ui/windows/Finances.cpp +++ b/src/openrct2-ui/windows/Finances.cpp @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index a3031d2821..865fdc43e9 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp index a91f79f185..c5c0f46d4a 100644 --- a/src/openrct2-ui/windows/Guest.cpp +++ b/src/openrct2-ui/windows/Guest.cpp @@ -14,8 +14,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/LandRights.cpp b/src/openrct2-ui/windows/LandRights.cpp index 30fb79e5be..60de6b797c 100644 --- a/src/openrct2-ui/windows/LandRights.cpp +++ b/src/openrct2-ui/windows/LandRights.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp index c3cd4ee0de..1539ee2e32 100644 --- a/src/openrct2-ui/windows/Map.cpp +++ b/src/openrct2-ui/windows/Map.cpp @@ -18,12 +18,13 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include +#include #include #include #include diff --git a/src/openrct2-ui/windows/MazeConstruction.cpp b/src/openrct2-ui/windows/MazeConstruction.cpp index 7a649af8a3..32b22622fe 100644 --- a/src/openrct2-ui/windows/MazeConstruction.cpp +++ b/src/openrct2-ui/windows/MazeConstruction.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Multiplayer.cpp b/src/openrct2-ui/windows/Multiplayer.cpp index ca63d3ded6..b38f1116e5 100644 --- a/src/openrct2-ui/windows/Multiplayer.cpp +++ b/src/openrct2-ui/windows/Multiplayer.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/NewCampaign.cpp b/src/openrct2-ui/windows/NewCampaign.cpp index 54c67d1abd..734438d590 100644 --- a/src/openrct2-ui/windows/NewCampaign.cpp +++ b/src/openrct2-ui/windows/NewCampaign.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Park.cpp b/src/openrct2-ui/windows/Park.cpp index 6e405d51a8..6866b57d79 100644 --- a/src/openrct2-ui/windows/Park.cpp +++ b/src/openrct2-ui/windows/Park.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Player.cpp b/src/openrct2-ui/windows/Player.cpp index 13b473b5d3..54bca579b1 100644 --- a/src/openrct2-ui/windows/Player.cpp +++ b/src/openrct2-ui/windows/Player.cpp @@ -13,8 +13,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Research.cpp b/src/openrct2-ui/windows/Research.cpp index a47cb55ca6..1ef336729a 100644 --- a/src/openrct2-ui/windows/Research.cpp +++ b/src/openrct2-ui/windows/Research.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp index afe2655032..6f845c842d 100644 --- a/src/openrct2-ui/windows/Ride.cpp +++ b/src/openrct2-ui/windows/Ride.cpp @@ -23,11 +23,11 @@ #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index 33617dcc35..3c84d635b9 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -17,10 +17,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Sign.cpp b/src/openrct2-ui/windows/Sign.cpp index cd0b8e1c9f..b6f876b8c1 100644 --- a/src/openrct2-ui/windows/Sign.cpp +++ b/src/openrct2-ui/windows/Sign.cpp @@ -12,10 +12,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/Staff.cpp b/src/openrct2-ui/windows/Staff.cpp index 2290d4733d..617d502f67 100644 --- a/src/openrct2-ui/windows/Staff.cpp +++ b/src/openrct2-ui/windows/Staff.cpp @@ -16,10 +16,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/StaffFirePrompt.cpp b/src/openrct2-ui/windows/StaffFirePrompt.cpp index 618a3c7755..baae4c9cb0 100644 --- a/src/openrct2-ui/windows/StaffFirePrompt.cpp +++ b/src/openrct2-ui/windows/StaffFirePrompt.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/StaffList.cpp b/src/openrct2-ui/windows/StaffList.cpp index d2fbda0959..213f6f67e8 100644 --- a/src/openrct2-ui/windows/StaffList.cpp +++ b/src/openrct2-ui/windows/StaffList.cpp @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index 36ef268c07..e11f474989 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/TitleMenu.cpp b/src/openrct2-ui/windows/TitleMenu.cpp index fd4bf9eea3..16470bee38 100644 --- a/src/openrct2-ui/windows/TitleMenu.cpp +++ b/src/openrct2-ui/windows/TitleMenu.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 30dea41c29..5a8d7189ed 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -26,25 +26,25 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/openrct2/Cheats.cpp b/src/openrct2/Cheats.cpp index 4dd62e43f4..e8458acf61 100644 --- a/src/openrct2/Cheats.cpp +++ b/src/openrct2/Cheats.cpp @@ -10,8 +10,8 @@ #include "Cheats.h" #include "GameState.h" -#include "actions/ParkSetLoanAction.hpp" -#include "actions/SetCheatAction.hpp" +#include "actions/ParkSetLoanAction.h" +#include "actions/SetCheatAction.h" #include "config/Config.h" #include "core/DataSerialiser.h" #include "localisation/Localisation.h" diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index 511e2669bb..2a5264d769 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -16,8 +16,8 @@ #include "GameState.h" #include "OpenRCT2.h" #include "ParkImporter.h" -#include "actions/LandBuyRightsAction.hpp" -#include "actions/LandSetRightsAction.hpp" +#include "actions/LandBuyRightsAction.h" +#include "actions/LandSetRightsAction.h" #include "audio/audio.h" #include "interface/Viewport.h" #include "interface/Window_internal.h" diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 14a76e14b4..b9b0b402eb 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -19,7 +19,7 @@ #include "ParkImporter.h" #include "PlatformEnvironment.h" #include "ReplayManager.h" -#include "actions/LoadOrQuitAction.hpp" +#include "actions/LoadOrQuitAction.h" #include "audio/audio.h" #include "config/Config.h" #include "core/FileScanner.h" diff --git a/src/openrct2/ReplayManager.cpp b/src/openrct2/ReplayManager.cpp index 2b010cca33..2f9577a0d5 100644 --- a/src/openrct2/ReplayManager.cpp +++ b/src/openrct2/ReplayManager.cpp @@ -15,13 +15,13 @@ #include "OpenRCT2.h" #include "ParkImporter.h" #include "PlatformEnvironment.h" -#include "actions/FootpathPlaceAction.hpp" +#include "actions/FootpathPlaceAction.h" #include "actions/GameAction.h" -#include "actions/RideEntranceExitPlaceAction.hpp" -#include "actions/RideSetSetting.hpp" -#include "actions/SetCheatAction.hpp" -#include "actions/TileModifyAction.hpp" -#include "actions/TrackPlaceAction.hpp" +#include "actions/RideEntranceExitPlaceAction.h" +#include "actions/RideSetSettingAction.h" +#include "actions/SetCheatAction.h" +#include "actions/TileModifyAction.h" +#include "actions/TrackPlaceAction.h" #include "config/Config.h" #include "core/DataSerialiser.h" #include "core/Path.hpp" diff --git a/src/openrct2/actions/BalloonPressAction.cpp b/src/openrct2/actions/BalloonPressAction.cpp new file mode 100644 index 0000000000..b32cc5c9b6 --- /dev/null +++ b/src/openrct2/actions/BalloonPressAction.cpp @@ -0,0 +1,48 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "BalloonPressAction.h" + +#include "GameAction.h" + +void BalloonPressAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("id", _spriteIndex); +} + +void BalloonPressAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_spriteIndex); +} + +GameActions::Result::Ptr BalloonPressAction::Query() const +{ + auto balloon = TryGetEntity(_spriteIndex); + if (balloon == nullptr) + { + log_error("Tried getting invalid sprite for balloon: %u", _spriteIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return MakeResult(); +} + +GameActions::Result::Ptr BalloonPressAction::Execute() const +{ + auto balloon = TryGetEntity(_spriteIndex); + if (balloon == nullptr) + { + log_error("Tried getting invalid sprite for balloon: %u", _spriteIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + balloon->Press(); + + return MakeResult(); +} diff --git a/src/openrct2/actions/BalloonPressAction.h b/src/openrct2/actions/BalloonPressAction.h new file mode 100644 index 0000000000..9496b47aa2 --- /dev/null +++ b/src/openrct2/actions/BalloonPressAction.h @@ -0,0 +1,35 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(BalloonPressAction, GAME_COMMAND_BALLOON_PRESS, GameActions::Result) +{ + uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; + +public: + BalloonPressAction() = default; + BalloonPressAction(uint16_t spriteIndex) + : _spriteIndex(spriteIndex) + { + } + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/BalloonPressAction.hpp b/src/openrct2/actions/BalloonPressAction.hpp deleted file mode 100644 index 17a800d197..0000000000 --- a/src/openrct2/actions/BalloonPressAction.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(BalloonPressAction, GAME_COMMAND_BALLOON_PRESS, GameActions::Result) -{ - uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; - -public: - BalloonPressAction() = default; - BalloonPressAction(uint16_t spriteIndex) - : _spriteIndex(spriteIndex) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("id", _spriteIndex); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_spriteIndex); - } - - GameActions::Result::Ptr Query() const override - { - auto balloon = TryGetEntity(_spriteIndex); - if (balloon == nullptr) - { - log_error("Tried getting invalid sprite for balloon: %u", _spriteIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto balloon = TryGetEntity(_spriteIndex); - if (balloon == nullptr) - { - log_error("Tried getting invalid sprite for balloon: %u", _spriteIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - balloon->Press(); - - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/BannerPlaceAction.cpp b/src/openrct2/actions/BannerPlaceAction.cpp new file mode 100644 index 0000000000..4d9910a299 --- /dev/null +++ b/src/openrct2/actions/BannerPlaceAction.cpp @@ -0,0 +1,182 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "BannerPlaceAction.h" + +#include "../management/Finance.h" +#include "../world/Banner.h" +#include "../world/MapAnimation.h" +#include "../world/Scenery.h" +#include "GameAction.h" + +void BannerPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _bannerType); + visitor.Visit("primaryColour", _primaryColour); + _bannerIndex = create_new_banner(0); +} + +void BannerPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_bannerType) << DS_TAG(_bannerIndex) << DS_TAG(_primaryColour); +} + +GameActions::Result::Ptr BannerPlaceAction::Query() const +{ + auto res = MakeResult(); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->Expenditure = ExpenditureType::Landscaping; + res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; + + if (!map_check_free_elements_and_reorganise(1)) + { + log_error("No free map elements."); + return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_POSITION_THIS_HERE); + } + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + auto pathElement = GetValidPathElement(); + + if (pathElement == nullptr) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS); + } + + if (!map_can_build_at(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto baseHeight = _loc.z + PATH_HEIGHT_STEP; + BannerElement* existingBannerElement = map_get_banner_element_at({ _loc.x, _loc.y, baseHeight }, _loc.direction); + if (existingBannerElement != nullptr) + { + return MakeResult(GameActions::Status::ItemAlreadyPlaced, STR_CANT_POSITION_THIS_HERE, STR_BANNER_SIGN_IN_THE_WAY); + } + + if (_bannerIndex == BANNER_INDEX_NULL || _bannerIndex >= MAX_BANNERS) + { + log_error("Invalid banner index, bannerIndex = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + auto banner = GetBanner(_bannerIndex); + if (!banner->IsNull()) + { + log_error("Banner index in use, bannerIndex = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + rct_scenery_entry* bannerEntry = get_banner_entry(_bannerType); + if (bannerEntry == nullptr) + { + log_error("Invalid banner object type. bannerType = ", _bannerType); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + res->Cost = bannerEntry->banner.price; + return res; +} + +GameActions::Result::Ptr BannerPlaceAction::Execute() const +{ + auto res = MakeResult(); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->Expenditure = ExpenditureType::Landscaping; + res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; + + if (!map_check_free_elements_and_reorganise(1)) + { + log_error("No free map elements."); + return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_POSITION_THIS_HERE); + } + + if (_bannerIndex == BANNER_INDEX_NULL || _bannerIndex >= MAX_BANNERS) + { + log_error("Invalid banner index, bannerIndex = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + rct_scenery_entry* bannerEntry = get_banner_entry(_bannerType); + if (bannerEntry == nullptr) + { + log_error("Invalid banner object type. bannerType = ", _bannerType); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + auto banner = GetBanner(_bannerIndex); + if (!banner->IsNull()) + { + log_error("Banner index in use, bannerIndex = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + TileElement* newTileElement = tile_element_insert({ _loc, _loc.z + (2 * COORDS_Z_STEP) }, 0b0000); + assert(newTileElement != nullptr); + + banner->flags = 0; + banner->text = {}; + banner->text_colour = 2; + banner->type = _bannerType; // Banner must be deleted after this point in an early return + banner->colour = _primaryColour; + banner->position = TileCoordsXY(_loc); + newTileElement->SetType(TILE_ELEMENT_TYPE_BANNER); + BannerElement* bannerElement = newTileElement->AsBanner(); + bannerElement->SetClearanceZ(_loc.z + PATH_CLEARANCE); + bannerElement->SetPosition(_loc.direction); + bannerElement->ResetAllowedEdges(); + bannerElement->SetIndex(_bannerIndex); + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + bannerElement->SetGhost(true); + } + map_invalidate_tile_full(_loc); + map_animation_create(MAP_ANIMATION_TYPE_BANNER, CoordsXYZ{ _loc, bannerElement->GetBaseZ() }); + + res->Cost = bannerEntry->banner.price; + return res; +} + +PathElement* BannerPlaceAction::GetValidPathElement() const +{ + TileElement* tileElement = map_get_first_element_at(_loc); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH) + continue; + + auto pathElement = tileElement->AsPath(); + + if (pathElement->GetBaseZ() != _loc.z && pathElement->GetBaseZ() != _loc.z - PATH_HEIGHT_STEP) + continue; + + if (!(pathElement->GetEdges() & (1 << _loc.direction))) + continue; + + if (pathElement->IsGhost() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + continue; + + return pathElement; + } while (!(tileElement++)->IsLastForTile()); + return nullptr; +} diff --git a/src/openrct2/actions/BannerPlaceAction.h b/src/openrct2/actions/BannerPlaceAction.h new file mode 100644 index 0000000000..691b7057bc --- /dev/null +++ b/src/openrct2/actions/BannerPlaceAction.h @@ -0,0 +1,45 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(BannerPlaceAction, GAME_COMMAND_PLACE_BANNER, GameActions::Result) +{ +private: + CoordsXYZD _loc; + ObjectEntryIndex _bannerType{ BANNER_NULL }; + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; + uint8_t _primaryColour{}; + +public: + BannerPlaceAction() = default; + BannerPlaceAction(const CoordsXYZD& loc, uint8_t bannerType, BannerIndex bannerIndex, uint8_t primaryColour) + : _loc(loc) + , _bannerType(bannerType) + , _bannerIndex(bannerIndex) + , _primaryColour(primaryColour) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + PathElement* GetValidPathElement() const; +}; diff --git a/src/openrct2/actions/BannerPlaceAction.hpp b/src/openrct2/actions/BannerPlaceAction.hpp deleted file mode 100644 index 4e3ee579fc..0000000000 --- a/src/openrct2/actions/BannerPlaceAction.hpp +++ /dev/null @@ -1,207 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../management/Finance.h" -#include "../world/Banner.h" -#include "../world/MapAnimation.h" -#include "../world/Scenery.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(BannerPlaceAction, GAME_COMMAND_PLACE_BANNER, GameActions::Result) -{ -private: - CoordsXYZD _loc; - ObjectEntryIndex _bannerType{ BANNER_NULL }; - BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; - uint8_t _primaryColour{}; - -public: - BannerPlaceAction() = default; - BannerPlaceAction(const CoordsXYZD& loc, uint8_t bannerType, BannerIndex bannerIndex, uint8_t primaryColour) - : _loc(loc) - , _bannerType(bannerType) - , _bannerIndex(bannerIndex) - , _primaryColour(primaryColour) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _bannerType); - visitor.Visit("primaryColour", _primaryColour); - _bannerIndex = create_new_banner(0); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_bannerType) << DS_TAG(_bannerIndex) << DS_TAG(_primaryColour); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - res->Expenditure = ExpenditureType::Landscaping; - res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; - - if (!map_check_free_elements_and_reorganise(1)) - { - log_error("No free map elements."); - return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_POSITION_THIS_HERE); - } - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - auto pathElement = GetValidPathElement(); - - if (pathElement == nullptr) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS); - } - - if (!map_can_build_at(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - auto baseHeight = _loc.z + PATH_HEIGHT_STEP; - BannerElement* existingBannerElement = map_get_banner_element_at({ _loc.x, _loc.y, baseHeight }, _loc.direction); - if (existingBannerElement != nullptr) - { - return MakeResult(GameActions::Status::ItemAlreadyPlaced, STR_CANT_POSITION_THIS_HERE, STR_BANNER_SIGN_IN_THE_WAY); - } - - if (_bannerIndex == BANNER_INDEX_NULL || _bannerIndex >= MAX_BANNERS) - { - log_error("Invalid banner index, bannerIndex = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - auto banner = GetBanner(_bannerIndex); - if (!banner->IsNull()) - { - log_error("Banner index in use, bannerIndex = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - rct_scenery_entry* bannerEntry = get_banner_entry(_bannerType); - if (bannerEntry == nullptr) - { - log_error("Invalid banner object type. bannerType = ", _bannerType); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - res->Cost = bannerEntry->banner.price; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - res->Expenditure = ExpenditureType::Landscaping; - res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; - - if (!map_check_free_elements_and_reorganise(1)) - { - log_error("No free map elements."); - return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_POSITION_THIS_HERE); - } - - if (_bannerIndex == BANNER_INDEX_NULL || _bannerIndex >= MAX_BANNERS) - { - log_error("Invalid banner index, bannerIndex = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - rct_scenery_entry* bannerEntry = get_banner_entry(_bannerType); - if (bannerEntry == nullptr) - { - log_error("Invalid banner object type. bannerType = ", _bannerType); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - auto banner = GetBanner(_bannerIndex); - if (!banner->IsNull()) - { - log_error("Banner index in use, bannerIndex = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - TileElement* newTileElement = tile_element_insert({ _loc, _loc.z + (2 * COORDS_Z_STEP) }, 0b0000); - assert(newTileElement != nullptr); - - banner->flags = 0; - banner->text = {}; - banner->text_colour = 2; - banner->type = _bannerType; // Banner must be deleted after this point in an early return - banner->colour = _primaryColour; - banner->position = TileCoordsXY(_loc); - newTileElement->SetType(TILE_ELEMENT_TYPE_BANNER); - BannerElement* bannerElement = newTileElement->AsBanner(); - bannerElement->SetClearanceZ(_loc.z + PATH_CLEARANCE); - bannerElement->SetPosition(_loc.direction); - bannerElement->ResetAllowedEdges(); - bannerElement->SetIndex(_bannerIndex); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - bannerElement->SetGhost(true); - } - map_invalidate_tile_full(_loc); - map_animation_create(MAP_ANIMATION_TYPE_BANNER, CoordsXYZ{ _loc, bannerElement->GetBaseZ() }); - - res->Cost = bannerEntry->banner.price; - return res; - } - -private: - PathElement* GetValidPathElement() const - { - TileElement* tileElement = map_get_first_element_at(_loc); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH) - continue; - - auto pathElement = tileElement->AsPath(); - - if (pathElement->GetBaseZ() != _loc.z && pathElement->GetBaseZ() != _loc.z - PATH_HEIGHT_STEP) - continue; - - if (!(pathElement->GetEdges() & (1 << _loc.direction))) - continue; - - if (pathElement->IsGhost() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - continue; - - return pathElement; - } while (!(tileElement++)->IsLastForTile()); - return nullptr; - } -}; diff --git a/src/openrct2/actions/BannerRemoveAction.cpp b/src/openrct2/actions/BannerRemoveAction.cpp new file mode 100644 index 0000000000..624f2a799f --- /dev/null +++ b/src/openrct2/actions/BannerRemoveAction.cpp @@ -0,0 +1,137 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "BannerRemoveAction.h" + +#include "../management/Finance.h" +#include "../world/Banner.h" +#include "../world/MapAnimation.h" +#include "../world/Scenery.h" +#include "GameAction.h" + +void BannerRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); +} + +void BannerRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr BannerRemoveAction::Query() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->ErrorTitle = STR_CANT_REMOVE_THIS; + + if (!LocationValid(_loc) || !map_can_build_at({ _loc.x, _loc.y, _loc.z - 16 })) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + BannerElement* bannerElement = GetBannerElementAt(); + if (bannerElement == nullptr) + { + log_error("Invalid banner location, x = %d, y = %d, z = %d, direction = %d", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + if (bannerElement->GetIndex() >= MAX_BANNERS || bannerElement->GetIndex() == BANNER_INDEX_NULL) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + auto banner = bannerElement->GetBanner(); + if (banner == nullptr) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + rct_scenery_entry* bannerEntry = get_banner_entry(banner->type); + if (bannerEntry != nullptr) + { + res->Cost = -((bannerEntry->banner.price * 3) / 4); + } + + return res; +} + +GameActions::Result::Ptr BannerRemoveAction::Execute() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->ErrorTitle = STR_CANT_REMOVE_THIS; + + BannerElement* bannerElement = GetBannerElementAt(); + if (bannerElement == nullptr) + { + log_error("Invalid banner location, x = %d, y = %d, z = %d, direction = %d", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + if (bannerElement->GetIndex() >= MAX_BANNERS || bannerElement->GetIndex() == BANNER_INDEX_NULL) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + auto banner = bannerElement->GetBanner(); + if (banner == nullptr) + { + log_error("Invalid banner index. index = ", bannerElement->GetIndex()); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + rct_scenery_entry* bannerEntry = get_banner_entry(banner->type); + if (bannerEntry != nullptr) + { + res->Cost = -((bannerEntry->banner.price * 3) / 4); + } + + tile_element_remove_banner_entry(reinterpret_cast(bannerElement)); + map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 32 }); + bannerElement->Remove(); + + return res; +} + +BannerElement* BannerRemoveAction::GetBannerElementAt() const +{ + TileElement* tileElement = map_get_first_element_at(_loc); + + // Find the banner element at known z and position + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) + continue; + if (tileElement->GetBaseZ() != _loc.z) + continue; + if (tileElement->IsGhost() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + continue; + if (tileElement->AsBanner()->GetPosition() != _loc.direction) + continue; + + return tileElement->AsBanner(); + } while (!(tileElement++)->IsLastForTile()); + + return nullptr; +} diff --git a/src/openrct2/actions/BannerRemoveAction.h b/src/openrct2/actions/BannerRemoveAction.h new file mode 100644 index 0000000000..0ddcf555e0 --- /dev/null +++ b/src/openrct2/actions/BannerRemoveAction.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(BannerRemoveAction, GAME_COMMAND_REMOVE_BANNER, GameActions::Result) +{ +private: + CoordsXYZD _loc; + +public: + BannerRemoveAction() = default; + BannerRemoveAction(const CoordsXYZD& loc) + : _loc(loc) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + BannerElement* GetBannerElementAt() const; +}; diff --git a/src/openrct2/actions/BannerRemoveAction.hpp b/src/openrct2/actions/BannerRemoveAction.hpp deleted file mode 100644 index 9edd6b5a49..0000000000 --- a/src/openrct2/actions/BannerRemoveAction.hpp +++ /dev/null @@ -1,158 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../management/Finance.h" -#include "../world/Banner.h" -#include "../world/MapAnimation.h" -#include "../world/Scenery.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(BannerRemoveAction, GAME_COMMAND_REMOVE_BANNER, GameActions::Result) -{ -private: - CoordsXYZD _loc; - -public: - BannerRemoveAction() = default; - BannerRemoveAction(const CoordsXYZD& loc) - : _loc(loc) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - res->ErrorTitle = STR_CANT_REMOVE_THIS; - - if (!LocationValid(_loc) || !map_can_build_at({ _loc.x, _loc.y, _loc.z - 16 })) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - BannerElement* bannerElement = GetBannerElementAt(); - if (bannerElement == nullptr) - { - log_error( - "Invalid banner location, x = %d, y = %d, z = %d, direction = %d", _loc.x, _loc.y, _loc.z, _loc.direction); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - if (bannerElement->GetIndex() >= MAX_BANNERS || bannerElement->GetIndex() == BANNER_INDEX_NULL) - { - log_error("Invalid banner index. index = ", bannerElement->GetIndex()); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - auto banner = bannerElement->GetBanner(); - if (banner == nullptr) - { - log_error("Invalid banner index. index = ", bannerElement->GetIndex()); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - rct_scenery_entry* bannerEntry = get_banner_entry(banner->type); - if (bannerEntry != nullptr) - { - res->Cost = -((bannerEntry->banner.price * 3) / 4); - } - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - res->ErrorTitle = STR_CANT_REMOVE_THIS; - - BannerElement* bannerElement = GetBannerElementAt(); - if (bannerElement == nullptr) - { - log_error( - "Invalid banner location, x = %d, y = %d, z = %d, direction = %d", _loc.x, _loc.y, _loc.z, _loc.direction); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - if (bannerElement->GetIndex() >= MAX_BANNERS || bannerElement->GetIndex() == BANNER_INDEX_NULL) - { - log_error("Invalid banner index. index = ", bannerElement->GetIndex()); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - auto banner = bannerElement->GetBanner(); - if (banner == nullptr) - { - log_error("Invalid banner index. index = ", bannerElement->GetIndex()); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - rct_scenery_entry* bannerEntry = get_banner_entry(banner->type); - if (bannerEntry != nullptr) - { - res->Cost = -((bannerEntry->banner.price * 3) / 4); - } - - tile_element_remove_banner_entry(reinterpret_cast(bannerElement)); - map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 32 }); - bannerElement->Remove(); - - return res; - } - -private: - BannerElement* GetBannerElementAt() const - { - TileElement* tileElement = map_get_first_element_at(_loc); - - // Find the banner element at known z and position - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) - continue; - if (tileElement->GetBaseZ() != _loc.z) - continue; - if (tileElement->IsGhost() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - continue; - if (tileElement->AsBanner()->GetPosition() != _loc.direction) - continue; - - return tileElement->AsBanner(); - } while (!(tileElement++)->IsLastForTile()); - - return nullptr; - } -}; diff --git a/src/openrct2/actions/BannerSetColourAction.cpp b/src/openrct2/actions/BannerSetColourAction.cpp new file mode 100644 index 0000000000..51a3dd36df --- /dev/null +++ b/src/openrct2/actions/BannerSetColourAction.cpp @@ -0,0 +1,94 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "BannerSetColourAction.h" + +#include "../Context.h" +#include "../management/Finance.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "GameAction.h" + +void BannerSetColourAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("primaryColour", _primaryColour); +} + +void BannerSetColourAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_primaryColour); +} + +GameActions::Result::Ptr BannerSetColourAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr BannerSetColourAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr BannerSetColourAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->ErrorTitle = STR_CANT_REPAINT_THIS; + + if (!LocationValid(_loc)) + { + log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (_primaryColour > 31) + { + log_error("Invalid primary colour: colour = %u", _primaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (!map_can_build_at({ _loc.x, _loc.y, _loc.z - 16 })) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto bannerElement = map_get_banner_element_at(_loc, _loc.direction); + + if (bannerElement == nullptr) + { + log_error("Could not find banner at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + + auto index = bannerElement->GetIndex(); + if (index >= MAX_BANNERS || index == BANNER_INDEX_NULL) + { + log_error("Invalid banner index: index = %u", index); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + + if (isExecuting) + { + auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); + intent.putExtra(INTENT_EXTRA_BANNER_INDEX, index); + context_broadcast_intent(&intent); + + auto banner = GetBanner(index); + banner->colour = _primaryColour; + map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 32 }); + } + + return res; +} diff --git a/src/openrct2/actions/BannerSetColourAction.h b/src/openrct2/actions/BannerSetColourAction.h new file mode 100644 index 0000000000..94af9b3db8 --- /dev/null +++ b/src/openrct2/actions/BannerSetColourAction.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(BannerSetColourAction, GAME_COMMAND_SET_BANNER_COLOUR, GameActions::Result) +{ +private: + CoordsXYZD _loc; + uint8_t _primaryColour{}; + +public: + BannerSetColourAction() = default; + + BannerSetColourAction(const CoordsXYZD& loc, uint8_t primaryColour) + : _loc(loc) + , _primaryColour(primaryColour) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/BannerSetColourAction.hpp b/src/openrct2/actions/BannerSetColourAction.hpp deleted file mode 100644 index 0e50bdfa55..0000000000 --- a/src/openrct2/actions/BannerSetColourAction.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../management/Finance.h" -#include "../windows/Intent.h" -#include "../world/Banner.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(BannerSetColourAction, GAME_COMMAND_SET_BANNER_COLOUR, GameActions::Result) -{ -private: - CoordsXYZD _loc; - uint8_t _primaryColour{}; - -public: - BannerSetColourAction() = default; - - BannerSetColourAction(const CoordsXYZD& loc, uint8_t primaryColour) - : _loc(loc) - , _primaryColour(primaryColour) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("primaryColour", _primaryColour); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_primaryColour); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - res->ErrorTitle = STR_CANT_REPAINT_THIS; - - if (!LocationValid(_loc)) - { - log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (_primaryColour > 31) - { - log_error("Invalid primary colour: colour = %u", _primaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (!map_can_build_at({ _loc.x, _loc.y, _loc.z - 16 })) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - auto bannerElement = map_get_banner_element_at(_loc, _loc.direction); - - if (bannerElement == nullptr) - { - log_error( - "Could not find banner at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, _loc.direction); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - - auto index = bannerElement->GetIndex(); - if (index >= MAX_BANNERS || index == BANNER_INDEX_NULL) - { - log_error("Invalid banner index: index = %u", index); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - - if (isExecuting) - { - auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); - intent.putExtra(INTENT_EXTRA_BANNER_INDEX, index); - context_broadcast_intent(&intent); - - auto banner = GetBanner(index); - banner->colour = _primaryColour; - map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 32 }); - } - - return res; - } -}; diff --git a/src/openrct2/actions/BannerSetNameAction.cpp b/src/openrct2/actions/BannerSetNameAction.cpp new file mode 100644 index 0000000000..172a4e8ae2 --- /dev/null +++ b/src/openrct2/actions/BannerSetNameAction.cpp @@ -0,0 +1,58 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "BannerSetNameAction.h" + +#include "../Context.h" +#include "../core/String.hpp" +#include "../drawing/Drawing.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../ui/UiContext.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "../world/Sprite.h" +#include "GameAction.h" + +void BannerSetNameAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("id", _bannerIndex); + visitor.Visit("name", _name); +} + +void BannerSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_bannerIndex) << DS_TAG(_name); +} + +GameActions::Result::Ptr BannerSetNameAction::Query() const +{ + if (_bannerIndex >= MAX_BANNERS) + { + log_warning("Invalid game command for setting banner name, banner id = %d", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return MakeResult(); +} + +GameActions::Result::Ptr BannerSetNameAction::Execute() const +{ + auto banner = GetBanner(_bannerIndex); + banner->text = _name; + + auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); + intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); + context_broadcast_intent(&intent); + + scrolling_text_invalidate(); + gfx_invalidate_screen(); + + return MakeResult(); +} diff --git a/src/openrct2/actions/BannerSetNameAction.h b/src/openrct2/actions/BannerSetNameAction.h new file mode 100644 index 0000000000..2678a46c6b --- /dev/null +++ b/src/openrct2/actions/BannerSetNameAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(BannerSetNameAction, GAME_COMMAND_SET_BANNER_NAME, GameActions::Result) +{ +private: + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; + std::string _name; + +public: + BannerSetNameAction() = default; + BannerSetNameAction(BannerIndex bannerIndex, const std::string& name) + : _bannerIndex(bannerIndex) + , _name(name) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/BannerSetNameAction.hpp b/src/openrct2/actions/BannerSetNameAction.hpp deleted file mode 100644 index 267d311e50..0000000000 --- a/src/openrct2/actions/BannerSetNameAction.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../core/String.hpp" -#include "../drawing/Drawing.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../ui/UiContext.h" -#include "../windows/Intent.h" -#include "../world/Banner.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(BannerSetNameAction, GAME_COMMAND_SET_BANNER_NAME, GameActions::Result) -{ -private: - BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; - std::string _name; - -public: - BannerSetNameAction() = default; - BannerSetNameAction(BannerIndex bannerIndex, const std::string& name) - : _bannerIndex(bannerIndex) - , _name(name) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("id", _bannerIndex); - visitor.Visit("name", _name); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_bannerIndex) << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - if (_bannerIndex >= MAX_BANNERS) - { - log_warning("Invalid game command for setting banner name, banner id = %d", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto banner = GetBanner(_bannerIndex); - banner->text = _name; - - auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); - intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); - context_broadcast_intent(&intent); - - scrolling_text_invalidate(); - gfx_invalidate_screen(); - - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/BannerSetStyleAction.cpp b/src/openrct2/actions/BannerSetStyleAction.cpp new file mode 100644 index 0000000000..546812709e --- /dev/null +++ b/src/openrct2/actions/BannerSetStyleAction.cpp @@ -0,0 +1,142 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "BannerSetStyleAction.h" + +#include "../Context.h" +#include "../management/Finance.h" +#include "../util/Util.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "GameAction.h" + +void BannerSetStyleAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("id", _bannerIndex); + visitor.Visit("type", _type); + visitor.Visit("parameter", _parameter); +} + +void BannerSetStyleAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_type) << DS_TAG(_bannerIndex) << DS_TAG(_parameter); +} + +GameActions::Result::Ptr BannerSetStyleAction::Query() const +{ + auto res = MakeResult(); + + if (_bannerIndex >= MAX_BANNERS || _bannerIndex == BANNER_INDEX_NULL) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); + } + + auto banner = GetBanner(_bannerIndex); + + res->Expenditure = ExpenditureType::Landscaping; + auto location = banner->position.ToCoordsXY().ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + + TileElement* tileElement = banner_get_tile_element(_bannerIndex); + + if (tileElement == nullptr) + { + log_error("Could not find banner index = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + switch (_type) + { + case BannerSetStyleType::PrimaryColour: + if (_parameter > 31) + { + log_error("Invalid primary colour: colour = %u", _parameter); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + break; + + case BannerSetStyleType::TextColour: + if (_parameter > 13) + { + log_error("Invalid text colour: colour = %u", _parameter); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + break; + case BannerSetStyleType::NoEntry: + if (tileElement->AsBanner() == nullptr) + { + log_error("Tile element was not a banner."); + return MakeResult(GameActions::Status::Unknown, STR_NONE); + } + break; + default: + log_error("Invalid type: %u", _type); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return res; +} + +GameActions::Result::Ptr BannerSetStyleAction::Execute() const +{ + auto res = MakeResult(); + + auto banner = GetBanner(_bannerIndex); + + res->Expenditure = ExpenditureType::Landscaping; + auto location = banner->position.ToCoordsXY().ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + + TileElement* tileElement = banner_get_tile_element(_bannerIndex); + + if (tileElement == nullptr) + { + log_error("Could not find banner index = %u", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + switch (_type) + { + case BannerSetStyleType::PrimaryColour: + banner->colour = _parameter; + break; + case BannerSetStyleType::TextColour: + banner->text_colour = _parameter; + break; + case BannerSetStyleType::NoEntry: + { + BannerElement* bannerElement = tileElement->AsBanner(); + if (bannerElement == nullptr) + { + log_error("Tile element was not a banner."); + return MakeResult(GameActions::Status::Unknown, STR_NONE); + } + + banner->flags &= ~BANNER_FLAG_NO_ENTRY; + banner->flags |= (_parameter != 0) ? BANNER_FLAG_NO_ENTRY : 0; + uint8_t allowedEdges = 0xF; + if (banner->flags & BANNER_FLAG_NO_ENTRY) + { + allowedEdges &= ~(1 << bannerElement->GetPosition()); + } + bannerElement->SetAllowedEdges(allowedEdges); + break; + } + default: + log_error("Invalid type: %u", _type); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); + intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); + context_broadcast_intent(&intent); + + return res; +} diff --git a/src/openrct2/actions/BannerSetStyleAction.h b/src/openrct2/actions/BannerSetStyleAction.h new file mode 100644 index 0000000000..09b32422c9 --- /dev/null +++ b/src/openrct2/actions/BannerSetStyleAction.h @@ -0,0 +1,51 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +// There is also the BannerSetColourAction that sets primary colour but this action takes banner index rather than x, y, z, +// direction +enum class BannerSetStyleType : uint8_t +{ + PrimaryColour, + TextColour, + NoEntry, + Count +}; + +DEFINE_GAME_ACTION(BannerSetStyleAction, GAME_COMMAND_SET_BANNER_STYLE, GameActions::Result) +{ +private: + BannerSetStyleType _type{ BannerSetStyleType::Count }; + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; + uint8_t _parameter{}; + +public: + BannerSetStyleAction() = default; + + BannerSetStyleAction(BannerSetStyleType type, uint8_t bannerIndex, uint8_t parameter) + : _type(type) + , _bannerIndex(bannerIndex) + , _parameter(parameter) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/BannerSetStyleAction.hpp b/src/openrct2/actions/BannerSetStyleAction.hpp deleted file mode 100644 index 7103804e0c..0000000000 --- a/src/openrct2/actions/BannerSetStyleAction.hpp +++ /dev/null @@ -1,175 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../management/Finance.h" -#include "../util/Util.h" -#include "../windows/Intent.h" -#include "../world/Banner.h" -#include "GameAction.h" - -// There is also the BannerSetColourAction that sets primary colour but this action takes banner index rather than x, y, z, -// direction -enum class BannerSetStyleType : uint8_t -{ - PrimaryColour, - TextColour, - NoEntry, - Count -}; - -DEFINE_GAME_ACTION(BannerSetStyleAction, GAME_COMMAND_SET_BANNER_STYLE, GameActions::Result) -{ -private: - BannerSetStyleType _type{ BannerSetStyleType::Count }; - BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; - uint8_t _parameter{}; - -public: - BannerSetStyleAction() = default; - - BannerSetStyleAction(BannerSetStyleType type, uint8_t bannerIndex, uint8_t parameter) - : _type(type) - , _bannerIndex(bannerIndex) - , _parameter(parameter) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("id", _bannerIndex); - visitor.Visit("type", _type); - visitor.Visit("parameter", _parameter); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_type) << DS_TAG(_bannerIndex) << DS_TAG(_parameter); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - - if (_bannerIndex >= MAX_BANNERS || _bannerIndex == BANNER_INDEX_NULL) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); - } - - auto banner = GetBanner(_bannerIndex); - - res->Expenditure = ExpenditureType::Landscaping; - auto location = banner->position.ToCoordsXY().ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - - TileElement* tileElement = banner_get_tile_element(_bannerIndex); - - if (tileElement == nullptr) - { - log_error("Could not find banner index = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - switch (_type) - { - case BannerSetStyleType::PrimaryColour: - if (_parameter > 31) - { - log_error("Invalid primary colour: colour = %u", _parameter); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - break; - - case BannerSetStyleType::TextColour: - if (_parameter > 13) - { - log_error("Invalid text colour: colour = %u", _parameter); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - break; - case BannerSetStyleType::NoEntry: - if (tileElement->AsBanner() == nullptr) - { - log_error("Tile element was not a banner."); - return MakeResult(GameActions::Status::Unknown, STR_NONE); - } - break; - default: - log_error("Invalid type: %u", _type); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - - auto banner = GetBanner(_bannerIndex); - - res->Expenditure = ExpenditureType::Landscaping; - auto location = banner->position.ToCoordsXY().ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - - TileElement* tileElement = banner_get_tile_element(_bannerIndex); - - if (tileElement == nullptr) - { - log_error("Could not find banner index = %u", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - switch (_type) - { - case BannerSetStyleType::PrimaryColour: - banner->colour = _parameter; - break; - case BannerSetStyleType::TextColour: - banner->text_colour = _parameter; - break; - case BannerSetStyleType::NoEntry: - { - BannerElement* bannerElement = tileElement->AsBanner(); - if (bannerElement == nullptr) - { - log_error("Tile element was not a banner."); - return MakeResult(GameActions::Status::Unknown, STR_NONE); - } - - banner->flags &= ~BANNER_FLAG_NO_ENTRY; - banner->flags |= (_parameter != 0) ? BANNER_FLAG_NO_ENTRY : 0; - uint8_t allowedEdges = 0xF; - if (banner->flags & BANNER_FLAG_NO_ENTRY) - { - allowedEdges &= ~(1 << bannerElement->GetPosition()); - } - bannerElement->SetAllowedEdges(allowedEdges); - break; - } - default: - log_error("Invalid type: %u", _type); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); - intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); - context_broadcast_intent(&intent); - - return res; - } -}; diff --git a/src/openrct2/actions/ClearAction.cpp b/src/openrct2/actions/ClearAction.cpp new file mode 100644 index 0000000000..a6c6148861 --- /dev/null +++ b/src/openrct2/actions/ClearAction.cpp @@ -0,0 +1,202 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ClearAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/LargeScenery.h" +#include "../world/Location.hpp" +#include "../world/Map.h" +#include "FootpathRemoveAction.h" +#include "LargeSceneryRemoveAction.h" +#include "SmallSceneryRemoveAction.h" +#include "WallRemoveAction.h" + +#include + +void ClearAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range) << DS_TAG(_itemsToClear); +} + +GameActions::Result::Ptr ClearAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr ClearAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr ClearAction::CreateResult() const +{ + auto result = MakeResult(); + result->ErrorTitle = STR_UNABLE_TO_REMOVE_ALL_SCENERY_FROM_HERE; + result->Expenditure = ExpenditureType::Landscaping; + + auto x = (_range.GetLeft() + _range.GetRight()) / 2 + 16; + auto y = (_range.GetTop() + _range.GetBottom()) / 2 + 16; + auto z = tile_element_height({ x, y }); + result->Position = CoordsXYZ(x, y, z); + + return result; +} + +GameActions::Result::Ptr ClearAction::QueryExecute(bool executing) const +{ + auto result = CreateResult(); + + auto noValidTiles = true; + auto error = GameActions::Status::Ok; + rct_string_id errorMessage = STR_NONE; + money32 totalCost = 0; + + auto x0 = std::max(_range.GetLeft(), 32); + auto y0 = std::max(_range.GetTop(), 32); + auto x1 = std::min(_range.GetRight(), static_cast(gMapSizeMaxXY)); + auto y1 = std::min(_range.GetBottom(), static_cast(gMapSizeMaxXY)); + + for (int32_t y = y0; y <= y1; y += COORDS_XY_STEP) + { + for (int32_t x = x0; x <= x1; x += COORDS_XY_STEP) + { + if (LocationValid({ x, y }) && MapCanClearAt({ x, y })) + { + auto cost = ClearSceneryFromTile({ x, y }, executing); + if (cost != MONEY32_UNDEFINED) + { + noValidTiles = false; + totalCost += cost; + } + } + else + { + error = GameActions::Status::NotOwned; + errorMessage = STR_LAND_NOT_OWNED_BY_PARK; + } + } + } + + if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_LARGE) + { + ResetClearLargeSceneryFlag(); + } + + if (noValidTiles) + { + result->Error = error; + result->ErrorMessage = errorMessage; + } + + result->Cost = totalCost; + return result; +} + +money32 ClearAction::ClearSceneryFromTile(const CoordsXY& tilePos, bool executing) const +{ + // Pass down all flags. + TileElement* tileElement = nullptr; + money32 totalCost = 0; + bool tileEdited; + do + { + tileEdited = false; + tileElement = map_get_first_element_at(tilePos); + if (tileElement == nullptr) + return totalCost; + do + { + if (tileElement->IsGhost()) + continue; + + auto type = tileElement->GetType(); + switch (type) + { + case TILE_ELEMENT_TYPE_PATH: + if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_FOOTPATH) + { + auto footpathRemoveAction = FootpathRemoveAction({ tilePos, tileElement->GetBaseZ() }); + footpathRemoveAction.SetFlags(GetFlags()); + + auto res = executing ? GameActions::ExecuteNested(&footpathRemoveAction) + : GameActions::QueryNested(&footpathRemoveAction); + + if (res->Error == GameActions::Status::Ok) + { + totalCost += res->Cost; + tileEdited = executing; + } + } + break; + case TILE_ELEMENT_TYPE_SMALL_SCENERY: + if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_SMALL) + { + auto removeSceneryAction = SmallSceneryRemoveAction( + { tilePos, tileElement->GetBaseZ() }, tileElement->AsSmallScenery()->GetSceneryQuadrant(), + tileElement->AsSmallScenery()->GetEntryIndex()); + removeSceneryAction.SetFlags(GetFlags()); + + auto res = executing ? GameActions::ExecuteNested(&removeSceneryAction) + : GameActions::QueryNested(&removeSceneryAction); + + if (res->Error == GameActions::Status::Ok) + { + totalCost += res->Cost; + tileEdited = executing; + } + } + break; + case TILE_ELEMENT_TYPE_WALL: + if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_SMALL) + { + CoordsXYZD wallLocation = { tilePos, tileElement->GetBaseZ(), tileElement->GetDirection() }; + auto wallRemoveAction = WallRemoveAction(wallLocation); + wallRemoveAction.SetFlags(GetFlags()); + + auto res = executing ? GameActions::ExecuteNested(&wallRemoveAction) + : GameActions::QueryNested(&wallRemoveAction); + + if (res->Error == GameActions::Status::Ok) + { + totalCost += res->Cost; + tileEdited = executing; + } + } + break; + case TILE_ELEMENT_TYPE_LARGE_SCENERY: + if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_LARGE) + { + auto removeSceneryAction = LargeSceneryRemoveAction( + { tilePos, tileElement->GetBaseZ(), tileElement->GetDirection() }, + tileElement->AsLargeScenery()->GetSequenceIndex()); + removeSceneryAction.SetFlags(GetFlags() | GAME_COMMAND_FLAG_PATH_SCENERY); + + auto res = executing ? GameActions::ExecuteNested(&removeSceneryAction) + : GameActions::QueryNested(&removeSceneryAction); + + if (res->Error == GameActions::Status::Ok) + { + totalCost += res->Cost; + tileEdited = executing; + } + } + break; + } + } while (!tileEdited && !(tileElement++)->IsLastForTile()); + } while (tileEdited); + + return totalCost; +} diff --git a/src/openrct2/actions/ClearAction.h b/src/openrct2/actions/ClearAction.h new file mode 100644 index 0000000000..090f6d4daa --- /dev/null +++ b/src/openrct2/actions/ClearAction.h @@ -0,0 +1,80 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "GameAction.h" + +using namespace OpenRCT2; + +using ClearableItems = uint8_t; + +namespace CLEARABLE_ITEMS +{ + constexpr ClearableItems SCENERY_SMALL = 1 << 0; + constexpr ClearableItems SCENERY_LARGE = 1 << 1; + constexpr ClearableItems SCENERY_FOOTPATH = 1 << 2; +} // namespace CLEARABLE_ITEMS + +DEFINE_GAME_ACTION(ClearAction, GAME_COMMAND_CLEAR_SCENERY, GameActions::Result) +{ +private: + MapRange _range; + ClearableItems _itemsToClear{}; + +public: + ClearAction() = default; + ClearAction(MapRange range, ClearableItems itemsToClear) + : _range(range) + , _itemsToClear(itemsToClear) + { + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr CreateResult() const; + GameActions::Result::Ptr QueryExecute(bool executing) const; + money32 ClearSceneryFromTile(const CoordsXY& tilePos, bool executing) const; + + /** + * Function to clear the flag that is set to prevent cost duplication + * when using the clear scenery tool with large scenery. + */ + static void ResetClearLargeSceneryFlag() + { + // TODO: Improve efficiency of this + for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) + { + for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) + { + auto tileElement = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() == TILE_ELEMENT_TYPE_LARGE_SCENERY) + { + tileElement->AsLargeScenery()->SetIsAccounted(false); + } + } while (!(tileElement++)->IsLastForTile()); + } + } + } + + static bool MapCanClearAt(const CoordsXY& location) + { + return (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode + || map_is_location_owned_or_has_rights(location); + } +}; diff --git a/src/openrct2/actions/ClearAction.hpp b/src/openrct2/actions/ClearAction.hpp deleted file mode 100644 index 4e91fe58d4..0000000000 --- a/src/openrct2/actions/ClearAction.hpp +++ /dev/null @@ -1,261 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/LargeScenery.h" -#include "../world/Location.hpp" -#include "../world/Map.h" -#include "FootpathRemoveAction.hpp" -#include "GameAction.h" -#include "LargeSceneryRemoveAction.hpp" -#include "SmallSceneryRemoveAction.hpp" -#include "WallRemoveAction.hpp" - -#include - -using namespace OpenRCT2; - -using ClearableItems = uint8_t; - -namespace CLEARABLE_ITEMS -{ - constexpr ClearableItems SCENERY_SMALL = 1 << 0; - constexpr ClearableItems SCENERY_LARGE = 1 << 1; - constexpr ClearableItems SCENERY_FOOTPATH = 1 << 2; -} // namespace CLEARABLE_ITEMS - -DEFINE_GAME_ACTION(ClearAction, GAME_COMMAND_CLEAR_SCENERY, GameActions::Result) -{ -private: - MapRange _range; - ClearableItems _itemsToClear{}; - -public: - ClearAction() = default; - ClearAction(MapRange range, ClearableItems itemsToClear) - : _range(range) - , _itemsToClear(itemsToClear) - { - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range) << DS_TAG(_itemsToClear); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr CreateResult() const - { - auto result = MakeResult(); - result->ErrorTitle = STR_UNABLE_TO_REMOVE_ALL_SCENERY_FROM_HERE; - result->Expenditure = ExpenditureType::Landscaping; - - auto x = (_range.GetLeft() + _range.GetRight()) / 2 + 16; - auto y = (_range.GetTop() + _range.GetBottom()) / 2 + 16; - auto z = tile_element_height({ x, y }); - result->Position = CoordsXYZ(x, y, z); - - return result; - } - - GameActions::Result::Ptr QueryExecute(bool executing) const - { - auto result = CreateResult(); - - auto noValidTiles = true; - auto error = GameActions::Status::Ok; - rct_string_id errorMessage = STR_NONE; - money32 totalCost = 0; - - auto x0 = std::max(_range.GetLeft(), 32); - auto y0 = std::max(_range.GetTop(), 32); - auto x1 = std::min(_range.GetRight(), static_cast(gMapSizeMaxXY)); - auto y1 = std::min(_range.GetBottom(), static_cast(gMapSizeMaxXY)); - - for (int32_t y = y0; y <= y1; y += COORDS_XY_STEP) - { - for (int32_t x = x0; x <= x1; x += COORDS_XY_STEP) - { - if (LocationValid({ x, y }) && MapCanClearAt({ x, y })) - { - auto cost = ClearSceneryFromTile({ x, y }, executing); - if (cost != MONEY32_UNDEFINED) - { - noValidTiles = false; - totalCost += cost; - } - } - else - { - error = GameActions::Status::NotOwned; - errorMessage = STR_LAND_NOT_OWNED_BY_PARK; - } - } - } - - if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_LARGE) - { - ResetClearLargeSceneryFlag(); - } - - if (noValidTiles) - { - result->Error = error; - result->ErrorMessage = errorMessage; - } - - result->Cost = totalCost; - return result; - } - - money32 ClearSceneryFromTile(const CoordsXY& tilePos, bool executing) const - { - // Pass down all flags. - TileElement* tileElement = nullptr; - money32 totalCost = 0; - bool tileEdited; - do - { - tileEdited = false; - tileElement = map_get_first_element_at(tilePos); - if (tileElement == nullptr) - return totalCost; - do - { - if (tileElement->IsGhost()) - continue; - - auto type = tileElement->GetType(); - switch (type) - { - case TILE_ELEMENT_TYPE_PATH: - if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_FOOTPATH) - { - auto footpathRemoveAction = FootpathRemoveAction({ tilePos, tileElement->GetBaseZ() }); - footpathRemoveAction.SetFlags(GetFlags()); - - auto res = executing ? GameActions::ExecuteNested(&footpathRemoveAction) - : GameActions::QueryNested(&footpathRemoveAction); - - if (res->Error == GameActions::Status::Ok) - { - totalCost += res->Cost; - tileEdited = executing; - } - } - break; - case TILE_ELEMENT_TYPE_SMALL_SCENERY: - if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_SMALL) - { - auto removeSceneryAction = SmallSceneryRemoveAction( - { tilePos, tileElement->GetBaseZ() }, tileElement->AsSmallScenery()->GetSceneryQuadrant(), - tileElement->AsSmallScenery()->GetEntryIndex()); - removeSceneryAction.SetFlags(GetFlags()); - - auto res = executing ? GameActions::ExecuteNested(&removeSceneryAction) - : GameActions::QueryNested(&removeSceneryAction); - - if (res->Error == GameActions::Status::Ok) - { - totalCost += res->Cost; - tileEdited = executing; - } - } - break; - case TILE_ELEMENT_TYPE_WALL: - if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_SMALL) - { - CoordsXYZD wallLocation = { tilePos, tileElement->GetBaseZ(), tileElement->GetDirection() }; - auto wallRemoveAction = WallRemoveAction(wallLocation); - wallRemoveAction.SetFlags(GetFlags()); - - auto res = executing ? GameActions::ExecuteNested(&wallRemoveAction) - : GameActions::QueryNested(&wallRemoveAction); - - if (res->Error == GameActions::Status::Ok) - { - totalCost += res->Cost; - tileEdited = executing; - } - } - break; - case TILE_ELEMENT_TYPE_LARGE_SCENERY: - if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_LARGE) - { - auto removeSceneryAction = LargeSceneryRemoveAction( - { tilePos, tileElement->GetBaseZ(), tileElement->GetDirection() }, - tileElement->AsLargeScenery()->GetSequenceIndex()); - removeSceneryAction.SetFlags(GetFlags() | GAME_COMMAND_FLAG_PATH_SCENERY); - - auto res = executing ? GameActions::ExecuteNested(&removeSceneryAction) - : GameActions::QueryNested(&removeSceneryAction); - - if (res->Error == GameActions::Status::Ok) - { - totalCost += res->Cost; - tileEdited = executing; - } - } - break; - } - } while (!tileEdited && !(tileElement++)->IsLastForTile()); - } while (tileEdited); - - return totalCost; - } - - /** - * Function to clear the flag that is set to prevent cost duplication - * when using the clear scenery tool with large scenery. - */ - static void ResetClearLargeSceneryFlag() - { - // TODO: Improve efficiency of this - for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) - { - for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) - { - auto tileElement = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() == TILE_ELEMENT_TYPE_LARGE_SCENERY) - { - tileElement->AsLargeScenery()->SetIsAccounted(false); - } - } while (!(tileElement++)->IsLastForTile()); - } - } - } - - static bool MapCanClearAt(const CoordsXY& location) - { - return (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode - || map_is_location_owned_or_has_rights(location); - } -}; diff --git a/src/openrct2/actions/ClimateSetAction.cpp b/src/openrct2/actions/ClimateSetAction.cpp new file mode 100644 index 0000000000..90f90a79e6 --- /dev/null +++ b/src/openrct2/actions/ClimateSetAction.cpp @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ClimateSetAction.h" + +void ClimateSetAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("climate", _climate); +} + +void ClimateSetAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_climate); +} + +GameActions::Result::Ptr ClimateSetAction::Query() const +{ + if (_climate >= ClimateType::Count) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_INVALID_CLIMATE_ID, STR_NONE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr ClimateSetAction::Execute() const +{ + gClimate = ClimateType{ _climate }; + + gfx_invalidate_screen(); + + return std::make_unique(); +} diff --git a/src/openrct2/actions/ClimateSetAction.hpp b/src/openrct2/actions/ClimateSetAction.h similarity index 51% rename from src/openrct2/actions/ClimateSetAction.hpp rename to src/openrct2/actions/ClimateSetAction.h index bcee196ad4..470ffd2e42 100644 --- a/src/openrct2/actions/ClimateSetAction.hpp +++ b/src/openrct2/actions/ClimateSetAction.h @@ -23,41 +23,14 @@ public: : _climate(climate) { } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("climate", _climate); - } + void AcceptParameters(GameActionParameterVisitor & visitor) override; uint16_t GetActionFlags() const override { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + return GameAction::GetActionFlags(); } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_climate); - } - - GameActions::Result::Ptr Query() const override - { - if (_climate >= ClimateType::Count) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_INVALID_CLIMATE_ID, STR_NONE); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - gClimate = ClimateType{ _climate }; - - gfx_invalidate_screen(); - - return std::make_unique(); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/CustomAction.cpp b/src/openrct2/actions/CustomAction.cpp new file mode 100644 index 0000000000..b0c8e142af --- /dev/null +++ b/src/openrct2/actions/CustomAction.cpp @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#ifdef ENABLE_SCRIPTING +# include "CustomAction.h" + +# include "../Context.h" +# include "../scripting/ScriptEngine.h" + +void CustomAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_id) << DS_TAG(_json); +} + +GameActions::Result::Ptr CustomAction::Query() const +{ + auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine(); + return scriptingEngine.QueryOrExecuteCustomGameAction(_id, _json, false); +} + +GameActions::Result::Ptr CustomAction::Execute() const +{ + auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine(); + return scriptingEngine.QueryOrExecuteCustomGameAction(_id, _json, true); +} + +#endif diff --git a/src/openrct2/actions/CustomAction.hpp b/src/openrct2/actions/CustomAction.h similarity index 61% rename from src/openrct2/actions/CustomAction.hpp rename to src/openrct2/actions/CustomAction.h index 0ae306b047..bb51acce21 100644 --- a/src/openrct2/actions/CustomAction.hpp +++ b/src/openrct2/actions/CustomAction.h @@ -11,8 +11,6 @@ #ifdef ENABLE_SCRIPTING -# include "../Context.h" -# include "../scripting/ScriptEngine.h" # include "GameAction.h" DEFINE_GAME_ACTION(CustomAction, GAME_COMMAND_CUSTOM, GameActions::Result) @@ -44,23 +42,9 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_id) << DS_TAG(_json); - } - - GameActions::Result::Ptr Query() const override - { - auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine(); - return scriptingEngine.QueryOrExecuteCustomGameAction(_id, _json, false); - } - - GameActions::Result::Ptr Execute() const override - { - auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine(); - return scriptingEngine.QueryOrExecuteCustomGameAction(_id, _json, true); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; #endif diff --git a/src/openrct2/actions/FootpathAdditionPlaceAction.cpp b/src/openrct2/actions/FootpathAdditionPlaceAction.cpp new file mode 100644 index 0000000000..5cb7056ca1 --- /dev/null +++ b/src/openrct2/actions/FootpathAdditionPlaceAction.cpp @@ -0,0 +1,191 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "FootpathAdditionPlaceAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Wall.h" + +void FootpathAdditionPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _pathItemType); +} + +void FootpathAdditionPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_pathItemType); +} + +GameActions::Result::Ptr FootpathAdditionPlaceAction::Query() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc; + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_OFF_EDGE_OF_MAP); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (_loc.z < FootpathMinHeight) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_LOW); + } + + if (_loc.z > FootpathMaxHeight) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_HIGH); + } + + auto tileElement = map_get_footpath_element(_loc); + if (tileElement == nullptr) + { + log_error("Could not find path element."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + auto pathElement = tileElement->AsPath(); + if (pathElement->IsLevelCrossing(_loc)) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, + STR_CANNOT_BUILD_PATH_ADDITIONS_ON_LEVEL_CROSSINGS); + } + + // No change + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAddition() == _pathItemType && !(pathElement->IsBroken())) + { + return res; + } + + if (_pathItemType != 0) + { + rct_scenery_entry* sceneryEntry = get_footpath_item_entry(_pathItemType - 1); + if (sceneryEntry == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + uint16_t sceneryFlags = sceneryEntry->path_bit.flags; + + if ((sceneryFlags & PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE) && pathElement->IsSloped()) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH); + } + + if ((sceneryFlags & PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE) && pathElement->IsQueue()) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA); + } + + if (!(sceneryFlags & (PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER | PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW)) + && (pathElement->GetEdges()) == 0x0F) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + if ((sceneryFlags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) && !pathElement->IsQueue()) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA); + } + + res->Cost = sceneryEntry->path_bit.price; + } + + // Should place a ghost? + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + // Check if there is something on the path already + if (pathElement->HasAddition()) + { + return MakeResult(GameActions::Status::ItemAlreadyPlaced, STR_CANT_POSITION_THIS_HERE); + } + } + return res; +} + +GameActions::Result::Ptr FootpathAdditionPlaceAction::Execute() const +{ + auto res = MakeResult(); + res->Position = _loc; + res->Expenditure = ExpenditureType::Landscaping; + + auto tileElement = map_get_footpath_element(_loc); + auto pathElement = tileElement->AsPath(); + + if (pathElement == nullptr) + { + log_error("Could not find path element."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + // No change + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAddition() == _pathItemType && !(pathElement->IsBroken()) + && !pathElement->AdditionIsGhost()) + { + return res; + } + + if (_pathItemType != 0) + { + rct_scenery_entry* sceneryEntry = get_footpath_item_entry(_pathItemType - 1); + if (sceneryEntry == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); + } + + res->Cost = sceneryEntry->path_bit.price; + } + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + pathElement->SetAdditionIsGhost(true); + } + else + { + footpath_interrupt_peeps(_loc); + } + + if ((_pathItemType != 0 && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + || (_pathItemType == 0 && pathElement->AdditionIsGhost())) + { + pathElement->SetAdditionIsGhost(false); + } + + pathElement->SetAddition(_pathItemType); + pathElement->SetIsBroken(false); + if (_pathItemType != 0) + { + rct_scenery_entry* scenery_entry = get_footpath_item_entry(_pathItemType - 1); + if (scenery_entry != nullptr && scenery_entry->path_bit.flags & PATH_BIT_FLAG_IS_BIN) + { + pathElement->SetAdditionStatus(255); + } + } + map_invalidate_tile_full(_loc); + return res; +} diff --git a/src/openrct2/actions/FootpathAdditionPlaceAction.h b/src/openrct2/actions/FootpathAdditionPlaceAction.h new file mode 100644 index 0000000000..7a76e9efc6 --- /dev/null +++ b/src/openrct2/actions/FootpathAdditionPlaceAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(FootpathAdditionPlaceAction, GAME_COMMAND_PLACE_FOOTPATH_ADDITION, GameActions::Result) +{ +private: + CoordsXYZ _loc; + ObjectEntryIndex _pathItemType{}; + +public: + FootpathAdditionPlaceAction() = default; + FootpathAdditionPlaceAction(const CoordsXYZ& loc, ObjectEntryIndex pathItemType) + : _loc(loc) + , _pathItemType(pathItemType) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/FootpathAdditionPlaceAction.hpp b/src/openrct2/actions/FootpathAdditionPlaceAction.hpp deleted file mode 100644 index c5c2affc97..0000000000 --- a/src/openrct2/actions/FootpathAdditionPlaceAction.hpp +++ /dev/null @@ -1,216 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Wall.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(FootpathAdditionPlaceAction, GAME_COMMAND_PLACE_FOOTPATH_ADDITION, GameActions::Result) -{ -private: - CoordsXYZ _loc; - ObjectEntryIndex _pathItemType{}; - -public: - FootpathAdditionPlaceAction() = default; - FootpathAdditionPlaceAction(const CoordsXYZ& loc, ObjectEntryIndex pathItemType) - : _loc(loc) - , _pathItemType(pathItemType) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _pathItemType); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_pathItemType); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc; - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_OFF_EDGE_OF_MAP); - } - - if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (_loc.z < FootpathMinHeight) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_LOW); - } - - if (_loc.z > FootpathMaxHeight) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_HIGH); - } - - auto tileElement = map_get_footpath_element(_loc); - if (tileElement == nullptr) - { - log_error("Could not find path element."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - auto pathElement = tileElement->AsPath(); - if (pathElement->IsLevelCrossing(_loc)) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, - STR_CANNOT_BUILD_PATH_ADDITIONS_ON_LEVEL_CROSSINGS); - } - - // No change - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAddition() == _pathItemType - && !(pathElement->IsBroken())) - { - return res; - } - - if (_pathItemType != 0) - { - rct_scenery_entry* sceneryEntry = get_footpath_item_entry(_pathItemType - 1); - if (sceneryEntry == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - uint16_t sceneryFlags = sceneryEntry->path_bit.flags; - - if ((sceneryFlags & PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE) && pathElement->IsSloped()) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, - STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH); - } - - if ((sceneryFlags & PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE) && pathElement->IsQueue()) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, - STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA); - } - - if (!(sceneryFlags & (PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER | PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW)) - && (pathElement->GetEdges()) == 0x0F) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - if ((sceneryFlags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) && !pathElement->IsQueue()) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, - STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA); - } - - res->Cost = sceneryEntry->path_bit.price; - } - - // Should place a ghost? - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - // Check if there is something on the path already - if (pathElement->HasAddition()) - { - return MakeResult(GameActions::Status::ItemAlreadyPlaced, STR_CANT_POSITION_THIS_HERE); - } - } - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Position = _loc; - res->Expenditure = ExpenditureType::Landscaping; - - auto tileElement = map_get_footpath_element(_loc); - auto pathElement = tileElement->AsPath(); - - if (pathElement == nullptr) - { - log_error("Could not find path element."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - // No change - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAddition() == _pathItemType && !(pathElement->IsBroken()) - && !pathElement->AdditionIsGhost()) - { - return res; - } - - if (_pathItemType != 0) - { - rct_scenery_entry* sceneryEntry = get_footpath_item_entry(_pathItemType - 1); - if (sceneryEntry == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); - } - - res->Cost = sceneryEntry->path_bit.price; - } - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - pathElement->SetAdditionIsGhost(true); - } - else - { - footpath_interrupt_peeps(_loc); - } - - if ((_pathItemType != 0 && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - || (_pathItemType == 0 && pathElement->AdditionIsGhost())) - { - pathElement->SetAdditionIsGhost(false); - } - - pathElement->SetAddition(_pathItemType); - pathElement->SetIsBroken(false); - if (_pathItemType != 0) - { - rct_scenery_entry* scenery_entry = get_footpath_item_entry(_pathItemType - 1); - if (scenery_entry != nullptr && scenery_entry->path_bit.flags & PATH_BIT_FLAG_IS_BIN) - { - pathElement->SetAdditionStatus(255); - } - } - map_invalidate_tile_full(_loc); - return res; - } -}; diff --git a/src/openrct2/actions/FootpathAdditionRemoveAction.cpp b/src/openrct2/actions/FootpathAdditionRemoveAction.cpp new file mode 100644 index 0000000000..9e7c92b2dc --- /dev/null +++ b/src/openrct2/actions/FootpathAdditionRemoveAction.cpp @@ -0,0 +1,105 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "FootpathAdditionRemoveAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Wall.h" + +void FootpathAdditionRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); +} + +void FootpathAdditionRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr FootpathAdditionRemoveAction::Query() const +{ + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_OFF_EDGE_OF_MAP); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (_loc.z < FootpathMinHeight) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_LOW); + } + + if (_loc.z > FootpathMaxHeight) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_HIGH); + } + + auto tileElement = map_get_footpath_element(_loc); + if (tileElement == nullptr) + { + log_warning("Could not find path element."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + auto pathElement = tileElement->AsPath(); + if (pathElement == nullptr) + { + log_warning("Could not find path element."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + if (!pathElement->AdditionIsGhost() && (GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + log_warning("Tried to remove non ghost during ghost removal."); + return MakeResult(GameActions::Status::Disallowed, STR_CANT_REMOVE_THIS); + } + auto res = MakeResult(); + res->Position = _loc; + res->Cost = MONEY(0, 0); + return res; +} + +GameActions::Result::Ptr FootpathAdditionRemoveAction::Execute() const +{ + auto tileElement = map_get_footpath_element(_loc); + auto pathElement = tileElement->AsPath(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_interrupt_peeps(_loc); + } + + if (pathElement == nullptr) + { + log_error("Could not find path element."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + pathElement->SetAddition(0); + map_invalidate_tile_full(_loc); + + auto res = MakeResult(); + res->Position = _loc; + res->Cost = MONEY(0, 0); + return res; +} diff --git a/src/openrct2/actions/FootpathAdditionRemoveAction.h b/src/openrct2/actions/FootpathAdditionRemoveAction.h new file mode 100644 index 0000000000..9ba064aa85 --- /dev/null +++ b/src/openrct2/actions/FootpathAdditionRemoveAction.h @@ -0,0 +1,35 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(FootpathAdditionRemoveAction, GAME_COMMAND_REMOVE_FOOTPATH_ADDITION, GameActions::Result) +{ +private: + CoordsXYZ _loc; + +public: + FootpathAdditionRemoveAction() = default; + FootpathAdditionRemoveAction(const CoordsXYZ& loc) + : _loc(loc) + { + } + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/FootpathAdditionRemoveAction.hpp b/src/openrct2/actions/FootpathAdditionRemoveAction.hpp deleted file mode 100644 index 889f1867f9..0000000000 --- a/src/openrct2/actions/FootpathAdditionRemoveAction.hpp +++ /dev/null @@ -1,125 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Park.h" -#include "../world/Wall.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(FootpathAdditionRemoveAction, GAME_COMMAND_REMOVE_FOOTPATH_ADDITION, GameActions::Result) -{ -private: - CoordsXYZ _loc; - -public: - FootpathAdditionRemoveAction() = default; - - FootpathAdditionRemoveAction(const CoordsXYZ& loc) - : _loc(loc) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_OFF_EDGE_OF_MAP); - } - - if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (_loc.z < FootpathMinHeight) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_LOW); - } - - if (_loc.z > FootpathMaxHeight) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_HIGH); - } - - auto tileElement = map_get_footpath_element(_loc); - if (tileElement == nullptr) - { - log_warning("Could not find path element."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - auto pathElement = tileElement->AsPath(); - if (pathElement == nullptr) - { - log_warning("Could not find path element."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - if (!pathElement->AdditionIsGhost() && (GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - log_warning("Tried to remove non ghost during ghost removal."); - return MakeResult(GameActions::Status::Disallowed, STR_CANT_REMOVE_THIS); - } - auto res = MakeResult(); - res->Position = _loc; - res->Cost = MONEY(0, 0); - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto tileElement = map_get_footpath_element(_loc); - auto pathElement = tileElement->AsPath(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_interrupt_peeps(_loc); - } - - if (pathElement == nullptr) - { - log_error("Could not find path element."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - pathElement->SetAddition(0); - map_invalidate_tile_full(_loc); - - auto res = MakeResult(); - res->Position = _loc; - res->Cost = MONEY(0, 0); - return res; - } -}; diff --git a/src/openrct2/actions/FootpathPlaceAction.cpp b/src/openrct2/actions/FootpathPlaceAction.cpp new file mode 100644 index 0000000000..79a22e4801 --- /dev/null +++ b/src/openrct2/actions/FootpathPlaceAction.cpp @@ -0,0 +1,450 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "FootpathPlaceAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Surface.h" +#include "../world/Wall.h" + +void FootpathPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _type); + visitor.Visit("direction", _direction); + visitor.Visit("slope", _slope); +} + +void FootpathPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_direction); +} + +GameActions::Result::Ptr FootpathPlaceAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc.ToTileCentre(); + + gFootpathGroundFlags = 0; + + if (!LocationValid(_loc) || map_is_edge(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_OFF_EDGE_OF_MAP); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (_slope & SLOPE_IS_IRREGULAR_FLAG) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_SLOPE_UNSUITABLE); + } + + if (_loc.z < FootpathMinHeight) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_LOW); + } + + if (_loc.z > FootpathMaxHeight) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_HIGH); + } + + if (_direction != INVALID_DIRECTION && !direction_valid(_direction)) + { + log_error("Direction invalid. direction = %u", _direction); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); + } + + footpath_provisional_remove(); + auto tileElement = map_get_footpath_element_slope(_loc, _slope); + if (tileElement == nullptr) + { + return ElementInsertQuery(std::move(res)); + } + else + { + return ElementUpdateQuery(tileElement, std::move(res)); + } +} + +GameActions::Result::Ptr FootpathPlaceAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc.ToTileCentre(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_interrupt_peeps(_loc); + } + + gFootpathGroundFlags = 0; + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + if (_direction != INVALID_DIRECTION && !gCheatsDisableClearanceChecks) + { + // It is possible, let's remove walls between the old and new piece of path + auto zLow = _loc.z; + auto zHigh = zLow + PATH_CLEARANCE; + wall_remove_intersecting_walls( + { _loc, zLow, zHigh + ((_slope & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) ? 16 : 0) }, + direction_reverse(_direction)); + wall_remove_intersecting_walls( + { _loc.x - CoordsDirectionDelta[_direction].x, _loc.y - CoordsDirectionDelta[_direction].y, zLow, zHigh }, + _direction); + } + } + + auto tileElement = map_get_footpath_element_slope(_loc, _slope); + if (tileElement == nullptr) + { + return ElementInsertExecute(std::move(res)); + } + else + { + return ElementUpdateExecute(tileElement, std::move(res)); + } +} + +GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateQuery(PathElement* pathElement, GameActions::Result::Ptr res) const +{ + const int32_t newFootpathType = (_type & (FOOTPATH_PROPERTIES_TYPE_MASK >> 4)); + const bool newPathIsQueue = ((_type >> 7) == 1); + if (pathElement->GetSurfaceEntryIndex() != newFootpathType || pathElement->IsQueue() != newPathIsQueue) + { + res->Cost += MONEY(6, 00); + } + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST && !pathElement->IsGhost()) + { + return MakeResult(GameActions::Status::Unknown, STR_CANT_BUILD_FOOTPATH_HERE); + } + return res; +} + +GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateExecute(PathElement* pathElement, GameActions::Result::Ptr res) const +{ + const int32_t newFootpathType = (_type & (FOOTPATH_PROPERTIES_TYPE_MASK >> 4)); + const bool newPathIsQueue = ((_type >> 7) == 1); + if (pathElement->GetSurfaceEntryIndex() != newFootpathType || pathElement->IsQueue() != newPathIsQueue) + { + res->Cost += MONEY(6, 00); + } + + footpath_queue_chain_reset(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) + { + footpath_remove_edges_at(_loc, reinterpret_cast(pathElement)); + } + + pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); + bool isQueue = _type & FOOTPATH_ELEMENT_INSERT_QUEUE; + pathElement->SetIsQueue(isQueue); + + rct_scenery_entry* elem = pathElement->GetAdditionEntry(); + if (elem != nullptr) + { + if (isQueue) + { + // remove any addition that isn't a TV or a lamp + if ((elem->path_bit.flags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) == 0 && (elem->path_bit.flags & PATH_BIT_FLAG_LAMP) == 0) + { + pathElement->SetIsBroken(false); + pathElement->SetAddition(0); + } + } + else + { + // remove all TVs + if ((elem->path_bit.flags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) != 0) + { + pathElement->SetIsBroken(false); + pathElement->SetAddition(0); + } + } + } + + RemoveIntersectingWalls(pathElement); + return res; +} + +GameActions::Result::Ptr FootpathPlaceAction::ElementInsertQuery(GameActions::Result::Ptr res) const +{ + bool entrancePath = false, entranceIsSamePath = false; + + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_BUILD_FOOTPATH_HERE); + } + + res->Cost = MONEY(12, 00); + + QuarterTile quarterTile{ 0b1111, 0 }; + auto zLow = _loc.z; + auto zHigh = zLow + PATH_CLEARANCE; + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); + zHigh += PATH_HEIGHT_STEP; + } + + auto entranceElement = map_get_park_entrance_element_at(_loc, false); + // Make sure the entrance part is the middle + if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) + { + entrancePath = true; + // Make the price the same as replacing a path + if (entranceElement->GetPathType() == (_type & 0xF)) + entranceIsSamePath = true; + else + res->Cost -= MONEY(6, 00); + } + + // Do not attempt to build a crossing with a queue or a sloped. + uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) + ? CREATE_CROSSING_MODE_NONE + : CREATE_CROSSING_MODE_PATH_OVER_TRACK; + if (!entrancePath + && !map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &res->Cost, crossingMode)) + { + return MakeResult( + GameActions::Status::NoClearance, STR_CANT_BUILD_FOOTPATH_HERE, gGameCommandErrorText, gCommonFormatArgs); + } + + gFootpathGroundFlags = gMapGroundFlags; + if (!gCheatsDisableClearanceChecks && (gMapGroundFlags & ELEMENT_IS_UNDERWATER)) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_CANT_BUILD_THIS_UNDERWATER); + } + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); + } + int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); + res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); + + // Prevent the place sound from being spammed + if (entranceIsSamePath) + res->Cost = 0; + + return res; +} + +GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions::Result::Ptr res) const +{ + bool entrancePath = false, entranceIsSamePath = false; + + if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST))) + { + footpath_remove_litter(_loc); + } + + res->Cost = MONEY(12, 00); + + QuarterTile quarterTile{ 0b1111, 0 }; + auto zLow = _loc.z; + auto zHigh = zLow + PATH_CLEARANCE; + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); + zHigh += PATH_HEIGHT_STEP; + } + + auto entranceElement = map_get_park_entrance_element_at(_loc, false); + // Make sure the entrance part is the middle + if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) + { + entrancePath = true; + // Make the price the same as replacing a path + if (entranceElement->GetPathType() == (_type & 0xF)) + entranceIsSamePath = true; + else + res->Cost -= MONEY(6, 00); + } + + // Do not attempt to build a crossing with a queue or a sloped. + uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) + ? CREATE_CROSSING_MODE_NONE + : CREATE_CROSSING_MODE_PATH_OVER_TRACK; + if (!entrancePath + && !map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), + &res->Cost, crossingMode)) + { + return MakeResult( + GameActions::Status::NoClearance, STR_CANT_BUILD_FOOTPATH_HERE, gGameCommandErrorText, gCommonFormatArgs); + } + + gFootpathGroundFlags = gMapGroundFlags; + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); + } + int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); + res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); + + if (entrancePath) + { + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath) + { + // Set the path type but make sure it's not a queue as that will not show up + entranceElement->SetPathType(_type & 0x7F); + map_invalidate_tile_full(_loc); + } + } + else + { + auto tileElement = tile_element_insert(_loc, 0b1111); + assert(tileElement != nullptr); + tileElement->SetType(TILE_ELEMENT_TYPE_PATH); + PathElement* pathElement = tileElement->AsPath(); + pathElement->SetClearanceZ(zHigh); + pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); + pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + pathElement->SetSloped(true); + } + if (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) + { + pathElement->SetIsQueue(true); + } + pathElement->SetAddition(0); + pathElement->SetRideIndex(RIDE_ID_NULL); + pathElement->SetAdditionStatus(255); + pathElement->SetIsBroken(false); + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + pathElement->SetGhost(true); + } + footpath_queue_chain_reset(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) + { + footpath_remove_edges_at(_loc, tileElement); + } + if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + AutomaticallySetPeepSpawn(); + } + + RemoveIntersectingWalls(pathElement); + } + + // Prevent the place sound from being spammed + if (entranceIsSamePath) + res->Cost = 0; + + return res; +} + +/** + * + * rct2: 0x006A65AD + */ +void FootpathPlaceAction::AutomaticallySetPeepSpawn() const +{ + uint8_t direction = 0; + if (_loc.x != 32) + { + direction++; + if (_loc.y != gMapSizeUnits - 32) + { + direction++; + if (_loc.x != gMapSizeUnits - 32) + { + direction++; + if (_loc.y != 32) + return; + } + } + } + + if (gPeepSpawns.empty()) + { + gPeepSpawns.emplace_back(); + } + PeepSpawn* peepSpawn = &gPeepSpawns[0]; + peepSpawn->x = _loc.x + (DirectionOffsets[direction].x * 15) + 16; + peepSpawn->y = _loc.y + (DirectionOffsets[direction].y * 15) + 16; + peepSpawn->direction = direction; + peepSpawn->z = _loc.z; +} + +void FootpathPlaceAction::RemoveIntersectingWalls(PathElement* pathElement) const +{ + if (pathElement->IsSloped() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + auto direction = pathElement->GetSlopeDirection(); + int32_t z = pathElement->GetBaseZ(); + wall_remove_intersecting_walls({ _loc, z, z + (6 * COORDS_Z_STEP) }, direction_reverse(direction)); + wall_remove_intersecting_walls({ _loc, z, z + (6 * COORDS_Z_STEP) }, direction); + // Removing walls may have made the pointer invalid, so find it again + auto tileElement = map_get_footpath_element(CoordsXYZ(_loc, z)); + if (tileElement == nullptr) + { + log_error("Something went wrong. Could not refind footpath."); + return; + } + pathElement = tileElement->AsPath(); + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) + footpath_connect_edges(_loc, reinterpret_cast(pathElement), GetFlags()); + + footpath_update_queue_chains(); + map_invalidate_tile_full(_loc); +} + +PathElement* FootpathPlaceAction::map_get_footpath_element_slope(const CoordsXYZ& footpathPos, int32_t slope) const +{ + TileElement* tileElement; + bool isSloped = slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED; + + tileElement = map_get_first_element_at(footpathPos); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH && tileElement->GetBaseZ() == footpathPos.z + && (tileElement->AsPath()->IsSloped() == isSloped) + && (tileElement->AsPath()->GetSlopeDirection() == (slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK))) + { + return tileElement->AsPath(); + } + } while (!(tileElement++)->IsLastForTile()); + return nullptr; +} diff --git a/src/openrct2/actions/FootpathPlaceAction.h b/src/openrct2/actions/FootpathPlaceAction.h new file mode 100644 index 0000000000..860e482357 --- /dev/null +++ b/src/openrct2/actions/FootpathPlaceAction.h @@ -0,0 +1,52 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/Footpath.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(FootpathPlaceAction, GAME_COMMAND_PLACE_PATH, GameActions::Result) +{ +private: + CoordsXYZ _loc; + uint8_t _slope{}; + ObjectEntryIndex _type{}; + Direction _direction{ INVALID_DIRECTION }; + +public: + FootpathPlaceAction() = default; + FootpathPlaceAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, Direction direction = INVALID_DIRECTION) + : _loc(loc) + , _slope(slope) + , _type(type) + , _direction(direction) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr ElementUpdateQuery(PathElement * pathElement, GameActions::Result::Ptr res) const; + GameActions::Result::Ptr ElementUpdateExecute(PathElement * pathElement, GameActions::Result::Ptr res) const; + GameActions::Result::Ptr ElementInsertQuery(GameActions::Result::Ptr res) const; + GameActions::Result::Ptr ElementInsertExecute(GameActions::Result::Ptr res) const; + void AutomaticallySetPeepSpawn() const; + void RemoveIntersectingWalls(PathElement * pathElement) const; + PathElement* map_get_footpath_element_slope(const CoordsXYZ& footpathPos, int32_t slope) const; +}; diff --git a/src/openrct2/actions/FootpathPlaceAction.hpp b/src/openrct2/actions/FootpathPlaceAction.hpp deleted file mode 100644 index 203bbdb341..0000000000 --- a/src/openrct2/actions/FootpathPlaceAction.hpp +++ /dev/null @@ -1,476 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Surface.h" -#include "../world/Wall.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(FootpathPlaceAction, GAME_COMMAND_PLACE_PATH, GameActions::Result) -{ -private: - CoordsXYZ _loc; - uint8_t _slope{}; - ObjectEntryIndex _type{}; - Direction _direction{ INVALID_DIRECTION }; - -public: - FootpathPlaceAction() = default; - FootpathPlaceAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, Direction direction = INVALID_DIRECTION) - : _loc(loc) - , _slope(slope) - , _type(type) - , _direction(direction) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _type); - visitor.Visit("direction", _direction); - visitor.Visit("slope", _slope); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_direction); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc.ToTileCentre(); - - gFootpathGroundFlags = 0; - - if (!LocationValid(_loc) || map_is_edge(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_OFF_EDGE_OF_MAP); - } - - if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (_slope & SLOPE_IS_IRREGULAR_FLAG) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_SLOPE_UNSUITABLE); - } - - if (_loc.z < FootpathMinHeight) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_LOW); - } - - if (_loc.z > FootpathMaxHeight) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_HIGH); - } - - if (_direction != INVALID_DIRECTION && !direction_valid(_direction)) - { - log_error("Direction invalid. direction = %u", _direction); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); - } - - footpath_provisional_remove(); - auto tileElement = map_get_footpath_element_slope(_loc, _slope); - if (tileElement == nullptr) - { - return ElementInsertQuery(std::move(res)); - } - else - { - return ElementUpdateQuery(tileElement, std::move(res)); - } - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc.ToTileCentre(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_interrupt_peeps(_loc); - } - - gFootpathGroundFlags = 0; - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - if (_direction != INVALID_DIRECTION && !gCheatsDisableClearanceChecks) - { - // It is possible, let's remove walls between the old and new piece of path - auto zLow = _loc.z; - auto zHigh = zLow + PATH_CLEARANCE; - wall_remove_intersecting_walls( - { _loc, zLow, zHigh + ((_slope & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) ? 16 : 0) }, - direction_reverse(_direction)); - wall_remove_intersecting_walls( - { _loc.x - CoordsDirectionDelta[_direction].x, _loc.y - CoordsDirectionDelta[_direction].y, zLow, zHigh }, - _direction); - } - } - - auto tileElement = map_get_footpath_element_slope(_loc, _slope); - if (tileElement == nullptr) - { - return ElementInsertExecute(std::move(res)); - } - else - { - return ElementUpdateExecute(tileElement, std::move(res)); - } - } - -private: - GameActions::Result::Ptr ElementUpdateQuery(PathElement * pathElement, GameActions::Result::Ptr res) const - { - const int32_t newFootpathType = (_type & (FOOTPATH_PROPERTIES_TYPE_MASK >> 4)); - const bool newPathIsQueue = ((_type >> 7) == 1); - if (pathElement->GetSurfaceEntryIndex() != newFootpathType || pathElement->IsQueue() != newPathIsQueue) - { - res->Cost += MONEY(6, 00); - } - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST && !pathElement->IsGhost()) - { - return MakeResult(GameActions::Status::Unknown, STR_CANT_BUILD_FOOTPATH_HERE); - } - return res; - } - - GameActions::Result::Ptr ElementUpdateExecute(PathElement * pathElement, GameActions::Result::Ptr res) const - { - const int32_t newFootpathType = (_type & (FOOTPATH_PROPERTIES_TYPE_MASK >> 4)); - const bool newPathIsQueue = ((_type >> 7) == 1); - if (pathElement->GetSurfaceEntryIndex() != newFootpathType || pathElement->IsQueue() != newPathIsQueue) - { - res->Cost += MONEY(6, 00); - } - - footpath_queue_chain_reset(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) - { - footpath_remove_edges_at(_loc, reinterpret_cast(pathElement)); - } - - pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); - bool isQueue = _type & FOOTPATH_ELEMENT_INSERT_QUEUE; - pathElement->SetIsQueue(isQueue); - - rct_scenery_entry* elem = pathElement->GetAdditionEntry(); - if (elem != nullptr) - { - if (isQueue) - { - // remove any addition that isn't a TV or a lamp - if ((elem->path_bit.flags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) == 0 - && (elem->path_bit.flags & PATH_BIT_FLAG_LAMP) == 0) - { - pathElement->SetIsBroken(false); - pathElement->SetAddition(0); - } - } - else - { - // remove all TVs - if ((elem->path_bit.flags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) != 0) - { - pathElement->SetIsBroken(false); - pathElement->SetAddition(0); - } - } - } - - RemoveIntersectingWalls(pathElement); - return res; - } - - GameActions::Result::Ptr ElementInsertQuery(GameActions::Result::Ptr res) const - { - bool entrancePath = false, entranceIsSamePath = false; - - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_BUILD_FOOTPATH_HERE); - } - - res->Cost = MONEY(12, 00); - - QuarterTile quarterTile{ 0b1111, 0 }; - auto zLow = _loc.z; - auto zHigh = zLow + PATH_CLEARANCE; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); - zHigh += PATH_HEIGHT_STEP; - } - - auto entranceElement = map_get_park_entrance_element_at(_loc, false); - // Make sure the entrance part is the middle - if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) - { - entrancePath = true; - // Make the price the same as replacing a path - if (entranceElement->GetPathType() == (_type & 0xF)) - entranceIsSamePath = true; - else - res->Cost -= MONEY(6, 00); - } - - // Do not attempt to build a crossing with a queue or a sloped. - uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) - ? CREATE_CROSSING_MODE_NONE - : CREATE_CROSSING_MODE_PATH_OVER_TRACK; - if (!entrancePath - && !map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &res->Cost, crossingMode)) - { - return MakeResult( - GameActions::Status::NoClearance, STR_CANT_BUILD_FOOTPATH_HERE, gGameCommandErrorText, gCommonFormatArgs); - } - - gFootpathGroundFlags = gMapGroundFlags; - if (!gCheatsDisableClearanceChecks && (gMapGroundFlags & ELEMENT_IS_UNDERWATER)) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_CANT_BUILD_THIS_UNDERWATER); - } - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); - } - int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); - res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); - - // Prevent the place sound from being spammed - if (entranceIsSamePath) - res->Cost = 0; - - return res; - } - - GameActions::Result::Ptr ElementInsertExecute(GameActions::Result::Ptr res) const - { - bool entrancePath = false, entranceIsSamePath = false; - - if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST))) - { - footpath_remove_litter(_loc); - } - - res->Cost = MONEY(12, 00); - - QuarterTile quarterTile{ 0b1111, 0 }; - auto zLow = _loc.z; - auto zHigh = zLow + PATH_CLEARANCE; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); - zHigh += PATH_HEIGHT_STEP; - } - - auto entranceElement = map_get_park_entrance_element_at(_loc, false); - // Make sure the entrance part is the middle - if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) - { - entrancePath = true; - // Make the price the same as replacing a path - if (entranceElement->GetPathType() == (_type & 0xF)) - entranceIsSamePath = true; - else - res->Cost -= MONEY(6, 00); - } - - // Do not attempt to build a crossing with a queue or a sloped. - uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) - ? CREATE_CROSSING_MODE_NONE - : CREATE_CROSSING_MODE_PATH_OVER_TRACK; - if (!entrancePath - && !map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), - &res->Cost, crossingMode)) - { - return MakeResult( - GameActions::Status::NoClearance, STR_CANT_BUILD_FOOTPATH_HERE, gGameCommandErrorText, gCommonFormatArgs); - } - - gFootpathGroundFlags = gMapGroundFlags; - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE); - } - int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); - res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); - - if (entrancePath) - { - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath) - { - // Set the path type but make sure it's not a queue as that will not show up - entranceElement->SetPathType(_type & 0x7F); - map_invalidate_tile_full(_loc); - } - } - else - { - auto tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); - tileElement->SetType(TILE_ELEMENT_TYPE_PATH); - PathElement* pathElement = tileElement->AsPath(); - pathElement->SetClearanceZ(zHigh); - pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); - pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - pathElement->SetSloped(true); - } - if (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) - { - pathElement->SetIsQueue(true); - } - pathElement->SetAddition(0); - pathElement->SetRideIndex(RIDE_ID_NULL); - pathElement->SetAdditionStatus(255); - pathElement->SetIsBroken(false); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - pathElement->SetGhost(true); - } - footpath_queue_chain_reset(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) - { - footpath_remove_edges_at(_loc, tileElement); - } - if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - AutomaticallySetPeepSpawn(); - } - - RemoveIntersectingWalls(pathElement); - } - - // Prevent the place sound from being spammed - if (entranceIsSamePath) - res->Cost = 0; - - return res; - } - /** - * - * rct2: 0x006A65AD - */ - void AutomaticallySetPeepSpawn() const - { - uint8_t direction = 0; - if (_loc.x != 32) - { - direction++; - if (_loc.y != gMapSizeUnits - 32) - { - direction++; - if (_loc.x != gMapSizeUnits - 32) - { - direction++; - if (_loc.y != 32) - return; - } - } - } - - if (gPeepSpawns.empty()) - { - gPeepSpawns.emplace_back(); - } - PeepSpawn* peepSpawn = &gPeepSpawns[0]; - peepSpawn->x = _loc.x + (DirectionOffsets[direction].x * 15) + 16; - peepSpawn->y = _loc.y + (DirectionOffsets[direction].y * 15) + 16; - peepSpawn->direction = direction; - peepSpawn->z = _loc.z; - } - - void RemoveIntersectingWalls(PathElement * pathElement) const - { - if (pathElement->IsSloped() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - auto direction = pathElement->GetSlopeDirection(); - int32_t z = pathElement->GetBaseZ(); - wall_remove_intersecting_walls({ _loc, z, z + (6 * COORDS_Z_STEP) }, direction_reverse(direction)); - wall_remove_intersecting_walls({ _loc, z, z + (6 * COORDS_Z_STEP) }, direction); - // Removing walls may have made the pointer invalid, so find it again - auto tileElement = map_get_footpath_element(CoordsXYZ(_loc, z)); - if (tileElement == nullptr) - { - log_error("Something went wrong. Could not refind footpath."); - return; - } - pathElement = tileElement->AsPath(); - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) - footpath_connect_edges(_loc, reinterpret_cast(pathElement), GetFlags()); - - footpath_update_queue_chains(); - map_invalidate_tile_full(_loc); - } - - PathElement* map_get_footpath_element_slope(const CoordsXYZ& footpathPos, int32_t slope) const - { - TileElement* tileElement; - bool isSloped = slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED; - - tileElement = map_get_first_element_at(footpathPos); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH && tileElement->GetBaseZ() == footpathPos.z - && (tileElement->AsPath()->IsSloped() == isSloped) - && (tileElement->AsPath()->GetSlopeDirection() == (slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK))) - { - return tileElement->AsPath(); - } - } while (!(tileElement++)->IsLastForTile()); - return nullptr; - } -}; diff --git a/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp b/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp new file mode 100644 index 0000000000..ae3d8402b6 --- /dev/null +++ b/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp @@ -0,0 +1,252 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "FootpathPlaceFromTrackAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Surface.h" +#include "../world/Wall.h" + +void FootpathPlaceFromTrackAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_edges); +} + +GameActions::Result::Ptr FootpathPlaceFromTrackAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc.ToTileCentre(); + + gFootpathGroundFlags = 0; + + if (!LocationValid(_loc) || map_is_edge(_loc)) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_OFF_EDGE_OF_MAP); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) + { + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (_loc.z < FootpathMinHeight) + { + return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_LOW); + } + + if (_loc.z > FootpathMaxHeight) + { + return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_HIGH); + } + + return ElementInsertQuery(std::move(res)); +} + +GameActions::Result::Ptr FootpathPlaceFromTrackAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc.ToTileCentre(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_interrupt_peeps(_loc); + } + + gFootpathGroundFlags = 0; + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + return ElementInsertExecute(std::move(res)); +} + +GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertQuery(GameActions::Result::Ptr res) const +{ + bool entrancePath = false, entranceIsSamePath = false; + + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); + } + + res->Cost = MONEY(12, 00); + + QuarterTile quarterTile{ 0b1111, 0 }; + auto zLow = _loc.z; + auto zHigh = zLow + PATH_CLEARANCE; + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); + zHigh += PATH_HEIGHT_STEP; + } + + auto entranceElement = map_get_park_entrance_element_at(_loc, false); + // Make sure the entrance part is the middle + if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) + { + entrancePath = true; + // Make the price the same as replacing a path + if (entranceElement->GetPathType() == (_type & 0xF)) + entranceIsSamePath = true; + else + res->Cost -= MONEY(6, 00); + } + + // Do not attempt to build a crossing with a queue or a sloped. + uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) + ? CREATE_CROSSING_MODE_NONE + : CREATE_CROSSING_MODE_PATH_OVER_TRACK; + if (!entrancePath + && !map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &res->Cost, crossingMode)) + { + return MakeResult( + GameActions::Status::NoClearance, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText, + gCommonFormatArgs); + } + + gFootpathGroundFlags = gMapGroundFlags; + if (!gCheatsDisableClearanceChecks && (gMapGroundFlags & ELEMENT_IS_UNDERWATER)) + { + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_CANT_BUILD_THIS_UNDERWATER); + } + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); + } + int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); + res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); + + // Prevent the place sound from being spammed + if (entranceIsSamePath) + res->Cost = 0; + + return res; +} + +GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(GameActions::Result::Ptr res) const +{ + bool entrancePath = false, entranceIsSamePath = false; + + if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST))) + { + footpath_remove_litter(_loc); + } + + res->Cost = MONEY(12, 00); + + QuarterTile quarterTile{ 0b1111, 0 }; + auto zLow = _loc.z; + auto zHigh = zLow + PATH_CLEARANCE; + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); + zHigh += PATH_HEIGHT_STEP; + } + + auto entranceElement = map_get_park_entrance_element_at(_loc, false); + // Make sure the entrance part is the middle + if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) + { + entrancePath = true; + // Make the price the same as replacing a path + if (entranceElement->GetPathType() == (_type & 0xF)) + entranceIsSamePath = true; + else + res->Cost -= MONEY(6, 00); + } + + // Do not attempt to build a crossing with a queue or a sloped. + uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) + ? CREATE_CROSSING_MODE_NONE + : CREATE_CROSSING_MODE_PATH_OVER_TRACK; + if (!entrancePath + && !map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), + &res->Cost, crossingMode)) + { + return MakeResult( + GameActions::Status::NoClearance, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText, + gCommonFormatArgs); + } + + gFootpathGroundFlags = gMapGroundFlags; + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); + } + int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); + res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); + + if (entrancePath) + { + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath) + { + // Set the path type but make sure it's not a queue as that will not show up + entranceElement->SetPathType(_type & 0x7F); + map_invalidate_tile_full(_loc); + } + } + else + { + auto tileElement = tile_element_insert(_loc, 0b1111); + assert(tileElement != nullptr); + tileElement->SetType(TILE_ELEMENT_TYPE_PATH); + PathElement* pathElement = tileElement->AsPath(); + pathElement->SetClearanceZ(zHigh); + pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); + pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); + if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + { + pathElement->SetSloped(true); + } + if (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) + { + pathElement->SetIsQueue(true); + } + pathElement->SetAddition(0); + pathElement->SetRideIndex(RIDE_ID_NULL); + pathElement->SetAdditionStatus(255); + pathElement->SetIsBroken(false); + pathElement->SetEdges(_edges); + pathElement->SetCorners(0); + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + pathElement->SetGhost(true); + } + map_invalidate_tile_full(_loc); + } + + // Prevent the place sound from being spammed + if (entranceIsSamePath) + res->Cost = 0; + + return res; +} diff --git a/src/openrct2/actions/FootpathPlaceFromTrackAction.h b/src/openrct2/actions/FootpathPlaceFromTrackAction.h new file mode 100644 index 0000000000..9878a91f47 --- /dev/null +++ b/src/openrct2/actions/FootpathPlaceFromTrackAction.h @@ -0,0 +1,44 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(FootpathPlaceFromTrackAction, GAME_COMMAND_PLACE_PATH_FROM_TRACK, GameActions::Result) +{ +private: + CoordsXYZ _loc; + uint8_t _slope{}; + ObjectEntryIndex _type{}; + uint8_t _edges{}; + +public: + FootpathPlaceFromTrackAction() = default; + FootpathPlaceFromTrackAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, uint8_t edges) + : _loc(loc) + , _slope(slope) + , _type(type) + , _edges(edges) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr ElementInsertQuery(GameActions::Result::Ptr res) const; + GameActions::Result::Ptr ElementInsertExecute(GameActions::Result::Ptr res) const; +}; diff --git a/src/openrct2/actions/FootpathPlaceFromTrackAction.hpp b/src/openrct2/actions/FootpathPlaceFromTrackAction.hpp deleted file mode 100644 index 6afeb828c5..0000000000 --- a/src/openrct2/actions/FootpathPlaceFromTrackAction.hpp +++ /dev/null @@ -1,279 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Park.h" -#include "../world/Surface.h" -#include "../world/Wall.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(FootpathPlaceFromTrackAction, GAME_COMMAND_PLACE_PATH_FROM_TRACK, GameActions::Result) -{ -private: - CoordsXYZ _loc; - uint8_t _slope{}; - ObjectEntryIndex _type{}; - uint8_t _edges{}; - -public: - FootpathPlaceFromTrackAction() = default; - FootpathPlaceFromTrackAction(const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, uint8_t edges) - : _loc(loc) - , _slope(slope) - , _type(type) - , _edges(edges) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_edges); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc.ToTileCentre(); - - gFootpathGroundFlags = 0; - - if (!LocationValid(_loc) || map_is_edge(_loc)) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_OFF_EDGE_OF_MAP); - } - - if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) - { - return MakeResult( - GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (_loc.z < FootpathMinHeight) - { - return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_LOW); - } - - if (_loc.z > FootpathMaxHeight) - { - return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_HIGH); - } - - return ElementInsertQuery(std::move(res)); - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc.ToTileCentre(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_interrupt_peeps(_loc); - } - - gFootpathGroundFlags = 0; - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - return ElementInsertExecute(std::move(res)); - } - -private: - GameActions::Result::Ptr ElementInsertQuery(GameActions::Result::Ptr res) const - { - bool entrancePath = false, entranceIsSamePath = false; - - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); - } - - res->Cost = MONEY(12, 00); - - QuarterTile quarterTile{ 0b1111, 0 }; - auto zLow = _loc.z; - auto zHigh = zLow + PATH_CLEARANCE; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); - zHigh += PATH_HEIGHT_STEP; - } - - auto entranceElement = map_get_park_entrance_element_at(_loc, false); - // Make sure the entrance part is the middle - if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) - { - entrancePath = true; - // Make the price the same as replacing a path - if (entranceElement->GetPathType() == (_type & 0xF)) - entranceIsSamePath = true; - else - res->Cost -= MONEY(6, 00); - } - - // Do not attempt to build a crossing with a queue or a sloped. - uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) - ? CREATE_CROSSING_MODE_NONE - : CREATE_CROSSING_MODE_PATH_OVER_TRACK; - if (!entrancePath - && !map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &res->Cost, crossingMode)) - { - return MakeResult( - GameActions::Status::NoClearance, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText, - gCommonFormatArgs); - } - - gFootpathGroundFlags = gMapGroundFlags; - if (!gCheatsDisableClearanceChecks && (gMapGroundFlags & ELEMENT_IS_UNDERWATER)) - { - return MakeResult( - GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, - STR_CANT_BUILD_THIS_UNDERWATER); - } - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); - } - int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); - res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); - - // Prevent the place sound from being spammed - if (entranceIsSamePath) - res->Cost = 0; - - return res; - } - - GameActions::Result::Ptr ElementInsertExecute(GameActions::Result::Ptr res) const - { - bool entrancePath = false, entranceIsSamePath = false; - - if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST))) - { - footpath_remove_litter(_loc); - } - - res->Cost = MONEY(12, 00); - - QuarterTile quarterTile{ 0b1111, 0 }; - auto zLow = _loc.z; - auto zHigh = zLow + PATH_CLEARANCE; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK); - zHigh += PATH_HEIGHT_STEP; - } - - auto entranceElement = map_get_park_entrance_element_at(_loc, false); - // Make sure the entrance part is the middle - if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0) - { - entrancePath = true; - // Make the price the same as replacing a path - if (entranceElement->GetPathType() == (_type & 0xF)) - entranceIsSamePath = true; - else - res->Cost -= MONEY(6, 00); - } - - // Do not attempt to build a crossing with a queue or a sloped. - uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT) - ? CREATE_CROSSING_MODE_NONE - : CREATE_CROSSING_MODE_PATH_OVER_TRACK; - if (!entrancePath - && !map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), - &res->Cost, crossingMode)) - { - return MakeResult( - GameActions::Status::NoClearance, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText, - gCommonFormatArgs); - } - - gFootpathGroundFlags = gMapGroundFlags; - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE); - } - int32_t supportHeight = zLow - surfaceElement->GetBaseZ(); - res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / PATH_HEIGHT_STEP) * MONEY(5, 00); - - if (entrancePath) - { - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath) - { - // Set the path type but make sure it's not a queue as that will not show up - entranceElement->SetPathType(_type & 0x7F); - map_invalidate_tile_full(_loc); - } - } - else - { - auto tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); - tileElement->SetType(TILE_ELEMENT_TYPE_PATH); - PathElement* pathElement = tileElement->AsPath(); - pathElement->SetClearanceZ(zHigh); - pathElement->SetSurfaceEntryIndex(_type & ~FOOTPATH_ELEMENT_INSERT_QUEUE); - pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) - { - pathElement->SetSloped(true); - } - if (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) - { - pathElement->SetIsQueue(true); - } - pathElement->SetAddition(0); - pathElement->SetRideIndex(RIDE_ID_NULL); - pathElement->SetAdditionStatus(255); - pathElement->SetIsBroken(false); - pathElement->SetEdges(_edges); - pathElement->SetCorners(0); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - pathElement->SetGhost(true); - } - map_invalidate_tile_full(_loc); - } - - // Prevent the place sound from being spammed - if (entranceIsSamePath) - res->Cost = 0; - - return res; - } -}; diff --git a/src/openrct2/actions/FootpathRemoveAction.cpp b/src/openrct2/actions/FootpathRemoveAction.cpp new file mode 100644 index 0000000000..16ad6df3d0 --- /dev/null +++ b/src/openrct2/actions/FootpathRemoveAction.cpp @@ -0,0 +1,174 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "FootpathRemoveAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Wall.h" +#include "BannerRemoveAction.h" + +void FootpathRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); +} + +void FootpathRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr FootpathRemoveAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = { _loc.x + 16, _loc.y + 16, _loc.z }; + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + TileElement* footpathElement = GetFootpathElement(); + if (footpathElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_FOOTPATH_FROM_HERE); + } + + res->Cost = GetRefundPrice(footpathElement); + + return res; +} + +GameActions::Result::Ptr FootpathRemoveAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = { _loc.x + 16, _loc.y + 16, _loc.z }; + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_interrupt_peeps(_loc); + footpath_remove_litter(_loc); + } + + TileElement* footpathElement = GetFootpathElement(); + if (footpathElement != nullptr) + { + footpath_queue_chain_reset(); + auto bannerRes = RemoveBannersAtElement(_loc, footpathElement); + if (bannerRes->Error == GameActions::Status::Ok) + { + res->Cost += bannerRes->Cost; + } + footpath_remove_edges_at(_loc, footpathElement); + map_invalidate_tile_full(_loc); + tile_element_remove(footpathElement); + footpath_update_queue_chains(); + + // Remove the spawn point (if there is one in the current tile) + gPeepSpawns.erase( + std::remove_if( + gPeepSpawns.begin(), gPeepSpawns.end(), + [this](const CoordsXYZ& spawn) { + { + return spawn.ToTileStart() == _loc.ToTileStart(); + } + }), + gPeepSpawns.end()); + } + else + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_FOOTPATH_FROM_HERE); + } + + res->Cost += GetRefundPrice(footpathElement); + + return res; +} + +TileElement* FootpathRemoveAction::GetFootpathElement() const +{ + bool getGhostPath = GetFlags() & GAME_COMMAND_FLAG_GHOST; + + TileElement* tileElement = map_get_footpath_element(_loc); + TileElement* footpathElement = nullptr; + if (tileElement != nullptr) + { + if (getGhostPath && !tileElement->IsGhost()) + { + while (!(tileElement++)->IsLastForTile()) + { + if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH && !tileElement->IsGhost()) + { + continue; + } + footpathElement = tileElement; + break; + } + } + else + { + footpathElement = tileElement; + } + } + + return footpathElement; +} + +money32 FootpathRemoveAction::GetRefundPrice(TileElement* footpathElement) const +{ + money32 cost = -MONEY(10, 00); + return cost; +} + +/** + * + * rct2: 0x006BA23E + */ +GameActions::Result::Ptr FootpathRemoveAction::RemoveBannersAtElement(const CoordsXY& loc, TileElement* tileElement) const +{ + auto result = MakeResult(); + while (!(tileElement++)->IsLastForTile()) + { + if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH) + return result; + else if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) + continue; + + auto bannerRemoveAction = BannerRemoveAction({ loc, tileElement->GetBaseZ(), tileElement->AsBanner()->GetPosition() }); + bool isGhost = tileElement->IsGhost(); + auto bannerFlags = GetFlags() | (isGhost ? static_cast(GAME_COMMAND_FLAG_GHOST) : 0); + bannerRemoveAction.SetFlags(bannerFlags); + auto res = GameActions::ExecuteNested(&bannerRemoveAction); + // Ghost removal is free + if (res->Error == GameActions::Status::Ok && !isGhost) + { + result->Cost += res->Cost; + } + tileElement--; + } + return result; +} diff --git a/src/openrct2/actions/FootpathRemoveAction.h b/src/openrct2/actions/FootpathRemoveAction.h new file mode 100644 index 0000000000..e4a269bd47 --- /dev/null +++ b/src/openrct2/actions/FootpathRemoveAction.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../management/Finance.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(FootpathRemoveAction, GAME_COMMAND_REMOVE_PATH, GameActions::Result) +{ +private: + CoordsXYZ _loc; + +public: + FootpathRemoveAction() = default; + FootpathRemoveAction(const CoordsXYZ& location) + : _loc(location) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + TileElement* GetFootpathElement() const; + money32 GetRefundPrice(TileElement * footpathElement) const; + GameActions::Result::Ptr RemoveBannersAtElement(const CoordsXY& loc, TileElement* tileElement) const; +}; diff --git a/src/openrct2/actions/FootpathRemoveAction.hpp b/src/openrct2/actions/FootpathRemoveAction.hpp deleted file mode 100644 index 71504c2ea0..0000000000 --- a/src/openrct2/actions/FootpathRemoveAction.hpp +++ /dev/null @@ -1,195 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Park.h" -#include "../world/Wall.h" -#include "BannerRemoveAction.hpp" -#include "GameAction.h" - -DEFINE_GAME_ACTION(FootpathRemoveAction, GAME_COMMAND_REMOVE_PATH, GameActions::Result) -{ -private: - CoordsXYZ _loc; - -public: - FootpathRemoveAction() = default; - FootpathRemoveAction(const CoordsXYZ& location) - : _loc(location) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = { _loc.x + 16, _loc.y + 16, _loc.z }; - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK); - } - - TileElement* footpathElement = GetFootpathElement(); - if (footpathElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_FOOTPATH_FROM_HERE); - } - - res->Cost = GetRefundPrice(footpathElement); - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = { _loc.x + 16, _loc.y + 16, _loc.z }; - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_interrupt_peeps(_loc); - footpath_remove_litter(_loc); - } - - TileElement* footpathElement = GetFootpathElement(); - if (footpathElement != nullptr) - { - footpath_queue_chain_reset(); - auto bannerRes = RemoveBannersAtElement(_loc, footpathElement); - if (bannerRes->Error == GameActions::Status::Ok) - { - res->Cost += bannerRes->Cost; - } - footpath_remove_edges_at(_loc, footpathElement); - map_invalidate_tile_full(_loc); - tile_element_remove(footpathElement); - footpath_update_queue_chains(); - - // Remove the spawn point (if there is one in the current tile) - gPeepSpawns.erase( - std::remove_if( - gPeepSpawns.begin(), gPeepSpawns.end(), - [this](const CoordsXYZ& spawn) { - { - return spawn.ToTileStart() == _loc.ToTileStart(); - } - }), - gPeepSpawns.end()); - } - else - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_FOOTPATH_FROM_HERE); - } - - res->Cost += GetRefundPrice(footpathElement); - - return res; - } - -private: - TileElement* GetFootpathElement() const - { - bool getGhostPath = GetFlags() & GAME_COMMAND_FLAG_GHOST; - - TileElement* tileElement = map_get_footpath_element(_loc); - TileElement* footpathElement = nullptr; - if (tileElement != nullptr) - { - if (getGhostPath && !tileElement->IsGhost()) - { - while (!(tileElement++)->IsLastForTile()) - { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH && !tileElement->IsGhost()) - { - continue; - } - footpathElement = tileElement; - break; - } - } - else - { - footpathElement = tileElement; - } - } - - return footpathElement; - } - - money32 GetRefundPrice(TileElement * footpathElement) const - { - money32 cost = -MONEY(10, 00); - return cost; - } - - /** - * - * rct2: 0x006BA23E - */ - GameActions::Result::Ptr RemoveBannersAtElement(const CoordsXY& loc, TileElement* tileElement) const - { - auto result = MakeResult(); - while (!(tileElement++)->IsLastForTile()) - { - if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH) - return result; - else if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER) - continue; - - auto bannerRemoveAction = BannerRemoveAction( - { loc, tileElement->GetBaseZ(), tileElement->AsBanner()->GetPosition() }); - bool isGhost = tileElement->IsGhost(); - auto bannerFlags = GetFlags() | (isGhost ? static_cast(GAME_COMMAND_FLAG_GHOST) : 0); - bannerRemoveAction.SetFlags(bannerFlags); - auto res = GameActions::ExecuteNested(&bannerRemoveAction); - // Ghost removal is free - if (res->Error == GameActions::Status::Ok && !isGhost) - { - result->Cost += res->Cost; - } - tileElement--; - } - return result; - } -}; diff --git a/src/openrct2/actions/GameActionCompat.cpp b/src/openrct2/actions/GameActionCompat.cpp index 576778a671..01de237685 100644 --- a/src/openrct2/actions/GameActionCompat.cpp +++ b/src/openrct2/actions/GameActionCompat.cpp @@ -7,18 +7,22 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../peep/Staff.h" +#include "../ride/Track.h" +#include "../world/Entrance.h" +#include "../world/Park.h" #include "GameAction.h" -#include "GuestSetNameAction.hpp" -#include "MazeSetTrackAction.hpp" -#include "PlaceParkEntranceAction.hpp" -#include "PlacePeepSpawnAction.hpp" -#include "RideCreateAction.hpp" -#include "RideDemolishAction.hpp" -#include "RideSetName.hpp" -#include "RideSetStatus.hpp" -#include "SetParkEntranceFeeAction.hpp" -#include "StaffSetNameAction.hpp" -#include "WallRemoveAction.hpp" +#include "GuestSetNameAction.h" +#include "MazeSetTrackAction.h" +#include "PlaceParkEntranceAction.h" +#include "PlacePeepSpawnAction.h" +#include "RideCreateAction.h" +#include "RideDemolishAction.h" +#include "RideSetNameAction.h" +#include "RideSetStatusAction.h" +#include "SetParkEntranceFeeAction.h" +#include "StaffSetNameAction.h" +#include "WallRemoveAction.h" #pragma region PlaceParkEntranceAction /** diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index e50c84153d..872883540c 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -7,87 +7,87 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ -#include "BalloonPressAction.hpp" -#include "BannerPlaceAction.hpp" -#include "BannerRemoveAction.hpp" -#include "BannerSetColourAction.hpp" -#include "BannerSetNameAction.hpp" -#include "BannerSetStyleAction.hpp" -#include "ClearAction.hpp" -#include "ClimateSetAction.hpp" -#include "CustomAction.hpp" -#include "FootpathAdditionPlaceAction.hpp" -#include "FootpathAdditionRemoveAction.hpp" -#include "FootpathPlaceAction.hpp" -#include "FootpathPlaceFromTrackAction.hpp" -#include "FootpathRemoveAction.hpp" +#include "BalloonPressAction.h" +#include "BannerPlaceAction.h" +#include "BannerRemoveAction.h" +#include "BannerSetColourAction.h" +#include "BannerSetNameAction.h" +#include "BannerSetStyleAction.h" +#include "ClearAction.h" +#include "ClimateSetAction.h" +#include "CustomAction.h" +#include "FootpathAdditionPlaceAction.h" +#include "FootpathAdditionRemoveAction.h" +#include "FootpathPlaceAction.h" +#include "FootpathPlaceFromTrackAction.h" +#include "FootpathRemoveAction.h" #include "GameAction.h" -#include "GuestSetFlagsAction.hpp" -#include "GuestSetNameAction.hpp" -#include "LandBuyRightsAction.hpp" -#include "LandLowerAction.hpp" -#include "LandRaiseAction.hpp" -#include "LandSetHeightAction.hpp" -#include "LandSetRightsAction.hpp" -#include "LandSmoothAction.hpp" -#include "LargeSceneryPlaceAction.hpp" -#include "LargeSceneryRemoveAction.hpp" -#include "LargeScenerySetColourAction.hpp" -#include "LoadOrQuitAction.hpp" -#include "MazePlaceTrackAction.hpp" -#include "MazeSetTrackAction.hpp" -#include "NetworkModifyGroupAction.hpp" -#include "ParkEntranceRemoveAction.hpp" -#include "ParkMarketingAction.hpp" -#include "ParkSetDateAction.hpp" -#include "ParkSetLoanAction.hpp" -#include "ParkSetNameAction.hpp" -#include "ParkSetParameterAction.hpp" -#include "ParkSetResearchFundingAction.hpp" -#include "PauseToggleAction.hpp" -#include "PeepPickupAction.hpp" -#include "PlaceParkEntranceAction.hpp" -#include "PlacePeepSpawnAction.hpp" -#include "PlayerKickAction.hpp" -#include "PlayerSetGroupAction.hpp" -#include "RideCreateAction.hpp" -#include "RideDemolishAction.hpp" -#include "RideEntranceExitPlaceAction.hpp" -#include "RideEntranceExitRemoveAction.hpp" -#include "RideSetAppearanceAction.hpp" -#include "RideSetColourScheme.hpp" -#include "RideSetName.hpp" -#include "RideSetPriceAction.hpp" -#include "RideSetSetting.hpp" -#include "RideSetStatus.hpp" -#include "RideSetVehiclesAction.hpp" -#include "ScenarioSetSettingAction.hpp" -#include "SetCheatAction.hpp" -#include "SetParkEntranceFeeAction.hpp" -#include "SignSetNameAction.hpp" -#include "SignSetStyleAction.hpp" -#include "SmallSceneryPlaceAction.hpp" -#include "SmallSceneryRemoveAction.hpp" -#include "SmallScenerySetColourAction.hpp" -#include "StaffFireAction.hpp" -#include "StaffHireNewAction.hpp" -#include "StaffSetColourAction.hpp" -#include "StaffSetCostumeAction.hpp" -#include "StaffSetNameAction.hpp" -#include "StaffSetOrdersAction.hpp" -#include "StaffSetPatrolAreaAction.hpp" -#include "SurfaceSetStyleAction.hpp" -#include "TileModifyAction.hpp" +#include "GuestSetFlagsAction.h" +#include "GuestSetNameAction.h" +#include "LandBuyRightsAction.h" +#include "LandLowerAction.h" +#include "LandRaiseAction.h" +#include "LandSetHeightAction.h" +#include "LandSetRightsAction.h" +#include "LandSmoothAction.h" +#include "LargeSceneryPlaceAction.h" +#include "LargeSceneryRemoveAction.h" +#include "LargeScenerySetColourAction.h" +#include "LoadOrQuitAction.h" +#include "MazePlaceTrackAction.h" +#include "MazeSetTrackAction.h" +#include "NetworkModifyGroupAction.h" +#include "ParkEntranceRemoveAction.h" +#include "ParkMarketingAction.h" +#include "ParkSetDateAction.h" +#include "ParkSetLoanAction.h" +#include "ParkSetNameAction.h" +#include "ParkSetParameterAction.h" +#include "ParkSetResearchFundingAction.h" +#include "PauseToggleAction.h" +#include "PeepPickupAction.h" +#include "PlaceParkEntranceAction.h" +#include "PlacePeepSpawnAction.h" +#include "PlayerKickAction.h" +#include "PlayerSetGroupAction.h" +#include "RideCreateAction.h" +#include "RideDemolishAction.h" +#include "RideEntranceExitPlaceAction.h" +#include "RideEntranceExitRemoveAction.h" +#include "RideSetAppearanceAction.h" +#include "RideSetColourSchemeAction.h" +#include "RideSetNameAction.h" +#include "RideSetPriceAction.h" +#include "RideSetSettingAction.h" +#include "RideSetStatusAction.h" +#include "RideSetVehicleAction.h" +#include "ScenarioSetSettingAction.h" +#include "SetCheatAction.h" +#include "SetParkEntranceFeeAction.h" +#include "SignSetNameAction.h" +#include "SignSetStyleAction.h" +#include "SmallSceneryPlaceAction.h" +#include "SmallSceneryRemoveAction.h" +#include "SmallScenerySetColourAction.h" +#include "StaffFireAction.h" +#include "StaffHireNewAction.h" +#include "StaffSetColourAction.h" +#include "StaffSetCostumeAction.h" +#include "StaffSetNameAction.h" +#include "StaffSetOrdersAction.h" +#include "StaffSetPatrolAreaAction.h" +#include "SurfaceSetStyleAction.h" +#include "TileModifyAction.h" #include "TrackDesignAction.h" -#include "TrackPlaceAction.hpp" -#include "TrackRemoveAction.hpp" -#include "TrackSetBrakeSpeedAction.hpp" -#include "WallPlaceAction.hpp" -#include "WallRemoveAction.hpp" -#include "WallSetColourAction.hpp" -#include "WaterLowerAction.hpp" -#include "WaterRaiseAction.hpp" -#include "WaterSetHeightAction.hpp" +#include "TrackPlaceAction.h" +#include "TrackRemoveAction.h" +#include "TrackSetBrakeSpeedAction.h" +#include "WallPlaceAction.h" +#include "WallRemoveAction.h" +#include "WallSetColourAction.h" +#include "WaterLowerAction.h" +#include "WaterRaiseAction.h" +#include "WaterSetHeightAction.h" namespace GameActions { diff --git a/src/openrct2/actions/GuestSetFlagsAction.cpp b/src/openrct2/actions/GuestSetFlagsAction.cpp new file mode 100644 index 0000000000..2644b04ae1 --- /dev/null +++ b/src/openrct2/actions/GuestSetFlagsAction.cpp @@ -0,0 +1,51 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "GuestSetFlagsAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" + +void GuestSetFlagsAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("peep", _peepId); + visitor.Visit("flags", _newFlags); +} + +void GuestSetFlagsAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_peepId) << DS_TAG(_newFlags); +} + +GameActions::Result::Ptr GuestSetFlagsAction::Query() const +{ + Peep* peep = TryGetEntity(_peepId); + if (peep == nullptr) + { + log_error("Used invalid sprite index for peep: %u", static_cast(_peepId)); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS); + } + return std::make_unique(); +} + +GameActions::Result::Ptr GuestSetFlagsAction::Execute() const +{ + Peep* peep = TryGetEntity(_peepId); + if (peep == nullptr) + { + log_error("Used invalid sprite index for peep: %u", static_cast(_peepId)); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS); + } + + peep->PeepFlags = _newFlags; + + return std::make_unique(); +} diff --git a/src/openrct2/actions/GuestSetFlagsAction.h b/src/openrct2/actions/GuestSetFlagsAction.h new file mode 100644 index 0000000000..6cf9db9290 --- /dev/null +++ b/src/openrct2/actions/GuestSetFlagsAction.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(GuestSetFlagsAction, GAME_COMMAND_GUEST_SET_FLAGS, GameActions::Result) +{ +private: + uint16_t _peepId{ SPRITE_INDEX_NULL }; + uint32_t _newFlags{}; + +public: + GuestSetFlagsAction() = default; + GuestSetFlagsAction(uint16_t peepId, uint32_t flags) + : _peepId(peepId) + , _newFlags(flags) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/GuestSetFlagsAction.hpp b/src/openrct2/actions/GuestSetFlagsAction.hpp deleted file mode 100644 index 4692b7a473..0000000000 --- a/src/openrct2/actions/GuestSetFlagsAction.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../OpenRCT2.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(GuestSetFlagsAction, GAME_COMMAND_GUEST_SET_FLAGS, GameActions::Result) -{ -private: - uint16_t _peepId{ SPRITE_INDEX_NULL }; - uint32_t _newFlags{}; - -public: - GuestSetFlagsAction() = default; - GuestSetFlagsAction(uint16_t peepId, uint32_t flags) - : _peepId(peepId) - , _newFlags(flags) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("peep", _peepId); - visitor.Visit("flags", _newFlags); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_peepId) << DS_TAG(_newFlags); - } - - GameActions::Result::Ptr Query() const override - { - Peep* peep = TryGetEntity(_peepId); - if (peep == nullptr) - { - log_error("Used invalid sprite index for peep: %u", static_cast(_peepId)); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS); - } - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - Peep* peep = TryGetEntity(_peepId); - if (peep == nullptr) - { - log_error("Used invalid sprite index for peep: %u", static_cast(_peepId)); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_THIS); - } - - peep->PeepFlags = _newFlags; - - return std::make_unique(); - } -}; diff --git a/src/openrct2/actions/GuestSetNameAction.cpp b/src/openrct2/actions/GuestSetNameAction.cpp new file mode 100644 index 0000000000..38a4b71841 --- /dev/null +++ b/src/openrct2/actions/GuestSetNameAction.cpp @@ -0,0 +1,86 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "GuestSetNameAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Sprite.h" + +void GuestSetNameAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("peep", _spriteIndex); + visitor.Visit("name", _name); +} + +void GuestSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_spriteIndex) << DS_TAG(_name); +} + +GameActions::Result::Ptr GuestSetNameAction::Query() const +{ + if (_spriteIndex >= MAX_SPRITES) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); + } + + auto guest = TryGetEntity(_spriteIndex); + if (guest == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr GuestSetNameAction::Execute() const +{ + auto guest = TryGetEntity(_spriteIndex); + if (guest == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); + } + + auto curName = guest->GetName(); + if (curName == _name) + { + return std::make_unique(GameActions::Status::Ok, STR_NONE); + } + + if (!guest->SetName(_name)) + { + return std::make_unique(GameActions::Status::Unknown, STR_CANT_NAME_GUEST, STR_NONE); + } + + // Easter egg functions are for guests only + guest->HandleEasterEggName(); + + gfx_invalidate_screen(); + + auto intent = Intent(INTENT_ACTION_REFRESH_GUEST_LIST); + context_broadcast_intent(&intent); + + auto res = std::make_unique(); + res->Position.x = guest->x; + res->Position.y = guest->y; + res->Position.z = guest->z; + return res; +} diff --git a/src/openrct2/actions/GuestSetNameAction.h b/src/openrct2/actions/GuestSetNameAction.h new file mode 100644 index 0000000000..4364a22a39 --- /dev/null +++ b/src/openrct2/actions/GuestSetNameAction.h @@ -0,0 +1,48 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(GuestSetNameAction, GAME_COMMAND_SET_GUEST_NAME, GameActions::Result) +{ +private: + uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; + std::string _name; + +public: + GuestSetNameAction() = default; + GuestSetNameAction(uint16_t spriteIndex, const std::string& name) + : _spriteIndex(spriteIndex) + , _name(name) + { + } + + uint16_t GetSpriteIndex() const + { + return _spriteIndex; + } + + std::string GetGuestName() const + { + return _name; + } + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/GuestSetNameAction.hpp b/src/openrct2/actions/GuestSetNameAction.hpp deleted file mode 100644 index 9403bcc731..0000000000 --- a/src/openrct2/actions/GuestSetNameAction.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(GuestSetNameAction, GAME_COMMAND_SET_GUEST_NAME, GameActions::Result) -{ -private: - uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; - std::string _name; - -public: - GuestSetNameAction() = default; - GuestSetNameAction(uint16_t spriteIndex, const std::string& name) - : _spriteIndex(spriteIndex) - , _name(name) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("peep", _spriteIndex); - visitor.Visit("name", _name); - } - - uint16_t GetSpriteIndex() const - { - return _spriteIndex; - } - - std::string GetGuestName() const - { - return _name; - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_spriteIndex) << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteIndex >= MAX_SPRITES) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); - } - - auto guest = TryGetEntity(_spriteIndex); - if (guest == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto guest = TryGetEntity(_spriteIndex); - if (guest == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_NAME_GUEST, STR_NONE); - } - - auto curName = guest->GetName(); - if (curName == _name) - { - return std::make_unique(GameActions::Status::Ok, STR_NONE); - } - - if (!guest->SetName(_name)) - { - return std::make_unique(GameActions::Status::Unknown, STR_CANT_NAME_GUEST, STR_NONE); - } - - // Easter egg functions are for guests only - guest->HandleEasterEggName(); - - gfx_invalidate_screen(); - - auto intent = Intent(INTENT_ACTION_REFRESH_GUEST_LIST); - context_broadcast_intent(&intent); - - auto res = std::make_unique(); - res->Position.x = guest->x; - res->Position.y = guest->y; - res->Position.z = guest->z; - return res; - } -}; diff --git a/src/openrct2/actions/LandBuyRightsAction.cpp b/src/openrct2/actions/LandBuyRightsAction.cpp new file mode 100644 index 0000000000..152f95c9f9 --- /dev/null +++ b/src/openrct2/actions/LandBuyRightsAction.cpp @@ -0,0 +1,149 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "LandBuyRightsAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandSetHeightAction.h" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../util/Util.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandBuyRightsAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range) << DS_TAG(_setting); +} + +GameActions::Result::Ptr LandBuyRightsAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr LandBuyRightsAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr LandBuyRightsAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + + MapRange normRange = _range.Normalise(); + // Keep big coordinates within map boundaries + auto aX = std::max(32, normRange.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, normRange.GetRight()); + auto aY = std::max(32, normRange.GetTop()); + auto bY = std::min(gMapSizeMaxXY, normRange.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + CoordsXYZ centre{ (validRange.GetLeft() + validRange.GetRight()) / 2 + 16, + (validRange.GetTop() + validRange.GetBottom()) / 2 + 16, 0 }; + centre.z = tile_element_height(centre); + + res->Position = centre; + res->Expenditure = ExpenditureType::LandPurchase; + + // Game command modified to accept selection size + for (auto y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (auto x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + auto result = map_buy_land_rights_for_tile({ x, y }, isExecuting); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + } + } + } + if (isExecuting) + { + map_count_remaining_land_rights(); + } + return res; +} + +GameActions::Result::Ptr LandBuyRightsAction::map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const +{ + if (_setting >= LandBuyRightSetting::Count) + { + log_warning("Tried calling buy land rights with an incorrect setting. setting = %u", _setting); + return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[0], STR_NONE); + } + + SurfaceElement* surfaceElement = map_get_surface_element_at(loc); + if (surfaceElement == nullptr) + { + log_error("Could not find surface. x = %d, y = %d", loc.x, loc.y); + return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[EnumValue(_setting)], STR_NONE); + } + + auto res = MakeResult(); + switch (_setting) + { + case LandBuyRightSetting::BuyLand: // 0 + if ((surfaceElement->GetOwnership() & OWNERSHIP_OWNED) != 0) + { // If the land is already owned + return res; + } + + if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 + || (surfaceElement->GetOwnership() & OWNERSHIP_AVAILABLE) == 0) + { + return MakeResult(GameActions::Status::NotOwned, _ErrorTitles[EnumValue(_setting)], STR_LAND_NOT_FOR_SALE); + } + if (isExecuting) + { + surfaceElement->SetOwnership(OWNERSHIP_OWNED); + update_park_fences_around_tile(loc); + } + res->Cost = gLandPrice; + return res; + + case LandBuyRightSetting::BuyConstructionRights: // 2 + if ((surfaceElement->GetOwnership() & (OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)) != 0) + { // If the land or construction rights are already owned + return res; + } + + if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 + || (surfaceElement->GetOwnership() & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) == 0) + { + return MakeResult( + GameActions::Status::NotOwned, _ErrorTitles[EnumValue(_setting)], STR_CONSTRUCTION_RIGHTS_NOT_FOR_SALE); + } + + if (isExecuting) + { + surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED); + uint16_t baseZ = surfaceElement->GetBaseZ(); + map_invalidate_tile({ loc, baseZ, baseZ + 16 }); + } + res->Cost = gConstructionRightsPrice; + return res; + + default: + log_warning("Tried calling buy land rights with an incorrect setting. setting = %u", _setting); + return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[0], STR_NONE); + } +} diff --git a/src/openrct2/actions/LandBuyRightsAction.h b/src/openrct2/actions/LandBuyRightsAction.h new file mode 100644 index 0000000000..45390db603 --- /dev/null +++ b/src/openrct2/actions/LandBuyRightsAction.h @@ -0,0 +1,56 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +enum class LandBuyRightSetting : uint8_t +{ + BuyLand, + BuyConstructionRights, + Count +}; + +DEFINE_GAME_ACTION(LandBuyRightsAction, GAME_COMMAND_BUY_LAND_RIGHTS, GameActions::Result) +{ +private: + MapRange _range; + LandBuyRightSetting _setting{ LandBuyRightSetting::Count }; + + constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_BUY_LAND, STR_CANT_BUY_CONSTRUCTION_RIGHTS_HERE }; + +public: + LandBuyRightsAction() = default; + + LandBuyRightsAction(const MapRange& range, LandBuyRightSetting setting) + : _range(range) + , _setting(setting) + { + } + + LandBuyRightsAction(const CoordsXY& coord, LandBuyRightSetting setting) + : _range(coord.x, coord.y, coord.x, coord.y) + , _setting(setting) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; + GameActions::Result::Ptr map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LandBuyRightsAction.hpp b/src/openrct2/actions/LandBuyRightsAction.hpp deleted file mode 100644 index d6afbe25c6..0000000000 --- a/src/openrct2/actions/LandBuyRightsAction.hpp +++ /dev/null @@ -1,187 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../OpenRCT2.h" -#include "../actions/LandSetHeightAction.hpp" -#include "../audio/audio.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../util/Util.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -enum class LandBuyRightSetting : uint8_t -{ - BuyLand, - BuyConstructionRights, - Count -}; - -DEFINE_GAME_ACTION(LandBuyRightsAction, GAME_COMMAND_BUY_LAND_RIGHTS, GameActions::Result) -{ -private: - MapRange _range; - LandBuyRightSetting _setting{ LandBuyRightSetting::Count }; - - constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_BUY_LAND, STR_CANT_BUY_CONSTRUCTION_RIGHTS_HERE }; - -public: - LandBuyRightsAction() = default; - - LandBuyRightsAction(const MapRange& range, LandBuyRightSetting setting) - : _range(range) - , _setting(setting) - { - } - - LandBuyRightsAction(const CoordsXY& coord, LandBuyRightSetting setting) - : _range(coord.x, coord.y, coord.x, coord.y) - , _setting(setting) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range) << DS_TAG(_setting); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - MapRange normRange = _range.Normalise(); - // Keep big coordinates within map boundaries - auto aX = std::max(32, normRange.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, normRange.GetRight()); - auto aY = std::max(32, normRange.GetTop()); - auto bY = std::min(gMapSizeMaxXY, normRange.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - CoordsXYZ centre{ (validRange.GetLeft() + validRange.GetRight()) / 2 + 16, - (validRange.GetTop() + validRange.GetBottom()) / 2 + 16, 0 }; - centre.z = tile_element_height(centre); - - res->Position = centre; - res->Expenditure = ExpenditureType::LandPurchase; - - // Game command modified to accept selection size - for (auto y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (auto x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - auto result = map_buy_land_rights_for_tile({ x, y }, isExecuting); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - } - } - } - if (isExecuting) - { - map_count_remaining_land_rights(); - } - return res; - } - - GameActions::Result::Ptr map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const - { - if (_setting >= LandBuyRightSetting::Count) - { - log_warning("Tried calling buy land rights with an incorrect setting. setting = %u", _setting); - return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[0], STR_NONE); - } - - SurfaceElement* surfaceElement = map_get_surface_element_at(loc); - if (surfaceElement == nullptr) - { - log_error("Could not find surface. x = %d, y = %d", loc.x, loc.y); - return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[EnumValue(_setting)], STR_NONE); - } - - auto res = MakeResult(); - switch (_setting) - { - case LandBuyRightSetting::BuyLand: // 0 - if ((surfaceElement->GetOwnership() & OWNERSHIP_OWNED) != 0) - { // If the land is already owned - return res; - } - - if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 - || (surfaceElement->GetOwnership() & OWNERSHIP_AVAILABLE) == 0) - { - return MakeResult(GameActions::Status::NotOwned, _ErrorTitles[EnumValue(_setting)], STR_LAND_NOT_FOR_SALE); - } - if (isExecuting) - { - surfaceElement->SetOwnership(OWNERSHIP_OWNED); - update_park_fences_around_tile(loc); - } - res->Cost = gLandPrice; - return res; - - case LandBuyRightSetting::BuyConstructionRights: // 2 - if ((surfaceElement->GetOwnership() & (OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)) != 0) - { // If the land or construction rights are already owned - return res; - } - - if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 - || (surfaceElement->GetOwnership() & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) == 0) - { - return MakeResult( - GameActions::Status::NotOwned, _ErrorTitles[EnumValue(_setting)], STR_CONSTRUCTION_RIGHTS_NOT_FOR_SALE); - } - - if (isExecuting) - { - surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED); - uint16_t baseZ = surfaceElement->GetBaseZ(); - map_invalidate_tile({ loc, baseZ, baseZ + 16 }); - } - res->Cost = gConstructionRightsPrice; - return res; - - default: - log_warning("Tried calling buy land rights with an incorrect setting. setting = %u", _setting); - return MakeResult(GameActions::Status::InvalidParameters, _ErrorTitles[0], STR_NONE); - } - } -}; diff --git a/src/openrct2/actions/LandLowerAction.cpp b/src/openrct2/actions/LandLowerAction.cpp new file mode 100644 index 0000000000..44bdbcf0ff --- /dev/null +++ b/src/openrct2/actions/LandLowerAction.cpp @@ -0,0 +1,136 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "LandLowerAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandSetHeightAction.h" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandLowerAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType); +} + +GameActions::Result::Ptr LandLowerAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr LandLowerAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr LandLowerAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + size_t tableRow = _selectionType; + + // The selections between MAP_SELECT_TYPE_FULL and MAP_SELECT_TYPE_EDGE_0 are not included in the tables + if (_selectionType >= MAP_SELECT_TYPE_EDGE_0 && _selectionType <= MAP_SELECT_TYPE_EDGE_3) + tableRow -= MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1; + + // Keep big coordinates within map boundaries + auto aX = std::max(32, _range.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); + auto aY = std::max(32, _range.GetTop()); + auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + res->Position = { _coords.x, _coords.y, tile_element_height(_coords) }; + res->Expenditure = ExpenditureType::Landscaping; + + if (isExecuting) + { + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, tile_element_height(_coords) }); + } + + uint8_t maxHeight = map_get_highest_land_height(validRange); + bool withinOwnership = false; + + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + withinOwnership = true; + + uint8_t height = surfaceElement->base_height; + if (surfaceElement->GetSlope() & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) + height += 2; + if (surfaceElement->GetSlope() & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) + height += 2; + + if (height < maxHeight) + continue; + + height = surfaceElement->base_height; + uint8_t currentSlope = surfaceElement->GetSlope(); + uint8_t newSlope = tile_element_lower_styles[tableRow][currentSlope]; + if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + height -= 2; + + newSlope &= TILE_ELEMENT_SURFACE_SLOPE_MASK; + + auto landSetHeightAction = LandSetHeightAction({ x, y }, height, newSlope); + landSetHeightAction.SetFlags(GetFlags()); + auto result = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) + : GameActions::QueryNested(&landSetHeightAction); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + } + else + { + result->ErrorTitle = STR_CANT_LOWER_LAND_HERE; + return result; + } + } + } + + if (!withinOwnership) + { + GameActions::Result::Ptr ownerShipResult = std::make_unique( + GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + ownerShipResult->ErrorTitle = STR_CANT_LOWER_LAND_HERE; + return ownerShipResult; + } + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + return res; +} diff --git a/src/openrct2/actions/LandLowerAction.h b/src/openrct2/actions/LandLowerAction.h new file mode 100644 index 0000000000..27a487b7ef --- /dev/null +++ b/src/openrct2/actions/LandLowerAction.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(LandLowerAction, GAME_COMMAND_LOWER_LAND, GameActions::Result) +{ +private: + CoordsXY _coords; + MapRange _range; + uint8_t _selectionType{}; + +public: + LandLowerAction() = default; + LandLowerAction(const CoordsXY& coords, MapRange range, uint8_t selectionType) + : _coords(coords) + , _range(range) + , _selectionType(selectionType) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LandLowerAction.hpp b/src/openrct2/actions/LandLowerAction.hpp deleted file mode 100644 index fbe53edbad..0000000000 --- a/src/openrct2/actions/LandLowerAction.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../OpenRCT2.h" -#include "../actions/LandSetHeightAction.hpp" -#include "../audio/audio.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LandLowerAction, GAME_COMMAND_LOWER_LAND, GameActions::Result) -{ -private: - CoordsXY _coords; - MapRange _range; - uint8_t _selectionType{}; - -public: - LandLowerAction() = default; - LandLowerAction(const CoordsXY& coords, MapRange range, uint8_t selectionType) - : _coords(coords) - , _range(range) - , _selectionType(selectionType) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - size_t tableRow = _selectionType; - - // The selections between MAP_SELECT_TYPE_FULL and MAP_SELECT_TYPE_EDGE_0 are not included in the tables - if (_selectionType >= MAP_SELECT_TYPE_EDGE_0 && _selectionType <= MAP_SELECT_TYPE_EDGE_3) - tableRow -= MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1; - - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - res->Position = { _coords.x, _coords.y, tile_element_height(_coords) }; - res->Expenditure = ExpenditureType::Landscaping; - - if (isExecuting) - { - OpenRCT2::Audio::Play3D( - OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, tile_element_height(_coords) }); - } - - uint8_t maxHeight = map_get_highest_land_height(validRange); - bool withinOwnership = false; - - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - withinOwnership = true; - - uint8_t height = surfaceElement->base_height; - if (surfaceElement->GetSlope() & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) - height += 2; - if (surfaceElement->GetSlope() & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) - height += 2; - - if (height < maxHeight) - continue; - - height = surfaceElement->base_height; - uint8_t currentSlope = surfaceElement->GetSlope(); - uint8_t newSlope = tile_element_lower_styles[tableRow][currentSlope]; - if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - height -= 2; - - newSlope &= TILE_ELEMENT_SURFACE_SLOPE_MASK; - - auto landSetHeightAction = LandSetHeightAction({ x, y }, height, newSlope); - landSetHeightAction.SetFlags(GetFlags()); - auto result = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - } - else - { - result->ErrorTitle = STR_CANT_LOWER_LAND_HERE; - return result; - } - } - } - - if (!withinOwnership) - { - GameActions::Result::Ptr ownerShipResult = std::make_unique( - GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - ownerShipResult->ErrorTitle = STR_CANT_LOWER_LAND_HERE; - return ownerShipResult; - } - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - return res; - } -}; diff --git a/src/openrct2/actions/LandRaiseAction.cpp b/src/openrct2/actions/LandRaiseAction.cpp new file mode 100644 index 0000000000..05ec2046c6 --- /dev/null +++ b/src/openrct2/actions/LandRaiseAction.cpp @@ -0,0 +1,132 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "LandRaiseAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandSetHeightAction.h" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandRaiseAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType); +} + +GameActions::Result::Ptr LandRaiseAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr LandRaiseAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr LandRaiseAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + size_t tableRow = _selectionType; + + // The selections between MAP_SELECT_TYPE_FULL and MAP_SELECT_TYPE_EDGE_0 are not included in the tables + if (_selectionType >= MAP_SELECT_TYPE_EDGE_0 && _selectionType <= MAP_SELECT_TYPE_EDGE_3) + tableRow -= MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1; + + // Keep big coordinates within map boundaries + auto aX = std::max(32, _range.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); + auto aY = std::max(32, _range.GetTop()); + auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + res->Position = { _coords.x, _coords.y, tile_element_height(_coords) }; + res->Expenditure = ExpenditureType::Landscaping; + + if (isExecuting) + { + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, tile_element_height(_coords) }); + } + + uint8_t minHeight = map_get_lowest_land_height(validRange); + bool withinOwnership = false; + + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + withinOwnership = true; + + uint8_t height = surfaceElement->base_height; + + if (height > minHeight) + continue; + + uint8_t currentSlope = surfaceElement->GetSlope(); + uint8_t newSlope = tile_element_raise_styles[tableRow][currentSlope]; + if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + height += 2; + + newSlope &= TILE_ELEMENT_SURFACE_SLOPE_MASK; + + auto landSetHeightAction = LandSetHeightAction({ x, y }, height, newSlope); + landSetHeightAction.SetFlags(GetFlags()); + auto result = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) + : GameActions::QueryNested(&landSetHeightAction); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + } + else + { + result->ErrorTitle = STR_CANT_RAISE_LAND_HERE; + return result; + } + } + } + + if (!withinOwnership) + { + GameActions::Result::Ptr ownerShipResult = std::make_unique( + GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + ownerShipResult->ErrorTitle = STR_CANT_RAISE_LAND_HERE; + return ownerShipResult; + } + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + return res; +} diff --git a/src/openrct2/actions/LandRaiseAction.h b/src/openrct2/actions/LandRaiseAction.h new file mode 100644 index 0000000000..6fd05c9169 --- /dev/null +++ b/src/openrct2/actions/LandRaiseAction.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(LandRaiseAction, GAME_COMMAND_RAISE_LAND, GameActions::Result) +{ +private: + CoordsXY _coords; + MapRange _range; + uint8_t _selectionType{}; + +public: + LandRaiseAction() = default; + LandRaiseAction(const CoordsXY& coords, MapRange range, uint8_t selectionType) + : _coords(coords) + , _range(range) + , _selectionType(selectionType) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LandRaiseAction.hpp b/src/openrct2/actions/LandRaiseAction.hpp deleted file mode 100644 index ebf293cd17..0000000000 --- a/src/openrct2/actions/LandRaiseAction.hpp +++ /dev/null @@ -1,157 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../OpenRCT2.h" -#include "../actions/LandSetHeightAction.hpp" -#include "../audio/audio.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LandRaiseAction, GAME_COMMAND_RAISE_LAND, GameActions::Result) -{ -private: - CoordsXY _coords; - MapRange _range; - uint8_t _selectionType{}; - -public: - LandRaiseAction() = default; - LandRaiseAction(const CoordsXY& coords, MapRange range, uint8_t selectionType) - : _coords(coords) - , _range(range) - , _selectionType(selectionType) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - size_t tableRow = _selectionType; - - // The selections between MAP_SELECT_TYPE_FULL and MAP_SELECT_TYPE_EDGE_0 are not included in the tables - if (_selectionType >= MAP_SELECT_TYPE_EDGE_0 && _selectionType <= MAP_SELECT_TYPE_EDGE_3) - tableRow -= MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1; - - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - res->Position = { _coords.x, _coords.y, tile_element_height(_coords) }; - res->Expenditure = ExpenditureType::Landscaping; - - if (isExecuting) - { - OpenRCT2::Audio::Play3D( - OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, tile_element_height(_coords) }); - } - - uint8_t minHeight = map_get_lowest_land_height(validRange); - bool withinOwnership = false; - - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - withinOwnership = true; - - uint8_t height = surfaceElement->base_height; - - if (height > minHeight) - continue; - - uint8_t currentSlope = surfaceElement->GetSlope(); - uint8_t newSlope = tile_element_raise_styles[tableRow][currentSlope]; - if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - height += 2; - - newSlope &= TILE_ELEMENT_SURFACE_SLOPE_MASK; - - auto landSetHeightAction = LandSetHeightAction({ x, y }, height, newSlope); - landSetHeightAction.SetFlags(GetFlags()); - auto result = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - } - else - { - result->ErrorTitle = STR_CANT_RAISE_LAND_HERE; - return result; - } - } - } - - if (!withinOwnership) - { - GameActions::Result::Ptr ownerShipResult = std::make_unique( - GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - ownerShipResult->ErrorTitle = STR_CANT_RAISE_LAND_HERE; - return ownerShipResult; - } - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - return res; - } -}; diff --git a/src/openrct2/actions/LandSetHeightAction.cpp b/src/openrct2/actions/LandSetHeightAction.cpp new file mode 100644 index 0000000000..4ffc5f77cf --- /dev/null +++ b/src/openrct2/actions/LandSetHeightAction.cpp @@ -0,0 +1,374 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "LandSetHeightAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/SmallScenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandSetHeightAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_height) << DS_TAG(_style); +} + +GameActions::Result::Ptr LandSetHeightAction::Query() const +{ + if (gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) + { + return std::make_unique(GameActions::Status::Disallowed, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); + } + + rct_string_id errorTitle = CheckParameters(); + if (errorTitle != STR_NONE) + { + return std::make_unique(GameActions::Status::Disallowed, errorTitle); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(_coords)) + { + return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + money32 sceneryRemovalCost = 0; + if (!gCheatsDisableClearanceChecks) + { + if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) + { + // Check for obstructing large trees + TileElement* tileElement = CheckTreeObstructions(); + if (tileElement != nullptr) + { + auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); + map_obstruction_set_error_text(tileElement, *res); + return res; + } + } + sceneryRemovalCost = GetSmallSceneryRemovalCost(); + } + + // Check for ride support limits + if (!gCheatsDisableSupportLimits) + { + errorTitle = CheckRideSupports(); + if (errorTitle != STR_NONE) + { + return std::make_unique(GameActions::Status::Disallowed, errorTitle); + } + } + + auto* surfaceElement = map_get_surface_element_at(_coords); + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + // We need to check if there is _currently_ a level crossing on the tile. + // For that, we need the old height, so we can't use the _height variable. + auto oldCoords = CoordsXYZ{ _coords, surfaceElement->GetBaseZ() }; + auto* pathElement = map_get_footpath_element(oldCoords); + if (pathElement != nullptr && pathElement->AsPath()->IsLevelCrossing(oldCoords)) + { + return MakeResult(GameActions::Status::Disallowed, STR_REMOVE_LEVEL_CROSSING_FIRST); + } + + TileElement* tileElement = CheckFloatingStructures(reinterpret_cast(surfaceElement), _height); + if (tileElement != nullptr) + { + auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); + map_obstruction_set_error_text(tileElement, *res); + return res; + } + + if (!gCheatsDisableClearanceChecks) + { + uint8_t zCorner = _height; + if (_style & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) + { + zCorner += 2; + if (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) + { + zCorner += 2; + } + } + + auto clearResult = MapCanConstructWithClearAt( + { _coords, _height * COORDS_Z_STEP, zCorner * COORDS_Z_STEP }, &map_set_land_height_clear_func, { 0b1111, 0 }, 0, + CREATE_CROSSING_MODE_NONE); + if (clearResult->Error != GameActions::Status::Ok) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_NONE, clearResult->ErrorMessage.GetStringId(), + clearResult->ErrorMessageArgs.data()); + } + + tileElement = CheckUnremovableObstructions(reinterpret_cast(surfaceElement), zCorner); + if (tileElement != nullptr) + { + auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); + map_obstruction_set_error_text(tileElement, *res); + return res; + } + } + auto res = std::make_unique(); + res->Cost = sceneryRemovalCost + GetSurfaceHeightChangeCost(surfaceElement); + res->Expenditure = ExpenditureType::Landscaping; + return res; +} + +GameActions::Result::Ptr LandSetHeightAction::Execute() const +{ + money32 cost = MONEY(0, 0); + auto surfaceHeight = tile_element_height(_coords); + footpath_remove_litter({ _coords, surfaceHeight }); + + if (!gCheatsDisableClearanceChecks) + { + wall_remove_at({ _coords, _height * 8 - 16, _height * 8 + 32 }); + cost += GetSmallSceneryRemovalCost(); + SmallSceneryRemoval(); + } + + auto* surfaceElement = map_get_surface_element_at(_coords); + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + cost += GetSurfaceHeightChangeCost(surfaceElement); + SetSurfaceHeight(reinterpret_cast(surfaceElement)); + + auto res = std::make_unique(); + res->Position = { _coords.x + 16, _coords.y + 16, surfaceHeight }; + res->Cost = cost; + res->Expenditure = ExpenditureType::Landscaping; + return res; +} + +rct_string_id LandSetHeightAction::CheckParameters() const +{ + if (!LocationValid(_coords)) + { + return STR_OFF_EDGE_OF_MAP; + } + + if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY) + { + return STR_OFF_EDGE_OF_MAP; + } + + if (_height < MINIMUM_LAND_HEIGHT) + { + return STR_TOO_LOW; + } + + // Divide by 2 and subtract 7 to get the in-game units. + if (_height > MAXIMUM_LAND_HEIGHT) + { + return STR_TOO_HIGH; + } + else if (_height > MAXIMUM_LAND_HEIGHT - 2 && (_style & TILE_ELEMENT_SURFACE_SLOPE_MASK) != 0) + { + return STR_TOO_HIGH; + } + + if (_height == MAXIMUM_LAND_HEIGHT - 2 && (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG)) + { + return STR_TOO_HIGH; + } + + return STR_NONE; +} + +TileElement* LandSetHeightAction::CheckTreeObstructions() const +{ + TileElement* tileElement = map_get_first_element_at(_coords); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) + continue; + if (_height > tileElement->clearance_height) + continue; + if (_height + 4 < tileElement->base_height) + continue; + rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry(); + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_IS_TREE)) + { + return tileElement; + } + } while (!(tileElement++)->IsLastForTile()); + return nullptr; +} + +money32 LandSetHeightAction::GetSmallSceneryRemovalCost() const +{ + money32 cost{ 0 }; + TileElement* tileElement = map_get_first_element_at(_coords); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) + continue; + if (_height > tileElement->clearance_height) + continue; + if (_height + 4 < tileElement->base_height) + continue; + rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry(); + cost += MONEY(sceneryEntry->small_scenery.removal_price, 0); + } while (!(tileElement++)->IsLastForTile()); + return cost; +} + +void LandSetHeightAction::SmallSceneryRemoval() const +{ + TileElement* tileElement = map_get_first_element_at(_coords); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) + continue; + if (_height > tileElement->clearance_height) + continue; + if (_height + 4 < tileElement->base_height) + continue; + tile_element_remove(tileElement--); + } while (!(tileElement++)->IsLastForTile()); +} + +rct_string_id LandSetHeightAction::CheckRideSupports() const +{ + TileElement* tileElement = map_get_first_element_at(_coords); + do + { + if (tileElement == nullptr) + break; + if (tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK) + { + ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); + auto ride = get_ride(rideIndex); + if (ride != nullptr) + { + rct_ride_entry* rideEntry = ride->GetRideEntry(); + if (rideEntry != nullptr) + { + int32_t maxHeight = rideEntry->max_height; + if (maxHeight == 0) + { + maxHeight = RideTypeDescriptors[ride->type].Heights.MaxHeight; + } + int32_t zDelta = tileElement->clearance_height - _height; + if (zDelta >= 0 && zDelta / 2 > maxHeight) + { + return STR_SUPPORTS_CANT_BE_EXTENDED; + } + } + } + } + } while (!(tileElement++)->IsLastForTile()); + return STR_NONE; +} + +TileElement* LandSetHeightAction::CheckFloatingStructures(TileElement* surfaceElement, uint8_t zCorner) const +{ + if (surfaceElement->AsSurface()->HasTrackThatNeedsWater()) + { + uint32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight(); + if (waterHeight != 0) + { + if (_style & TILE_ELEMENT_SURFACE_SLOPE_MASK) + { + zCorner += 2; + if (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) + { + zCorner += 2; + } + } + if (zCorner > (waterHeight / COORDS_Z_STEP) - 2) + { + return ++surfaceElement; + } + } + } + return nullptr; +} + +TileElement* LandSetHeightAction::CheckUnremovableObstructions(TileElement* surfaceElement, uint8_t zCorner) const +{ + TileElement* tileElement = map_get_first_element_at(_coords); + do + { + if (tileElement == nullptr) + break; + int32_t elementType = tileElement->GetType(); + + // Wall's and Small Scenery are removed and therefore do not need checked + if (elementType == TILE_ELEMENT_TYPE_WALL) + continue; + if (elementType == TILE_ELEMENT_TYPE_SMALL_SCENERY) + continue; + if (tileElement->IsGhost()) + continue; + if (tileElement == surfaceElement) + continue; + if (tileElement > surfaceElement) + { + if (zCorner > tileElement->base_height) + { + return tileElement; + } + continue; + } + if (_height < tileElement->clearance_height) + { + return tileElement; + } + } while (!(tileElement++)->IsLastForTile()); + return nullptr; +} + +money32 LandSetHeightAction::GetSurfaceHeightChangeCost(SurfaceElement* surfaceElement) const +{ + money32 cost{ 0 }; + for (Direction i : ALL_DIRECTIONS) + { + int32_t cornerHeight = tile_element_get_corner_height(surfaceElement, i); + cornerHeight -= map_get_corner_height(_height, _style & TILE_ELEMENT_SURFACE_SLOPE_MASK, i); + cost += MONEY(abs(cornerHeight) * 5 / 2, 0); + } + return cost; +} + +void LandSetHeightAction::SetSurfaceHeight(TileElement* surfaceElement) const +{ + surfaceElement->base_height = _height; + surfaceElement->clearance_height = _height; + surfaceElement->AsSurface()->SetSlope(_style); + int32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight() / COORDS_Z_STEP; + if (waterHeight != 0 && waterHeight <= _height) + { + surfaceElement->AsSurface()->SetWaterHeight(0); + } + + map_invalidate_tile_full(_coords); +} diff --git a/src/openrct2/actions/LandSetHeightAction.h b/src/openrct2/actions/LandSetHeightAction.h new file mode 100644 index 0000000000..2e30e48aa8 --- /dev/null +++ b/src/openrct2/actions/LandSetHeightAction.h @@ -0,0 +1,66 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(LandSetHeightAction, GAME_COMMAND_SET_LAND_HEIGHT, GameActions::Result) +{ +private: + CoordsXY _coords; + uint8_t _height{}; + uint8_t _style{}; + +public: + LandSetHeightAction() = default; + LandSetHeightAction(const CoordsXY& coords, uint8_t height, uint8_t style) + : _coords(coords) + , _height(height) + , _style(style) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + rct_string_id CheckParameters() const; + TileElement* CheckTreeObstructions() const; + money32 GetSmallSceneryRemovalCost() const; + void SmallSceneryRemoval() const; + rct_string_id CheckRideSupports() const; + TileElement* CheckFloatingStructures(TileElement * surfaceElement, uint8_t zCorner) const; + TileElement* CheckUnremovableObstructions(TileElement * surfaceElement, uint8_t zCorner) const; + money32 GetSurfaceHeightChangeCost(SurfaceElement * surfaceElement) const; + void SetSurfaceHeight(TileElement * surfaceElement) const; + + /** + * + * rct2: 0x00663CB9 + */ + static int32_t map_set_land_height_clear_func( + TileElement * *tile_element, [[maybe_unused]] const CoordsXY& coords, [[maybe_unused]] uint8_t flags, + [[maybe_unused]] money32* price) + { + if ((*tile_element)->GetType() == TILE_ELEMENT_TYPE_SURFACE) + return 0; + + if ((*tile_element)->GetType() == TILE_ELEMENT_TYPE_SMALL_SCENERY) + return 0; + + return 1; + } +}; diff --git a/src/openrct2/actions/LandSetHeightAction.hpp b/src/openrct2/actions/LandSetHeightAction.hpp deleted file mode 100644 index bee949649e..0000000000 --- a/src/openrct2/actions/LandSetHeightAction.hpp +++ /dev/null @@ -1,415 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../OpenRCT2.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/SmallScenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LandSetHeightAction, GAME_COMMAND_SET_LAND_HEIGHT, GameActions::Result) -{ -private: - CoordsXY _coords; - uint8_t _height{}; - uint8_t _style{}; - -public: - LandSetHeightAction() = default; - LandSetHeightAction(const CoordsXY& coords, uint8_t height, uint8_t style) - : _coords(coords) - , _height(height) - , _style(style) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_coords) << DS_TAG(_height) << DS_TAG(_style); - } - - GameActions::Result::Ptr Query() const override - { - if (gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) - { - return std::make_unique(GameActions::Status::Disallowed, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); - } - - rct_string_id errorTitle = CheckParameters(); - if (errorTitle != STR_NONE) - { - return std::make_unique(GameActions::Status::Disallowed, errorTitle); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(_coords)) - { - return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - money32 sceneryRemovalCost = 0; - if (!gCheatsDisableClearanceChecks) - { - if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) - { - // Check for obstructing large trees - TileElement* tileElement = CheckTreeObstructions(); - if (tileElement != nullptr) - { - auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); - map_obstruction_set_error_text(tileElement, *res); - return res; - } - } - sceneryRemovalCost = GetSmallSceneryRemovalCost(); - } - - // Check for ride support limits - if (!gCheatsDisableSupportLimits) - { - errorTitle = CheckRideSupports(); - if (errorTitle != STR_NONE) - { - return std::make_unique(GameActions::Status::Disallowed, errorTitle); - } - } - - auto* surfaceElement = map_get_surface_element_at(_coords); - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - // We need to check if there is _currently_ a level crossing on the tile. - // For that, we need the old height, so we can't use the _height variable. - auto oldCoords = CoordsXYZ{ _coords, surfaceElement->GetBaseZ() }; - auto* pathElement = map_get_footpath_element(oldCoords); - if (pathElement != nullptr && pathElement->AsPath()->IsLevelCrossing(oldCoords)) - { - return MakeResult(GameActions::Status::Disallowed, STR_REMOVE_LEVEL_CROSSING_FIRST); - } - - TileElement* tileElement = CheckFloatingStructures(reinterpret_cast(surfaceElement), _height); - if (tileElement != nullptr) - { - auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); - map_obstruction_set_error_text(tileElement, *res); - return res; - } - - if (!gCheatsDisableClearanceChecks) - { - uint8_t zCorner = _height; - if (_style & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) - { - zCorner += 2; - if (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) - { - zCorner += 2; - } - } - - auto clearResult = MapCanConstructWithClearAt( - { _coords, _height * COORDS_Z_STEP, zCorner * COORDS_Z_STEP }, &map_set_land_height_clear_func, { 0b1111, 0 }, - 0, CREATE_CROSSING_MODE_NONE); - if (clearResult->Error != GameActions::Status::Ok) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_NONE, clearResult->ErrorMessage.GetStringId(), - clearResult->ErrorMessageArgs.data()); - } - - tileElement = CheckUnremovableObstructions(reinterpret_cast(surfaceElement), zCorner); - if (tileElement != nullptr) - { - auto res = MakeResult(GameActions::Status::Disallowed, STR_NONE); - map_obstruction_set_error_text(tileElement, *res); - return res; - } - } - auto res = std::make_unique(); - res->Cost = sceneryRemovalCost + GetSurfaceHeightChangeCost(surfaceElement); - res->Expenditure = ExpenditureType::Landscaping; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - money32 cost = MONEY(0, 0); - auto surfaceHeight = tile_element_height(_coords); - footpath_remove_litter({ _coords, surfaceHeight }); - - if (!gCheatsDisableClearanceChecks) - { - wall_remove_at({ _coords, _height * 8 - 16, _height * 8 + 32 }); - cost += GetSmallSceneryRemovalCost(); - SmallSceneryRemoval(); - } - - auto* surfaceElement = map_get_surface_element_at(_coords); - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - cost += GetSurfaceHeightChangeCost(surfaceElement); - SetSurfaceHeight(reinterpret_cast(surfaceElement)); - - auto res = std::make_unique(); - res->Position = { _coords.x + 16, _coords.y + 16, surfaceHeight }; - res->Cost = cost; - res->Expenditure = ExpenditureType::Landscaping; - return res; - } - -private: - rct_string_id CheckParameters() const - { - if (!LocationValid(_coords)) - { - return STR_OFF_EDGE_OF_MAP; - } - - if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY) - { - return STR_OFF_EDGE_OF_MAP; - } - - if (_height < MINIMUM_LAND_HEIGHT) - { - return STR_TOO_LOW; - } - - // Divide by 2 and subtract 7 to get the in-game units. - if (_height > MAXIMUM_LAND_HEIGHT) - { - return STR_TOO_HIGH; - } - else if (_height > MAXIMUM_LAND_HEIGHT - 2 && (_style & TILE_ELEMENT_SURFACE_SLOPE_MASK) != 0) - { - return STR_TOO_HIGH; - } - - if (_height == MAXIMUM_LAND_HEIGHT - 2 && (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG)) - { - return STR_TOO_HIGH; - } - - return STR_NONE; - } - - TileElement* CheckTreeObstructions() const - { - TileElement* tileElement = map_get_first_element_at(_coords); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - continue; - if (_height > tileElement->clearance_height) - continue; - if (_height + 4 < tileElement->base_height) - continue; - rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry(); - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_IS_TREE)) - { - return tileElement; - } - } while (!(tileElement++)->IsLastForTile()); - return nullptr; - } - - money32 GetSmallSceneryRemovalCost() const - { - money32 cost{ 0 }; - TileElement* tileElement = map_get_first_element_at(_coords); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - continue; - if (_height > tileElement->clearance_height) - continue; - if (_height + 4 < tileElement->base_height) - continue; - rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry(); - cost += MONEY(sceneryEntry->small_scenery.removal_price, 0); - } while (!(tileElement++)->IsLastForTile()); - return cost; - } - - void SmallSceneryRemoval() const - { - TileElement* tileElement = map_get_first_element_at(_coords); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - continue; - if (_height > tileElement->clearance_height) - continue; - if (_height + 4 < tileElement->base_height) - continue; - tile_element_remove(tileElement--); - } while (!(tileElement++)->IsLastForTile()); - } - - rct_string_id CheckRideSupports() const - { - TileElement* tileElement = map_get_first_element_at(_coords); - do - { - if (tileElement == nullptr) - break; - if (tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK) - { - ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); - auto ride = get_ride(rideIndex); - if (ride != nullptr) - { - rct_ride_entry* rideEntry = ride->GetRideEntry(); - if (rideEntry != nullptr) - { - int32_t maxHeight = rideEntry->max_height; - if (maxHeight == 0) - { - maxHeight = RideTypeDescriptors[ride->type].Heights.MaxHeight; - } - int32_t zDelta = tileElement->clearance_height - _height; - if (zDelta >= 0 && zDelta / 2 > maxHeight) - { - return STR_SUPPORTS_CANT_BE_EXTENDED; - } - } - } - } - } while (!(tileElement++)->IsLastForTile()); - return STR_NONE; - } - - TileElement* CheckFloatingStructures(TileElement * surfaceElement, uint8_t zCorner) const - { - if (surfaceElement->AsSurface()->HasTrackThatNeedsWater()) - { - uint32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight(); - if (waterHeight != 0) - { - if (_style & TILE_ELEMENT_SURFACE_SLOPE_MASK) - { - zCorner += 2; - if (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG) - { - zCorner += 2; - } - } - if (zCorner > (waterHeight / COORDS_Z_STEP) - 2) - { - return ++surfaceElement; - } - } - } - return nullptr; - } - - TileElement* CheckUnremovableObstructions(TileElement * surfaceElement, uint8_t zCorner) const - { - TileElement* tileElement = map_get_first_element_at(_coords); - do - { - if (tileElement == nullptr) - break; - int32_t elementType = tileElement->GetType(); - - // Wall's and Small Scenery are removed and therefore do not need checked - if (elementType == TILE_ELEMENT_TYPE_WALL) - continue; - if (elementType == TILE_ELEMENT_TYPE_SMALL_SCENERY) - continue; - if (tileElement->IsGhost()) - continue; - if (tileElement == surfaceElement) - continue; - if (tileElement > surfaceElement) - { - if (zCorner > tileElement->base_height) - { - return tileElement; - } - continue; - } - if (_height < tileElement->clearance_height) - { - return tileElement; - } - } while (!(tileElement++)->IsLastForTile()); - return nullptr; - } - - money32 GetSurfaceHeightChangeCost(SurfaceElement * surfaceElement) const - { - money32 cost{ 0 }; - for (Direction i : ALL_DIRECTIONS) - { - int32_t cornerHeight = tile_element_get_corner_height(surfaceElement, i); - cornerHeight -= map_get_corner_height(_height, _style & TILE_ELEMENT_SURFACE_SLOPE_MASK, i); - cost += MONEY(abs(cornerHeight) * 5 / 2, 0); - } - return cost; - } - - void SetSurfaceHeight(TileElement * surfaceElement) const - { - surfaceElement->base_height = _height; - surfaceElement->clearance_height = _height; - surfaceElement->AsSurface()->SetSlope(_style); - int32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight() / COORDS_Z_STEP; - if (waterHeight != 0 && waterHeight <= _height) - { - surfaceElement->AsSurface()->SetWaterHeight(0); - } - - map_invalidate_tile_full(_coords); - } - - /** - * - * rct2: 0x00663CB9 - */ - static int32_t map_set_land_height_clear_func( - TileElement * *tile_element, [[maybe_unused]] const CoordsXY& coords, [[maybe_unused]] uint8_t flags, - [[maybe_unused]] money32* price) - { - if ((*tile_element)->GetType() == TILE_ELEMENT_TYPE_SURFACE) - return 0; - - if ((*tile_element)->GetType() == TILE_ELEMENT_TYPE_SMALL_SCENERY) - return 0; - - return 1; - } -}; diff --git a/src/openrct2/actions/LandSetRightsAction.cpp b/src/openrct2/actions/LandSetRightsAction.cpp new file mode 100644 index 0000000000..57df0615f2 --- /dev/null +++ b/src/openrct2/actions/LandSetRightsAction.cpp @@ -0,0 +1,193 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "LandSetRightsAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandSetHeightAction.h" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../util/Util.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandSetRightsAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range) << DS_TAG(_setting) << DS_TAG(_ownership); +} + +GameActions::Result::Ptr LandSetRightsAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr LandSetRightsAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr LandSetRightsAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + + MapRange normRange = _range.Normalise(); + // Keep big coordinates within map boundaries + auto aX = std::max(32, normRange.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, normRange.GetRight()); + auto aY = std::max(32, normRange.GetTop()); + auto bY = std::min(gMapSizeMaxXY, normRange.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + CoordsXYZ centre{ (validRange.GetLeft() + validRange.GetRight()) / 2 + 16, + (validRange.GetTop() + validRange.GetBottom()) / 2 + 16, 0 }; + centre.z = tile_element_height(centre); + + res->Position = centre; + res->Expenditure = ExpenditureType::LandPurchase; + + if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) + { + return MakeResult(GameActions::Status::NotInEditorMode, STR_NONE, STR_LAND_NOT_FOR_SALE); + } + + // Game command modified to accept selection size + for (auto y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (auto x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + auto result = map_buy_land_rights_for_tile({ x, y }, isExecuting); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + } + } + } + + if (isExecuting) + { + map_count_remaining_land_rights(); + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, centre); + } + return res; +} + +GameActions::Result::Ptr LandSetRightsAction::map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const +{ + SurfaceElement* surfaceElement = map_get_surface_element_at(loc); + if (surfaceElement == nullptr) + { + log_error("Could not find surface. x = %d, y = %d", loc.x, loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); + } + + auto res = MakeResult(); + switch (_setting) + { + case LandSetRightSetting::UnownLand: + if (isExecuting) + { + surfaceElement->SetOwnership( + surfaceElement->GetOwnership() & ~(OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)); + update_park_fences_around_tile(loc); + } + return res; + case LandSetRightSetting::UnownConstructionRights: + if (isExecuting) + { + surfaceElement->SetOwnership(surfaceElement->GetOwnership() & ~OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED); + uint16_t baseZ = surfaceElement->GetBaseZ(); + map_invalidate_tile({ loc, baseZ, baseZ + 16 }); + } + return res; + case LandSetRightSetting::SetForSale: + if (isExecuting) + { + surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_AVAILABLE); + uint16_t baseZ = surfaceElement->GetBaseZ(); + map_invalidate_tile({ loc, baseZ, baseZ + 16 }); + } + return res; + case LandSetRightSetting::SetConstructionRightsForSale: + if (isExecuting) + { + surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE); + uint16_t baseZ = surfaceElement->GetBaseZ(); + map_invalidate_tile({ loc, baseZ, baseZ + 16 }); + } + return res; + case LandSetRightSetting::SetOwnershipWithChecks: + { + if (_ownership == surfaceElement->GetOwnership()) + { + return res; + } + + TileElement* tileElement = map_get_first_element_at(loc); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() != ENTRANCE_TYPE_PARK_ENTRANCE) + continue; + + // Do not allow ownership of park entrance. + if (_ownership == OWNERSHIP_OWNED || _ownership == OWNERSHIP_AVAILABLE) + return res; + + // Allow construction rights available / for sale on park entrances on surface. + // There is no need to check the height if _ownership is 0 (unowned and no rights available). + if (_ownership == OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED || _ownership == OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) + { + if (tileElement->base_height - 3 > surfaceElement->base_height + || tileElement->base_height < surfaceElement->base_height) + return res; + } + } while (!(tileElement++)->IsLastForTile()); + + res->Cost = gLandPrice; + if (isExecuting) + { + if (_ownership != OWNERSHIP_UNOWNED) + { + gPeepSpawns.erase( + std::remove_if( + gPeepSpawns.begin(), gPeepSpawns.end(), + [x = loc.x, y = loc.y](const auto& spawn) { + return floor2(spawn.x, 32) == x && floor2(spawn.y, 32) == y; + }), + gPeepSpawns.end()); + } + surfaceElement->SetOwnership(_ownership); + update_park_fences_around_tile(loc); + gMapLandRightsUpdateSuccess = true; + } + return res; + } + default: + log_warning("Tried calling set land rights with an incorrect setting. setting = %u", _setting); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); + } +} diff --git a/src/openrct2/actions/LandSetRightsAction.h b/src/openrct2/actions/LandSetRightsAction.h new file mode 100644 index 0000000000..7cfd4c3c18 --- /dev/null +++ b/src/openrct2/actions/LandSetRightsAction.h @@ -0,0 +1,60 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +enum class LandSetRightSetting : uint8_t +{ + UnownLand, + UnownConstructionRights, + SetForSale, + SetConstructionRightsForSale, + SetOwnershipWithChecks, + Count +}; + +DEFINE_GAME_ACTION(LandSetRightsAction, GAME_COMMAND_SET_LAND_OWNERSHIP, GameActions::Result) +{ +private: + MapRange _range; + LandSetRightSetting _setting{ LandSetRightSetting::Count }; + uint8_t _ownership{}; + +public: + LandSetRightsAction() = default; + + LandSetRightsAction(const MapRange& range, LandSetRightSetting setting, uint8_t ownership = 0) + : _range(range) + , _setting(setting) + , _ownership(ownership) + { + } + + LandSetRightsAction(const CoordsXY& coord, LandSetRightSetting setting, uint8_t ownership = 0) + : _range(coord.x, coord.y, coord.x, coord.y) + , _setting(setting) + , _ownership(ownership) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; + GameActions::Result::Ptr map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LandSetRightsAction.hpp b/src/openrct2/actions/LandSetRightsAction.hpp deleted file mode 100644 index 1ffc5dfe40..0000000000 --- a/src/openrct2/actions/LandSetRightsAction.hpp +++ /dev/null @@ -1,236 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../OpenRCT2.h" -#include "../actions/LandSetHeightAction.hpp" -#include "../audio/audio.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../util/Util.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -enum class LandSetRightSetting : uint8_t -{ - UnownLand, - UnownConstructionRights, - SetForSale, - SetConstructionRightsForSale, - SetOwnershipWithChecks, - Count -}; - -DEFINE_GAME_ACTION(LandSetRightsAction, GAME_COMMAND_SET_LAND_OWNERSHIP, GameActions::Result) -{ -private: - MapRange _range; - LandSetRightSetting _setting{ LandSetRightSetting::Count }; - uint8_t _ownership{}; - -public: - LandSetRightsAction() = default; - - LandSetRightsAction(const MapRange& range, LandSetRightSetting setting, uint8_t ownership = 0) - : _range(range) - , _setting(setting) - , _ownership(ownership) - { - } - - LandSetRightsAction(const CoordsXY& coord, LandSetRightSetting setting, uint8_t ownership = 0) - : _range(coord.x, coord.y, coord.x, coord.y) - , _setting(setting) - , _ownership(ownership) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range) << DS_TAG(_setting) << DS_TAG(_ownership); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - MapRange normRange = _range.Normalise(); - // Keep big coordinates within map boundaries - auto aX = std::max(32, normRange.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, normRange.GetRight()); - auto aY = std::max(32, normRange.GetTop()); - auto bY = std::min(gMapSizeMaxXY, normRange.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - CoordsXYZ centre{ (validRange.GetLeft() + validRange.GetRight()) / 2 + 16, - (validRange.GetTop() + validRange.GetBottom()) / 2 + 16, 0 }; - centre.z = tile_element_height(centre); - - res->Position = centre; - res->Expenditure = ExpenditureType::LandPurchase; - - if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) - { - return MakeResult(GameActions::Status::NotInEditorMode, STR_NONE, STR_LAND_NOT_FOR_SALE); - } - - // Game command modified to accept selection size - for (auto y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (auto x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - auto result = map_buy_land_rights_for_tile({ x, y }, isExecuting); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - } - } - } - - if (isExecuting) - { - map_count_remaining_land_rights(); - OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, centre); - } - return res; - } - - GameActions::Result::Ptr map_buy_land_rights_for_tile(const CoordsXY& loc, bool isExecuting) const - { - SurfaceElement* surfaceElement = map_get_surface_element_at(loc); - if (surfaceElement == nullptr) - { - log_error("Could not find surface. x = %d, y = %d", loc.x, loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); - } - - auto res = MakeResult(); - switch (_setting) - { - case LandSetRightSetting::UnownLand: - if (isExecuting) - { - surfaceElement->SetOwnership( - surfaceElement->GetOwnership() & ~(OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)); - update_park_fences_around_tile(loc); - } - return res; - case LandSetRightSetting::UnownConstructionRights: - if (isExecuting) - { - surfaceElement->SetOwnership(surfaceElement->GetOwnership() & ~OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED); - uint16_t baseZ = surfaceElement->GetBaseZ(); - map_invalidate_tile({ loc, baseZ, baseZ + 16 }); - } - return res; - case LandSetRightSetting::SetForSale: - if (isExecuting) - { - surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_AVAILABLE); - uint16_t baseZ = surfaceElement->GetBaseZ(); - map_invalidate_tile({ loc, baseZ, baseZ + 16 }); - } - return res; - case LandSetRightSetting::SetConstructionRightsForSale: - if (isExecuting) - { - surfaceElement->SetOwnership(surfaceElement->GetOwnership() | OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE); - uint16_t baseZ = surfaceElement->GetBaseZ(); - map_invalidate_tile({ loc, baseZ, baseZ + 16 }); - } - return res; - case LandSetRightSetting::SetOwnershipWithChecks: - { - if (_ownership == surfaceElement->GetOwnership()) - { - return res; - } - - TileElement* tileElement = map_get_first_element_at(loc); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() != ENTRANCE_TYPE_PARK_ENTRANCE) - continue; - - // Do not allow ownership of park entrance. - if (_ownership == OWNERSHIP_OWNED || _ownership == OWNERSHIP_AVAILABLE) - return res; - - // Allow construction rights available / for sale on park entrances on surface. - // There is no need to check the height if _ownership is 0 (unowned and no rights available). - if (_ownership == OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED - || _ownership == OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) - { - if (tileElement->base_height - 3 > surfaceElement->base_height - || tileElement->base_height < surfaceElement->base_height) - return res; - } - } while (!(tileElement++)->IsLastForTile()); - - res->Cost = gLandPrice; - if (isExecuting) - { - if (_ownership != OWNERSHIP_UNOWNED) - { - gPeepSpawns.erase( - std::remove_if( - gPeepSpawns.begin(), gPeepSpawns.end(), - [x = loc.x, y = loc.y](const auto& spawn) { - return floor2(spawn.x, 32) == x && floor2(spawn.y, 32) == y; - }), - gPeepSpawns.end()); - } - surfaceElement->SetOwnership(_ownership); - update_park_fences_around_tile(loc); - gMapLandRightsUpdateSuccess = true; - } - return res; - } - default: - log_warning("Tried calling set land rights with an incorrect setting. setting = %u", _setting); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); - } - } -}; diff --git a/src/openrct2/actions/LandSmoothAction.cpp b/src/openrct2/actions/LandSmoothAction.cpp new file mode 100644 index 0000000000..2299a7fb44 --- /dev/null +++ b/src/openrct2/actions/LandSmoothAction.cpp @@ -0,0 +1,635 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "LandSmoothAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../actions/LandLowerAction.h" +#include "../actions/LandRaiseAction.h" +#include "../actions/LandSetHeightAction.h" +#include "../audio/audio.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../windows/Intent.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void LandSmoothAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType) << DS_TAG(_isLowering); +} + +GameActions::Result::Ptr LandSmoothAction::Query() const +{ + return SmoothLand(false); +} + +GameActions::Result::Ptr LandSmoothAction::Execute() const +{ + return SmoothLand(true); +} + +GameActions::Result::Ptr LandSmoothAction::SmoothLandTile( + int32_t direction, bool isExecuting, const CoordsXY& loc, SurfaceElement* surfaceElement) const +{ + int32_t targetBaseZ = surfaceElement->base_height; + int32_t slope = surfaceElement->GetSlope(); + if (_isLowering) + { + slope = tile_element_lower_styles[direction][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ -= 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + else + { + slope = tile_element_raise_styles[direction][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ += 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + + auto landSetHeightAction = LandSetHeightAction(loc, targetBaseZ, slope); + landSetHeightAction.SetFlags(GetFlags()); + auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) : GameActions::QueryNested(&landSetHeightAction); + + return res; +} + +money32 LandSmoothAction::SmoothLandRowByEdge( + bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight1, int32_t expectedLandHeight2, int32_t stepX, + int32_t stepY, int32_t direction1, int32_t direction2, int32_t checkDirection1, int32_t checkDirection2) const +{ + uint8_t shouldContinue = 0xF; + int32_t landChangePerTile = _isLowering ? 2 : -2; + money32 totalCost = 0; + + // check if we need to start at all + if (!LocationValid(loc) || !LocationValid({ loc.x + stepX, loc.y + stepY })) + { + return 0; + } + auto surfaceElement = map_get_surface_element_at(loc); + auto nextSurfaceElement = map_get_surface_element_at(CoordsXY{ loc.x + stepX, loc.y + stepY }); + if (surfaceElement == nullptr || nextSurfaceElement == nullptr) + { + return 0; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection1) != expectedLandHeight1 + landChangePerTile) + { + shouldContinue &= ~0x1; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection2) != expectedLandHeight2 + landChangePerTile) + { + shouldContinue &= ~0x2; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection1) + != tile_element_get_corner_height(nextSurfaceElement, direction1)) + { + shouldContinue &= ~0x1; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection2) + != tile_element_get_corner_height(nextSurfaceElement, direction2)) + { + shouldContinue &= ~0x2; + } + auto nextLoc = loc; + while ((shouldContinue & 0x3) != 0) + { + shouldContinue = ((shouldContinue << 2) | 0x3) & shouldContinue; + nextLoc.x += stepX; + nextLoc.y += stepY; + // check if we need to continue after raising the current tile + // this needs to be checked before the tile is changed + if (!LocationValid({ nextLoc.x + stepX, nextLoc.y + stepY })) + { + shouldContinue &= ~0x3; + } + else + { + surfaceElement = nextSurfaceElement; + nextSurfaceElement = map_get_surface_element_at(CoordsXY{ nextLoc.x + stepX, nextLoc.y + stepY }); + if (nextSurfaceElement == nullptr) + { + shouldContinue &= ~0x3; + } + if (tile_element_get_corner_height(surfaceElement, direction1) + landChangePerTile + != tile_element_get_corner_height(surfaceElement, checkDirection1)) + { + shouldContinue &= ~0x1; + } + if (tile_element_get_corner_height(surfaceElement, direction2) + landChangePerTile + != tile_element_get_corner_height(surfaceElement, checkDirection2)) + { + shouldContinue &= ~0x2; + } + if ((shouldContinue & 0x1) + && tile_element_get_corner_height(surfaceElement, checkDirection1) + != tile_element_get_corner_height(nextSurfaceElement, direction1)) + { + shouldContinue &= ~0x1; + } + if ((shouldContinue & 0x2) + && tile_element_get_corner_height(surfaceElement, checkDirection2) + != tile_element_get_corner_height(nextSurfaceElement, direction2)) + { + shouldContinue &= ~0x2; + } + } + expectedLandHeight1 += landChangePerTile; + + // change land of current tile + int32_t targetBaseZ = surfaceElement->base_height; + int32_t slope = surfaceElement->GetSlope(); + int32_t oldSlope = slope; + if (_isLowering) + { + if (shouldContinue & 0x4) + { + slope = tile_element_lower_styles[direction1][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ -= 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + if ((shouldContinue & 0x8) + && map_get_corner_height(surfaceElement->base_height, oldSlope, direction2) + == map_get_corner_height(targetBaseZ, slope, direction2)) + { + slope = tile_element_lower_styles[direction2][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ -= 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + } + else + { + if (shouldContinue & 0x4) + { + slope = tile_element_raise_styles[direction1][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ += 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + if ((shouldContinue & 0x8) + && map_get_corner_height(surfaceElement->base_height, oldSlope, direction2) + == map_get_corner_height(targetBaseZ, slope, direction2)) + { + slope = tile_element_raise_styles[direction2][slope]; + if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + targetBaseZ += 2; + slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + } + } + auto landSetHeightAction = LandSetHeightAction(nextLoc, targetBaseZ, slope); + landSetHeightAction.SetFlags(GetFlags()); + auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) + : GameActions::QueryNested(&landSetHeightAction); + if (res->Error == GameActions::Status::Ok) + { + totalCost += res->Cost; + } + } + return totalCost; +} + +money32 LandSmoothAction::SmoothLandRowByCorner( + bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight, int32_t stepX, int32_t stepY, int32_t direction, + int32_t checkDirection) const +{ + bool shouldContinue = true; + money32 totalCost = 0; + int32_t landChangePerTile; + if (stepX == 0 || stepY == 0) + { + landChangePerTile = _isLowering ? 2 : -2; + } + else + { + landChangePerTile = _isLowering ? 4 : -4; + } + + // check if we need to start at all + if (!LocationValid(loc) || !LocationValid({ loc.x + stepX, loc.y + stepY })) + { + return 0; + } + auto surfaceElement = map_get_surface_element_at(loc); + auto nextSurfaceElement = map_get_surface_element_at(CoordsXY{ loc.x + stepX, loc.y + stepY }); + if (surfaceElement == nullptr || nextSurfaceElement == nullptr) + { + return 0; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection) != expectedLandHeight + (_isLowering ? 2 : -2)) + { + return 0; + } + if (tile_element_get_corner_height(surfaceElement, checkDirection) + != tile_element_get_corner_height(nextSurfaceElement, direction)) + { + return 0; + } + + auto nextLoc = loc; + while (shouldContinue) + { + nextLoc.x += stepX; + nextLoc.y += stepY; + // check if we need to continue after raising the current tile + // this needs to be checked before the tile is changed + if (!LocationValid({ nextLoc.x + stepX, nextLoc.y + stepY })) + { + shouldContinue = false; + } + else + { + surfaceElement = nextSurfaceElement; + nextSurfaceElement = map_get_surface_element_at(CoordsXY{ nextLoc.x + stepX, nextLoc.y + stepY }); + if (nextSurfaceElement == nullptr) + { + shouldContinue = false; + } + if (tile_element_get_corner_height(surfaceElement, direction) + landChangePerTile + != tile_element_get_corner_height(surfaceElement, checkDirection)) + { + shouldContinue = false; + } + if (shouldContinue + && tile_element_get_corner_height(surfaceElement, checkDirection) + != tile_element_get_corner_height(nextSurfaceElement, direction)) + { + shouldContinue = false; + } + } + if (stepX * stepY != 0) + { + totalCost += SmoothLandRowByCorner( + isExecuting, nextLoc, expectedLandHeight + (landChangePerTile / 2), 0, stepY, direction, checkDirection ^ 3); + totalCost += SmoothLandRowByCorner( + isExecuting, nextLoc, expectedLandHeight + (landChangePerTile / 2), stepX, 0, direction, checkDirection ^ 1); + } + expectedLandHeight += landChangePerTile; + // change land of current tile + auto result = SmoothLandTile(direction, isExecuting, nextLoc, surfaceElement); + if (result->Error == GameActions::Status::Ok) + { + totalCost += result->Cost; + } + } + return totalCost; +} + +GameActions::Result::Ptr LandSmoothAction::SmoothLand(bool isExecuting) const +{ + const bool raiseLand = !_isLowering; + const int32_t selectionType = _selectionType; + const int32_t heightOffset = raiseLand ? 2 : -2; + + auto normRange = _range.Normalise(); + // Cap bounds to map + auto l = std::max(normRange.GetLeft(), 32); + auto t = std::max(normRange.GetTop(), 32); + auto r = std::clamp(normRange.GetRight(), 0, MAXIMUM_TILE_START_XY); + auto b = std::clamp(normRange.GetBottom(), 0, MAXIMUM_TILE_START_XY); + auto validRange = MapRange{ l, t, r, b }; + + int32_t centreZ = tile_element_height(_coords); + + auto res = MakeResult(); + res->ErrorTitle = _ErrorTitles[_isLowering ? 0 : 1]; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = { _coords.x, _coords.y, centreZ }; + + // Do the smoothing + switch (selectionType) + { + case MAP_SELECT_TYPE_FULL: + { + uint8_t minHeight = heightOffset + map_get_lowest_land_height(validRange); + uint8_t maxHeight = heightOffset + map_get_highest_land_height(validRange); + + // Smooth the 4 corners + { // top-left + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); + if (surfaceElement != nullptr) + { + int32_t z = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); + } + } + { // bottom-left + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetBottom() }); + if (surfaceElement != nullptr) + { + int32_t z = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetBottom() }, z, -32, 32, 1, 3); + } + } + { // bottom-right + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), validRange.GetBottom() }); + if (surfaceElement != nullptr) + { + int32_t z = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetRight(), validRange.GetBottom() }, z, 32, 32, 2, 0); + } + } + { // top-right + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), validRange.GetTop() }); + if (surfaceElement != nullptr) + { + int32_t z = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetRight(), validRange.GetTop() }, z, 32, -32, 3, 1); + } + } + + // Smooth the edges + int32_t z1, z2; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), y }); + if (surfaceElement != nullptr) + { + z1 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); + z2 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { validRange.GetLeft(), y }, z1, z2, -32, 0, 0, 1, 3, 2); + } + + surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), y }); + if (surfaceElement != nullptr) + { + z1 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); + z2 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { validRange.GetRight(), y }, z1, z2, 32, 0, 2, 3, 1, 0); + } + } + + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + auto surfaceElement = map_get_surface_element_at(CoordsXY{ x, validRange.GetTop() }); + if (surfaceElement != nullptr) + { + z1 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); + z2 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { x, validRange.GetTop() }, z1, z2, 0, -32, 0, 3, 1, 2); + } + + surfaceElement = map_get_surface_element_at(CoordsXY{ x, validRange.GetBottom() }); + if (surfaceElement != nullptr) + { + z1 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); + z2 = std::clamp( + static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); + res->Cost += SmoothLandRowByEdge(isExecuting, { x, validRange.GetBottom() }, z1, z2, 0, 32, 1, 2, 0, 3); + } + } + break; + } + case MAP_SELECT_TYPE_CORNER_0: + case MAP_SELECT_TYPE_CORNER_1: + case MAP_SELECT_TYPE_CORNER_2: + case MAP_SELECT_TYPE_CORNER_3: + { + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); + if (surfaceElement == nullptr) + break; + uint8_t newBaseZ = surfaceElement->base_height; + uint8_t newSlope = surfaceElement->GetSlope(); + + if (raiseLand) + { + newSlope = tile_element_raise_styles[selectionType][newSlope]; + } + else + { + newSlope = tile_element_lower_styles[selectionType][newSlope]; + } + + if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) + { + newBaseZ += heightOffset; + newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + + // Smooth the corners + int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 32, 2, 0); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 32, 1, 3); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); + + // Smooth the edges + switch (selectionType) + { + case MAP_SELECT_TYPE_CORNER_0: + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 3, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 1, 0); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 0, 3); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 0, 1); + break; + case MAP_SELECT_TYPE_CORNER_1: + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 2, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 0, 1); + z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 1, 2); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 1, 0); + break; + case MAP_SELECT_TYPE_CORNER_2: + z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 1, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 3, 2); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 2, 1); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 2, 3); + break; + case MAP_SELECT_TYPE_CORNER_3: + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 0, 3); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 2, 3); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 3, 0); + z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 3, 2); + break; + } + break; + } + case MAP_SELECT_TYPE_EDGE_0: + case MAP_SELECT_TYPE_EDGE_1: + case MAP_SELECT_TYPE_EDGE_2: + case MAP_SELECT_TYPE_EDGE_3: + { + // TODO: Handle smoothing by edge + // Get the two corners to raise + auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); + if (surfaceElement == nullptr) + break; + uint8_t newBaseZ = surfaceElement->base_height; + uint8_t oldSlope = surfaceElement->GetSlope(); + uint8_t newSlope = oldSlope; + int32_t rowIndex = selectionType - (MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1); + + if (raiseLand) + { + newSlope = tile_element_raise_styles[rowIndex][oldSlope]; + } + else + { + newSlope = tile_element_lower_styles[rowIndex][oldSlope]; + } + + const bool changeBaseHeight = newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + if (changeBaseHeight) + { + newBaseZ += heightOffset; + newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; + } + + const uint8_t edge = selectionType - MAP_SELECT_TYPE_EDGE_0; + + // Table with corners for each edge selection. The first two are the selected corners, the latter + // two are the opposites + static constexpr uint8_t cornerIndices[][4] = { + { 2, 3, 1, 0 }, // MAP_SELECT_TYPE_EDGE_0 + { 3, 0, 2, 1 }, // MAP_SELECT_TYPE_EDGE_1 + { 0, 1, 3, 2 }, // MAP_SELECT_TYPE_EDGE_2 + { 1, 2, 0, 3 }, // MAP_SELECT_TYPE_EDGE_3 + }; + // Big coordinate offsets for the neigbouring tile for the given edge selection + static constexpr CoordsXY stepOffsets[] = { + { -32, 0 }, + { 0, 32 }, + { 32, 0 }, + { 0, -32 }, + }; + + // Smooth higher and lower edges + uint8_t c1 = cornerIndices[edge][0]; + uint8_t c2 = cornerIndices[edge][1]; + uint8_t c3 = cornerIndices[edge][2]; + uint8_t c4 = cornerIndices[edge][3]; + uint8_t z1 = map_get_corner_height(newBaseZ, newSlope, c1); + uint8_t z2 = map_get_corner_height(newBaseZ, newSlope, c2); + uint8_t z3 = map_get_corner_height(newBaseZ, newSlope, c3); + uint8_t z4 = map_get_corner_height(newBaseZ, newSlope, c4); + // Smooth the edge at the top of the new slope + res->Cost += SmoothLandRowByEdge( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z1, z2, stepOffsets[edge].x, stepOffsets[edge].y, + c3, c4, c1, c2); + // Smooth the edge at the bottom of the new slope + res->Cost += SmoothLandRowByEdge( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z3, z4, -stepOffsets[edge].x, -stepOffsets[edge].y, + c1, c2, c3, c4); + + // Smooth corners + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z1, -stepOffsets[edge].y, stepOffsets[edge].x, c2, + c1); + res->Cost += SmoothLandRowByCorner( + isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z2, stepOffsets[edge].y, -stepOffsets[edge].x, c1, + c2); + int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); + z = map_get_corner_height(newBaseZ, newSlope, 0); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 32, 2, 0); + z = map_get_corner_height(newBaseZ, newSlope, 3); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 32, 1, 3); + z = map_get_corner_height(newBaseZ, newSlope, 1); + res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); + break; + } + default: + log_error("Invalid map selection %u", _selectionType); + return MakeResult(GameActions::Status::InvalidParameters, res->ErrorTitle.GetStringId()); + } // switch selectionType + + // Raise / lower the land tool selection area + GameActions::Result::Ptr result; + if (raiseLand) + { + auto raiseLandAction = LandRaiseAction({ _coords.x, _coords.y }, validRange, selectionType); + raiseLandAction.SetFlags(GetFlags()); + result = isExecuting ? GameActions::ExecuteNested(&raiseLandAction) : GameActions::QueryNested(&raiseLandAction); + } + else + { + auto lowerLandAction = LandLowerAction({ _coords.x, _coords.y }, validRange, selectionType); + lowerLandAction.SetFlags(GetFlags()); + result = isExecuting ? GameActions::ExecuteNested(&lowerLandAction) : GameActions::QueryNested(&lowerLandAction); + } + if (result->Error != GameActions::Status::Ok) + { + return result; + } + + if (isExecuting) + { + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, centreZ }); + } + res->Cost += result->Cost; + return res; +} diff --git a/src/openrct2/actions/LandSmoothAction.h b/src/openrct2/actions/LandSmoothAction.h new file mode 100644 index 0000000000..f7f3880465 --- /dev/null +++ b/src/openrct2/actions/LandSmoothAction.h @@ -0,0 +1,53 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(LandSmoothAction, GAME_COMMAND_EDIT_LAND_SMOOTH, GameActions::Result) +{ +private: + CoordsXY _coords; + MapRange _range; + uint8_t _selectionType{}; + bool _isLowering{}; + + constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_LOWER_LAND_HERE, STR_CANT_RAISE_LAND_HERE }; + +public: + LandSmoothAction() = default; + LandSmoothAction(const CoordsXY& coords, MapRange range, uint8_t selectionType, bool isLowering) + : _coords(coords) + , _range(range) + , _selectionType(selectionType) + , _isLowering(isLowering) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr SmoothLandTile( + int32_t direction, bool isExecuting, const CoordsXY& loc, SurfaceElement* surfaceElement) const; + money32 SmoothLandRowByEdge( + bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight1, int32_t expectedLandHeight2, int32_t stepX, + int32_t stepY, int32_t direction1, int32_t direction2, int32_t checkDirection1, int32_t checkDirection2) const; + money32 SmoothLandRowByCorner( + bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight, int32_t stepX, int32_t stepY, int32_t direction, + int32_t checkDirection) const; + GameActions::Result::Ptr SmoothLand(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LandSmoothAction.hpp b/src/openrct2/actions/LandSmoothAction.hpp deleted file mode 100644 index 3a66ba046c..0000000000 --- a/src/openrct2/actions/LandSmoothAction.hpp +++ /dev/null @@ -1,672 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../OpenRCT2.h" -#include "../actions/LandLowerAction.hpp" -#include "../actions/LandRaiseAction.hpp" -#include "../actions/LandSetHeightAction.hpp" -#include "../audio/audio.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LandSmoothAction, GAME_COMMAND_EDIT_LAND_SMOOTH, GameActions::Result) -{ -private: - CoordsXY _coords; - MapRange _range; - uint8_t _selectionType{}; - bool _isLowering{}; - - constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_LOWER_LAND_HERE, STR_CANT_RAISE_LAND_HERE }; - -public: - LandSmoothAction() = default; - LandSmoothAction(const CoordsXY& coords, MapRange range, uint8_t selectionType, bool isLowering) - : _coords(coords) - , _range(range) - , _selectionType(selectionType) - , _isLowering(isLowering) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_coords) << DS_TAG(_range) << DS_TAG(_selectionType) << DS_TAG(_isLowering); - } - - GameActions::Result::Ptr Query() const override - { - return SmoothLand(false); - } - - GameActions::Result::Ptr Execute() const override - { - return SmoothLand(true); - } - -private: - GameActions::Result::Ptr SmoothLandTile( - int32_t direction, bool isExecuting, const CoordsXY& loc, SurfaceElement* surfaceElement) const - { - int32_t targetBaseZ = surfaceElement->base_height; - int32_t slope = surfaceElement->GetSlope(); - if (_isLowering) - { - slope = tile_element_lower_styles[direction][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ -= 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - else - { - slope = tile_element_raise_styles[direction][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ += 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - - auto landSetHeightAction = LandSetHeightAction(loc, targetBaseZ, slope); - landSetHeightAction.SetFlags(GetFlags()); - auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); - - return res; - } - - money32 SmoothLandRowByEdge( - bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight1, int32_t expectedLandHeight2, int32_t stepX, - int32_t stepY, int32_t direction1, int32_t direction2, int32_t checkDirection1, int32_t checkDirection2) const - { - uint8_t shouldContinue = 0xF; - int32_t landChangePerTile = _isLowering ? 2 : -2; - money32 totalCost = 0; - - // check if we need to start at all - if (!LocationValid(loc) || !LocationValid({ loc.x + stepX, loc.y + stepY })) - { - return 0; - } - auto surfaceElement = map_get_surface_element_at(loc); - auto nextSurfaceElement = map_get_surface_element_at(CoordsXY{ loc.x + stepX, loc.y + stepY }); - if (surfaceElement == nullptr || nextSurfaceElement == nullptr) - { - return 0; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection1) != expectedLandHeight1 + landChangePerTile) - { - shouldContinue &= ~0x1; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection2) != expectedLandHeight2 + landChangePerTile) - { - shouldContinue &= ~0x2; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection1) - != tile_element_get_corner_height(nextSurfaceElement, direction1)) - { - shouldContinue &= ~0x1; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection2) - != tile_element_get_corner_height(nextSurfaceElement, direction2)) - { - shouldContinue &= ~0x2; - } - auto nextLoc = loc; - while ((shouldContinue & 0x3) != 0) - { - shouldContinue = ((shouldContinue << 2) | 0x3) & shouldContinue; - nextLoc.x += stepX; - nextLoc.y += stepY; - // check if we need to continue after raising the current tile - // this needs to be checked before the tile is changed - if (!LocationValid({ nextLoc.x + stepX, nextLoc.y + stepY })) - { - shouldContinue &= ~0x3; - } - else - { - surfaceElement = nextSurfaceElement; - nextSurfaceElement = map_get_surface_element_at(CoordsXY{ nextLoc.x + stepX, nextLoc.y + stepY }); - if (nextSurfaceElement == nullptr) - { - shouldContinue &= ~0x3; - } - if (tile_element_get_corner_height(surfaceElement, direction1) + landChangePerTile - != tile_element_get_corner_height(surfaceElement, checkDirection1)) - { - shouldContinue &= ~0x1; - } - if (tile_element_get_corner_height(surfaceElement, direction2) + landChangePerTile - != tile_element_get_corner_height(surfaceElement, checkDirection2)) - { - shouldContinue &= ~0x2; - } - if ((shouldContinue & 0x1) - && tile_element_get_corner_height(surfaceElement, checkDirection1) - != tile_element_get_corner_height(nextSurfaceElement, direction1)) - { - shouldContinue &= ~0x1; - } - if ((shouldContinue & 0x2) - && tile_element_get_corner_height(surfaceElement, checkDirection2) - != tile_element_get_corner_height(nextSurfaceElement, direction2)) - { - shouldContinue &= ~0x2; - } - } - expectedLandHeight1 += landChangePerTile; - - // change land of current tile - int32_t targetBaseZ = surfaceElement->base_height; - int32_t slope = surfaceElement->GetSlope(); - int32_t oldSlope = slope; - if (_isLowering) - { - if (shouldContinue & 0x4) - { - slope = tile_element_lower_styles[direction1][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ -= 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - if ((shouldContinue & 0x8) - && map_get_corner_height(surfaceElement->base_height, oldSlope, direction2) - == map_get_corner_height(targetBaseZ, slope, direction2)) - { - slope = tile_element_lower_styles[direction2][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ -= 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - } - else - { - if (shouldContinue & 0x4) - { - slope = tile_element_raise_styles[direction1][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ += 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - if ((shouldContinue & 0x8) - && map_get_corner_height(surfaceElement->base_height, oldSlope, direction2) - == map_get_corner_height(targetBaseZ, slope, direction2)) - { - slope = tile_element_raise_styles[direction2][slope]; - if (slope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - targetBaseZ += 2; - slope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - } - } - auto landSetHeightAction = LandSetHeightAction(nextLoc, targetBaseZ, slope); - landSetHeightAction.SetFlags(GetFlags()); - auto res = isExecuting ? GameActions::ExecuteNested(&landSetHeightAction) - : GameActions::QueryNested(&landSetHeightAction); - if (res->Error == GameActions::Status::Ok) - { - totalCost += res->Cost; - } - } - return totalCost; - } - - money32 SmoothLandRowByCorner( - bool isExecuting, const CoordsXY& loc, int32_t expectedLandHeight, int32_t stepX, int32_t stepY, int32_t direction, - int32_t checkDirection) const - { - bool shouldContinue = true; - money32 totalCost = 0; - int32_t landChangePerTile; - if (stepX == 0 || stepY == 0) - { - landChangePerTile = _isLowering ? 2 : -2; - } - else - { - landChangePerTile = _isLowering ? 4 : -4; - } - - // check if we need to start at all - if (!LocationValid(loc) || !LocationValid({ loc.x + stepX, loc.y + stepY })) - { - return 0; - } - auto surfaceElement = map_get_surface_element_at(loc); - auto nextSurfaceElement = map_get_surface_element_at(CoordsXY{ loc.x + stepX, loc.y + stepY }); - if (surfaceElement == nullptr || nextSurfaceElement == nullptr) - { - return 0; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection) != expectedLandHeight + (_isLowering ? 2 : -2)) - { - return 0; - } - if (tile_element_get_corner_height(surfaceElement, checkDirection) - != tile_element_get_corner_height(nextSurfaceElement, direction)) - { - return 0; - } - - auto nextLoc = loc; - while (shouldContinue) - { - nextLoc.x += stepX; - nextLoc.y += stepY; - // check if we need to continue after raising the current tile - // this needs to be checked before the tile is changed - if (!LocationValid({ nextLoc.x + stepX, nextLoc.y + stepY })) - { - shouldContinue = false; - } - else - { - surfaceElement = nextSurfaceElement; - nextSurfaceElement = map_get_surface_element_at(CoordsXY{ nextLoc.x + stepX, nextLoc.y + stepY }); - if (nextSurfaceElement == nullptr) - { - shouldContinue = false; - } - if (tile_element_get_corner_height(surfaceElement, direction) + landChangePerTile - != tile_element_get_corner_height(surfaceElement, checkDirection)) - { - shouldContinue = false; - } - if (shouldContinue - && tile_element_get_corner_height(surfaceElement, checkDirection) - != tile_element_get_corner_height(nextSurfaceElement, direction)) - { - shouldContinue = false; - } - } - if (stepX * stepY != 0) - { - totalCost += SmoothLandRowByCorner( - isExecuting, nextLoc, expectedLandHeight + (landChangePerTile / 2), 0, stepY, direction, - checkDirection ^ 3); - totalCost += SmoothLandRowByCorner( - isExecuting, nextLoc, expectedLandHeight + (landChangePerTile / 2), stepX, 0, direction, - checkDirection ^ 1); - } - expectedLandHeight += landChangePerTile; - // change land of current tile - auto result = SmoothLandTile(direction, isExecuting, nextLoc, surfaceElement); - if (result->Error == GameActions::Status::Ok) - { - totalCost += result->Cost; - } - } - return totalCost; - } - - GameActions::Result::Ptr SmoothLand(bool isExecuting) const - { - const bool raiseLand = !_isLowering; - const int32_t selectionType = _selectionType; - const int32_t heightOffset = raiseLand ? 2 : -2; - - auto normRange = _range.Normalise(); - // Cap bounds to map - auto l = std::max(normRange.GetLeft(), 32); - auto t = std::max(normRange.GetTop(), 32); - auto r = std::clamp(normRange.GetRight(), 0, MAXIMUM_TILE_START_XY); - auto b = std::clamp(normRange.GetBottom(), 0, MAXIMUM_TILE_START_XY); - auto validRange = MapRange{ l, t, r, b }; - - int32_t centreZ = tile_element_height(_coords); - - auto res = MakeResult(); - res->ErrorTitle = _ErrorTitles[_isLowering ? 0 : 1]; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = { _coords.x, _coords.y, centreZ }; - - // Do the smoothing - switch (selectionType) - { - case MAP_SELECT_TYPE_FULL: - { - uint8_t minHeight = heightOffset + map_get_lowest_land_height(validRange); - uint8_t maxHeight = heightOffset + map_get_highest_land_height(validRange); - - // Smooth the 4 corners - { // top-left - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); - if (surfaceElement != nullptr) - { - int32_t z = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); - } - } - { // bottom-left - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetBottom() }); - if (surfaceElement != nullptr) - { - int32_t z = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetBottom() }, z, -32, 32, 1, 3); - } - } - { // bottom-right - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), validRange.GetBottom() }); - if (surfaceElement != nullptr) - { - int32_t z = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetRight(), validRange.GetBottom() }, z, 32, 32, 2, 0); - } - } - { // top-right - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), validRange.GetTop() }); - if (surfaceElement != nullptr) - { - int32_t z = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetRight(), validRange.GetTop() }, z, 32, -32, 3, 1); - } - } - - // Smooth the edges - int32_t z1, z2; - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), y }); - if (surfaceElement != nullptr) - { - z1 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); - z2 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); - res->Cost += SmoothLandRowByEdge(isExecuting, { validRange.GetLeft(), y }, z1, z2, -32, 0, 0, 1, 3, 2); - } - - surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetRight(), y }); - if (surfaceElement != nullptr) - { - z1 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); - z2 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); - res->Cost += SmoothLandRowByEdge(isExecuting, { validRange.GetRight(), y }, z1, z2, 32, 0, 2, 3, 1, 0); - } - } - - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - auto surfaceElement = map_get_surface_element_at(CoordsXY{ x, validRange.GetTop() }); - if (surfaceElement != nullptr) - { - z1 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 1)), minHeight, maxHeight); - z2 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 2)), minHeight, maxHeight); - res->Cost += SmoothLandRowByEdge(isExecuting, { x, validRange.GetTop() }, z1, z2, 0, -32, 0, 3, 1, 2); - } - - surfaceElement = map_get_surface_element_at(CoordsXY{ x, validRange.GetBottom() }); - if (surfaceElement != nullptr) - { - z1 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 0)), minHeight, maxHeight); - z2 = std::clamp( - static_cast(tile_element_get_corner_height(surfaceElement, 3)), minHeight, maxHeight); - res->Cost += SmoothLandRowByEdge(isExecuting, { x, validRange.GetBottom() }, z1, z2, 0, 32, 1, 2, 0, 3); - } - } - break; - } - case MAP_SELECT_TYPE_CORNER_0: - case MAP_SELECT_TYPE_CORNER_1: - case MAP_SELECT_TYPE_CORNER_2: - case MAP_SELECT_TYPE_CORNER_3: - { - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); - if (surfaceElement == nullptr) - break; - uint8_t newBaseZ = surfaceElement->base_height; - uint8_t newSlope = surfaceElement->GetSlope(); - - if (raiseLand) - { - newSlope = tile_element_raise_styles[selectionType][newSlope]; - } - else - { - newSlope = tile_element_lower_styles[selectionType][newSlope]; - } - - if (newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT) - { - newBaseZ += heightOffset; - newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - - // Smooth the corners - int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); - z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 32, 2, 0); - z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 32, 1, 3); - z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); - - // Smooth the edges - switch (selectionType) - { - case MAP_SELECT_TYPE_CORNER_0: - z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 3, 0); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 1, 0); - z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 0, 3); - z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 0, 1); - break; - case MAP_SELECT_TYPE_CORNER_1: - z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 2, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 0, 1); - z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 1, 2); - z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 1, 0); - break; - case MAP_SELECT_TYPE_CORNER_2: - z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 1, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 3, 2); - z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 2, 1); - z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 2, 3); - break; - case MAP_SELECT_TYPE_CORNER_3: - z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 0, 0, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, 32, 2, 3); - z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 0, 3, 0); - z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 0, -32, 3, 2); - break; - } - break; - } - case MAP_SELECT_TYPE_EDGE_0: - case MAP_SELECT_TYPE_EDGE_1: - case MAP_SELECT_TYPE_EDGE_2: - case MAP_SELECT_TYPE_EDGE_3: - { - // TODO: Handle smoothing by edge - // Get the two corners to raise - auto surfaceElement = map_get_surface_element_at(CoordsXY{ validRange.GetLeft(), validRange.GetTop() }); - if (surfaceElement == nullptr) - break; - uint8_t newBaseZ = surfaceElement->base_height; - uint8_t oldSlope = surfaceElement->GetSlope(); - uint8_t newSlope = oldSlope; - int32_t rowIndex = selectionType - (MAP_SELECT_TYPE_EDGE_0 - MAP_SELECT_TYPE_FULL - 1); - - if (raiseLand) - { - newSlope = tile_element_raise_styles[rowIndex][oldSlope]; - } - else - { - newSlope = tile_element_lower_styles[rowIndex][oldSlope]; - } - - const bool changeBaseHeight = newSlope & SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - if (changeBaseHeight) - { - newBaseZ += heightOffset; - newSlope &= ~SURFACE_STYLE_FLAG_RAISE_OR_LOWER_BASE_HEIGHT; - } - - const uint8_t edge = selectionType - MAP_SELECT_TYPE_EDGE_0; - - // Table with corners for each edge selection. The first two are the selected corners, the latter - // two are the opposites - static constexpr uint8_t cornerIndices[][4] = { - { 2, 3, 1, 0 }, // MAP_SELECT_TYPE_EDGE_0 - { 3, 0, 2, 1 }, // MAP_SELECT_TYPE_EDGE_1 - { 0, 1, 3, 2 }, // MAP_SELECT_TYPE_EDGE_2 - { 1, 2, 0, 3 }, // MAP_SELECT_TYPE_EDGE_3 - }; - // Big coordinate offsets for the neigbouring tile for the given edge selection - static constexpr CoordsXY stepOffsets[] = { - { -32, 0 }, - { 0, 32 }, - { 32, 0 }, - { 0, -32 }, - }; - - // Smooth higher and lower edges - uint8_t c1 = cornerIndices[edge][0]; - uint8_t c2 = cornerIndices[edge][1]; - uint8_t c3 = cornerIndices[edge][2]; - uint8_t c4 = cornerIndices[edge][3]; - uint8_t z1 = map_get_corner_height(newBaseZ, newSlope, c1); - uint8_t z2 = map_get_corner_height(newBaseZ, newSlope, c2); - uint8_t z3 = map_get_corner_height(newBaseZ, newSlope, c3); - uint8_t z4 = map_get_corner_height(newBaseZ, newSlope, c4); - // Smooth the edge at the top of the new slope - res->Cost += SmoothLandRowByEdge( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z1, z2, stepOffsets[edge].x, - stepOffsets[edge].y, c3, c4, c1, c2); - // Smooth the edge at the bottom of the new slope - res->Cost += SmoothLandRowByEdge( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z3, z4, -stepOffsets[edge].x, - -stepOffsets[edge].y, c1, c2, c3, c4); - - // Smooth corners - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z1, -stepOffsets[edge].y, stepOffsets[edge].x, - c2, c1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z2, stepOffsets[edge].y, -stepOffsets[edge].x, - c1, c2); - int32_t z = map_get_corner_height(newBaseZ, newSlope, 2); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, -32, 0, 2); - z = map_get_corner_height(newBaseZ, newSlope, 0); - res->Cost += SmoothLandRowByCorner(isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, 32, 2, 0); - z = map_get_corner_height(newBaseZ, newSlope, 3); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, -32, 32, 1, 3); - z = map_get_corner_height(newBaseZ, newSlope, 1); - res->Cost += SmoothLandRowByCorner( - isExecuting, { validRange.GetLeft(), validRange.GetTop() }, z, 32, -32, 3, 1); - break; - } - default: - log_error("Invalid map selection %u", _selectionType); - return MakeResult(GameActions::Status::InvalidParameters, res->ErrorTitle.GetStringId()); - } // switch selectionType - - // Raise / lower the land tool selection area - GameActions::Result::Ptr result; - if (raiseLand) - { - auto raiseLandAction = LandRaiseAction({ _coords.x, _coords.y }, validRange, selectionType); - raiseLandAction.SetFlags(GetFlags()); - result = isExecuting ? GameActions::ExecuteNested(&raiseLandAction) : GameActions::QueryNested(&raiseLandAction); - } - else - { - auto lowerLandAction = LandLowerAction({ _coords.x, _coords.y }, validRange, selectionType); - lowerLandAction.SetFlags(GetFlags()); - result = isExecuting ? GameActions::ExecuteNested(&lowerLandAction) : GameActions::QueryNested(&lowerLandAction); - } - if (result->Error != GameActions::Status::Ok) - { - return result; - } - - if (isExecuting) - { - OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, { _coords.x, _coords.y, centreZ }); - } - res->Cost += result->Cost; - return res; - } -}; diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.cpp b/src/openrct2/actions/LargeSceneryPlaceAction.cpp new file mode 100644 index 0000000000..910b7a4cbc --- /dev/null +++ b/src/openrct2/actions/LargeSceneryPlaceAction.cpp @@ -0,0 +1,359 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "LargeSceneryPlaceAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../object/ObjectLimits.h" +#include "../ride/Ride.h" +#include "../world/Banner.h" +#include "../world/MapAnimation.h" +#include "../world/Surface.h" + +void LargeSceneryPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _sceneryType); + visitor.Visit("primaryColour", _primaryColour); + visitor.Visit("secondaryColour", _secondaryColour); + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); + if (sceneryEntry != nullptr) + { + if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) + { + _bannerId = create_new_banner(0); + } + } +} + +void LargeSceneryPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) << DS_TAG(_bannerId); +} + +GameActions::Result::Ptr LargeSceneryPlaceAction::Query() const +{ + auto res = std::make_unique(); + res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; + res->Expenditure = ExpenditureType::Landscaping; + int16_t surfaceHeight = tile_element_height(_loc); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = surfaceHeight; + res->GroundFlags = 0; + + money32 supportsCost = 0; + + if (_primaryColour > TILE_ELEMENT_COLOUR_MASK || _secondaryColour > TILE_ELEMENT_COLOUR_MASK) + { + log_error( + "Invalid game command for scenery placement, primaryColour = %u, secondaryColour = %u", _primaryColour, + _secondaryColour); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + if (_sceneryType >= MAX_LARGE_SCENERY_OBJECTS) + { + log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); + if (sceneryEntry == nullptr) + { + log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + uint32_t totalNumTiles = GetTotalNumTiles(sceneryEntry->large_scenery.tiles); + int16_t maxHeight = GetMaxSurfaceHeight(sceneryEntry->large_scenery.tiles); + + if (_loc.z != 0) + { + maxHeight = _loc.z; + } + + res->Position.z = maxHeight; + + if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) + { + if (_bannerId == BANNER_INDEX_NULL) + { + log_error("Banner Index not specified."); + return MakeResult(GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); + } + + auto banner = GetBanner(_bannerId); + if (!banner->IsNull()) + { + log_error("No free banners available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + } + + if (!map_check_free_elements_and_reorganise(totalNumTiles)) + { + log_error("No free map elements available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + + uint8_t tileNum = 0; + for (rct_large_scenery_tile* tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; tile++, tileNum++) + { + auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); + + curTile.x += _loc.x; + curTile.y += _loc.y; + + int32_t zLow = tile->z_offset + maxHeight; + int32_t zHigh = tile->z_clearance + zLow; + + QuarterTile quarterTile = QuarterTile{ static_cast(tile->flags >> 12), 0 }.Rotate(_loc.direction); + if (!map_can_construct_with_clear_at( + { curTile, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost, + CREATE_CROSSING_MODE_NONE)) + { + return std::make_unique( + GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); + } + + int32_t tempSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + if (!gCheatsDisableClearanceChecks) + { + if ((gMapGroundFlags & ELEMENT_IS_UNDERWATER) || (gMapGroundFlags & ELEMENT_IS_UNDERGROUND)) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); + } + if (res->GroundFlags && !(res->GroundFlags & tempSceneryGroundFlags)) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); + } + } + + res->GroundFlags = tempSceneryGroundFlags; + + if (!LocationValid(curTile) || curTile.x >= gMapSizeUnits || curTile.y >= gMapSizeUnits) + { + return std::make_unique(GameActions::Status::Disallowed, STR_OFF_EDGE_OF_MAP); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_owned({ curTile, zLow }) && !gCheatsSandboxMode) + { + return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + res->Cost = (sceneryEntry->large_scenery.price * 10) + supportsCost; + return res; +} + +GameActions::Result::Ptr LargeSceneryPlaceAction::Execute() const +{ + auto res = std::make_unique(); + res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; + res->Expenditure = ExpenditureType::Landscaping; + + int16_t surfaceHeight = tile_element_height(_loc); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = surfaceHeight; + res->GroundFlags = 0; + + money32 supportsCost = 0; + + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); + if (sceneryEntry == nullptr) + { + log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + if (sceneryEntry->large_scenery.tiles == nullptr) + { + log_error("Invalid large scenery object, sceneryType = %u", _sceneryType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + uint32_t totalNumTiles = GetTotalNumTiles(sceneryEntry->large_scenery.tiles); + int16_t maxHeight = GetMaxSurfaceHeight(sceneryEntry->large_scenery.tiles); + + if (_loc.z != 0) + { + maxHeight = _loc.z; + } + + res->Position.z = maxHeight; + + if (!map_check_free_elements_and_reorganise(totalNumTiles)) + { + log_error("No free map elements available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + + uint8_t tileNum = 0; + for (rct_large_scenery_tile* tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; tile++, tileNum++) + { + auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); + + curTile.x += _loc.x; + curTile.y += _loc.y; + + int32_t zLow = tile->z_offset + maxHeight; + int32_t zHigh = tile->z_clearance + zLow; + + QuarterTile quarterTile = QuarterTile{ static_cast(tile->flags >> 12), 0 }.Rotate(_loc.direction); + if (!map_can_construct_with_clear_at( + { curTile, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost, + CREATE_CROSSING_MODE_NONE)) + { + return std::make_unique( + GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); + } + + res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter({ curTile, zLow }); + if (!gCheatsDisableClearanceChecks) + { + wall_remove_at({ curTile, zLow, zHigh }); + } + } + + TileElement* newTileElement = tile_element_insert( + CoordsXYZ{ curTile.x, curTile.y, zLow }, quarterTile.GetBaseQuarterOccupied()); + Guard::Assert(newTileElement != nullptr); + map_animation_create(MAP_ANIMATION_TYPE_LARGE_SCENERY, { curTile, zLow }); + newTileElement->SetType(TILE_ELEMENT_TYPE_LARGE_SCENERY); + newTileElement->SetClearanceZ(zHigh); + auto newSceneryElement = newTileElement->AsLargeScenery(); + + SetNewLargeSceneryElement(*newSceneryElement, tileNum); + + if (tileNum == 0) + { + res->tileElement = newTileElement; + } + map_invalidate_tile_full(curTile); + } + + // Allocate banner after all tiles to ensure banner id doesn't need to be freed. + if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) + { + if (_bannerId == BANNER_INDEX_NULL) + { + log_error("No free banners available"); + return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_BANNERS_IN_GAME); + } + + auto banner = GetBanner(_bannerId); + if (!banner->IsNull()) + { + log_error("No free banners available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + + banner->text = {}; + banner->colour = 2; + banner->text_colour = 2; + banner->flags = BANNER_FLAG_IS_LARGE_SCENERY; + banner->type = 0; + banner->position = TileCoordsXY(_loc); + + ride_id_t rideIndex = banner_get_closest_ride_index({ _loc, maxHeight }); + if (rideIndex != RIDE_ID_NULL) + { + banner->ride_index = rideIndex; + banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; + } + } + + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + res->Cost = (sceneryEntry->large_scenery.price * 10) + supportsCost; + return res; +} + +int16_t LargeSceneryPlaceAction::GetTotalNumTiles(rct_large_scenery_tile* tiles) const +{ + uint32_t totalNumTiles = 0; + for (rct_large_scenery_tile* tile = tiles; tile->x_offset != -1; tile++) + { + totalNumTiles++; + } + return totalNumTiles; +} + +int16_t LargeSceneryPlaceAction::GetMaxSurfaceHeight(rct_large_scenery_tile* tiles) const +{ + int16_t maxHeight = -1; + for (rct_large_scenery_tile* tile = tiles; tile->x_offset != -1; tile++) + { + auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); + + curTile.x += _loc.x; + curTile.y += _loc.y; + + if (!map_is_location_valid(curTile)) + { + continue; + } + + auto* surfaceElement = map_get_surface_element_at(curTile); + if (surfaceElement == nullptr) + continue; + + int32_t baseZ = surfaceElement->GetBaseZ(); + int32_t slope = surfaceElement->GetSlope(); + + if ((slope & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) != TILE_ELEMENT_SLOPE_FLAT) + { + baseZ += LAND_HEIGHT_STEP; + if (slope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) + { + baseZ += LAND_HEIGHT_STEP; + } + } + + if (baseZ > maxHeight) + { + maxHeight = baseZ; + } + } + return maxHeight; +} + +void LargeSceneryPlaceAction::SetNewLargeSceneryElement(LargeSceneryElement& sceneryElement, uint8_t tileNum) const +{ + sceneryElement.SetDirection(_loc.direction); + sceneryElement.SetEntryIndex(_sceneryType); + sceneryElement.SetSequenceIndex(tileNum); + sceneryElement.SetPrimaryColour(_primaryColour); + sceneryElement.SetSecondaryColour(_secondaryColour); + + if (_bannerId != BANNER_INDEX_NULL) + { + sceneryElement.SetBannerIndex(_bannerId); + } + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + sceneryElement.SetGhost(true); + } +} diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.h b/src/openrct2/actions/LargeSceneryPlaceAction.h new file mode 100644 index 0000000000..f09a801fb5 --- /dev/null +++ b/src/openrct2/actions/LargeSceneryPlaceAction.h @@ -0,0 +1,83 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/LargeScenery.h" +#include "../world/Scenery.h" +#include "GameAction.h" + +class LargeSceneryPlaceActionResult final : public GameActions::Result +{ +public: + LargeSceneryPlaceActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_CANT_POSITION_THIS_HERE) + { + } + LargeSceneryPlaceActionResult(GameActions::Status error) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE) + { + } + LargeSceneryPlaceActionResult(GameActions::Status error, rct_string_id message) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message) + { + } + LargeSceneryPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message, args) + { + } + + uint8_t GroundFlags{ 0 }; + TileElement* tileElement = nullptr; +}; + +DEFINE_GAME_ACTION(LargeSceneryPlaceAction, GAME_COMMAND_PLACE_LARGE_SCENERY, LargeSceneryPlaceActionResult) +{ +private: + CoordsXYZD _loc; + ObjectEntryIndex _sceneryType{ OBJECT_ENTRY_INDEX_NULL }; + uint8_t _primaryColour{}; + uint8_t _secondaryColour{}; + BannerIndex _bannerId{ BANNER_INDEX_NULL }; + +public: + LargeSceneryPlaceAction() = default; + + LargeSceneryPlaceAction(const CoordsXYZD& loc, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) + : _loc(loc) + , _sceneryType(sceneryType) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + { + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); + if (sceneryEntry != nullptr) + { + if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) + { + _bannerId = create_new_banner(0); + } + } + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + int16_t GetTotalNumTiles(rct_large_scenery_tile * tiles) const; + int16_t GetMaxSurfaceHeight(rct_large_scenery_tile * tiles) const; + void SetNewLargeSceneryElement(LargeSceneryElement & sceneryElement, uint8_t tileNum) const; +}; diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.hpp b/src/openrct2/actions/LargeSceneryPlaceAction.hpp deleted file mode 100644 index cb6b6f48cf..0000000000 --- a/src/openrct2/actions/LargeSceneryPlaceAction.hpp +++ /dev/null @@ -1,424 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../object/ObjectLimits.h" -#include "../ride/Ride.h" -#include "../world/Banner.h" -#include "../world/LargeScenery.h" -#include "../world/MapAnimation.h" -#include "../world/Scenery.h" -#include "../world/Surface.h" -#include "GameAction.h" - -class LargeSceneryPlaceActionResult final : public GameActions::Result -{ -public: - LargeSceneryPlaceActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_CANT_POSITION_THIS_HERE) - { - } - LargeSceneryPlaceActionResult(GameActions::Status error) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE) - { - } - LargeSceneryPlaceActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message) - { - } - LargeSceneryPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message, args) - { - } - - uint8_t GroundFlags{ 0 }; - TileElement* tileElement = nullptr; -}; - -DEFINE_GAME_ACTION(LargeSceneryPlaceAction, GAME_COMMAND_PLACE_LARGE_SCENERY, LargeSceneryPlaceActionResult) -{ -private: - CoordsXYZD _loc; - ObjectEntryIndex _sceneryType{ OBJECT_ENTRY_INDEX_NULL }; - uint8_t _primaryColour{}; - uint8_t _secondaryColour{}; - BannerIndex _bannerId{ BANNER_INDEX_NULL }; - -public: - LargeSceneryPlaceAction() = default; - - LargeSceneryPlaceAction(const CoordsXYZD& loc, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) - : _loc(loc) - , _sceneryType(sceneryType) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - { - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); - if (sceneryEntry != nullptr) - { - if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - _bannerId = create_new_banner(0); - } - } - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _sceneryType); - visitor.Visit("primaryColour", _primaryColour); - visitor.Visit("secondaryColour", _secondaryColour); - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); - if (sceneryEntry != nullptr) - { - if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - _bannerId = create_new_banner(0); - } - } - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) - << DS_TAG(_bannerId); - } - - GameActions::Result::Ptr Query() const override - { - auto res = std::make_unique(); - res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; - res->Expenditure = ExpenditureType::Landscaping; - int16_t surfaceHeight = tile_element_height(_loc); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = surfaceHeight; - res->GroundFlags = 0; - - money32 supportsCost = 0; - - if (_primaryColour > TILE_ELEMENT_COLOUR_MASK || _secondaryColour > TILE_ELEMENT_COLOUR_MASK) - { - log_error( - "Invalid game command for scenery placement, primaryColour = %u, secondaryColour = %u", _primaryColour, - _secondaryColour); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - if (_sceneryType >= MAX_LARGE_SCENERY_OBJECTS) - { - log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); - if (sceneryEntry == nullptr) - { - log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - uint32_t totalNumTiles = GetTotalNumTiles(sceneryEntry->large_scenery.tiles); - int16_t maxHeight = GetMaxSurfaceHeight(sceneryEntry->large_scenery.tiles); - - if (_loc.z != 0) - { - maxHeight = _loc.z; - } - - res->Position.z = maxHeight; - - if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - if (_bannerId == BANNER_INDEX_NULL) - { - log_error("Banner Index not specified."); - return MakeResult(GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); - } - - auto banner = GetBanner(_bannerId); - if (!banner->IsNull()) - { - log_error("No free banners available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - } - - if (!map_check_free_elements_and_reorganise(totalNumTiles)) - { - log_error("No free map elements available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - - uint8_t tileNum = 0; - for (rct_large_scenery_tile* tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; tile++, tileNum++) - { - auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); - - curTile.x += _loc.x; - curTile.y += _loc.y; - - int32_t zLow = tile->z_offset + maxHeight; - int32_t zHigh = tile->z_clearance + zLow; - - QuarterTile quarterTile = QuarterTile{ static_cast(tile->flags >> 12), 0 }.Rotate(_loc.direction); - if (!map_can_construct_with_clear_at( - { curTile, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost, - CREATE_CROSSING_MODE_NONE)) - { - return std::make_unique( - GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); - } - - int32_t tempSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - if (!gCheatsDisableClearanceChecks) - { - if ((gMapGroundFlags & ELEMENT_IS_UNDERWATER) || (gMapGroundFlags & ELEMENT_IS_UNDERGROUND)) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); - } - if (res->GroundFlags && !(res->GroundFlags & tempSceneryGroundFlags)) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); - } - } - - res->GroundFlags = tempSceneryGroundFlags; - - if (!LocationValid(curTile) || curTile.x >= gMapSizeUnits || curTile.y >= gMapSizeUnits) - { - return std::make_unique(GameActions::Status::Disallowed, STR_OFF_EDGE_OF_MAP); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_owned({ curTile, zLow }) - && !gCheatsSandboxMode) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - res->Cost = (sceneryEntry->large_scenery.price * 10) + supportsCost; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - res->ErrorTitle = STR_CANT_POSITION_THIS_HERE; - res->Expenditure = ExpenditureType::Landscaping; - - int16_t surfaceHeight = tile_element_height(_loc); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = surfaceHeight; - res->GroundFlags = 0; - - money32 supportsCost = 0; - - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType); - if (sceneryEntry == nullptr) - { - log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - if (sceneryEntry->large_scenery.tiles == nullptr) - { - log_error("Invalid large scenery object, sceneryType = %u", _sceneryType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - uint32_t totalNumTiles = GetTotalNumTiles(sceneryEntry->large_scenery.tiles); - int16_t maxHeight = GetMaxSurfaceHeight(sceneryEntry->large_scenery.tiles); - - if (_loc.z != 0) - { - maxHeight = _loc.z; - } - - res->Position.z = maxHeight; - - if (!map_check_free_elements_and_reorganise(totalNumTiles)) - { - log_error("No free map elements available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - - uint8_t tileNum = 0; - for (rct_large_scenery_tile* tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; tile++, tileNum++) - { - auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); - - curTile.x += _loc.x; - curTile.y += _loc.y; - - int32_t zLow = tile->z_offset + maxHeight; - int32_t zHigh = tile->z_clearance + zLow; - - QuarterTile quarterTile = QuarterTile{ static_cast(tile->flags >> 12), 0 }.Rotate(_loc.direction); - if (!map_can_construct_with_clear_at( - { curTile, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost, - CREATE_CROSSING_MODE_NONE)) - { - return std::make_unique( - GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); - } - - res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter({ curTile, zLow }); - if (!gCheatsDisableClearanceChecks) - { - wall_remove_at({ curTile, zLow, zHigh }); - } - } - - TileElement* newTileElement = tile_element_insert( - CoordsXYZ{ curTile.x, curTile.y, zLow }, quarterTile.GetBaseQuarterOccupied()); - Guard::Assert(newTileElement != nullptr); - map_animation_create(MAP_ANIMATION_TYPE_LARGE_SCENERY, { curTile, zLow }); - newTileElement->SetType(TILE_ELEMENT_TYPE_LARGE_SCENERY); - newTileElement->SetClearanceZ(zHigh); - auto newSceneryElement = newTileElement->AsLargeScenery(); - - SetNewLargeSceneryElement(*newSceneryElement, tileNum); - - if (tileNum == 0) - { - res->tileElement = newTileElement; - } - map_invalidate_tile_full(curTile); - } - - // Allocate banner after all tiles to ensure banner id doesn't need to be freed. - if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - if (_bannerId == BANNER_INDEX_NULL) - { - log_error("No free banners available"); - return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_BANNERS_IN_GAME); - } - - auto banner = GetBanner(_bannerId); - if (!banner->IsNull()) - { - log_error("No free banners available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - - banner->text = {}; - banner->colour = 2; - banner->text_colour = 2; - banner->flags = BANNER_FLAG_IS_LARGE_SCENERY; - banner->type = 0; - banner->position = TileCoordsXY(_loc); - - ride_id_t rideIndex = banner_get_closest_ride_index({ _loc, maxHeight }); - if (rideIndex != RIDE_ID_NULL) - { - banner->ride_index = rideIndex; - banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; - } - } - - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - res->Cost = (sceneryEntry->large_scenery.price * 10) + supportsCost; - return res; - } - -private: - int16_t GetTotalNumTiles(rct_large_scenery_tile * tiles) const - { - uint32_t totalNumTiles = 0; - for (rct_large_scenery_tile* tile = tiles; tile->x_offset != -1; tile++) - { - totalNumTiles++; - } - return totalNumTiles; - } - - int16_t GetMaxSurfaceHeight(rct_large_scenery_tile * tiles) const - { - int16_t maxHeight = -1; - for (rct_large_scenery_tile* tile = tiles; tile->x_offset != -1; tile++) - { - auto curTile = CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction); - - curTile.x += _loc.x; - curTile.y += _loc.y; - - if (!map_is_location_valid(curTile)) - { - continue; - } - - auto* surfaceElement = map_get_surface_element_at(curTile); - if (surfaceElement == nullptr) - continue; - - int32_t baseZ = surfaceElement->GetBaseZ(); - int32_t slope = surfaceElement->GetSlope(); - - if ((slope & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) != TILE_ELEMENT_SLOPE_FLAT) - { - baseZ += LAND_HEIGHT_STEP; - if (slope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) - { - baseZ += LAND_HEIGHT_STEP; - } - } - - if (baseZ > maxHeight) - { - maxHeight = baseZ; - } - } - return maxHeight; - } - - void SetNewLargeSceneryElement(LargeSceneryElement & sceneryElement, uint8_t tileNum) const - { - sceneryElement.SetDirection(_loc.direction); - sceneryElement.SetEntryIndex(_sceneryType); - sceneryElement.SetSequenceIndex(tileNum); - sceneryElement.SetPrimaryColour(_primaryColour); - sceneryElement.SetSecondaryColour(_secondaryColour); - - if (_bannerId != BANNER_INDEX_NULL) - { - sceneryElement.SetBannerIndex(_bannerId); - } - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - sceneryElement.SetGhost(true); - } - } -}; diff --git a/src/openrct2/actions/LargeSceneryRemoveAction.cpp b/src/openrct2/actions/LargeSceneryRemoveAction.cpp new file mode 100644 index 0000000000..f96e7ea160 --- /dev/null +++ b/src/openrct2/actions/LargeSceneryRemoveAction.cpp @@ -0,0 +1,227 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "LargeSceneryRemoveAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../world/Park.h" +#include "../world/SmallScenery.h" +#include "../world/Sprite.h" + +void LargeSceneryRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("tileIndex", _tileIndex); +} + +void LargeSceneryRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_tileIndex); +} + +GameActions::Result::Ptr LargeSceneryRemoveAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + const uint32_t flags = GetFlags(); + + int32_t z = tile_element_height(_loc); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = z; + res->Expenditure = ExpenditureType::Landscaping; + res->Cost = 0; + + TileElement* tileElement = FindLargeSceneryElement(); + if (tileElement == nullptr) + { + log_warning("Invalid game command for scenery removal, x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); + } + + rct_scenery_entry* scenery_entry = tileElement->AsLargeScenery()->GetEntry(); + + auto rotatedOffsets = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[_tileIndex].x_offset, + scenery_entry->large_scenery.tiles[_tileIndex].y_offset } + .Rotate(_loc.direction), + scenery_entry->large_scenery.tiles[_tileIndex].z_offset }; + + auto firstTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedOffsets; + + bool calculate_cost = true; + for (int32_t i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; i++) + { + auto currentTileRotatedOffset = CoordsXYZ{ + CoordsXY{ scenery_entry->large_scenery.tiles[i].x_offset, scenery_entry->large_scenery.tiles[i].y_offset }.Rotate( + _loc.direction), + scenery_entry->large_scenery.tiles[i].z_offset + }; + + auto currentTile = CoordsXYZ{ firstTile.x, firstTile.y, firstTile.z } + currentTileRotatedOffset; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_owned({ currentTile.x, currentTile.y, currentTile.z })) + { + return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + if (!LocationValid(currentTile)) + { + return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + // Prevent duplicate costs when using the clear scenery tool that overlaps multiple large + // scenery tile elements. + if (flags & GAME_COMMAND_FLAG_PATH_SCENERY) + { + if (tileElement->AsLargeScenery()->IsAccounted()) + calculate_cost = false; + + // Sets the flag to prevent this being counted in additional calls + tileElement->AsLargeScenery()->SetIsAccounted(true); + } + } + + if (calculate_cost) + res->Cost = scenery_entry->large_scenery.removal_price * 10; + + return res; +} + +GameActions::Result::Ptr LargeSceneryRemoveAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + const uint32_t flags = GetFlags(); + + int32_t z = tile_element_height(_loc); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = z; + res->Expenditure = ExpenditureType::Landscaping; + res->Cost = 0; + + TileElement* tileElement = FindLargeSceneryElement(); + if (tileElement == nullptr) + { + log_warning("Invalid game command for scenery removal, x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); + } + + tile_element_remove_banner_entry(tileElement); + + rct_scenery_entry* scenery_entry = tileElement->AsLargeScenery()->GetEntry(); + + auto rotatedFirstTile = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[_tileIndex].x_offset, + scenery_entry->large_scenery.tiles[_tileIndex].y_offset } + .Rotate(_loc.direction), + scenery_entry->large_scenery.tiles[_tileIndex].z_offset }; + + auto firstTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedFirstTile; + + for (int32_t i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; i++) + { + auto rotatedCurrentTile = CoordsXYZ{ + CoordsXY{ scenery_entry->large_scenery.tiles[i].x_offset, scenery_entry->large_scenery.tiles[i].y_offset }.Rotate( + _loc.direction), + scenery_entry->large_scenery.tiles[i].z_offset + }; + + auto currentTile = CoordsXYZ{ firstTile.x, firstTile.y, firstTile.z } + rotatedCurrentTile; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_owned({ currentTile.x, currentTile.y, currentTile.z })) + { + return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + TileElement* sceneryElement = map_get_first_element_at(currentTile); + bool element_found = false; + if (sceneryElement != nullptr) + { + do + { + if (sceneryElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) + continue; + + if (sceneryElement->GetDirection() != _loc.direction) + continue; + + if (sceneryElement->AsLargeScenery()->GetSequenceIndex() != i) + continue; + + if (sceneryElement->GetBaseZ() != currentTile.z) + continue; + + // If we are removing ghost elements + if ((flags & GAME_COMMAND_FLAG_GHOST) && sceneryElement->IsGhost() == false) + continue; + + map_invalidate_tile_full(currentTile); + tile_element_remove(sceneryElement); + + element_found = true; + break; + } while (!(sceneryElement++)->IsLastForTile()); + } + + if (element_found == false) + { + log_error("Tile not found when trying to remove element!"); + } + } + + res->Cost = scenery_entry->large_scenery.removal_price * 10; + + return res; +} + +TileElement* LargeSceneryRemoveAction::FindLargeSceneryElement() const +{ + TileElement* tileElement = map_get_first_element_at(_loc); + if (tileElement == nullptr) + return nullptr; + + do + { + if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) + continue; + + if (tileElement->GetBaseZ() != _loc.z) + continue; + + if (tileElement->AsLargeScenery()->GetSequenceIndex() != _tileIndex) + continue; + + if (tileElement->GetDirection() != _loc.direction) + continue; + + // If we are removing ghost elements + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && tileElement->IsGhost() == false) + continue; + + return tileElement; + + } while (!(tileElement++)->IsLastForTile()); + + return nullptr; +} diff --git a/src/openrct2/actions/LargeSceneryRemoveAction.h b/src/openrct2/actions/LargeSceneryRemoveAction.h new file mode 100644 index 0000000000..46a1153072 --- /dev/null +++ b/src/openrct2/actions/LargeSceneryRemoveAction.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(LargeSceneryRemoveAction, GAME_COMMAND_REMOVE_LARGE_SCENERY, GameActions::Result) +{ +private: + CoordsXYZD _loc; + uint16_t _tileIndex{}; + +public: + LargeSceneryRemoveAction() = default; + + LargeSceneryRemoveAction(const CoordsXYZD& location, uint16_t tileIndex) + : _loc(location) + , _tileIndex(tileIndex) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + TileElement* FindLargeSceneryElement() const; +}; diff --git a/src/openrct2/actions/LargeSceneryRemoveAction.hpp b/src/openrct2/actions/LargeSceneryRemoveAction.hpp deleted file mode 100644 index d29e81b479..0000000000 --- a/src/openrct2/actions/LargeSceneryRemoveAction.hpp +++ /dev/null @@ -1,248 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../world/Park.h" -#include "../world/SmallScenery.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LargeSceneryRemoveAction, GAME_COMMAND_REMOVE_LARGE_SCENERY, GameActions::Result) -{ -private: - CoordsXYZD _loc; - uint16_t _tileIndex{}; - -public: - LargeSceneryRemoveAction() = default; - - LargeSceneryRemoveAction(const CoordsXYZD& location, uint16_t tileIndex) - : _loc(location) - , _tileIndex(tileIndex) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("tileIndex", _tileIndex); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_tileIndex); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - const uint32_t flags = GetFlags(); - - int32_t z = tile_element_height(_loc); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = z; - res->Expenditure = ExpenditureType::Landscaping; - res->Cost = 0; - - TileElement* tileElement = FindLargeSceneryElement(); - if (tileElement == nullptr) - { - log_warning("Invalid game command for scenery removal, x = %d, y = %d", _loc.x, _loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); - } - - rct_scenery_entry* scenery_entry = tileElement->AsLargeScenery()->GetEntry(); - - auto rotatedOffsets = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[_tileIndex].x_offset, - scenery_entry->large_scenery.tiles[_tileIndex].y_offset } - .Rotate(_loc.direction), - scenery_entry->large_scenery.tiles[_tileIndex].z_offset }; - - auto firstTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedOffsets; - - bool calculate_cost = true; - for (int32_t i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; i++) - { - auto currentTileRotatedOffset = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[i].x_offset, - scenery_entry->large_scenery.tiles[i].y_offset } - .Rotate(_loc.direction), - scenery_entry->large_scenery.tiles[i].z_offset }; - - auto currentTile = CoordsXYZ{ firstTile.x, firstTile.y, firstTile.z } + currentTileRotatedOffset; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_owned({ currentTile.x, currentTile.y, currentTile.z })) - { - return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - if (!LocationValid(currentTile)) - { - return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - // Prevent duplicate costs when using the clear scenery tool that overlaps multiple large - // scenery tile elements. - if (flags & GAME_COMMAND_FLAG_PATH_SCENERY) - { - if (tileElement->AsLargeScenery()->IsAccounted()) - calculate_cost = false; - - // Sets the flag to prevent this being counted in additional calls - tileElement->AsLargeScenery()->SetIsAccounted(true); - } - } - - if (calculate_cost) - res->Cost = scenery_entry->large_scenery.removal_price * 10; - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - const uint32_t flags = GetFlags(); - - int32_t z = tile_element_height(_loc); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = z; - res->Expenditure = ExpenditureType::Landscaping; - res->Cost = 0; - - TileElement* tileElement = FindLargeSceneryElement(); - if (tileElement == nullptr) - { - log_warning("Invalid game command for scenery removal, x = %d, y = %d", _loc.x, _loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); - } - - tile_element_remove_banner_entry(tileElement); - - rct_scenery_entry* scenery_entry = tileElement->AsLargeScenery()->GetEntry(); - - auto rotatedFirstTile = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[_tileIndex].x_offset, - scenery_entry->large_scenery.tiles[_tileIndex].y_offset } - .Rotate(_loc.direction), - scenery_entry->large_scenery.tiles[_tileIndex].z_offset }; - - auto firstTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedFirstTile; - - for (int32_t i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; i++) - { - auto rotatedCurrentTile = CoordsXYZ{ CoordsXY{ scenery_entry->large_scenery.tiles[i].x_offset, - scenery_entry->large_scenery.tiles[i].y_offset } - .Rotate(_loc.direction), - scenery_entry->large_scenery.tiles[i].z_offset }; - - auto currentTile = CoordsXYZ{ firstTile.x, firstTile.y, firstTile.z } + rotatedCurrentTile; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_owned({ currentTile.x, currentTile.y, currentTile.z })) - { - return MakeResult(GameActions::Status::NoClearance, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - TileElement* sceneryElement = map_get_first_element_at(currentTile); - bool element_found = false; - if (sceneryElement != nullptr) - { - do - { - if (sceneryElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) - continue; - - if (sceneryElement->GetDirection() != _loc.direction) - continue; - - if (sceneryElement->AsLargeScenery()->GetSequenceIndex() != i) - continue; - - if (sceneryElement->GetBaseZ() != currentTile.z) - continue; - - // If we are removing ghost elements - if ((flags & GAME_COMMAND_FLAG_GHOST) && sceneryElement->IsGhost() == false) - continue; - - map_invalidate_tile_full(currentTile); - tile_element_remove(sceneryElement); - - element_found = true; - break; - } while (!(sceneryElement++)->IsLastForTile()); - } - - if (element_found == false) - { - log_error("Tile not found when trying to remove element!"); - } - } - - res->Cost = scenery_entry->large_scenery.removal_price * 10; - - return res; - } - -private: - TileElement* FindLargeSceneryElement() const - { - TileElement* tileElement = map_get_first_element_at(_loc); - if (tileElement == nullptr) - return nullptr; - - do - { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) - continue; - - if (tileElement->GetBaseZ() != _loc.z) - continue; - - if (tileElement->AsLargeScenery()->GetSequenceIndex() != _tileIndex) - continue; - - if (tileElement->GetDirection() != _loc.direction) - continue; - - // If we are removing ghost elements - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && tileElement->IsGhost() == false) - continue; - - return tileElement; - - } while (!(tileElement++)->IsLastForTile()); - - return nullptr; - } -}; diff --git a/src/openrct2/actions/LargeScenerySetColourAction.cpp b/src/openrct2/actions/LargeScenerySetColourAction.cpp new file mode 100644 index 0000000000..65f96183cc --- /dev/null +++ b/src/openrct2/actions/LargeScenerySetColourAction.cpp @@ -0,0 +1,128 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "LargeScenerySetColourAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../world/Scenery.h" + +void LargeScenerySetColourAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_tileIndex) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour); +} + +GameActions::Result::Ptr LargeScenerySetColourAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr LargeScenerySetColourAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr LargeScenerySetColourAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = tile_element_height(_loc); + res->ErrorTitle = STR_CANT_REPAINT_THIS; + + if (_loc.x < 0 || _loc.y < 0 || _loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY) + { + log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (_primaryColour > 31) + { + log_error("Invalid primary colour: colour = %u", _primaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (_secondaryColour > 31) + { + log_error("Invalid primary colour: colour = %u", _secondaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + auto largeElement = map_get_large_scenery_segment(_loc, _tileIndex); + + if (largeElement == nullptr) + { + log_error( + "Could not find large scenery at: x = %d, y = %d, z = %d, direction = %d, tileIndex = %u", _loc.x, _loc.y, _loc.z, + _loc.direction, _tileIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(largeElement->IsGhost())) + { + return res; + } + + rct_scenery_entry* sceneryEntry = largeElement->GetEntry(); + + if (sceneryEntry == nullptr) + { + log_error("Could not find scenery object. type = %u", largeElement->GetEntryIndex()); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + // Work out the base tile coordinates (Tile with index 0) + auto rotatedBaseCoordsOffset = CoordsXYZ{ CoordsXY{ sceneryEntry->large_scenery.tiles[_tileIndex].x_offset, + sceneryEntry->large_scenery.tiles[_tileIndex].y_offset } + .Rotate(_loc.direction), + sceneryEntry->large_scenery.tiles[_tileIndex].z_offset }; + + auto baseTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedBaseCoordsOffset; + + auto i = 0; + for (auto tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; ++tile, ++i) + { + // Work out the current tile coordinates + auto rotatedTileCoords = CoordsXYZ{ CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction), tile->z_offset }; + auto currentTile = CoordsXYZ{ baseTile.x, baseTile.y, baseTile.z } + rotatedTileCoords; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_owned(currentTile)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + if (!LocationValid(currentTile)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto tileElement = map_get_large_scenery_segment({ currentTile.x, currentTile.y, _loc.z, _loc.direction }, i); + + if (tileElement == nullptr) + { + log_error( + "Large scenery element not found at: x = %d, y = %d, z = %d, direction = %d", _loc.x, _loc.y, _loc.z, + _loc.direction); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + if (isExecuting) + { + tileElement->SetPrimaryColour(_primaryColour); + tileElement->SetSecondaryColour(_secondaryColour); + + map_invalidate_tile_full(currentTile); + } + } + return res; +} diff --git a/src/openrct2/actions/LargeScenerySetColourAction.h b/src/openrct2/actions/LargeScenerySetColourAction.h new file mode 100644 index 0000000000..4329492b98 --- /dev/null +++ b/src/openrct2/actions/LargeScenerySetColourAction.h @@ -0,0 +1,44 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(LargeScenerySetColourAction, GAME_COMMAND_SET_LARGE_SCENERY_COLOUR, GameActions::Result) +{ +private: + CoordsXYZD _loc; + uint8_t _tileIndex{}; + uint8_t _primaryColour{}; + uint8_t _secondaryColour{}; + +public: + LargeScenerySetColourAction() = default; + + LargeScenerySetColourAction(const CoordsXYZD& loc, uint8_t tileIndex, uint8_t primaryColour, uint8_t secondaryColour) + : _loc(loc) + , _tileIndex(tileIndex) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/LargeScenerySetColourAction.hpp b/src/openrct2/actions/LargeScenerySetColourAction.hpp deleted file mode 100644 index 1bfdb9c472..0000000000 --- a/src/openrct2/actions/LargeScenerySetColourAction.hpp +++ /dev/null @@ -1,156 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../world/Scenery.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(LargeScenerySetColourAction, GAME_COMMAND_SET_LARGE_SCENERY_COLOUR, GameActions::Result) -{ -private: - CoordsXYZD _loc; - uint8_t _tileIndex{}; - uint8_t _primaryColour{}; - uint8_t _secondaryColour{}; - -public: - LargeScenerySetColourAction() = default; - - LargeScenerySetColourAction(const CoordsXYZD& loc, uint8_t tileIndex, uint8_t primaryColour, uint8_t secondaryColour) - : _loc(loc) - , _tileIndex(tileIndex) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_tileIndex) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = tile_element_height(_loc); - res->ErrorTitle = STR_CANT_REPAINT_THIS; - - if (_loc.x < 0 || _loc.y < 0 || _loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY) - { - log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (_primaryColour > 31) - { - log_error("Invalid primary colour: colour = %u", _primaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (_secondaryColour > 31) - { - log_error("Invalid primary colour: colour = %u", _secondaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - auto largeElement = map_get_large_scenery_segment(_loc, _tileIndex); - - if (largeElement == nullptr) - { - log_error( - "Could not find large scenery at: x = %d, y = %d, z = %d, direction = %d, tileIndex = %u", _loc.x, _loc.y, - _loc.z, _loc.direction, _tileIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(largeElement->IsGhost())) - { - return res; - } - - rct_scenery_entry* sceneryEntry = largeElement->GetEntry(); - - if (sceneryEntry == nullptr) - { - log_error("Could not find scenery object. type = %u", largeElement->GetEntryIndex()); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - // Work out the base tile coordinates (Tile with index 0) - auto rotatedBaseCoordsOffset = CoordsXYZ{ CoordsXY{ sceneryEntry->large_scenery.tiles[_tileIndex].x_offset, - sceneryEntry->large_scenery.tiles[_tileIndex].y_offset } - .Rotate(_loc.direction), - sceneryEntry->large_scenery.tiles[_tileIndex].z_offset }; - - auto baseTile = CoordsXYZ{ _loc.x, _loc.y, _loc.z } - rotatedBaseCoordsOffset; - - auto i = 0; - for (auto tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; ++tile, ++i) - { - // Work out the current tile coordinates - auto rotatedTileCoords = CoordsXYZ{ CoordsXY{ tile->x_offset, tile->y_offset }.Rotate(_loc.direction), - tile->z_offset }; - auto currentTile = CoordsXYZ{ baseTile.x, baseTile.y, baseTile.z } + rotatedTileCoords; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_owned(currentTile)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - if (!LocationValid(currentTile)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - auto tileElement = map_get_large_scenery_segment({ currentTile.x, currentTile.y, _loc.z, _loc.direction }, i); - - if (tileElement == nullptr) - { - log_error( - "Large scenery element not found at: x = %d, y = %d, z = %d, direction = %d", _loc.x, _loc.y, _loc.z, - _loc.direction); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - if (isExecuting) - { - tileElement->SetPrimaryColour(_primaryColour); - tileElement->SetSecondaryColour(_secondaryColour); - - map_invalidate_tile_full(currentTile); - } - } - return res; - } -}; diff --git a/src/openrct2/actions/LoadOrQuitAction.cpp b/src/openrct2/actions/LoadOrQuitAction.cpp new file mode 100644 index 0000000000..d238bbba0f --- /dev/null +++ b/src/openrct2/actions/LoadOrQuitAction.cpp @@ -0,0 +1,44 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "LoadOrQuitAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" + +void LoadOrQuitAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_mode) << DS_TAG(_savePromptMode); +} + +GameActions::Result::Ptr LoadOrQuitAction::Query() const +{ + return std::make_unique(); +} + +GameActions::Result::Ptr LoadOrQuitAction::Execute() const +{ + auto mode = static_cast(_mode); + switch (mode) + { + case LoadOrQuitModes::OpenSavePrompt: + gSavePromptMode = _savePromptMode; + context_open_window(WC_SAVE_PROMPT); + break; + case LoadOrQuitModes::CloseSavePrompt: + window_close_by_class(WC_SAVE_PROMPT); + break; + default: + game_load_or_quit_no_save_prompt(); + break; + } + return std::make_unique(); +} diff --git a/src/openrct2/actions/LoadOrQuitAction.hpp b/src/openrct2/actions/LoadOrQuitAction.h similarity index 51% rename from src/openrct2/actions/LoadOrQuitAction.hpp rename to src/openrct2/actions/LoadOrQuitAction.h index effe1b8fd1..d5bec9f38c 100644 --- a/src/openrct2/actions/LoadOrQuitAction.hpp +++ b/src/openrct2/actions/LoadOrQuitAction.h @@ -9,8 +9,6 @@ #pragma once -#include "../Context.h" -#include "../OpenRCT2.h" #include "GameAction.h" enum class LoadOrQuitModes : uint8_t @@ -35,37 +33,10 @@ public: uint16_t GetActionFlags() const override { - return GameAction::GetActionFlags() | GameActions::Flags::ClientOnly | GameActions::Flags::AllowWhilePaused; + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_mode) << DS_TAG(_savePromptMode); - } - - GameActions::Result::Ptr Query() const override - { - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto mode = static_cast(_mode); - switch (mode) - { - case LoadOrQuitModes::OpenSavePrompt: - gSavePromptMode = _savePromptMode; - context_open_window(WC_SAVE_PROMPT); - break; - case LoadOrQuitModes::CloseSavePrompt: - window_close_by_class(WC_SAVE_PROMPT); - break; - default: - game_load_or_quit_no_save_prompt(); - break; - } - return std::make_unique(); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/MazePlaceTrackAction.cpp b/src/openrct2/actions/MazePlaceTrackAction.cpp new file mode 100644 index 0000000000..732129d9da --- /dev/null +++ b/src/openrct2/actions/MazePlaceTrackAction.cpp @@ -0,0 +1,191 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ +#include "MazePlaceTrackAction.h" + +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../ride/TrackData.h" + +void MazePlaceTrackAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("ride", _rideIndex); + visitor.Visit("mazeEntry", _mazeEntry); +} + +void MazePlaceTrackAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_loc) << DS_TAG(_rideIndex) << DS_TAG(_mazeEntry); +} + +GameActions::Result::Ptr MazePlaceTrackAction::Query() const +{ + auto res = std::make_unique(); + + res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; + res->Expenditure = ExpenditureType::RideConstruction; + res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + if (!map_check_free_elements_and_reorganise(1)) + { + res->Error = GameActions::Status::NoFreeElements; + res->ErrorMessage = STR_TILE_ELEMENT_LIMIT_REACHED; + return res; + } + if ((_loc.z & 0xF) != 0) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_CONSTRUCTION_ERR_UNKNOWN; + return res; + } + + if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode)) + { + res->Error = GameActions::Status::NotOwned; + res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; + return res; + } + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; + return res; + } + + auto baseHeight = _loc.z; + auto clearanceHeight = _loc.z + MAZE_CLEARANCE_HEIGHT; + + auto heightDifference = baseHeight - surfaceElement->GetBaseZ(); + if (heightDifference >= 0 && !gCheatsDisableSupportLimits) + { + heightDifference /= COORDS_Z_PER_TINY_Z; + + if (heightDifference > RideTypeDescriptors[RIDE_TYPE_MAZE].Heights.MaxHeight) + { + res->Error = GameActions::Status::TooHigh; + res->ErrorMessage = STR_TOO_HIGH_FOR_SUPPORTS; + return res; + } + } + + money32 clearCost = 0; + + if (!map_can_construct_with_clear_at( + { _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags(), + &clearCost, CREATE_CROSSING_MODE_NONE)) + { + return MakeResult( + GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), gGameCommandErrorText, gCommonFormatArgs); + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorMessage = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; + return res; + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERGROUND) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorMessage = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + return res; + } + + auto ride = get_ride(_rideIndex); + if (ride == nullptr || ride->type == RIDE_TYPE_NULL) + { + res->Error = GameActions::Status::InvalidParameters; + res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; + return res; + } + + money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); + res->Cost = clearCost + price / 2 * 10; + + return res; +} + +GameActions::Result::Ptr MazePlaceTrackAction::Execute() const +{ + auto res = std::make_unique(); + + res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; + res->Expenditure = ExpenditureType::RideConstruction; + res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + res->Error = GameActions::Status::InvalidParameters; + res->ErrorMessage = STR_NONE; + return res; + } + + if (!map_check_free_elements_and_reorganise(1)) + { + res->Error = GameActions::Status::NoFreeElements; + res->ErrorMessage = STR_NONE; + return res; + } + + uint32_t flags = GetFlags(); + if (!(flags & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter(_loc); + wall_remove_at({ _loc.ToTileStart(), _loc.z, _loc.z + 32 }); + } + + auto baseHeight = _loc.z; + auto clearanceHeight = _loc.z + MAZE_CLEARANCE_HEIGHT; + + money32 clearCost = 0; + if (!map_can_construct_with_clear_at( + { _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, + GetFlags() | GAME_COMMAND_FLAG_APPLY, &clearCost, CREATE_CROSSING_MODE_NONE)) + { + return MakeResult( + GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), gGameCommandErrorText, gCommonFormatArgs); + } + + money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); + res->Cost = clearCost + price / 2 * 10; + + auto startLoc = _loc.ToTileStart(); + + auto tileElement = tile_element_insert(_loc, 0b1111); + assert(tileElement != nullptr); + + tileElement->SetClearanceZ(clearanceHeight); + tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); + + tileElement->AsTrack()->SetTrackType(TrackElemType::Maze); + tileElement->AsTrack()->SetRideIndex(_rideIndex); + tileElement->AsTrack()->SetMazeEntry(_mazeEntry); + + if (flags & GAME_COMMAND_FLAG_GHOST) + { + tileElement->SetGhost(true); + } + + map_invalidate_tile_full(startLoc); + + ride->maze_tiles++; + ride->stations[0].SetBaseZ(tileElement->GetBaseZ()); + ride->stations[0].Start = { 0, 0 }; + + if (ride->maze_tiles == 1) + { + ride->overall_view = startLoc; + } + + return res; +} diff --git a/src/openrct2/actions/MazePlaceTrackAction.h b/src/openrct2/actions/MazePlaceTrackAction.h new file mode 100644 index 0000000000..3127a1f75b --- /dev/null +++ b/src/openrct2/actions/MazePlaceTrackAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(MazePlaceTrackAction, GAME_COMMAND_PLACE_MAZE_DESIGN, GameActions::Result) +{ +private: + CoordsXYZ _loc; + NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; + uint16_t _mazeEntry{}; + +public: + MazePlaceTrackAction() = default; + + MazePlaceTrackAction(const CoordsXYZ& location, NetworkRideId_t rideIndex, uint16_t mazeEntry) + : _loc(location) + , _rideIndex(rideIndex) + , _mazeEntry(mazeEntry) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/MazePlaceTrackAction.hpp b/src/openrct2/actions/MazePlaceTrackAction.hpp deleted file mode 100644 index ade7d3761c..0000000000 --- a/src/openrct2/actions/MazePlaceTrackAction.hpp +++ /dev/null @@ -1,210 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ -#pragma once - -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../ride/TrackData.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(MazePlaceTrackAction, GAME_COMMAND_PLACE_MAZE_DESIGN, GameActions::Result) -{ -private: - CoordsXYZ _loc; - NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; - uint16_t _mazeEntry{}; - -public: - MazePlaceTrackAction() = default; - - MazePlaceTrackAction(const CoordsXYZ& location, NetworkRideId_t rideIndex, uint16_t mazeEntry) - : _loc(location) - , _rideIndex(rideIndex) - , _mazeEntry(mazeEntry) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("ride", _rideIndex); - visitor.Visit("mazeEntry", _mazeEntry); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_loc) << DS_TAG(_rideIndex) << DS_TAG(_mazeEntry); - } - - GameActions::Result::Ptr Query() const override - { - auto res = std::make_unique(); - - res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; - res->Expenditure = ExpenditureType::RideConstruction; - res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - if (!map_check_free_elements_and_reorganise(1)) - { - res->Error = GameActions::Status::NoFreeElements; - res->ErrorMessage = STR_TILE_ELEMENT_LIMIT_REACHED; - return res; - } - if ((_loc.z & 0xF) != 0) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_CONSTRUCTION_ERR_UNKNOWN; - return res; - } - - if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode)) - { - res->Error = GameActions::Status::NotOwned; - res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; - return res; - } - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; - return res; - } - - auto baseHeight = _loc.z; - auto clearanceHeight = _loc.z + MAZE_CLEARANCE_HEIGHT; - - auto heightDifference = baseHeight - surfaceElement->GetBaseZ(); - if (heightDifference >= 0 && !gCheatsDisableSupportLimits) - { - heightDifference /= COORDS_Z_PER_TINY_Z; - - if (heightDifference > RideTypeDescriptors[RIDE_TYPE_MAZE].Heights.MaxHeight) - { - res->Error = GameActions::Status::TooHigh; - res->ErrorMessage = STR_TOO_HIGH_FOR_SUPPORTS; - return res; - } - } - - money32 clearCost = 0; - - if (!map_can_construct_with_clear_at( - { _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, - GetFlags(), &clearCost, CREATE_CROSSING_MODE_NONE)) - { - return MakeResult( - GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), gGameCommandErrorText, gCommonFormatArgs); - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorMessage = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; - return res; - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERGROUND) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorMessage = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; - return res; - } - - auto ride = get_ride(_rideIndex); - if (ride == nullptr || ride->type == RIDE_TYPE_NULL) - { - res->Error = GameActions::Status::InvalidParameters; - res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; - return res; - } - - money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); - res->Cost = clearCost + price / 2 * 10; - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - - res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; - res->Expenditure = ExpenditureType::RideConstruction; - res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - res->Error = GameActions::Status::InvalidParameters; - res->ErrorMessage = STR_NONE; - return res; - } - - if (!map_check_free_elements_and_reorganise(1)) - { - res->Error = GameActions::Status::NoFreeElements; - res->ErrorMessage = STR_NONE; - return res; - } - - uint32_t flags = GetFlags(); - if (!(flags & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter(_loc); - wall_remove_at({ _loc.ToTileStart(), _loc.z, _loc.z + 32 }); - } - - auto baseHeight = _loc.z; - auto clearanceHeight = _loc.z + MAZE_CLEARANCE_HEIGHT; - - money32 clearCost = 0; - if (!map_can_construct_with_clear_at( - { _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, - GetFlags() | GAME_COMMAND_FLAG_APPLY, &clearCost, CREATE_CROSSING_MODE_NONE)) - { - return MakeResult( - GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), gGameCommandErrorText, gCommonFormatArgs); - } - - money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); - res->Cost = clearCost + price / 2 * 10; - - auto startLoc = _loc.ToTileStart(); - - auto tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); - - tileElement->SetClearanceZ(clearanceHeight); - tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); - - tileElement->AsTrack()->SetTrackType(TrackElemType::Maze); - tileElement->AsTrack()->SetRideIndex(_rideIndex); - tileElement->AsTrack()->SetMazeEntry(_mazeEntry); - - if (flags & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } - - map_invalidate_tile_full(startLoc); - - ride->maze_tiles++; - ride->stations[0].SetBaseZ(tileElement->GetBaseZ()); - ride->stations[0].Start = { 0, 0 }; - - if (ride->maze_tiles == 1) - { - ride->overall_view = startLoc; - } - - return res; - } -}; diff --git a/src/openrct2/actions/MazeSetTrackAction.cpp b/src/openrct2/actions/MazeSetTrackAction.cpp new file mode 100644 index 0000000000..36be0f0cf3 --- /dev/null +++ b/src/openrct2/actions/MazeSetTrackAction.cpp @@ -0,0 +1,322 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "MazeSetTrackAction.h" + +#include "../Cheats.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../ride/Track.h" +#include "../ride/TrackData.h" +#include "../world/Footpath.h" +#include "../world/Park.h" + +void MazeSetTrackAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("ride", _rideIndex); + visitor.Visit("mode", _mode); + visitor.Visit("isInitialPlacement", _initialPlacement); +} + +void MazeSetTrackAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_loc) << DS_TAG(_loc.direction) << DS_TAG(_initialPlacement) << DS_TAG(_rideIndex) << DS_TAG(_mode); +} + +GameActions::Result::Ptr MazeSetTrackAction::Query() const +{ + auto res = std::make_unique(); + + res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; + res->Expenditure = ExpenditureType::RideConstruction; + res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + if (!map_check_free_elements_and_reorganise(1)) + { + res->Error = GameActions::Status::NoFreeElements; + res->ErrorMessage = STR_TILE_ELEMENT_LIMIT_REACHED; + return res; + } + if ((_loc.z & 0xF) != 0 && _mode == GC_SET_MAZE_TRACK_BUILD) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_CONSTRUCTION_ERR_UNKNOWN; + return res; + } + + if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode)) + { + res->Error = GameActions::Status::NotOwned; + res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; + return res; + } + + auto surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; + return res; + } + + auto baseHeight = _loc.z; + auto clearanceHeight = _loc.z + 32; + + auto heightDifference = baseHeight - surfaceElement->GetBaseZ(); + if (heightDifference >= 0 && !gCheatsDisableSupportLimits) + { + heightDifference /= COORDS_Z_PER_TINY_Z; + + if (heightDifference > RideTypeDescriptors[RIDE_TYPE_MAZE].Heights.MaxHeight) + { + res->Error = GameActions::Status::TooHigh; + res->ErrorMessage = STR_TOO_HIGH_FOR_SUPPORTS; + return res; + } + } + + TileElement* tileElement = map_get_track_element_at_of_type_from_ride(_loc, TrackElemType::Maze, _rideIndex); + if (tileElement == nullptr) + { + if (_mode != GC_SET_MAZE_TRACK_BUILD) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; + return res; + } + auto constructResult = MapCanConstructAt({ _loc.ToTileStart(), baseHeight, clearanceHeight }, { 0b1111, 0 }); + if (constructResult->Error != GameActions::Status::Ok) + { + return MakeResult( + GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), constructResult->ErrorMessage.GetStringId(), + constructResult->ErrorMessageArgs.data()); + } + + if (constructResult->GroundFlags & ELEMENT_IS_UNDERWATER) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorMessage = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; + return res; + } + + if (constructResult->GroundFlags & ELEMENT_IS_UNDERGROUND) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorMessage = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + return res; + } + + auto ride = get_ride(_rideIndex); + if (ride == nullptr || ride->type == RIDE_CRASH_TYPE_NONE) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; + return res; + } + + money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); + res->Cost = price / 2 * 10; + + return res; + } + + return std::make_unique(); +} + +GameActions::Result::Ptr MazeSetTrackAction::Execute() const +{ + auto res = std::make_unique(); + + res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; + res->Expenditure = ExpenditureType::RideConstruction; + res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + res->Error = GameActions::Status::InvalidParameters; + res->ErrorMessage = STR_NONE; + return res; + } + + if (!map_check_free_elements_and_reorganise(1)) + { + res->Error = GameActions::Status::NoFreeElements; + res->ErrorMessage = STR_NONE; + return res; + } + + uint32_t flags = GetFlags(); + if (!(flags & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter(_loc); + wall_remove_at({ _loc.ToTileStart(), _loc.z, _loc.z + 32 }); + } + + auto tileElement = map_get_track_element_at_of_type_from_ride(_loc, TrackElemType::Maze, _rideIndex); + if (tileElement == nullptr) + { + money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); + res->Cost = price / 2 * 10; + + auto startLoc = _loc.ToTileStart(); + + tileElement = tile_element_insert(_loc, 0b1111); + assert(tileElement != nullptr); + + tileElement->SetClearanceZ(_loc.z + MAZE_CLEARANCE_HEIGHT); + tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); + + tileElement->AsTrack()->SetTrackType(TrackElemType::Maze); + tileElement->AsTrack()->SetRideIndex(_rideIndex); + tileElement->AsTrack()->SetMazeEntry(0xFFFF); + + if (flags & GAME_COMMAND_FLAG_GHOST) + { + tileElement->SetGhost(true); + } + + map_invalidate_tile_full(startLoc); + + ride->maze_tiles++; + ride->stations[0].SetBaseZ(tileElement->GetBaseZ()); + ride->stations[0].Start = { 0, 0 }; + + if (_initialPlacement && !(flags & GAME_COMMAND_FLAG_GHOST)) + { + ride->overall_view = startLoc; + } + } + + switch (_mode) + { + case GC_SET_MAZE_TRACK_BUILD: + { + uint8_t segmentOffset = MazeGetSegmentBit(_loc.x, _loc.y); + + tileElement->AsTrack()->MazeEntrySubtract(1 << segmentOffset); + + if (!_initialPlacement) + { + segmentOffset = byte_993CE9[(_loc.direction + segmentOffset)]; + tileElement->AsTrack()->MazeEntrySubtract(1 << segmentOffset); + + uint8_t temp_edx = byte_993CFC[segmentOffset]; + if (temp_edx != 0xFF) + { + auto previousElementLoc = CoordsXY{ _loc }.ToTileStart() - CoordsDirectionDelta[_loc.direction]; + + TileElement* previousTileElement = map_get_track_element_at_of_type_from_ride( + { previousElementLoc, _loc.z }, TrackElemType::Maze, _rideIndex); + + if (previousTileElement != nullptr) + { + previousTileElement->AsTrack()->MazeEntrySubtract(1 << temp_edx); + } + else + { + tileElement->AsTrack()->MazeEntryAdd(1 << segmentOffset); + } + } + } + + break; + } + + case GC_SET_MAZE_TRACK_MOVE: + break; + + case GC_SET_MAZE_TRACK_FILL: + if (!_initialPlacement) + { + auto previousSegment = CoordsXY{ _loc.x - CoordsDirectionDelta[_loc.direction].x / 2, + _loc.y - CoordsDirectionDelta[_loc.direction].y / 2 }; + + tileElement = map_get_track_element_at_of_type_from_ride( + { previousSegment, _loc.z }, TrackElemType::Maze, _rideIndex); + + map_invalidate_tile_full(previousSegment.ToTileStart()); + if (tileElement == nullptr) + { + log_error("No surface found"); + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_NONE; + return res; + } + + uint32_t segmentBit = MazeGetSegmentBit(previousSegment.x, previousSegment.y); + + tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); + segmentBit--; + tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); + segmentBit = (segmentBit - 4) & 0x0F; + tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); + segmentBit = (segmentBit + 3) & 0x0F; + + do + { + tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); + + uint32_t direction1 = byte_993D0C[segmentBit]; + auto nextElementLoc = previousSegment.ToTileStart() + CoordsDirectionDelta[direction1]; + + TileElement* tmp_tileElement = map_get_track_element_at_of_type_from_ride( + { nextElementLoc, _loc.z }, TrackElemType::Maze, _rideIndex); + + if (tmp_tileElement != nullptr) + { + uint8_t edx11 = byte_993CFC[segmentBit]; + tmp_tileElement->AsTrack()->MazeEntryAdd(1 << (edx11)); + } + + segmentBit--; + } while ((segmentBit & 0x3) != 0x3); + } + break; + } + + map_invalidate_tile({ _loc.ToTileStart(), tileElement->GetBaseZ(), tileElement->GetClearanceZ() }); + + if ((tileElement->AsTrack()->GetMazeEntry() & 0x8888) == 0x8888) + { + tile_element_remove(tileElement); + sub_6CB945(ride); + ride->maze_tiles--; + } + + return res; +} + +uint8_t MazeSetTrackAction::MazeGetSegmentBit(uint16_t x, uint16_t y) const +{ + uint8_t minorX = x & 0x1F; // 0 or 16 + uint8_t minorY = y & 0x1F; // 0 or 16 + + if (minorX == 0 && minorY == 0) + { + return 3; + } + + if (minorY == 16 && minorX == 16) + { + return 11; + } + + if (minorY == 0) + { + return 15; + } + + return 7; +} diff --git a/src/openrct2/actions/MazeSetTrackAction.h b/src/openrct2/actions/MazeSetTrackAction.h new file mode 100644 index 0000000000..a983cfd458 --- /dev/null +++ b/src/openrct2/actions/MazeSetTrackAction.h @@ -0,0 +1,65 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" +// clang-format off +/** rct2: 0x00993CE9 */ +static constexpr const uint8_t byte_993CE9[] = { + 0xFF, 0xE0, 0xFF, + 14, 0, 1, 2, + 6, 2, 4, 5, + 9, 10, 6, 8, + 12, 13, 14, 10, +}; + +/** rct2: 0x00993CFC */ +static constexpr const uint8_t byte_993CFC[] = { + 5, 12, 0xFF, 0xFF, + 9, 0, 0xFF, 0xFF, + 13, 4, 0xFF, 0xFF, + 1, 8, 0xFF, 0xFF, +}; + +/** rct2: 0x00993D0C */ +static constexpr const uint8_t byte_993D0C[] = { + 3, 0, 0xFF, 0xFF, + 0, 1, 0xFF, 0xFF, + 1, 2, 0xFF, 0xFF, + 2, 3, 0xFF, 0xFF, +}; +// clang-format on + +DEFINE_GAME_ACTION(MazeSetTrackAction, GAME_COMMAND_SET_MAZE_TRACK, GameActions::Result) +{ +private: + CoordsXYZD _loc; + bool _initialPlacement{}; + NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; + uint8_t _mode{}; + +public: + MazeSetTrackAction() = default; + MazeSetTrackAction(const CoordsXYZD& location, bool initialPlacement, NetworkRideId_t rideIndex, uint8_t mode) + : _loc(location) + , _initialPlacement(initialPlacement) + , _rideIndex(rideIndex) + , _mode(mode) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + uint8_t MazeGetSegmentBit(uint16_t x, uint16_t y) const; +}; diff --git a/src/openrct2/actions/MazeSetTrackAction.hpp b/src/openrct2/actions/MazeSetTrackAction.hpp deleted file mode 100644 index 87076c3f0d..0000000000 --- a/src/openrct2/actions/MazeSetTrackAction.hpp +++ /dev/null @@ -1,370 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ -#pragma once - -#include "../Cheats.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../ride/Track.h" -#include "../ride/TrackData.h" -#include "../world/Footpath.h" -#include "../world/Park.h" -#include "GameAction.h" -// clang-format off -/** rct2: 0x00993CE9 */ -static constexpr const uint8_t byte_993CE9[] = { - 0xFF, 0xE0, 0xFF, - 14, 0, 1, 2, - 6, 2, 4, 5, - 9, 10, 6, 8, - 12, 13, 14, 10, -}; - -/** rct2: 0x00993CFC */ -static constexpr const uint8_t byte_993CFC[] = { - 5, 12, 0xFF, 0xFF, - 9, 0, 0xFF, 0xFF, - 13, 4, 0xFF, 0xFF, - 1, 8, 0xFF, 0xFF, -}; - -/** rct2: 0x00993D0C */ -static constexpr const uint8_t byte_993D0C[] = { - 3, 0, 0xFF, 0xFF, - 0, 1, 0xFF, 0xFF, - 1, 2, 0xFF, 0xFF, - 2, 3, 0xFF, 0xFF, -}; -// clang-format on - -DEFINE_GAME_ACTION(MazeSetTrackAction, GAME_COMMAND_SET_MAZE_TRACK, GameActions::Result) -{ -private: - CoordsXYZD _loc; - bool _initialPlacement{}; - NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; - uint8_t _mode{}; - -public: - MazeSetTrackAction() = default; - MazeSetTrackAction(const CoordsXYZD& location, bool initialPlacement, NetworkRideId_t rideIndex, uint8_t mode) - : _loc(location) - , _initialPlacement(initialPlacement) - , _rideIndex(rideIndex) - , _mode(mode) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("ride", _rideIndex); - visitor.Visit("mode", _mode); - visitor.Visit("isInitialPlacement", _initialPlacement); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_loc) << DS_TAG(_loc.direction) << DS_TAG(_initialPlacement) << DS_TAG(_rideIndex) << DS_TAG(_mode); - } - - GameActions::Result::Ptr Query() const override - { - auto res = std::make_unique(); - - res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; - res->Expenditure = ExpenditureType::RideConstruction; - res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - if (!map_check_free_elements_and_reorganise(1)) - { - res->Error = GameActions::Status::NoFreeElements; - res->ErrorMessage = STR_TILE_ELEMENT_LIMIT_REACHED; - return res; - } - if ((_loc.z & 0xF) != 0 && _mode == GC_SET_MAZE_TRACK_BUILD) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_CONSTRUCTION_ERR_UNKNOWN; - return res; - } - - if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode)) - { - res->Error = GameActions::Status::NotOwned; - res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; - return res; - } - - auto surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; - return res; - } - - auto baseHeight = _loc.z; - auto clearanceHeight = _loc.z + 32; - - auto heightDifference = baseHeight - surfaceElement->GetBaseZ(); - if (heightDifference >= 0 && !gCheatsDisableSupportLimits) - { - heightDifference /= COORDS_Z_PER_TINY_Z; - - if (heightDifference > RideTypeDescriptors[RIDE_TYPE_MAZE].Heights.MaxHeight) - { - res->Error = GameActions::Status::TooHigh; - res->ErrorMessage = STR_TOO_HIGH_FOR_SUPPORTS; - return res; - } - } - - TileElement* tileElement = map_get_track_element_at_of_type_from_ride(_loc, TrackElemType::Maze, _rideIndex); - if (tileElement == nullptr) - { - if (_mode != GC_SET_MAZE_TRACK_BUILD) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; - return res; - } - auto constructResult = MapCanConstructAt({ _loc.ToTileStart(), baseHeight, clearanceHeight }, { 0b1111, 0 }); - if (constructResult->Error != GameActions::Status::Ok) - { - return MakeResult( - GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), - constructResult->ErrorMessage.GetStringId(), constructResult->ErrorMessageArgs.data()); - } - - if (constructResult->GroundFlags & ELEMENT_IS_UNDERWATER) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorMessage = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; - return res; - } - - if (constructResult->GroundFlags & ELEMENT_IS_UNDERGROUND) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorMessage = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; - return res; - } - - auto ride = get_ride(_rideIndex); - if (ride == nullptr || ride->type == RIDE_CRASH_TYPE_NONE) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS; - return res; - } - - money32 price = (( - (RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); - res->Cost = price / 2 * 10; - - return res; - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - - res->Position = _loc + CoordsXYZ{ 8, 8, 0 }; - res->Expenditure = ExpenditureType::RideConstruction; - res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - res->Error = GameActions::Status::InvalidParameters; - res->ErrorMessage = STR_NONE; - return res; - } - - if (!map_check_free_elements_and_reorganise(1)) - { - res->Error = GameActions::Status::NoFreeElements; - res->ErrorMessage = STR_NONE; - return res; - } - - uint32_t flags = GetFlags(); - if (!(flags & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter(_loc); - wall_remove_at({ _loc.ToTileStart(), _loc.z, _loc.z + 32 }); - } - - auto tileElement = map_get_track_element_at_of_type_from_ride(_loc, TrackElemType::Maze, _rideIndex); - if (tileElement == nullptr) - { - money32 price = (( - (RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16)); - res->Cost = price / 2 * 10; - - auto startLoc = _loc.ToTileStart(); - - tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); - - tileElement->SetClearanceZ(_loc.z + MAZE_CLEARANCE_HEIGHT); - tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); - - tileElement->AsTrack()->SetTrackType(TrackElemType::Maze); - tileElement->AsTrack()->SetRideIndex(_rideIndex); - tileElement->AsTrack()->SetMazeEntry(0xFFFF); - - if (flags & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } - - map_invalidate_tile_full(startLoc); - - ride->maze_tiles++; - ride->stations[0].SetBaseZ(tileElement->GetBaseZ()); - ride->stations[0].Start = { 0, 0 }; - - if (_initialPlacement && !(flags & GAME_COMMAND_FLAG_GHOST)) - { - ride->overall_view = startLoc; - } - } - - switch (_mode) - { - case GC_SET_MAZE_TRACK_BUILD: - { - uint8_t segmentOffset = MazeGetSegmentBit(_loc.x, _loc.y); - - tileElement->AsTrack()->MazeEntrySubtract(1 << segmentOffset); - - if (!_initialPlacement) - { - segmentOffset = byte_993CE9[(_loc.direction + segmentOffset)]; - tileElement->AsTrack()->MazeEntrySubtract(1 << segmentOffset); - - uint8_t temp_edx = byte_993CFC[segmentOffset]; - if (temp_edx != 0xFF) - { - auto previousElementLoc = CoordsXY{ _loc }.ToTileStart() - CoordsDirectionDelta[_loc.direction]; - - TileElement* previousTileElement = map_get_track_element_at_of_type_from_ride( - { previousElementLoc, _loc.z }, TrackElemType::Maze, _rideIndex); - - if (previousTileElement != nullptr) - { - previousTileElement->AsTrack()->MazeEntrySubtract(1 << temp_edx); - } - else - { - tileElement->AsTrack()->MazeEntryAdd(1 << segmentOffset); - } - } - } - - break; - } - - case GC_SET_MAZE_TRACK_MOVE: - break; - - case GC_SET_MAZE_TRACK_FILL: - if (!_initialPlacement) - { - auto previousSegment = CoordsXY{ _loc.x - CoordsDirectionDelta[_loc.direction].x / 2, - _loc.y - CoordsDirectionDelta[_loc.direction].y / 2 }; - - tileElement = map_get_track_element_at_of_type_from_ride( - { previousSegment, _loc.z }, TrackElemType::Maze, _rideIndex); - - map_invalidate_tile_full(previousSegment.ToTileStart()); - if (tileElement == nullptr) - { - log_error("No surface found"); - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_NONE; - return res; - } - - uint32_t segmentBit = MazeGetSegmentBit(previousSegment.x, previousSegment.y); - - tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); - segmentBit--; - tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); - segmentBit = (segmentBit - 4) & 0x0F; - tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); - segmentBit = (segmentBit + 3) & 0x0F; - - do - { - tileElement->AsTrack()->MazeEntryAdd(1 << segmentBit); - - uint32_t direction1 = byte_993D0C[segmentBit]; - auto nextElementLoc = previousSegment.ToTileStart() + CoordsDirectionDelta[direction1]; - - TileElement* tmp_tileElement = map_get_track_element_at_of_type_from_ride( - { nextElementLoc, _loc.z }, TrackElemType::Maze, _rideIndex); - - if (tmp_tileElement != nullptr) - { - uint8_t edx11 = byte_993CFC[segmentBit]; - tmp_tileElement->AsTrack()->MazeEntryAdd(1 << (edx11)); - } - - segmentBit--; - } while ((segmentBit & 0x3) != 0x3); - } - break; - } - - map_invalidate_tile({ _loc.ToTileStart(), tileElement->GetBaseZ(), tileElement->GetClearanceZ() }); - - if ((tileElement->AsTrack()->GetMazeEntry() & 0x8888) == 0x8888) - { - tile_element_remove(tileElement); - sub_6CB945(ride); - ride->maze_tiles--; - } - - return res; - } - -private: - uint8_t MazeGetSegmentBit(uint16_t x, uint16_t y) const - { - uint8_t minorX = x & 0x1F; // 0 or 16 - uint8_t minorY = y & 0x1F; // 0 or 16 - - if (minorX == 0 && minorY == 0) - { - return 3; - } - - if (minorY == 16 && minorX == 16) - { - return 11; - } - - if (minorY == 0) - { - return 15; - } - - return 7; - } -}; diff --git a/src/openrct2/actions/NetworkModifyGroupAction.cpp b/src/openrct2/actions/NetworkModifyGroupAction.cpp new file mode 100644 index 0000000000..78005032ac --- /dev/null +++ b/src/openrct2/actions/NetworkModifyGroupAction.cpp @@ -0,0 +1,30 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "NetworkModifyGroupAction.h" + +#include "../network/network.h" +#include "../util/Util.h" + +void NetworkModifyGroupAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_type) << DS_TAG(_groupId) << DS_TAG(_name) << DS_TAG(_permissionIndex) << DS_TAG(_permissionState); +} + +GameActions::Result::Ptr NetworkModifyGroupAction::Query() const +{ + return network_modify_groups(GetPlayer(), _type, _groupId, _name, _permissionIndex, _permissionState, false); +} + +GameActions::Result::Ptr NetworkModifyGroupAction::Execute() const +{ + return network_modify_groups(GetPlayer(), _type, _groupId, _name, _permissionIndex, _permissionState, true); +} diff --git a/src/openrct2/actions/NetworkModifyGroupAction.hpp b/src/openrct2/actions/NetworkModifyGroupAction.h similarity index 71% rename from src/openrct2/actions/NetworkModifyGroupAction.hpp rename to src/openrct2/actions/NetworkModifyGroupAction.h index b11bff56de..f99343c542 100644 --- a/src/openrct2/actions/NetworkModifyGroupAction.hpp +++ b/src/openrct2/actions/NetworkModifyGroupAction.h @@ -9,8 +9,6 @@ #pragma once -#include "../network/network.h" -#include "../util/Util.h" #include "GameAction.h" enum class ModifyGroupType : uint8_t @@ -59,20 +57,7 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_type) << DS_TAG(_groupId) << DS_TAG(_name) << DS_TAG(_permissionIndex) << DS_TAG(_permissionState); - } - - GameActions::Result::Ptr Query() const override - { - return network_modify_groups(GetPlayer(), _type, _groupId, _name, _permissionIndex, _permissionState, false); - } - - GameActions::Result::Ptr Execute() const override - { - return network_modify_groups(GetPlayer(), _type, _groupId, _name, _permissionIndex, _permissionState, true); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/ParkEntranceRemoveAction.cpp b/src/openrct2/actions/ParkEntranceRemoveAction.cpp new file mode 100644 index 0000000000..8ece98d28e --- /dev/null +++ b/src/openrct2/actions/ParkEntranceRemoveAction.cpp @@ -0,0 +1,87 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ParkEntranceRemoveAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../world/Entrance.h" +#include "../world/Park.h" + +void ParkEntranceRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr ParkEntranceRemoveAction::Query() const +{ + if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) + { + return MakeResult(GameActions::Status::NotInEditorMode, STR_CANT_REMOVE_THIS); + } + + auto res = MakeResult(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = _loc; + res->ErrorTitle = STR_CANT_REMOVE_THIS; + + auto entranceIndex = park_entrance_get_index(_loc); + if (!LocationValid(_loc) || entranceIndex == -1) + { + log_error("Could not find entrance at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + return res; +} + +GameActions::Result::Ptr ParkEntranceRemoveAction::Execute() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = _loc; + res->ErrorTitle = STR_CANT_REMOVE_THIS; + + auto entranceIndex = park_entrance_get_index(_loc); + if (entranceIndex == -1) + { + log_error("Could not find entrance at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); + } + + auto direction = (gParkEntrances[entranceIndex].direction - 1) & 3; + + // Centre (sign) + ParkEntranceRemoveSegment(_loc); + + // Left post + ParkEntranceRemoveSegment( + { _loc.x + CoordsDirectionDelta[direction].x, _loc.y + CoordsDirectionDelta[direction].y, _loc.z }); + + // Right post + ParkEntranceRemoveSegment( + { _loc.x - CoordsDirectionDelta[direction].x, _loc.y - CoordsDirectionDelta[direction].y, _loc.z }); + + gParkEntrances.erase(gParkEntrances.begin() + entranceIndex); + return res; +} + +void ParkEntranceRemoveAction::ParkEntranceRemoveSegment(const CoordsXYZ& loc) const +{ + auto entranceElement = map_get_park_entrance_element_at(loc, true); + if (entranceElement == nullptr) + { + return; + } + + map_invalidate_tile({ loc, entranceElement->GetBaseZ(), entranceElement->GetClearanceZ() }); + entranceElement->Remove(); + update_park_fences({ loc.x, loc.y }); +} diff --git a/src/openrct2/actions/ParkEntranceRemoveAction.h b/src/openrct2/actions/ParkEntranceRemoveAction.h new file mode 100644 index 0000000000..e62edfdaae --- /dev/null +++ b/src/openrct2/actions/ParkEntranceRemoveAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(ParkEntranceRemoveAction, GAME_COMMAND_REMOVE_PARK_ENTRANCE, GameActions::Result) +{ +private: + CoordsXYZ _loc; + +public: + ParkEntranceRemoveAction() = default; + + ParkEntranceRemoveAction(const CoordsXYZ& loc) + : _loc(loc) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + void ParkEntranceRemoveSegment(const CoordsXYZ& loc) const; +}; diff --git a/src/openrct2/actions/ParkEntranceRemoveAction.hpp b/src/openrct2/actions/ParkEntranceRemoveAction.hpp deleted file mode 100644 index 04e61d332a..0000000000 --- a/src/openrct2/actions/ParkEntranceRemoveAction.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../world/Entrance.h" -#include "../world/Park.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(ParkEntranceRemoveAction, GAME_COMMAND_REMOVE_PARK_ENTRANCE, GameActions::Result) -{ -private: - CoordsXYZ _loc; - -public: - ParkEntranceRemoveAction() = default; - - ParkEntranceRemoveAction(const CoordsXYZ& loc) - : _loc(loc) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::EditorOnly; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) - { - return MakeResult(GameActions::Status::NotInEditorMode, STR_CANT_REMOVE_THIS); - } - - auto res = MakeResult(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = _loc; - res->ErrorTitle = STR_CANT_REMOVE_THIS; - - auto entranceIndex = park_entrance_get_index(_loc); - if (!LocationValid(_loc) || entranceIndex == -1) - { - log_error("Could not find entrance at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = _loc; - res->ErrorTitle = STR_CANT_REMOVE_THIS; - - auto entranceIndex = park_entrance_get_index(_loc); - if (entranceIndex == -1) - { - log_error("Could not find entrance at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS); - } - - auto direction = (gParkEntrances[entranceIndex].direction - 1) & 3; - - // Centre (sign) - ParkEntranceRemoveSegment(_loc); - - // Left post - ParkEntranceRemoveSegment( - { _loc.x + CoordsDirectionDelta[direction].x, _loc.y + CoordsDirectionDelta[direction].y, _loc.z }); - - // Right post - ParkEntranceRemoveSegment( - { _loc.x - CoordsDirectionDelta[direction].x, _loc.y - CoordsDirectionDelta[direction].y, _loc.z }); - - gParkEntrances.erase(gParkEntrances.begin() + entranceIndex); - return res; - } - -private: - void ParkEntranceRemoveSegment(const CoordsXYZ& loc) const - { - auto entranceElement = map_get_park_entrance_element_at(loc, true); - if (entranceElement == nullptr) - { - return; - } - - map_invalidate_tile({ loc, entranceElement->GetBaseZ(), entranceElement->GetClearanceZ() }); - entranceElement->Remove(); - update_park_fences({ loc.x, loc.y }); - } -}; diff --git a/src/openrct2/actions/ParkMarketingAction.cpp b/src/openrct2/actions/ParkMarketingAction.cpp new file mode 100644 index 0000000000..1be4e4f2f5 --- /dev/null +++ b/src/openrct2/actions/ParkMarketingAction.cpp @@ -0,0 +1,81 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ParkMarketingAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../management/Marketing.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" +#include "../world/Park.h" + +#include + +void ParkMarketingAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_type) << DS_TAG(_item) << DS_TAG(_numWeeks); +} + +GameActions::Result::Ptr ParkMarketingAction::Query() const +{ + if (static_cast(_type) >= std::size(AdvertisingCampaignPricePerWeek) || _numWeeks >= 256) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_START_MARKETING_CAMPAIGN); + } + if (gParkFlags & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN) + { + return MakeResult( + GameActions::Status::Disallowed, STR_CANT_START_MARKETING_CAMPAIGN, + STR_MARKETING_CAMPAIGNS_FORBIDDEN_BY_LOCAL_AUTHORITY); + } + + return CreateResult(); +} + +GameActions::Result::Ptr ParkMarketingAction::Execute() const +{ + MarketingCampaign campaign{}; + campaign.Type = _type; + campaign.WeeksLeft = _numWeeks; + campaign.Flags = MarketingCampaignFlags::FIRST_WEEK; + if (campaign.Type == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign.Type == ADVERTISING_CAMPAIGN_RIDE) + { + campaign.RideId = _item; + } + else if (campaign.Type == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) + { + campaign.ShopItemType = ShopItem(_item); + } + marketing_new_campaign(campaign); + + // We are only interested in invalidating the finances (marketing) window + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_CASH)); + + return CreateResult(); +} + +GameActions::Result::Ptr ParkMarketingAction::CreateResult() const +{ + auto result = MakeResult(); + result->ErrorTitle = STR_CANT_START_MARKETING_CAMPAIGN; + result->Expenditure = ExpenditureType::Marketing; + result->Cost = CalculatePrice(); + return result; +} + +money32 ParkMarketingAction::CalculatePrice() const +{ + return _numWeeks * AdvertisingCampaignPricePerWeek[_type]; +} diff --git a/src/openrct2/actions/ParkMarketingAction.h b/src/openrct2/actions/ParkMarketingAction.h new file mode 100644 index 0000000000..205b12a0db --- /dev/null +++ b/src/openrct2/actions/ParkMarketingAction.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(ParkMarketingAction, GAME_COMMAND_START_MARKETING_CAMPAIGN, GameActions::Result) +{ +private: + int32_t _type{}; + int32_t _item{}; + int32_t _numWeeks{}; + +public: + ParkMarketingAction() = default; + ParkMarketingAction(int32_t type, int32_t item, int32_t numWeeks) + : _type(type) + , _item(item) + , _numWeeks(numWeeks) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr CreateResult() const; + money32 CalculatePrice() const; +}; diff --git a/src/openrct2/actions/ParkMarketingAction.hpp b/src/openrct2/actions/ParkMarketingAction.hpp deleted file mode 100644 index 91d7b9e481..0000000000 --- a/src/openrct2/actions/ParkMarketingAction.hpp +++ /dev/null @@ -1,105 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../management/Marketing.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "GameAction.h" - -#include - -DEFINE_GAME_ACTION(ParkMarketingAction, GAME_COMMAND_START_MARKETING_CAMPAIGN, GameActions::Result) -{ -private: - int32_t _type{}; - int32_t _item{}; - int32_t _numWeeks{}; - -public: - ParkMarketingAction() = default; - ParkMarketingAction(int32_t type, int32_t item, int32_t numWeeks) - : _type(type) - , _item(item) - , _numWeeks(numWeeks) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_type) << DS_TAG(_item) << DS_TAG(_numWeeks); - } - - GameActions::Result::Ptr Query() const override - { - if (static_cast(_type) >= std::size(AdvertisingCampaignPricePerWeek) || _numWeeks >= 256) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_START_MARKETING_CAMPAIGN); - } - if (gParkFlags & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN) - { - return MakeResult( - GameActions::Status::Disallowed, STR_CANT_START_MARKETING_CAMPAIGN, - STR_MARKETING_CAMPAIGNS_FORBIDDEN_BY_LOCAL_AUTHORITY); - } - - return CreateResult(); - } - - GameActions::Result::Ptr Execute() const override - { - MarketingCampaign campaign{}; - campaign.Type = _type; - campaign.WeeksLeft = _numWeeks; - campaign.Flags = MarketingCampaignFlags::FIRST_WEEK; - if (campaign.Type == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign.Type == ADVERTISING_CAMPAIGN_RIDE) - { - campaign.RideId = _item; - } - else if (campaign.Type == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) - { - campaign.ShopItemType = ShopItem(_item); - } - marketing_new_campaign(campaign); - - // We are only interested in invalidating the finances (marketing) window - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_CASH)); - - return CreateResult(); - } - -private: - GameActions::Result::Ptr CreateResult() const - { - auto result = MakeResult(); - result->ErrorTitle = STR_CANT_START_MARKETING_CAMPAIGN; - result->Expenditure = ExpenditureType::Marketing; - result->Cost = CalculatePrice(); - return result; - } - - money32 CalculatePrice() const - { - return _numWeeks * AdvertisingCampaignPricePerWeek[_type]; - } -}; diff --git a/src/openrct2/actions/ParkSetDateAction.cpp b/src/openrct2/actions/ParkSetDateAction.cpp new file mode 100644 index 0000000000..8d910c2020 --- /dev/null +++ b/src/openrct2/actions/ParkSetDateAction.cpp @@ -0,0 +1,40 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ParkSetDateAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" + +void ParkSetDateAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_year) << DS_TAG(_month) << DS_TAG(_day); +} + +GameActions::Result::Ptr ParkSetDateAction::Query() const +{ + if (_year <= 0 || _year > MAX_YEAR || _month <= 0 || _month > MONTH_COUNT || _day <= 0 || _day > 31) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr ParkSetDateAction::Execute() const +{ + date_set(_year, _month, _day); + return MakeResult(); +} diff --git a/src/openrct2/actions/ParkSetDateAction.hpp b/src/openrct2/actions/ParkSetDateAction.h similarity index 53% rename from src/openrct2/actions/ParkSetDateAction.hpp rename to src/openrct2/actions/ParkSetDateAction.h index dbb6d44b2a..b986c1e592 100644 --- a/src/openrct2/actions/ParkSetDateAction.hpp +++ b/src/openrct2/actions/ParkSetDateAction.h @@ -9,13 +9,6 @@ #pragma once -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" #include "GameAction.h" DEFINE_GAME_ACTION(ParkSetDateAction, GAME_COMMAND_SET_DATE, GameActions::Result) @@ -39,25 +32,7 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_year) << DS_TAG(_month) << DS_TAG(_day); - } - - GameActions::Result::Ptr Query() const override - { - if (_year <= 0 || _year > MAX_YEAR || _month <= 0 || _month > MONTH_COUNT || _day <= 0 || _day > 31) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - date_set(_year, _month, _day); - return MakeResult(); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/ParkSetLoanAction.cpp b/src/openrct2/actions/ParkSetLoanAction.cpp new file mode 100644 index 0000000000..6dc4473a8f --- /dev/null +++ b/src/openrct2/actions/ParkSetLoanAction.cpp @@ -0,0 +1,56 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ParkSetLoanAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" + +void ParkSetLoanAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_value); +} + +GameActions::Result::Ptr ParkSetLoanAction::Query() const +{ + auto currentLoan = gBankLoan; + auto loanDifference = currentLoan - _value; + if (_value > currentLoan) + { + if (_value > gMaxBankLoan) + { + return MakeResult( + GameActions::Status::Disallowed, STR_CANT_BORROW_ANY_MORE_MONEY, STR_BANK_REFUSES_TO_INCREASE_LOAN); + } + } + else + { + if (loanDifference > gCash) + { + return MakeResult(GameActions::Status::InsufficientFunds, STR_CANT_PAY_BACK_LOAN, STR_NOT_ENOUGH_CASH_AVAILABLE); + } + } + return MakeResult(); +} + +GameActions::Result::Ptr ParkSetLoanAction::Execute() const +{ + gCash -= (gBankLoan - _value); + gBankLoan = _value; + + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_CASH)); + return MakeResult(); +} diff --git a/src/openrct2/actions/ParkSetLoanAction.h b/src/openrct2/actions/ParkSetLoanAction.h new file mode 100644 index 0000000000..37f0f47443 --- /dev/null +++ b/src/openrct2/actions/ParkSetLoanAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(ParkSetLoanAction, GAME_COMMAND_SET_CURRENT_LOAN, GameActions::Result) +{ +private: + money32 _value{ MONEY32_UNDEFINED }; + +public: + ParkSetLoanAction() = default; + ParkSetLoanAction(money32 value) + : _value(value) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/ParkSetLoanAction.hpp b/src/openrct2/actions/ParkSetLoanAction.hpp deleted file mode 100644 index 61616daceb..0000000000 --- a/src/openrct2/actions/ParkSetLoanAction.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(ParkSetLoanAction, GAME_COMMAND_SET_CURRENT_LOAN, GameActions::Result) -{ -private: - money32 _value{ MONEY32_UNDEFINED }; - -public: - ParkSetLoanAction() = default; - ParkSetLoanAction(money32 value) - : _value(value) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_value); - } - - GameActions::Result::Ptr Query() const override - { - auto currentLoan = gBankLoan; - auto loanDifference = currentLoan - _value; - if (_value > currentLoan) - { - if (_value > gMaxBankLoan) - { - return MakeResult( - GameActions::Status::Disallowed, STR_CANT_BORROW_ANY_MORE_MONEY, STR_BANK_REFUSES_TO_INCREASE_LOAN); - } - } - else - { - if (loanDifference > gCash) - { - return MakeResult( - GameActions::Status::InsufficientFunds, STR_CANT_PAY_BACK_LOAN, STR_NOT_ENOUGH_CASH_AVAILABLE); - } - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - gCash -= (gBankLoan - _value); - gBankLoan = _value; - - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_CASH)); - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/ParkSetNameAction.cpp b/src/openrct2/actions/ParkSetNameAction.cpp new file mode 100644 index 0000000000..da6c52bc45 --- /dev/null +++ b/src/openrct2/actions/ParkSetNameAction.cpp @@ -0,0 +1,56 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ParkSetNameAction.h" + +#include "../Context.h" +#include "../GameState.h" +#include "../config/Config.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../localisation/Localisation.h" +#include "../management/Finance.h" +#include "../network/network.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" +#include "../world/Park.h" + +void ParkSetNameAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("name", _name); +} + +void ParkSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_name); +} + +GameActions::Result::Ptr ParkSetNameAction::Query() const +{ + if (_name.empty()) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_RENAME_PARK, STR_INVALID_NAME_FOR_PARK); + } + return MakeResult(); +} + +GameActions::Result::Ptr ParkSetNameAction::Execute() const +{ + // Do a no-op if new name is the same as the current name is the same + auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); + if (_name != park.Name) + { + park.Name = _name; + scrolling_text_invalidate(); + gfx_invalidate_screen(); + } + return MakeResult(); +} diff --git a/src/openrct2/actions/ParkSetNameAction.h b/src/openrct2/actions/ParkSetNameAction.h new file mode 100644 index 0000000000..66775fba35 --- /dev/null +++ b/src/openrct2/actions/ParkSetNameAction.h @@ -0,0 +1,36 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(ParkSetNameAction, GAME_COMMAND_SET_PARK_NAME, GameActions::Result) +{ +private: + std::string _name; + +public: + ParkSetNameAction() = default; + ParkSetNameAction(const std::string& name) + : _name(name) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/ParkSetNameAction.hpp b/src/openrct2/actions/ParkSetNameAction.hpp deleted file mode 100644 index a36dbff702..0000000000 --- a/src/openrct2/actions/ParkSetNameAction.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../GameState.h" -#include "../config/Config.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../localisation/Localisation.h" -#include "../management/Finance.h" -#include "../network/network.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(ParkSetNameAction, GAME_COMMAND_SET_PARK_NAME, GameActions::Result) -{ -private: - std::string _name; - -public: - ParkSetNameAction() = default; - ParkSetNameAction(const std::string& name) - : _name(name) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("name", _name); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - if (_name.empty()) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_RENAME_PARK, STR_INVALID_NAME_FOR_PARK); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - // Do a no-op if new name is the same as the current name is the same - auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); - if (_name != park.Name) - { - park.Name = _name; - scrolling_text_invalidate(); - gfx_invalidate_screen(); - } - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/ParkSetParameterAction.cpp b/src/openrct2/actions/ParkSetParameterAction.cpp new file mode 100644 index 0000000000..ddd5e0a670 --- /dev/null +++ b/src/openrct2/actions/ParkSetParameterAction.cpp @@ -0,0 +1,64 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ParkSetParameterAction.h" + +#include "../interface/Window.h" +#include "../ride/ShopItem.h" +#include "../util/Util.h" +#include "../world/Park.h" + +void ParkSetParameterAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_parameter) << DS_TAG(_value); +} + +GameActions::Result::Ptr ParkSetParameterAction::Query() const +{ + if (_parameter >= ParkParameter::Count) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto res = MakeResult(); + res->ErrorTitle = _ErrorTitles[EnumValue(_parameter)]; + return res; +} + +GameActions::Result::Ptr ParkSetParameterAction::Execute() const +{ + switch (_parameter) + { + case ParkParameter::Close: + if (gParkFlags & PARK_FLAGS_PARK_OPEN) + { + gParkFlags &= ~PARK_FLAGS_PARK_OPEN; + window_invalidate_by_class(WC_PARK_INFORMATION); + } + break; + case ParkParameter::Open: + if (!(gParkFlags & PARK_FLAGS_PARK_OPEN)) + { + gParkFlags |= PARK_FLAGS_PARK_OPEN; + window_invalidate_by_class(WC_PARK_INFORMATION); + } + break; + case ParkParameter::SamePriceInPark: + gSamePriceThroughoutPark = _value; + window_invalidate_by_class(WC_RIDE); + break; + default: + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto res = MakeResult(); + res->ErrorTitle = _ErrorTitles[EnumValue(_parameter)]; + return res; +} \ No newline at end of file diff --git a/src/openrct2/actions/ParkSetParameterAction.h b/src/openrct2/actions/ParkSetParameterAction.h new file mode 100644 index 0000000000..7de96cefa6 --- /dev/null +++ b/src/openrct2/actions/ParkSetParameterAction.h @@ -0,0 +1,46 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +enum class ParkParameter : uint8_t +{ + Close, + Open, + SamePriceInPark, + Count +}; + +DEFINE_GAME_ACTION(ParkSetParameterAction, GAME_COMMAND_SET_PARK_OPEN, GameActions::Result) +{ +private: + ParkParameter _parameter{ ParkParameter::Count }; + uint64_t _value{}; + + constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_CLOSE_PARK, STR_CANT_OPEN_PARK, STR_NONE, STR_NONE }; + +public: + ParkSetParameterAction() = default; + ParkSetParameterAction(ParkParameter parameter, uint64_t value = 0) + : _parameter(parameter) + , _value(value) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/ParkSetParameterAction.hpp b/src/openrct2/actions/ParkSetParameterAction.hpp deleted file mode 100644 index 2765668fad..0000000000 --- a/src/openrct2/actions/ParkSetParameterAction.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../interface/Window.h" -#include "../ride/ShopItem.h" -#include "../util/Util.h" -#include "../world/Park.h" -#include "GameAction.h" - -enum class ParkParameter : uint8_t -{ - Close, - Open, - SamePriceInPark, - Count -}; - -DEFINE_GAME_ACTION(ParkSetParameterAction, GAME_COMMAND_SET_PARK_OPEN, GameActions::Result) -{ -private: - ParkParameter _parameter{ ParkParameter::Count }; - uint64_t _value{}; - - constexpr static rct_string_id _ErrorTitles[] = { STR_CANT_CLOSE_PARK, STR_CANT_OPEN_PARK, STR_NONE, STR_NONE }; - -public: - ParkSetParameterAction() = default; - ParkSetParameterAction(ParkParameter parameter, uint64_t value = 0) - : _parameter(parameter) - , _value(value) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_parameter) << DS_TAG(_value); - } - - GameActions::Result::Ptr Query() const override - { - if (_parameter >= ParkParameter::Count) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto res = MakeResult(); - res->ErrorTitle = _ErrorTitles[EnumValue(_parameter)]; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - switch (_parameter) - { - case ParkParameter::Close: - if (gParkFlags & PARK_FLAGS_PARK_OPEN) - { - gParkFlags &= ~PARK_FLAGS_PARK_OPEN; - window_invalidate_by_class(WC_PARK_INFORMATION); - } - break; - case ParkParameter::Open: - if (!(gParkFlags & PARK_FLAGS_PARK_OPEN)) - { - gParkFlags |= PARK_FLAGS_PARK_OPEN; - window_invalidate_by_class(WC_PARK_INFORMATION); - } - break; - case ParkParameter::SamePriceInPark: - gSamePriceThroughoutPark = _value; - window_invalidate_by_class(WC_RIDE); - break; - default: - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - break; - } - - auto res = MakeResult(); - res->ErrorTitle = _ErrorTitles[EnumValue(_parameter)]; - return res; - } -}; diff --git a/src/openrct2/actions/ParkSetResearchFundingAction.cpp b/src/openrct2/actions/ParkSetResearchFundingAction.cpp new file mode 100644 index 0000000000..82d8ea2645 --- /dev/null +++ b/src/openrct2/actions/ParkSetResearchFundingAction.cpp @@ -0,0 +1,43 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ParkSetResearchFundingAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Research.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" + +void ParkSetResearchFundingAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_priorities) << DS_TAG(_fundingAmount); +} + +GameActions::Result::Ptr ParkSetResearchFundingAction::Query() const +{ + if (_fundingAmount >= RESEARCH_FUNDING_COUNT) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return MakeResult(); +} + +GameActions::Result::Ptr ParkSetResearchFundingAction::Execute() const +{ + gResearchPriorities = _priorities; + gResearchFundingLevel = _fundingAmount; + + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_RESEARCH)); + return MakeResult(); +} diff --git a/src/openrct2/actions/ParkSetResearchFundingAction.hpp b/src/openrct2/actions/ParkSetResearchFundingAction.h similarity index 51% rename from src/openrct2/actions/ParkSetResearchFundingAction.hpp rename to src/openrct2/actions/ParkSetResearchFundingAction.h index 711fe3762e..ae1c00c566 100644 --- a/src/openrct2/actions/ParkSetResearchFundingAction.hpp +++ b/src/openrct2/actions/ParkSetResearchFundingAction.h @@ -9,13 +9,6 @@ #pragma once -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Research.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" #include "GameAction.h" DEFINE_GAME_ACTION(ParkSetResearchFundingAction, GAME_COMMAND_SET_RESEARCH_FUNDING, GameActions::Result) @@ -38,28 +31,7 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_priorities) << DS_TAG(_fundingAmount); - } - - GameActions::Result::Ptr Query() const override - { - if (_fundingAmount >= RESEARCH_FUNDING_COUNT) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - gResearchPriorities = _priorities; - gResearchFundingLevel = _fundingAmount; - - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_RESEARCH)); - return MakeResult(); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/PauseToggleAction.cpp b/src/openrct2/actions/PauseToggleAction.cpp new file mode 100644 index 0000000000..467e33b27c --- /dev/null +++ b/src/openrct2/actions/PauseToggleAction.cpp @@ -0,0 +1,16 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "PauseToggleAction.h" + +GameActions::Result::Ptr PauseToggleAction::Execute() const +{ + pause_toggle(); + return std::make_unique(); +} diff --git a/src/openrct2/actions/PauseToggleAction.hpp b/src/openrct2/actions/PauseToggleAction.h similarity index 86% rename from src/openrct2/actions/PauseToggleAction.hpp rename to src/openrct2/actions/PauseToggleAction.h index b25daa5705..6fbb926b6d 100644 --- a/src/openrct2/actions/PauseToggleAction.hpp +++ b/src/openrct2/actions/PauseToggleAction.h @@ -28,10 +28,6 @@ public: return std::make_unique(); } - GameActions::Result::Ptr Execute() const override - { - pause_toggle(); - return std::make_unique(); - } + GameActions::Result::Ptr Execute() const override; }; // clang-format on diff --git a/src/openrct2/actions/PeepPickupAction.cpp b/src/openrct2/actions/PeepPickupAction.cpp new file mode 100644 index 0000000000..4be81c6eeb --- /dev/null +++ b/src/openrct2/actions/PeepPickupAction.cpp @@ -0,0 +1,181 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "PeepPickupAction.h" + +#include "../Input.h" +#include "../network/network.h" +#include "../util/Util.h" + +void PeepPickupAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_type) << DS_TAG(_spriteId) << DS_TAG(_loc) << DS_TAG(_owner); +} + +GameActions::Result::Ptr PeepPickupAction::Query() const +{ + if (_spriteId >= MAX_SPRITES || _spriteId == SPRITE_INDEX_NULL) + { + log_error("Failed to pick up peep for sprite %d", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + + if (!_loc.isNull() && !LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + + auto* const peep = TryGetEntity(_spriteId); + if (!peep || peep->sprite_identifier != SpriteIdentifier::Peep) + { + log_error("Failed to pick up peep for sprite %d", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + + auto res = MakeResult(); + + switch (_type) + { + case PeepPickupType::Pickup: + { + res->Position = { peep->x, peep->y, peep->z }; + if (!peep_can_be_picked_up(peep)) + { + return MakeResult(GameActions::Status::Disallowed, STR_ERR_CANT_PLACE_PERSON_HERE); + } + Peep* existing = network_get_pickup_peep(_owner); + if (existing) + { + // already picking up a peep + PeepPickupAction existingPickupAction{ + PeepPickupType::Cancel, existing->sprite_index, { network_get_pickup_peep_old_x(_owner), 0, 0 }, _owner + }; + auto result = GameActions::QueryNested(&existingPickupAction); + + if (existing == peep) + { + return result; + } + } + } + break; + case PeepPickupType::Cancel: + res->Position = { peep->x, peep->y, peep->z }; + break; + case PeepPickupType::Place: + res->Position = _loc; + if (network_get_pickup_peep(_owner) != peep) + { + return MakeResult(GameActions::Status::Unknown, STR_ERR_CANT_PLACE_PERSON_HERE); + } + + if (auto res2 = peep->Place(TileCoordsXYZ(_loc), false); res2->Error != GameActions::Status::Ok) + { + return res2; + } + break; + default: + log_error("Invalid pickup type: %u", _type); + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + return res; +} + +GameActions::Result::Ptr PeepPickupAction::Execute() const +{ + Peep* const peep = TryGetEntity(_spriteId); + if (!peep || peep->sprite_identifier != SpriteIdentifier::Peep) + { + log_error("Failed to pick up peep for sprite %d", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + + auto res = MakeResult(); + + switch (_type) + { + case PeepPickupType::Pickup: + { + res->Position = { peep->x, peep->y, peep->z }; + + Peep* existing = network_get_pickup_peep(_owner); + if (existing) + { + // already picking up a peep + PeepPickupAction existingPickupAction{ + PeepPickupType::Cancel, existing->sprite_index, { network_get_pickup_peep_old_x(_owner), 0, 0 }, _owner + }; + auto result = GameActions::ExecuteNested(&existingPickupAction); + + if (existing == peep) + { + return result; + } + if (_owner == network_get_current_player_id()) + { + // prevent tool_cancel() + input_set_flag(INPUT_FLAG_TOOL_ACTIVE, false); + } + } + + network_set_pickup_peep(_owner, peep); + network_set_pickup_peep_old_x(_owner, peep->x); + peep->Pickup(); + } + break; + case PeepPickupType::Cancel: + { + res->Position = { peep->x, peep->y, peep->z }; + + Peep* const pickedUpPeep = network_get_pickup_peep(_owner); + if (pickedUpPeep) + { + pickedUpPeep->PickupAbort(_loc.x); + } + + network_set_pickup_peep(_owner, nullptr); + } + break; + case PeepPickupType::Place: + res->Position = _loc; + if (auto res2 = peep->Place(TileCoordsXYZ(_loc), true); res2->Error != GameActions::Status::Ok) + { + return res2; + } + CancelConcurrentPickups(peep); + break; + default: + log_error("Invalid pickup type: %u", _type); + return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); + } + return res; +} + +void PeepPickupAction::CancelConcurrentPickups(Peep* pickedPeep) const +{ + // This part is only relevant in multiplayer games. + if (network_get_mode() == NETWORK_MODE_NONE) + return; + + // Not relevant for owner, owner gets to place it normally. + NetworkPlayerId_t currentPlayerId = network_get_current_player_id(); + if (currentPlayerId == _owner) + return; + + Peep* peep = network_get_pickup_peep(network_get_current_player_id()); + if (peep != pickedPeep) + return; + + // By assigning the peep to null before calling tool_cancel we can avoid + // resetting the peep to the initial position. + network_set_pickup_peep(currentPlayerId, nullptr); + tool_cancel(); +} diff --git a/src/openrct2/actions/PeepPickupAction.h b/src/openrct2/actions/PeepPickupAction.h new file mode 100644 index 0000000000..58546696b1 --- /dev/null +++ b/src/openrct2/actions/PeepPickupAction.h @@ -0,0 +1,52 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/Sprite.h" +#include "GameAction.h" + +enum class PeepPickupType : uint8_t +{ + Pickup, + Cancel, + Place, + Count +}; + +DEFINE_GAME_ACTION(PeepPickupAction, GAME_COMMAND_PICKUP_GUEST, GameActions::Result) +{ +private: + PeepPickupType _type{ PeepPickupType::Count }; + uint32_t _spriteId{ SPRITE_INDEX_NULL }; + CoordsXYZ _loc; + NetworkPlayerId_t _owner{ -1 }; + +public: + PeepPickupAction() = default; + PeepPickupAction(PeepPickupType type, uint32_t spriteId, const CoordsXYZ& loc, NetworkPlayerId_t owner) + : _type(type) + , _spriteId(spriteId) + , _loc(loc) + , _owner(owner) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + void CancelConcurrentPickups(Peep * pickedPeep) const; +}; diff --git a/src/openrct2/actions/PeepPickupAction.hpp b/src/openrct2/actions/PeepPickupAction.hpp deleted file mode 100644 index 3bf32f36e7..0000000000 --- a/src/openrct2/actions/PeepPickupAction.hpp +++ /dev/null @@ -1,218 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Input.h" -#include "../network/network.h" -#include "../util/Util.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -enum class PeepPickupType : uint8_t -{ - Pickup, - Cancel, - Place, - Count -}; - -DEFINE_GAME_ACTION(PeepPickupAction, GAME_COMMAND_PICKUP_GUEST, GameActions::Result) -{ -private: - PeepPickupType _type{ PeepPickupType::Count }; - uint32_t _spriteId{ SPRITE_INDEX_NULL }; - CoordsXYZ _loc; - NetworkPlayerId_t _owner{ -1 }; - -public: - PeepPickupAction() = default; - PeepPickupAction(PeepPickupType type, uint32_t spriteId, const CoordsXYZ& loc, NetworkPlayerId_t owner) - : _type(type) - , _spriteId(spriteId) - , _loc(loc) - , _owner(owner) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_type) << DS_TAG(_spriteId) << DS_TAG(_loc) << DS_TAG(_owner); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteId >= MAX_SPRITES || _spriteId == SPRITE_INDEX_NULL) - { - log_error("Failed to pick up peep for sprite %d", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - } - - if (!_loc.isNull() && !LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - } - - auto* const peep = TryGetEntity(_spriteId); - if (!peep || peep->sprite_identifier != SpriteIdentifier::Peep) - { - log_error("Failed to pick up peep for sprite %d", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - } - - auto res = MakeResult(); - - switch (_type) - { - case PeepPickupType::Pickup: - { - res->Position = { peep->x, peep->y, peep->z }; - if (!peep_can_be_picked_up(peep)) - { - return MakeResult(GameActions::Status::Disallowed, STR_ERR_CANT_PLACE_PERSON_HERE); - } - Peep* existing = network_get_pickup_peep(_owner); - if (existing) - { - // already picking up a peep - PeepPickupAction existingPickupAction{ - PeepPickupType::Cancel, existing->sprite_index, { network_get_pickup_peep_old_x(_owner), 0, 0 }, _owner - }; - auto result = GameActions::QueryNested(&existingPickupAction); - - if (existing == peep) - { - return result; - } - } - } - break; - case PeepPickupType::Cancel: - res->Position = { peep->x, peep->y, peep->z }; - break; - case PeepPickupType::Place: - res->Position = _loc; - if (network_get_pickup_peep(_owner) != peep) - { - return MakeResult(GameActions::Status::Unknown, STR_ERR_CANT_PLACE_PERSON_HERE); - } - - if (auto res2 = peep->Place(TileCoordsXYZ(_loc), false); res2->Error != GameActions::Status::Ok) - { - return res2; - } - break; - default: - log_error("Invalid pickup type: %u", _type); - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - break; - } - return res; - } - - GameActions::Result::Ptr Execute() const override - { - Peep* const peep = TryGetEntity(_spriteId); - if (!peep || peep->sprite_identifier != SpriteIdentifier::Peep) - { - log_error("Failed to pick up peep for sprite %d", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - } - - auto res = MakeResult(); - - switch (_type) - { - case PeepPickupType::Pickup: - { - res->Position = { peep->x, peep->y, peep->z }; - - Peep* existing = network_get_pickup_peep(_owner); - if (existing) - { - // already picking up a peep - PeepPickupAction existingPickupAction{ - PeepPickupType::Cancel, existing->sprite_index, { network_get_pickup_peep_old_x(_owner), 0, 0 }, _owner - }; - auto result = GameActions::ExecuteNested(&existingPickupAction); - - if (existing == peep) - { - return result; - } - if (_owner == network_get_current_player_id()) - { - // prevent tool_cancel() - input_set_flag(INPUT_FLAG_TOOL_ACTIVE, false); - } - } - - network_set_pickup_peep(_owner, peep); - network_set_pickup_peep_old_x(_owner, peep->x); - peep->Pickup(); - } - break; - case PeepPickupType::Cancel: - { - res->Position = { peep->x, peep->y, peep->z }; - - Peep* const pickedUpPeep = network_get_pickup_peep(_owner); - if (pickedUpPeep) - { - pickedUpPeep->PickupAbort(_loc.x); - } - - network_set_pickup_peep(_owner, nullptr); - } - break; - case PeepPickupType::Place: - res->Position = _loc; - if (auto res2 = peep->Place(TileCoordsXYZ(_loc), true); res2->Error != GameActions::Status::Ok) - { - return res2; - } - CancelConcurrentPickups(peep); - break; - default: - log_error("Invalid pickup type: %u", _type); - return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); - break; - } - return res; - } - -private: - void CancelConcurrentPickups(Peep * pickedPeep) const - { - // This part is only relevant in multiplayer games. - if (network_get_mode() == NETWORK_MODE_NONE) - return; - - // Not relevant for owner, owner gets to place it normally. - NetworkPlayerId_t currentPlayerId = network_get_current_player_id(); - if (currentPlayerId == _owner) - return; - - Peep* peep = network_get_pickup_peep(network_get_current_player_id()); - if (peep != pickedPeep) - return; - - // By assigning the peep to null before calling tool_cancel we can avoid - // resetting the peep to the initial position. - network_set_pickup_peep(currentPlayerId, nullptr); - tool_cancel(); - } -}; diff --git a/src/openrct2/actions/PlaceParkEntranceAction.cpp b/src/openrct2/actions/PlaceParkEntranceAction.cpp new file mode 100644 index 0000000000..f452e479fd --- /dev/null +++ b/src/openrct2/actions/PlaceParkEntranceAction.cpp @@ -0,0 +1,175 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "PlaceParkEntranceAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Entrance.h" +#include "../world/Footpath.h" +#include "../world/MapAnimation.h" +#include "../world/Park.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" + +void PlaceParkEntranceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr PlaceParkEntranceAction::Query() const +{ + if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) + { + return std::make_unique( + GameActions::Status::NotInEditorMode, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); + } + + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = { _loc.x, _loc.y, _loc.z }; + + if (!map_check_free_elements_and_reorganise(3)) + { + return std::make_unique( + GameActions::Status::NoFreeElements, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); + } + + if (!LocationValid(_loc) || _loc.x <= 32 || _loc.y <= 32 || _loc.x >= (gMapSizeUnits - 32) + || _loc.y >= (gMapSizeUnits - 32)) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_TOO_CLOSE_TO_EDGE_OF_MAP); + } + + if (gParkEntrances.size() >= MAX_PARK_ENTRANCES) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_ERR_TOO_MANY_PARK_ENTRANCES); + } + + auto zLow = _loc.z; + auto zHigh = zLow + ParkEntranceHeight; + CoordsXYZ entranceLoc = _loc; + for (uint8_t index = 0; index < 3; index++) + { + if (index == 1) + { + entranceLoc += CoordsDirectionDelta[(_loc.direction - 1) & 0x3]; + } + else if (index == 2) + { + entranceLoc.x += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].x * 2; + entranceLoc.y += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].y * 2; + } + + if (auto res2 = MapCanConstructAt({ entranceLoc, zLow, zHigh }, { 0b1111, 0 }); res2->Error != GameActions::Status::Ok) + { + return std::make_unique( + GameActions::Status::NoClearance, STR_CANT_BUILD_PARK_ENTRANCE_HERE, res2->ErrorMessage.GetStringId(), + res2->ErrorMessageArgs.data()); + } + + // Check that entrance element does not already exist at this location + EntranceElement* entranceElement = map_get_park_entrance_element_at(entranceLoc, false); + if (entranceElement != nullptr) + { + return std::make_unique( + GameActions::Status::ItemAlreadyPlaced, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); + } + } + + return res; +} + +GameActions::Result::Ptr PlaceParkEntranceAction::Execute() const +{ + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = CoordsXYZ{ _loc.x, _loc.y, _loc.z }; + + uint32_t flags = GetFlags(); + + CoordsXYZD parkEntrance; + parkEntrance = _loc; + + gParkEntrances.push_back(parkEntrance); + + auto zLow = _loc.z; + auto zHigh = zLow + ParkEntranceHeight; + CoordsXY entranceLoc = { _loc.x, _loc.y }; + for (uint8_t index = 0; index < 3; index++) + { + if (index == 1) + { + entranceLoc.x += CoordsDirectionDelta[(_loc.direction - 1) & 0x3].x; + entranceLoc.y += CoordsDirectionDelta[(_loc.direction - 1) & 0x3].y; + } + else if (index == 2) + { + entranceLoc.x += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].x * 2; + entranceLoc.y += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].y * 2; + } + + if (!(flags & GAME_COMMAND_FLAG_GHOST)) + { + SurfaceElement* surfaceElement = map_get_surface_element_at(entranceLoc); + if (surfaceElement != nullptr) + { + surfaceElement->SetOwnership(OWNERSHIP_UNOWNED); + } + } + + TileElement* newElement = tile_element_insert(CoordsXYZ{ entranceLoc, zLow }, 0b1111); + Guard::Assert(newElement != nullptr); + newElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); + auto entranceElement = newElement->AsEntrance(); + if (entranceElement == nullptr) + { + Guard::Assert(false); + return nullptr; + } + entranceElement->SetClearanceZ(zHigh); + + if (flags & GAME_COMMAND_FLAG_GHOST) + { + newElement->SetGhost(true); + } + + entranceElement->SetDirection(_loc.direction); + entranceElement->SetSequenceIndex(index); + entranceElement->SetEntranceType(ENTRANCE_TYPE_PARK_ENTRANCE); + entranceElement->SetPathType(gFootpathSelectedId); + + if (!(flags & GAME_COMMAND_FLAG_GHOST)) + { + footpath_connect_edges(entranceLoc, newElement, GAME_COMMAND_FLAG_APPLY); + } + + update_park_fences(entranceLoc); + update_park_fences({ entranceLoc.x - COORDS_XY_STEP, entranceLoc.y }); + update_park_fences({ entranceLoc.x + COORDS_XY_STEP, entranceLoc.y }); + update_park_fences({ entranceLoc.x, entranceLoc.y - COORDS_XY_STEP }); + update_park_fences({ entranceLoc.x, entranceLoc.y + COORDS_XY_STEP }); + + map_invalidate_tile({ entranceLoc, newElement->GetBaseZ(), newElement->GetClearanceZ() }); + + if (index == 0) + { + map_animation_create(MAP_ANIMATION_TYPE_PARK_ENTRANCE, { entranceLoc, zLow }); + } + } + + return res; +} diff --git a/src/openrct2/actions/PlaceParkEntranceAction.h b/src/openrct2/actions/PlaceParkEntranceAction.h new file mode 100644 index 0000000000..2c53b8c383 --- /dev/null +++ b/src/openrct2/actions/PlaceParkEntranceAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(PlaceParkEntranceAction, GAME_COMMAND_PLACE_PARK_ENTRANCE, GameActions::Result) +{ +private: + CoordsXYZD _loc; + +public: + PlaceParkEntranceAction() = default; + PlaceParkEntranceAction(const CoordsXYZD& location) + : _loc(location) + { + } + + uint16_t GetActionFlags() const override + { + return GameActionBase::GetActionFlags() | GameActions::Flags::EditorOnly; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/PlaceParkEntranceAction.hpp b/src/openrct2/actions/PlaceParkEntranceAction.hpp deleted file mode 100644 index 1960a50fc2..0000000000 --- a/src/openrct2/actions/PlaceParkEntranceAction.hpp +++ /dev/null @@ -1,195 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Entrance.h" -#include "../world/Footpath.h" -#include "../world/MapAnimation.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(PlaceParkEntranceAction, GAME_COMMAND_PLACE_PARK_ENTRANCE, GameActions::Result) -{ -private: - CoordsXYZD _loc; - -public: - PlaceParkEntranceAction() = default; - PlaceParkEntranceAction(const CoordsXYZD& location) - : _loc(location) - { - } - - uint16_t GetActionFlags() const override - { - return GameActionBase::GetActionFlags() | GameActions::Flags::EditorOnly; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) - { - return std::make_unique( - GameActions::Status::NotInEditorMode, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); - } - - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = { _loc.x, _loc.y, _loc.z }; - - if (!map_check_free_elements_and_reorganise(3)) - { - return std::make_unique( - GameActions::Status::NoFreeElements, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); - } - - if (!LocationValid(_loc) || _loc.x <= 32 || _loc.y <= 32 || _loc.x >= (gMapSizeUnits - 32) - || _loc.y >= (gMapSizeUnits - 32)) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_TOO_CLOSE_TO_EDGE_OF_MAP); - } - - if (gParkEntrances.size() >= MAX_PARK_ENTRANCES) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_ERR_TOO_MANY_PARK_ENTRANCES); - } - - auto zLow = _loc.z; - auto zHigh = zLow + ParkEntranceHeight; - CoordsXYZ entranceLoc = _loc; - for (uint8_t index = 0; index < 3; index++) - { - if (index == 1) - { - entranceLoc += CoordsDirectionDelta[(_loc.direction - 1) & 0x3]; - } - else if (index == 2) - { - entranceLoc.x += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].x * 2; - entranceLoc.y += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].y * 2; - } - - if (auto res2 = MapCanConstructAt({ entranceLoc, zLow, zHigh }, { 0b1111, 0 }); - res2->Error != GameActions::Status::Ok) - { - return std::make_unique( - GameActions::Status::NoClearance, STR_CANT_BUILD_PARK_ENTRANCE_HERE, res2->ErrorMessage.GetStringId(), - res2->ErrorMessageArgs.data()); - } - - // Check that entrance element does not already exist at this location - EntranceElement* entranceElement = map_get_park_entrance_element_at(entranceLoc, false); - if (entranceElement != nullptr) - { - return std::make_unique( - GameActions::Status::ItemAlreadyPlaced, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); - } - } - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = CoordsXYZ{ _loc.x, _loc.y, _loc.z }; - - uint32_t flags = GetFlags(); - - CoordsXYZD parkEntrance; - parkEntrance = _loc; - - gParkEntrances.push_back(parkEntrance); - - auto zLow = _loc.z; - auto zHigh = zLow + ParkEntranceHeight; - CoordsXY entranceLoc = { _loc.x, _loc.y }; - for (uint8_t index = 0; index < 3; index++) - { - if (index == 1) - { - entranceLoc.x += CoordsDirectionDelta[(_loc.direction - 1) & 0x3].x; - entranceLoc.y += CoordsDirectionDelta[(_loc.direction - 1) & 0x3].y; - } - else if (index == 2) - { - entranceLoc.x += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].x * 2; - entranceLoc.y += CoordsDirectionDelta[(_loc.direction + 1) & 0x3].y * 2; - } - - if (!(flags & GAME_COMMAND_FLAG_GHOST)) - { - SurfaceElement* surfaceElement = map_get_surface_element_at(entranceLoc); - if (surfaceElement != nullptr) - { - surfaceElement->SetOwnership(OWNERSHIP_UNOWNED); - } - } - - TileElement* newElement = tile_element_insert(CoordsXYZ{ entranceLoc, zLow }, 0b1111); - Guard::Assert(newElement != nullptr); - newElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); - auto entranceElement = newElement->AsEntrance(); - if (entranceElement == nullptr) - { - Guard::Assert(false); - return nullptr; - } - entranceElement->SetClearanceZ(zHigh); - - if (flags & GAME_COMMAND_FLAG_GHOST) - { - newElement->SetGhost(true); - } - - entranceElement->SetDirection(_loc.direction); - entranceElement->SetSequenceIndex(index); - entranceElement->SetEntranceType(ENTRANCE_TYPE_PARK_ENTRANCE); - entranceElement->SetPathType(gFootpathSelectedId); - - if (!(flags & GAME_COMMAND_FLAG_GHOST)) - { - footpath_connect_edges(entranceLoc, newElement, GAME_COMMAND_FLAG_APPLY); - } - - update_park_fences(entranceLoc); - update_park_fences({ entranceLoc.x - COORDS_XY_STEP, entranceLoc.y }); - update_park_fences({ entranceLoc.x + COORDS_XY_STEP, entranceLoc.y }); - update_park_fences({ entranceLoc.x, entranceLoc.y - COORDS_XY_STEP }); - update_park_fences({ entranceLoc.x, entranceLoc.y + COORDS_XY_STEP }); - - map_invalidate_tile({ entranceLoc, newElement->GetBaseZ(), newElement->GetClearanceZ() }); - - if (index == 0) - { - map_animation_create(MAP_ANIMATION_TYPE_PARK_ENTRANCE, { entranceLoc, zLow }); - } - } - - return res; - } -}; diff --git a/src/openrct2/actions/PlacePeepSpawnAction.cpp b/src/openrct2/actions/PlacePeepSpawnAction.cpp new file mode 100644 index 0000000000..a9bc934acf --- /dev/null +++ b/src/openrct2/actions/PlacePeepSpawnAction.cpp @@ -0,0 +1,128 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "PlacePeepSpawnAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Park.h" +#include "../world/Surface.h" + +void PlacePeepSpawnAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_location.x) << DS_TAG(_location.y) << DS_TAG(_location.z) << DS_TAG(_location.direction); +} + +GameActions::Result::Ptr PlacePeepSpawnAction::Query() const +{ + if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) + { + return std::make_unique( + GameActions::Status::NotInEditorMode, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); + } + + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = _location; + + if (!map_check_free_elements_and_reorganise(3)) + { + return std::make_unique( + GameActions::Status::NoFreeElements, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); + } + + if (!LocationValid(_location) || _location.x <= 16 || _location.y <= 16 || _location.x >= (gMapSizeUnits - 16) + || _location.y >= (gMapSizeUnits - 16)) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_OFF_EDGE_OF_MAP); + } + + // Verify footpath exists at location, and retrieve coordinates + auto pathElement = map_get_path_element_at(TileCoordsXYZ{ _location }); + if (pathElement == nullptr) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS); + } + + // Verify location is unowned + auto surfaceMapElement = map_get_surface_element_at(_location); + if (surfaceMapElement == nullptr) + { + return std::make_unique( + GameActions::Status::Unknown, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); + } + if (surfaceMapElement->GetOwnership() != OWNERSHIP_UNOWNED) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, + STR_ERR_MUST_BE_OUTSIDE_PARK_BOUNDARIES); + } + + return res; +} + +GameActions::Result::Ptr PlacePeepSpawnAction::Execute() const +{ + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::LandPurchase; + res->Position = _location; + + // Shift the spawn point to the edge of the tile + auto spawnPos = CoordsXY{ _location.ToTileCentre() } + + CoordsXY{ DirectionOffsets[_location.direction].x * 15, DirectionOffsets[_location.direction].y * 15 }; + + PeepSpawn spawn; + spawn.x = spawnPos.x; + spawn.y = spawnPos.y; + spawn.z = _location.z; + spawn.direction = _location.direction; + + // When attempting to place a peep spawn on a tile that already contains it, + // remove that peep spawn instead. + if (!gPeepSpawns.empty()) + { + // When searching for existing spawns, ignore the direction. + auto foundSpawn = std::find_if(gPeepSpawns.begin(), gPeepSpawns.end(), [spawn](const CoordsXYZ& existingSpawn) { + { + return existingSpawn.ToTileStart() == spawn.ToTileStart(); + } + }); + + if (foundSpawn != std::end(gPeepSpawns)) + { + gPeepSpawns.erase(foundSpawn); + map_invalidate_tile_full(spawn); + return res; + } + } + + // If we have reached our max peep spawns, remove the oldest spawns + while (gPeepSpawns.size() >= MAX_PEEP_SPAWNS) + { + PeepSpawn oldestSpawn = *gPeepSpawns.begin(); + gPeepSpawns.erase(gPeepSpawns.begin()); + map_invalidate_tile_full(oldestSpawn); + } + + // Set peep spawn + gPeepSpawns.push_back(spawn); + + // Invalidate tile + map_invalidate_tile_full(_location); + + return res; +} diff --git a/src/openrct2/actions/PlacePeepSpawnAction.h b/src/openrct2/actions/PlacePeepSpawnAction.h new file mode 100644 index 0000000000..8308936b95 --- /dev/null +++ b/src/openrct2/actions/PlacePeepSpawnAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(PlacePeepSpawnAction, GAME_COMMAND_PLACE_PEEP_SPAWN, GameActions::Result) +{ +private: + CoordsXYZD _location; + +public: + PlacePeepSpawnAction() = default; + PlacePeepSpawnAction(const CoordsXYZD& location) + : _location(location) + { + } + + uint16_t GetActionFlags() const override + { + return GameActionBase::GetActionFlags() | GameActions::Flags::EditorOnly | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/PlacePeepSpawnAction.hpp b/src/openrct2/actions/PlacePeepSpawnAction.hpp deleted file mode 100644 index ba4e3327b7..0000000000 --- a/src/openrct2/actions/PlacePeepSpawnAction.hpp +++ /dev/null @@ -1,147 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Footpath.h" -#include "../world/Park.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(PlacePeepSpawnAction, GAME_COMMAND_PLACE_PEEP_SPAWN, GameActions::Result) -{ -private: - CoordsXYZD _location; - -public: - PlacePeepSpawnAction() = default; - PlacePeepSpawnAction(const CoordsXYZD& location) - : _location(location) - { - } - - uint16_t GetActionFlags() const override - { - return GameActionBase::GetActionFlags() | GameActions::Flags::EditorOnly | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_location.x) << DS_TAG(_location.y) << DS_TAG(_location.z) << DS_TAG(_location.direction); - } - - GameActions::Result::Ptr Query() const override - { - if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) - { - return std::make_unique( - GameActions::Status::NotInEditorMode, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); - } - - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = _location; - - if (!map_check_free_elements_and_reorganise(3)) - { - return std::make_unique( - GameActions::Status::NoFreeElements, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); - } - - if (!LocationValid(_location) || _location.x <= 16 || _location.y <= 16 || _location.x >= (gMapSizeUnits - 16) - || _location.y >= (gMapSizeUnits - 16)) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_OFF_EDGE_OF_MAP); - } - - // Verify footpath exists at location, and retrieve coordinates - auto pathElement = map_get_path_element_at(TileCoordsXYZ{ _location }); - if (pathElement == nullptr) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS); - } - - // Verify location is unowned - auto surfaceMapElement = map_get_surface_element_at(_location); - if (surfaceMapElement == nullptr) - { - return std::make_unique( - GameActions::Status::Unknown, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); - } - if (surfaceMapElement->GetOwnership() != OWNERSHIP_UNOWNED) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, - STR_ERR_MUST_BE_OUTSIDE_PARK_BOUNDARIES); - } - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::LandPurchase; - res->Position = _location; - - // Shift the spawn point to the edge of the tile - auto spawnPos = CoordsXY{ _location.ToTileCentre() } - + CoordsXY{ DirectionOffsets[_location.direction].x * 15, DirectionOffsets[_location.direction].y * 15 }; - - PeepSpawn spawn; - spawn.x = spawnPos.x; - spawn.y = spawnPos.y; - spawn.z = _location.z; - spawn.direction = _location.direction; - - // When attempting to place a peep spawn on a tile that already contains it, - // remove that peep spawn instead. - if (!gPeepSpawns.empty()) - { - // When searching for existing spawns, ignore the direction. - auto foundSpawn = std::find_if(gPeepSpawns.begin(), gPeepSpawns.end(), [spawn](const CoordsXYZ& existingSpawn) { - { - return existingSpawn.ToTileStart() == spawn.ToTileStart(); - } - }); - - if (foundSpawn != std::end(gPeepSpawns)) - { - gPeepSpawns.erase(foundSpawn); - map_invalidate_tile_full(spawn); - return res; - } - } - - // If we have reached our max peep spawns, remove the oldest spawns - while (gPeepSpawns.size() >= MAX_PEEP_SPAWNS) - { - PeepSpawn oldestSpawn = *gPeepSpawns.begin(); - gPeepSpawns.erase(gPeepSpawns.begin()); - map_invalidate_tile_full(oldestSpawn); - } - - // Set peep spawn - gPeepSpawns.push_back(spawn); - - // Invalidate tile - map_invalidate_tile_full(_location); - - return res; - } -}; diff --git a/src/openrct2/actions/PlayerKickAction.cpp b/src/openrct2/actions/PlayerKickAction.cpp new file mode 100644 index 0000000000..b1c260f0d5 --- /dev/null +++ b/src/openrct2/actions/PlayerKickAction.cpp @@ -0,0 +1,28 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "PlayerKickAction.h" + +#include "../network/network.h" + +void PlayerKickAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_playerId); +} +GameActions::Result::Ptr PlayerKickAction::Query() const +{ + return network_kick_player(_playerId, false); +} + +GameActions::Result::Ptr PlayerKickAction::Execute() const +{ + return network_kick_player(_playerId, true); +} diff --git a/src/openrct2/actions/PlayerKickAction.hpp b/src/openrct2/actions/PlayerKickAction.h similarity index 68% rename from src/openrct2/actions/PlayerKickAction.hpp rename to src/openrct2/actions/PlayerKickAction.h index a76f881eb1..129461e840 100644 --- a/src/openrct2/actions/PlayerKickAction.hpp +++ b/src/openrct2/actions/PlayerKickAction.h @@ -9,7 +9,6 @@ #pragma once -#include "../network/network.h" #include "GameAction.h" DEFINE_GAME_ACTION(PlayerKickAction, GAME_COMMAND_KICK_PLAYER, GameActions::Result) @@ -30,19 +29,7 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_playerId); - } - GameActions::Result::Ptr Query() const override - { - return network_kick_player(_playerId, false); - } - - GameActions::Result::Ptr Execute() const override - { - return network_kick_player(_playerId, true); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/PlayerSetGroupAction.cpp b/src/openrct2/actions/PlayerSetGroupAction.cpp new file mode 100644 index 0000000000..94e049aeab --- /dev/null +++ b/src/openrct2/actions/PlayerSetGroupAction.cpp @@ -0,0 +1,28 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "PlayerSetGroupAction.h" + +#include "../network/network.h" + +void PlayerSetGroupAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_playerId) << DS_TAG(_groupId); +} +GameActions::Result::Ptr PlayerSetGroupAction::Query() const +{ + return network_set_player_group(GetPlayer(), _playerId, _groupId, false); +} + +GameActions::Result::Ptr PlayerSetGroupAction::Execute() const +{ + return network_set_player_group(GetPlayer(), _playerId, _groupId, true); +} diff --git a/src/openrct2/actions/PlayerSetGroupAction.hpp b/src/openrct2/actions/PlayerSetGroupAction.h similarity index 67% rename from src/openrct2/actions/PlayerSetGroupAction.hpp rename to src/openrct2/actions/PlayerSetGroupAction.h index ea36d26a7b..e326a3fca3 100644 --- a/src/openrct2/actions/PlayerSetGroupAction.hpp +++ b/src/openrct2/actions/PlayerSetGroupAction.h @@ -9,7 +9,6 @@ #pragma once -#include "../network/network.h" #include "GameAction.h" DEFINE_GAME_ACTION(PlayerSetGroupAction, GAME_COMMAND_SET_PLAYER_GROUP, GameActions::Result) @@ -32,19 +31,7 @@ public: return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_playerId) << DS_TAG(_groupId); - } - GameActions::Result::Ptr Query() const override - { - return network_set_player_group(GetPlayer(), _playerId, _groupId, false); - } - - GameActions::Result::Ptr Execute() const override - { - return network_set_player_group(GetPlayer(), _playerId, _groupId, true); - } + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; }; diff --git a/src/openrct2/actions/RideCreateAction.cpp b/src/openrct2/actions/RideCreateAction.cpp new file mode 100644 index 0000000000..265bb9f806 --- /dev/null +++ b/src/openrct2/actions/RideCreateAction.cpp @@ -0,0 +1,270 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideCreateAction.h" + +#include "../Cheats.h" +#include "../core/Memory.hpp" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Date.h" +#include "../localisation/StringIds.h" +#include "../rct1/RCT1.h" +#include "../ride/Ride.h" +#include "../ride/RideData.h" +#include "../ride/ShopItem.h" +#include "../ride/Station.h" +#include "../scenario/Scenario.h" +#include "../world/Park.h" + +#include + +void RideCreateAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("rideType", _rideType); + visitor.Visit("rideObject", _subType); + visitor.Visit("colour1", _colour1); + visitor.Visit("colour2", _colour2); +} + +void RideCreateAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideType) << DS_TAG(_subType) << DS_TAG(_colour1) << DS_TAG(_colour2); +} + +GameActions::Result::Ptr RideCreateAction::Query() const +{ + auto rideIndex = GetNextFreeRideId(); + if (rideIndex == RIDE_ID_NULL) + { + // No more free slots available. + return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_RIDES); + } + + if (_rideType >= RIDE_TYPE_COUNT) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_RIDE_TYPE); + } + + int32_t rideEntryIndex = ride_get_entry_index(_rideType, _subType); + if (rideEntryIndex >= MAX_RIDE_OBJECTS) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_RIDE_TYPE); + } + + const auto& colourPresets = RideTypeDescriptors[_rideType].ColourPresets; + if (_colour1 >= colourPresets.count) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + rct_ride_entry* rideEntry = get_ride_entry(rideEntryIndex); + if (rideEntry == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list; + if ((presetList->count > 0 && presetList->count != 255) && _colour2 >= presetList->count) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr RideCreateAction::Execute() const +{ + rct_ride_entry* rideEntry; + auto res = MakeResult(); + + int32_t rideEntryIndex = ride_get_entry_index(_rideType, _subType); + auto rideIndex = GetNextFreeRideId(); + + res->rideIndex = rideIndex; + + auto ride = GetOrAllocateRide(rideIndex); + rideEntry = get_ride_entry(rideEntryIndex); + if (rideEntry == nullptr) + { + log_warning("Invalid request for ride %u", rideIndex); + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = STR_UNKNOWN_OBJECT_TYPE; + return res; + } + + ride->id = rideIndex; + ride->type = _rideType; + ride->subtype = rideEntryIndex; + ride->SetColourPreset(_colour1); + ride->overall_view.setNull(); + ride->SetNameToDefault(); + + for (int32_t i = 0; i < MAX_STATIONS; i++) + { + ride->stations[i].Start.setNull(); + ride_clear_entrance_location(ride, i); + ride_clear_exit_location(ride, i); + ride->stations[i].TrainAtStation = RideStation::NO_TRAIN; + ride->stations[i].QueueTime = 0; + } + + for (auto& vehicle : ride->vehicles) + { + vehicle = SPRITE_INDEX_NULL; + } + + ride->status = RIDE_STATUS_CLOSED; + ride->lifecycle_flags = 0; + ride->vehicle_change_timeout = 0; + ride->num_stations = 0; + ride->num_vehicles = 1; + ride->proposed_num_vehicles = 32; + ride->max_trains = 32; + ride->num_cars_per_train = 1; + ride->proposed_num_cars_per_train = 12; + ride->min_waiting_time = 10; + ride->max_waiting_time = 60; + ride->depart_flags = RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH | 3; + if (RideTypeDescriptors[ride->type].Flags & RIDE_TYPE_FLAG_MUSIC_ON_DEFAULT) + { + ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; + } + ride->music = RideTypeDescriptors[ride->type].DefaultMusic; + + const auto& operatingSettings = RideTypeDescriptors[ride->type].OperatingSettings; + ride->operation_option = (operatingSettings.MinValue * 3 + operatingSettings.MaxValue) / 4; + + ride->lift_hill_speed = RideTypeDescriptors[ride->type].LiftData.minimum_speed; + + ride->measurement = {}; + ride->excitement = RIDE_RATING_UNDEFINED; + ride->cur_num_customers = 0; + ride->num_customers_timeout = 0; + ride->chairlift_bullwheel_rotation = 0; + + for (auto& price : ride->price) + { + price = 0; + } + + if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) + { + for (auto i = 0; i < NUM_SHOP_ITEMS_PER_RIDE; i++) + { + ride->price[i] = RideTypeDescriptors[ride->type].DefaultPrices[i]; + } + + if (rideEntry->shop_item[0] == ShopItem::None) + { + if (!park_ride_prices_unlocked()) + { + ride->price[0] = 0; + } + } + else + { + ride->price[0] = GetShopItemDescriptor(rideEntry->shop_item[0]).DefaultPrice; + } + if (rideEntry->shop_item[1] != ShopItem::None) + { + ride->price[1] = GetShopItemDescriptor(rideEntry->shop_item[1]).DefaultPrice; + } + + if (gScenarioObjective.Type == OBJECTIVE_BUILD_THE_BEST) + { + ride->price[0] = 0; + } + + if (ride->type == RIDE_TYPE_TOILETS) + { + if (shop_item_has_common_price(ShopItem::Admission)) + { + money32 price = ride_get_common_price(ride); + if (price != MONEY32_UNDEFINED) + { + ride->price[0] = static_cast(price); + } + } + } + + for (auto i = 0; i < NUM_SHOP_ITEMS_PER_RIDE; i++) + { + if (rideEntry->shop_item[i] != ShopItem::None) + { + if (shop_item_has_common_price(rideEntry->shop_item[i])) + { + money32 price = shop_item_get_common_price(ride, rideEntry->shop_item[i]); + if (price != MONEY32_UNDEFINED) + { + ride->price[i] = static_cast(price); + } + } + } + } + + // Set the on-ride photo price, whether the ride has one or not (except shops). + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP) && shop_item_has_common_price(ShopItem::Photo)) + { + money32 price = shop_item_get_common_price(ride, ShopItem::Photo); + if (price != MONEY32_UNDEFINED) + { + ride->price[1] = static_cast(price); + } + } + } + + std::fill(std::begin(ride->num_customers), std::end(ride->num_customers), 0); + ride->value = RIDE_VALUE_UNDEFINED; + ride->satisfaction = 255; + ride->satisfaction_time_out = 0; + ride->satisfaction_next = 0; + ride->popularity = 255; + ride->popularity_time_out = 0; + ride->popularity_next = 0; + ride->window_invalidate_flags = 0; + ride->total_customers = 0; + ride->total_profit = 0; + ride->num_riders = 0; + ride->slide_in_use = 0; + ride->maze_tiles = 0; + ride->build_date = gDateMonthsElapsed; + ride->music_tune_id = 255; + + ride->breakdown_reason = 255; + ride->upkeep_cost = MONEY16_UNDEFINED; + ride->reliability = RIDE_INITIAL_RELIABILITY; + ride->unreliability_factor = 1; + ride->inspection_interval = RIDE_INSPECTION_EVERY_30_MINUTES; + ride->last_inspection = 0; + ride->downtime = 0; + std::fill_n(ride->downtime_history, sizeof(ride->downtime_history), 0x00); + ride->no_primary_items_sold = 0; + ride->no_secondary_items_sold = 0; + ride->last_crash_type = RIDE_CRASH_TYPE_NONE; + ride->income_per_hour = MONEY32_UNDEFINED; + ride->profit = MONEY32_UNDEFINED; + ride->connected_message_throttle = 0; + ride->entrance_style = 0; + ride->num_block_brakes = 0; + ride->guests_favourite = 0; + + ride->num_circuits = 1; + ride->mode = ride->GetDefaultMode(); + ride->SetMinCarsPerTrain(rideEntry->min_cars_in_train); + ride->SetMaxCarsPerTrain(rideEntry->max_cars_in_train); + ride_set_vehicle_colours_to_random_preset(ride, _colour2); + window_invalidate_by_class(WC_RIDE_LIST); + + res->Expenditure = ExpenditureType::RideConstruction; + + return res; +} \ No newline at end of file diff --git a/src/openrct2/actions/RideCreateAction.h b/src/openrct2/actions/RideCreateAction.h new file mode 100644 index 0000000000..d3e0e59e8f --- /dev/null +++ b/src/openrct2/actions/RideCreateAction.h @@ -0,0 +1,68 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +class RideCreateGameActionResult final : public GameActions::Result +{ +public: + RideCreateGameActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_NONE) + { + } + RideCreateGameActionResult(GameActions::Status error, rct_string_id message) + : GameActions::Result(error, STR_CANT_CREATE_NEW_RIDE_ATTRACTION, message) + { + } + + ride_id_t rideIndex = RIDE_ID_NULL; +}; + +DEFINE_GAME_ACTION(RideCreateAction, GAME_COMMAND_CREATE_RIDE, RideCreateGameActionResult) +{ +private: + int32_t _rideType{ RIDE_ID_NULL }; + ObjectEntryIndex _subType{ RIDE_ENTRY_INDEX_NULL }; + uint8_t _colour1{ 0xFF }; + uint8_t _colour2{ 0xFF }; + +public: + RideCreateAction() = default; + + RideCreateAction(int32_t rideType, ObjectEntryIndex subType, int32_t colour1, int32_t colour2) + : _rideType(rideType) + , _subType(subType) + , _colour1(colour1) + , _colour2(colour2) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + int32_t GetRideType() const + { + return _rideType; + } + + int32_t GetRideObject() const + { + return _subType; + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideCreateAction.hpp b/src/openrct2/actions/RideCreateAction.hpp deleted file mode 100644 index 0509bd36de..0000000000 --- a/src/openrct2/actions/RideCreateAction.hpp +++ /dev/null @@ -1,321 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../core/Memory.hpp" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Date.h" -#include "../localisation/StringIds.h" -#include "../rct1/RCT1.h" -#include "../ride/Ride.h" -#include "../ride/RideData.h" -#include "../ride/ShopItem.h" -#include "../ride/Station.h" -#include "../scenario/Scenario.h" -#include "../world/Park.h" -#include "GameAction.h" - -#include - -class RideCreateGameActionResult final : public GameActions::Result -{ -public: - RideCreateGameActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_NONE) - { - } - RideCreateGameActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_CANT_CREATE_NEW_RIDE_ATTRACTION, message) - { - } - - ride_id_t rideIndex = RIDE_ID_NULL; -}; - -DEFINE_GAME_ACTION(RideCreateAction, GAME_COMMAND_CREATE_RIDE, RideCreateGameActionResult) -{ -private: - int32_t _rideType{ RIDE_ID_NULL }; - ObjectEntryIndex _subType{ RIDE_ENTRY_INDEX_NULL }; - uint8_t _colour1{ 0xFF }; - uint8_t _colour2{ 0xFF }; - -public: - RideCreateAction() = default; - - RideCreateAction(int32_t rideType, ObjectEntryIndex subType, int32_t colour1, int32_t colour2) - : _rideType(rideType) - , _subType(subType) - , _colour1(colour1) - , _colour2(colour2) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("rideType", _rideType); - visitor.Visit("rideObject", _subType); - visitor.Visit("colour1", _colour1); - visitor.Visit("colour2", _colour2); - } - - int32_t GetRideType() const - { - return _rideType; - } - - int32_t GetRideObject() const - { - return _subType; - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideType) << DS_TAG(_subType) << DS_TAG(_colour1) << DS_TAG(_colour2); - } - - GameActions::Result::Ptr Query() const override - { - auto rideIndex = GetNextFreeRideId(); - if (rideIndex == RIDE_ID_NULL) - { - // No more free slots available. - return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_RIDES); - } - - if (_rideType >= RIDE_TYPE_COUNT) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_RIDE_TYPE); - } - - int32_t rideEntryIndex = ride_get_entry_index(_rideType, _subType); - if (rideEntryIndex >= MAX_RIDE_OBJECTS) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_RIDE_TYPE); - } - - const auto& colourPresets = RideTypeDescriptors[_rideType].ColourPresets; - if (_colour1 >= colourPresets.count) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - rct_ride_entry* rideEntry = get_ride_entry(rideEntryIndex); - if (rideEntry == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list; - if ((presetList->count > 0 && presetList->count != 255) && _colour2 >= presetList->count) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - rct_ride_entry* rideEntry; - auto res = MakeResult(); - - int32_t rideEntryIndex = ride_get_entry_index(_rideType, _subType); - auto rideIndex = GetNextFreeRideId(); - - res->rideIndex = rideIndex; - - auto ride = GetOrAllocateRide(rideIndex); - rideEntry = get_ride_entry(rideEntryIndex); - if (rideEntry == nullptr) - { - log_warning("Invalid request for ride %u", rideIndex); - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = STR_UNKNOWN_OBJECT_TYPE; - return res; - } - - ride->id = rideIndex; - ride->type = _rideType; - ride->subtype = rideEntryIndex; - ride->SetColourPreset(_colour1); - ride->overall_view.setNull(); - ride->SetNameToDefault(); - - for (int32_t i = 0; i < MAX_STATIONS; i++) - { - ride->stations[i].Start.setNull(); - ride_clear_entrance_location(ride, i); - ride_clear_exit_location(ride, i); - ride->stations[i].TrainAtStation = RideStation::NO_TRAIN; - ride->stations[i].QueueTime = 0; - } - - for (auto& vehicle : ride->vehicles) - { - vehicle = SPRITE_INDEX_NULL; - } - - ride->status = RIDE_STATUS_CLOSED; - ride->lifecycle_flags = 0; - ride->vehicle_change_timeout = 0; - ride->num_stations = 0; - ride->num_vehicles = 1; - ride->proposed_num_vehicles = 32; - ride->max_trains = 32; - ride->num_cars_per_train = 1; - ride->proposed_num_cars_per_train = 12; - ride->min_waiting_time = 10; - ride->max_waiting_time = 60; - ride->depart_flags = RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH | 3; - if (RideTypeDescriptors[ride->type].Flags & RIDE_TYPE_FLAG_MUSIC_ON_DEFAULT) - { - ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; - } - ride->music = RideTypeDescriptors[ride->type].DefaultMusic; - - const auto& operatingSettings = RideTypeDescriptors[ride->type].OperatingSettings; - ride->operation_option = (operatingSettings.MinValue * 3 + operatingSettings.MaxValue) / 4; - - ride->lift_hill_speed = RideTypeDescriptors[ride->type].LiftData.minimum_speed; - - ride->measurement = {}; - ride->excitement = RIDE_RATING_UNDEFINED; - ride->cur_num_customers = 0; - ride->num_customers_timeout = 0; - ride->chairlift_bullwheel_rotation = 0; - - for (auto& price : ride->price) - { - price = 0; - } - - if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) - { - for (auto i = 0; i < NUM_SHOP_ITEMS_PER_RIDE; i++) - { - ride->price[i] = RideTypeDescriptors[ride->type].DefaultPrices[i]; - } - - if (rideEntry->shop_item[0] == ShopItem::None) - { - if (!park_ride_prices_unlocked()) - { - ride->price[0] = 0; - } - } - else - { - ride->price[0] = GetShopItemDescriptor(rideEntry->shop_item[0]).DefaultPrice; - } - if (rideEntry->shop_item[1] != ShopItem::None) - { - ride->price[1] = GetShopItemDescriptor(rideEntry->shop_item[1]).DefaultPrice; - } - - if (gScenarioObjective.Type == OBJECTIVE_BUILD_THE_BEST) - { - ride->price[0] = 0; - } - - if (ride->type == RIDE_TYPE_TOILETS) - { - if (shop_item_has_common_price(ShopItem::Admission)) - { - money32 price = ride_get_common_price(ride); - if (price != MONEY32_UNDEFINED) - { - ride->price[0] = static_cast(price); - } - } - } - - for (auto i = 0; i < NUM_SHOP_ITEMS_PER_RIDE; i++) - { - if (rideEntry->shop_item[i] != ShopItem::None) - { - if (shop_item_has_common_price(rideEntry->shop_item[i])) - { - money32 price = shop_item_get_common_price(ride, rideEntry->shop_item[i]); - if (price != MONEY32_UNDEFINED) - { - ride->price[i] = static_cast(price); - } - } - } - } - - // Set the on-ride photo price, whether the ride has one or not (except shops). - if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP) && shop_item_has_common_price(ShopItem::Photo)) - { - money32 price = shop_item_get_common_price(ride, ShopItem::Photo); - if (price != MONEY32_UNDEFINED) - { - ride->price[1] = static_cast(price); - } - } - } - - std::fill(std::begin(ride->num_customers), std::end(ride->num_customers), 0); - ride->value = RIDE_VALUE_UNDEFINED; - ride->satisfaction = 255; - ride->satisfaction_time_out = 0; - ride->satisfaction_next = 0; - ride->popularity = 255; - ride->popularity_time_out = 0; - ride->popularity_next = 0; - ride->window_invalidate_flags = 0; - ride->total_customers = 0; - ride->total_profit = 0; - ride->num_riders = 0; - ride->slide_in_use = 0; - ride->maze_tiles = 0; - ride->build_date = gDateMonthsElapsed; - ride->music_tune_id = 255; - - ride->breakdown_reason = 255; - ride->upkeep_cost = MONEY16_UNDEFINED; - ride->reliability = RIDE_INITIAL_RELIABILITY; - ride->unreliability_factor = 1; - ride->inspection_interval = RIDE_INSPECTION_EVERY_30_MINUTES; - ride->last_inspection = 0; - ride->downtime = 0; - std::fill_n(ride->downtime_history, sizeof(ride->downtime_history), 0x00); - ride->no_primary_items_sold = 0; - ride->no_secondary_items_sold = 0; - ride->last_crash_type = RIDE_CRASH_TYPE_NONE; - ride->income_per_hour = MONEY32_UNDEFINED; - ride->profit = MONEY32_UNDEFINED; - ride->connected_message_throttle = 0; - ride->entrance_style = 0; - ride->num_block_brakes = 0; - ride->guests_favourite = 0; - - ride->num_circuits = 1; - ride->mode = ride->GetDefaultMode(); - ride->SetMinCarsPerTrain(rideEntry->min_cars_in_train); - ride->SetMaxCarsPerTrain(rideEntry->max_cars_in_train); - ride_set_vehicle_colours_to_random_preset(ride, _colour2); - window_invalidate_by_class(WC_RIDE_LIST); - - res->Expenditure = ExpenditureType::RideConstruction; - - return res; - } -}; diff --git a/src/openrct2/actions/RideDemolishAction.cpp b/src/openrct2/actions/RideDemolishAction.cpp new file mode 100644 index 0000000000..39ef1781dd --- /dev/null +++ b/src/openrct2/actions/RideDemolishAction.cpp @@ -0,0 +1,368 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideDemolishAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../GameState.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../management/NewsItem.h" +#include "../ride/Ride.h" +#include "../ride/RideData.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Banner.h" +#include "../world/Park.h" +#include "../world/Sprite.h" +#include "MazeSetTrackAction.h" +#include "TrackRemoveAction.h" + +using namespace OpenRCT2; + +void RideDemolishAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("modifyType", _modifyType); +} + +void RideDemolishAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_modifyType); +} + +GameActions::Result::Ptr RideDemolishAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_DEMOLISH_RIDE, STR_NONE); + } + + if (ride->lifecycle_flags & (RIDE_LIFECYCLE_INDESTRUCTIBLE | RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) + && _modifyType == RIDE_MODIFY_DEMOLISH) + { + return std::make_unique( + GameActions::Status::NoClearance, STR_CANT_DEMOLISH_RIDE, + STR_LOCAL_AUTHORITY_FORBIDS_DEMOLITION_OR_MODIFICATIONS_TO_THIS_RIDE); + } + + GameActions::Result::Ptr result = std::make_unique(); + + if (_modifyType == RIDE_MODIFY_RENEW) + { + if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_MUST_BE_CLOSED_FIRST); + } + + if (ride->num_riders > 0) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_RIDE_NOT_YET_EMPTY); + } + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) + || RideTypeDescriptors[ride->type].AvailableBreakdowns == 0) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_CANT_REFURBISH_NOT_NEEDED); + } + + result->ErrorTitle = STR_CANT_REFURBISH_RIDE; + result->Cost = GetRefurbishPrice(ride); + } + + return result; +} + +GameActions::Result::Ptr RideDemolishAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_DEMOLISH_RIDE, STR_NONE); + } + + switch (_modifyType) + { + case RIDE_MODIFY_DEMOLISH: + return DemolishRide(ride); + case RIDE_MODIFY_RENEW: + return RefurbishRide(ride); + } + + return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_DO_THIS); +} + +GameActions::Result::Ptr RideDemolishAction::DemolishRide(Ride* ride) const +{ + money32 refundPrice = DemolishTracks(); + + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + ride->StopGuestsQueuing(); + + sub_6CB945(ride); + ride_clear_leftover_entrances(ride); + News::DisableNewsItems(News::ItemType::Ride, _rideIndex); + + for (BannerIndex i = 0; i < MAX_BANNERS; i++) + { + auto banner = GetBanner(i); + if (!banner->IsNull() && banner->flags & BANNER_FLAG_LINKED_TO_RIDE && banner->ride_index == _rideIndex) + { + banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; + banner->text = {}; + } + } + + for (auto peep : EntityList(EntityListId::Peep)) + { + uint8_t ride_id_bit = _rideIndex % 8; + uint8_t ride_id_offset = _rideIndex / 8; + + // clear ride from potentially being in RidesBeenOn + peep->RidesBeenOn[ride_id_offset] &= ~(1 << ride_id_bit); + if (peep->State == PeepState::Watching) + { + if (peep->CurrentRide == _rideIndex) + { + peep->CurrentRide = RIDE_ID_NULL; + if (peep->TimeToStand >= 50) + { + // make peep stop watching the ride + peep->TimeToStand = 50; + } + } + } + + // remove any free voucher for this ride from peep + if (peep->HasItem(ShopItem::Voucher)) + { + if (peep->VoucherType == VOUCHER_TYPE_RIDE_FREE && peep->VoucherRideId == _rideIndex) + { + peep->RemoveItem(ShopItem::Voucher); + } + } + + // remove any photos of this ride from peep + if (peep->HasItem(ShopItem::Photo)) + { + if (peep->Photo1RideRef == _rideIndex) + { + peep->RemoveItem(ShopItem::Photo); + } + } + if (peep->HasItem(ShopItem::Photo2)) + { + if (peep->Photo2RideRef == _rideIndex) + { + peep->RemoveItem(ShopItem::Photo2); + } + } + if (peep->HasItem(ShopItem::Photo3)) + { + if (peep->Photo3RideRef == _rideIndex) + { + peep->RemoveItem(ShopItem::Photo3); + } + } + if (peep->HasItem(ShopItem::Photo4)) + { + if (peep->Photo4RideRef == _rideIndex) + { + peep->RemoveItem(ShopItem::Photo4); + } + } + + if (peep->GuestHeadingToRideId == _rideIndex) + { + peep->GuestHeadingToRideId = RIDE_ID_NULL; + } + if (peep->FavouriteRide == _rideIndex) + { + peep->FavouriteRide = RIDE_ID_NULL; + } + + for (int32_t i = 0; i < PEEP_MAX_THOUGHTS; i++) + { + // Don't touch items after the first NONE thought as they are not valid + // fixes issues with clearing out bad thought data in multiplayer + if (peep->Thoughts[i].type == PeepThoughtType::None) + break; + + if (peep->Thoughts[i].type != PeepThoughtType::None && peep->Thoughts[i].item == _rideIndex) + { + // Clear top thought, push others up + memmove(&peep->Thoughts[i], &peep->Thoughts[i + 1], sizeof(rct_peep_thought) * (PEEP_MAX_THOUGHTS - i - 1)); + peep->Thoughts[PEEP_MAX_THOUGHTS - 1].type = PeepThoughtType::None; + peep->Thoughts[PEEP_MAX_THOUGHTS - 1].item = PEEP_THOUGHT_ITEM_NONE; + // Next iteration, check the new thought at this index + i--; + } + } + } + + MarketingCancelCampaignsForRide(_rideIndex); + + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::RideConstruction; + res->Cost = refundPrice; + + if (!ride->overall_view.isNull()) + { + auto xy = ride->overall_view.ToTileCentre(); + res->Position = { xy, tile_element_height(xy) }; + } + + ride->Delete(); + gParkValue = GetContext()->GetGameState()->GetPark().CalculateParkValue(); + + // Close windows related to the demolished ride + if (!(GetFlags() & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED)) + { + window_close_by_number(WC_RIDE_CONSTRUCTION, _rideIndex); + } + window_close_by_number(WC_RIDE, _rideIndex); + window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, _rideIndex); + window_close_by_class(WC_NEW_CAMPAIGN); + + // Refresh windows that display the ride name + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_RIDE_LIST)); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_GUEST_LIST)); + + scrolling_text_invalidate(); + gfx_invalidate_screen(); + + return res; +} + +money32 RideDemolishAction::MazeRemoveTrack(const CoordsXYZD& coords) const +{ + auto setMazeTrack = MazeSetTrackAction(coords, false, _rideIndex, GC_SET_MAZE_TRACK_FILL); + setMazeTrack.SetFlags(GetFlags()); + + auto execRes = GameActions::ExecuteNested(&setMazeTrack); + if (execRes->Error == GameActions::Status::Ok) + { + return execRes->Cost; + } + + return MONEY32_UNDEFINED; +} + +money32 RideDemolishAction::DemolishTracks() const +{ + money32 refundPrice = 0; + + uint8_t oldpaused = gGamePaused; + gGamePaused = 0; + + tile_element_iterator it; + + tile_element_iterator_begin(&it); + while (tile_element_iterator_next(&it)) + { + if (it.element->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if (it.element->AsTrack()->GetRideIndex() != static_cast(_rideIndex)) + continue; + + auto location = CoordsXYZD(TileCoordsXY(it.x, it.y).ToCoordsXY(), it.element->GetBaseZ(), it.element->GetDirection()); + auto type = it.element->AsTrack()->GetTrackType(); + + if (type != TrackElemType::Maze) + { + auto trackRemoveAction = TrackRemoveAction(type, it.element->AsTrack()->GetSequenceIndex(), location); + trackRemoveAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND); + + auto removRes = GameActions::ExecuteNested(&trackRemoveAction); + + if (removRes->Error != GameActions::Status::Ok) + { + tile_element_remove(it.element); + } + else + { + refundPrice += removRes->Cost; + } + + tile_element_iterator_restart_for_tile(&it); + continue; + } + + static constexpr const CoordsXY DirOffsets[] = { + { 0, 0 }, + { 0, 16 }, + { 16, 16 }, + { 16, 0 }, + }; + + for (Direction dir : ALL_DIRECTIONS) + { + const CoordsXYZ off = { DirOffsets[dir], 0 }; + money32 removePrice = MazeRemoveTrack({ location + off, dir }); + if (removePrice != MONEY32_UNDEFINED) + refundPrice += removePrice; + else + break; + } + + tile_element_iterator_restart_for_tile(&it); + } + + gGamePaused = oldpaused; + return refundPrice; +} + +GameActions::Result::Ptr RideDemolishAction::RefurbishRide(Ride* ride) const +{ + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::RideConstruction; + res->Cost = GetRefurbishPrice(ride); + + ride->Renew(); + + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_EVER_BEEN_OPENED; + ride->last_crash_type = RIDE_CRASH_TYPE_NONE; + + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE | RIDE_INVALIDATE_RIDE_CUSTOMER; + + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + } + + window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, _rideIndex); + + return res; +} + +money32 RideDemolishAction::GetRefurbishPrice(const Ride* ride) const +{ + return -GetRefundPrice(ride) / 2; +} + +money32 RideDemolishAction::GetRefundPrice(const Ride* ride) const +{ + return ride_get_refund_price(ride); +} diff --git a/src/openrct2/actions/RideDemolishAction.h b/src/openrct2/actions/RideDemolishAction.h new file mode 100644 index 0000000000..c911b12808 --- /dev/null +++ b/src/openrct2/actions/RideDemolishAction.h @@ -0,0 +1,46 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(RideDemolishAction, GAME_COMMAND_DEMOLISH_RIDE, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + uint8_t _modifyType{ RIDE_MODIFY_DEMOLISH }; + +public: + RideDemolishAction() = default; + RideDemolishAction(ride_id_t rideIndex, uint8_t modifyType) + : _rideIndex(rideIndex) + , _modifyType(modifyType) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint32_t GetCooldownTime() const override + { + return 1000; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr DemolishRide(Ride * ride) const; + money32 MazeRemoveTrack(const CoordsXYZD& coords) const; + money32 DemolishTracks() const; + GameActions::Result::Ptr RefurbishRide(Ride * ride) const; + money32 GetRefurbishPrice(const Ride* ride) const; + money32 GetRefundPrice(const Ride* ride) const; +}; diff --git a/src/openrct2/actions/RideDemolishAction.hpp b/src/openrct2/actions/RideDemolishAction.hpp deleted file mode 100644 index c28b96e4d6..0000000000 --- a/src/openrct2/actions/RideDemolishAction.hpp +++ /dev/null @@ -1,392 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../Context.h" -#include "../GameState.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../management/NewsItem.h" -#include "../ride/Ride.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../world/Banner.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" -#include "MazeSetTrackAction.hpp" -#include "TrackRemoveAction.hpp" - -using namespace OpenRCT2; - -DEFINE_GAME_ACTION(RideDemolishAction, GAME_COMMAND_DEMOLISH_RIDE, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - uint8_t _modifyType{ RIDE_MODIFY_DEMOLISH }; - -public: - RideDemolishAction() = default; - RideDemolishAction(ride_id_t rideIndex, uint8_t modifyType) - : _rideIndex(rideIndex) - , _modifyType(modifyType) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("modifyType", _modifyType); - } - - uint32_t GetCooldownTime() const override - { - return 1000; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_modifyType); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_DEMOLISH_RIDE, STR_NONE); - } - - if (ride->lifecycle_flags & (RIDE_LIFECYCLE_INDESTRUCTIBLE | RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) - && _modifyType == RIDE_MODIFY_DEMOLISH) - { - return std::make_unique( - GameActions::Status::NoClearance, STR_CANT_DEMOLISH_RIDE, - STR_LOCAL_AUTHORITY_FORBIDS_DEMOLITION_OR_MODIFICATIONS_TO_THIS_RIDE); - } - - GameActions::Result::Ptr result = std::make_unique(); - - if (_modifyType == RIDE_MODIFY_RENEW) - { - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_MUST_BE_CLOSED_FIRST); - } - - if (ride->num_riders > 0) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_RIDE_NOT_YET_EMPTY); - } - - if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) - || RideTypeDescriptors[ride->type].AvailableBreakdowns == 0) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_CANT_REFURBISH_NOT_NEEDED); - } - - result->ErrorTitle = STR_CANT_REFURBISH_RIDE; - result->Cost = GetRefurbishPrice(ride); - } - - return result; - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_DEMOLISH_RIDE, STR_NONE); - } - - switch (_modifyType) - { - case RIDE_MODIFY_DEMOLISH: - return DemolishRide(ride); - case RIDE_MODIFY_RENEW: - return RefurbishRide(ride); - } - - return std::make_unique(GameActions::Status::InvalidParameters, STR_CANT_DO_THIS); - } - -private: - GameActions::Result::Ptr DemolishRide(Ride * ride) const - { - money32 refundPrice = DemolishTracks(); - - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - ride->StopGuestsQueuing(); - - sub_6CB945(ride); - ride_clear_leftover_entrances(ride); - News::DisableNewsItems(News::ItemType::Ride, _rideIndex); - - for (BannerIndex i = 0; i < MAX_BANNERS; i++) - { - auto banner = GetBanner(i); - if (!banner->IsNull() && banner->flags & BANNER_FLAG_LINKED_TO_RIDE && banner->ride_index == _rideIndex) - { - banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; - banner->text = {}; - } - } - - for (auto peep : EntityList(EntityListId::Peep)) - { - uint8_t ride_id_bit = _rideIndex % 8; - uint8_t ride_id_offset = _rideIndex / 8; - - // clear ride from potentially being in RidesBeenOn - peep->RidesBeenOn[ride_id_offset] &= ~(1 << ride_id_bit); - if (peep->State == PeepState::Watching) - { - if (peep->CurrentRide == _rideIndex) - { - peep->CurrentRide = RIDE_ID_NULL; - if (peep->TimeToStand >= 50) - { - // make peep stop watching the ride - peep->TimeToStand = 50; - } - } - } - - // remove any free voucher for this ride from peep - if (peep->HasItem(ShopItem::Voucher)) - { - if (peep->VoucherType == VOUCHER_TYPE_RIDE_FREE && peep->VoucherRideId == _rideIndex) - { - peep->RemoveItem(ShopItem::Voucher); - } - } - - // remove any photos of this ride from peep - if (peep->HasItem(ShopItem::Photo)) - { - if (peep->Photo1RideRef == _rideIndex) - { - peep->RemoveItem(ShopItem::Photo); - } - } - if (peep->HasItem(ShopItem::Photo2)) - { - if (peep->Photo2RideRef == _rideIndex) - { - peep->RemoveItem(ShopItem::Photo2); - } - } - if (peep->HasItem(ShopItem::Photo3)) - { - if (peep->Photo3RideRef == _rideIndex) - { - peep->RemoveItem(ShopItem::Photo3); - } - } - if (peep->HasItem(ShopItem::Photo4)) - { - if (peep->Photo4RideRef == _rideIndex) - { - peep->RemoveItem(ShopItem::Photo4); - } - } - - if (peep->GuestHeadingToRideId == _rideIndex) - { - peep->GuestHeadingToRideId = RIDE_ID_NULL; - } - if (peep->FavouriteRide == _rideIndex) - { - peep->FavouriteRide = RIDE_ID_NULL; - } - - for (int32_t i = 0; i < PEEP_MAX_THOUGHTS; i++) - { - // Don't touch items after the first NONE thought as they are not valid - // fixes issues with clearing out bad thought data in multiplayer - if (peep->Thoughts[i].type == PeepThoughtType::None) - break; - - if (peep->Thoughts[i].type != PeepThoughtType::None && peep->Thoughts[i].item == _rideIndex) - { - // Clear top thought, push others up - memmove(&peep->Thoughts[i], &peep->Thoughts[i + 1], sizeof(rct_peep_thought) * (PEEP_MAX_THOUGHTS - i - 1)); - peep->Thoughts[PEEP_MAX_THOUGHTS - 1].type = PeepThoughtType::None; - peep->Thoughts[PEEP_MAX_THOUGHTS - 1].item = PEEP_THOUGHT_ITEM_NONE; - // Next iteration, check the new thought at this index - i--; - } - } - } - - MarketingCancelCampaignsForRide(_rideIndex); - - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::RideConstruction; - res->Cost = refundPrice; - - if (!ride->overall_view.isNull()) - { - auto xy = ride->overall_view.ToTileCentre(); - res->Position = { xy, tile_element_height(xy) }; - } - - ride->Delete(); - gParkValue = GetContext()->GetGameState()->GetPark().CalculateParkValue(); - - // Close windows related to the demolished ride - if (!(GetFlags() & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED)) - { - window_close_by_number(WC_RIDE_CONSTRUCTION, _rideIndex); - } - window_close_by_number(WC_RIDE, _rideIndex); - window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, _rideIndex); - window_close_by_class(WC_NEW_CAMPAIGN); - - // Refresh windows that display the ride name - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_RIDE_LIST)); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_GUEST_LIST)); - - scrolling_text_invalidate(); - gfx_invalidate_screen(); - - return res; - } - - money32 MazeRemoveTrack(const CoordsXYZD& coords) const - { - auto setMazeTrack = MazeSetTrackAction(coords, false, _rideIndex, GC_SET_MAZE_TRACK_FILL); - setMazeTrack.SetFlags(GetFlags()); - - auto execRes = GameActions::ExecuteNested(&setMazeTrack); - if (execRes->Error == GameActions::Status::Ok) - { - return execRes->Cost; - } - - return MONEY32_UNDEFINED; - } - - money32 DemolishTracks() const - { - money32 refundPrice = 0; - - uint8_t oldpaused = gGamePaused; - gGamePaused = 0; - - tile_element_iterator it; - - tile_element_iterator_begin(&it); - while (tile_element_iterator_next(&it)) - { - if (it.element->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if (it.element->AsTrack()->GetRideIndex() != static_cast(_rideIndex)) - continue; - - auto location = CoordsXYZD( - TileCoordsXY(it.x, it.y).ToCoordsXY(), it.element->GetBaseZ(), it.element->GetDirection()); - auto type = it.element->AsTrack()->GetTrackType(); - - if (type != TrackElemType::Maze) - { - auto trackRemoveAction = TrackRemoveAction(type, it.element->AsTrack()->GetSequenceIndex(), location); - trackRemoveAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND); - - auto removRes = GameActions::ExecuteNested(&trackRemoveAction); - - if (removRes->Error != GameActions::Status::Ok) - { - tile_element_remove(it.element); - } - else - { - refundPrice += removRes->Cost; - } - - tile_element_iterator_restart_for_tile(&it); - continue; - } - - static constexpr const CoordsXY DirOffsets[] = { - { 0, 0 }, - { 0, 16 }, - { 16, 16 }, - { 16, 0 }, - }; - - for (Direction dir : ALL_DIRECTIONS) - { - const CoordsXYZ off = { DirOffsets[dir], 0 }; - money32 removePrice = MazeRemoveTrack({ location + off, dir }); - if (removePrice != MONEY32_UNDEFINED) - refundPrice += removePrice; - else - break; - } - - tile_element_iterator_restart_for_tile(&it); - } - - gGamePaused = oldpaused; - return refundPrice; - } - - GameActions::Result::Ptr RefurbishRide(Ride * ride) const - { - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::RideConstruction; - res->Cost = GetRefurbishPrice(ride); - - ride->Renew(); - - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_EVER_BEEN_OPENED; - ride->last_crash_type = RIDE_CRASH_TYPE_NONE; - - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE | RIDE_INVALIDATE_RIDE_CUSTOMER; - - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - } - - window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, _rideIndex); - - return res; - } - - money32 GetRefurbishPrice(const Ride* ride) const - { - return -GetRefundPrice(ride) / 2; - } - - money32 GetRefundPrice(const Ride* ride) const - { - return ride_get_refund_price(ride); - } -}; diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.cpp b/src/openrct2/actions/RideEntranceExitPlaceAction.cpp new file mode 100644 index 0000000000..4f6f2dd5f0 --- /dev/null +++ b/src/openrct2/actions/RideEntranceExitPlaceAction.cpp @@ -0,0 +1,204 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideEntranceExitPlaceAction.h" + +#include "../actions/RideEntranceExitRemoveAction.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../ride/Station.h" +#include "../world/MapAnimation.h" +#include "../world/Sprite.h" + +void RideEntranceExitPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("direction", _direction); + visitor.Visit("ride", _rideIndex); + visitor.Visit("station", _stationNum); + visitor.Visit("isExit", _isExit); +} + +void RideEntranceExitPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_direction) << DS_TAG(_rideIndex) << DS_TAG(_stationNum) << DS_TAG(_isExit); +} + +GameActions::Result::Ptr RideEntranceExitPlaceAction::Query() const +{ + auto errorTitle = _isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION + : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, errorTitle); + } + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %d", static_cast(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, errorTitle); + } + + if (_stationNum >= MAX_STATIONS) + { + log_warning("Invalid station number for ride. stationNum: %u", _stationNum); + return MakeResult(GameActions::Status::InvalidParameters, errorTitle); + } + + if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + { + return MakeResult(GameActions::Status::NotClosed, errorTitle, STR_MUST_BE_CLOSED_FIRST); + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) + { + return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_NOT_ALLOWED_TO_MODIFY_STATION); + } + + const auto location = _isExit ? ride_get_exit_location(ride, _stationNum) : ride_get_entrance_location(ride, _stationNum); + + if (!location.isNull()) + { + auto rideEntranceExitRemove = RideEntranceExitRemoveAction(location.ToCoordsXY(), _rideIndex, _stationNum, _isExit); + rideEntranceExitRemove.SetFlags(GetFlags()); + + auto result = GameActions::QueryNested(&rideEntranceExitRemove); + if (result->Error != GameActions::Status::Ok) + { + return result; + } + } + + auto z = ride->stations[_stationNum].GetBaseZ(); + if (!LocationValid(_loc) || (!gCheatsSandboxMode && !map_is_location_owned({ _loc, z }))) + { + return MakeResult(GameActions::Status::NotOwned, errorTitle); + } + + auto clear_z = z + (_isExit ? RideExitHeight : RideEntranceHeight); + auto cost = MONEY32_UNDEFINED; + if (!map_can_construct_with_clear_at( + { _loc, z, clear_z }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags(), &cost, + CREATE_CROSSING_MODE_NONE)) + { + return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) + { + return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); + } + + if (z > MaxRideEntranceOrExitHeight) + { + return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_TOO_HIGH); + } + + auto res = MakeResult(); + res->Position = { _loc.ToTileCentre(), z }; + res->Expenditure = ExpenditureType::RideConstruction; + return res; +} + +GameActions::Result::Ptr RideEntranceExitPlaceAction::Execute() const +{ + // Remember when in unknown station num mode rideIndex is unknown and z is set + // When in known station num mode rideIndex is known and z is unknown + auto errorTitle = _isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION + : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %d", static_cast(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, errorTitle); + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + } + + const auto location = _isExit ? ride_get_exit_location(ride, _stationNum) : ride_get_entrance_location(ride, _stationNum); + if (!location.isNull()) + { + auto rideEntranceExitRemove = RideEntranceExitRemoveAction(location.ToCoordsXY(), _rideIndex, _stationNum, _isExit); + rideEntranceExitRemove.SetFlags(GetFlags()); + + auto result = GameActions::ExecuteNested(&rideEntranceExitRemove); + if (result->Error != GameActions::Status::Ok) + { + return result; + } + } + + auto z = ride->stations[_stationNum].GetBaseZ(); + if (!(GetFlags() & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter({ _loc, z }); + wall_remove_at_z({ _loc, z }); + } + + auto clear_z = z + (_isExit ? RideExitHeight : RideEntranceHeight); + auto cost = MONEY32_UNDEFINED; + if (!map_can_construct_with_clear_at( + { _loc, z, clear_z }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags() | GAME_COMMAND_FLAG_APPLY, &cost, + CREATE_CROSSING_MODE_NONE)) + { + return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); + } + + auto res = MakeResult(); + res->Position = { _loc.ToTileCentre(), z }; + res->Expenditure = ExpenditureType::RideConstruction; + + TileElement* tileElement = tile_element_insert(CoordsXYZ{ _loc, z }, 0b1111); + assert(tileElement != nullptr); + tileElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); + tileElement->SetDirection(_direction); + tileElement->SetClearanceZ(clear_z); + tileElement->AsEntrance()->SetEntranceType(_isExit ? ENTRANCE_TYPE_RIDE_EXIT : ENTRANCE_TYPE_RIDE_ENTRANCE); + tileElement->AsEntrance()->SetStationIndex(_stationNum); + tileElement->AsEntrance()->SetRideIndex(_rideIndex); + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + tileElement->SetGhost(true); + } + + if (_isExit) + { + ride_set_exit_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, tileElement->GetDirection() })); + } + else + { + ride_set_entrance_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, tileElement->GetDirection() })); + ride->stations[_stationNum].LastPeepInQueue = SPRITE_INDEX_NULL; + ride->stations[_stationNum].QueueLength = 0; + + map_animation_create(MAP_ANIMATION_TYPE_RIDE_ENTRANCE, { _loc, z }); + } + + footpath_queue_chain_reset(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + maze_entrance_hedge_removal({ _loc, tileElement }); + } + + footpath_connect_edges(_loc, tileElement, GetFlags()); + footpath_update_queue_chains(); + + map_invalidate_tile_full(_loc); + + return res; +} diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.h b/src/openrct2/actions/RideEntranceExitPlaceAction.h new file mode 100644 index 0000000000..ba5be6ed22 --- /dev/null +++ b/src/openrct2/actions/RideEntranceExitPlaceAction.h @@ -0,0 +1,85 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/Entrance.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(RideEntranceExitPlaceAction, GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, GameActions::Result) +{ +private: + CoordsXY _loc; + Direction _direction{ INVALID_DIRECTION }; + NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; + StationIndex _stationNum{ STATION_INDEX_NULL }; + bool _isExit{}; + +public: + RideEntranceExitPlaceAction() = default; + + RideEntranceExitPlaceAction( + const CoordsXY& loc, Direction direction, ride_id_t rideIndex, StationIndex stationNum, bool isExit) + : _loc(loc) + , _direction(direction) + , _rideIndex(rideIndex) + , _stationNum(stationNum) + , _isExit(isExit) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + + static GameActions::Result::Ptr TrackPlaceQuery(const CoordsXYZ& loc, const bool isExit) + { + auto errorTitle = isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION + : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, errorTitle); + } + + if (!gCheatsSandboxMode && !map_is_location_owned(loc)) + { + return MakeResult(GameActions::Status::NotOwned, errorTitle); + } + + int16_t baseZ = loc.z; + int16_t clearZ = baseZ + (isExit ? RideExitHeight : RideEntranceHeight); + auto cost = MONEY32_UNDEFINED; + if (!map_can_construct_with_clear_at( + { loc, baseZ, clearZ }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, 0, &cost, CREATE_CROSSING_MODE_NONE)) + { + return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) + { + return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); + } + + if (baseZ > MaxRideEntranceOrExitHeight) + { + return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_TOO_HIGH); + } + auto res = MakeResult(); + res->Position = { loc.ToTileCentre(), tile_element_height(loc) }; + res->Expenditure = ExpenditureType::RideConstruction; + return res; + } +}; diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.hpp b/src/openrct2/actions/RideEntranceExitPlaceAction.hpp deleted file mode 100644 index 0036eb2dd1..0000000000 --- a/src/openrct2/actions/RideEntranceExitPlaceAction.hpp +++ /dev/null @@ -1,274 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../actions/RideEntranceExitRemoveAction.hpp" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../ride/Station.h" -#include "../world/Entrance.h" -#include "../world/MapAnimation.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(RideEntranceExitPlaceAction, GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, GameActions::Result) -{ -private: - CoordsXY _loc; - Direction _direction{ INVALID_DIRECTION }; - NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; - StationIndex _stationNum{ STATION_INDEX_NULL }; - bool _isExit{}; - -public: - RideEntranceExitPlaceAction() = default; - - RideEntranceExitPlaceAction( - const CoordsXY& loc, Direction direction, ride_id_t rideIndex, StationIndex stationNum, bool isExit) - : _loc(loc) - , _direction(direction) - , _rideIndex(rideIndex) - , _stationNum(stationNum) - , _isExit(isExit) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("direction", _direction); - visitor.Visit("ride", _rideIndex); - visitor.Visit("station", _stationNum); - visitor.Visit("isExit", _isExit); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_direction) << DS_TAG(_rideIndex) << DS_TAG(_stationNum) << DS_TAG(_isExit); - } - - GameActions::Result::Ptr Query() const override - { - auto errorTitle = _isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION - : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, errorTitle); - } - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %d", static_cast(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, errorTitle); - } - - if (_stationNum >= MAX_STATIONS) - { - log_warning("Invalid station number for ride. stationNum: %u", _stationNum); - return MakeResult(GameActions::Status::InvalidParameters, errorTitle); - } - - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) - { - return MakeResult(GameActions::Status::NotClosed, errorTitle, STR_MUST_BE_CLOSED_FIRST); - } - - if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) - { - return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_NOT_ALLOWED_TO_MODIFY_STATION); - } - - const auto location = _isExit ? ride_get_exit_location(ride, _stationNum) - : ride_get_entrance_location(ride, _stationNum); - - if (!location.isNull()) - { - auto rideEntranceExitRemove = RideEntranceExitRemoveAction(location.ToCoordsXY(), _rideIndex, _stationNum, _isExit); - rideEntranceExitRemove.SetFlags(GetFlags()); - - auto result = GameActions::QueryNested(&rideEntranceExitRemove); - if (result->Error != GameActions::Status::Ok) - { - return result; - } - } - - auto z = ride->stations[_stationNum].GetBaseZ(); - if (!LocationValid(_loc) || (!gCheatsSandboxMode && !map_is_location_owned({ _loc, z }))) - { - return MakeResult(GameActions::Status::NotOwned, errorTitle); - } - - auto clear_z = z + (_isExit ? RideExitHeight : RideEntranceHeight); - auto cost = MONEY32_UNDEFINED; - if (!map_can_construct_with_clear_at( - { _loc, z, clear_z }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags(), &cost, - CREATE_CROSSING_MODE_NONE)) - { - return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) - { - return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); - } - - if (z > MaxRideEntranceOrExitHeight) - { - return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_TOO_HIGH); - } - - auto res = MakeResult(); - res->Position = { _loc.ToTileCentre(), z }; - res->Expenditure = ExpenditureType::RideConstruction; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - // Remember when in unknown station num mode rideIndex is unknown and z is set - // When in known station num mode rideIndex is known and z is unknown - auto errorTitle = _isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION - : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %d", static_cast(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, errorTitle); - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - } - - const auto location = _isExit ? ride_get_exit_location(ride, _stationNum) - : ride_get_entrance_location(ride, _stationNum); - if (!location.isNull()) - { - auto rideEntranceExitRemove = RideEntranceExitRemoveAction(location.ToCoordsXY(), _rideIndex, _stationNum, _isExit); - rideEntranceExitRemove.SetFlags(GetFlags()); - - auto result = GameActions::ExecuteNested(&rideEntranceExitRemove); - if (result->Error != GameActions::Status::Ok) - { - return result; - } - } - - auto z = ride->stations[_stationNum].GetBaseZ(); - if (!(GetFlags() & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter({ _loc, z }); - wall_remove_at_z({ _loc, z }); - } - - auto clear_z = z + (_isExit ? RideExitHeight : RideEntranceHeight); - auto cost = MONEY32_UNDEFINED; - if (!map_can_construct_with_clear_at( - { _loc, z, clear_z }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags() | GAME_COMMAND_FLAG_APPLY, - &cost, CREATE_CROSSING_MODE_NONE)) - { - return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); - } - - auto res = MakeResult(); - res->Position = { _loc.ToTileCentre(), z }; - res->Expenditure = ExpenditureType::RideConstruction; - - TileElement* tileElement = tile_element_insert(CoordsXYZ{ _loc, z }, 0b1111); - assert(tileElement != nullptr); - tileElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); - tileElement->SetDirection(_direction); - tileElement->SetClearanceZ(clear_z); - tileElement->AsEntrance()->SetEntranceType(_isExit ? ENTRANCE_TYPE_RIDE_EXIT : ENTRANCE_TYPE_RIDE_ENTRANCE); - tileElement->AsEntrance()->SetStationIndex(_stationNum); - tileElement->AsEntrance()->SetRideIndex(_rideIndex); - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } - - if (_isExit) - { - ride_set_exit_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, tileElement->GetDirection() })); - } - else - { - ride_set_entrance_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, tileElement->GetDirection() })); - ride->stations[_stationNum].LastPeepInQueue = SPRITE_INDEX_NULL; - ride->stations[_stationNum].QueueLength = 0; - - map_animation_create(MAP_ANIMATION_TYPE_RIDE_ENTRANCE, { _loc, z }); - } - - footpath_queue_chain_reset(); - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - maze_entrance_hedge_removal({ _loc, tileElement }); - } - - footpath_connect_edges(_loc, tileElement, GetFlags()); - footpath_update_queue_chains(); - - map_invalidate_tile_full(_loc); - - return res; - } - - static GameActions::Result::Ptr TrackPlaceQuery(const CoordsXYZ& loc, const bool isExit) - { - auto errorTitle = isExit ? STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION - : STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, errorTitle); - } - - if (!gCheatsSandboxMode && !map_is_location_owned(loc)) - { - return MakeResult(GameActions::Status::NotOwned, errorTitle); - } - - int16_t baseZ = loc.z; - int16_t clearZ = baseZ + (isExit ? RideExitHeight : RideEntranceHeight); - auto cost = MONEY32_UNDEFINED; - if (!map_can_construct_with_clear_at( - { loc, baseZ, clearZ }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, 0, &cost, CREATE_CROSSING_MODE_NONE)) - { - return MakeResult(GameActions::Status::NoClearance, errorTitle, gGameCommandErrorText, gCommonFormatArgs); - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) - { - return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); - } - - if (baseZ > MaxRideEntranceOrExitHeight) - { - return MakeResult(GameActions::Status::Disallowed, errorTitle, STR_TOO_HIGH); - } - auto res = MakeResult(); - res->Position = { loc.ToTileCentre(), tile_element_height(loc) }; - res->Expenditure = ExpenditureType::RideConstruction; - return res; - } -}; diff --git a/src/openrct2/actions/RideEntranceExitRemoveAction.cpp b/src/openrct2/actions/RideEntranceExitRemoveAction.cpp new file mode 100644 index 0000000000..45eb9dae3e --- /dev/null +++ b/src/openrct2/actions/RideEntranceExitRemoveAction.cpp @@ -0,0 +1,180 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideEntranceExitRemoveAction.h" + +#include "../ride/Ride.h" +#include "../ride/Station.h" +#include "../world/Entrance.h" + +void RideEntranceExitRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("ride", _rideIndex); + visitor.Visit("station", _stationNum); + visitor.Visit("isExit", _isExit); +} + +void RideEntranceExitRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_rideIndex) << DS_TAG(_stationNum) << DS_TAG(_isExit); +} + +GameActions::Result::Ptr RideEntranceExitRemoveAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride id %d for entrance/exit removal", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_MUST_BE_CLOSED_FIRST); + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NOT_ALLOWED_TO_MODIFY_STATION); + } + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); + } + + bool found = false; + TileElement* tileElement = map_get_first_element_at(_loc); + + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) + continue; + + if (tileElement->GetRideIndex() != _rideIndex) + continue; + + if (tileElement->AsEntrance()->GetStationIndex() != _stationNum) + continue; + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(tileElement->IsGhost())) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE && _isExit) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT && !_isExit) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, + static_cast(_rideIndex), _stationNum); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr RideEntranceExitRemoveAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride id %d for entrance/exit removal", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + invalidate_test_results(ride); + } + + bool found = false; + TileElement* tileElement = map_get_first_element_at(_loc); + + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) + continue; + + if (tileElement->GetRideIndex() != _rideIndex) + continue; + + if (tileElement->AsEntrance()->GetStationIndex() != _stationNum) + continue; + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !tileElement->IsGhost()) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE && _isExit) + continue; + + if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT && !_isExit) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, + static_cast(_rideIndex), _stationNum); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto res = MakeResult(); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = tile_element_height(res->Position); + + footpath_queue_chain_reset(); + maze_entrance_hedge_replacement({ _loc, tileElement }); + footpath_remove_edges_at(_loc, tileElement); + + tile_element_remove(tileElement); + + if (_isExit) + { + ride_clear_exit_location(ride, _stationNum); + } + else + { + ride_clear_entrance_location(ride, _stationNum); + } + + footpath_update_queue_chains(); + + map_invalidate_tile_full(_loc); + return res; +} diff --git a/src/openrct2/actions/RideEntranceExitRemoveAction.h b/src/openrct2/actions/RideEntranceExitRemoveAction.h new file mode 100644 index 0000000000..21e67eaa71 --- /dev/null +++ b/src/openrct2/actions/RideEntranceExitRemoveAction.h @@ -0,0 +1,43 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(RideEntranceExitRemoveAction, GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, GameActions::Result) +{ +private: + CoordsXY _loc; + NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; + StationIndex _stationNum{ STATION_INDEX_NULL }; + bool _isExit{}; + +public: + RideEntranceExitRemoveAction() = default; + + RideEntranceExitRemoveAction(const CoordsXY& loc, ride_id_t rideIndex, StationIndex stationNum, bool isExit) + : _loc(loc) + , _rideIndex(rideIndex) + , _stationNum(stationNum) + , _isExit(isExit) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideEntranceExitRemoveAction.hpp b/src/openrct2/actions/RideEntranceExitRemoveAction.hpp deleted file mode 100644 index c46cab164c..0000000000 --- a/src/openrct2/actions/RideEntranceExitRemoveAction.hpp +++ /dev/null @@ -1,206 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../ride/Ride.h" -#include "../ride/Station.h" -#include "../world/Entrance.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(RideEntranceExitRemoveAction, GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, GameActions::Result) -{ -private: - CoordsXY _loc; - NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; - StationIndex _stationNum{ STATION_INDEX_NULL }; - bool _isExit{}; - -public: - RideEntranceExitRemoveAction() = default; - - RideEntranceExitRemoveAction(const CoordsXY& loc, ride_id_t rideIndex, StationIndex stationNum, bool isExit) - : _loc(loc) - , _rideIndex(rideIndex) - , _stationNum(stationNum) - , _isExit(isExit) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("ride", _rideIndex); - visitor.Visit("station", _stationNum); - visitor.Visit("isExit", _isExit); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_rideIndex) << DS_TAG(_stationNum) << DS_TAG(_isExit); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride id %d for entrance/exit removal", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_MUST_BE_CLOSED_FIRST); - } - - if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NOT_ALLOWED_TO_MODIFY_STATION); - } - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); - } - - bool found = false; - TileElement* tileElement = map_get_first_element_at(_loc); - - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) - continue; - - if (tileElement->GetRideIndex() != _rideIndex) - continue; - - if (tileElement->AsEntrance()->GetStationIndex() != _stationNum) - continue; - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(tileElement->IsGhost())) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE && _isExit) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT && !_isExit) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, - static_cast(_rideIndex), _stationNum); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride id %d for entrance/exit removal", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - invalidate_test_results(ride); - } - - bool found = false; - TileElement* tileElement = map_get_first_element_at(_loc); - - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) - continue; - - if (tileElement->GetRideIndex() != _rideIndex) - continue; - - if (tileElement->AsEntrance()->GetStationIndex() != _stationNum) - continue; - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !tileElement->IsGhost()) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE && _isExit) - continue; - - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT && !_isExit) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, - static_cast(_rideIndex), _stationNum); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto res = MakeResult(); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = tile_element_height(res->Position); - - footpath_queue_chain_reset(); - maze_entrance_hedge_replacement({ _loc, tileElement }); - footpath_remove_edges_at(_loc, tileElement); - - tile_element_remove(tileElement); - - if (_isExit) - { - ride_clear_exit_location(ride, _stationNum); - } - else - { - ride_clear_entrance_location(ride, _stationNum); - } - - footpath_update_queue_chains(); - - map_invalidate_tile_full(_loc); - return res; - } -}; diff --git a/src/openrct2/actions/RideSetAppearanceAction.cpp b/src/openrct2/actions/RideSetAppearanceAction.cpp new file mode 100644 index 0000000000..b4408e4468 --- /dev/null +++ b/src/openrct2/actions/RideSetAppearanceAction.cpp @@ -0,0 +1,138 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideSetAppearanceAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../ride/Ride.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Park.h" + +void RideSetAppearanceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("type", _type); + visitor.Visit("value", _value); + visitor.Visit("index", _index); +} + +void RideSetAppearanceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_rideIndex) << DS_TAG(_type) << DS_TAG(_value) << DS_TAG(_index); +} + +GameActions::Result::Ptr RideSetAppearanceAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + switch (_type) + { + case RideSetAppearanceType::TrackColourMain: + case RideSetAppearanceType::TrackColourAdditional: + case RideSetAppearanceType::TrackColourSupports: + if (_index >= std::size(ride->track_colour)) + { + log_warning("Invalid game command, index %d out of bounds", _index); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + break; + case RideSetAppearanceType::VehicleColourBody: + case RideSetAppearanceType::VehicleColourTrim: + case RideSetAppearanceType::VehicleColourTernary: + if (_index >= std::size(ride->vehicle_colours)) + { + log_warning("Invalid game command, index %d out of bounds", _index); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + break; + case RideSetAppearanceType::VehicleColourScheme: + case RideSetAppearanceType::EntranceStyle: + break; + default: + log_warning("Invalid game command, type %d not recognised", _type); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetAppearanceAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + switch (_type) + { + case RideSetAppearanceType::TrackColourMain: + ride->track_colour[_index].main = _value; + gfx_invalidate_screen(); + break; + case RideSetAppearanceType::TrackColourAdditional: + ride->track_colour[_index].additional = _value; + gfx_invalidate_screen(); + break; + case RideSetAppearanceType::TrackColourSupports: + ride->track_colour[_index].supports = _value; + gfx_invalidate_screen(); + break; + case RideSetAppearanceType::VehicleColourBody: + ride->vehicle_colours[_index].Body = _value; + ride_update_vehicle_colours(ride); + break; + case RideSetAppearanceType::VehicleColourTrim: + ride->vehicle_colours[_index].Trim = _value; + ride_update_vehicle_colours(ride); + break; + case RideSetAppearanceType::VehicleColourTernary: + ride->vehicle_colours[_index].Ternary = _value; + ride_update_vehicle_colours(ride); + break; + case RideSetAppearanceType::VehicleColourScheme: + ride->colour_scheme_type &= ~(RIDE_COLOUR_SCHEME_DIFFERENT_PER_TRAIN | RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR); + ride->colour_scheme_type |= _value; + for (uint32_t i = 1; i < std::size(ride->vehicle_colours); i++) + { + ride->vehicle_colours[i] = ride->vehicle_colours[0]; + } + ride_update_vehicle_colours(ride); + break; + case RideSetAppearanceType::EntranceStyle: + ride->entrance_style = _value; + gLastEntranceStyle = _value; + gfx_invalidate_screen(); + break; + } + window_invalidate_by_number(WC_RIDE, _rideIndex); + + auto res = std::make_unique(); + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + } + + return res; +} diff --git a/src/openrct2/actions/RideSetAppearanceAction.h b/src/openrct2/actions/RideSetAppearanceAction.h new file mode 100644 index 0000000000..3530a35f96 --- /dev/null +++ b/src/openrct2/actions/RideSetAppearanceAction.h @@ -0,0 +1,55 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +enum class RideSetAppearanceType : uint8_t +{ + TrackColourMain, + TrackColourAdditional, + TrackColourSupports, + MazeStyle = TrackColourSupports, + VehicleColourBody, + VehicleColourTrim, + VehicleColourTernary, + VehicleColourScheme, + EntranceStyle +}; + +DEFINE_GAME_ACTION(RideSetAppearanceAction, GAME_COMMAND_SET_RIDE_APPEARANCE, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + RideSetAppearanceType _type{}; + uint8_t _value{}; + uint32_t _index{}; + +public: + RideSetAppearanceAction() = default; + RideSetAppearanceAction(ride_id_t rideIndex, RideSetAppearanceType type, uint8_t value, uint32_t index) + : _rideIndex(rideIndex) + , _type(type) + , _value(value) + , _index(index) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideSetAppearanceAction.hpp b/src/openrct2/actions/RideSetAppearanceAction.hpp deleted file mode 100644 index 02ffedee8c..0000000000 --- a/src/openrct2/actions/RideSetAppearanceAction.hpp +++ /dev/null @@ -1,176 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../ride/Ride.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../world/Park.h" -#include "GameAction.h" - -enum class RideSetAppearanceType : uint8_t -{ - TrackColourMain, - TrackColourAdditional, - TrackColourSupports, - MazeStyle = TrackColourSupports, - VehicleColourBody, - VehicleColourTrim, - VehicleColourTernary, - VehicleColourScheme, - EntranceStyle -}; - -DEFINE_GAME_ACTION(RideSetAppearanceAction, GAME_COMMAND_SET_RIDE_APPEARANCE, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - RideSetAppearanceType _type{}; - uint8_t _value{}; - uint32_t _index{}; - -public: - RideSetAppearanceAction() = default; - RideSetAppearanceAction(ride_id_t rideIndex, RideSetAppearanceType type, uint8_t value, uint32_t index) - : _rideIndex(rideIndex) - , _type(type) - , _value(value) - , _index(index) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("type", _type); - visitor.Visit("value", _value); - visitor.Visit("index", _index); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_rideIndex) << DS_TAG(_type) << DS_TAG(_value) << DS_TAG(_index); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - switch (_type) - { - case RideSetAppearanceType::TrackColourMain: - case RideSetAppearanceType::TrackColourAdditional: - case RideSetAppearanceType::TrackColourSupports: - if (_index >= std::size(ride->track_colour)) - { - log_warning("Invalid game command, index %d out of bounds", _index); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - break; - case RideSetAppearanceType::VehicleColourBody: - case RideSetAppearanceType::VehicleColourTrim: - case RideSetAppearanceType::VehicleColourTernary: - if (_index >= std::size(ride->vehicle_colours)) - { - log_warning("Invalid game command, index %d out of bounds", _index); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - break; - case RideSetAppearanceType::VehicleColourScheme: - case RideSetAppearanceType::EntranceStyle: - break; - default: - log_warning("Invalid game command, type %d not recognised", _type); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - switch (_type) - { - case RideSetAppearanceType::TrackColourMain: - ride->track_colour[_index].main = _value; - gfx_invalidate_screen(); - break; - case RideSetAppearanceType::TrackColourAdditional: - ride->track_colour[_index].additional = _value; - gfx_invalidate_screen(); - break; - case RideSetAppearanceType::TrackColourSupports: - ride->track_colour[_index].supports = _value; - gfx_invalidate_screen(); - break; - case RideSetAppearanceType::VehicleColourBody: - ride->vehicle_colours[_index].Body = _value; - ride_update_vehicle_colours(ride); - break; - case RideSetAppearanceType::VehicleColourTrim: - ride->vehicle_colours[_index].Trim = _value; - ride_update_vehicle_colours(ride); - break; - case RideSetAppearanceType::VehicleColourTernary: - ride->vehicle_colours[_index].Ternary = _value; - ride_update_vehicle_colours(ride); - break; - case RideSetAppearanceType::VehicleColourScheme: - ride->colour_scheme_type &= ~(RIDE_COLOUR_SCHEME_DIFFERENT_PER_TRAIN | RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR); - ride->colour_scheme_type |= _value; - for (uint32_t i = 1; i < std::size(ride->vehicle_colours); i++) - { - ride->vehicle_colours[i] = ride->vehicle_colours[0]; - } - ride_update_vehicle_colours(ride); - break; - case RideSetAppearanceType::EntranceStyle: - ride->entrance_style = _value; - gLastEntranceStyle = _value; - gfx_invalidate_screen(); - break; - } - window_invalidate_by_number(WC_RIDE, _rideIndex); - - auto res = std::make_unique(); - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - } - - return res; - } -}; diff --git a/src/openrct2/actions/RideSetColourScheme.hpp b/src/openrct2/actions/RideSetColourScheme.hpp deleted file mode 100644 index 470f69dff3..0000000000 --- a/src/openrct2/actions/RideSetColourScheme.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(RideSetColourSchemeAction, GAME_COMMAND_SET_COLOUR_SCHEME, GameActions::Result) -{ -private: - CoordsXYZD _loc; - int32_t _trackType{}; - uint16_t _newColourScheme{}; - -public: - RideSetColourSchemeAction() = default; - RideSetColourSchemeAction(const CoordsXYZD& location, int32_t trackType, uint16_t newColourScheme) - : _loc(location) - , _trackType(trackType) - , _newColourScheme(newColourScheme) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("trackType", _trackType); - visitor.Visit("colourScheme", _newColourScheme); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_trackType) << DS_TAG(_newColourScheme); - } - - GameActions::Result::Ptr Query() const override - { - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); - } - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Expenditure = ExpenditureType::RideConstruction; - res->ErrorTitle = STR_CANT_SET_COLOUR_SCHEME; - - sub_6C683D(_loc, _trackType, _newColourScheme, nullptr, TRACK_ELEMENT_SET_COLOUR_SCHEME); - - return res; - } -}; diff --git a/src/openrct2/actions/RideSetColourSchemeAction.cpp b/src/openrct2/actions/RideSetColourSchemeAction.cpp new file mode 100644 index 0000000000..33a1aeed4e --- /dev/null +++ b/src/openrct2/actions/RideSetColourSchemeAction.cpp @@ -0,0 +1,55 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideSetColourSchemeAction.h" + +#include "../Cheats.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../world/Park.h" +#include "../world/Sprite.h" + +void RideSetColourSchemeAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("trackType", _trackType); + visitor.Visit("colourScheme", _newColourScheme); +} + +void RideSetColourSchemeAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_trackType) << DS_TAG(_newColourScheme); +} + +GameActions::Result::Ptr RideSetColourSchemeAction::Query() const +{ + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); + } + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetColourSchemeAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Expenditure = ExpenditureType::RideConstruction; + res->ErrorTitle = STR_CANT_SET_COLOUR_SCHEME; + + sub_6C683D(_loc, _trackType, _newColourScheme, nullptr, TRACK_ELEMENT_SET_COLOUR_SCHEME); + + return res; +} diff --git a/src/openrct2/actions/RideSetColourSchemeAction.h b/src/openrct2/actions/RideSetColourSchemeAction.h new file mode 100644 index 0000000000..1afd87b396 --- /dev/null +++ b/src/openrct2/actions/RideSetColourSchemeAction.h @@ -0,0 +1,40 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(RideSetColourSchemeAction, GAME_COMMAND_SET_COLOUR_SCHEME, GameActions::Result) +{ +private: + CoordsXYZD _loc; + int32_t _trackType{}; + uint16_t _newColourScheme{}; + +public: + RideSetColourSchemeAction() = default; + RideSetColourSchemeAction(const CoordsXYZD& location, int32_t trackType, uint16_t newColourScheme) + : _loc(location) + , _trackType(trackType) + , _newColourScheme(newColourScheme) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideSetName.hpp b/src/openrct2/actions/RideSetName.hpp deleted file mode 100644 index aad6894eee..0000000000 --- a/src/openrct2/actions/RideSetName.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../ride/Ride.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../world/Park.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(RideSetNameAction, GAME_COMMAND_SET_RIDE_NAME, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - std::string _name; - -public: - RideSetNameAction() = default; - RideSetNameAction(ride_id_t rideIndex, const std::string& name) - : _rideIndex(rideIndex) - , _name(name) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("name", _name); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_NONE); - } - - if (!_name.empty() && Ride::NameExists(_name, ride->id)) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_ERROR_EXISTING_NAME); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_NONE); - } - - if (_name.empty()) - { - ride->SetNameToDefault(); - } - else - { - ride->custom_name = _name; - } - - scrolling_text_invalidate(); - gfx_invalidate_screen(); - - // Refresh windows that display ride name - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_RIDE_LIST)); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_GUEST_LIST)); - - auto res = std::make_unique(); - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - - return res; - } -}; diff --git a/src/openrct2/actions/RideSetNameAction.cpp b/src/openrct2/actions/RideSetNameAction.cpp new file mode 100644 index 0000000000..888c60c23d --- /dev/null +++ b/src/openrct2/actions/RideSetNameAction.cpp @@ -0,0 +1,89 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideSetNameAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../ride/Ride.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Park.h" + +void RideSetNameAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("name", _name); +} + +void RideSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_name); +} + +GameActions::Result::Ptr RideSetNameAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_NONE); + } + + if (!_name.empty() && Ride::NameExists(_name, ride->id)) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_ERROR_EXISTING_NAME); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetNameAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_RENAME_RIDE_ATTRACTION, STR_NONE); + } + + if (_name.empty()) + { + ride->SetNameToDefault(); + } + else + { + ride->custom_name = _name; + } + + scrolling_text_invalidate(); + gfx_invalidate_screen(); + + // Refresh windows that display ride name + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_RIDE_LIST)); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_GUEST_LIST)); + + auto res = std::make_unique(); + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + + return res; +} diff --git a/src/openrct2/actions/RideSetNameAction.h b/src/openrct2/actions/RideSetNameAction.h new file mode 100644 index 0000000000..4dbb4fa967 --- /dev/null +++ b/src/openrct2/actions/RideSetNameAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(RideSetNameAction, GAME_COMMAND_SET_RIDE_NAME, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + std::string _name; + +public: + RideSetNameAction() = default; + RideSetNameAction(ride_id_t rideIndex, const std::string& name) + : _rideIndex(rideIndex) + , _name(name) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideSetPriceAction.cpp b/src/openrct2/actions/RideSetPriceAction.cpp new file mode 100644 index 0000000000..918fb16a97 --- /dev/null +++ b/src/openrct2/actions/RideSetPriceAction.cpp @@ -0,0 +1,175 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideSetPriceAction.h" + +#include "../Cheats.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../ride/RideData.h" +#include "../ride/ShopItem.h" +#include "../world/Park.h" +#include "../world/Sprite.h" + +void RideSetPriceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("price", _price); + visitor.Visit("isPrimaryPrice", _primaryPrice); +} + +void RideSetPriceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_price) << DS_TAG(_primaryPrice); +} + +GameActions::Result::Ptr RideSetPriceAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return res; +} + +GameActions::Result::Ptr RideSetPriceAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Expenditure = ExpenditureType::ParkRideTickets; + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + } + + ShopItem shopItem; + if (_primaryPrice) + { + shopItem = ShopItem::Admission; + if (ride->type != RIDE_TYPE_TOILETS) + { + shopItem = rideEntry->shop_item[0]; + if (shopItem == ShopItem::None) + { + ride->price[0] = _price; + window_invalidate_by_class(WC_RIDE); + return res; + } + } + // Check same price in park flags + if (!shop_item_has_common_price(shopItem)) + { + ride->price[0] = _price; + window_invalidate_by_class(WC_RIDE); + return res; + } + } + else + { + shopItem = rideEntry->shop_item[1]; + if (shopItem == ShopItem::None) + { + shopItem = RideTypeDescriptors[ride->type].PhotoItem; + if ((ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) == 0) + { + ride->price[1] = _price; + window_invalidate_by_class(WC_RIDE); + return res; + } + } + // Check same price in park flags + if (!shop_item_has_common_price(shopItem)) + { + ride->price[1] = _price; + window_invalidate_by_class(WC_RIDE); + return res; + } + } + + // Synchronize prices if enabled. + RideSetCommonPrice(shopItem); + + return res; +} + +void RideSetPriceAction::RideSetCommonPrice(ShopItem shopItem) const +{ + for (auto& ride : GetRideManager()) + { + auto invalidate = false; + auto rideEntry = get_ride_entry(ride.subtype); + if (ride.type == RIDE_TYPE_TOILETS && shopItem == ShopItem::Admission) + { + if (ride.price[0] != _price) + { + ride.price[0] = _price; + invalidate = true; + } + } + else if (rideEntry != nullptr && rideEntry->shop_item[0] == shopItem) + { + if (ride.price[0] != _price) + { + ride.price[0] = _price; + invalidate = true; + } + } + if (rideEntry != nullptr) + { + // If the shop item is the same or an on-ride photo + if (rideEntry->shop_item[1] == shopItem + || (rideEntry->shop_item[1] == ShopItem::None && GetShopItemDescriptor(shopItem).IsPhoto())) + { + if (ride.price[1] != _price) + { + ride.price[1] = _price; + invalidate = true; + } + } + } + if (invalidate) + { + window_invalidate_by_number(WC_RIDE, ride.id); + } + } +} diff --git a/src/openrct2/actions/RideSetPriceAction.h b/src/openrct2/actions/RideSetPriceAction.h new file mode 100644 index 0000000000..1987b68883 --- /dev/null +++ b/src/openrct2/actions/RideSetPriceAction.h @@ -0,0 +1,43 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(RideSetPriceAction, GAME_COMMAND_SET_RIDE_PRICE, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + money16 _price{ MONEY16_UNDEFINED }; + bool _primaryPrice{ true }; + +public: + RideSetPriceAction() = default; + RideSetPriceAction(ride_id_t rideIndex, money16 price, bool primaryPrice) + : _rideIndex(rideIndex) + , _price(price) + , _primaryPrice(primaryPrice) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + void RideSetCommonPrice(ShopItem shopItem) const; +}; diff --git a/src/openrct2/actions/RideSetPriceAction.hpp b/src/openrct2/actions/RideSetPriceAction.hpp deleted file mode 100644 index 6b370821f1..0000000000 --- a/src/openrct2/actions/RideSetPriceAction.hpp +++ /dev/null @@ -1,199 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../ride/RideData.h" -#include "../ride/ShopItem.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(RideSetPriceAction, GAME_COMMAND_SET_RIDE_PRICE, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - money16 _price{ MONEY16_UNDEFINED }; - bool _primaryPrice{ true }; - -public: - RideSetPriceAction() = default; - RideSetPriceAction(ride_id_t rideIndex, money16 price, bool primaryPrice) - : _rideIndex(rideIndex) - , _price(price) - , _primaryPrice(primaryPrice) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("price", _price); - visitor.Visit("isPrimaryPrice", _primaryPrice); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_price) << DS_TAG(_primaryPrice); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Expenditure = ExpenditureType::ParkRideTickets; - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - } - - ShopItem shopItem; - if (_primaryPrice) - { - shopItem = ShopItem::Admission; - if (ride->type != RIDE_TYPE_TOILETS) - { - shopItem = rideEntry->shop_item[0]; - if (shopItem == ShopItem::None) - { - ride->price[0] = _price; - window_invalidate_by_class(WC_RIDE); - return res; - } - } - // Check same price in park flags - if (!shop_item_has_common_price(shopItem)) - { - ride->price[0] = _price; - window_invalidate_by_class(WC_RIDE); - return res; - } - } - else - { - shopItem = rideEntry->shop_item[1]; - if (shopItem == ShopItem::None) - { - shopItem = RideTypeDescriptors[ride->type].PhotoItem; - if ((ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) == 0) - { - ride->price[1] = _price; - window_invalidate_by_class(WC_RIDE); - return res; - } - } - // Check same price in park flags - if (!shop_item_has_common_price(shopItem)) - { - ride->price[1] = _price; - window_invalidate_by_class(WC_RIDE); - return res; - } - } - - // Synchronize prices if enabled. - RideSetCommonPrice(shopItem); - - return res; - } - -private: - void RideSetCommonPrice(ShopItem shopItem) const - { - for (auto& ride : GetRideManager()) - { - auto invalidate = false; - auto rideEntry = get_ride_entry(ride.subtype); - if (ride.type == RIDE_TYPE_TOILETS && shopItem == ShopItem::Admission) - { - if (ride.price[0] != _price) - { - ride.price[0] = _price; - invalidate = true; - } - } - else if (rideEntry != nullptr && rideEntry->shop_item[0] == shopItem) - { - if (ride.price[0] != _price) - { - ride.price[0] = _price; - invalidate = true; - } - } - if (rideEntry != nullptr) - { - // If the shop item is the same or an on-ride photo - if (rideEntry->shop_item[1] == shopItem - || (rideEntry->shop_item[1] == ShopItem::None && GetShopItemDescriptor(shopItem).IsPhoto())) - { - if (ride.price[1] != _price) - { - ride.price[1] = _price; - invalidate = true; - } - } - } - if (invalidate) - { - window_invalidate_by_number(WC_RIDE, ride.id); - } - } - } -}; diff --git a/src/openrct2/actions/RideSetSetting.hpp b/src/openrct2/actions/RideSetSetting.hpp deleted file mode 100644 index 4748483aeb..0000000000 --- a/src/openrct2/actions/RideSetSetting.hpp +++ /dev/null @@ -1,324 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../ride/Ride.h" -#include "../ride/RideData.h" -#include "GameAction.h" - -enum class RideSetSetting : uint8_t -{ - Mode, - Departure, - MinWaitingTime, - MaxWaitingTime, - Operation, - InspectionInterval, - Music, - MusicType, - LiftHillSpeed, - NumCircuits, - RideType, -}; - -DEFINE_GAME_ACTION(RideSetSettingAction, GAME_COMMAND_SET_RIDE_SETTING, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - RideSetSetting _setting{}; - uint8_t _value{}; - -public: - RideSetSettingAction() = default; - RideSetSettingAction(ride_id_t rideIndex, RideSetSetting setting, uint8_t value) - : _rideIndex(rideIndex) - , _setting(setting) - , _value(value) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("setting", _setting); - visitor.Visit("value", _value); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_setting) << DS_TAG(_value); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride: #%d.", static_cast(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - - switch (_setting) - { - case RideSetSetting::Mode: - if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) - { - return MakeResult( - GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE, - STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); - } - - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) - { - return MakeResult( - GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE, STR_MUST_BE_CLOSED_FIRST); - } - - if (!ride_is_mode_valid(ride) && !gCheatsShowAllOperatingModes) - { - log_warning("Invalid ride mode: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::Departure: - break; - case RideSetSetting::MinWaitingTime: - if (_value > 250) - { - log_warning("Invalid minimum waiting time: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::MaxWaitingTime: - if (_value > 250) - { - log_warning("Invalid maximum waiting time: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::Operation: - if (!ride_is_valid_operation_option(ride)) - { - log_warning("Invalid operation option value: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, GetOperationErrorMessage(ride)); - } - break; - case RideSetSetting::InspectionInterval: - if (_value > RIDE_INSPECTION_NEVER) - { - log_warning("Invalid inspection interval: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::Music: - break; - case RideSetSetting::MusicType: - if (_value >= MUSIC_STYLE_COUNT) - { - log_warning("Invalid music style: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::LiftHillSpeed: - if (!ride_is_valid_lift_hill_speed(ride)) - { - log_warning("Invalid lift hill speed: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::NumCircuits: - if (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT && _value > 1) - { - return MakeResult( - GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE, - STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL); - } - - if (!ride_is_valid_num_circuits()) - { - log_warning("Invalid number of circuits: %u", _value); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - case RideSetSetting::RideType: - if (!gCheatsAllowArbitraryRideTypeChanges) - { - log_warning("Arbitary ride type changes not allowed."); - return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE); - } - break; - default: - log_warning("Invalid RideSetSetting: %u", static_cast(_setting)); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - break; - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride: #%d.", static_cast(_rideIndex)); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); - } - - switch (_setting) - { - case RideSetSetting::Mode: - invalidate_test_results(ride); - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - - ride->mode = static_cast(_value); - ride->UpdateMaxVehicles(); - ride->UpdateNumberOfCircuits(); - break; - case RideSetSetting::Departure: - ride->depart_flags = _value; - break; - case RideSetSetting::MinWaitingTime: - ride->min_waiting_time = _value; - ride->max_waiting_time = std::max(_value, ride->max_waiting_time); - break; - case RideSetSetting::MaxWaitingTime: - ride->max_waiting_time = _value; - ride->min_waiting_time = std::min(_value, ride->min_waiting_time); - break; - case RideSetSetting::Operation: - invalidate_test_results(ride); - ride->operation_option = _value; - break; - case RideSetSetting::InspectionInterval: - - if (_value == RIDE_INSPECTION_NEVER) - { - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_DUE_INSPECTION; - } - - ride->inspection_interval = _value; - break; - case RideSetSetting::Music: - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_MUSIC; - if (_value) - { - ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; - } - break; - case RideSetSetting::MusicType: - if (_value != ride->music) - { - ride->music = _value; - ride->music_tune_id = 0xFF; - } - break; - case RideSetSetting::LiftHillSpeed: - if (_value != ride->lift_hill_speed) - { - ride->lift_hill_speed = _value; - invalidate_test_results(ride); - } - break; - case RideSetSetting::NumCircuits: - if (_value != ride->num_circuits) - { - ride->num_circuits = _value; - invalidate_test_results(ride); - } - - break; - case RideSetSetting::RideType: - ride->type = _value; - gfx_invalidate_screen(); - break; - } - - auto res = std::make_unique(); - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(location) }; - } - window_invalidate_by_number(WC_RIDE, _rideIndex); - return res; - } - -private: - bool ride_is_mode_valid(Ride * ride) const - { - return RideTypeDescriptors[ride->type].RideModes & (1ULL << _value); - } - - bool ride_is_valid_lift_hill_speed(Ride * ride) const - { - int32_t minSpeed = gCheatsFastLiftHill ? 0 : RideTypeDescriptors[ride->type].LiftData.minimum_speed; - int32_t maxSpeed = gCheatsFastLiftHill ? 255 : RideTypeDescriptors[ride->type].LiftData.maximum_speed; - return _value >= minSpeed && _value <= maxSpeed; - } - - bool ride_is_valid_num_circuits() const - { - int32_t minNumCircuits = 1; - int32_t maxNumCircuits = gCheatsFastLiftHill ? 255 : 20; - return _value >= minNumCircuits && _value <= maxNumCircuits; - } - - bool ride_is_valid_operation_option(Ride * ride) const - { - const auto& operatingSettings = RideTypeDescriptors[ride->type].OperatingSettings; - uint8_t minValue = operatingSettings.MinValue; - uint8_t maxValue = operatingSettings.MaxValue; - if (gCheatsFastLiftHill) - { - minValue = 0; - maxValue = 255; - } - - return _value >= minValue && _value <= maxValue; - } - - rct_string_id GetOperationErrorMessage(Ride * ride) const - { - switch (ride->mode) - { - case RideMode::StationToStation: - return STR_CANT_CHANGE_SPEED; - case RideMode::Race: - return STR_CANT_CHANGE_NUMBER_OF_LAPS; - case RideMode::Dodgems: - return STR_CANT_CHANGE_TIME_LIMIT; - case RideMode::Swing: - return STR_CANT_CHANGE_NUMBER_OF_SWINGS; - case RideMode::Rotation: - case RideMode::ForwardRotation: - case RideMode::BackwardRotation: - return STR_CANT_CHANGE_NUMBER_OF_ROTATIONS; - default: - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_VEHICLES)) - { - return STR_CANT_CHANGE_THIS; - } - else - { - return STR_CANT_CHANGE_LAUNCH_SPEED; - } - break; - } - } -}; diff --git a/src/openrct2/actions/RideSetSettingAction.cpp b/src/openrct2/actions/RideSetSettingAction.cpp new file mode 100644 index 0000000000..7d8f401889 --- /dev/null +++ b/src/openrct2/actions/RideSetSettingAction.cpp @@ -0,0 +1,281 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideSetSettingAction.h" + +#include "../ride/Ride.h" +#include "../ride/RideData.h" + +void RideSetSettingAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("setting", _setting); + visitor.Visit("value", _value); +} + +void RideSetSettingAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_setting) << DS_TAG(_value); +} + +GameActions::Result::Ptr RideSetSettingAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride: #%d.", static_cast(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + + switch (_setting) + { + case RideSetSetting::Mode: + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) + { + return MakeResult( + GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); + } + + if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE, STR_MUST_BE_CLOSED_FIRST); + } + + if (!ride_is_mode_valid(ride) && !gCheatsShowAllOperatingModes) + { + log_warning("Invalid ride mode: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::Departure: + break; + case RideSetSetting::MinWaitingTime: + if (_value > 250) + { + log_warning("Invalid minimum waiting time: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::MaxWaitingTime: + if (_value > 250) + { + log_warning("Invalid maximum waiting time: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::Operation: + if (!ride_is_valid_operation_option(ride)) + { + log_warning("Invalid operation option value: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, GetOperationErrorMessage(ride)); + } + break; + case RideSetSetting::InspectionInterval: + if (_value > RIDE_INSPECTION_NEVER) + { + log_warning("Invalid inspection interval: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::Music: + break; + case RideSetSetting::MusicType: + if (_value >= MUSIC_STYLE_COUNT) + { + log_warning("Invalid music style: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::LiftHillSpeed: + if (!ride_is_valid_lift_hill_speed(ride)) + { + log_warning("Invalid lift hill speed: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::NumCircuits: + if (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT && _value > 1) + { + return MakeResult( + GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE, + STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL); + } + + if (!ride_is_valid_num_circuits()) + { + log_warning("Invalid number of circuits: %u", _value); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + case RideSetSetting::RideType: + if (!gCheatsAllowArbitraryRideTypeChanges) + { + log_warning("Arbitary ride type changes not allowed."); + return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE); + } + break; + default: + log_warning("Invalid RideSetSetting: %u", static_cast(_setting)); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetSettingAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride: #%d.", static_cast(_rideIndex)); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); + } + + switch (_setting) + { + case RideSetSetting::Mode: + invalidate_test_results(ride); + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + + ride->mode = static_cast(_value); + ride->UpdateMaxVehicles(); + ride->UpdateNumberOfCircuits(); + break; + case RideSetSetting::Departure: + ride->depart_flags = _value; + break; + case RideSetSetting::MinWaitingTime: + ride->min_waiting_time = _value; + ride->max_waiting_time = std::max(_value, ride->max_waiting_time); + break; + case RideSetSetting::MaxWaitingTime: + ride->max_waiting_time = _value; + ride->min_waiting_time = std::min(_value, ride->min_waiting_time); + break; + case RideSetSetting::Operation: + invalidate_test_results(ride); + ride->operation_option = _value; + break; + case RideSetSetting::InspectionInterval: + + if (_value == RIDE_INSPECTION_NEVER) + { + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_DUE_INSPECTION; + } + + ride->inspection_interval = _value; + break; + case RideSetSetting::Music: + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_MUSIC; + if (_value) + { + ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; + } + break; + case RideSetSetting::MusicType: + if (_value != ride->music) + { + ride->music = _value; + ride->music_tune_id = 0xFF; + } + break; + case RideSetSetting::LiftHillSpeed: + if (_value != ride->lift_hill_speed) + { + ride->lift_hill_speed = _value; + invalidate_test_results(ride); + } + break; + case RideSetSetting::NumCircuits: + if (_value != ride->num_circuits) + { + ride->num_circuits = _value; + invalidate_test_results(ride); + } + + break; + case RideSetSetting::RideType: + ride->type = _value; + gfx_invalidate_screen(); + break; + } + + auto res = std::make_unique(); + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(location) }; + } + window_invalidate_by_number(WC_RIDE, _rideIndex); + return res; +} + +bool RideSetSettingAction::ride_is_mode_valid(Ride* ride) const +{ + return RideTypeDescriptors[ride->type].RideModes & (1ULL << _value); +} + +bool RideSetSettingAction::ride_is_valid_lift_hill_speed(Ride* ride) const +{ + int32_t minSpeed = gCheatsFastLiftHill ? 0 : RideTypeDescriptors[ride->type].LiftData.minimum_speed; + int32_t maxSpeed = gCheatsFastLiftHill ? 255 : RideTypeDescriptors[ride->type].LiftData.maximum_speed; + return _value >= minSpeed && _value <= maxSpeed; +} + +bool RideSetSettingAction::ride_is_valid_num_circuits() const +{ + int32_t minNumCircuits = 1; + int32_t maxNumCircuits = gCheatsFastLiftHill ? 255 : 20; + return _value >= minNumCircuits && _value <= maxNumCircuits; +} + +bool RideSetSettingAction::ride_is_valid_operation_option(Ride* ride) const +{ + const auto& operatingSettings = RideTypeDescriptors[ride->type].OperatingSettings; + uint8_t minValue = operatingSettings.MinValue; + uint8_t maxValue = operatingSettings.MaxValue; + if (gCheatsFastLiftHill) + { + minValue = 0; + maxValue = 255; + } + + return _value >= minValue && _value <= maxValue; +} + +rct_string_id RideSetSettingAction::GetOperationErrorMessage(Ride* ride) const +{ + switch (ride->mode) + { + case RideMode::StationToStation: + return STR_CANT_CHANGE_SPEED; + case RideMode::Race: + return STR_CANT_CHANGE_NUMBER_OF_LAPS; + case RideMode::Dodgems: + return STR_CANT_CHANGE_TIME_LIMIT; + case RideMode::Swing: + return STR_CANT_CHANGE_NUMBER_OF_SWINGS; + case RideMode::Rotation: + case RideMode::ForwardRotation: + case RideMode::BackwardRotation: + return STR_CANT_CHANGE_NUMBER_OF_ROTATIONS; + default: + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_VEHICLES)) + { + return STR_CANT_CHANGE_THIS; + } + else + { + return STR_CANT_CHANGE_LAUNCH_SPEED; + } + } +} diff --git a/src/openrct2/actions/RideSetSettingAction.h b/src/openrct2/actions/RideSetSettingAction.h new file mode 100644 index 0000000000..6af75ff9ab --- /dev/null +++ b/src/openrct2/actions/RideSetSettingAction.h @@ -0,0 +1,62 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +enum class RideSetSetting : uint8_t +{ + Mode, + Departure, + MinWaitingTime, + MaxWaitingTime, + Operation, + InspectionInterval, + Music, + MusicType, + LiftHillSpeed, + NumCircuits, + RideType, +}; + +DEFINE_GAME_ACTION(RideSetSettingAction, GAME_COMMAND_SET_RIDE_SETTING, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + RideSetSetting _setting{}; + uint8_t _value{}; + +public: + RideSetSettingAction() = default; + RideSetSettingAction(ride_id_t rideIndex, RideSetSetting setting, uint8_t value) + : _rideIndex(rideIndex) + , _setting(setting) + , _value(value) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + bool ride_is_mode_valid(Ride * ride) const; + bool ride_is_valid_lift_hill_speed(Ride * ride) const; + bool ride_is_valid_num_circuits() const; + bool ride_is_valid_operation_option(Ride * ride) const; + rct_string_id GetOperationErrorMessage(Ride * ride) const; +}; diff --git a/src/openrct2/actions/RideSetStatus.hpp b/src/openrct2/actions/RideSetStatus.hpp deleted file mode 100644 index 6fed33f790..0000000000 --- a/src/openrct2/actions/RideSetStatus.hpp +++ /dev/null @@ -1,248 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -static rct_string_id _StatusErrorTitles[] = { - STR_CANT_CLOSE, - STR_CANT_OPEN, - STR_CANT_TEST, - STR_CANT_SIMULATE, -}; - -DEFINE_GAME_ACTION(RideSetStatusAction, GAME_COMMAND_SET_RIDE_STATUS, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - uint8_t _status{ RIDE_STATUS_CLOSED }; - -public: - RideSetStatusAction() = default; - RideSetStatusAction(ride_id_t rideIndex, uint8_t status) - : _rideIndex(rideIndex) - , _status(status) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("status", _status); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_status); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - res->Error = GameActions::Status::InvalidParameters; - res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; - res->ErrorMessage = STR_NONE; - return res; - } - - if (_status >= RIDE_STATUS_COUNT) - { - log_warning("Invalid ride status %u for ride %u", uint32_t(_status), uint32_t(_rideIndex)); - res->Error = GameActions::Status::InvalidParameters; - res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; - res->ErrorMessage = STR_NONE; - return res; - } - - res->ErrorTitle = _StatusErrorTitles[_status]; - - Formatter ft(res->ErrorMessageArgs.data()); - ft.Increment(6); - ride->FormatNameTo(ft); - if (_status != ride->status) - { - if (_status == RIDE_STATUS_SIMULATING && (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) - { - // Simulating will force clear the track, so make sure player can't cheat around a break down - res->Error = GameActions::Status::Disallowed; - res->ErrorMessage = STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING; - return res; - } - else if (_status == RIDE_STATUS_TESTING || _status == RIDE_STATUS_SIMULATING) - { - if (!ride->Test(_status, false)) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = gGameCommandErrorText; - return res; - } - } - else if (_status == RIDE_STATUS_OPEN) - { - if (!ride->Open(false)) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = gGameCommandErrorText; - return res; - } - } - } - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Expenditure = ExpenditureType::RideRunningCosts; - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); - res->Error = GameActions::Status::InvalidParameters; - res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; - res->ErrorMessage = STR_NONE; - return res; - } - - res->ErrorTitle = _StatusErrorTitles[_status]; - - Formatter ft(res->ErrorMessageArgs.data()); - ft.Increment(6); - ride->FormatNameTo(ft); - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(res->Position) }; - } - - switch (_status) - { - case RIDE_STATUS_CLOSED: - if (ride->status == _status || ride->status == RIDE_STATUS_SIMULATING) - { - if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) - { - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - } - } - - ride->status = RIDE_STATUS_CLOSED; - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; - ride->race_winner = SPRITE_INDEX_NULL; - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - window_invalidate_by_number(WC_RIDE, _rideIndex); - break; - case RIDE_STATUS_SIMULATING: - { - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - - if (!ride->Test(_status, true)) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = gGameCommandErrorText; - return res; - } - - ride->status = _status; - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; - ride->race_winner = SPRITE_INDEX_NULL; - ride->current_issues = 0; - ride->last_issue_time = 0; - ride->GetMeasurement(); - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - window_invalidate_by_number(WC_RIDE, _rideIndex); - break; - } - case RIDE_STATUS_TESTING: - case RIDE_STATUS_OPEN: - { - if (ride->status == _status) - { - return res; - } - - if (ride->status == RIDE_STATUS_SIMULATING) - { - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - } - - // Fix #3183: Make sure we close the construction window so the ride finishes any editing code before opening - // otherwise vehicles get added to the ride incorrectly (such as to a ghost station) - rct_window* constructionWindow = window_find_by_number(WC_RIDE_CONSTRUCTION, _rideIndex); - if (constructionWindow != nullptr) - { - window_close(constructionWindow); - } - - if (_status == RIDE_STATUS_TESTING) - { - if (!ride->Test(_status, true)) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = gGameCommandErrorText; - return res; - } - } - else if (!ride->Open(true)) - { - res->Error = GameActions::Status::Unknown; - res->ErrorMessage = gGameCommandErrorText; - return res; - } - - ride->race_winner = SPRITE_INDEX_NULL; - ride->status = _status; - ride->current_issues = 0; - ride->last_issue_time = 0; - ride->GetMeasurement(); - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - window_invalidate_by_number(WC_RIDE, _rideIndex); - break; - } - default: - Guard::Assert(false, "Invalid status passed: %u", _status); - break; - } - auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); - windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); - - return res; - } -}; diff --git a/src/openrct2/actions/RideSetStatusAction.cpp b/src/openrct2/actions/RideSetStatusAction.cpp new file mode 100644 index 0000000000..25242653e8 --- /dev/null +++ b/src/openrct2/actions/RideSetStatusAction.cpp @@ -0,0 +1,227 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideSetStatusAction.h" + +#include "../Cheats.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Park.h" +#include "../world/Sprite.h" + +static rct_string_id _StatusErrorTitles[] = { + STR_CANT_CLOSE, + STR_CANT_OPEN, + STR_CANT_TEST, + STR_CANT_SIMULATE, +}; + +void RideSetStatusAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("status", _status); +} + +void RideSetStatusAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_status); +} + +GameActions::Result::Ptr RideSetStatusAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + res->Error = GameActions::Status::InvalidParameters; + res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; + res->ErrorMessage = STR_NONE; + return res; + } + + if (_status >= RIDE_STATUS_COUNT) + { + log_warning("Invalid ride status %u for ride %u", uint32_t(_status), uint32_t(_rideIndex)); + res->Error = GameActions::Status::InvalidParameters; + res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; + res->ErrorMessage = STR_NONE; + return res; + } + + res->ErrorTitle = _StatusErrorTitles[_status]; + + Formatter ft(res->ErrorMessageArgs.data()); + ft.Increment(6); + ride->FormatNameTo(ft); + if (_status != ride->status) + { + if (_status == RIDE_STATUS_SIMULATING && (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) + { + // Simulating will force clear the track, so make sure player can't cheat around a break down + res->Error = GameActions::Status::Disallowed; + res->ErrorMessage = STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING; + return res; + } + else if (_status == RIDE_STATUS_TESTING || _status == RIDE_STATUS_SIMULATING) + { + if (!ride->Test(_status, false)) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = gGameCommandErrorText; + return res; + } + } + else if (_status == RIDE_STATUS_OPEN) + { + if (!ride->Open(false)) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = gGameCommandErrorText; + return res; + } + } + } + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetStatusAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Expenditure = ExpenditureType::RideRunningCosts; + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + res->Error = GameActions::Status::InvalidParameters; + res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; + res->ErrorMessage = STR_NONE; + return res; + } + + res->ErrorTitle = _StatusErrorTitles[_status]; + + Formatter ft(res->ErrorMessageArgs.data()); + ft.Increment(6); + ride->FormatNameTo(ft); + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(res->Position) }; + } + + switch (_status) + { + case RIDE_STATUS_CLOSED: + if (ride->status == _status || ride->status == RIDE_STATUS_SIMULATING) + { + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) + { + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + } + } + + ride->status = RIDE_STATUS_CLOSED; + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; + ride->race_winner = SPRITE_INDEX_NULL; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + window_invalidate_by_number(WC_RIDE, _rideIndex); + break; + case RIDE_STATUS_SIMULATING: + { + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + + if (!ride->Test(_status, true)) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = gGameCommandErrorText; + return res; + } + + ride->status = _status; + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; + ride->race_winner = SPRITE_INDEX_NULL; + ride->current_issues = 0; + ride->last_issue_time = 0; + ride->GetMeasurement(); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + window_invalidate_by_number(WC_RIDE, _rideIndex); + break; + } + case RIDE_STATUS_TESTING: + case RIDE_STATUS_OPEN: + { + if (ride->status == _status) + { + return res; + } + + if (ride->status == RIDE_STATUS_SIMULATING) + { + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + } + + // Fix #3183: Make sure we close the construction window so the ride finishes any editing code before opening + // otherwise vehicles get added to the ride incorrectly (such as to a ghost station) + rct_window* constructionWindow = window_find_by_number(WC_RIDE_CONSTRUCTION, _rideIndex); + if (constructionWindow != nullptr) + { + window_close(constructionWindow); + } + + if (_status == RIDE_STATUS_TESTING) + { + if (!ride->Test(_status, true)) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = gGameCommandErrorText; + return res; + } + } + else if (!ride->Open(true)) + { + res->Error = GameActions::Status::Unknown; + res->ErrorMessage = gGameCommandErrorText; + return res; + } + + ride->race_winner = SPRITE_INDEX_NULL; + ride->status = _status; + ride->current_issues = 0; + ride->last_issue_time = 0; + ride->GetMeasurement(); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + window_invalidate_by_number(WC_RIDE, _rideIndex); + break; + } + default: + Guard::Assert(false, "Invalid status passed: %u", _status); + break; + } + auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager(); + windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST)); + + return res; +} diff --git a/src/openrct2/actions/RideSetStatusAction.h b/src/openrct2/actions/RideSetStatusAction.h new file mode 100644 index 0000000000..03bc54cd46 --- /dev/null +++ b/src/openrct2/actions/RideSetStatusAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(RideSetStatusAction, GAME_COMMAND_SET_RIDE_STATUS, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + uint8_t _status{ RIDE_STATUS_CLOSED }; + +public: + RideSetStatusAction() = default; + RideSetStatusAction(ride_id_t rideIndex, uint8_t status) + : _rideIndex(rideIndex) + , _status(status) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/RideSetVehicleAction.cpp b/src/openrct2/actions/RideSetVehicleAction.cpp new file mode 100644 index 0000000000..ce3ac10c52 --- /dev/null +++ b/src/openrct2/actions/RideSetVehicleAction.cpp @@ -0,0 +1,240 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "RideSetVehicleAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Research.h" +#include "../object/ObjectManager.h" +#include "../ride/Ride.h" +#include "../ride/RideData.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../util/Util.h" +#include "../world/Park.h" + +void RideSetVehicleAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("ride", _rideIndex); + visitor.Visit("type", _type); + visitor.Visit("value", _value); + visitor.Visit("colour", _colour); +} + +void RideSetVehicleAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_rideIndex) << DS_TAG(_type) << DS_TAG(_value) << DS_TAG(_colour); +} + +GameActions::Result::Ptr RideSetVehicleAction::Query() const +{ + if (_type >= RideSetVehicleType::Count) + { + log_warning("Invalid type. type = %d", _type); + } + auto errTitle = SetVehicleTypeErrorTitle[EnumValue(_type)]; + + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) + { + return std::make_unique( + GameActions::Status::Broken, errTitle, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); + } + + if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + { + return std::make_unique(GameActions::Status::NotClosed, errTitle, STR_MUST_BE_CLOSED_FIRST); + } + + switch (_type) + { + case RideSetVehicleType::NumTrains: + case RideSetVehicleType::NumCarsPerTrain: + break; + case RideSetVehicleType::RideEntry: + { + if (!ride_is_vehicle_type_valid(ride)) + { + log_error("Invalid vehicle type. type = %d", _value); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + auto rideEntry = get_ride_entry(_value); + if (rideEntry == nullptr) + { + log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + // Validate preset + vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list; + if (_colour >= presetList->count && _colour != 255 && _colour != 0) + { + log_error("Unknown vehicle colour preset. colour = %d", _colour); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + break; + } + + default: + log_error("Unknown vehicle command. type = %d", _type); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr RideSetVehicleAction::Execute() const +{ + auto errTitle = SetVehicleTypeErrorTitle[EnumValue(_type)]; + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + switch (_type) + { + case RideSetVehicleType::NumTrains: + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + ride->vehicle_change_timeout = 100; + + ride->proposed_num_vehicles = _value; + break; + case RideSetVehicleType::NumCarsPerTrain: + { + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + ride->vehicle_change_timeout = 100; + + invalidate_test_results(ride); + auto rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + auto clampValue = _value; + if (!gCheatsDisableTrainLengthLimit) + { + clampValue = std::clamp(clampValue, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train); + } + ride->proposed_num_cars_per_train = clampValue; + break; + } + case RideSetVehicleType::RideEntry: + { + ride_clear_for_construction(ride); + ride_remove_peeps(ride); + ride->vehicle_change_timeout = 100; + + invalidate_test_results(ride); + ride->subtype = _value; + auto rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + ride_set_vehicle_colours_to_random_preset(ride, _colour); + if (!gCheatsDisableTrainLengthLimit) + { + ride->proposed_num_cars_per_train = std::clamp( + ride->proposed_num_cars_per_train, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train); + } + break; + } + + default: + log_error("Unknown vehicle command. type = %d", _type); + return std::make_unique(GameActions::Status::InvalidParameters, errTitle); + } + + ride->num_circuits = 1; + ride->UpdateMaxVehicles(); + + auto res = std::make_unique(); + if (!ride->overall_view.isNull()) + { + auto location = ride->overall_view.ToTileCentre(); + res->Position = { location, tile_element_height(res->Position) }; + } + + auto intent = Intent(INTENT_ACTION_RIDE_PAINT_RESET_VEHICLE); + intent.putExtra(INTENT_EXTRA_RIDE_ID, _rideIndex); + context_broadcast_intent(&intent); + + gfx_invalidate_screen(); + return res; +} + +bool RideSetVehicleAction::ride_is_vehicle_type_valid(Ride* ride) const +{ + bool selectionShouldBeExpanded; + int32_t rideTypeIterator, rideTypeIteratorMax; + + if (gCheatsShowVehiclesFromOtherTrackTypes + && !( + ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) || ride->type == RIDE_TYPE_MAZE + || ride->type == RIDE_TYPE_MINI_GOLF)) + { + selectionShouldBeExpanded = true; + rideTypeIterator = 0; + rideTypeIteratorMax = RIDE_TYPE_COUNT - 1; + } + else + { + selectionShouldBeExpanded = false; + rideTypeIterator = ride->type; + rideTypeIteratorMax = ride->type; + } + + for (; rideTypeIterator <= rideTypeIteratorMax; rideTypeIterator++) + { + if (selectionShouldBeExpanded) + { + if (ride_type_has_flag(rideTypeIterator, RIDE_TYPE_FLAG_FLAT_RIDE)) + continue; + if (rideTypeIterator == RIDE_TYPE_MAZE || rideTypeIterator == RIDE_TYPE_MINI_GOLF) + continue; + } + + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + auto& rideEntries = objManager.GetAllRideEntries(rideTypeIterator); + for (auto rideEntryIndex : rideEntries) + { + if (rideEntryIndex == _value) + { + if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) + { + return false; + } + + return true; + } + } + } + + return false; +} diff --git a/src/openrct2/actions/RideSetVehicleAction.h b/src/openrct2/actions/RideSetVehicleAction.h new file mode 100644 index 0000000000..1bf36a0136 --- /dev/null +++ b/src/openrct2/actions/RideSetVehicleAction.h @@ -0,0 +1,57 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +enum class RideSetVehicleType : uint8_t +{ + NumTrains, + NumCarsPerTrain, + RideEntry, + Count, +}; + +DEFINE_GAME_ACTION(RideSetVehicleAction, GAME_COMMAND_SET_RIDE_VEHICLES, GameActions::Result) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + RideSetVehicleType _type{}; + uint8_t _value{}; + uint8_t _colour{}; + + constexpr static rct_string_id SetVehicleTypeErrorTitle[] = { STR_RIDE_SET_VEHICLE_SET_NUM_TRAINS_FAIL, + STR_RIDE_SET_VEHICLE_SET_NUM_CARS_PER_TRAIN_FAIL, + STR_RIDE_SET_VEHICLE_TYPE_FAIL }; + +public: + RideSetVehicleAction() = default; + RideSetVehicleAction(ride_id_t rideIndex, RideSetVehicleType type, uint8_t value, uint8_t colour = 0) + : _rideIndex(rideIndex) + , _type(type) + , _value(value) + , _colour(colour) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + bool ride_is_vehicle_type_valid(Ride * ride) const; +}; diff --git a/src/openrct2/actions/RideSetVehiclesAction.hpp b/src/openrct2/actions/RideSetVehiclesAction.hpp deleted file mode 100644 index 7bbd53e7c6..0000000000 --- a/src/openrct2/actions/RideSetVehiclesAction.hpp +++ /dev/null @@ -1,278 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Research.h" -#include "../object/ObjectManager.h" -#include "../ride/Ride.h" -#include "../ride/RideData.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../util/Util.h" -#include "../world/Park.h" -#include "GameAction.h" - -enum class RideSetVehicleType : uint8_t -{ - NumTrains, - NumCarsPerTrain, - RideEntry, - Count, -}; - -DEFINE_GAME_ACTION(RideSetVehicleAction, GAME_COMMAND_SET_RIDE_VEHICLES, GameActions::Result) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - RideSetVehicleType _type{}; - uint8_t _value{}; - uint8_t _colour{}; - - constexpr static rct_string_id SetVehicleTypeErrorTitle[] = { STR_RIDE_SET_VEHICLE_SET_NUM_TRAINS_FAIL, - STR_RIDE_SET_VEHICLE_SET_NUM_CARS_PER_TRAIN_FAIL, - STR_RIDE_SET_VEHICLE_TYPE_FAIL }; - -public: - RideSetVehicleAction() = default; - RideSetVehicleAction(ride_id_t rideIndex, RideSetVehicleType type, uint8_t value, uint8_t colour = 0) - : _rideIndex(rideIndex) - , _type(type) - , _value(value) - , _colour(colour) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("ride", _rideIndex); - visitor.Visit("type", _type); - visitor.Visit("value", _value); - visitor.Visit("colour", _colour); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_rideIndex) << DS_TAG(_type) << DS_TAG(_value) << DS_TAG(_colour); - } - - GameActions::Result::Ptr Query() const override - { - if (_type >= RideSetVehicleType::Count) - { - log_warning("Invalid type. type = %d", _type); - } - auto errTitle = SetVehicleTypeErrorTitle[EnumValue(_type)]; - - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) - { - return std::make_unique( - GameActions::Status::Broken, errTitle, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); - } - - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) - { - return std::make_unique(GameActions::Status::NotClosed, errTitle, STR_MUST_BE_CLOSED_FIRST); - } - - switch (_type) - { - case RideSetVehicleType::NumTrains: - case RideSetVehicleType::NumCarsPerTrain: - break; - case RideSetVehicleType::RideEntry: - { - if (!ride_is_vehicle_type_valid(ride)) - { - log_error("Invalid vehicle type. type = %d", _value); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - auto rideEntry = get_ride_entry(_value); - if (rideEntry == nullptr) - { - log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - // Validate preset - vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list; - if (_colour >= presetList->count && _colour != 255 && _colour != 0) - { - log_error("Unknown vehicle colour preset. colour = %d", _colour); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - break; - } - - default: - log_error("Unknown vehicle command. type = %d", _type); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto errTitle = SetVehicleTypeErrorTitle[EnumValue(_type)]; - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - switch (_type) - { - case RideSetVehicleType::NumTrains: - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - ride->vehicle_change_timeout = 100; - - ride->proposed_num_vehicles = _value; - break; - case RideSetVehicleType::NumCarsPerTrain: - { - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - ride->vehicle_change_timeout = 100; - - invalidate_test_results(ride); - auto rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - auto clampValue = _value; - if (!gCheatsDisableTrainLengthLimit) - { - clampValue = std::clamp(clampValue, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train); - } - ride->proposed_num_cars_per_train = clampValue; - break; - } - case RideSetVehicleType::RideEntry: - { - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - ride->vehicle_change_timeout = 100; - - invalidate_test_results(ride); - ride->subtype = _value; - auto rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - ride_set_vehicle_colours_to_random_preset(ride, _colour); - if (!gCheatsDisableTrainLengthLimit) - { - ride->proposed_num_cars_per_train = std::clamp( - ride->proposed_num_cars_per_train, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train); - } - break; - } - - default: - log_error("Unknown vehicle command. type = %d", _type); - return std::make_unique(GameActions::Status::InvalidParameters, errTitle); - } - - ride->num_circuits = 1; - ride->UpdateMaxVehicles(); - - auto res = std::make_unique(); - if (!ride->overall_view.isNull()) - { - auto location = ride->overall_view.ToTileCentre(); - res->Position = { location, tile_element_height(res->Position) }; - } - - auto intent = Intent(INTENT_ACTION_RIDE_PAINT_RESET_VEHICLE); - intent.putExtra(INTENT_EXTRA_RIDE_ID, _rideIndex); - context_broadcast_intent(&intent); - - gfx_invalidate_screen(); - return res; - } - -private: - bool ride_is_vehicle_type_valid(Ride * ride) const - { - bool selectionShouldBeExpanded; - int32_t rideTypeIterator, rideTypeIteratorMax; - - if (gCheatsShowVehiclesFromOtherTrackTypes - && !( - ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) || ride->type == RIDE_TYPE_MAZE - || ride->type == RIDE_TYPE_MINI_GOLF)) - { - selectionShouldBeExpanded = true; - rideTypeIterator = 0; - rideTypeIteratorMax = RIDE_TYPE_COUNT - 1; - } - else - { - selectionShouldBeExpanded = false; - rideTypeIterator = ride->type; - rideTypeIteratorMax = ride->type; - } - - for (; rideTypeIterator <= rideTypeIteratorMax; rideTypeIterator++) - { - if (selectionShouldBeExpanded) - { - if (ride_type_has_flag(rideTypeIterator, RIDE_TYPE_FLAG_FLAT_RIDE)) - continue; - if (rideTypeIterator == RIDE_TYPE_MAZE || rideTypeIterator == RIDE_TYPE_MINI_GOLF) - continue; - } - - auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); - auto& rideEntries = objManager.GetAllRideEntries(rideTypeIterator); - for (auto rideEntryIndex : rideEntries) - { - if (rideEntryIndex == _value) - { - if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) - { - return false; - } - - return true; - } - } - } - - return false; - } -}; diff --git a/src/openrct2/actions/ScenarioSetSettingAction.cpp b/src/openrct2/actions/ScenarioSetSettingAction.cpp new file mode 100644 index 0000000000..4ae585d2d4 --- /dev/null +++ b/src/openrct2/actions/ScenarioSetSettingAction.cpp @@ -0,0 +1,245 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ScenarioSetSettingAction.h" + +#include "../OpenRCT2.h" +#include "../interface/Window.h" +#include "../management/Finance.h" +#include "../peep/Peep.h" +#include "../util/Util.h" +#include "../world/Park.h" + +#include + +void ScenarioSetSettingAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_setting) << DS_TAG(_value); +} + +GameActions::Result::Ptr ScenarioSetSettingAction::Query() const +{ + if (_setting >= ScenarioSetSetting::Count) + { + log_error("Invalid setting: %u", _setting); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr ScenarioSetSettingAction::Execute() const +{ + switch (_setting) + { + case ScenarioSetSetting::NoMoney: + if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) + { + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_NO_MONEY_SCENARIO; + } + else + { + gParkFlags &= ~PARK_FLAGS_NO_MONEY_SCENARIO; + } + } + else + { + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_NO_MONEY; + } + else + { + gParkFlags &= ~PARK_FLAGS_NO_MONEY; + } + // Invalidate all windows that have anything to do with finance + window_invalidate_by_class(WC_RIDE); + window_invalidate_by_class(WC_PEEP); + window_invalidate_by_class(WC_PARK_INFORMATION); + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + window_invalidate_by_class(WC_TOP_TOOLBAR); + } + break; + case ScenarioSetSetting::InitialCash: + gInitialCash = std::clamp(_value, MONEY(0, 00), MONEY(1000000, 00)); + gCash = gInitialCash; + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + break; + case ScenarioSetSetting::InitialLoan: + gBankLoan = std::clamp(_value, MONEY(0, 00), MONEY(5000000, 00)); + gMaxBankLoan = std::max(gBankLoan, gMaxBankLoan); + window_invalidate_by_class(WC_FINANCES); + break; + case ScenarioSetSetting::MaximumLoanSize: + gMaxBankLoan = std::clamp(_value, MONEY(0, 00), MONEY(5000000, 00)); + gBankLoan = std::min(gBankLoan, gMaxBankLoan); + window_invalidate_by_class(WC_FINANCES); + break; + case ScenarioSetSetting::AnnualInterestRate: + gBankLoanInterestRate = std::clamp(_value, 0, 80); + window_invalidate_by_class(WC_FINANCES); + break; + case ScenarioSetSetting::ForbidMarketingCampaigns: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_FORBID_MARKETING_CAMPAIGN; + } + else + { + gParkFlags &= ~PARK_FLAGS_FORBID_MARKETING_CAMPAIGN; + } + break; + case ScenarioSetSetting::AverageCashPerGuest: + gGuestInitialCash = std::clamp(_value, MONEY(0, 00), MONEY(1000, 00)); + break; + case ScenarioSetSetting::GuestInitialHappiness: + gGuestInitialHappiness = std::clamp(_value, 40, 250); + break; + case ScenarioSetSetting::GuestInitialHunger: + gGuestInitialHunger = std::clamp(_value, 40, 250); + break; + case ScenarioSetSetting::GuestInitialThirst: + gGuestInitialThirst = std::clamp(_value, 40, 250); + break; + case ScenarioSetSetting::GuestsPreferLessIntenseRides: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_PREF_LESS_INTENSE_RIDES; + } + else + { + gParkFlags &= ~PARK_FLAGS_PREF_LESS_INTENSE_RIDES; + } + break; + case ScenarioSetSetting::GuestsPreferMoreIntenseRides: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_PREF_MORE_INTENSE_RIDES; + } + else + { + gParkFlags &= ~PARK_FLAGS_PREF_MORE_INTENSE_RIDES; + } + break; + case ScenarioSetSetting::CostToBuyLand: + gLandPrice = std::clamp(_value, MONEY(5, 00), MONEY(200, 00)); + break; + case ScenarioSetSetting::CostToBuyConstructionRights: + gConstructionRightsPrice = std::clamp(_value, MONEY(5, 00), MONEY(200, 00)); + break; + case ScenarioSetSetting::ParkChargeMethod: + if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) + { + if (_value == 0) + { + gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; + gParkEntranceFee = MONEY(0, 00); + } + else if (_value == 1) + { + gParkFlags &= ~PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; + gParkEntranceFee = MONEY(10, 00); + } + else + { + gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags |= PARK_FLAGS_UNLOCK_ALL_PRICES; + gParkEntranceFee = MONEY(10, 00); + } + } + else + { + if (_value == 0) + { + gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; + } + else if (_value == 1) + { + gParkFlags &= ~PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; + } + else + { + gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; + gParkFlags |= PARK_FLAGS_UNLOCK_ALL_PRICES; + } + window_invalidate_by_class(WC_PARK_INFORMATION); + window_invalidate_by_class(WC_RIDE); + } + break; + case ScenarioSetSetting::ParkChargeEntryFee: + gParkEntranceFee = std::clamp(_value, MONEY(0, 00), MAX_ENTRANCE_FEE); + window_invalidate_by_class(WC_PARK_INFORMATION); + break; + case ScenarioSetSetting::ForbidTreeRemoval: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_FORBID_TREE_REMOVAL; + } + else + { + gParkFlags &= ~PARK_FLAGS_FORBID_TREE_REMOVAL; + } + break; + case ScenarioSetSetting::ForbidLandscapeChanges: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_FORBID_LANDSCAPE_CHANGES; + } + else + { + gParkFlags &= ~PARK_FLAGS_FORBID_LANDSCAPE_CHANGES; + } + break; + case ScenarioSetSetting::ForbidHighConstruction: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; + } + else + { + gParkFlags &= ~PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; + } + break; + case ScenarioSetSetting::ParkRatingHigherDifficultyLevel: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_DIFFICULT_PARK_RATING; + } + else + { + gParkFlags &= ~PARK_FLAGS_DIFFICULT_PARK_RATING; + } + break; + case ScenarioSetSetting::GuestGenerationHigherDifficultyLevel: + if (_value != 0) + { + gParkFlags |= PARK_FLAGS_DIFFICULT_GUEST_GENERATION; + } + else + { + gParkFlags &= ~PARK_FLAGS_DIFFICULT_GUEST_GENERATION; + } + break; + default: + log_error("Invalid setting: %u", _setting); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + window_invalidate_by_class(WC_EDITOR_SCENARIO_OPTIONS); + return MakeResult(); +} diff --git a/src/openrct2/actions/ScenarioSetSettingAction.h b/src/openrct2/actions/ScenarioSetSettingAction.h new file mode 100644 index 0000000000..ea104258ec --- /dev/null +++ b/src/openrct2/actions/ScenarioSetSettingAction.h @@ -0,0 +1,62 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +enum class ScenarioSetSetting : uint8_t +{ + NoMoney, + InitialCash, + InitialLoan, + MaximumLoanSize, + AnnualInterestRate, + ForbidMarketingCampaigns, + AverageCashPerGuest, + GuestInitialHappiness, + GuestInitialHunger, + GuestInitialThirst, + GuestsPreferLessIntenseRides, + GuestsPreferMoreIntenseRides, + CostToBuyLand, + CostToBuyConstructionRights, + ParkChargeMethod, + ParkChargeEntryFee, + ForbidTreeRemoval, + ForbidLandscapeChanges, + ForbidHighConstruction, + ParkRatingHigherDifficultyLevel, + GuestGenerationHigherDifficultyLevel, + Count +}; + +DEFINE_GAME_ACTION(ScenarioSetSettingAction, GAME_COMMAND_EDIT_SCENARIO_OPTIONS, GameActions::Result) +{ +private: + ScenarioSetSetting _setting{ ScenarioSetSetting::Count }; + uint32_t _value{}; + +public: + ScenarioSetSettingAction() = default; + ScenarioSetSettingAction(ScenarioSetSetting setting, uint32_t value) + : _setting(setting) + , _value(value) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/ScenarioSetSettingAction.hpp b/src/openrct2/actions/ScenarioSetSettingAction.hpp deleted file mode 100644 index 132a74dc20..0000000000 --- a/src/openrct2/actions/ScenarioSetSettingAction.hpp +++ /dev/null @@ -1,293 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../OpenRCT2.h" -#include "../interface/Window.h" -#include "../management/Finance.h" -#include "../peep/Peep.h" -#include "../util/Util.h" -#include "../world/Park.h" -#include "GameAction.h" - -#include - -enum class ScenarioSetSetting : uint8_t -{ - NoMoney, - InitialCash, - InitialLoan, - MaximumLoanSize, - AnnualInterestRate, - ForbidMarketingCampaigns, - AverageCashPerGuest, - GuestInitialHappiness, - GuestInitialHunger, - GuestInitialThirst, - GuestsPreferLessIntenseRides, - GuestsPreferMoreIntenseRides, - CostToBuyLand, - CostToBuyConstructionRights, - ParkChargeMethod, - ParkChargeEntryFee, - ForbidTreeRemoval, - ForbidLandscapeChanges, - ForbidHighConstruction, - ParkRatingHigherDifficultyLevel, - GuestGenerationHigherDifficultyLevel, - Count -}; - -DEFINE_GAME_ACTION(ScenarioSetSettingAction, GAME_COMMAND_EDIT_SCENARIO_OPTIONS, GameActions::Result) -{ -private: - ScenarioSetSetting _setting{ ScenarioSetSetting::Count }; - uint32_t _value{}; - -public: - ScenarioSetSettingAction() = default; - ScenarioSetSettingAction(ScenarioSetSetting setting, uint32_t value) - : _setting(setting) - , _value(value) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_setting) << DS_TAG(_value); - } - - GameActions::Result::Ptr Query() const override - { - if (_setting >= ScenarioSetSetting::Count) - { - log_error("Invalid setting: %u", _setting); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - switch (_setting) - { - case ScenarioSetSetting::NoMoney: - if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) - { - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_NO_MONEY_SCENARIO; - } - else - { - gParkFlags &= ~PARK_FLAGS_NO_MONEY_SCENARIO; - } - } - else - { - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_NO_MONEY; - } - else - { - gParkFlags &= ~PARK_FLAGS_NO_MONEY; - } - // Invalidate all windows that have anything to do with finance - window_invalidate_by_class(WC_RIDE); - window_invalidate_by_class(WC_PEEP); - window_invalidate_by_class(WC_PARK_INFORMATION); - window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - window_invalidate_by_class(WC_TOP_TOOLBAR); - } - break; - case ScenarioSetSetting::InitialCash: - gInitialCash = std::clamp(_value, MONEY(0, 00), MONEY(1000000, 00)); - gCash = gInitialCash; - window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - break; - case ScenarioSetSetting::InitialLoan: - gBankLoan = std::clamp(_value, MONEY(0, 00), MONEY(5000000, 00)); - gMaxBankLoan = std::max(gBankLoan, gMaxBankLoan); - window_invalidate_by_class(WC_FINANCES); - break; - case ScenarioSetSetting::MaximumLoanSize: - gMaxBankLoan = std::clamp(_value, MONEY(0, 00), MONEY(5000000, 00)); - gBankLoan = std::min(gBankLoan, gMaxBankLoan); - window_invalidate_by_class(WC_FINANCES); - break; - case ScenarioSetSetting::AnnualInterestRate: - gBankLoanInterestRate = std::clamp(_value, 0, 80); - window_invalidate_by_class(WC_FINANCES); - break; - case ScenarioSetSetting::ForbidMarketingCampaigns: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_FORBID_MARKETING_CAMPAIGN; - } - else - { - gParkFlags &= ~PARK_FLAGS_FORBID_MARKETING_CAMPAIGN; - } - break; - case ScenarioSetSetting::AverageCashPerGuest: - gGuestInitialCash = std::clamp(_value, MONEY(0, 00), MONEY(1000, 00)); - break; - case ScenarioSetSetting::GuestInitialHappiness: - gGuestInitialHappiness = std::clamp(_value, 40, 250); - break; - case ScenarioSetSetting::GuestInitialHunger: - gGuestInitialHunger = std::clamp(_value, 40, 250); - break; - case ScenarioSetSetting::GuestInitialThirst: - gGuestInitialThirst = std::clamp(_value, 40, 250); - break; - case ScenarioSetSetting::GuestsPreferLessIntenseRides: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_PREF_LESS_INTENSE_RIDES; - } - else - { - gParkFlags &= ~PARK_FLAGS_PREF_LESS_INTENSE_RIDES; - } - break; - case ScenarioSetSetting::GuestsPreferMoreIntenseRides: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_PREF_MORE_INTENSE_RIDES; - } - else - { - gParkFlags &= ~PARK_FLAGS_PREF_MORE_INTENSE_RIDES; - } - break; - case ScenarioSetSetting::CostToBuyLand: - gLandPrice = std::clamp(_value, MONEY(5, 00), MONEY(200, 00)); - break; - case ScenarioSetSetting::CostToBuyConstructionRights: - gConstructionRightsPrice = std::clamp(_value, MONEY(5, 00), MONEY(200, 00)); - break; - case ScenarioSetSetting::ParkChargeMethod: - if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) - { - if (_value == 0) - { - gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; - gParkEntranceFee = MONEY(0, 00); - } - else if (_value == 1) - { - gParkFlags &= ~PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; - gParkEntranceFee = MONEY(10, 00); - } - else - { - gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags |= PARK_FLAGS_UNLOCK_ALL_PRICES; - gParkEntranceFee = MONEY(10, 00); - } - } - else - { - if (_value == 0) - { - gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; - } - else if (_value == 1) - { - gParkFlags &= ~PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags &= ~PARK_FLAGS_UNLOCK_ALL_PRICES; - } - else - { - gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY; - gParkFlags |= PARK_FLAGS_UNLOCK_ALL_PRICES; - } - window_invalidate_by_class(WC_PARK_INFORMATION); - window_invalidate_by_class(WC_RIDE); - } - break; - case ScenarioSetSetting::ParkChargeEntryFee: - gParkEntranceFee = std::clamp(_value, MONEY(0, 00), MAX_ENTRANCE_FEE); - window_invalidate_by_class(WC_PARK_INFORMATION); - break; - case ScenarioSetSetting::ForbidTreeRemoval: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_FORBID_TREE_REMOVAL; - } - else - { - gParkFlags &= ~PARK_FLAGS_FORBID_TREE_REMOVAL; - } - break; - case ScenarioSetSetting::ForbidLandscapeChanges: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_FORBID_LANDSCAPE_CHANGES; - } - else - { - gParkFlags &= ~PARK_FLAGS_FORBID_LANDSCAPE_CHANGES; - } - break; - case ScenarioSetSetting::ForbidHighConstruction: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; - } - else - { - gParkFlags &= ~PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; - } - break; - case ScenarioSetSetting::ParkRatingHigherDifficultyLevel: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_DIFFICULT_PARK_RATING; - } - else - { - gParkFlags &= ~PARK_FLAGS_DIFFICULT_PARK_RATING; - } - break; - case ScenarioSetSetting::GuestGenerationHigherDifficultyLevel: - if (_value != 0) - { - gParkFlags |= PARK_FLAGS_DIFFICULT_GUEST_GENERATION; - } - else - { - gParkFlags &= ~PARK_FLAGS_DIFFICULT_GUEST_GENERATION; - } - break; - default: - log_error("Invalid setting: %u", _setting); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - break; - } - window_invalidate_by_class(WC_EDITOR_SCENARIO_OPTIONS); - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/SetCheatAction.cpp b/src/openrct2/actions/SetCheatAction.cpp new file mode 100644 index 0000000000..761116fc57 --- /dev/null +++ b/src/openrct2/actions/SetCheatAction.cpp @@ -0,0 +1,732 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "SetCheatAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../GameState.h" +#include "../config/Config.h" +#include "../core/String.hpp" +#include "../drawing/Drawing.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../network/network.h" +#include "../ride/Ride.h" +#include "../scenario/Scenario.h" +#include "../ui/UiContext.h" +#include "../util/Util.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "../world/Climate.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Map.h" +#include "../world/Park.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" +#include "ParkSetLoanAction.h" +#include "ParkSetParameterAction.h" + +using ParametersRange = std::pair, std::pair>; + +void SetCheatAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("type", _cheatType); + visitor.Visit("param1", _param1); + visitor.Visit("param2", _param2); +} + +void SetCheatAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_cheatType) << DS_TAG(_param1) << DS_TAG(_param2); +} + +GameActions::Result::Ptr SetCheatAction::Query() const +{ + if (static_cast(_cheatType) >= static_cast(CheatType::Count)) + { + MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + ParametersRange validRange = GetParameterRange(static_cast(_cheatType.id)); + + if (_param1 < validRange.first.first || _param1 > validRange.first.second) + { + MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + if (_param2 < validRange.second.first || _param2 > validRange.second.second) + { + MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr SetCheatAction::Execute() const +{ + switch (static_cast(_cheatType.id)) + { + case CheatType::SandboxMode: + gCheatsSandboxMode = _param1 != 0; + window_invalidate_by_class(WC_MAP); + window_invalidate_by_class(WC_FOOTPATH); + break; + case CheatType::DisableClearanceChecks: + gCheatsDisableClearanceChecks = _param1 != 0; + // Required to update the clearance checks overlay on the Cheats button. + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case CheatType::DisableSupportLimits: + gCheatsDisableSupportLimits = _param1 != 0; + break; + case CheatType::ShowAllOperatingModes: + gCheatsShowAllOperatingModes = _param1 != 0; + break; + case CheatType::ShowVehiclesFromOtherTrackTypes: + gCheatsShowVehiclesFromOtherTrackTypes = _param1 != 0; + break; + case CheatType::FastLiftHill: + gCheatsFastLiftHill = _param1 != 0; + break; + case CheatType::DisableBrakesFailure: + gCheatsDisableBrakesFailure = _param1 != 0; + break; + case CheatType::DisableAllBreakdowns: + gCheatsDisableAllBreakdowns = _param1 != 0; + break; + case CheatType::DisableTrainLengthLimit: + gCheatsDisableTrainLengthLimit = _param1 != 0; + break; + case CheatType::EnableChainLiftOnAllTrack: + gCheatsEnableChainLiftOnAllTrack = _param1 != 0; + break; + case CheatType::BuildInPauseMode: + gCheatsBuildInPauseMode = _param1 != 0; + break; + case CheatType::IgnoreRideIntensity: + gCheatsIgnoreRideIntensity = _param1 != 0; + break; + case CheatType::DisableVandalism: + gCheatsDisableVandalism = _param1 != 0; + break; + case CheatType::DisableLittering: + gCheatsDisableLittering = _param1 != 0; + break; + case CheatType::NoMoney: + SetScenarioNoMoney(_param1 != 0); + break; + case CheatType::AddMoney: + AddMoney(_param1); + break; + case CheatType::SetMoney: + SetMoney(_param1); + break; + case CheatType::ClearLoan: + ClearLoan(); + break; + case CheatType::SetGuestParameter: + SetGuestParameter(_param1, _param2); + break; + case CheatType::GenerateGuests: + GenerateGuests(_param1); + break; + case CheatType::RemoveAllGuests: + RemoveAllGuests(); + break; + case CheatType::GiveAllGuests: + GiveObjectToGuests(_param1); + break; + case CheatType::SetGrassLength: + SetGrassLength(_param1); + break; + case CheatType::WaterPlants: + WaterPlants(); + break; + case CheatType::FixVandalism: + FixVandalism(); + break; + case CheatType::RemoveLitter: + RemoveLitter(); + break; + case CheatType::DisablePlantAging: + gCheatsDisablePlantAging = _param1 != 0; + break; + case CheatType::SetStaffSpeed: + SetStaffSpeed(_param1); + break; + case CheatType::RenewRides: + RenewRides(); + break; + case CheatType::MakeDestructible: + MakeDestructible(); + break; + case CheatType::FixRides: + FixBrokenRides(); + break; + case CheatType::ResetCrashStatus: + ResetRideCrashStatus(); + break; + case CheatType::TenMinuteInspections: + Set10MinuteInspection(); + break; + case CheatType::WinScenario: + scenario_success(); + break; + case CheatType::ForceWeather: + // Todo - make sure this is safe + climate_force_weather(WeatherType{ static_cast(_param1) }); + break; + case CheatType::FreezeWeather: + gCheatsFreezeWeather = _param1 != 0; + break; + case CheatType::NeverEndingMarketing: + gCheatsNeverendingMarketing = _param1 != 0; + break; + case CheatType::OpenClosePark: + ParkSetOpen(!park_is_open()); + break; + case CheatType::HaveFun: + gScenarioObjective.Type = OBJECTIVE_HAVE_FUN; + break; + case CheatType::SetForcedParkRating: + set_forced_park_rating(_param1); + break; + case CheatType::AllowArbitraryRideTypeChanges: + gCheatsAllowArbitraryRideTypeChanges = _param1 != 0; + window_invalidate_by_class(WC_RIDE); + break; + case CheatType::OwnAllLand: + OwnAllLand(); + break; + case CheatType::DisableRideValueAging: + gCheatsDisableRideValueAging = _param1 != 0; + break; + case CheatType::IgnoreResearchStatus: + gCheatsIgnoreResearchStatus = _param1 != 0; + break; + case CheatType::EnableAllDrawableTrackPieces: + gCheatsEnableAllDrawableTrackPieces = _param1 != 0; + break; + case CheatType::CreateDucks: + CreateDucks(_param1); + break; + case CheatType::RemoveDucks: + duck_remove_all(); + break; + case CheatType::AllowTrackPlaceInvalidHeights: + gCheatsAllowTrackPlaceInvalidHeights = _param1 != 0; + break; + default: + { + log_error("Unabled cheat: %d", _cheatType.id); + MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + break; + } + + if (network_get_mode() == NETWORK_MODE_NONE) + { + config_save_default(); + } + + window_invalidate_by_class(WC_CHEATS); + return MakeResult(); +} + +ParametersRange SetCheatAction::GetParameterRange(CheatType cheatType) const +{ + switch (static_cast(_cheatType.id)) + { + case CheatType::SandboxMode: + [[fallthrough]]; + case CheatType::DisableClearanceChecks: + [[fallthrough]]; + case CheatType::DisableSupportLimits: + [[fallthrough]]; + case CheatType::ShowAllOperatingModes: + [[fallthrough]]; + case CheatType::ShowVehiclesFromOtherTrackTypes: + [[fallthrough]]; + case CheatType::FastLiftHill: + [[fallthrough]]; + case CheatType::DisableBrakesFailure: + [[fallthrough]]; + case CheatType::DisableAllBreakdowns: + [[fallthrough]]; + case CheatType::DisableTrainLengthLimit: + [[fallthrough]]; + case CheatType::EnableChainLiftOnAllTrack: + [[fallthrough]]; + case CheatType::BuildInPauseMode: + [[fallthrough]]; + case CheatType::IgnoreRideIntensity: + [[fallthrough]]; + case CheatType::DisableVandalism: + [[fallthrough]]; + case CheatType::DisableLittering: + [[fallthrough]]; + case CheatType::NoMoney: + [[fallthrough]]; + case CheatType::DisablePlantAging: + [[fallthrough]]; + case CheatType::FreezeWeather: + [[fallthrough]]; + case CheatType::NeverEndingMarketing: + [[fallthrough]]; + case CheatType::AllowArbitraryRideTypeChanges: + [[fallthrough]]; + case CheatType::DisableRideValueAging: + [[fallthrough]]; + case CheatType::IgnoreResearchStatus: + [[fallthrough]]; + case CheatType::EnableAllDrawableTrackPieces: + [[fallthrough]]; + case CheatType::OpenClosePark: + return { { 0, 1 }, { 0, 0 } }; + case CheatType::AddMoney: + [[fallthrough]]; + case CheatType::SetMoney: + return { { std::numeric_limits::min(), std::numeric_limits::max() }, { 0, 0 } }; + case CheatType::SetGuestParameter: + switch (_param1) + { + case GUEST_PARAMETER_HAPPINESS: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, + { 0, PEEP_MAX_HAPPINESS } }; + case GUEST_PARAMETER_ENERGY: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, + { PEEP_MIN_ENERGY, PEEP_MAX_ENERGY } }; + case GUEST_PARAMETER_HUNGER: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, PEEP_MAX_HUNGER } }; + case GUEST_PARAMETER_THIRST: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, PEEP_MAX_THIRST } }; + case GUEST_PARAMETER_NAUSEA: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, PEEP_MAX_NAUSEA } }; + case GUEST_PARAMETER_NAUSEA_TOLERANCE: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, + { EnumValue(PeepNauseaTolerance::None), EnumValue(PeepNauseaTolerance::High) } }; + case GUEST_PARAMETER_TOILET: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, PEEP_MAX_TOILET } }; + case GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY: + return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, 255 } }; + default: + return { { 0, 0 }, { 0, 0 } }; + } + case CheatType::GenerateGuests: + return { { 1, 10000 }, { 0, 0 } }; + case CheatType::GiveAllGuests: + return { { OBJECT_MONEY, OBJECT_UMBRELLA }, { 0, 0 } }; + case CheatType::SetGrassLength: + return { { 0, 7 }, { 0, 0 } }; + case CheatType::SetStaffSpeed: + return { { 0, 255 }, { 0, 0 } }; + case CheatType::ForceWeather: + return { { 0, EnumValue(WeatherType::Count) - 1 }, { 0, 0 } }; + case CheatType::SetForcedParkRating: + return { { 0, 999 }, { 0, 0 } }; + case CheatType::CreateDucks: + return { { 0, 100 }, { 0, 0 } }; + default: + return { { 0, 0 }, { 0, 0 } }; + } +} + +void SetCheatAction::SetGrassLength(int32_t length) const +{ + for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) + { + for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) + { + auto surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); + if (surfaceElement == nullptr) + continue; + + if (surfaceElement != nullptr && (surfaceElement->GetOwnership() & OWNERSHIP_OWNED) + && surfaceElement->GetWaterHeight() == 0 && surfaceElement->CanGrassGrow()) + { + surfaceElement->SetGrassLength(length); + } + } + } + + gfx_invalidate_screen(); +} + +void SetCheatAction::WaterPlants() const +{ + tile_element_iterator it; + + tile_element_iterator_begin(&it); + do + { + if (it.element->GetType() == TILE_ELEMENT_TYPE_SMALL_SCENERY) + { + it.element->AsSmallScenery()->SetAge(0); + } + } while (tile_element_iterator_next(&it)); + + gfx_invalidate_screen(); +} + +void SetCheatAction::FixVandalism() const +{ + tile_element_iterator it; + + tile_element_iterator_begin(&it); + do + { + if (it.element->GetType() != TILE_ELEMENT_TYPE_PATH) + continue; + + if (!(it.element)->AsPath()->HasAddition()) + continue; + + it.element->AsPath()->SetIsBroken(false); + } while (tile_element_iterator_next(&it)); + + gfx_invalidate_screen(); +} + +void SetCheatAction::RemoveLitter() const +{ + for (auto litter : EntityList(EntityListId::Litter)) + { + sprite_remove(litter); + } + + tile_element_iterator it; + rct_scenery_entry* sceneryEntry; + + tile_element_iterator_begin(&it); + do + { + if (it.element->GetType() != TILE_ELEMENT_TYPE_PATH) + continue; + + if (!(it.element)->AsPath()->HasAddition()) + continue; + + sceneryEntry = it.element->AsPath()->GetAdditionEntry(); + if (sceneryEntry->path_bit.flags & PATH_BIT_FLAG_IS_BIN) + it.element->AsPath()->SetAdditionStatus(0xFF); + + } while (tile_element_iterator_next(&it)); + + gfx_invalidate_screen(); +} + +void SetCheatAction::FixBrokenRides() const +{ + for (auto& ride : GetRideManager()) + { + if ((ride.mechanic_status != RIDE_MECHANIC_STATUS_FIXING) + && (ride.lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN))) + { + auto mechanic = ride_get_assigned_mechanic(&ride); + if (mechanic != nullptr) + { + mechanic->RemoveFromRide(); + } + + ride_fix_breakdown(&ride, 0); + ride.window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + } + } +} + +void SetCheatAction::RenewRides() const +{ + for (auto& ride : GetRideManager()) + { + ride.Renew(); + } + window_invalidate_by_class(WC_RIDE); +} + +void SetCheatAction::MakeDestructible() const +{ + for (auto& ride : GetRideManager()) + { + ride.lifecycle_flags &= ~RIDE_LIFECYCLE_INDESTRUCTIBLE; + ride.lifecycle_flags &= ~RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK; + } + window_invalidate_by_class(WC_RIDE); +} + +void SetCheatAction::ResetRideCrashStatus() const +{ + for (auto& ride : GetRideManager()) + { + // Reset crash status and history + ride.lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; + ride.last_crash_type = RIDE_CRASH_TYPE_NONE; + } + window_invalidate_by_class(WC_RIDE); +} + +void SetCheatAction::Set10MinuteInspection() const +{ + for (auto& ride : GetRideManager()) + { + // Set inspection interval to 10 minutes + ride.inspection_interval = RIDE_INSPECTION_EVERY_10_MINUTES; + } + window_invalidate_by_class(WC_RIDE); +} + +void SetCheatAction::SetScenarioNoMoney(bool enabled) const +{ + if (enabled) + { + gParkFlags |= PARK_FLAGS_NO_MONEY; + } + else + { + gParkFlags &= ~PARK_FLAGS_NO_MONEY; + } + // Invalidate all windows that have anything to do with finance + window_invalidate_by_class(WC_RIDE); + window_invalidate_by_class(WC_PEEP); + window_invalidate_by_class(WC_PARK_INFORMATION); + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + window_invalidate_by_class(WC_TOP_TOOLBAR); + window_invalidate_by_class(WC_CHEATS); +} + +void SetCheatAction::SetMoney(money32 amount) const +{ + gCash = amount; + + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); +} + +void SetCheatAction::AddMoney(money32 amount) const +{ + gCash = add_clamp_money32(gCash, amount); + + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); +} + +void SetCheatAction::ClearLoan() const +{ + // First give money + AddMoney(gBankLoan); + + // Then pay the loan + auto gameAction = ParkSetLoanAction(MONEY(0, 00)); + GameActions::ExecuteNested(&gameAction); +} + +void SetCheatAction::GenerateGuests(int32_t count) const +{ + auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); + for (int32_t i = 0; i < count; i++) + { + park.GenerateGuest(); + } + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); +} + +void SetCheatAction::SetGuestParameter(int32_t parameter, int32_t value) const +{ + for (auto peep : EntityList(EntityListId::Peep)) + { + switch (parameter) + { + case GUEST_PARAMETER_HAPPINESS: + peep->Happiness = value; + peep->HappinessTarget = value; + // Clear the 'red-faced with anger' status if we're making the guest happy + if (value > 0) + { + peep->PeepFlags &= ~PEEP_FLAGS_ANGRY; + peep->Angriness = 0; + } + break; + case GUEST_PARAMETER_ENERGY: + peep->Energy = value; + peep->EnergyTarget = value; + break; + case GUEST_PARAMETER_HUNGER: + peep->Hunger = value; + break; + case GUEST_PARAMETER_THIRST: + peep->Thirst = value; + break; + case GUEST_PARAMETER_NAUSEA: + peep->Nausea = value; + peep->NauseaTarget = value; + break; + case GUEST_PARAMETER_NAUSEA_TOLERANCE: + peep->NauseaTolerance = static_cast(value); + break; + case GUEST_PARAMETER_TOILET: + peep->Toilet = value; + break; + case GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY: + peep->Intensity = IntensityRange(value, 15); + break; + } + peep->UpdateSpriteType(); + } +} + +void SetCheatAction::GiveObjectToGuests(int32_t object) const +{ + for (auto peep : EntityList(EntityListId::Peep)) + { + switch (object) + { + case OBJECT_MONEY: + peep->CashInPocket = MONEY(1000, 00); + break; + case OBJECT_PARK_MAP: + peep->GiveItem(ShopItem::Map); + break; + case OBJECT_BALLOON: + peep->GiveItem(ShopItem::Balloon); + peep->BalloonColour = scenario_rand_max(COLOUR_COUNT - 1); + peep->UpdateSpriteType(); + break; + case OBJECT_UMBRELLA: + peep->GiveItem(ShopItem::Umbrella); + peep->UmbrellaColour = scenario_rand_max(COLOUR_COUNT - 1); + peep->UpdateSpriteType(); + break; + } + } + window_invalidate_by_class(WC_PEEP); +} + +void SetCheatAction::RemoveAllGuests() const +{ + for (auto& ride : GetRideManager()) + { + ride.num_riders = 0; + + for (size_t stationIndex = 0; stationIndex < MAX_STATIONS; stationIndex++) + { + ride.stations[stationIndex].QueueLength = 0; + ride.stations[stationIndex].LastPeepInQueue = SPRITE_INDEX_NULL; + } + + for (auto trainIndex : ride.vehicles) + { + for (Vehicle* vehicle = TryGetEntity(trainIndex); vehicle != nullptr; + vehicle = TryGetEntity(vehicle->next_vehicle_on_train)) + { + for (auto& peepInTrainIndex : vehicle->peep) + { + auto peep = TryGetEntity(peepInTrainIndex); + if (peep != nullptr) + { + vehicle->mass -= peep->Mass; + } + peepInTrainIndex = SPRITE_INDEX_NULL; + } + + vehicle->num_peeps = 0; + vehicle->next_free_seat = 0; + } + } + } + + // Do not use the FOR_ALL_PEEPS macro for this as next sprite index + // will be fetched on a deleted peep. + for (auto peep : EntityList(EntityListId::Peep)) + { + if (peep->AssignedPeepType == PeepType::Guest) + { + peep->Remove(); + } + } + + window_invalidate_by_class(WC_RIDE); + gfx_invalidate_screen(); +} + +void SetCheatAction::SetStaffSpeed(uint8_t value) const +{ + for (auto peep : EntityList(EntityListId::Peep)) + { + peep->Energy = value; + peep->EnergyTarget = value; + } +} + +void SetCheatAction::OwnAllLand() const +{ + const int32_t min = 32; + const int32_t max = gMapSizeUnits - 32; + + for (CoordsXY coords = { min, min }; coords.y <= max; coords.y += COORDS_XY_STEP) + { + for (coords.x = min; coords.x <= max; coords.x += COORDS_XY_STEP) + { + auto* surfaceElement = map_get_surface_element_at(coords); + if (surfaceElement == nullptr) + continue; + + // Ignore already owned tiles. + if (surfaceElement->GetOwnership() & OWNERSHIP_OWNED) + continue; + + int32_t baseZ = surfaceElement->GetBaseZ(); + int32_t destOwnership = check_max_allowable_land_rights_for_tile({ coords, baseZ }); + + // only own tiles that were not set to 0 + if (destOwnership != OWNERSHIP_UNOWNED) + { + surfaceElement->SetOwnership(destOwnership); + update_park_fences_around_tile(coords); + map_invalidate_tile({ coords, baseZ, baseZ + 16 }); + } + } + } + + // Completely unown peep spawn points + for (const auto& spawn : gPeepSpawns) + { + auto* surfaceElement = map_get_surface_element_at(spawn); + if (surfaceElement != nullptr) + { + surfaceElement->SetOwnership(OWNERSHIP_UNOWNED); + update_park_fences_around_tile(spawn); + uint16_t baseZ = surfaceElement->GetBaseZ(); + map_invalidate_tile({ spawn, baseZ, baseZ + 16 }); + } + } + + map_count_remaining_land_rights(); +} + +void SetCheatAction::ParkSetOpen(bool isOpen) const +{ + auto parkSetParameter = ParkSetParameterAction(isOpen ? ParkParameter::Open : ParkParameter::Close); + GameActions::ExecuteNested(&parkSetParameter); +} + +void SetCheatAction::CreateDucks(int count) const +{ + for (int i = 0; i < count; i++) + { + // 100 attempts at finding some water to create a few ducks at + for (int32_t attempts = 0; attempts < 100; attempts++) + { + if (scenario_create_ducks()) + break; + } + } +} diff --git a/src/openrct2/actions/SetCheatAction.h b/src/openrct2/actions/SetCheatAction.h new file mode 100644 index 0000000000..7b9e7a3614 --- /dev/null +++ b/src/openrct2/actions/SetCheatAction.h @@ -0,0 +1,66 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(SetCheatAction, GAME_COMMAND_CHEAT, GameActions::Result) +{ + using ParametersRange = std::pair, std::pair>; + +private: + NetworkCheatType_t _cheatType{ EnumValue(CheatType::Count) }; + int32_t _param1{}; + int32_t _param2{}; + +public: + SetCheatAction() = default; + SetCheatAction(CheatType cheatType, int32_t param1 = 0, int32_t param2 = 0) + : _cheatType(static_cast(cheatType)) + , _param1(param1) + , _param2(param2) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + ParametersRange GetParameterRange(CheatType cheatType) const; + void SetGrassLength(int32_t length) const; + void WaterPlants() const; + void FixVandalism() const; + void RemoveLitter() const; + void FixBrokenRides() const; + void RenewRides() const; + void MakeDestructible() const; + void ResetRideCrashStatus() const; + void Set10MinuteInspection() const; + void SetScenarioNoMoney(bool enabled) const; + void SetMoney(money32 amount) const; + void AddMoney(money32 amount) const; + void ClearLoan() const; + void GenerateGuests(int32_t count) const; + void SetGuestParameter(int32_t parameter, int32_t value) const; + void GiveObjectToGuests(int32_t object) const; + void RemoveAllGuests() const; + void SetStaffSpeed(uint8_t value) const; + void OwnAllLand() const; + void ParkSetOpen(bool isOpen) const; + void CreateDucks(int count) const; +}; diff --git a/src/openrct2/actions/SetCheatAction.hpp b/src/openrct2/actions/SetCheatAction.hpp deleted file mode 100644 index f3d7b8a9fa..0000000000 --- a/src/openrct2/actions/SetCheatAction.hpp +++ /dev/null @@ -1,760 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../Context.h" -#include "../GameState.h" -#include "../config/Config.h" -#include "../core/String.hpp" -#include "../drawing/Drawing.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../network/network.h" -#include "../ride/Ride.h" -#include "../scenario/Scenario.h" -#include "../ui/UiContext.h" -#include "../util/Util.h" -#include "../windows/Intent.h" -#include "../world/Banner.h" -#include "../world/Climate.h" -#include "../world/Footpath.h" -#include "../world/Location.hpp" -#include "../world/Map.h" -#include "../world/Park.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "GameAction.h" -#include "ParkSetLoanAction.hpp" -#include "ParkSetParameterAction.hpp" - -DEFINE_GAME_ACTION(SetCheatAction, GAME_COMMAND_CHEAT, GameActions::Result) -{ - using ParametersRange = std::pair, std::pair>; - -private: - NetworkCheatType_t _cheatType{ EnumValue(CheatType::Count) }; - int32_t _param1{}; - int32_t _param2{}; - -public: - SetCheatAction() = default; - SetCheatAction(CheatType cheatType, int32_t param1 = 0, int32_t param2 = 0) - : _cheatType(static_cast(cheatType)) - , _param1(param1) - , _param2(param2) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("type", _cheatType); - visitor.Visit("param1", _param1); - visitor.Visit("param2", _param2); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_cheatType) << DS_TAG(_param1) << DS_TAG(_param2); - } - - GameActions::Result::Ptr Query() const override - { - if (static_cast(_cheatType) >= static_cast(CheatType::Count)) - { - MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - ParametersRange validRange = GetParameterRange(static_cast(_cheatType.id)); - - if (_param1 < validRange.first.first || _param1 > validRange.first.second) - { - MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - if (_param2 < validRange.second.first || _param2 > validRange.second.second) - { - MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - switch (static_cast(_cheatType.id)) - { - case CheatType::SandboxMode: - gCheatsSandboxMode = _param1 != 0; - window_invalidate_by_class(WC_MAP); - window_invalidate_by_class(WC_FOOTPATH); - break; - case CheatType::DisableClearanceChecks: - gCheatsDisableClearanceChecks = _param1 != 0; - // Required to update the clearance checks overlay on the Cheats button. - window_invalidate_by_class(WC_TOP_TOOLBAR); - break; - case CheatType::DisableSupportLimits: - gCheatsDisableSupportLimits = _param1 != 0; - break; - case CheatType::ShowAllOperatingModes: - gCheatsShowAllOperatingModes = _param1 != 0; - break; - case CheatType::ShowVehiclesFromOtherTrackTypes: - gCheatsShowVehiclesFromOtherTrackTypes = _param1 != 0; - break; - case CheatType::FastLiftHill: - gCheatsFastLiftHill = _param1 != 0; - break; - case CheatType::DisableBrakesFailure: - gCheatsDisableBrakesFailure = _param1 != 0; - break; - case CheatType::DisableAllBreakdowns: - gCheatsDisableAllBreakdowns = _param1 != 0; - break; - case CheatType::DisableTrainLengthLimit: - gCheatsDisableTrainLengthLimit = _param1 != 0; - break; - case CheatType::EnableChainLiftOnAllTrack: - gCheatsEnableChainLiftOnAllTrack = _param1 != 0; - break; - case CheatType::BuildInPauseMode: - gCheatsBuildInPauseMode = _param1 != 0; - break; - case CheatType::IgnoreRideIntensity: - gCheatsIgnoreRideIntensity = _param1 != 0; - break; - case CheatType::DisableVandalism: - gCheatsDisableVandalism = _param1 != 0; - break; - case CheatType::DisableLittering: - gCheatsDisableLittering = _param1 != 0; - break; - case CheatType::NoMoney: - SetScenarioNoMoney(_param1 != 0); - break; - case CheatType::AddMoney: - AddMoney(_param1); - break; - case CheatType::SetMoney: - SetMoney(_param1); - break; - case CheatType::ClearLoan: - ClearLoan(); - break; - case CheatType::SetGuestParameter: - SetGuestParameter(_param1, _param2); - break; - case CheatType::GenerateGuests: - GenerateGuests(_param1); - break; - case CheatType::RemoveAllGuests: - RemoveAllGuests(); - break; - case CheatType::GiveAllGuests: - GiveObjectToGuests(_param1); - break; - case CheatType::SetGrassLength: - SetGrassLength(_param1); - break; - case CheatType::WaterPlants: - WaterPlants(); - break; - case CheatType::FixVandalism: - FixVandalism(); - break; - case CheatType::RemoveLitter: - RemoveLitter(); - break; - case CheatType::DisablePlantAging: - gCheatsDisablePlantAging = _param1 != 0; - break; - case CheatType::SetStaffSpeed: - SetStaffSpeed(_param1); - break; - case CheatType::RenewRides: - RenewRides(); - break; - case CheatType::MakeDestructible: - MakeDestructible(); - break; - case CheatType::FixRides: - FixBrokenRides(); - break; - case CheatType::ResetCrashStatus: - ResetRideCrashStatus(); - break; - case CheatType::TenMinuteInspections: - Set10MinuteInspection(); - break; - case CheatType::WinScenario: - scenario_success(); - break; - case CheatType::ForceWeather: - // Todo - make sure this is safe - climate_force_weather(WeatherType{ static_cast(_param1) }); - break; - case CheatType::FreezeWeather: - gCheatsFreezeWeather = _param1 != 0; - break; - case CheatType::NeverEndingMarketing: - gCheatsNeverendingMarketing = _param1 != 0; - break; - case CheatType::OpenClosePark: - ParkSetOpen(!park_is_open()); - break; - case CheatType::HaveFun: - gScenarioObjective.Type = OBJECTIVE_HAVE_FUN; - break; - case CheatType::SetForcedParkRating: - set_forced_park_rating(_param1); - break; - case CheatType::AllowArbitraryRideTypeChanges: - gCheatsAllowArbitraryRideTypeChanges = _param1 != 0; - window_invalidate_by_class(WC_RIDE); - break; - case CheatType::OwnAllLand: - OwnAllLand(); - break; - case CheatType::DisableRideValueAging: - gCheatsDisableRideValueAging = _param1 != 0; - break; - case CheatType::IgnoreResearchStatus: - gCheatsIgnoreResearchStatus = _param1 != 0; - break; - case CheatType::EnableAllDrawableTrackPieces: - gCheatsEnableAllDrawableTrackPieces = _param1 != 0; - break; - case CheatType::CreateDucks: - CreateDucks(_param1); - break; - case CheatType::RemoveDucks: - duck_remove_all(); - break; - case CheatType::AllowTrackPlaceInvalidHeights: - gCheatsAllowTrackPlaceInvalidHeights = _param1 != 0; - break; - default: - { - log_error("Unabled cheat: %d", _cheatType.id); - MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - break; - } - - if (network_get_mode() == NETWORK_MODE_NONE) - { - config_save_default(); - } - - window_invalidate_by_class(WC_CHEATS); - return MakeResult(); - } - -private: - ParametersRange GetParameterRange(CheatType cheatType) const - { - switch (static_cast(_cheatType.id)) - { - case CheatType::SandboxMode: - [[fallthrough]]; - case CheatType::DisableClearanceChecks: - [[fallthrough]]; - case CheatType::DisableSupportLimits: - [[fallthrough]]; - case CheatType::ShowAllOperatingModes: - [[fallthrough]]; - case CheatType::ShowVehiclesFromOtherTrackTypes: - [[fallthrough]]; - case CheatType::FastLiftHill: - [[fallthrough]]; - case CheatType::DisableBrakesFailure: - [[fallthrough]]; - case CheatType::DisableAllBreakdowns: - [[fallthrough]]; - case CheatType::DisableTrainLengthLimit: - [[fallthrough]]; - case CheatType::EnableChainLiftOnAllTrack: - [[fallthrough]]; - case CheatType::BuildInPauseMode: - [[fallthrough]]; - case CheatType::IgnoreRideIntensity: - [[fallthrough]]; - case CheatType::DisableVandalism: - [[fallthrough]]; - case CheatType::DisableLittering: - [[fallthrough]]; - case CheatType::NoMoney: - [[fallthrough]]; - case CheatType::DisablePlantAging: - [[fallthrough]]; - case CheatType::FreezeWeather: - [[fallthrough]]; - case CheatType::NeverEndingMarketing: - [[fallthrough]]; - case CheatType::AllowArbitraryRideTypeChanges: - [[fallthrough]]; - case CheatType::DisableRideValueAging: - [[fallthrough]]; - case CheatType::IgnoreResearchStatus: - [[fallthrough]]; - case CheatType::EnableAllDrawableTrackPieces: - [[fallthrough]]; - case CheatType::OpenClosePark: - return { { 0, 1 }, { 0, 0 } }; - case CheatType::AddMoney: - [[fallthrough]]; - case CheatType::SetMoney: - return { { std::numeric_limits::min(), std::numeric_limits::max() }, { 0, 0 } }; - case CheatType::SetGuestParameter: - switch (_param1) - { - case GUEST_PARAMETER_HAPPINESS: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { 0, PEEP_MAX_HAPPINESS } }; - case GUEST_PARAMETER_ENERGY: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { PEEP_MIN_ENERGY, PEEP_MAX_ENERGY } }; - case GUEST_PARAMETER_HUNGER: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { 0, PEEP_MAX_HUNGER } }; - case GUEST_PARAMETER_THIRST: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { 0, PEEP_MAX_THIRST } }; - case GUEST_PARAMETER_NAUSEA: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { 0, PEEP_MAX_NAUSEA } }; - case GUEST_PARAMETER_NAUSEA_TOLERANCE: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { EnumValue(PeepNauseaTolerance::None), EnumValue(PeepNauseaTolerance::High) } }; - case GUEST_PARAMETER_TOILET: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, - { 0, PEEP_MAX_TOILET } }; - case GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY: - return { { GUEST_PARAMETER_HAPPINESS, GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY }, { 0, 255 } }; - default: - return { { 0, 0 }, { 0, 0 } }; - } - case CheatType::GenerateGuests: - return { { 1, 10000 }, { 0, 0 } }; - case CheatType::GiveAllGuests: - return { { OBJECT_MONEY, OBJECT_UMBRELLA }, { 0, 0 } }; - case CheatType::SetGrassLength: - return { { 0, 7 }, { 0, 0 } }; - case CheatType::SetStaffSpeed: - return { { 0, 255 }, { 0, 0 } }; - case CheatType::ForceWeather: - return { { 0, EnumValue(WeatherType::Count) - 1 }, { 0, 0 } }; - case CheatType::SetForcedParkRating: - return { { 0, 999 }, { 0, 0 } }; - case CheatType::CreateDucks: - return { { 0, 100 }, { 0, 0 } }; - default: - return { { 0, 0 }, { 0, 0 } }; - } - } - - void SetGrassLength(int32_t length) const - { - for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) - { - for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) - { - auto surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); - if (surfaceElement == nullptr) - continue; - - if (surfaceElement != nullptr && (surfaceElement->GetOwnership() & OWNERSHIP_OWNED) - && surfaceElement->GetWaterHeight() == 0 && surfaceElement->CanGrassGrow()) - { - surfaceElement->SetGrassLength(length); - } - } - } - - gfx_invalidate_screen(); - } - - void WaterPlants() const - { - tile_element_iterator it; - - tile_element_iterator_begin(&it); - do - { - if (it.element->GetType() == TILE_ELEMENT_TYPE_SMALL_SCENERY) - { - it.element->AsSmallScenery()->SetAge(0); - } - } while (tile_element_iterator_next(&it)); - - gfx_invalidate_screen(); - } - - void FixVandalism() const - { - tile_element_iterator it; - - tile_element_iterator_begin(&it); - do - { - if (it.element->GetType() != TILE_ELEMENT_TYPE_PATH) - continue; - - if (!(it.element)->AsPath()->HasAddition()) - continue; - - it.element->AsPath()->SetIsBroken(false); - } while (tile_element_iterator_next(&it)); - - gfx_invalidate_screen(); - } - - void RemoveLitter() const - { - for (auto litter : EntityList(EntityListId::Litter)) - { - sprite_remove(litter); - } - - tile_element_iterator it; - rct_scenery_entry* sceneryEntry; - - tile_element_iterator_begin(&it); - do - { - if (it.element->GetType() != TILE_ELEMENT_TYPE_PATH) - continue; - - if (!(it.element)->AsPath()->HasAddition()) - continue; - - sceneryEntry = it.element->AsPath()->GetAdditionEntry(); - if (sceneryEntry->path_bit.flags & PATH_BIT_FLAG_IS_BIN) - it.element->AsPath()->SetAdditionStatus(0xFF); - - } while (tile_element_iterator_next(&it)); - - gfx_invalidate_screen(); - } - - void FixBrokenRides() const - { - for (auto& ride : GetRideManager()) - { - if ((ride.mechanic_status != RIDE_MECHANIC_STATUS_FIXING) - && (ride.lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN))) - { - auto mechanic = ride_get_assigned_mechanic(&ride); - if (mechanic != nullptr) - { - mechanic->RemoveFromRide(); - } - - ride_fix_breakdown(&ride, 0); - ride.window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - } - } - } - - void RenewRides() const - { - for (auto& ride : GetRideManager()) - { - ride.Renew(); - } - window_invalidate_by_class(WC_RIDE); - } - - void MakeDestructible() const - { - for (auto& ride : GetRideManager()) - { - ride.lifecycle_flags &= ~RIDE_LIFECYCLE_INDESTRUCTIBLE; - ride.lifecycle_flags &= ~RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK; - } - window_invalidate_by_class(WC_RIDE); - } - - void ResetRideCrashStatus() const - { - for (auto& ride : GetRideManager()) - { - // Reset crash status and history - ride.lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; - ride.last_crash_type = RIDE_CRASH_TYPE_NONE; - } - window_invalidate_by_class(WC_RIDE); - } - - void Set10MinuteInspection() const - { - for (auto& ride : GetRideManager()) - { - // Set inspection interval to 10 minutes - ride.inspection_interval = RIDE_INSPECTION_EVERY_10_MINUTES; - } - window_invalidate_by_class(WC_RIDE); - } - - void SetScenarioNoMoney(bool enabled) const - { - if (enabled) - { - gParkFlags |= PARK_FLAGS_NO_MONEY; - } - else - { - gParkFlags &= ~PARK_FLAGS_NO_MONEY; - } - // Invalidate all windows that have anything to do with finance - window_invalidate_by_class(WC_RIDE); - window_invalidate_by_class(WC_PEEP); - window_invalidate_by_class(WC_PARK_INFORMATION); - window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - window_invalidate_by_class(WC_TOP_TOOLBAR); - window_invalidate_by_class(WC_CHEATS); - } - - void SetMoney(money32 amount) const - { - gCash = amount; - - window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - } - - void AddMoney(money32 amount) const - { - gCash = add_clamp_money32(gCash, amount); - - window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - } - - void ClearLoan() const - { - // First give money - AddMoney(gBankLoan); - - // Then pay the loan - auto gameAction = ParkSetLoanAction(MONEY(0, 00)); - GameActions::ExecuteNested(&gameAction); - } - - void GenerateGuests(int32_t count) const - { - auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); - for (int32_t i = 0; i < count; i++) - { - park.GenerateGuest(); - } - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); - } - - void SetGuestParameter(int32_t parameter, int32_t value) const - { - for (auto peep : EntityList(EntityListId::Peep)) - { - switch (parameter) - { - case GUEST_PARAMETER_HAPPINESS: - peep->Happiness = value; - peep->HappinessTarget = value; - // Clear the 'red-faced with anger' status if we're making the guest happy - if (value > 0) - { - peep->PeepFlags &= ~PEEP_FLAGS_ANGRY; - peep->Angriness = 0; - } - break; - case GUEST_PARAMETER_ENERGY: - peep->Energy = value; - peep->EnergyTarget = value; - break; - case GUEST_PARAMETER_HUNGER: - peep->Hunger = value; - break; - case GUEST_PARAMETER_THIRST: - peep->Thirst = value; - break; - case GUEST_PARAMETER_NAUSEA: - peep->Nausea = value; - peep->NauseaTarget = value; - break; - case GUEST_PARAMETER_NAUSEA_TOLERANCE: - peep->NauseaTolerance = static_cast(value); - break; - case GUEST_PARAMETER_TOILET: - peep->Toilet = value; - break; - case GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY: - peep->Intensity = IntensityRange(value, 15); - break; - } - peep->UpdateSpriteType(); - } - } - - void GiveObjectToGuests(int32_t object) const - { - for (auto peep : EntityList(EntityListId::Peep)) - { - switch (object) - { - case OBJECT_MONEY: - peep->CashInPocket = MONEY(1000, 00); - break; - case OBJECT_PARK_MAP: - peep->GiveItem(ShopItem::Map); - break; - case OBJECT_BALLOON: - peep->GiveItem(ShopItem::Balloon); - peep->BalloonColour = scenario_rand_max(COLOUR_COUNT - 1); - peep->UpdateSpriteType(); - break; - case OBJECT_UMBRELLA: - peep->GiveItem(ShopItem::Umbrella); - peep->UmbrellaColour = scenario_rand_max(COLOUR_COUNT - 1); - peep->UpdateSpriteType(); - break; - } - } - window_invalidate_by_class(WC_PEEP); - } - - void RemoveAllGuests() const - { - for (auto& ride : GetRideManager()) - { - ride.num_riders = 0; - - for (size_t stationIndex = 0; stationIndex < MAX_STATIONS; stationIndex++) - { - ride.stations[stationIndex].QueueLength = 0; - ride.stations[stationIndex].LastPeepInQueue = SPRITE_INDEX_NULL; - } - - for (auto trainIndex : ride.vehicles) - { - for (Vehicle* vehicle = TryGetEntity(trainIndex); vehicle != nullptr; - vehicle = TryGetEntity(vehicle->next_vehicle_on_train)) - { - for (auto& peepInTrainIndex : vehicle->peep) - { - auto peep = TryGetEntity(peepInTrainIndex); - if (peep != nullptr) - { - vehicle->mass -= peep->Mass; - } - peepInTrainIndex = SPRITE_INDEX_NULL; - } - - vehicle->num_peeps = 0; - vehicle->next_free_seat = 0; - } - } - } - - // Do not use the FOR_ALL_PEEPS macro for this as next sprite index - // will be fetched on a deleted peep. - for (auto peep : EntityList(EntityListId::Peep)) - { - if (peep->AssignedPeepType == PeepType::Guest) - { - peep->Remove(); - } - } - - window_invalidate_by_class(WC_RIDE); - gfx_invalidate_screen(); - } - - void SetStaffSpeed(uint8_t value) const - { - for (auto peep : EntityList(EntityListId::Peep)) - { - peep->Energy = value; - peep->EnergyTarget = value; - } - } - - void OwnAllLand() const - { - const int32_t min = 32; - const int32_t max = gMapSizeUnits - 32; - - for (CoordsXY coords = { min, min }; coords.y <= max; coords.y += COORDS_XY_STEP) - { - for (coords.x = min; coords.x <= max; coords.x += COORDS_XY_STEP) - { - auto* surfaceElement = map_get_surface_element_at(coords); - if (surfaceElement == nullptr) - continue; - - // Ignore already owned tiles. - if (surfaceElement->GetOwnership() & OWNERSHIP_OWNED) - continue; - - int32_t baseZ = surfaceElement->GetBaseZ(); - int32_t destOwnership = check_max_allowable_land_rights_for_tile({ coords, baseZ }); - - // only own tiles that were not set to 0 - if (destOwnership != OWNERSHIP_UNOWNED) - { - surfaceElement->SetOwnership(destOwnership); - update_park_fences_around_tile(coords); - map_invalidate_tile({ coords, baseZ, baseZ + 16 }); - } - } - } - - // Completely unown peep spawn points - for (const auto& spawn : gPeepSpawns) - { - auto* surfaceElement = map_get_surface_element_at(spawn); - if (surfaceElement != nullptr) - { - surfaceElement->SetOwnership(OWNERSHIP_UNOWNED); - update_park_fences_around_tile(spawn); - uint16_t baseZ = surfaceElement->GetBaseZ(); - map_invalidate_tile({ spawn, baseZ, baseZ + 16 }); - } - } - - map_count_remaining_land_rights(); - } - - void ParkSetOpen(bool isOpen) const - { - auto parkSetParameter = ParkSetParameterAction(isOpen ? ParkParameter::Open : ParkParameter::Close); - GameActions::ExecuteNested(&parkSetParameter); - } - - void CreateDucks(int count) const - { - for (int i = 0; i < count; i++) - { - // 100 attempts at finding some water to create a few ducks at - for (int32_t attempts = 0; attempts < 100; attempts++) - { - if (scenario_create_ducks()) - break; - } - } - } -}; diff --git a/src/openrct2/actions/SetParkEntranceFeeAction.cpp b/src/openrct2/actions/SetParkEntranceFeeAction.cpp new file mode 100644 index 0000000000..fa4491aca6 --- /dev/null +++ b/src/openrct2/actions/SetParkEntranceFeeAction.cpp @@ -0,0 +1,45 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "SetParkEntranceFeeAction.h" + +#include "../Cheats.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../world/Park.h" + +void SetParkEntranceFeeAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_fee); +} + +GameActions::Result::Ptr SetParkEntranceFeeAction::Query() const +{ + bool noMoney = (gParkFlags & PARK_FLAGS_NO_MONEY) != 0; + bool forceFreeEntry = !park_entry_price_unlocked(); + if (noMoney || forceFreeEntry) + { + return std::make_unique(GameActions::Status::Disallowed, STR_NONE); + } + if (_fee < MONEY_FREE || _fee > MAX_ENTRANCE_FEE) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + return std::make_unique(); +} + +GameActions::Result::Ptr SetParkEntranceFeeAction::Execute() const +{ + gParkEntranceFee = _fee; + window_invalidate_by_class(WC_PARK_INFORMATION); + return std::make_unique(); +} diff --git a/src/openrct2/actions/SetParkEntranceFeeAction.h b/src/openrct2/actions/SetParkEntranceFeeAction.h new file mode 100644 index 0000000000..cf8478200c --- /dev/null +++ b/src/openrct2/actions/SetParkEntranceFeeAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(SetParkEntranceFeeAction, GAME_COMMAND_SET_PARK_ENTRANCE_FEE, GameActions::Result) +{ +private: + money16 _fee{ MONEY16_UNDEFINED }; + +public: + SetParkEntranceFeeAction() = default; + SetParkEntranceFeeAction(money16 fee) + : _fee(fee) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/SetParkEntranceFeeAction.hpp b/src/openrct2/actions/SetParkEntranceFeeAction.hpp deleted file mode 100644 index c8682e8dbd..0000000000 --- a/src/openrct2/actions/SetParkEntranceFeeAction.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../world/Park.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(SetParkEntranceFeeAction, GAME_COMMAND_SET_PARK_ENTRANCE_FEE, GameActions::Result) -{ -private: - money16 _fee{ MONEY16_UNDEFINED }; - -public: - SetParkEntranceFeeAction() = default; - SetParkEntranceFeeAction(money16 fee) - : _fee(fee) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_fee); - } - - GameActions::Result::Ptr Query() const override - { - bool noMoney = (gParkFlags & PARK_FLAGS_NO_MONEY) != 0; - bool forceFreeEntry = !park_entry_price_unlocked(); - if (noMoney || forceFreeEntry) - { - return std::make_unique(GameActions::Status::Disallowed, STR_NONE); - } - if (_fee < MONEY_FREE || _fee > MAX_ENTRANCE_FEE) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - gParkEntranceFee = _fee; - window_invalidate_by_class(WC_PARK_INFORMATION); - return std::make_unique(); - } -}; diff --git a/src/openrct2/actions/SignSetNameAction.cpp b/src/openrct2/actions/SignSetNameAction.cpp new file mode 100644 index 0000000000..c2e7f850d2 --- /dev/null +++ b/src/openrct2/actions/SignSetNameAction.cpp @@ -0,0 +1,70 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "SignSetNameAction.h" + +#include "../Context.h" +#include "../Diagnostic.h" +#include "../common.h" +#include "../drawing/Drawing.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../ride/Ride.h" +#include "../world/Banner.h" + +#include + +void SignSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_bannerIndex) << DS_TAG(_name); +} + +GameActions::Result::Ptr SignSetNameAction::Query() const +{ + if (_bannerIndex >= MAX_BANNERS) + { + log_warning("Invalid game command for setting sign name, banner id = %d", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return MakeResult(); +} + +GameActions::Result::Ptr SignSetNameAction::Execute() const +{ + auto banner = GetBanner(_bannerIndex); + + if (!_name.empty()) + { + banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; + banner->ride_index = RIDE_ID_NULL; + banner->text = _name; + } + else + { + // If empty name take closest ride name. + ride_id_t rideIndex = banner_get_closest_ride_index({ banner->position.ToCoordsXY(), 16 }); + if (rideIndex == RIDE_ID_NULL) + { + banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; + banner->ride_index = RIDE_ID_NULL; + banner->text = {}; + } + else + { + banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; + banner->ride_index = rideIndex; + banner->text = {}; + } + } + + scrolling_text_invalidate(); + gfx_invalidate_screen(); + return MakeResult(); +} diff --git a/src/openrct2/actions/SignSetNameAction.h b/src/openrct2/actions/SignSetNameAction.h new file mode 100644 index 0000000000..4a828ec8a3 --- /dev/null +++ b/src/openrct2/actions/SignSetNameAction.h @@ -0,0 +1,36 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(SignSetNameAction, GAME_COMMAND_SET_SIGN_NAME, GameActions::Result) +{ +private: + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; + std::string _name; + +public: + SignSetNameAction() = default; + SignSetNameAction(BannerIndex bannerIndex, const std::string& name) + : _bannerIndex(bannerIndex) + , _name(name) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/SignSetNameAction.hpp b/src/openrct2/actions/SignSetNameAction.hpp deleted file mode 100644 index f1aa3c584b..0000000000 --- a/src/openrct2/actions/SignSetNameAction.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../Diagnostic.h" -#include "../common.h" -#include "../drawing/Drawing.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../ride/Ride.h" -#include "../world/Banner.h" -#include "GameAction.h" - -#include - -DEFINE_GAME_ACTION(SignSetNameAction, GAME_COMMAND_SET_SIGN_NAME, GameActions::Result) -{ -private: - BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; - std::string _name; - -public: - SignSetNameAction() = default; - SignSetNameAction(BannerIndex bannerIndex, const std::string& name) - : _bannerIndex(bannerIndex) - , _name(name) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_bannerIndex) << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - if (_bannerIndex >= MAX_BANNERS) - { - log_warning("Invalid game command for setting sign name, banner id = %d", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto banner = GetBanner(_bannerIndex); - - if (!_name.empty()) - { - banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; - banner->ride_index = RIDE_ID_NULL; - banner->text = _name; - } - else - { - // If empty name take closest ride name. - ride_id_t rideIndex = banner_get_closest_ride_index({ banner->position.ToCoordsXY(), 16 }); - if (rideIndex == RIDE_ID_NULL) - { - banner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE; - banner->ride_index = RIDE_ID_NULL; - banner->text = {}; - } - else - { - banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; - banner->ride_index = rideIndex; - banner->text = {}; - } - } - - scrolling_text_invalidate(); - gfx_invalidate_screen(); - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/SignSetStyleAction.cpp b/src/openrct2/actions/SignSetStyleAction.cpp new file mode 100644 index 0000000000..994af3b9c4 --- /dev/null +++ b/src/openrct2/actions/SignSetStyleAction.cpp @@ -0,0 +1,94 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "SignSetStyleAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../localisation/StringIds.h" +#include "../ui/UiContext.h" +#include "../windows/Intent.h" +#include "../world/Banner.h" +#include "../world/Scenery.h" +#include "../world/Sprite.h" + +void SignSetStyleAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_bannerIndex) << DS_TAG(_mainColour) << DS_TAG(_textColour) << DS_TAG(_isLarge); +} + +GameActions::Result::Ptr SignSetStyleAction::Query() const +{ + if (_bannerIndex >= MAX_BANNERS) + { + log_warning("Invalid game command for setting sign style, banner id '%d' out of range", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (_isLarge) + { + TileElement* tileElement = banner_get_tile_element(_bannerIndex); + if (tileElement == nullptr) + { + log_warning("Invalid game command for setting sign style, banner id '%d' not found", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) + { + log_warning("Invalid game command for setting sign style, banner id '%d' is not large", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + } + else + { + WallElement* wallElement = banner_get_scrolling_wall_tile_element(_bannerIndex); + + if (!wallElement) + { + log_warning("Invalid game command for setting sign style, banner id '%d' not found", _bannerIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + } + + return MakeResult(); +} + +GameActions::Result::Ptr SignSetStyleAction::Execute() const +{ + auto banner = GetBanner(_bannerIndex); + + CoordsXY coords = banner->position.ToCoordsXY(); + + if (_isLarge) + { + TileElement* tileElement = banner_get_tile_element(_bannerIndex); + if (!map_large_scenery_sign_set_colour( + { coords, tileElement->GetBaseZ(), tileElement->GetDirection() }, + tileElement->AsLargeScenery()->GetSequenceIndex(), _mainColour, _textColour)) + { + return MakeResult(GameActions::Status::Unknown, STR_NONE); + } + } + else + { + WallElement* wallElement = banner_get_scrolling_wall_tile_element(_bannerIndex); + + wallElement->SetPrimaryColour(_mainColour); + wallElement->SetSecondaryColour(_textColour); + map_invalidate_tile({ coords, wallElement->GetBaseZ(), wallElement->GetClearanceZ() }); + } + + auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); + intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); + context_broadcast_intent(&intent); + + return MakeResult(); +} diff --git a/src/openrct2/actions/SignSetStyleAction.h b/src/openrct2/actions/SignSetStyleAction.h new file mode 100644 index 0000000000..498ef63b9a --- /dev/null +++ b/src/openrct2/actions/SignSetStyleAction.h @@ -0,0 +1,40 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(SignSetStyleAction, GAME_COMMAND_SET_SIGN_STYLE, GameActions::Result) +{ +private: + BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; + uint8_t _mainColour{}; + uint8_t _textColour{}; + bool _isLarge{}; + +public: + SignSetStyleAction() = default; + SignSetStyleAction(BannerIndex bannerIndex, uint8_t mainColour, uint8_t textColour, bool isLarge) + : _bannerIndex(bannerIndex) + , _mainColour(mainColour) + , _textColour(textColour) + , _isLarge(isLarge) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/SignSetStyleAction.hpp b/src/openrct2/actions/SignSetStyleAction.hpp deleted file mode 100644 index d500cdd201..0000000000 --- a/src/openrct2/actions/SignSetStyleAction.hpp +++ /dev/null @@ -1,119 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../localisation/StringIds.h" -#include "../ui/UiContext.h" -#include "../windows/Intent.h" -#include "../world/Banner.h" -#include "../world/Scenery.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(SignSetStyleAction, GAME_COMMAND_SET_SIGN_STYLE, GameActions::Result) -{ -private: - BannerIndex _bannerIndex{ BANNER_INDEX_NULL }; - uint8_t _mainColour{}; - uint8_t _textColour{}; - bool _isLarge{}; - -public: - SignSetStyleAction() = default; - SignSetStyleAction(BannerIndex bannerIndex, uint8_t mainColour, uint8_t textColour, bool isLarge) - : _bannerIndex(bannerIndex) - , _mainColour(mainColour) - , _textColour(textColour) - , _isLarge(isLarge) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_bannerIndex) << DS_TAG(_mainColour) << DS_TAG(_textColour) << DS_TAG(_isLarge); - } - - GameActions::Result::Ptr Query() const override - { - if (_bannerIndex >= MAX_BANNERS) - { - log_warning("Invalid game command for setting sign style, banner id '%d' out of range", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (_isLarge) - { - TileElement* tileElement = banner_get_tile_element(_bannerIndex); - if (tileElement == nullptr) - { - log_warning("Invalid game command for setting sign style, banner id '%d' not found", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) - { - log_warning("Invalid game command for setting sign style, banner id '%d' is not large", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - } - else - { - WallElement* wallElement = banner_get_scrolling_wall_tile_element(_bannerIndex); - - if (!wallElement) - { - log_warning("Invalid game command for setting sign style, banner id '%d' not found", _bannerIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto banner = GetBanner(_bannerIndex); - - CoordsXY coords = banner->position.ToCoordsXY(); - - if (_isLarge) - { - TileElement* tileElement = banner_get_tile_element(_bannerIndex); - if (!map_large_scenery_sign_set_colour( - { coords, tileElement->GetBaseZ(), tileElement->GetDirection() }, - tileElement->AsLargeScenery()->GetSequenceIndex(), _mainColour, _textColour)) - { - return MakeResult(GameActions::Status::Unknown, STR_NONE); - } - } - else - { - WallElement* wallElement = banner_get_scrolling_wall_tile_element(_bannerIndex); - - wallElement->SetPrimaryColour(_mainColour); - wallElement->SetSecondaryColour(_textColour); - map_invalidate_tile({ coords, wallElement->GetBaseZ(), wallElement->GetClearanceZ() }); - } - - auto intent = Intent(INTENT_ACTION_UPDATE_BANNER); - intent.putExtra(INTENT_EXTRA_BANNER_INDEX, _bannerIndex); - context_broadcast_intent(&intent); - - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.cpp b/src/openrct2/actions/SmallSceneryPlaceAction.cpp new file mode 100644 index 0000000000..0f693cc8f8 --- /dev/null +++ b/src/openrct2/actions/SmallSceneryPlaceAction.cpp @@ -0,0 +1,423 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "SmallSceneryPlaceAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../ride/TrackDesign.h" +#include "../world/MapAnimation.h" +#include "../world/Park.h" +#include "../world/SmallScenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" +#include "../world/TileElement.h" +#include "GameAction.h" +#include "SmallSceneryRemoveAction.h" + +void SmallSceneryPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("quadrant", _quadrant); + visitor.Visit("object", _sceneryType); + visitor.Visit("primaryColour", _primaryColour); + visitor.Visit("secondaryColour", _secondaryColour); +} + +void SmallSceneryPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour); +} + +GameActions::Result::Ptr SmallSceneryPlaceAction::Query() const +{ + bool isOnWater = false; + bool supportsRequired = false; + if (_loc.z != 0) + { + supportsRequired = true; + } + int32_t landHeight = tile_element_height(_loc); + int16_t waterHeight = tile_element_water_height(_loc); + + int32_t surfaceHeight = landHeight; + // If on water + if (waterHeight > 0) + { + surfaceHeight = waterHeight; + } + auto res = std::make_unique(); + auto centre = _loc.ToTileCentre(); + res->Position.x = centre.x; + res->Position.y = centre.y; + res->Position.z = surfaceHeight; + if (_loc.z != 0) + { + surfaceHeight = _loc.z; + res->Position.z = surfaceHeight; + } + + if (!map_check_free_elements_and_reorganise(1)) + { + return std::make_unique(GameActions::Status::NoFreeElements); + } + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters); + } + + if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY)) + { + return std::make_unique(GameActions::Status::InvalidParameters); + } + + rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType); + if (sceneryEntry == nullptr) + { + return std::make_unique(GameActions::Status::InvalidParameters); + } + + auto quadrant = _quadrant; + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE) + || !scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL)) + { + if (scenery_small_entry_has_flag( + sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS)) + { + quadrant = 0; + } + } + + // Check if sub tile height is any different compared to actual surface tile height + auto loc2 = _loc; + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) + { + loc2 = loc2.ToTileCentre(); + } + else + { + loc2.x += SceneryQuadrantOffsets[quadrant & 3].x - 1; + loc2.y += SceneryQuadrantOffsets[quadrant & 3].y - 1; + } + landHeight = tile_element_height(loc2); + waterHeight = tile_element_water_height(loc2); + + surfaceHeight = landHeight; + // If on water + if (waterHeight > 0) + { + // base_height2 is now the water height + surfaceHeight = waterHeight; + if (_loc.z == 0) + { + isOnWater = true; + } + } + auto targetHeight = _loc.z; + if (_loc.z == 0) + { + targetHeight = surfaceHeight; + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode + && !map_is_location_owned({ _loc.x, _loc.y, targetHeight })) + { + return std::make_unique(GameActions::Status::NotOwned, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto* surfaceElement = map_get_surface_element_at(_loc); + + if (surfaceElement != nullptr && !gCheatsDisableClearanceChecks && surfaceElement->GetWaterHeight() > 0) + { + int32_t water_height = surfaceElement->GetWaterHeight() - 1; + if (water_height > targetHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); + } + } + + if (!gCheatsDisableClearanceChecks && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE))) + { + if (isOnWater) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); + } + + if (surfaceElement != nullptr && surfaceElement->GetWaterHeight() > 0) + { + if (surfaceElement->GetWaterHeight() > targetHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); + } + } + } + + if (!gCheatsDisableClearanceChecks && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE)) + && !supportsRequired && !isOnWater && surfaceElement != nullptr + && (surfaceElement->GetSlope() != TILE_ELEMENT_SLOPE_FLAT)) + { + return std::make_unique(GameActions::Status::Disallowed, STR_LEVEL_LAND_REQUIRED); + } + + if (!gCheatsDisableSupportLimits && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE)) + && supportsRequired) + { + if (!isOnWater) + { + if (surfaceElement != nullptr) + { + if (surfaceElement->GetWaterHeight() > 0 || (surfaceElement->GetBaseZ()) != targetHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_LEVEL_LAND_REQUIRED); + } + } + } + else + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); + } + } + + int32_t zLow = targetHeight; + int32_t zHigh = zLow + ceil2(sceneryEntry->small_scenery.height, COORDS_Z_STEP); + uint8_t collisionQuadrants = 0b1111; + auto quadRotation{ 0 }; + if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))) + { + quadRotation = (quadrant ^ 2); + collisionQuadrants = 0b0001; + } + if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE))) + { + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL) + && scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) + { + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) + { + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; + collisionQuadrants = 0b1011; + } + else + { + quadRotation = (quadrant + _loc.direction) & 1; + collisionQuadrants = 0b1010; + } + } + } + else + { + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; + collisionQuadrants = 0b0011; + } + uint8_t supports = 0; + if (!supportsRequired) + { + supports = 0b1111; + } + + QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); + money32 clearCost = 0; + + if (!map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &clearCost, + CREATE_CROSSING_MODE_NONE)) + { + return std::make_unique( + GameActions::Status::Disallowed, gGameCommandErrorText, gCommonFormatArgs); + } + + res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + + res->Expenditure = ExpenditureType::Landscaping; + res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost; + + return res; +} + +GameActions::Result::Ptr SmallSceneryPlaceAction::Execute() const +{ + bool supportsRequired = false; + if (_loc.z != 0) + { + supportsRequired = true; + } + int32_t landHeight = tile_element_height(_loc); + int16_t waterHeight = tile_element_water_height(_loc); + + int32_t surfaceHeight = landHeight; + // If on water + if (waterHeight > 0) + { + surfaceHeight = waterHeight; + } + auto res = std::make_unique(); + auto centre = _loc.ToTileCentre(); + res->Position.x = centre.x; + res->Position.y = centre.y; + res->Position.z = surfaceHeight; + if (_loc.z != 0) + { + surfaceHeight = _loc.z; + res->Position.z = surfaceHeight; + } + + rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType); + if (sceneryEntry == nullptr) + { + return std::make_unique(GameActions::Status::InvalidParameters); + } + + auto quadrant = _quadrant; + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE) + || !scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL)) + { + if (scenery_small_entry_has_flag( + sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS)) + { + quadrant = 0; + } + } + + // Check if sub tile height is any different compared to actual surface tile height + int32_t x2 = _loc.x; + int32_t y2 = _loc.y; + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) + { + x2 += 16; + y2 += 16; + } + else + { + x2 += SceneryQuadrantOffsets[quadrant & 3].x - 1; + y2 += SceneryQuadrantOffsets[quadrant & 3].y - 1; + } + landHeight = tile_element_height({ x2, y2 }); + waterHeight = tile_element_water_height({ x2, y2 }); + + surfaceHeight = landHeight; + // If on water + if (waterHeight > 0) + { + // base_height2 is now the water height + surfaceHeight = waterHeight; + } + auto targetHeight = _loc.z; + if (_loc.z == 0) + { + targetHeight = surfaceHeight; + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter({ _loc, targetHeight }); + if (!gCheatsDisableClearanceChecks && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_NO_WALLS))) + { + wall_remove_at({ _loc, targetHeight, targetHeight + sceneryEntry->small_scenery.height }); + } + } + + int32_t zLow = targetHeight; + int32_t zHigh = zLow + ceil2(sceneryEntry->small_scenery.height, 8); + uint8_t collisionQuadrants = 0b1111; + auto quadRotation{ 0 }; + if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))) + { + quadRotation = (quadrant ^ 2); + collisionQuadrants = 0b0001; + } + if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE))) + { + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL) + && scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) + { + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) + { + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; + collisionQuadrants = 0b1011; + } + else + { + quadRotation = (quadrant + _loc.direction) & 1; + collisionQuadrants = 0b1010; + } + } + } + else + { + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; + collisionQuadrants = 0b0011; + } + uint8_t supports = 0; + if (!supportsRequired) + { + supports = 0b1111; + } + + QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); + money32 clearCost = 0; + + if (!map_can_construct_with_clear_at( + { _loc, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags() | GAME_COMMAND_FLAG_APPLY, &clearCost, + CREATE_CROSSING_MODE_NONE)) + { + return std::make_unique( + GameActions::Status::Disallowed, gGameCommandErrorText, gCommonFormatArgs); + } + + res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + + res->Expenditure = ExpenditureType::Landscaping; + res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost; + + TileElement* newElement = tile_element_insert(CoordsXYZ{ _loc, zLow }, quarterTile.GetBaseQuarterOccupied()); + assert(newElement != nullptr); + res->tileElement = newElement; + newElement->SetType(TILE_ELEMENT_TYPE_SMALL_SCENERY); + newElement->SetDirection(_loc.direction); + SmallSceneryElement* sceneryElement = newElement->AsSmallScenery(); + sceneryElement->SetSceneryQuadrant(quadrant); + sceneryElement->SetEntryIndex(_sceneryType); + sceneryElement->SetAge(0); + sceneryElement->SetPrimaryColour(_primaryColour); + sceneryElement->SetSecondaryColour(_secondaryColour); + sceneryElement->SetClearanceZ(sceneryElement->GetBaseZ() + sceneryEntry->small_scenery.height + 7); + + if (supportsRequired) + { + sceneryElement->SetNeedsSupports(); + } + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + sceneryElement->SetGhost(true); + } + + map_invalidate_tile_full(_loc); + if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_ANIMATED)) + { + map_animation_create(MAP_ANIMATION_TYPE_SMALL_SCENERY, CoordsXYZ{ _loc, sceneryElement->GetBaseZ() }); + } + + return res; +} diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.h b/src/openrct2/actions/SmallSceneryPlaceAction.h new file mode 100644 index 0000000000..17c14d3cbd --- /dev/null +++ b/src/openrct2/actions/SmallSceneryPlaceAction.h @@ -0,0 +1,75 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/TileElement.h" +#include "GameAction.h" + +class SmallSceneryPlaceActionResult final : public GameActions::Result +{ +public: + SmallSceneryPlaceActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_CANT_POSITION_THIS_HERE) + { + } + SmallSceneryPlaceActionResult(GameActions::Status error) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE) + { + } + SmallSceneryPlaceActionResult(GameActions::Status error, rct_string_id message) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message) + { + } + SmallSceneryPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) + : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message, args) + { + } + + uint8_t GroundFlags{ 0 }; + TileElement* tileElement = nullptr; +}; + +DEFINE_GAME_ACTION(SmallSceneryPlaceAction, GAME_COMMAND_PLACE_SCENERY, SmallSceneryPlaceActionResult) +{ +private: + CoordsXYZD _loc; + uint8_t _quadrant{}; + ObjectEntryIndex _sceneryType{}; + uint8_t _primaryColour{}; + uint8_t _secondaryColour{}; + +public: + SmallSceneryPlaceAction() = default; + + SmallSceneryPlaceAction( + const CoordsXYZD& loc, uint8_t quadrant, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) + : _loc(loc) + , _quadrant(quadrant) + , _sceneryType(sceneryType) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + uint32_t GetCooldownTime() const override + { + return 20; + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.hpp b/src/openrct2/actions/SmallSceneryPlaceAction.hpp deleted file mode 100644 index b487e6726d..0000000000 --- a/src/openrct2/actions/SmallSceneryPlaceAction.hpp +++ /dev/null @@ -1,480 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../ride/TrackDesign.h" -#include "../world/MapAnimation.h" -#include "../world/Park.h" -#include "../world/SmallScenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "../world/TileElement.h" -#include "GameAction.h" - -class SmallSceneryPlaceActionResult final : public GameActions::Result -{ -public: - SmallSceneryPlaceActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_CANT_POSITION_THIS_HERE) - { - } - SmallSceneryPlaceActionResult(GameActions::Status error) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE) - { - } - SmallSceneryPlaceActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message) - { - } - SmallSceneryPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) - : GameActions::Result(error, STR_CANT_POSITION_THIS_HERE, message, args) - { - } - - uint8_t GroundFlags{ 0 }; - TileElement* tileElement = nullptr; -}; - -DEFINE_GAME_ACTION(SmallSceneryPlaceAction, GAME_COMMAND_PLACE_SCENERY, SmallSceneryPlaceActionResult) -{ -private: - CoordsXYZD _loc; - uint8_t _quadrant{}; - ObjectEntryIndex _sceneryType{}; - uint8_t _primaryColour{}; - uint8_t _secondaryColour{}; - -public: - SmallSceneryPlaceAction() = default; - - SmallSceneryPlaceAction( - const CoordsXYZD& loc, uint8_t quadrant, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) - : _loc(loc) - , _quadrant(quadrant) - , _sceneryType(sceneryType) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("quadrant", _quadrant); - visitor.Visit("object", _sceneryType); - visitor.Visit("primaryColour", _primaryColour); - visitor.Visit("secondaryColour", _secondaryColour); - } - - uint32_t GetCooldownTime() const override - { - return 20; - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) - << DS_TAG(_secondaryColour); - } - - GameActions::Result::Ptr Query() const override - { - bool isOnWater = false; - bool supportsRequired = false; - if (_loc.z != 0) - { - supportsRequired = true; - } - int32_t landHeight = tile_element_height(_loc); - int16_t waterHeight = tile_element_water_height(_loc); - - int32_t surfaceHeight = landHeight; - // If on water - if (waterHeight > 0) - { - surfaceHeight = waterHeight; - } - auto res = std::make_unique(); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = surfaceHeight; - if (_loc.z != 0) - { - surfaceHeight = _loc.z; - res->Position.z = surfaceHeight; - } - - if (!map_check_free_elements_and_reorganise(1)) - { - return std::make_unique(GameActions::Status::NoFreeElements); - } - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters); - } - - if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY)) - { - return std::make_unique(GameActions::Status::InvalidParameters); - } - - rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType); - if (sceneryEntry == nullptr) - { - return std::make_unique(GameActions::Status::InvalidParameters); - } - - auto quadrant = _quadrant; - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE) - || !scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL)) - { - if (scenery_small_entry_has_flag( - sceneryEntry, - SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS)) - { - quadrant = 0; - } - } - - // Check if sub tile height is any different compared to actual surface tile height - auto loc2 = _loc; - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) - { - loc2 = loc2.ToTileCentre(); - } - else - { - loc2.x += SceneryQuadrantOffsets[quadrant & 3].x - 1; - loc2.y += SceneryQuadrantOffsets[quadrant & 3].y - 1; - } - landHeight = tile_element_height(loc2); - waterHeight = tile_element_water_height(loc2); - - surfaceHeight = landHeight; - // If on water - if (waterHeight > 0) - { - // base_height2 is now the water height - surfaceHeight = waterHeight; - if (_loc.z == 0) - { - isOnWater = true; - } - } - auto targetHeight = _loc.z; - if (_loc.z == 0) - { - targetHeight = surfaceHeight; - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode - && !map_is_location_owned({ _loc.x, _loc.y, targetHeight })) - { - return std::make_unique(GameActions::Status::NotOwned, STR_LAND_NOT_OWNED_BY_PARK); - } - - auto* surfaceElement = map_get_surface_element_at(_loc); - - if (surfaceElement != nullptr && !gCheatsDisableClearanceChecks && surfaceElement->GetWaterHeight() > 0) - { - int32_t water_height = surfaceElement->GetWaterHeight() - 1; - if (water_height > targetHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); - } - } - - if (!gCheatsDisableClearanceChecks && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE))) - { - if (isOnWater) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); - } - - if (surfaceElement != nullptr && surfaceElement->GetWaterHeight() > 0) - { - if (surfaceElement->GetWaterHeight() > targetHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); - } - } - } - - if (!gCheatsDisableClearanceChecks - && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE)) && !supportsRequired - && !isOnWater && surfaceElement != nullptr && (surfaceElement->GetSlope() != TILE_ELEMENT_SLOPE_FLAT)) - { - return std::make_unique(GameActions::Status::Disallowed, STR_LEVEL_LAND_REQUIRED); - } - - if (!gCheatsDisableSupportLimits && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE)) - && supportsRequired) - { - if (!isOnWater) - { - if (surfaceElement != nullptr) - { - if (surfaceElement->GetWaterHeight() > 0 || (surfaceElement->GetBaseZ()) != targetHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_LEVEL_LAND_REQUIRED); - } - } - } - else - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_LAND); - } - } - - int32_t zLow = targetHeight; - int32_t zHigh = zLow + ceil2(sceneryEntry->small_scenery.height, COORDS_Z_STEP); - uint8_t collisionQuadrants = 0b1111; - auto quadRotation{ 0 }; - if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))) - { - quadRotation = (quadrant ^ 2); - collisionQuadrants = 0b0001; - } - if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE))) - { - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL) - && scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) - { - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) - { - quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; - collisionQuadrants = 0b1011; - } - else - { - quadRotation = (quadrant + _loc.direction) & 1; - collisionQuadrants = 0b1010; - } - } - } - else - { - quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; - collisionQuadrants = 0b0011; - } - uint8_t supports = 0; - if (!supportsRequired) - { - supports = 0b1111; - } - - QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); - money32 clearCost = 0; - - if (!map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &clearCost, - CREATE_CROSSING_MODE_NONE)) - { - return std::make_unique( - GameActions::Status::Disallowed, gGameCommandErrorText, gCommonFormatArgs); - } - - res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - - res->Expenditure = ExpenditureType::Landscaping; - res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost; - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - bool supportsRequired = false; - if (_loc.z != 0) - { - supportsRequired = true; - } - int32_t landHeight = tile_element_height(_loc); - int16_t waterHeight = tile_element_water_height(_loc); - - int32_t surfaceHeight = landHeight; - // If on water - if (waterHeight > 0) - { - surfaceHeight = waterHeight; - } - auto res = std::make_unique(); - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = surfaceHeight; - if (_loc.z != 0) - { - surfaceHeight = _loc.z; - res->Position.z = surfaceHeight; - } - - rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType); - if (sceneryEntry == nullptr) - { - return std::make_unique(GameActions::Status::InvalidParameters); - } - - auto quadrant = _quadrant; - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE) - || !scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL)) - { - if (scenery_small_entry_has_flag( - sceneryEntry, - SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS)) - { - quadrant = 0; - } - } - - // Check if sub tile height is any different compared to actual surface tile height - int32_t x2 = _loc.x; - int32_t y2 = _loc.y; - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) - { - x2 += 16; - y2 += 16; - } - else - { - x2 += SceneryQuadrantOffsets[quadrant & 3].x - 1; - y2 += SceneryQuadrantOffsets[quadrant & 3].y - 1; - } - landHeight = tile_element_height({ x2, y2 }); - waterHeight = tile_element_water_height({ x2, y2 }); - - surfaceHeight = landHeight; - // If on water - if (waterHeight > 0) - { - // base_height2 is now the water height - surfaceHeight = waterHeight; - } - auto targetHeight = _loc.z; - if (_loc.z == 0) - { - targetHeight = surfaceHeight; - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter({ _loc, targetHeight }); - if (!gCheatsDisableClearanceChecks && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_NO_WALLS))) - { - wall_remove_at({ _loc, targetHeight, targetHeight + sceneryEntry->small_scenery.height }); - } - } - - int32_t zLow = targetHeight; - int32_t zHigh = zLow + ceil2(sceneryEntry->small_scenery.height, 8); - uint8_t collisionQuadrants = 0b1111; - auto quadRotation{ 0 }; - if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))) - { - quadRotation = (quadrant ^ 2); - collisionQuadrants = 0b0001; - } - if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE))) - { - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL) - && scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) - { - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) - { - quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; - collisionQuadrants = 0b1011; - } - else - { - quadRotation = (quadrant + _loc.direction) & 1; - collisionQuadrants = 0b1010; - } - } - } - else - { - quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; - collisionQuadrants = 0b0011; - } - uint8_t supports = 0; - if (!supportsRequired) - { - supports = 0b1111; - } - - QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); - money32 clearCost = 0; - - if (!map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags() | GAME_COMMAND_FLAG_APPLY, - &clearCost, CREATE_CROSSING_MODE_NONE)) - { - return std::make_unique( - GameActions::Status::Disallowed, gGameCommandErrorText, gCommonFormatArgs); - } - - res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - - res->Expenditure = ExpenditureType::Landscaping; - res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost; - - TileElement* newElement = tile_element_insert(CoordsXYZ{ _loc, zLow }, quarterTile.GetBaseQuarterOccupied()); - assert(newElement != nullptr); - res->tileElement = newElement; - newElement->SetType(TILE_ELEMENT_TYPE_SMALL_SCENERY); - newElement->SetDirection(_loc.direction); - SmallSceneryElement* sceneryElement = newElement->AsSmallScenery(); - sceneryElement->SetSceneryQuadrant(quadrant); - sceneryElement->SetEntryIndex(_sceneryType); - sceneryElement->SetAge(0); - sceneryElement->SetPrimaryColour(_primaryColour); - sceneryElement->SetSecondaryColour(_secondaryColour); - sceneryElement->SetClearanceZ(sceneryElement->GetBaseZ() + sceneryEntry->small_scenery.height + 7); - - if (supportsRequired) - { - sceneryElement->SetNeedsSupports(); - } - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - sceneryElement->SetGhost(true); - } - - map_invalidate_tile_full(_loc); - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_ANIMATED)) - { - map_animation_create(MAP_ANIMATION_TYPE_SMALL_SCENERY, CoordsXYZ{ _loc, sceneryElement->GetBaseZ() }); - } - - return res; - } -}; diff --git a/src/openrct2/actions/SmallSceneryRemoveAction.cpp b/src/openrct2/actions/SmallSceneryRemoveAction.cpp new file mode 100644 index 0000000000..0da6b1c68f --- /dev/null +++ b/src/openrct2/actions/SmallSceneryRemoveAction.cpp @@ -0,0 +1,145 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "SmallSceneryRemoveAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../world/Park.h" +#include "../world/SmallScenery.h" +#include "../world/Sprite.h" +#include "GameAction.h" +#include "SmallSceneryPlaceAction.h" + +void SmallSceneryRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _sceneryType); + visitor.Visit("quadrant", _quadrant); +} + +void SmallSceneryRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType); +} + +GameActions::Result::Ptr SmallSceneryRemoveAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + rct_scenery_entry* entry = get_small_scenery_entry(_sceneryType); + if (entry == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + res->Cost = entry->small_scenery.removal_price * 10; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsSandboxMode) + { + // Check if allowed to remove item + if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) + { + if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_IS_TREE)) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorTitle = STR_CANT_REMOVE_THIS; + res->ErrorMessage = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY; + return res; + } + } + + // Check if the land is owned + if (!map_is_location_owned(_loc)) + { + res->Error = GameActions::Status::NoClearance; + res->ErrorTitle = STR_CANT_REMOVE_THIS; + res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; + return res; + } + } + + TileElement* tileElement = FindSceneryElement(); + if (tileElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + return res; +} + +GameActions::Result::Ptr SmallSceneryRemoveAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + + rct_scenery_entry* entry = get_small_scenery_entry(_sceneryType); + if (entry == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); + } + + res->Cost = entry->small_scenery.removal_price * 10; + res->Expenditure = ExpenditureType::Landscaping; + res->Position = _loc; + + TileElement* tileElement = FindSceneryElement(); + if (tileElement == nullptr) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + res->Position.z = tile_element_height(res->Position); + + map_invalidate_tile_full(_loc); + tile_element_remove(tileElement); + + return res; +} + +TileElement* SmallSceneryRemoveAction::FindSceneryElement() const +{ + TileElement* tileElement = map_get_first_element_at(_loc); + if (!tileElement) + return nullptr; + + do + { + if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) + continue; + if ((tileElement->AsSmallScenery()->GetSceneryQuadrant()) != _quadrant) + continue; + if (tileElement->GetBaseZ() != _loc.z) + continue; + if (tileElement->AsSmallScenery()->GetEntryIndex() != _sceneryType) + continue; + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && tileElement->IsGhost() == false) + continue; + + return tileElement; + + } while (!(tileElement++)->IsLastForTile()); + + return nullptr; +} diff --git a/src/openrct2/actions/SmallSceneryRemoveAction.h b/src/openrct2/actions/SmallSceneryRemoveAction.h new file mode 100644 index 0000000000..c9e59ca40c --- /dev/null +++ b/src/openrct2/actions/SmallSceneryRemoveAction.h @@ -0,0 +1,45 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/TileElement.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(SmallSceneryRemoveAction, GAME_COMMAND_REMOVE_SCENERY, GameActions::Result) +{ +private: + CoordsXYZ _loc; + uint8_t _quadrant{}; + ObjectEntryIndex _sceneryType{}; + +public: + SmallSceneryRemoveAction() = default; + + SmallSceneryRemoveAction(const CoordsXYZ& location, uint8_t quadrant, ObjectEntryIndex sceneryType) + : _loc(location) + , _quadrant(quadrant) + , _sceneryType(sceneryType) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + TileElement* FindSceneryElement() const; +}; diff --git a/src/openrct2/actions/SmallSceneryRemoveAction.hpp b/src/openrct2/actions/SmallSceneryRemoveAction.hpp deleted file mode 100644 index f3e05d44c6..0000000000 --- a/src/openrct2/actions/SmallSceneryRemoveAction.hpp +++ /dev/null @@ -1,168 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../world/Park.h" -#include "../world/SmallScenery.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(SmallSceneryRemoveAction, GAME_COMMAND_REMOVE_SCENERY, GameActions::Result) -{ -private: - CoordsXYZ _loc; - uint8_t _quadrant{}; - ObjectEntryIndex _sceneryType{}; - -public: - SmallSceneryRemoveAction() = default; - - SmallSceneryRemoveAction(const CoordsXYZ& location, uint8_t quadrant, ObjectEntryIndex sceneryType) - : _loc(location) - , _quadrant(quadrant) - , _sceneryType(sceneryType) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _sceneryType); - visitor.Visit("quadrant", _quadrant); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - rct_scenery_entry* entry = get_small_scenery_entry(_sceneryType); - if (entry == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - res->Cost = entry->small_scenery.removal_price * 10; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsSandboxMode) - { - // Check if allowed to remove item - if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) - { - if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_IS_TREE)) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorTitle = STR_CANT_REMOVE_THIS; - res->ErrorMessage = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY; - return res; - } - } - - // Check if the land is owned - if (!map_is_location_owned(_loc)) - { - res->Error = GameActions::Status::NoClearance; - res->ErrorTitle = STR_CANT_REMOVE_THIS; - res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; - return res; - } - } - - TileElement* tileElement = FindSceneryElement(); - if (tileElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - - rct_scenery_entry* entry = get_small_scenery_entry(_sceneryType); - if (entry == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_INVALID_SELECTION_OF_OBJECTS); - } - - res->Cost = entry->small_scenery.removal_price * 10; - res->Expenditure = ExpenditureType::Landscaping; - res->Position = _loc; - - TileElement* tileElement = FindSceneryElement(); - if (tileElement == nullptr) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - res->Position.z = tile_element_height(res->Position); - - map_invalidate_tile_full(_loc); - tile_element_remove(tileElement); - - return res; - } - -private: - TileElement* FindSceneryElement() const - { - TileElement* tileElement = map_get_first_element_at(_loc); - if (!tileElement) - return nullptr; - - do - { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - continue; - if ((tileElement->AsSmallScenery()->GetSceneryQuadrant()) != _quadrant) - continue; - if (tileElement->GetBaseZ() != _loc.z) - continue; - if (tileElement->AsSmallScenery()->GetEntryIndex() != _sceneryType) - continue; - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && tileElement->IsGhost() == false) - continue; - - return tileElement; - - } while (!(tileElement++)->IsLastForTile()); - - return nullptr; - } -}; diff --git a/src/openrct2/actions/SmallScenerySetColourAction.cpp b/src/openrct2/actions/SmallScenerySetColourAction.cpp new file mode 100644 index 0000000000..54bf93496b --- /dev/null +++ b/src/openrct2/actions/SmallScenerySetColourAction.cpp @@ -0,0 +1,90 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "SmallScenerySetColourAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../common.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../ride/TrackDesign.h" +#include "../world/MapAnimation.h" +#include "../world/Park.h" +#include "../world/SmallScenery.h" +#include "../world/Sprite.h" +#include "../world/Surface.h" +#include "../world/TileElement.h" + +void SmallScenerySetColourAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour); +} + +GameActions::Result::Ptr SmallScenerySetColourAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr SmallScenerySetColourAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr SmallScenerySetColourAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->ErrorTitle = STR_CANT_REPAINT_THIS; + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_owned(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + auto sceneryElement = map_get_small_scenery_element_at(_loc, _sceneryType, _quadrant); + + if (sceneryElement == nullptr) + { + log_error("Small scenery not found at: x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(sceneryElement->IsGhost())) + { + return res; + } + + if (isExecuting) + { + sceneryElement->SetPrimaryColour(_primaryColour); + sceneryElement->SetSecondaryColour(_secondaryColour); + + map_invalidate_tile_full(_loc); + } + + return res; +} diff --git a/src/openrct2/actions/SmallScenerySetColourAction.h b/src/openrct2/actions/SmallScenerySetColourAction.h new file mode 100644 index 0000000000..089d5815de --- /dev/null +++ b/src/openrct2/actions/SmallScenerySetColourAction.h @@ -0,0 +1,47 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(SmallScenerySetColourAction, GAME_COMMAND_SET_SCENERY_COLOUR, GameActions::Result) +{ +private: + CoordsXYZ _loc; + uint8_t _quadrant{}; + ObjectEntryIndex _sceneryType{}; + uint8_t _primaryColour{}; + uint8_t _secondaryColour{}; + +public: + SmallScenerySetColourAction() = default; + + SmallScenerySetColourAction( + const CoordsXYZ& loc, uint8_t quadrant, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) + : _loc(loc) + , _quadrant(quadrant) + , _sceneryType(sceneryType) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/SmallScenerySetColourAction.hpp b/src/openrct2/actions/SmallScenerySetColourAction.hpp deleted file mode 100644 index 73ece75cc7..0000000000 --- a/src/openrct2/actions/SmallScenerySetColourAction.hpp +++ /dev/null @@ -1,121 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../common.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../ride/Ride.h" -#include "../ride/TrackDesign.h" -#include "../world/MapAnimation.h" -#include "../world/Park.h" -#include "../world/SmallScenery.h" -#include "../world/Sprite.h" -#include "../world/Surface.h" -#include "../world/TileElement.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(SmallScenerySetColourAction, GAME_COMMAND_SET_SCENERY_COLOUR, GameActions::Result) -{ -private: - CoordsXYZ _loc; - uint8_t _quadrant{}; - ObjectEntryIndex _sceneryType{}; - uint8_t _primaryColour{}; - uint8_t _secondaryColour{}; - -public: - SmallScenerySetColourAction() = default; - - SmallScenerySetColourAction( - const CoordsXYZ& loc, uint8_t quadrant, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) - : _loc(loc) - , _quadrant(quadrant) - , _sceneryType(sceneryType) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) - << DS_TAG(_secondaryColour); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - res->ErrorTitle = STR_CANT_REPAINT_THIS; - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_owned(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - auto sceneryElement = map_get_small_scenery_element_at(_loc, _sceneryType, _quadrant); - - if (sceneryElement == nullptr) - { - log_error("Small scenery not found at: x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(sceneryElement->IsGhost())) - { - return res; - } - - if (isExecuting) - { - sceneryElement->SetPrimaryColour(_primaryColour); - sceneryElement->SetSecondaryColour(_secondaryColour); - - map_invalidate_tile_full(_loc); - } - - return res; - } -}; diff --git a/src/openrct2/actions/StaffFireAction.cpp b/src/openrct2/actions/StaffFireAction.cpp new file mode 100644 index 0000000000..ed96e8bd7a --- /dev/null +++ b/src/openrct2/actions/StaffFireAction.cpp @@ -0,0 +1,50 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "StaffFireAction.h" + +#include "../interface/Window.h" +#include "../peep/Peep.h" + +void StaffFireAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_spriteId); +} + +GameActions::Result::Ptr StaffFireAction::Query() const +{ + if (_spriteId >= MAX_SPRITES) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto staff = TryGetEntity(_spriteId); + if (staff == nullptr) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr StaffFireAction::Execute() const +{ + auto staff = TryGetEntity(_spriteId); + if (staff == nullptr) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + window_close_by_class(WC_FIRE_PROMPT); + peep_sprite_remove(staff); + return MakeResult(); +} diff --git a/src/openrct2/actions/StaffFireAction.h b/src/openrct2/actions/StaffFireAction.h new file mode 100644 index 0000000000..ca3938c738 --- /dev/null +++ b/src/openrct2/actions/StaffFireAction.h @@ -0,0 +1,35 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(StaffFireAction, GAME_COMMAND_FIRE_STAFF_MEMBER, GameActions::Result) +{ +private: + uint16_t _spriteId{ SPRITE_INDEX_NULL }; + +public: + StaffFireAction() = default; + StaffFireAction(uint16_t spriteId) + : _spriteId(spriteId) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffFireAction.hpp b/src/openrct2/actions/StaffFireAction.hpp deleted file mode 100644 index ee29a6d6f5..0000000000 --- a/src/openrct2/actions/StaffFireAction.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../interface/Window.h" -#include "../peep/Peep.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(StaffFireAction, GAME_COMMAND_FIRE_STAFF_MEMBER, GameActions::Result) -{ -private: - uint16_t _spriteId{ SPRITE_INDEX_NULL }; - -public: - StaffFireAction() = default; - StaffFireAction(uint16_t spriteId) - : _spriteId(spriteId) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_spriteId); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteId >= MAX_SPRITES) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto staff = TryGetEntity(_spriteId); - if (staff == nullptr) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto staff = TryGetEntity(_spriteId); - if (staff == nullptr) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - window_close_by_class(WC_FIRE_PROMPT); - peep_sprite_remove(staff); - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/StaffHireNewAction.cpp b/src/openrct2/actions/StaffHireNewAction.cpp new file mode 100644 index 0000000000..99b9b9b8c4 --- /dev/null +++ b/src/openrct2/actions/StaffHireNewAction.cpp @@ -0,0 +1,305 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "StaffHireNewAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../peep/Staff.h" +#include "../ride/Ride.h" +#include "../scenario/Scenario.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Entrance.h" +#include "../world/Park.h" +#include "../world/Sprite.h" + +void StaffHireNewAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("autoPosition", _autoPosition); + visitor.Visit("staffType", _staffType); + visitor.Visit("entertainerType", _entertainerType); + visitor.Visit("staffOrders", _staffOrders); +} + +void StaffHireNewAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_autoPosition) << DS_TAG(_staffType) << DS_TAG(_entertainerType) << DS_TAG(_staffOrders); +} + +GameActions::Result::Ptr StaffHireNewAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr StaffHireNewAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr StaffHireNewAction::QueryExecute(bool execute) const +{ + auto res = std::make_unique(); + + res->Expenditure = ExpenditureType::Wages; + + if (_staffType >= static_cast(StaffType::Count)) + { + // Invalid staff type. + log_error("Tried to use invalid staff type: %u", static_cast(_staffType)); + + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (GetEntityListCount(EntityListId::Free) < 400) + { + return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_PEOPLE_IN_GAME); + } + + if (_staffType == static_cast(StaffType::Entertainer)) + { + if (static_cast(_entertainerType) >= static_cast(EntertainerCostume::Count)) + { + // Invalid entertainer costume + log_error("Tried to use invalid entertainer type: %u", static_cast(_entertainerType)); + + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + uint32_t availableCostumes = staff_get_available_entertainer_costumes(); + if (!(availableCostumes & (1 << static_cast(_entertainerType)))) + { + // Entertainer costume unavailable + log_error("Tried to use unavailable entertainer type: %u", static_cast(_entertainerType)); + + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + } + + // Look for a free slot in the staff modes. + int32_t staffIndex; + for (staffIndex = 0; staffIndex < STAFF_MAX_COUNT; ++staffIndex) + { + if (gStaffModes[staffIndex] == StaffMode::None) + break; + } + + if (staffIndex == STAFF_MAX_COUNT) + { + // Too many staff members exist already. + return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_STAFF_IN_GAME); + } + + Peep* newPeep = &(create_sprite(SpriteIdentifier::Peep)->peep); + if (newPeep == nullptr) + { + // Too many peeps exist already. + return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_PEOPLE_IN_GAME); + } + + if (execute == false) + { + // In query we just want to see if we can obtain a sprite slot. + sprite_remove(newPeep); + } + else + { + newPeep->sprite_identifier = SpriteIdentifier::Peep; + newPeep->WindowInvalidateFlags = 0; + newPeep->Action = PeepActionType::None2; + newPeep->SpecialSprite = 0; + newPeep->ActionSpriteImageOffset = 0; + newPeep->WalkingFrameNum = 0; + newPeep->ActionSpriteType = PeepActionSpriteType::None; + newPeep->PathCheckOptimisation = 0; + newPeep->AssignedPeepType = PeepType::Staff; + newPeep->OutsideOfPark = false; + newPeep->PeepFlags = 0; + newPeep->PaidToEnter = 0; + newPeep->PaidOnRides = 0; + newPeep->PaidOnFood = 0; + newPeep->PaidOnSouvenirs = 0; + newPeep->FavouriteRide = RIDE_ID_NULL; + newPeep->StaffOrders = _staffOrders; + + // We search for the first available Id for a given staff type + uint32_t newStaffId = 0; + for (;;) + { + bool found = false; + ++newStaffId; + for (auto searchPeep : EntityList(EntityListId::Peep)) + { + if (static_cast(searchPeep->AssignedStaffType) != _staffType) + continue; + + if (searchPeep->Id == newStaffId) + { + found = true; + break; + } + } + + if (!found) + break; + } + + newPeep->Id = newStaffId; + newPeep->AssignedStaffType = static_cast(_staffType); + + PeepSpriteType spriteType = spriteTypes[_staffType]; + if (_staffType == static_cast(StaffType::Entertainer)) + { + spriteType = EntertainerCostumeToSprite(_entertainerType); + } + newPeep->Name = nullptr; + newPeep->SpriteType = spriteType; + + const rct_sprite_bounds* spriteBounds = &GetSpriteBounds(spriteType); + newPeep->sprite_width = spriteBounds->sprite_width; + newPeep->sprite_height_negative = spriteBounds->sprite_height_negative; + newPeep->sprite_height_positive = spriteBounds->sprite_height_positive; + + if (_autoPosition) + { + AutoPositionNewStaff(newPeep); + } + else + { + // NOTE: This state is required for the window to act. + newPeep->State = PeepState::Picked; + + newPeep->MoveTo({ newPeep->x, newPeep->y, newPeep->z }); + } + + // Staff uses this + newPeep->AsStaff()->SetHireDate(gDateMonthsElapsed); + newPeep->PathfindGoal.x = 0xFF; + newPeep->PathfindGoal.y = 0xFF; + newPeep->PathfindGoal.z = 0xFF; + newPeep->PathfindGoal.direction = INVALID_DIRECTION; + + uint8_t colour = staff_get_colour(static_cast(_staffType)); + newPeep->TshirtColour = colour; + newPeep->TrousersColour = colour; + + // Staff energy determines their walking speed + newPeep->Energy = 0x60; + newPeep->EnergyTarget = 0x60; + newPeep->StaffMowingTimeout = 0; + + newPeep->StaffId = staffIndex; + + gStaffModes[staffIndex] = StaffMode::Walk; + + for (int32_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++) + { + gStaffPatrolAreas[staffIndex * STAFF_PATROL_AREA_SIZE + i] = 0; + } + + res->peepSriteIndex = newPeep->sprite_index; + } + + return res; +} + +void StaffHireNewAction::AutoPositionNewStaff(Peep* newPeep) const +{ + // Find a location to place new staff member + newPeep->State = PeepState::Falling; + + uint32_t count = 0; + PathElement* guest_tile = nullptr; + + // Count number of walking guests + { + for (auto guest : EntityList(EntityListId::Peep)) + { + if (guest->State == PeepState::Walking) + { + // Check the walking guest's tile. Only count them if they're on a path tile. + guest_tile = map_get_path_element_at(TileCoordsXYZ{ guest->NextLoc }); + if (guest_tile != nullptr) + ++count; + } + } + } + + CoordsXYZ newLocation{}; + if (count > 0) + { + // Place staff at a random guest + uint32_t rand = scenario_rand_max(count); + Guest* chosenGuest = nullptr; + + for (auto guest : EntityList(EntityListId::Peep)) + { + if (guest->State == PeepState::Walking) + { + guest_tile = map_get_path_element_at(TileCoordsXYZ{ guest->NextLoc }); + if (guest_tile != nullptr) + { + if (rand == 0) + { + chosenGuest = guest; + break; + } + --rand; + } + } + } + + if (chosenGuest != nullptr) + { + newLocation.x = chosenGuest->x; + newLocation.y = chosenGuest->y; + newLocation.z = chosenGuest->z; + } + else + { + // User must pick a location + newPeep->State = PeepState::Picked; + newLocation.x = newPeep->x; + newLocation.y = newPeep->y; + newLocation.z = newPeep->z; + } + } + else + { + // No walking guests; pick random park entrance + if (!gParkEntrances.empty()) + { + auto rand = scenario_rand_max(static_cast(gParkEntrances.size())); + const auto& entrance = gParkEntrances[rand]; + auto dir = entrance.direction; + newLocation = entrance; + // TODO: Replace with CoordsDirectionDelta + newLocation.x += 16 + ((dir & 1) == 0 ? ((dir & 2) ? 32 : -32) : 0); + newLocation.y += 16 + ((dir & 1) == 1 ? ((dir & 2) ? -32 : 32) : 0); + } + else + { + // User must pick a location + newPeep->State = PeepState::Picked; + newLocation.x = newPeep->x; + newLocation.y = newPeep->y; + newLocation.z = newPeep->z; + } + } + + newPeep->MoveTo(newLocation + CoordsXYZ{ 0, 0, 16 }); +} diff --git a/src/openrct2/actions/StaffHireNewAction.h b/src/openrct2/actions/StaffHireNewAction.h new file mode 100644 index 0000000000..cf401eec49 --- /dev/null +++ b/src/openrct2/actions/StaffHireNewAction.h @@ -0,0 +1,71 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../peep/Staff.h" +#include "../world/Sprite.h" +#include "GameAction.h" + +/* rct2: 0x009929FC */ +static constexpr const PeepSpriteType spriteTypes[] = { + PeepSpriteType::Handyman, + PeepSpriteType::Mechanic, + PeepSpriteType::Security, + PeepSpriteType::EntertainerPanda, +}; + +class StaffHireNewActionResult final : public GameActions::Result +{ +public: + StaffHireNewActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_CANT_HIRE_NEW_STAFF) + { + } + StaffHireNewActionResult(GameActions::Status error, rct_string_id message) + : GameActions::Result(error, STR_CANT_HIRE_NEW_STAFF, message) + { + } + + uint32_t peepSriteIndex = SPRITE_INDEX_NULL; +}; + +DEFINE_GAME_ACTION(StaffHireNewAction, GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, StaffHireNewActionResult) +{ +private: + bool _autoPosition{}; + uint8_t _staffType{ EnumValue(StaffType::Count) }; + EntertainerCostume _entertainerType{ EntertainerCostume::Count }; + uint32_t _staffOrders{}; + +public: + StaffHireNewAction() = default; + StaffHireNewAction(bool autoPosition, StaffType staffType, EntertainerCostume entertainerType, uint32_t staffOrders) + : _autoPosition(autoPosition) + , _staffType(static_cast(staffType)) + , _entertainerType(entertainerType) + , _staffOrders(staffOrders) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool execute) const; + void AutoPositionNewStaff(Peep * newPeep) const; +}; diff --git a/src/openrct2/actions/StaffHireNewAction.hpp b/src/openrct2/actions/StaffHireNewAction.hpp deleted file mode 100644 index fc119002eb..0000000000 --- a/src/openrct2/actions/StaffHireNewAction.hpp +++ /dev/null @@ -1,354 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../peep/Staff.h" -#include "../ride/Ride.h" -#include "../scenario/Scenario.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../world/Entrance.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -/* rct2: 0x009929FC */ -static constexpr const PeepSpriteType spriteTypes[] = { - PeepSpriteType::Handyman, - PeepSpriteType::Mechanic, - PeepSpriteType::Security, - PeepSpriteType::EntertainerPanda, -}; - -class StaffHireNewActionResult final : public GameActions::Result -{ -public: - StaffHireNewActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_CANT_HIRE_NEW_STAFF) - { - } - StaffHireNewActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_CANT_HIRE_NEW_STAFF, message) - { - } - - uint32_t peepSriteIndex = SPRITE_INDEX_NULL; -}; - -DEFINE_GAME_ACTION(StaffHireNewAction, GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, StaffHireNewActionResult) -{ -private: - bool _autoPosition{}; - uint8_t _staffType{ EnumValue(StaffType::Count) }; - EntertainerCostume _entertainerType{ EntertainerCostume::Count }; - uint32_t _staffOrders{}; - -public: - StaffHireNewAction() = default; - StaffHireNewAction(bool autoPosition, StaffType staffType, EntertainerCostume entertainerType, uint32_t staffOrders) - : _autoPosition(autoPosition) - , _staffType(static_cast(staffType)) - , _entertainerType(entertainerType) - , _staffOrders(staffOrders) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit("autoPosition", _autoPosition); - visitor.Visit("staffType", _staffType); - visitor.Visit("entertainerType", _entertainerType); - visitor.Visit("staffOrders", _staffOrders); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_autoPosition) << DS_TAG(_staffType) << DS_TAG(_entertainerType) << DS_TAG(_staffOrders); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool execute) const - { - auto res = std::make_unique(); - - res->Expenditure = ExpenditureType::Wages; - - if (_staffType >= static_cast(StaffType::Count)) - { - // Invalid staff type. - log_error("Tried to use invalid staff type: %u", static_cast(_staffType)); - - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (GetEntityListCount(EntityListId::Free) < 400) - { - return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_PEOPLE_IN_GAME); - } - - if (_staffType == static_cast(StaffType::Entertainer)) - { - if (static_cast(_entertainerType) >= static_cast(EntertainerCostume::Count)) - { - // Invalid entertainer costume - log_error("Tried to use invalid entertainer type: %u", static_cast(_entertainerType)); - - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - uint32_t availableCostumes = staff_get_available_entertainer_costumes(); - if (!(availableCostumes & (1 << static_cast(_entertainerType)))) - { - // Entertainer costume unavailable - log_error("Tried to use unavailable entertainer type: %u", static_cast(_entertainerType)); - - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - } - - // Look for a free slot in the staff modes. - int32_t staffIndex; - for (staffIndex = 0; staffIndex < STAFF_MAX_COUNT; ++staffIndex) - { - if (gStaffModes[staffIndex] == StaffMode::None) - break; - } - - if (staffIndex == STAFF_MAX_COUNT) - { - // Too many staff members exist already. - return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_STAFF_IN_GAME); - } - - Peep* newPeep = &(create_sprite(SpriteIdentifier::Peep)->peep); - if (newPeep == nullptr) - { - // Too many peeps exist already. - return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_PEOPLE_IN_GAME); - } - - if (execute == false) - { - // In query we just want to see if we can obtain a sprite slot. - sprite_remove(newPeep); - } - else - { - newPeep->sprite_identifier = SpriteIdentifier::Peep; - newPeep->WindowInvalidateFlags = 0; - newPeep->Action = PeepActionType::None2; - newPeep->SpecialSprite = 0; - newPeep->ActionSpriteImageOffset = 0; - newPeep->WalkingFrameNum = 0; - newPeep->ActionSpriteType = PeepActionSpriteType::None; - newPeep->PathCheckOptimisation = 0; - newPeep->AssignedPeepType = PeepType::Staff; - newPeep->OutsideOfPark = false; - newPeep->PeepFlags = 0; - newPeep->PaidToEnter = 0; - newPeep->PaidOnRides = 0; - newPeep->PaidOnFood = 0; - newPeep->PaidOnSouvenirs = 0; - newPeep->FavouriteRide = RIDE_ID_NULL; - newPeep->StaffOrders = _staffOrders; - - // We search for the first available Id for a given staff type - uint32_t newStaffId = 0; - for (;;) - { - bool found = false; - ++newStaffId; - for (auto searchPeep : EntityList(EntityListId::Peep)) - { - if (static_cast(searchPeep->AssignedStaffType) != _staffType) - continue; - - if (searchPeep->Id == newStaffId) - { - found = true; - break; - } - } - - if (!found) - break; - } - - newPeep->Id = newStaffId; - newPeep->AssignedStaffType = static_cast(_staffType); - - PeepSpriteType spriteType = spriteTypes[_staffType]; - if (_staffType == static_cast(StaffType::Entertainer)) - { - spriteType = EntertainerCostumeToSprite(_entertainerType); - } - newPeep->Name = nullptr; - newPeep->SpriteType = spriteType; - - const rct_sprite_bounds* spriteBounds = &GetSpriteBounds(spriteType); - newPeep->sprite_width = spriteBounds->sprite_width; - newPeep->sprite_height_negative = spriteBounds->sprite_height_negative; - newPeep->sprite_height_positive = spriteBounds->sprite_height_positive; - - if (_autoPosition) - { - AutoPositionNewStaff(newPeep); - } - else - { - // NOTE: This state is required for the window to act. - newPeep->State = PeepState::Picked; - - newPeep->MoveTo({ newPeep->x, newPeep->y, newPeep->z }); - } - - // Staff uses this - newPeep->AsStaff()->SetHireDate(gDateMonthsElapsed); - newPeep->PathfindGoal.x = 0xFF; - newPeep->PathfindGoal.y = 0xFF; - newPeep->PathfindGoal.z = 0xFF; - newPeep->PathfindGoal.direction = INVALID_DIRECTION; - - uint8_t colour = staff_get_colour(static_cast(_staffType)); - newPeep->TshirtColour = colour; - newPeep->TrousersColour = colour; - - // Staff energy determines their walking speed - newPeep->Energy = 0x60; - newPeep->EnergyTarget = 0x60; - newPeep->StaffMowingTimeout = 0; - - newPeep->StaffId = staffIndex; - - gStaffModes[staffIndex] = StaffMode::Walk; - - for (int32_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++) - { - gStaffPatrolAreas[staffIndex * STAFF_PATROL_AREA_SIZE + i] = 0; - } - - res->peepSriteIndex = newPeep->sprite_index; - } - - return res; - } - - void AutoPositionNewStaff(Peep * newPeep) const - { - // Find a location to place new staff member - newPeep->State = PeepState::Falling; - - uint32_t count = 0; - PathElement* guest_tile = nullptr; - - // Count number of walking guests - { - for (auto guest : EntityList(EntityListId::Peep)) - { - if (guest->State == PeepState::Walking) - { - // Check the walking guest's tile. Only count them if they're on a path tile. - guest_tile = map_get_path_element_at(TileCoordsXYZ{ guest->NextLoc }); - if (guest_tile != nullptr) - ++count; - } - } - } - - CoordsXYZ newLocation{}; - if (count > 0) - { - // Place staff at a random guest - uint32_t rand = scenario_rand_max(count); - Guest* chosenGuest = nullptr; - - for (auto guest : EntityList(EntityListId::Peep)) - { - if (guest->State == PeepState::Walking) - { - guest_tile = map_get_path_element_at(TileCoordsXYZ{ guest->NextLoc }); - if (guest_tile != nullptr) - { - if (rand == 0) - { - chosenGuest = guest; - break; - } - --rand; - } - } - } - - if (chosenGuest != nullptr) - { - newLocation.x = chosenGuest->x; - newLocation.y = chosenGuest->y; - newLocation.z = chosenGuest->z; - } - else - { - // User must pick a location - newPeep->State = PeepState::Picked; - newLocation.x = newPeep->x; - newLocation.y = newPeep->y; - newLocation.z = newPeep->z; - } - } - else - { - // No walking guests; pick random park entrance - if (!gParkEntrances.empty()) - { - auto rand = scenario_rand_max(static_cast(gParkEntrances.size())); - const auto& entrance = gParkEntrances[rand]; - auto dir = entrance.direction; - newLocation = entrance; - // TODO: Replace with CoordsDirectionDelta - newLocation.x += 16 + ((dir & 1) == 0 ? ((dir & 2) ? 32 : -32) : 0); - newLocation.y += 16 + ((dir & 1) == 1 ? ((dir & 2) ? -32 : 32) : 0); - } - else - { - // User must pick a location - newPeep->State = PeepState::Picked; - newLocation.x = newPeep->x; - newLocation.y = newPeep->y; - newLocation.z = newPeep->z; - } - } - - newPeep->MoveTo(newLocation + CoordsXYZ{ 0, 0, 16 }); - } -}; diff --git a/src/openrct2/actions/StaffSetColourAction.cpp b/src/openrct2/actions/StaffSetColourAction.cpp new file mode 100644 index 0000000000..b806ee459c --- /dev/null +++ b/src/openrct2/actions/StaffSetColourAction.cpp @@ -0,0 +1,58 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "StaffSetColourAction.h" + +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../localisation/StringIds.h" +#include "../peep/Staff.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../windows/Intent.h" +#include "../world/Sprite.h" + +void StaffSetColourAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_staffType) << DS_TAG(_colour); +} + +GameActions::Result::Ptr StaffSetColourAction::Query() const +{ + auto staffType = static_cast(_staffType); + if (staffType != StaffType::Handyman && staffType != StaffType::Mechanic && staffType != StaffType::Security) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + return MakeResult(); +} + +GameActions::Result::Ptr StaffSetColourAction::Execute() const +{ + // Update global uniform colour property + if (!staff_set_colour(static_cast(_staffType), _colour)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + // Update each staff member's uniform + for (auto peep : EntityList(EntityListId::Peep)) + { + if (peep->AssignedStaffType == static_cast(_staffType)) + { + peep->TshirtColour = _colour; + peep->TrousersColour = _colour; + } + } + + gfx_invalidate_screen(); + return MakeResult(); +} diff --git a/src/openrct2/actions/StaffSetColourAction.h b/src/openrct2/actions/StaffSetColourAction.h new file mode 100644 index 0000000000..4da9ccb82a --- /dev/null +++ b/src/openrct2/actions/StaffSetColourAction.h @@ -0,0 +1,36 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(StaffSetColourAction, GAME_COMMAND_SET_STAFF_COLOUR, GameActions::Result) +{ +private: + uint8_t _staffType{}; + uint8_t _colour{}; + +public: + StaffSetColourAction() = default; + StaffSetColourAction(StaffType staffType, uint8_t colour) + : _staffType(static_cast(staffType)) + , _colour(colour) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffSetColourAction.hpp b/src/openrct2/actions/StaffSetColourAction.hpp deleted file mode 100644 index 18e050b38c..0000000000 --- a/src/openrct2/actions/StaffSetColourAction.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../localisation/StringIds.h" -#include "../peep/Staff.h" -#include "../ui/UiContext.h" -#include "../ui/WindowManager.h" -#include "../windows/Intent.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(StaffSetColourAction, GAME_COMMAND_SET_STAFF_COLOUR, GameActions::Result) -{ -private: - uint8_t _staffType{}; - uint8_t _colour{}; - -public: - StaffSetColourAction() = default; - StaffSetColourAction(StaffType staffType, uint8_t colour) - : _staffType(static_cast(staffType)) - , _colour(colour) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_staffType) << DS_TAG(_colour); - } - - GameActions::Result::Ptr Query() const override - { - auto staffType = static_cast(_staffType); - if (staffType != StaffType::Handyman && staffType != StaffType::Mechanic && staffType != StaffType::Security) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - // Update global uniform colour property - if (!staff_set_colour(static_cast(_staffType), _colour)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - // Update each staff member's uniform - for (auto peep : EntityList(EntityListId::Peep)) - { - if (peep->AssignedStaffType == static_cast(_staffType)) - { - peep->TshirtColour = _colour; - peep->TrousersColour = _colour; - } - } - - gfx_invalidate_screen(); - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/StaffSetCostumeAction.cpp b/src/openrct2/actions/StaffSetCostumeAction.cpp new file mode 100644 index 0000000000..b6434a3296 --- /dev/null +++ b/src/openrct2/actions/StaffSetCostumeAction.cpp @@ -0,0 +1,77 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "StaffSetCostumeAction.h" + +#include "../Context.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../windows/Intent.h" + +void StaffSetCostumeAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_spriteIndex) << DS_TAG(_costume); +} + +GameActions::Result::Ptr StaffSetCostumeAction::Query() const +{ + if (_spriteIndex >= MAX_SPRITES) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto* staff = TryGetEntity(_spriteIndex); + if (staff == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto spriteType = EntertainerCostumeToSprite(_costume); + if (EnumValue(spriteType) > std::size(peep_slow_walking_types)) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + return std::make_unique(); +} + +GameActions::Result::Ptr StaffSetCostumeAction::Execute() const +{ + auto* staff = TryGetEntity(_spriteIndex); + if (staff == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto spriteType = EntertainerCostumeToSprite(_costume); + staff->SpriteType = spriteType; + staff->PeepFlags &= ~PEEP_FLAGS_SLOW_WALK; + if (peep_slow_walking_types[EnumValue(spriteType)]) + { + staff->PeepFlags |= PEEP_FLAGS_SLOW_WALK; + } + staff->ActionFrame = 0; + staff->UpdateCurrentActionSpriteType(); + staff->Invalidate(); + + window_invalidate_by_number(WC_PEEP, _spriteIndex); + auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); + context_broadcast_intent(&intent); + + auto res = std::make_unique(); + res->Position.x = staff->x; + res->Position.y = staff->y; + res->Position.z = staff->z; + return res; +} diff --git a/src/openrct2/actions/StaffSetCostumeAction.h b/src/openrct2/actions/StaffSetCostumeAction.h new file mode 100644 index 0000000000..9bf3178b19 --- /dev/null +++ b/src/openrct2/actions/StaffSetCostumeAction.h @@ -0,0 +1,58 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../peep/Staff.h" +#include "../world/Sprite.h" +#include "GameAction.h" + +/** rct2: 0x00982134 */ +constexpr const bool peep_slow_walking_types[] = { + false, // PeepSpriteType::Normal + false, // PeepSpriteType::Handyman + false, // PeepSpriteType::Mechanic + false, // PeepSpriteType::Security + false, // PeepSpriteType::EntertainerPanda + false, // PeepSpriteType::EntertainerTiger + false, // PeepSpriteType::EntertainerElephant + false, // PeepSpriteType::EntertainerRoman + false, // PeepSpriteType::EntertainerGorilla + false, // PeepSpriteType::EntertainerSnowman + false, // PeepSpriteType::EntertainerKnight + true, // PeepSpriteType::EntertainerAstronaut + false, // PeepSpriteType::EntertainerBandit + false, // PeepSpriteType::EntertainerSheriff + true, // PeepSpriteType::EntertainerPirate + true, // PeepSpriteType::Balloon +}; + +DEFINE_GAME_ACTION(StaffSetCostumeAction, GAME_COMMAND_SET_STAFF_COSTUME, GameActions::Result) +{ +private: + uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; + EntertainerCostume _costume = EntertainerCostume::Count; + +public: + StaffSetCostumeAction() = default; + StaffSetCostumeAction(uint16_t spriteIndex, EntertainerCostume costume) + : _spriteIndex(spriteIndex) + , _costume(costume) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffSetCostumeAction.hpp b/src/openrct2/actions/StaffSetCostumeAction.hpp deleted file mode 100644 index 2d95f031cb..0000000000 --- a/src/openrct2/actions/StaffSetCostumeAction.hpp +++ /dev/null @@ -1,120 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../peep/Staff.h" -#include "../windows/Intent.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -/** rct2: 0x00982134 */ -constexpr const bool peep_slow_walking_types[] = { - false, // PeepSpriteType::Normal - false, // PeepSpriteType::Handyman - false, // PeepSpriteType::Mechanic - false, // PeepSpriteType::Security - false, // PeepSpriteType::EntertainerPanda - false, // PeepSpriteType::EntertainerTiger - false, // PeepSpriteType::EntertainerElephant - false, // PeepSpriteType::EntertainerRoman - false, // PeepSpriteType::EntertainerGorilla - false, // PeepSpriteType::EntertainerSnowman - false, // PeepSpriteType::EntertainerKnight - true, // PeepSpriteType::EntertainerAstronaut - false, // PeepSpriteType::EntertainerBandit - false, // PeepSpriteType::EntertainerSheriff - true, // PeepSpriteType::EntertainerPirate - true, // PeepSpriteType::Balloon -}; - -DEFINE_GAME_ACTION(StaffSetCostumeAction, GAME_COMMAND_SET_STAFF_COSTUME, GameActions::Result) -{ -private: - uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; - EntertainerCostume _costume = EntertainerCostume::Count; - -public: - StaffSetCostumeAction() = default; - StaffSetCostumeAction(uint16_t spriteIndex, EntertainerCostume costume) - : _spriteIndex(spriteIndex) - , _costume(costume) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_spriteIndex) << DS_TAG(_costume); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteIndex >= MAX_SPRITES) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto* staff = TryGetEntity(_spriteIndex); - if (staff == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto spriteType = EntertainerCostumeToSprite(_costume); - if (EnumValue(spriteType) > std::size(peep_slow_walking_types)) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto* staff = TryGetEntity(_spriteIndex); - if (staff == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto spriteType = EntertainerCostumeToSprite(_costume); - staff->SpriteType = spriteType; - staff->PeepFlags &= ~PEEP_FLAGS_SLOW_WALK; - if (peep_slow_walking_types[EnumValue(spriteType)]) - { - staff->PeepFlags |= PEEP_FLAGS_SLOW_WALK; - } - staff->ActionFrame = 0; - staff->UpdateCurrentActionSpriteType(); - staff->Invalidate(); - - window_invalidate_by_number(WC_PEEP, _spriteIndex); - auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); - context_broadcast_intent(&intent); - - auto res = std::make_unique(); - res->Position.x = staff->x; - res->Position.y = staff->y; - res->Position.z = staff->z; - return res; - } -}; diff --git a/src/openrct2/actions/StaffSetNameAction.cpp b/src/openrct2/actions/StaffSetNameAction.cpp new file mode 100644 index 0000000000..2cc09b3685 --- /dev/null +++ b/src/openrct2/actions/StaffSetNameAction.cpp @@ -0,0 +1,80 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "StaffSetNameAction.h" + +#include "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../peep/Staff.h" +#include "../windows/Intent.h" +#include "../world/Park.h" + +void StaffSetNameAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_spriteIndex) << DS_TAG(_name); +} + +GameActions::Result::Ptr StaffSetNameAction::Query() const +{ + if (_spriteIndex >= MAX_SPRITES) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); + } + + auto staff = TryGetEntity(_spriteIndex); + if (staff == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr StaffSetNameAction::Execute() const +{ + auto staff = TryGetEntity(_spriteIndex); + if (staff == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); + } + + auto curName = staff->GetName(); + if (curName == _name) + { + return std::make_unique(GameActions::Status::Ok, STR_NONE); + } + + if (!staff->SetName(_name)) + { + return std::make_unique(GameActions::Status::Unknown, STR_CANT_NAME_GUEST, STR_NONE); + } + + gfx_invalidate_screen(); + + auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); + context_broadcast_intent(&intent); + + auto res = std::make_unique(); + res->Position.x = staff->x; + res->Position.y = staff->y; + res->Position.z = staff->z; + return res; +} diff --git a/src/openrct2/actions/StaffSetNameAction.h b/src/openrct2/actions/StaffSetNameAction.h new file mode 100644 index 0000000000..6c4ddff9ac --- /dev/null +++ b/src/openrct2/actions/StaffSetNameAction.h @@ -0,0 +1,37 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(StaffSetNameAction, GAME_COMMAND_SET_STAFF_NAME, GameActions::Result) +{ +private: + uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; + std::string _name; + +public: + StaffSetNameAction() = default; + StaffSetNameAction(uint16_t spriteIndex, const std::string& name) + : _spriteIndex(spriteIndex) + , _name(name) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffSetNameAction.hpp b/src/openrct2/actions/StaffSetNameAction.hpp deleted file mode 100644 index ce02259f6d..0000000000 --- a/src/openrct2/actions/StaffSetNameAction.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../Context.h" -#include "../core/MemoryStream.h" -#include "../drawing/Drawing.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../peep/Staff.h" -#include "../windows/Intent.h" -#include "../world/Park.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(StaffSetNameAction, GAME_COMMAND_SET_STAFF_NAME, GameActions::Result) -{ -private: - uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; - std::string _name; - -public: - StaffSetNameAction() = default; - StaffSetNameAction(uint16_t spriteIndex, const std::string& name) - : _spriteIndex(spriteIndex) - , _name(name) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_spriteIndex) << DS_TAG(_name); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteIndex >= MAX_SPRITES) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); - } - - auto staff = TryGetEntity(_spriteIndex); - if (staff == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto staff = TryGetEntity(_spriteIndex); - if (staff == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_STAFF_ERROR_CANT_NAME_STAFF_MEMBER, STR_NONE); - } - - auto curName = staff->GetName(); - if (curName == _name) - { - return std::make_unique(GameActions::Status::Ok, STR_NONE); - } - - if (!staff->SetName(_name)) - { - return std::make_unique(GameActions::Status::Unknown, STR_CANT_NAME_GUEST, STR_NONE); - } - - gfx_invalidate_screen(); - - auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); - context_broadcast_intent(&intent); - - auto res = std::make_unique(); - res->Position.x = staff->x; - res->Position.y = staff->y; - res->Position.z = staff->z; - return res; - } -}; diff --git a/src/openrct2/actions/StaffSetOrdersAction.cpp b/src/openrct2/actions/StaffSetOrdersAction.cpp new file mode 100644 index 0000000000..e07566c724 --- /dev/null +++ b/src/openrct2/actions/StaffSetOrdersAction.cpp @@ -0,0 +1,63 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "StaffSetOrdersAction.h" + +#include "../Context.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../peep/Staff.h" +#include "../windows/Intent.h" + +void StaffSetOrdersAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_spriteIndex) << DS_TAG(_ordersId); +} + +GameActions::Result::Ptr StaffSetOrdersAction::Query() const +{ + if (_spriteIndex >= MAX_SPRITES) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto* staff = TryGetEntity(_spriteIndex); + if (staff == nullptr + || (staff->AssignedStaffType != StaffType::Handyman && staff->AssignedStaffType != StaffType::Mechanic)) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + return std::make_unique(); +} + +GameActions::Result::Ptr StaffSetOrdersAction::Execute() const +{ + auto* staff = TryGetEntity(_spriteIndex); + if (staff == nullptr) + { + log_warning("Invalid game command for sprite %u", _spriteIndex); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + staff->StaffOrders = _ordersId; + + window_invalidate_by_number(WC_PEEP, _spriteIndex); + auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); + context_broadcast_intent(&intent); + + auto res = std::make_unique(); + res->Position.x = staff->x; + res->Position.y = staff->y; + res->Position.z = staff->z; + return res; +} diff --git a/src/openrct2/actions/StaffSetOrdersAction.h b/src/openrct2/actions/StaffSetOrdersAction.h new file mode 100644 index 0000000000..0c28864141 --- /dev/null +++ b/src/openrct2/actions/StaffSetOrdersAction.h @@ -0,0 +1,37 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(StaffSetOrdersAction, GAME_COMMAND_SET_STAFF_ORDERS, GameActions::Result) +{ +private: + uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; + uint8_t _ordersId{}; + +public: + StaffSetOrdersAction() = default; + StaffSetOrdersAction(uint16_t spriteIndex, uint8_t ordersId) + : _spriteIndex(spriteIndex) + , _ordersId(ordersId) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffSetOrdersAction.hpp b/src/openrct2/actions/StaffSetOrdersAction.hpp deleted file mode 100644 index f9048684a0..0000000000 --- a/src/openrct2/actions/StaffSetOrdersAction.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../interface/Window.h" -#include "../localisation/Localisation.h" -#include "../localisation/StringIds.h" -#include "../peep/Staff.h" -#include "../windows/Intent.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(StaffSetOrdersAction, GAME_COMMAND_SET_STAFF_ORDERS, GameActions::Result) -{ -private: - uint16_t _spriteIndex{ SPRITE_INDEX_NULL }; - uint8_t _ordersId{}; - -public: - StaffSetOrdersAction() = default; - StaffSetOrdersAction(uint16_t spriteIndex, uint8_t ordersId) - : _spriteIndex(spriteIndex) - , _ordersId(ordersId) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_spriteIndex) << DS_TAG(_ordersId); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteIndex >= MAX_SPRITES) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto* staff = TryGetEntity(_spriteIndex); - if (staff == nullptr - || (staff->AssignedStaffType != StaffType::Handyman && staff->AssignedStaffType != StaffType::Mechanic)) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - return std::make_unique(); - } - - GameActions::Result::Ptr Execute() const override - { - auto* staff = TryGetEntity(_spriteIndex); - if (staff == nullptr) - { - log_warning("Invalid game command for sprite %u", _spriteIndex); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - staff->StaffOrders = _ordersId; - - window_invalidate_by_number(WC_PEEP, _spriteIndex); - auto intent = Intent(INTENT_ACTION_REFRESH_STAFF_LIST); - context_broadcast_intent(&intent); - - auto res = std::make_unique(); - res->Position.x = staff->x; - res->Position.y = staff->y; - res->Position.z = staff->z; - return res; - } -}; diff --git a/src/openrct2/actions/StaffSetPatrolAreaAction.cpp b/src/openrct2/actions/StaffSetPatrolAreaAction.cpp new file mode 100644 index 0000000000..bcf20dad23 --- /dev/null +++ b/src/openrct2/actions/StaffSetPatrolAreaAction.cpp @@ -0,0 +1,87 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "StaffSetPatrolAreaAction.h" + +#include "../interface/Window.h" +#include "../peep/Peep.h" +#include "../peep/Staff.h" + +void StaffSetPatrolAreaAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_spriteId) << DS_TAG(_loc); +} + +GameActions::Result::Ptr StaffSetPatrolAreaAction::Query() const +{ + if (_spriteId >= MAX_SPRITES) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto staff = TryGetEntity(_spriteId); + if (staff == nullptr) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + return MakeResult(); +} + +GameActions::Result::Ptr StaffSetPatrolAreaAction::Execute() const +{ + auto staff = TryGetEntity(_spriteId); + if (staff == nullptr) + { + log_error("Invalid spriteId. spriteId = %u", _spriteId); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + int32_t patrolOffset = staff->StaffId * STAFF_PATROL_AREA_SIZE; + + staff_toggle_patrol_area(staff->StaffId, _loc); + + bool isPatrolling = false; + for (int32_t i = 0; i < 128; i++) + { + if (gStaffPatrolAreas[patrolOffset + i]) + { + isPatrolling = true; + break; + } + } + + if (isPatrolling) + { + gStaffModes[staff->StaffId] = StaffMode::Patrol; + } + else if (gStaffModes[staff->StaffId] == StaffMode::Patrol) + { + gStaffModes[staff->StaffId] = StaffMode::Walk; + } + + for (int32_t y = 0; y < 4 * COORDS_XY_STEP; y += COORDS_XY_STEP) + { + for (int32_t x = 0; x < 4 * COORDS_XY_STEP; x += COORDS_XY_STEP) + { + map_invalidate_tile_full({ (_loc.x & 0x1F80) + x, (_loc.y & 0x1F80) + y }); + } + } + staff_update_greyed_patrol_areas(); + + return MakeResult(); +} diff --git a/src/openrct2/actions/StaffSetPatrolAreaAction.h b/src/openrct2/actions/StaffSetPatrolAreaAction.h new file mode 100644 index 0000000000..e3d7cd2e29 --- /dev/null +++ b/src/openrct2/actions/StaffSetPatrolAreaAction.h @@ -0,0 +1,37 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../world/Sprite.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(StaffSetPatrolAreaAction, GAME_COMMAND_SET_STAFF_PATROL, GameActions::Result) +{ +private: + uint16_t _spriteId{ SPRITE_INDEX_NULL }; + CoordsXY _loc; + +public: + StaffSetPatrolAreaAction() = default; + StaffSetPatrolAreaAction(uint16_t spriteId, const CoordsXY& loc) + : _spriteId(spriteId) + , _loc(loc) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/StaffSetPatrolAreaAction.hpp b/src/openrct2/actions/StaffSetPatrolAreaAction.hpp deleted file mode 100644 index b1cc95110b..0000000000 --- a/src/openrct2/actions/StaffSetPatrolAreaAction.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../interface/Window.h" -#include "../peep/Peep.h" -#include "../peep/Staff.h" -#include "../world/Sprite.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(StaffSetPatrolAreaAction, GAME_COMMAND_SET_STAFF_PATROL, GameActions::Result) -{ -private: - uint16_t _spriteId{ SPRITE_INDEX_NULL }; - CoordsXY _loc; - -public: - StaffSetPatrolAreaAction() = default; - StaffSetPatrolAreaAction(uint16_t spriteId, const CoordsXY& loc) - : _spriteId(spriteId) - , _loc(loc) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_spriteId) << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - if (_spriteId >= MAX_SPRITES) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto staff = TryGetEntity(_spriteId); - if (staff == nullptr) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - return MakeResult(); - } - - GameActions::Result::Ptr Execute() const override - { - auto staff = TryGetEntity(_spriteId); - if (staff == nullptr) - { - log_error("Invalid spriteId. spriteId = %u", _spriteId); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - int32_t patrolOffset = staff->StaffId * STAFF_PATROL_AREA_SIZE; - - staff_toggle_patrol_area(staff->StaffId, _loc); - - bool isPatrolling = false; - for (int32_t i = 0; i < 128; i++) - { - if (gStaffPatrolAreas[patrolOffset + i]) - { - isPatrolling = true; - break; - } - } - - if (isPatrolling) - { - gStaffModes[staff->StaffId] = StaffMode::Patrol; - } - else if (gStaffModes[staff->StaffId] == StaffMode::Patrol) - { - gStaffModes[staff->StaffId] = StaffMode::Walk; - } - - for (int32_t y = 0; y < 4 * COORDS_XY_STEP; y += COORDS_XY_STEP) - { - for (int32_t x = 0; x < 4 * COORDS_XY_STEP; x += COORDS_XY_STEP) - { - map_invalidate_tile_full({ (_loc.x & 0x1F80) + x, (_loc.y & 0x1F80) + y }); - } - } - staff_update_greyed_patrol_areas(); - - return MakeResult(); - } -}; diff --git a/src/openrct2/actions/SurfaceSetStyleAction.cpp b/src/openrct2/actions/SurfaceSetStyleAction.cpp new file mode 100644 index 0000000000..3921395eb3 --- /dev/null +++ b/src/openrct2/actions/SurfaceSetStyleAction.cpp @@ -0,0 +1,235 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "SurfaceSetStyleAction.h" + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../object/ObjectManager.h" +#include "../object/TerrainEdgeObject.h" +#include "../object/TerrainSurfaceObject.h" +#include "../world/Park.h" +#include "../world/Surface.h" +#include "../world/TileElement.h" + +void SurfaceSetStyleAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range) << DS_TAG(_surfaceStyle) << DS_TAG(_edgeStyle); +} + +GameActions::Result::Ptr SurfaceSetStyleAction::Query() const +{ + auto res = MakeResult(); + res->ErrorTitle = STR_CANT_CHANGE_LAND_TYPE; + res->Expenditure = ExpenditureType::Landscaping; + + auto normRange = _range.Normalise(); + auto x0 = std::max(normRange.GetLeft(), 32); + auto y0 = std::max(normRange.GetTop(), 32); + auto x1 = std::min(normRange.GetRight(), static_cast(gMapSizeMaxXY)); + auto y1 = std::min(normRange.GetBottom(), static_cast(gMapSizeMaxXY)); + + MapRange validRange{ x0, y0, x1, y1 }; + + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) + { + if (_surfaceStyle > 0x1F) + { + log_error("Invalid surface style."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); + } + + const auto surfaceObj = static_cast( + objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); + + if (surfaceObj == nullptr) + { + log_error("Invalid surface style."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); + } + } + + if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) + { + if (_edgeStyle > 0xF) + { + log_error("Invalid edge style."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); + } + + const auto edgeObj = static_cast(objManager.GetLoadedObject(ObjectType::TerrainEdge, _edgeStyle)); + + if (edgeObj == nullptr) + { + log_error("Invalid edge style."); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); + } + } + + auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; + auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; + auto heightMid = tile_element_height({ xMid, yMid }); + + res->Position.x = xMid; + res->Position.y = yMid; + res->Position.z = heightMid; + + // Do nothing if not in editor, sandbox mode or landscaping is forbidden + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode + && (gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES)) + { + return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_LAND_TYPE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); + } + + money32 surfaceCost = 0; + money32 edgeCost = 0; + for (CoordsXY coords = { validRange.GetLeft(), validRange.GetTop() }; coords.x <= validRange.GetRight(); + coords.x += COORDS_XY_STEP) + { + for (coords.y = validRange.GetTop(); coords.y <= validRange.GetBottom(); coords.y += COORDS_XY_STEP) + { + if (!LocationValid(coords)) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(coords)) + continue; + } + + auto surfaceElement = map_get_surface_element_at(coords); + if (surfaceElement == nullptr) + { + continue; + } + + if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) + { + uint8_t curSurfaceStyle = surfaceElement->GetSurfaceStyle(); + + if (_surfaceStyle != curSurfaceStyle) + { + const auto surfaceObject = static_cast( + objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); + if (surfaceObject != nullptr) + { + surfaceCost += surfaceObject->Price; + } + } + } + + if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) + { + uint8_t curEdgeStyle = surfaceElement->GetEdgeStyle(); + + if (_edgeStyle != curEdgeStyle) + { + edgeCost += 100; + } + } + } + } + res->Cost = surfaceCost + edgeCost; + + return res; +} + +GameActions::Result::Ptr SurfaceSetStyleAction::Execute() const +{ + auto res = MakeResult(); + res->ErrorTitle = STR_CANT_CHANGE_LAND_TYPE; + res->Expenditure = ExpenditureType::Landscaping; + + auto normRange = _range.Normalise(); + auto x0 = std::max(normRange.GetLeft(), 32); + auto y0 = std::max(normRange.GetTop(), 32); + auto x1 = std::min(normRange.GetRight(), static_cast(gMapSizeMaxXY)); + auto y1 = std::min(normRange.GetBottom(), static_cast(gMapSizeMaxXY)); + + MapRange validRange{ x0, y0, x1, y1 }; + + auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; + auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; + auto heightMid = tile_element_height({ xMid, yMid }); + + res->Position.x = xMid; + res->Position.y = yMid; + res->Position.z = heightMid; + + money32 surfaceCost = 0; + money32 edgeCost = 0; + for (CoordsXY coords = { validRange.GetLeft(), validRange.GetTop() }; coords.x <= validRange.GetRight(); + coords.x += COORDS_XY_STEP) + { + for (coords.y = validRange.GetTop(); coords.y <= validRange.GetBottom(); coords.y += COORDS_XY_STEP) + { + if (!LocationValid(coords)) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(coords)) + continue; + } + + auto surfaceElement = map_get_surface_element_at(coords); + if (surfaceElement == nullptr) + { + continue; + } + + if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) + { + uint8_t curSurfaceStyle = surfaceElement->GetSurfaceStyle(); + + if (_surfaceStyle != curSurfaceStyle) + { + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + const auto surfaceObject = static_cast( + objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); + if (surfaceObject != nullptr) + { + surfaceCost += surfaceObject->Price; + + surfaceElement->SetSurfaceStyle(_surfaceStyle); + + map_invalidate_tile_full(coords); + footpath_remove_litter({ coords, tile_element_height(coords) }); + } + } + } + + if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) + { + uint8_t curEdgeStyle = surfaceElement->GetEdgeStyle(); + + if (_edgeStyle != curEdgeStyle) + { + edgeCost += 100; + + surfaceElement->SetEdgeStyle(_edgeStyle); + map_invalidate_tile_full(coords); + } + } + + if (surfaceElement->CanGrassGrow() && (surfaceElement->GetGrassLength() & 7) != GRASS_LENGTH_CLEAR_0) + { + surfaceElement->SetGrassLength(GRASS_LENGTH_CLEAR_0); + map_invalidate_tile_full(coords); + } + } + } + res->Cost = surfaceCost + edgeCost; + + return res; +} diff --git a/src/openrct2/actions/SurfaceSetStyleAction.h b/src/openrct2/actions/SurfaceSetStyleAction.h new file mode 100644 index 0000000000..eea5f66d23 --- /dev/null +++ b/src/openrct2/actions/SurfaceSetStyleAction.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(SurfaceSetStyleAction, GAME_COMMAND_CHANGE_SURFACE_STYLE, GameActions::Result) +{ +private: + MapRange _range; + ObjectEntryIndex _surfaceStyle{}; + ObjectEntryIndex _edgeStyle{}; + +public: + SurfaceSetStyleAction() = default; + + SurfaceSetStyleAction(MapRange range, ObjectEntryIndex surfaceStyle, ObjectEntryIndex edgeStyle) + : _range(range) + , _surfaceStyle(surfaceStyle) + , _edgeStyle(edgeStyle) + { + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/SurfaceSetStyleAction.hpp b/src/openrct2/actions/SurfaceSetStyleAction.hpp deleted file mode 100644 index 7d023d6dc9..0000000000 --- a/src/openrct2/actions/SurfaceSetStyleAction.hpp +++ /dev/null @@ -1,255 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Context.h" -#include "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../object/ObjectManager.h" -#include "../object/TerrainEdgeObject.h" -#include "../object/TerrainSurfaceObject.h" -#include "../world/Park.h" -#include "../world/Surface.h" -#include "../world/TileElement.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(SurfaceSetStyleAction, GAME_COMMAND_CHANGE_SURFACE_STYLE, GameActions::Result) -{ -private: - MapRange _range; - ObjectEntryIndex _surfaceStyle{}; - ObjectEntryIndex _edgeStyle{}; - -public: - SurfaceSetStyleAction() = default; - - SurfaceSetStyleAction(MapRange range, ObjectEntryIndex surfaceStyle, ObjectEntryIndex edgeStyle) - : _range(range) - , _surfaceStyle(surfaceStyle) - , _edgeStyle(edgeStyle) - { - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range) << DS_TAG(_surfaceStyle) << DS_TAG(_edgeStyle); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->ErrorTitle = STR_CANT_CHANGE_LAND_TYPE; - res->Expenditure = ExpenditureType::Landscaping; - - auto normRange = _range.Normalise(); - auto x0 = std::max(normRange.GetLeft(), 32); - auto y0 = std::max(normRange.GetTop(), 32); - auto x1 = std::min(normRange.GetRight(), static_cast(gMapSizeMaxXY)); - auto y1 = std::min(normRange.GetBottom(), static_cast(gMapSizeMaxXY)); - - MapRange validRange{ x0, y0, x1, y1 }; - - auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); - if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) - { - if (_surfaceStyle > 0x1F) - { - log_error("Invalid surface style."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); - } - - const auto surfaceObj = static_cast( - objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); - - if (surfaceObj == nullptr) - { - log_error("Invalid surface style."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); - } - } - - if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) - { - if (_edgeStyle > 0xF) - { - log_error("Invalid edge style."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); - } - - const auto edgeObj = static_cast( - objManager.GetLoadedObject(ObjectType::TerrainEdge, _edgeStyle)); - - if (edgeObj == nullptr) - { - log_error("Invalid edge style."); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_LAND_TYPE); - } - } - - auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; - auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; - auto heightMid = tile_element_height({ xMid, yMid }); - - res->Position.x = xMid; - res->Position.y = yMid; - res->Position.z = heightMid; - - // Do nothing if not in editor, sandbox mode or landscaping is forbidden - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode - && (gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES)) - { - return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_LAND_TYPE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); - } - - money32 surfaceCost = 0; - money32 edgeCost = 0; - for (CoordsXY coords = { validRange.GetLeft(), validRange.GetTop() }; coords.x <= validRange.GetRight(); - coords.x += COORDS_XY_STEP) - { - for (coords.y = validRange.GetTop(); coords.y <= validRange.GetBottom(); coords.y += COORDS_XY_STEP) - { - if (!LocationValid(coords)) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(coords)) - continue; - } - - auto surfaceElement = map_get_surface_element_at(coords); - if (surfaceElement == nullptr) - { - continue; - } - - if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) - { - uint8_t curSurfaceStyle = surfaceElement->GetSurfaceStyle(); - - if (_surfaceStyle != curSurfaceStyle) - { - const auto surfaceObject = static_cast( - objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); - if (surfaceObject != nullptr) - { - surfaceCost += surfaceObject->Price; - } - } - } - - if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) - { - uint8_t curEdgeStyle = surfaceElement->GetEdgeStyle(); - - if (_edgeStyle != curEdgeStyle) - { - edgeCost += 100; - } - } - } - } - res->Cost = surfaceCost + edgeCost; - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->ErrorTitle = STR_CANT_CHANGE_LAND_TYPE; - res->Expenditure = ExpenditureType::Landscaping; - - auto normRange = _range.Normalise(); - auto x0 = std::max(normRange.GetLeft(), 32); - auto y0 = std::max(normRange.GetTop(), 32); - auto x1 = std::min(normRange.GetRight(), static_cast(gMapSizeMaxXY)); - auto y1 = std::min(normRange.GetBottom(), static_cast(gMapSizeMaxXY)); - - MapRange validRange{ x0, y0, x1, y1 }; - - auto xMid = (validRange.GetLeft() + validRange.GetRight()) / 2 + 16; - auto yMid = (validRange.GetTop() + validRange.GetBottom()) / 2 + 16; - auto heightMid = tile_element_height({ xMid, yMid }); - - res->Position.x = xMid; - res->Position.y = yMid; - res->Position.z = heightMid; - - money32 surfaceCost = 0; - money32 edgeCost = 0; - for (CoordsXY coords = { validRange.GetLeft(), validRange.GetTop() }; coords.x <= validRange.GetRight(); - coords.x += COORDS_XY_STEP) - { - for (coords.y = validRange.GetTop(); coords.y <= validRange.GetBottom(); coords.y += COORDS_XY_STEP) - { - if (!LocationValid(coords)) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(coords)) - continue; - } - - auto surfaceElement = map_get_surface_element_at(coords); - if (surfaceElement == nullptr) - { - continue; - } - - if (_surfaceStyle != OBJECT_ENTRY_INDEX_NULL) - { - uint8_t curSurfaceStyle = surfaceElement->GetSurfaceStyle(); - - if (_surfaceStyle != curSurfaceStyle) - { - auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); - const auto surfaceObject = static_cast( - objManager.GetLoadedObject(ObjectType::TerrainSurface, _surfaceStyle)); - if (surfaceObject != nullptr) - { - surfaceCost += surfaceObject->Price; - - surfaceElement->SetSurfaceStyle(_surfaceStyle); - - map_invalidate_tile_full(coords); - footpath_remove_litter({ coords, tile_element_height(coords) }); - } - } - } - - if (_edgeStyle != OBJECT_ENTRY_INDEX_NULL) - { - uint8_t curEdgeStyle = surfaceElement->GetEdgeStyle(); - - if (_edgeStyle != curEdgeStyle) - { - edgeCost += 100; - - surfaceElement->SetEdgeStyle(_edgeStyle); - map_invalidate_tile_full(coords); - } - } - - if (surfaceElement->CanGrassGrow() && (surfaceElement->GetGrassLength() & 7) != GRASS_LENGTH_CLEAR_0) - { - surfaceElement->SetGrassLength(GRASS_LENGTH_CLEAR_0); - map_invalidate_tile_full(coords); - } - } - } - res->Cost = surfaceCost + edgeCost; - - return res; - } -}; diff --git a/src/openrct2/actions/TileModifyAction.cpp b/src/openrct2/actions/TileModifyAction.cpp new file mode 100644 index 0000000000..fc51709ed7 --- /dev/null +++ b/src/openrct2/actions/TileModifyAction.cpp @@ -0,0 +1,212 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "TileModifyAction.h" + +#include "../world/TileInspector.h" + +void TileModifyAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_setting) << DS_TAG(_value1) << DS_TAG(_value2) << DS_TAG(_pasteElement); +} + +GameActions::Result::Ptr TileModifyAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr TileModifyAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr TileModifyAction::QueryExecute(bool isExecuting) const +{ + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); + } + auto res = MakeResult(); + switch (_setting) + { + case TileModifyType::AnyRemove: + { + const auto elementIndex = _value1; + res = tile_inspector_remove_element_at(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::AnySwap: + { + const auto firstIndex = _value1; + const auto secondIndex = _value2; + res = tile_inspector_swap_elements_at(_loc, firstIndex, secondIndex, isExecuting); + break; + } + case TileModifyType::AnyInsertCorrupt: + { + const auto elementIndex = _value1; + res = tile_inspector_insert_corrupt_at(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::AnyRotate: + { + const auto elementIndex = _value1; + res = tile_inspector_rotate_element_at(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::AnyPaste: + { + res = tile_inspector_paste_element_at(_loc, _pasteElement, isExecuting); + break; + } + case TileModifyType::AnySort: + { + res = tile_inspector_sort_elements_at(_loc, isExecuting); + break; + } + case TileModifyType::AnyBaseHeightOffset: + { + const auto elementIndex = _value1; + const auto heightOffset = _value2; + res = tile_inspector_any_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); + break; + } + case TileModifyType::SurfaceShowParkFences: + { + const bool showFences = _value1; + res = tile_inspector_surface_show_park_fences(_loc, showFences, isExecuting); + break; + } + case TileModifyType::SurfaceToggleCorner: + { + const auto cornerIndex = _value1; + res = tile_inspector_surface_toggle_corner(_loc, cornerIndex, isExecuting); + break; + } + case TileModifyType::SurfaceToggleDiagonal: + { + res = tile_inspector_surface_toggle_diagonal(_loc, isExecuting); + break; + } + case TileModifyType::PathSetSlope: + { + const auto elementIndex = _value1; + const bool sloped = _value2; + res = tile_inspector_path_set_sloped(_loc, elementIndex, sloped, isExecuting); + break; + } + case TileModifyType::PathSetBroken: + { + const auto elementIndex = _value1; + const bool broken = _value2; + res = tile_inspector_path_set_broken(_loc, elementIndex, broken, isExecuting); + break; + } + case TileModifyType::PathToggleEdge: + { + const auto elementIndex = _value1; + const auto edgeIndex = _value2; + res = tile_inspector_path_toggle_edge(_loc, elementIndex, edgeIndex, isExecuting); + break; + } + case TileModifyType::EntranceMakeUsable: + { + const auto elementIndex = _value1; + res = tile_inspector_entrance_make_usable(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::WallSetSlope: + { + const auto elementIndex = _value1; + const auto slopeValue = _value2; + res = tile_inspector_wall_set_slope(_loc, elementIndex, slopeValue, isExecuting); + break; + } + case TileModifyType::WallSetAnimationFrame: + { + const auto elementIndex = _value1; + const auto animationFrameOffset = _value2; + res = tile_inspector_wall_animation_frame_offset(_loc, elementIndex, animationFrameOffset, isExecuting); + break; + } + case TileModifyType::TrackBaseHeightOffset: + { + const auto elementIndex = _value1; + const auto heightOffset = _value2; + res = tile_inspector_track_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); + break; + } + case TileModifyType::TrackSetChainBlock: + { + const auto elementIndex = _value1; + const bool setChain = _value2; + res = tile_inspector_track_set_chain(_loc, elementIndex, true, setChain, isExecuting); + break; + } + case TileModifyType::TrackSetChain: + { + const auto elementIndex = _value1; + const bool setChain = _value2; + res = tile_inspector_track_set_chain(_loc, elementIndex, false, setChain, isExecuting); + break; + } + case TileModifyType::TrackSetBlockBrake: + { + const auto elementIndex = _value1; + const bool blockBrake = _value2; + res = tile_inspector_track_set_block_brake(_loc, elementIndex, blockBrake, isExecuting); + break; + } + case TileModifyType::TrackSetIndestructible: + { + const auto elementIndex = _value1; + const bool isIndestructible = _value2; + res = tile_inspector_track_set_indestructible(_loc, elementIndex, isIndestructible, isExecuting); + break; + } + case TileModifyType::ScenerySetQuarterLocation: + { + const auto elementIndex = _value1; + const auto quarterIndex = _value2; + res = tile_inspector_scenery_set_quarter_location(_loc, elementIndex, quarterIndex, isExecuting); + break; + } + case TileModifyType::ScenerySetQuarterCollision: + { + const auto elementIndex = _value1; + const auto quarterIndex = _value2; + res = tile_inspector_scenery_set_quarter_collision(_loc, elementIndex, quarterIndex, isExecuting); + break; + } + case TileModifyType::BannerToggleBlockingEdge: + { + const auto elementIndex = _value1; + const auto edgeIndex = _value2; + res = tile_inspector_banner_toggle_blocking_edge(_loc, elementIndex, edgeIndex, isExecuting); + break; + } + case TileModifyType::CorruptClamp: + { + const auto elementIndex = _value1; + res = tile_inspector_corrupt_clamp(_loc, elementIndex, isExecuting); + break; + } + default: + log_error("invalid instruction"); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + res->Position.x = _loc.x; + res->Position.y = _loc.y; + res->Position.z = tile_element_height(_loc); + + return res; +} diff --git a/src/openrct2/actions/TileModifyAction.h b/src/openrct2/actions/TileModifyAction.h new file mode 100644 index 0000000000..a51e0e53a3 --- /dev/null +++ b/src/openrct2/actions/TileModifyAction.h @@ -0,0 +1,76 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +enum class TileModifyType : uint8_t +{ + AnyRemove, + AnySwap, + AnyInsertCorrupt, + AnyRotate, + AnyPaste, + AnySort, + AnyBaseHeightOffset, + SurfaceShowParkFences, + SurfaceToggleCorner, + SurfaceToggleDiagonal, + PathSetSlope, + PathSetBroken, + PathToggleEdge, + EntranceMakeUsable, + WallSetSlope, + WallSetAnimationFrame, + TrackBaseHeightOffset, + TrackSetChain, + TrackSetChainBlock, + TrackSetBlockBrake, + TrackSetIndestructible, + ScenerySetQuarterLocation, + ScenerySetQuarterCollision, + BannerToggleBlockingEdge, + CorruptClamp, + Count, +}; + +DEFINE_GAME_ACTION(TileModifyAction, GAME_COMMAND_MODIFY_TILE, GameActions::Result) +{ +private: + CoordsXY _loc; + TileModifyType _setting{}; + uint32_t _value1{}; + uint32_t _value2{}; + TileElement _pasteElement{}; + +public: + TileModifyAction() = default; + TileModifyAction( + CoordsXY loc, TileModifyType setting, uint32_t value1 = 0, uint32_t value2 = 0, TileElement pasteElement = {}) + : _loc(loc) + , _setting(setting) + , _value1(value1) + , _value2(value2) + , _pasteElement(pasteElement) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/TileModifyAction.hpp b/src/openrct2/actions/TileModifyAction.hpp deleted file mode 100644 index 26f0e9ec07..0000000000 --- a/src/openrct2/actions/TileModifyAction.hpp +++ /dev/null @@ -1,272 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../world/TileInspector.h" -#include "GameAction.h" - -enum class TileModifyType : uint8_t -{ - AnyRemove, - AnySwap, - AnyInsertCorrupt, - AnyRotate, - AnyPaste, - AnySort, - AnyBaseHeightOffset, - SurfaceShowParkFences, - SurfaceToggleCorner, - SurfaceToggleDiagonal, - PathSetSlope, - PathSetBroken, - PathToggleEdge, - EntranceMakeUsable, - WallSetSlope, - WallSetAnimationFrame, - TrackBaseHeightOffset, - TrackSetChain, - TrackSetChainBlock, - TrackSetBlockBrake, - TrackSetIndestructible, - ScenerySetQuarterLocation, - ScenerySetQuarterCollision, - BannerToggleBlockingEdge, - CorruptClamp, - Count, -}; - -DEFINE_GAME_ACTION(TileModifyAction, GAME_COMMAND_MODIFY_TILE, GameActions::Result) -{ -private: - CoordsXY _loc; - TileModifyType _setting{}; - uint32_t _value1{}; - uint32_t _value2{}; - TileElement _pasteElement{}; - -public: - TileModifyAction() = default; - TileModifyAction( - CoordsXY loc, TileModifyType setting, uint32_t value1 = 0, uint32_t value2 = 0, TileElement pasteElement = {}) - : _loc(loc) - , _setting(setting) - , _value1(value1) - , _value2(value2) - , _pasteElement(pasteElement) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_setting) << DS_TAG(_value1) << DS_TAG(_value2) << DS_TAG(_pasteElement); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_LAND_NOT_OWNED_BY_PARK); - } - auto res = MakeResult(); - switch (_setting) - { - case TileModifyType::AnyRemove: - { - const auto elementIndex = _value1; - res = tile_inspector_remove_element_at(_loc, elementIndex, isExecuting); - break; - } - case TileModifyType::AnySwap: - { - const auto firstIndex = _value1; - const auto secondIndex = _value2; - res = tile_inspector_swap_elements_at(_loc, firstIndex, secondIndex, isExecuting); - break; - } - case TileModifyType::AnyInsertCorrupt: - { - const auto elementIndex = _value1; - res = tile_inspector_insert_corrupt_at(_loc, elementIndex, isExecuting); - break; - } - case TileModifyType::AnyRotate: - { - const auto elementIndex = _value1; - res = tile_inspector_rotate_element_at(_loc, elementIndex, isExecuting); - break; - } - case TileModifyType::AnyPaste: - { - res = tile_inspector_paste_element_at(_loc, _pasteElement, isExecuting); - break; - } - case TileModifyType::AnySort: - { - res = tile_inspector_sort_elements_at(_loc, isExecuting); - break; - } - case TileModifyType::AnyBaseHeightOffset: - { - const auto elementIndex = _value1; - const auto heightOffset = _value2; - res = tile_inspector_any_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); - break; - } - case TileModifyType::SurfaceShowParkFences: - { - const bool showFences = _value1; - res = tile_inspector_surface_show_park_fences(_loc, showFences, isExecuting); - break; - } - case TileModifyType::SurfaceToggleCorner: - { - const auto cornerIndex = _value1; - res = tile_inspector_surface_toggle_corner(_loc, cornerIndex, isExecuting); - break; - } - case TileModifyType::SurfaceToggleDiagonal: - { - res = tile_inspector_surface_toggle_diagonal(_loc, isExecuting); - break; - } - case TileModifyType::PathSetSlope: - { - const auto elementIndex = _value1; - const bool sloped = _value2; - res = tile_inspector_path_set_sloped(_loc, elementIndex, sloped, isExecuting); - break; - } - case TileModifyType::PathSetBroken: - { - const auto elementIndex = _value1; - const bool broken = _value2; - res = tile_inspector_path_set_broken(_loc, elementIndex, broken, isExecuting); - break; - } - case TileModifyType::PathToggleEdge: - { - const auto elementIndex = _value1; - const auto edgeIndex = _value2; - res = tile_inspector_path_toggle_edge(_loc, elementIndex, edgeIndex, isExecuting); - break; - } - case TileModifyType::EntranceMakeUsable: - { - const auto elementIndex = _value1; - res = tile_inspector_entrance_make_usable(_loc, elementIndex, isExecuting); - break; - } - case TileModifyType::WallSetSlope: - { - const auto elementIndex = _value1; - const auto slopeValue = _value2; - res = tile_inspector_wall_set_slope(_loc, elementIndex, slopeValue, isExecuting); - break; - } - case TileModifyType::WallSetAnimationFrame: - { - const auto elementIndex = _value1; - const auto animationFrameOffset = _value2; - res = tile_inspector_wall_animation_frame_offset(_loc, elementIndex, animationFrameOffset, isExecuting); - break; - } - case TileModifyType::TrackBaseHeightOffset: - { - const auto elementIndex = _value1; - const auto heightOffset = _value2; - res = tile_inspector_track_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); - break; - } - case TileModifyType::TrackSetChainBlock: - { - const auto elementIndex = _value1; - const bool setChain = _value2; - res = tile_inspector_track_set_chain(_loc, elementIndex, true, setChain, isExecuting); - break; - } - case TileModifyType::TrackSetChain: - { - const auto elementIndex = _value1; - const bool setChain = _value2; - res = tile_inspector_track_set_chain(_loc, elementIndex, false, setChain, isExecuting); - break; - } - case TileModifyType::TrackSetBlockBrake: - { - const auto elementIndex = _value1; - const bool blockBrake = _value2; - res = tile_inspector_track_set_block_brake(_loc, elementIndex, blockBrake, isExecuting); - break; - } - case TileModifyType::TrackSetIndestructible: - { - const auto elementIndex = _value1; - const bool isIndestructible = _value2; - res = tile_inspector_track_set_indestructible(_loc, elementIndex, isIndestructible, isExecuting); - break; - } - case TileModifyType::ScenerySetQuarterLocation: - { - const auto elementIndex = _value1; - const auto quarterIndex = _value2; - res = tile_inspector_scenery_set_quarter_location(_loc, elementIndex, quarterIndex, isExecuting); - break; - } - case TileModifyType::ScenerySetQuarterCollision: - { - const auto elementIndex = _value1; - const auto quarterIndex = _value2; - res = tile_inspector_scenery_set_quarter_collision(_loc, elementIndex, quarterIndex, isExecuting); - break; - } - case TileModifyType::BannerToggleBlockingEdge: - { - const auto elementIndex = _value1; - const auto edgeIndex = _value2; - res = tile_inspector_banner_toggle_blocking_edge(_loc, elementIndex, edgeIndex, isExecuting); - break; - } - case TileModifyType::CorruptClamp: - { - const auto elementIndex = _value1; - res = tile_inspector_corrupt_clamp(_loc, elementIndex, isExecuting); - break; - } - default: - log_error("invalid instruction"); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - break; - } - - res->Position.x = _loc.x; - res->Position.y = _loc.y; - res->Position.z = tile_element_height(_loc); - - return res; - } -}; diff --git a/src/openrct2/actions/TrackDesignAction.cpp b/src/openrct2/actions/TrackDesignAction.cpp index aa3df02c0c..a4df7d9f31 100644 --- a/src/openrct2/actions/TrackDesignAction.cpp +++ b/src/openrct2/actions/TrackDesignAction.cpp @@ -15,11 +15,11 @@ #include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" #include "../ride/TrackDesign.h" -#include "RideCreateAction.hpp" -#include "RideDemolishAction.hpp" -#include "RideSetName.hpp" -#include "RideSetSetting.hpp" -#include "RideSetVehiclesAction.hpp" +#include "RideCreateAction.h" +#include "RideDemolishAction.h" +#include "RideSetNameAction.h" +#include "RideSetSettingAction.h" +#include "RideSetVehicleAction.h" static int32_t place_virtual_track( const TrackDesign& td6, uint8_t ptdOperation, bool placeScenery, Ride* ride, const CoordsXYZ& loc) diff --git a/src/openrct2/actions/TrackPlaceAction.cpp b/src/openrct2/actions/TrackPlaceAction.cpp new file mode 100644 index 0000000000..b948a67157 --- /dev/null +++ b/src/openrct2/actions/TrackPlaceAction.cpp @@ -0,0 +1,670 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "TrackPlaceAction.h" + +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../ride/Track.h" +#include "../ride/TrackData.h" +#include "../ride/TrackDesign.h" +#include "../util/Util.h" +#include "../world/MapAnimation.h" +#include "../world/Surface.h" +#include "RideSetSettingAction.h" + +void TrackPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_origin); + visitor.Visit("ride", _rideIndex); + visitor.Visit("trackType", _trackType); + visitor.Visit("brakeSpeed", _brakeSpeed); + visitor.Visit("colour", _colour); + visitor.Visit("seatRotation", _seatRotation); + visitor.Visit("trackPlaceFlags", _trackPlaceFlags); + visitor.Visit("isFromTrackDesign", _fromTrackDesign); +} + +void TrackPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_rideIndex) << DS_TAG(_trackType) << DS_TAG(_origin) << DS_TAG(_brakeSpeed) << DS_TAG(_colour) + << DS_TAG(_seatRotation) << DS_TAG(_trackPlaceFlags); +} + +GameActions::Result::Ptr TrackPlaceAction::Query() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride for track placement, rideIndex = %d", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid ride subtype for track placement, rideIndex = %d", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (!direction_valid(_origin.direction)) + { + log_warning("Invalid direction for track placement, direction = %d", _origin.direction); + return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + } + + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::RideConstruction; + res->Position.x = _origin.x + 16; + res->Position.y = _origin.y + 16; + res->Position.z = _origin.z; + + res->GroundFlags = 0; + + uint32_t rideTypeFlags = RideTypeDescriptors[ride->type].Flags; + + if ((ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) && _trackType == TrackElemType::EndStation) + { + return std::make_unique(GameActions::Status::Disallowed, STR_NOT_ALLOWED_TO_MODIFY_STATION); + } + + if (!(GetActionFlags() & GameActions::Flags::AllowWhilePaused)) + { + if (game_is_paused() && !gCheatsBuildInPauseMode) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED); + } + } + + if (!(rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE)) + { + if (_trackType == TrackElemType::OnRidePhoto) + { + if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_ONLY_ONE_ON_RIDE_PHOTO_PER_RIDE); + } + } + else if (_trackType == TrackElemType::CableLiftHill) + { + if (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_ONLY_ONE_CABLE_LIFT_HILL_PER_RIDE); + } + } + // Backwards steep lift hills are allowed, even on roller coasters that do not support forwards steep lift hills. + if ((_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED) + && !RideTypeDescriptors[ride->type].SupportsTrackPiece(TRACK_LIFT_HILL_STEEP) && !gCheatsEnableChainLiftOnAllTrack) + { + if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_IS_STEEP_UP) + { + return std::make_unique(GameActions::Status::Disallowed, STR_TOO_STEEP_FOR_LIFT_HILL); + } + } + } + + money32 cost = 0; + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, _trackType); + uint32_t numElements = 0; + // First check if any of the track pieces are outside the park + for (; trackBlock->index != 0xFF; trackBlock++) + { + auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), 0 }; + auto tileCoords = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; + + if (!LocationValid(tileCoords) || (!map_is_location_owned(tileCoords) && !gCheatsSandboxMode)) + { + return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + } + numElements++; + } + + if (!map_check_free_elements_and_reorganise(numElements)) + { + log_warning("Not enough free map elments to place track."); + return std::make_unique(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); + } + const uint16_t* trackFlags = (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatTrackFlags : TrackFlags; + if (!gCheatsAllowTrackPlaceInvalidHeights) + { + if (trackFlags[_trackType] & TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT) + { + if ((_origin.z & 0x0F) != 8) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CONSTRUCTION_ERR_UNKNOWN); + } + } + else + { + if ((_origin.z & 0x0F) != 0) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CONSTRUCTION_ERR_UNKNOWN); + } + } + } + + // If that is not the case, then perform the remaining checks + trackBlock = get_track_def_from_ride(ride, _trackType); + + for (int32_t blockIndex = 0; trackBlock->index != 0xFF; trackBlock++, blockIndex++) + { + auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), trackBlock->z }; + auto mapLoc = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; + auto quarterTile = trackBlock->var_08.Rotate(_origin.direction); + + if (mapLoc.z < 16) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_TOO_LOW); + } + + int32_t baseZ = floor2(mapLoc.z, COORDS_Z_STEP); + + int32_t clearanceZ = trackBlock->var_07; + if (trackBlock->flags & RCT_PREVIEW_TRACK_FLAG_IS_VERTICAL + && RideTypeDescriptors[ride->type].Heights.ClearanceHeight > 24) + { + clearanceZ += 24; + } + else + { + clearanceZ += RideTypeDescriptors[ride->type].Heights.ClearanceHeight; + } + + clearanceZ = floor2(clearanceZ, COORDS_Z_STEP) + baseZ; + + if (clearanceZ > MAX_TRACK_HEIGHT) + { + return std::make_unique(GameActions::Status::InvalidParameters, STR_TOO_HIGH); + } + + uint8_t crossingMode = (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS) + && _trackType == TrackElemType::Flat) + ? CREATE_CROSSING_MODE_TRACK_OVER_PATH + : CREATE_CROSSING_MODE_NONE; + if (!map_can_construct_with_clear_at( + { mapLoc, baseZ, clearanceZ }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &cost, crossingMode)) + { + return std::make_unique( + GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); + } + + // When building a level crossing, remove any pre-existing path furniture. + if (crossingMode == CREATE_CROSSING_MODE_TRACK_OVER_PATH) + { + auto footpathElement = map_get_footpath_element(mapLoc); + if (footpathElement != nullptr && footpathElement->AsPath()->HasAddition()) + { + footpathElement->AsPath()->SetAddition(0); + } + } + + uint8_t mapGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + if (res->GroundFlags != 0 && (res->GroundFlags & mapGroundFlags) == 0) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); + } + + res->GroundFlags = mapGroundFlags; + if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) + { + if (FlatTrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_ABOVE_GROUND) + { + if (res->GroundFlags & ELEMENT_IS_UNDERGROUND) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + } + } + else + { + if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_ABOVE_GROUND) + { + if (res->GroundFlags & ELEMENT_IS_UNDERGROUND) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + } + } + + if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) + { + if (FlatTrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_UNDERWATER) + { + if (!(gMapGroundFlags & ELEMENT_IS_UNDERWATER)) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_UNDERWATER); + } + } + } + else + { + if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_UNDERWATER) + { // No element has this flag + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_UNDERWATER); + } + } + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER && !gCheatsDisableClearanceChecks) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); + } + + if ((rideTypeFlags & RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER) && !byte_9D8150) + { + auto surfaceElement = map_get_surface_element_at(mapLoc); + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + auto waterHeight = surfaceElement->GetWaterHeight(); + if (waterHeight == 0) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); + } + + if (waterHeight != baseZ) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); + } + waterHeight -= LAND_HEIGHT_STEP; + if (waterHeight == surfaceElement->GetBaseZ()) + { + uint8_t slope = surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP; + if (slope == TILE_ELEMENT_SLOPE_W_CORNER_DN || slope == TILE_ELEMENT_SLOPE_S_CORNER_DN + || slope == TILE_ELEMENT_SLOPE_E_CORNER_DN || slope == TILE_ELEMENT_SLOPE_N_CORNER_DN) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); + } + } + } + + int32_t entranceDirections; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; + } + else + { + entranceDirections = TrackSequenceProperties[_trackType][0]; + } + if ((entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN) && trackBlock->index == 0) + { + if (!track_add_station_element({ mapLoc, baseZ, _origin.direction }, _rideIndex, 0, _fromTrackDesign)) + { + return std::make_unique(GameActions::Status::Unknown, gGameCommandErrorText); + } + } + + // 6c5648 12 push + auto surfaceElement = map_get_surface_element_at(mapLoc); + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (!gCheatsDisableSupportLimits) + { + int32_t ride_height = clearanceZ - surfaceElement->GetBaseZ(); + if (ride_height >= 0) + { + uint16_t maxHeight; + + if (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY) + && rideEntry->max_height != 0) + { + maxHeight = rideEntry->max_height; + } + else + { + maxHeight = RideTypeDescriptors[ride->type].Heights.MaxHeight; + } + + ride_height /= COORDS_Z_PER_TINY_Z; + if (ride_height > maxHeight && !byte_9D8150) + { + return std::make_unique(GameActions::Status::Disallowed, STR_TOO_HIGH_FOR_SUPPORTS); + } + } + } + + int32_t supportHeight = baseZ - surfaceElement->GetBaseZ(); + if (supportHeight < 0) + { + supportHeight = (10 * COORDS_Z_STEP); + } + + cost += ((supportHeight / (2 * COORDS_Z_STEP)) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice) * 5; + } + + money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; + price *= (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatRideTrackPricing[_trackType] : TrackPricing[_trackType]; + + price >>= 16; + res->Cost = cost + ((price / 2) * 10); + return res; +} + +GameActions::Result::Ptr TrackPlaceAction::Execute() const +{ + auto ride = get_ride(_rideIndex); + if (ride == nullptr) + { + log_warning("Invalid ride for track placement, rideIndex = %d", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); + if (rideEntry == nullptr) + { + log_warning("Invalid ride subtype for track placement, rideIndex = %d", static_cast(_rideIndex)); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + auto res = std::make_unique(); + res->Expenditure = ExpenditureType::RideConstruction; + res->Position.x = _origin.x + 16; + res->Position.y = _origin.y + 16; + res->Position.z = _origin.z; + + res->GroundFlags = 0; + + uint32_t rideTypeFlags = RideTypeDescriptors[ride->type].Flags; + + const uint8_t(*wallEdges)[16]; + if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) + { + wallEdges = &FlatRideTrackSequenceElementAllowedWallEdges[_trackType]; + } + else + { + wallEdges = &TrackSequenceElementAllowedWallEdges[_trackType]; + } + + money32 cost = 0; + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, _trackType); + + trackBlock = get_track_def_from_ride(ride, _trackType); + for (int32_t blockIndex = 0; trackBlock->index != 0xFF; trackBlock++, blockIndex++) + { + auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), trackBlock->z }; + auto mapLoc = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; + + auto quarterTile = trackBlock->var_08.Rotate(_origin.direction); + + int32_t baseZ = floor2(mapLoc.z, COORDS_Z_STEP); + int32_t clearanceZ = trackBlock->var_07; + if (trackBlock->flags & RCT_PREVIEW_TRACK_FLAG_IS_VERTICAL + && RideTypeDescriptors[ride->type].Heights.ClearanceHeight > 24) + { + clearanceZ += 24; + } + else + { + clearanceZ += RideTypeDescriptors[ride->type].Heights.ClearanceHeight; + } + + clearanceZ = floor2(clearanceZ, COORDS_Z_STEP) + baseZ; + const auto mapLocWithClearance = CoordsXYRangedZ(mapLoc, baseZ, clearanceZ); + + uint8_t crossingMode = (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS) + && _trackType == TrackElemType::Flat) + ? CREATE_CROSSING_MODE_TRACK_OVER_PATH + : CREATE_CROSSING_MODE_NONE; + if (!map_can_construct_with_clear_at( + mapLocWithClearance, &map_place_non_scenery_clear_func, quarterTile, GetFlags() | GAME_COMMAND_FLAG_APPLY, + &cost, crossingMode)) + { + return std::make_unique( + GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsDisableClearanceChecks) + { + footpath_remove_litter(mapLoc); + if (rideTypeFlags & RIDE_TYPE_FLAG_TRACK_NO_WALLS) + { + wall_remove_at(mapLocWithClearance); + } + else + { + // Remove walls in the directions this track intersects + uint8_t intersectingDirections = (*wallEdges)[blockIndex]; + intersectingDirections ^= 0x0F; + intersectingDirections = rol4(intersectingDirections, _origin.direction); + for (int32_t i = 0; i < NumOrthogonalDirections; i++) + { + if (intersectingDirections & (1 << i)) + { + wall_remove_intersecting_walls(mapLocWithClearance, i); + } + } + } + } + + uint8_t mapGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + if (res->GroundFlags != 0 && (res->GroundFlags & mapGroundFlags) == 0) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); + } + + res->GroundFlags = mapGroundFlags; + + // 6c5648 12 push + auto surfaceElement = map_get_surface_element_at(mapLoc); + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + int32_t supportHeight = baseZ - surfaceElement->GetBaseZ(); + if (supportHeight < 0) + { + supportHeight = (10 * COORDS_Z_STEP); + } + + cost += ((supportHeight / (2 * COORDS_Z_STEP)) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice) * 5; + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + invalidate_test_results(ride); + switch (_trackType) + { + case TrackElemType::OnRidePhoto: + ride->lifecycle_flags |= RIDE_LIFECYCLE_ON_RIDE_PHOTO; + break; + case TrackElemType::CableLiftHill: + if (trackBlock->index != 0) + break; + ride->lifecycle_flags |= RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED; + ride->CableLiftLoc = mapLoc; + break; + case TrackElemType::BlockBrakes: + { + ride->num_block_brakes++; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_OPERATING; + + RideMode newMode = RideMode::ContinuousCircuitBlockSectioned; + if (ride->type == RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER) + newMode = RideMode::PoweredLaunchBlockSectioned; + + auto rideSetSetting = RideSetSettingAction(ride->id, RideSetSetting::Mode, static_cast(newMode)); + GameActions::ExecuteNested(&rideSetSetting); + break; + } + } + + if (trackBlock->index == 0) + { + switch (_trackType) + { + case TrackElemType::Up25ToFlat: + case TrackElemType::Up60ToFlat: + case TrackElemType::DiagUp25ToFlat: + case TrackElemType::DiagUp60ToFlat: + if (!(_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED)) + break; + [[fallthrough]]; + case TrackElemType::CableLiftHill: + ride->num_block_brakes++; + break; + } + } + } + + int32_t entranceDirections = 0; + if (!ride->overall_view.isNull()) + { + if (!(GetFlags() & GAME_COMMAND_FLAG_NO_SPEND)) + { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; + } + else + { + entranceDirections = TrackSequenceProperties[_trackType][0]; + } + } + } + + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN || ride->overall_view.isNull()) + { + ride->overall_view = mapLoc; + } + + auto tileElement = tile_element_insert(mapLoc, quarterTile.GetBaseQuarterOccupied()); + assert(tileElement != nullptr); + tileElement->SetClearanceZ(clearanceZ); + tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); + tileElement->SetDirection(_origin.direction); + if (_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED) + { + tileElement->AsTrack()->SetHasChain(true); + } + + tileElement->AsTrack()->SetSequenceIndex(trackBlock->index); + tileElement->AsTrack()->SetRideIndex(_rideIndex); + tileElement->AsTrack()->SetTrackType(_trackType); + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + tileElement->SetGhost(true); + } + + switch (_trackType) + { + case TrackElemType::Waterfall: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_WATERFALL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + break; + case TrackElemType::Rapids: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_RAPIDS, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + break; + case TrackElemType::Whirlpool: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + break; + case TrackElemType::SpinningTunnel: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + break; + } + if (TrackTypeHasSpeedSetting(_trackType)) + { + tileElement->AsTrack()->SetBrakeBoosterSpeed(_brakeSpeed); + } + else + { + tileElement->AsTrack()->SetSeatRotation(_seatRotation); + } + + if (_trackPlaceFlags & RIDE_TYPE_ALTERNATIVE_TRACK_TYPE) + { + tileElement->AsTrack()->SetInverted(true); + } + tileElement->AsTrack()->SetColourScheme(_colour); + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; + } + else + { + entranceDirections = TrackSequenceProperties[_trackType][0]; + } + + if (entranceDirections & TRACK_SEQUENCE_FLAG_CONNECTS_TO_PATH) + { + uint8_t availableDirections = entranceDirections & 0x0F; + if (availableDirections != 0) + { + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsDisableClearanceChecks) + { + for (int32_t chosenDirection = bitscanforward(availableDirections); chosenDirection != -1; + chosenDirection = bitscanforward(availableDirections)) + { + availableDirections &= ~(1 << chosenDirection); + CoordsXY tempLoc{ mapLoc.x, mapLoc.y }; + int32_t tempDirection = (_origin.direction + chosenDirection) & 3; + tempLoc.x += CoordsDirectionDelta[tempDirection].x; + tempLoc.y += CoordsDirectionDelta[tempDirection].y; + tempDirection = direction_reverse(tempDirection); + wall_remove_intersecting_walls({ tempLoc, baseZ, clearanceZ }, tempDirection & 3); + } + } + } + } + + // If the placed tile is a station modify station properties. + // Don't do this if the ride is simulating and the tile is a ghost to prevent desyncs. + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN + && !(ride->status == RIDE_STATUS_SIMULATING && GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + if (trackBlock->index == 0) + { + track_add_station_element({ mapLoc, _origin.direction }, _rideIndex, GAME_COMMAND_FLAG_APPLY, _fromTrackDesign); + } + sub_6CB945(ride); + ride->UpdateMaxVehicles(); + } + + if (rideTypeFlags & RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER) + { + auto* waterSurfaceElement = map_get_surface_element_at(mapLoc); + if (waterSurfaceElement != nullptr) + { + waterSurfaceElement->SetHasTrackThatNeedsWater(true); + tileElement = reinterpret_cast(waterSurfaceElement); + } + } + + if (!gCheatsDisableClearanceChecks || !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_connect_edges(mapLoc, tileElement, GetFlags()); + } + map_invalidate_tile_full(mapLoc); + } + + money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; + price *= (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatRideTrackPricing[_trackType] : TrackPricing[_trackType]; + + price >>= 16; + res->Cost = cost + ((price / 2) * 10); + return res; +} diff --git a/src/openrct2/actions/TrackPlaceAction.h b/src/openrct2/actions/TrackPlaceAction.h new file mode 100644 index 0000000000..5f74f1c8e3 --- /dev/null +++ b/src/openrct2/actions/TrackPlaceAction.h @@ -0,0 +1,76 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +class TrackPlaceActionResult final : public GameActions::Result +{ +public: + TrackPlaceActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE) + { + } + TrackPlaceActionResult(GameActions::Status error) + : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE) + { + } + TrackPlaceActionResult(GameActions::Status error, rct_string_id message) + : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message) + { + } + TrackPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) + : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message, args) + { + } + + uint8_t GroundFlags{ 0 }; +}; + +DEFINE_GAME_ACTION(TrackPlaceAction, GAME_COMMAND_PLACE_TRACK, TrackPlaceActionResult) +{ +private: + NetworkRideId_t _rideIndex{ RideIdNewNull }; + int32_t _trackType{}; + CoordsXYZD _origin; + int32_t _brakeSpeed{}; + int32_t _colour{}; + int32_t _seatRotation{}; + int32_t _trackPlaceFlags{}; + bool _fromTrackDesign{}; + +public: + TrackPlaceAction() = default; + TrackPlaceAction( + NetworkRideId_t rideIndex, int32_t trackType, const CoordsXYZD& origin, int32_t brakeSpeed, int32_t colour, + int32_t seatRotation, int32_t liftHillAndAlternativeState, bool fromTrackDesign) + : _rideIndex(rideIndex) + , _trackType(trackType) + , _origin(origin) + , _brakeSpeed(brakeSpeed) + , _colour(colour) + , _seatRotation(seatRotation) + , _trackPlaceFlags(liftHillAndAlternativeState) + , _fromTrackDesign(fromTrackDesign) + { + _origin.direction &= 3; + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override final + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/TrackPlaceAction.hpp b/src/openrct2/actions/TrackPlaceAction.hpp deleted file mode 100644 index 417a7a60fb..0000000000 --- a/src/openrct2/actions/TrackPlaceAction.hpp +++ /dev/null @@ -1,736 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../ride/Track.h" -#include "../ride/TrackData.h" -#include "../ride/TrackDesign.h" -#include "../util/Util.h" -#include "../world/MapAnimation.h" -#include "../world/Surface.h" -#include "GameAction.h" -#include "RideSetSetting.hpp" - -class TrackPlaceActionResult final : public GameActions::Result -{ -public: - TrackPlaceActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE) - { - } - TrackPlaceActionResult(GameActions::Status error) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE) - { - } - TrackPlaceActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message) - { - } - TrackPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message, args) - { - } - - uint8_t GroundFlags{ 0 }; -}; - -DEFINE_GAME_ACTION(TrackPlaceAction, GAME_COMMAND_PLACE_TRACK, TrackPlaceActionResult) -{ -private: - NetworkRideId_t _rideIndex{ RideIdNewNull }; - int32_t _trackType{}; - CoordsXYZD _origin; - int32_t _brakeSpeed{}; - int32_t _colour{}; - int32_t _seatRotation{}; - int32_t _trackPlaceFlags{}; - bool _fromTrackDesign{}; - -public: - TrackPlaceAction() = default; - TrackPlaceAction( - NetworkRideId_t rideIndex, int32_t trackType, const CoordsXYZD& origin, int32_t brakeSpeed, int32_t colour, - int32_t seatRotation, int32_t liftHillAndAlternativeState, bool fromTrackDesign) - : _rideIndex(rideIndex) - , _trackType(trackType) - , _origin(origin) - , _brakeSpeed(brakeSpeed) - , _colour(colour) - , _seatRotation(seatRotation) - , _trackPlaceFlags(liftHillAndAlternativeState) - , _fromTrackDesign(fromTrackDesign) - { - _origin.direction &= 3; - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_origin); - visitor.Visit("ride", _rideIndex); - visitor.Visit("trackType", _trackType); - visitor.Visit("brakeSpeed", _brakeSpeed); - visitor.Visit("colour", _colour); - visitor.Visit("seatRotation", _seatRotation); - visitor.Visit("trackPlaceFlags", _trackPlaceFlags); - visitor.Visit("isFromTrackDesign", _fromTrackDesign); - } - - uint16_t GetActionFlags() const override final - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_rideIndex) << DS_TAG(_trackType) << DS_TAG(_origin) << DS_TAG(_brakeSpeed) << DS_TAG(_colour) - << DS_TAG(_seatRotation) << DS_TAG(_trackPlaceFlags); - } - - GameActions::Result::Ptr Query() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride for track placement, rideIndex = %d", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid ride subtype for track placement, rideIndex = %d", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (!direction_valid(_origin.direction)) - { - log_warning("Invalid direction for track placement, direction = %d", _origin.direction); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); - } - - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::RideConstruction; - res->Position.x = _origin.x + 16; - res->Position.y = _origin.y + 16; - res->Position.z = _origin.z; - - res->GroundFlags = 0; - - uint32_t rideTypeFlags = RideTypeDescriptors[ride->type].Flags; - - if ((ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) && _trackType == TrackElemType::EndStation) - { - return std::make_unique(GameActions::Status::Disallowed, STR_NOT_ALLOWED_TO_MODIFY_STATION); - } - - if (!(GetActionFlags() & GameActions::Flags::AllowWhilePaused)) - { - if (game_is_paused() && !gCheatsBuildInPauseMode) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED); - } - } - - if (!(rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE)) - { - if (_trackType == TrackElemType::OnRidePhoto) - { - if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_ONLY_ONE_ON_RIDE_PHOTO_PER_RIDE); - } - } - else if (_trackType == TrackElemType::CableLiftHill) - { - if (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_ONLY_ONE_CABLE_LIFT_HILL_PER_RIDE); - } - } - // Backwards steep lift hills are allowed, even on roller coasters that do not support forwards steep lift hills. - if ((_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED) - && !RideTypeDescriptors[ride->type].SupportsTrackPiece(TRACK_LIFT_HILL_STEEP) - && !gCheatsEnableChainLiftOnAllTrack) - { - if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_IS_STEEP_UP) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_TOO_STEEP_FOR_LIFT_HILL); - } - } - } - - money32 cost = 0; - const rct_preview_track* trackBlock = get_track_def_from_ride(ride, _trackType); - uint32_t numElements = 0; - // First check if any of the track pieces are outside the park - for (; trackBlock->index != 0xFF; trackBlock++) - { - auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), 0 }; - auto tileCoords = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; - - if (!LocationValid(tileCoords) || (!map_is_location_owned(tileCoords) && !gCheatsSandboxMode)) - { - return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - } - numElements++; - } - - if (!map_check_free_elements_and_reorganise(numElements)) - { - log_warning("Not enough free map elments to place track."); - return std::make_unique( - GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); - } - const uint16_t* trackFlags = (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatTrackFlags : TrackFlags; - if (!gCheatsAllowTrackPlaceInvalidHeights) - { - if (trackFlags[_trackType] & TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT) - { - if ((_origin.z & 0x0F) != 8) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CONSTRUCTION_ERR_UNKNOWN); - } - } - else - { - if ((_origin.z & 0x0F) != 0) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CONSTRUCTION_ERR_UNKNOWN); - } - } - } - - // If that is not the case, then perform the remaining checks - trackBlock = get_track_def_from_ride(ride, _trackType); - - for (int32_t blockIndex = 0; trackBlock->index != 0xFF; trackBlock++, blockIndex++) - { - auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), trackBlock->z }; - auto mapLoc = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; - auto quarterTile = trackBlock->var_08.Rotate(_origin.direction); - - if (mapLoc.z < 16) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_TOO_LOW); - } - - int32_t baseZ = floor2(mapLoc.z, COORDS_Z_STEP); - - int32_t clearanceZ = trackBlock->var_07; - if (trackBlock->flags & RCT_PREVIEW_TRACK_FLAG_IS_VERTICAL - && RideTypeDescriptors[ride->type].Heights.ClearanceHeight > 24) - { - clearanceZ += 24; - } - else - { - clearanceZ += RideTypeDescriptors[ride->type].Heights.ClearanceHeight; - } - - clearanceZ = floor2(clearanceZ, COORDS_Z_STEP) + baseZ; - - if (clearanceZ > MAX_TRACK_HEIGHT) - { - return std::make_unique(GameActions::Status::InvalidParameters, STR_TOO_HIGH); - } - - uint8_t crossingMode = (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS) - && _trackType == TrackElemType::Flat) - ? CREATE_CROSSING_MODE_TRACK_OVER_PATH - : CREATE_CROSSING_MODE_NONE; - if (!map_can_construct_with_clear_at( - { mapLoc, baseZ, clearanceZ }, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &cost, - crossingMode)) - { - return std::make_unique( - GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); - } - - // When building a level crossing, remove any pre-existing path furniture. - if (crossingMode == CREATE_CROSSING_MODE_TRACK_OVER_PATH) - { - auto footpathElement = map_get_footpath_element(mapLoc); - if (footpathElement != nullptr && footpathElement->AsPath()->HasAddition()) - { - footpathElement->AsPath()->SetAddition(0); - } - } - - uint8_t mapGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - if (res->GroundFlags != 0 && (res->GroundFlags & mapGroundFlags) == 0) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); - } - - res->GroundFlags = mapGroundFlags; - if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) - { - if (FlatTrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_ABOVE_GROUND) - { - if (res->GroundFlags & ELEMENT_IS_UNDERGROUND) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - } - } - else - { - if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_ABOVE_GROUND) - { - if (res->GroundFlags & ELEMENT_IS_UNDERGROUND) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - } - } - - if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) - { - if (FlatTrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_UNDERWATER) - { - if (!(gMapGroundFlags & ELEMENT_IS_UNDERWATER)) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_UNDERWATER); - } - } - } - else - { - if (TrackFlags[_trackType] & TRACK_ELEM_FLAG_ONLY_UNDERWATER) - { // No element has this flag - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_UNDERWATER); - } - } - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER && !gCheatsDisableClearanceChecks) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); - } - - if ((rideTypeFlags & RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER) && !byte_9D8150) - { - auto surfaceElement = map_get_surface_element_at(mapLoc); - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - auto waterHeight = surfaceElement->GetWaterHeight(); - if (waterHeight == 0) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); - } - - if (waterHeight != baseZ) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); - } - waterHeight -= LAND_HEIGHT_STEP; - if (waterHeight == surfaceElement->GetBaseZ()) - { - uint8_t slope = surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP; - if (slope == TILE_ELEMENT_SLOPE_W_CORNER_DN || slope == TILE_ELEMENT_SLOPE_S_CORNER_DN - || slope == TILE_ELEMENT_SLOPE_E_CORNER_DN || slope == TILE_ELEMENT_SLOPE_N_CORNER_DN) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); - } - } - } - - int32_t entranceDirections; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; - } - else - { - entranceDirections = TrackSequenceProperties[_trackType][0]; - } - if ((entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN) && trackBlock->index == 0) - { - if (!track_add_station_element({ mapLoc, baseZ, _origin.direction }, _rideIndex, 0, _fromTrackDesign)) - { - return std::make_unique(GameActions::Status::Unknown, gGameCommandErrorText); - } - } - - // 6c5648 12 push - auto surfaceElement = map_get_surface_element_at(mapLoc); - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (!gCheatsDisableSupportLimits) - { - int32_t ride_height = clearanceZ - surfaceElement->GetBaseZ(); - if (ride_height >= 0) - { - uint16_t maxHeight; - - if (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY) - && rideEntry->max_height != 0) - { - maxHeight = rideEntry->max_height; - } - else - { - maxHeight = RideTypeDescriptors[ride->type].Heights.MaxHeight; - } - - ride_height /= COORDS_Z_PER_TINY_Z; - if (ride_height > maxHeight && !byte_9D8150) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_TOO_HIGH_FOR_SUPPORTS); - } - } - } - - int32_t supportHeight = baseZ - surfaceElement->GetBaseZ(); - if (supportHeight < 0) - { - supportHeight = (10 * COORDS_Z_STEP); - } - - cost += ((supportHeight / (2 * COORDS_Z_STEP)) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice) * 5; - } - - money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; - price *= (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatRideTrackPricing[_trackType] : TrackPricing[_trackType]; - - price >>= 16; - res->Cost = cost + ((price / 2) * 10); - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto ride = get_ride(_rideIndex); - if (ride == nullptr) - { - log_warning("Invalid ride for track placement, rideIndex = %d", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); - if (rideEntry == nullptr) - { - log_warning("Invalid ride subtype for track placement, rideIndex = %d", static_cast(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - auto res = std::make_unique(); - res->Expenditure = ExpenditureType::RideConstruction; - res->Position.x = _origin.x + 16; - res->Position.y = _origin.y + 16; - res->Position.z = _origin.z; - - res->GroundFlags = 0; - - uint32_t rideTypeFlags = RideTypeDescriptors[ride->type].Flags; - - const uint8_t(*wallEdges)[16]; - if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) - { - wallEdges = &FlatRideTrackSequenceElementAllowedWallEdges[_trackType]; - } - else - { - wallEdges = &TrackSequenceElementAllowedWallEdges[_trackType]; - } - - money32 cost = 0; - const rct_preview_track* trackBlock = get_track_def_from_ride(ride, _trackType); - - trackBlock = get_track_def_from_ride(ride, _trackType); - for (int32_t blockIndex = 0; trackBlock->index != 0xFF; trackBlock++, blockIndex++) - { - auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), trackBlock->z }; - auto mapLoc = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; - - auto quarterTile = trackBlock->var_08.Rotate(_origin.direction); - - int32_t baseZ = floor2(mapLoc.z, COORDS_Z_STEP); - int32_t clearanceZ = trackBlock->var_07; - if (trackBlock->flags & RCT_PREVIEW_TRACK_FLAG_IS_VERTICAL - && RideTypeDescriptors[ride->type].Heights.ClearanceHeight > 24) - { - clearanceZ += 24; - } - else - { - clearanceZ += RideTypeDescriptors[ride->type].Heights.ClearanceHeight; - } - - clearanceZ = floor2(clearanceZ, COORDS_Z_STEP) + baseZ; - const auto mapLocWithClearance = CoordsXYRangedZ(mapLoc, baseZ, clearanceZ); - - uint8_t crossingMode = (RideTypeDescriptors[ride->type].HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS) - && _trackType == TrackElemType::Flat) - ? CREATE_CROSSING_MODE_TRACK_OVER_PATH - : CREATE_CROSSING_MODE_NONE; - if (!map_can_construct_with_clear_at( - mapLocWithClearance, &map_place_non_scenery_clear_func, quarterTile, GetFlags() | GAME_COMMAND_FLAG_APPLY, - &cost, crossingMode)) - { - return std::make_unique( - GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsDisableClearanceChecks) - { - footpath_remove_litter(mapLoc); - if (rideTypeFlags & RIDE_TYPE_FLAG_TRACK_NO_WALLS) - { - wall_remove_at(mapLocWithClearance); - } - else - { - // Remove walls in the directions this track intersects - uint8_t intersectingDirections = (*wallEdges)[blockIndex]; - intersectingDirections ^= 0x0F; - intersectingDirections = rol4(intersectingDirections, _origin.direction); - for (int32_t i = 0; i < NumOrthogonalDirections; i++) - { - if (intersectingDirections & (1 << i)) - { - wall_remove_intersecting_walls(mapLocWithClearance, i); - } - } - } - } - - uint8_t mapGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - if (res->GroundFlags != 0 && (res->GroundFlags & mapGroundFlags) == 0) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); - } - - res->GroundFlags = mapGroundFlags; - - // 6c5648 12 push - auto surfaceElement = map_get_surface_element_at(mapLoc); - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - int32_t supportHeight = baseZ - surfaceElement->GetBaseZ(); - if (supportHeight < 0) - { - supportHeight = (10 * COORDS_Z_STEP); - } - - cost += ((supportHeight / (2 * COORDS_Z_STEP)) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice) * 5; - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - invalidate_test_results(ride); - switch (_trackType) - { - case TrackElemType::OnRidePhoto: - ride->lifecycle_flags |= RIDE_LIFECYCLE_ON_RIDE_PHOTO; - break; - case TrackElemType::CableLiftHill: - if (trackBlock->index != 0) - break; - ride->lifecycle_flags |= RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED; - ride->CableLiftLoc = mapLoc; - break; - case TrackElemType::BlockBrakes: - { - ride->num_block_brakes++; - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_OPERATING; - - RideMode newMode = RideMode::ContinuousCircuitBlockSectioned; - if (ride->type == RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER) - newMode = RideMode::PoweredLaunchBlockSectioned; - - auto rideSetSetting = RideSetSettingAction( - ride->id, RideSetSetting::Mode, static_cast(newMode)); - GameActions::ExecuteNested(&rideSetSetting); - break; - } - } - - if (trackBlock->index == 0) - { - switch (_trackType) - { - case TrackElemType::Up25ToFlat: - case TrackElemType::Up60ToFlat: - case TrackElemType::DiagUp25ToFlat: - case TrackElemType::DiagUp60ToFlat: - if (!(_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED)) - break; - [[fallthrough]]; - case TrackElemType::CableLiftHill: - ride->num_block_brakes++; - break; - } - } - } - - int32_t entranceDirections = 0; - if (!ride->overall_view.isNull()) - { - if (!(GetFlags() & GAME_COMMAND_FLAG_NO_SPEND)) - { - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; - } - else - { - entranceDirections = TrackSequenceProperties[_trackType][0]; - } - } - } - - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN || ride->overall_view.isNull()) - { - ride->overall_view = mapLoc; - } - - auto tileElement = tile_element_insert(mapLoc, quarterTile.GetBaseQuarterOccupied()); - assert(tileElement != nullptr); - tileElement->SetClearanceZ(clearanceZ); - tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); - tileElement->SetDirection(_origin.direction); - if (_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED) - { - tileElement->AsTrack()->SetHasChain(true); - } - - tileElement->AsTrack()->SetSequenceIndex(trackBlock->index); - tileElement->AsTrack()->SetRideIndex(_rideIndex); - tileElement->AsTrack()->SetTrackType(_trackType); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } - - switch (_trackType) - { - case TrackElemType::Waterfall: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_WATERFALL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); - break; - case TrackElemType::Rapids: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_RAPIDS, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); - break; - case TrackElemType::Whirlpool: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); - break; - case TrackElemType::SpinningTunnel: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); - break; - } - if (TrackTypeHasSpeedSetting(_trackType)) - { - tileElement->AsTrack()->SetBrakeBoosterSpeed(_brakeSpeed); - } - else - { - tileElement->AsTrack()->SetSeatRotation(_seatRotation); - } - - if (_trackPlaceFlags & RIDE_TYPE_ALTERNATIVE_TRACK_TYPE) - { - tileElement->AsTrack()->SetInverted(true); - } - tileElement->AsTrack()->SetColourScheme(_colour); - - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - entranceDirections = FlatRideTrackSequenceProperties[_trackType][0]; - } - else - { - entranceDirections = TrackSequenceProperties[_trackType][0]; - } - - if (entranceDirections & TRACK_SEQUENCE_FLAG_CONNECTS_TO_PATH) - { - uint8_t availableDirections = entranceDirections & 0x0F; - if (availableDirections != 0) - { - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsDisableClearanceChecks) - { - for (int32_t chosenDirection = bitscanforward(availableDirections); chosenDirection != -1; - chosenDirection = bitscanforward(availableDirections)) - { - availableDirections &= ~(1 << chosenDirection); - CoordsXY tempLoc{ mapLoc.x, mapLoc.y }; - int32_t tempDirection = (_origin.direction + chosenDirection) & 3; - tempLoc.x += CoordsDirectionDelta[tempDirection].x; - tempLoc.y += CoordsDirectionDelta[tempDirection].y; - tempDirection = direction_reverse(tempDirection); - wall_remove_intersecting_walls({ tempLoc, baseZ, clearanceZ }, tempDirection & 3); - } - } - } - } - - // If the placed tile is a station modify station properties. - // Don't do this if the ride is simulating and the tile is a ghost to prevent desyncs. - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN - && !(ride->status == RIDE_STATUS_SIMULATING && GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - if (trackBlock->index == 0) - { - track_add_station_element( - { mapLoc, _origin.direction }, _rideIndex, GAME_COMMAND_FLAG_APPLY, _fromTrackDesign); - } - sub_6CB945(ride); - ride->UpdateMaxVehicles(); - } - - if (rideTypeFlags & RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER) - { - auto* waterSurfaceElement = map_get_surface_element_at(mapLoc); - if (waterSurfaceElement != nullptr) - { - waterSurfaceElement->SetHasTrackThatNeedsWater(true); - tileElement = reinterpret_cast(waterSurfaceElement); - } - } - - if (!gCheatsDisableClearanceChecks || !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - footpath_connect_edges(mapLoc, tileElement, GetFlags()); - } - map_invalidate_tile_full(mapLoc); - } - - money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; - price *= (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? FlatRideTrackPricing[_trackType] : TrackPricing[_trackType]; - - price >>= 16; - res->Cost = cost + ((price / 2) * 10); - return res; - } -}; diff --git a/src/openrct2/actions/TrackRemoveAction.cpp b/src/openrct2/actions/TrackRemoveAction.cpp new file mode 100644 index 0000000000..bab512fa74 --- /dev/null +++ b/src/openrct2/actions/TrackRemoveAction.cpp @@ -0,0 +1,505 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "TrackRemoveAction.h" + +#include "../management/Finance.h" +#include "../ride/RideData.h" +#include "../ride/Track.h" +#include "../ride/TrackData.h" +#include "../ride/TrackDesign.h" +#include "../util/Util.h" +#include "../world/MapAnimation.h" +#include "../world/Surface.h" +#include "RideSetSettingAction.h" + +void TrackRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_origin); + visitor.Visit("trackType", _trackType); + visitor.Visit("sequence", _sequence); +} + +void TrackRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_trackType) << DS_TAG(_sequence) << DS_TAG(_origin); +} + +GameActions::Result::Ptr TrackRemoveAction::Query() const +{ + auto res = MakeResult(); + res->Position.x = _origin.x + 16; + res->Position.y = _origin.y + 16; + res->Position.z = _origin.z; + res->Expenditure = ExpenditureType::RideConstruction; + + // Stations require some massaging of the track type for comparing + auto comparableTrackType = _trackType; + switch (_trackType) + { + case TrackElemType::BeginStation: + case TrackElemType::MiddleStation: + comparableTrackType = TrackElemType::EndStation; + break; + } + + bool found = false; + bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; + TileElement* tileElement = map_get_first_element_at(_origin); + + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetBaseZ() != _origin.z) + continue; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if ((tileElement->GetDirection()) != _origin.direction) + continue; + + if (tileElement->AsTrack()->GetSequenceIndex() != _sequence) + continue; + + if (tileElement->IsGhost() != isGhost) + continue; + + auto tileTrackType = tileElement->AsTrack()->GetTrackType(); + switch (tileTrackType) + { + case TrackElemType::BeginStation: + case TrackElemType::MiddleStation: + tileTrackType = TrackElemType::EndStation; + break; + } + + if (tileTrackType != comparableTrackType) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", _origin.x, _origin.y, _origin.z, + _origin.direction, _sequence); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + if (tileElement->AsTrack()->IsIndestructible()) + { + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, + STR_YOU_ARE_NOT_ALLOWED_TO_REMOVE_THIS_SECTION); + } + + ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); + auto trackType = tileElement->AsTrack()->GetTrackType(); + + auto ride = get_ride(rideIndex); + if (ride == nullptr) + { + log_warning("Ride not found. ride index = %d.", rideIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + if (ride->type >= RIDE_TYPE_COUNT) + { + log_warning("Ride type not found. ride type = %d.", ride->type); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, trackType); + trackBlock += tileElement->AsTrack()->GetSequenceIndex(); + + auto startLoc = _origin; + startLoc.direction = tileElement->GetDirection(); + + auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; + startLoc.x -= rotatedTrack.x; + startLoc.y -= rotatedTrack.y; + startLoc.z -= rotatedTrack.z; + res->Position.x = startLoc.x; + res->Position.y = startLoc.y; + res->Position.z = startLoc.z; + + money32 cost = 0; + + trackBlock = get_track_def_from_ride(ride, trackType); + for (; trackBlock->index != 255; trackBlock++) + { + rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; + auto mapLoc = CoordsXYZ{ startLoc.x, startLoc.y, startLoc.z } + rotatedTrack; + + if (!LocationValid(mapLoc)) + { + return MakeResult( + GameActions::Status::NotOwned, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + map_invalidate_tile_full(mapLoc); + + found = false; + tileElement = map_get_first_element_at(mapLoc); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetBaseZ() != mapLoc.z) + continue; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if (tileElement->GetDirection() != _origin.direction) + continue; + + if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) + continue; + + if (tileElement->AsTrack()->GetTrackType() != trackType) + continue; + + if (tileElement->IsGhost() != isGhost) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", mapLoc.x, mapLoc.y, mapLoc.z, + _origin.direction, trackBlock->index); + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + int32_t entranceDirections; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + entranceDirections = FlatRideTrackSequenceProperties[trackType][0]; + } + else + { + entranceDirections = TrackSequenceProperties[trackType][0]; + } + + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN && (tileElement->AsTrack()->GetSequenceIndex() == 0)) + { + if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, 0)) + { + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); + } + } + + auto* surfaceElement = map_get_surface_element_at(mapLoc); + if (surfaceElement == nullptr) + { + log_warning("Surface Element not found. x = %d, y = %d", mapLoc.x, mapLoc.y); + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + int8_t _support_height = tileElement->base_height - surfaceElement->base_height; + if (_support_height < 0) + { + _support_height = 10; + } + + cost += (_support_height / 2) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice; + } + + money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + price *= FlatRideTrackPricing[trackType]; + } + else + { + price *= TrackPricing[trackType]; + } + price >>= 16; + price = (price + cost) / 2; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) + price *= -7; + else + price *= -10; + + res->Cost = price; + return res; +} + +GameActions::Result::Ptr TrackRemoveAction::Execute() const +{ + auto res = MakeResult(); + res->Position.x = _origin.x + 16; + res->Position.y = _origin.y + 16; + res->Position.z = _origin.z; + res->Expenditure = ExpenditureType::RideConstruction; + + // Stations require some massaging of the track type for comparing + auto comparableTrackType = _trackType; + switch (_trackType) + { + case TrackElemType::BeginStation: + case TrackElemType::MiddleStation: + comparableTrackType = TrackElemType::EndStation; + break; + } + + bool found = false; + bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; + TileElement* tileElement = map_get_first_element_at(_origin); + + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetBaseZ() != _origin.z) + continue; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if ((tileElement->GetDirection()) != _origin.direction) + continue; + + if (tileElement->AsTrack()->GetSequenceIndex() != _sequence) + continue; + + if (tileElement->IsGhost() != isGhost) + continue; + + auto tileTrackType = tileElement->AsTrack()->GetTrackType(); + switch (tileTrackType) + { + case TrackElemType::BeginStation: + case TrackElemType::MiddleStation: + tileTrackType = TrackElemType::EndStation; + break; + } + + if (tileTrackType != comparableTrackType) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", _origin.x, _origin.y, _origin.z, + _origin.direction, _sequence); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); + auto trackType = tileElement->AsTrack()->GetTrackType(); + bool isLiftHill = tileElement->AsTrack()->HasChain(); + + auto ride = get_ride(rideIndex); + if (ride == nullptr) + { + log_warning("Ride not found. ride index = %d.", rideIndex); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, trackType); + trackBlock += tileElement->AsTrack()->GetSequenceIndex(); + + auto startLoc = _origin; + startLoc.direction = tileElement->GetDirection(); + + auto rotatedTrackLoc = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; + startLoc.x -= rotatedTrackLoc.x; + startLoc.y -= rotatedTrackLoc.y; + startLoc.z -= rotatedTrackLoc.z; + res->Position.x = startLoc.x; + res->Position.y = startLoc.y; + res->Position.z = startLoc.z; + money32 cost = 0; + + trackBlock = get_track_def_from_ride(ride, trackType); + for (; trackBlock->index != 255; trackBlock++) + { + rotatedTrackLoc = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; + auto mapLoc = CoordsXYZ{ startLoc.x, startLoc.y, startLoc.z } + rotatedTrackLoc; + + map_invalidate_tile_full(mapLoc); + + found = false; + tileElement = map_get_first_element_at(mapLoc); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetBaseZ() != mapLoc.z) + continue; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if (tileElement->GetDirection() != _origin.direction) + continue; + + if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) + continue; + + if (tileElement->AsTrack()->GetTrackType() != trackType) + continue; + + if (tileElement->IsGhost() != isGhost) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_warning( + "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", mapLoc.x, mapLoc.y, mapLoc.z, + _origin.direction, trackBlock->index); + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + int32_t entranceDirections; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + entranceDirections = FlatRideTrackSequenceProperties[trackType][0]; + } + else + { + entranceDirections = TrackSequenceProperties[trackType][0]; + } + + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN && (tileElement->AsTrack()->GetSequenceIndex() == 0)) + { + if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, 0)) + { + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); + } + } + + auto* surfaceElement = map_get_surface_element_at(mapLoc); + if (surfaceElement == nullptr) + { + log_warning("Surface Element not found. x = %d, y = %d", mapLoc.x, mapLoc.y); + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); + } + + int8_t _support_height = tileElement->base_height - surfaceElement->base_height; + if (_support_height < 0) + { + _support_height = 10; + } + + cost += (_support_height / 2) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice; + + // If the removed tile is a station modify station properties. + // Don't do this if the ride is simulating and the tile is a ghost to prevent desyncs. + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN + && !(ride->status == RIDE_STATUS_SIMULATING && tileElement->Flags & TILE_ELEMENT_FLAG_GHOST) + && (tileElement->AsTrack()->GetSequenceIndex() == 0)) + { + if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, GAME_COMMAND_FLAG_APPLY)) + { + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); + } + } + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER)) + { + surfaceElement->SetHasTrackThatNeedsWater(false); + } + + invalidate_test_results(ride); + footpath_queue_chain_reset(); + if (!gCheatsDisableClearanceChecks || !(tileElement->IsGhost())) + { + footpath_remove_edges_at(mapLoc, tileElement); + } + tile_element_remove(tileElement); + sub_6CB945(ride); + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + ride->UpdateMaxVehicles(); + } + } + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + switch (trackType) + { + case TrackElemType::OnRidePhoto: + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_ON_RIDE_PHOTO; + break; + case TrackElemType::CableLiftHill: + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED; + break; + case TrackElemType::BlockBrakes: + ride->num_block_brakes--; + if (ride->num_block_brakes == 0) + { + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_OPERATING; + RideMode newMode = RideMode::ContinuousCircuit; + if (ride->type == RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER) + { + newMode = RideMode::PoweredLaunch; + } + + auto rideSetSetting = RideSetSettingAction(ride->id, RideSetSetting::Mode, static_cast(newMode)); + GameActions::ExecuteNested(&rideSetSetting); + } + + break; + } + + switch (trackType) + { + case TrackElemType::Up25ToFlat: + case TrackElemType::Up60ToFlat: + case TrackElemType::DiagUp25ToFlat: + case TrackElemType::DiagUp60ToFlat: + if (!isLiftHill) + break; + [[fallthrough]]; + case TrackElemType::CableLiftHill: + ride->num_block_brakes--; + break; + } + } + + money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + price *= FlatRideTrackPricing[trackType]; + } + else + { + price *= TrackPricing[trackType]; + } + price >>= 16; + price = (price + cost) / 2; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) + price *= -7; + else + price *= -10; + + res->Cost = price; + return res; +} diff --git a/src/openrct2/actions/TrackRemoveAction.h b/src/openrct2/actions/TrackRemoveAction.h new file mode 100644 index 0000000000..f950d27f07 --- /dev/null +++ b/src/openrct2/actions/TrackRemoveAction.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(TrackRemoveAction, GAME_COMMAND_REMOVE_TRACK, GameActions::Result) +{ +private: + int32_t _trackType{}; + int32_t _sequence{}; + CoordsXYZD _origin; + +public: + TrackRemoveAction() = default; + TrackRemoveAction(int32_t trackType, int32_t sequence, const CoordsXYZD& origin) + : _trackType(trackType) + , _sequence(sequence) + , _origin(origin) + { + _origin.direction &= 3; + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override final + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/TrackRemoveAction.hpp b/src/openrct2/actions/TrackRemoveAction.hpp deleted file mode 100644 index 44bfa30ede..0000000000 --- a/src/openrct2/actions/TrackRemoveAction.hpp +++ /dev/null @@ -1,533 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../ride/Track.h" -#include "../ride/TrackData.h" -#include "../ride/TrackDesign.h" -#include "../util/Util.h" -#include "../world/MapAnimation.h" -#include "../world/Surface.h" -#include "GameAction.h" -#include "RideSetSetting.hpp" - -DEFINE_GAME_ACTION(TrackRemoveAction, GAME_COMMAND_REMOVE_TRACK, GameActions::Result) -{ -private: - int32_t _trackType{}; - int32_t _sequence{}; - CoordsXYZD _origin; - -public: - TrackRemoveAction() = default; - TrackRemoveAction(int32_t trackType, int32_t sequence, const CoordsXYZD& origin) - : _trackType(trackType) - , _sequence(sequence) - , _origin(origin) - { - _origin.direction &= 3; - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_origin); - visitor.Visit("trackType", _trackType); - visitor.Visit("sequence", _sequence); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_trackType) << DS_TAG(_sequence) << DS_TAG(_origin); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->Position.x = _origin.x + 16; - res->Position.y = _origin.y + 16; - res->Position.z = _origin.z; - res->Expenditure = ExpenditureType::RideConstruction; - - // Stations require some massaging of the track type for comparing - auto comparableTrackType = _trackType; - switch (_trackType) - { - case TrackElemType::BeginStation: - case TrackElemType::MiddleStation: - comparableTrackType = TrackElemType::EndStation; - break; - } - - bool found = false; - bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; - TileElement* tileElement = map_get_first_element_at(_origin); - - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != _origin.z) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if ((tileElement->GetDirection()) != _origin.direction) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != _sequence) - continue; - - if (tileElement->IsGhost() != isGhost) - continue; - - auto tileTrackType = tileElement->AsTrack()->GetTrackType(); - switch (tileTrackType) - { - case TrackElemType::BeginStation: - case TrackElemType::MiddleStation: - tileTrackType = TrackElemType::EndStation; - break; - } - - if (tileTrackType != comparableTrackType) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", _origin.x, _origin.y, _origin.z, - _origin.direction, _sequence); - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - if (tileElement->AsTrack()->IsIndestructible()) - { - return MakeResult( - GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, - STR_YOU_ARE_NOT_ALLOWED_TO_REMOVE_THIS_SECTION); - } - - ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); - auto trackType = tileElement->AsTrack()->GetTrackType(); - - auto ride = get_ride(rideIndex); - if (ride == nullptr) - { - log_warning("Ride not found. ride index = %d.", rideIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - if (ride->type >= RIDE_TYPE_COUNT) - { - log_warning("Ride type not found. ride type = %d.", ride->type); - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - const rct_preview_track* trackBlock = get_track_def_from_ride(ride, trackType); - trackBlock += tileElement->AsTrack()->GetSequenceIndex(); - - auto startLoc = _origin; - startLoc.direction = tileElement->GetDirection(); - - auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; - startLoc.x -= rotatedTrack.x; - startLoc.y -= rotatedTrack.y; - startLoc.z -= rotatedTrack.z; - res->Position.x = startLoc.x; - res->Position.y = startLoc.y; - res->Position.z = startLoc.z; - - money32 cost = 0; - - trackBlock = get_track_def_from_ride(ride, trackType); - for (; trackBlock->index != 255; trackBlock++) - { - rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; - auto mapLoc = CoordsXYZ{ startLoc.x, startLoc.y, startLoc.z } + rotatedTrack; - - if (!LocationValid(mapLoc)) - { - return MakeResult( - GameActions::Status::NotOwned, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - map_invalidate_tile_full(mapLoc); - - found = false; - tileElement = map_get_first_element_at(mapLoc); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != mapLoc.z) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if (tileElement->GetDirection() != _origin.direction) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) - continue; - - if (tileElement->AsTrack()->GetTrackType() != trackType) - continue; - - if (tileElement->IsGhost() != isGhost) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", mapLoc.x, mapLoc.y, mapLoc.z, - _origin.direction, trackBlock->index); - return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - int32_t entranceDirections; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - entranceDirections = FlatRideTrackSequenceProperties[trackType][0]; - } - else - { - entranceDirections = TrackSequenceProperties[trackType][0]; - } - - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN && (tileElement->AsTrack()->GetSequenceIndex() == 0)) - { - if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, 0)) - { - return MakeResult( - GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); - } - } - - auto* surfaceElement = map_get_surface_element_at(mapLoc); - if (surfaceElement == nullptr) - { - log_warning("Surface Element not found. x = %d, y = %d", mapLoc.x, mapLoc.y); - return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - int8_t _support_height = tileElement->base_height - surfaceElement->base_height; - if (_support_height < 0) - { - _support_height = 10; - } - - cost += (_support_height / 2) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice; - } - - money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - price *= FlatRideTrackPricing[trackType]; - } - else - { - price *= TrackPricing[trackType]; - } - price >>= 16; - price = (price + cost) / 2; - if (ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) - price *= -7; - else - price *= -10; - - res->Cost = price; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Position.x = _origin.x + 16; - res->Position.y = _origin.y + 16; - res->Position.z = _origin.z; - res->Expenditure = ExpenditureType::RideConstruction; - - // Stations require some massaging of the track type for comparing - auto comparableTrackType = _trackType; - switch (_trackType) - { - case TrackElemType::BeginStation: - case TrackElemType::MiddleStation: - comparableTrackType = TrackElemType::EndStation; - break; - } - - bool found = false; - bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; - TileElement* tileElement = map_get_first_element_at(_origin); - - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != _origin.z) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if ((tileElement->GetDirection()) != _origin.direction) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != _sequence) - continue; - - if (tileElement->IsGhost() != isGhost) - continue; - - auto tileTrackType = tileElement->AsTrack()->GetTrackType(); - switch (tileTrackType) - { - case TrackElemType::BeginStation: - case TrackElemType::MiddleStation: - tileTrackType = TrackElemType::EndStation; - break; - } - - if (tileTrackType != comparableTrackType) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", _origin.x, _origin.y, _origin.z, - _origin.direction, _sequence); - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex(); - auto trackType = tileElement->AsTrack()->GetTrackType(); - bool isLiftHill = tileElement->AsTrack()->HasChain(); - - auto ride = get_ride(rideIndex); - if (ride == nullptr) - { - log_warning("Ride not found. ride index = %d.", rideIndex); - return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - const rct_preview_track* trackBlock = get_track_def_from_ride(ride, trackType); - trackBlock += tileElement->AsTrack()->GetSequenceIndex(); - - auto startLoc = _origin; - startLoc.direction = tileElement->GetDirection(); - - auto rotatedTrackLoc = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; - startLoc.x -= rotatedTrackLoc.x; - startLoc.y -= rotatedTrackLoc.y; - startLoc.z -= rotatedTrackLoc.z; - res->Position.x = startLoc.x; - res->Position.y = startLoc.y; - res->Position.z = startLoc.z; - money32 cost = 0; - - trackBlock = get_track_def_from_ride(ride, trackType); - for (; trackBlock->index != 255; trackBlock++) - { - rotatedTrackLoc = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; - auto mapLoc = CoordsXYZ{ startLoc.x, startLoc.y, startLoc.z } + rotatedTrackLoc; - - map_invalidate_tile_full(mapLoc); - - found = false; - tileElement = map_get_first_element_at(mapLoc); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != mapLoc.z) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if (tileElement->GetDirection() != _origin.direction) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) - continue; - - if (tileElement->AsTrack()->GetTrackType() != trackType) - continue; - - if (tileElement->IsGhost() != isGhost) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_warning( - "Track Element not found. x = %d, y = %d, z = %d, d = %d, seq = %d.", mapLoc.x, mapLoc.y, mapLoc.z, - _origin.direction, trackBlock->index); - return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - int32_t entranceDirections; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - entranceDirections = FlatRideTrackSequenceProperties[trackType][0]; - } - else - { - entranceDirections = TrackSequenceProperties[trackType][0]; - } - - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN && (tileElement->AsTrack()->GetSequenceIndex() == 0)) - { - if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, 0)) - { - return MakeResult( - GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); - } - } - - auto* surfaceElement = map_get_surface_element_at(mapLoc); - if (surfaceElement == nullptr) - { - log_warning("Surface Element not found. x = %d, y = %d", mapLoc.x, mapLoc.y); - return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS); - } - - int8_t _support_height = tileElement->base_height - surfaceElement->base_height; - if (_support_height < 0) - { - _support_height = 10; - } - - cost += (_support_height / 2) * RideTypeDescriptors[ride->type].BuildCosts.SupportPrice; - - // If the removed tile is a station modify station properties. - // Don't do this if the ride is simulating and the tile is a ghost to prevent desyncs. - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN - && !(ride->status == RIDE_STATUS_SIMULATING && tileElement->Flags & TILE_ELEMENT_FLAG_GHOST) - && (tileElement->AsTrack()->GetSequenceIndex() == 0)) - { - if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, GAME_COMMAND_FLAG_APPLY)) - { - return MakeResult( - GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, gGameCommandErrorText); - } - } - - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER)) - { - surfaceElement->SetHasTrackThatNeedsWater(false); - } - - invalidate_test_results(ride); - footpath_queue_chain_reset(); - if (!gCheatsDisableClearanceChecks || !(tileElement->IsGhost())) - { - footpath_remove_edges_at(mapLoc, tileElement); - } - tile_element_remove(tileElement); - sub_6CB945(ride); - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - ride->UpdateMaxVehicles(); - } - } - - if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) - { - switch (trackType) - { - case TrackElemType::OnRidePhoto: - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_ON_RIDE_PHOTO; - break; - case TrackElemType::CableLiftHill: - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED; - break; - case TrackElemType::BlockBrakes: - ride->num_block_brakes--; - if (ride->num_block_brakes == 0) - { - ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_OPERATING; - RideMode newMode = RideMode::ContinuousCircuit; - if (ride->type == RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER) - { - newMode = RideMode::PoweredLaunch; - } - - auto rideSetSetting = RideSetSettingAction( - ride->id, RideSetSetting::Mode, static_cast(newMode)); - GameActions::ExecuteNested(&rideSetSetting); - } - - break; - } - - switch (trackType) - { - case TrackElemType::Up25ToFlat: - case TrackElemType::Up60ToFlat: - case TrackElemType::DiagUp25ToFlat: - case TrackElemType::DiagUp60ToFlat: - if (!isLiftHill) - break; - [[fallthrough]]; - case TrackElemType::CableLiftHill: - ride->num_block_brakes--; - break; - } - } - - money32 price = RideTypeDescriptors[ride->type].BuildCosts.TrackPrice; - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - price *= FlatRideTrackPricing[trackType]; - } - else - { - price *= TrackPricing[trackType]; - } - price >>= 16; - price = (price + cost) / 2; - if (ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) - price *= -7; - else - price *= -10; - - res->Cost = price; - return res; - } -}; diff --git a/src/openrct2/actions/TrackSetBrakeSpeedAction.cpp b/src/openrct2/actions/TrackSetBrakeSpeedAction.cpp new file mode 100644 index 0000000000..cdf6658a81 --- /dev/null +++ b/src/openrct2/actions/TrackSetBrakeSpeedAction.cpp @@ -0,0 +1,63 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "TrackSetBrakeSpeedAction.h" + +#include "../management/Finance.h" + +void TrackSetBrakeSpeedAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("trackType", _trackType); + visitor.Visit("brakeSpeed", _brakeSpeed); +} + +void TrackSetBrakeSpeedAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + stream << DS_TAG(_loc) << DS_TAG(_trackType) << DS_TAG(_brakeSpeed); +} + +GameActions::Result::Ptr TrackSetBrakeSpeedAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr TrackSetBrakeSpeedAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr TrackSetBrakeSpeedAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + + res->Position = _loc; + res->Position.x += 16; + res->Position.y += 16; + res->Expenditure = ExpenditureType::RideConstruction; + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_NONE); + } + + TileElement* tileElement = map_get_track_element_at_of_type(_loc, _trackType); + if (tileElement == nullptr) + { + log_warning("Invalid game command for setting brakes speed. x = %d, y = %d", _loc.x, _loc.y); + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); + } + + if (isExecuting) + { + tileElement->AsTrack()->SetBrakeBoosterSpeed(_brakeSpeed); + } + return res; +} diff --git a/src/openrct2/actions/TrackSetBrakeSpeedAction.h b/src/openrct2/actions/TrackSetBrakeSpeedAction.h new file mode 100644 index 0000000000..22515b55f5 --- /dev/null +++ b/src/openrct2/actions/TrackSetBrakeSpeedAction.h @@ -0,0 +1,43 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(TrackSetBrakeSpeedAction, GAME_COMMAND_SET_BRAKES_SPEED, GameActions::Result) +{ +private: + CoordsXYZ _loc; + track_type_t _trackType{}; + uint8_t _brakeSpeed{}; + +public: + TrackSetBrakeSpeedAction() = default; + TrackSetBrakeSpeedAction(const CoordsXYZ& loc, track_type_t trackType, uint8_t brakeSpeed) + : _loc(loc) + , _trackType(trackType) + , _brakeSpeed(brakeSpeed) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override final + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; +}; diff --git a/src/openrct2/actions/TrackSetBrakeSpeedAction.hpp b/src/openrct2/actions/TrackSetBrakeSpeedAction.hpp deleted file mode 100644 index bd7dbe7d3f..0000000000 --- a/src/openrct2/actions/TrackSetBrakeSpeedAction.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../management/Finance.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(TrackSetBrakeSpeedAction, GAME_COMMAND_SET_BRAKES_SPEED, GameActions::Result) -{ -private: - CoordsXYZ _loc; - track_type_t _trackType{}; - uint8_t _brakeSpeed{}; - -public: - TrackSetBrakeSpeedAction() = default; - TrackSetBrakeSpeedAction(const CoordsXYZ& loc, track_type_t trackType, uint8_t brakeSpeed) - : _loc(loc) - , _trackType(trackType) - , _brakeSpeed(brakeSpeed) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("trackType", _trackType); - visitor.Visit("brakeSpeed", _brakeSpeed); - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - stream << DS_TAG(_loc) << DS_TAG(_trackType) << DS_TAG(_brakeSpeed); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - res->Position = _loc; - res->Position.x += 16; - res->Position.y += 16; - res->Expenditure = ExpenditureType::RideConstruction; - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_NONE); - } - - TileElement* tileElement = map_get_track_element_at_of_type(_loc, _trackType); - if (tileElement == nullptr) - { - log_warning("Invalid game command for setting brakes speed. x = %d, y = %d", _loc.x, _loc.y); - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); - } - - if (isExecuting) - { - tileElement->AsTrack()->SetBrakeBoosterSpeed(_brakeSpeed); - } - return res; - } -}; diff --git a/src/openrct2/actions/WallPlaceAction.cpp b/src/openrct2/actions/WallPlaceAction.cpp new file mode 100644 index 0000000000..707a7cf5ad --- /dev/null +++ b/src/openrct2/actions/WallPlaceAction.cpp @@ -0,0 +1,580 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "WallPlaceAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../ride/Track.h" +#include "../ride/TrackDesign.h" +#include "../world/Banner.h" +#include "../world/LargeScenery.h" +#include "../world/MapAnimation.h" +#include "../world/SmallScenery.h" +#include "../world/Surface.h" +#include "../world/Wall.h" + +void WallPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); + visitor.Visit("object", _wallType); + visitor.Visit("edge", _edge); + visitor.Visit("primaryColour", _primaryColour); + visitor.Visit("secondaryColour", _secondaryColour); + visitor.Visit("tertiaryColour", _tertiaryColour); + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_wallType); + if (sceneryEntry != nullptr) + { + if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) + { + _bannerId = create_new_banner(0); + } + } +} + +void WallPlaceAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_wallType) << DS_TAG(_loc) << DS_TAG(_edge) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) + << DS_TAG(_tertiaryColour) << DS_TAG(_bannerId); +} + +GameActions::Result::Ptr WallPlaceAction::Query() const +{ + auto res = std::make_unique(); + res->ErrorTitle = STR_CANT_BUILD_PARK_ENTRANCE_HERE; + res->Position = _loc; + + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x += 16; + res->Position.y += 16; + + if (_loc.z == 0) + { + res->Position.z = tile_element_height(res->Position); + } + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::NotOwned); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsSandboxMode) + { + if (_loc.z == 0) + { + if (!map_is_location_in_park(_loc)) + { + return std::make_unique(GameActions::Status::NotOwned); + } + } + else if (!map_is_location_owned(_loc)) + { + return std::make_unique(GameActions::Status::NotOwned); + } + } + else if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY)) + { + log_error("Invalid x/y coordinates. x = %d y = %d", _loc.x, _loc.y); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + if (_edge > 3) + { + return std::make_unique(GameActions::Status::InvalidParameters); + } + + uint8_t edgeSlope = 0; + auto targetHeight = _loc.z; + if (targetHeight == 0) + { + auto* surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); + return std::make_unique(GameActions::Status::InvalidParameters); + } + targetHeight = surfaceElement->GetBaseZ(); + + uint8_t slope = surfaceElement->GetSlope(); + edgeSlope = LandSlopeToWallSlope[slope][_edge & 3]; + if (edgeSlope & EDGE_SLOPE_ELEVATED) + { + targetHeight += 16; + edgeSlope &= ~EDGE_SLOPE_ELEVATED; + } + } + + auto* surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + if (surfaceElement->GetWaterHeight() > 0) + { + uint16_t waterHeight = surfaceElement->GetWaterHeight(); + + if (targetHeight < waterHeight && !gCheatsDisableClearanceChecks) + { + return std::make_unique(GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); + } + } + + if (targetHeight < surfaceElement->GetBaseZ() && !gCheatsDisableClearanceChecks) + { + return std::make_unique(GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + + if (!(edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS))) + { + uint8_t newEdge = (_edge + 2) & 3; + uint8_t newBaseHeight = surfaceElement->base_height; + newBaseHeight += 2; + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + if (targetHeight / 8 < newBaseHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + + if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) + { + newEdge = (newEdge - 1) & 3; + + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + newEdge = (newEdge + 2) & 3; + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + newBaseHeight += 2; + if (targetHeight / 8 < newBaseHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + newBaseHeight -= 2; + } + } + } + } + + newEdge = (_edge + 3) & 3; + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + if (targetHeight / 8 < newBaseHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + + if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) + { + newEdge = (newEdge - 1) & 3; + + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + newEdge = (newEdge + 2) & 3; + if (surfaceElement->GetSlope() & (1 << newEdge)) + { + newBaseHeight += 2; + if (targetHeight / 8 < newBaseHeight) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + } + } + } + } + } + } + + rct_scenery_entry* wallEntry = get_wall_entry(_wallType); + + if (wallEntry == nullptr) + { + log_error("Wall Type not found %d", _wallType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + if (wallEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) + { + if (_bannerId == BANNER_INDEX_NULL) + { + log_error("Banner Index not specified."); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); + } + + auto banner = GetBanner(_bannerId); + if (!banner->IsNull()) + { + log_error("No free banners available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + } + + uint8_t clearanceHeight = targetHeight / 8; + if (edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) + { + if (wallEntry->wall.flags & WALL_SCENERY_CANT_BUILD_ON_SLOPE) + { + return std::make_unique( + GameActions::Status::Disallowed, STR_ERR_UNABLE_TO_BUILD_THIS_ON_SLOPE); + } + clearanceHeight += 2; + } + clearanceHeight += wallEntry->wall.height; + + bool wallAcrossTrack = false; + if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsDisableClearanceChecks) + { + auto result = WallCheckObstruction(wallEntry, targetHeight / 8, clearanceHeight, &wallAcrossTrack); + if (result->Error != GameActions::Status::Ok) + { + return result; + } + } + + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); + } + + res->Cost = wallEntry->wall.price; + return res; +} + +GameActions::Result::Ptr WallPlaceAction::Execute() const +{ + auto res = std::make_unique(); + res->ErrorTitle = STR_CANT_BUILD_PARK_ENTRANCE_HERE; + res->Position = _loc; + + res->Expenditure = ExpenditureType::Landscaping; + res->Position.x += 16; + res->Position.y += 16; + + if (res->Position.z == 0) + { + res->Position.z = tile_element_height(res->Position); + } + + uint8_t edgeSlope = 0; + auto targetHeight = _loc.z; + if (targetHeight == 0) + { + auto* surfaceElement = map_get_surface_element_at(_loc); + if (surfaceElement == nullptr) + { + log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); + return std::make_unique(GameActions::Status::InvalidParameters); + } + targetHeight = surfaceElement->GetBaseZ(); + + uint8_t slope = surfaceElement->GetSlope(); + edgeSlope = LandSlopeToWallSlope[slope][_edge & 3]; + if (edgeSlope & EDGE_SLOPE_ELEVATED) + { + targetHeight += 16; + edgeSlope &= ~EDGE_SLOPE_ELEVATED; + } + } + auto targetLoc = CoordsXYZ(_loc, targetHeight); + + rct_scenery_entry* wallEntry = get_wall_entry(_wallType); + + if (wallEntry == nullptr) + { + log_error("Wall Type not found %d", _wallType); + return std::make_unique(GameActions::Status::InvalidParameters); + } + + uint8_t clearanceHeight = targetHeight / COORDS_Z_STEP; + if (edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) + { + clearanceHeight += 2; + } + clearanceHeight += wallEntry->wall.height; + + bool wallAcrossTrack = false; + if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsDisableClearanceChecks) + { + auto result = WallCheckObstruction(wallEntry, targetHeight / COORDS_Z_STEP, clearanceHeight, &wallAcrossTrack); + if (result->Error != GameActions::Status::Ok) + { + return result; + } + } + + if (!map_check_free_elements_and_reorganise(1)) + { + return MakeResult(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); + } + + if (wallEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) + { + if (_bannerId == BANNER_INDEX_NULL) + { + log_error("Banner Index not specified."); + return std::make_unique( + GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); + } + + auto banner = GetBanner(_bannerId); + if (!banner->IsNull()) + { + log_error("No free banners available"); + return std::make_unique(GameActions::Status::NoFreeElements); + } + + banner->text = {}; + banner->colour = COLOUR_WHITE; + banner->text_colour = COLOUR_WHITE; + banner->flags = BANNER_FLAG_IS_WALL; + banner->type = 0; // Banner must be deleted after this point in an early return + banner->position = TileCoordsXY(_loc); + + ride_id_t rideIndex = banner_get_closest_ride_index(targetLoc); + if (rideIndex != RIDE_ID_NULL) + { + banner->ride_index = rideIndex; + banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; + } + } + + TileElement* tileElement = tile_element_insert(targetLoc, 0b0000); + assert(tileElement != nullptr); + + map_animation_create(MAP_ANIMATION_TYPE_WALL, targetLoc); + + tileElement->SetType(TILE_ELEMENT_TYPE_WALL); + WallElement* wallElement = tileElement->AsWall(); + wallElement->clearance_height = clearanceHeight; + wallElement->SetDirection(_edge); + wallElement->SetSlope(edgeSlope); + + wallElement->SetPrimaryColour(_primaryColour); + wallElement->SetSecondaryColour(_secondaryColour); + + if (wallAcrossTrack) + { + wallElement->SetAcrossTrack(true); + } + + wallElement->SetEntryIndex(_wallType); + if (_bannerId != BANNER_INDEX_NULL) + { + wallElement->SetBannerIndex(_bannerId); + } + + if (wallEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) + { + wallElement->SetTertiaryColour(_tertiaryColour); + } + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + wallElement->SetGhost(true); + } + + res->tileElement = tileElement; + map_invalidate_tile_zoom1({ _loc, wallElement->GetBaseZ(), wallElement->GetBaseZ() + 72 }); + + res->Cost = wallEntry->wall.price; + return res; +} + +/** + * + * rct2: 0x006E5CBA + */ +bool WallPlaceAction::WallCheckObstructionWithTrack( + rct_scenery_entry* wall, int32_t z0, TrackElement* trackElement, bool* wallAcrossTrack) const +{ + track_type_t trackType = trackElement->GetTrackType(); + int32_t sequence = trackElement->GetSequenceIndex(); + int32_t direction = (_edge - trackElement->GetDirection()) & TILE_ELEMENT_DIRECTION_MASK; + auto ride = get_ride(trackElement->GetRideIndex()); + if (ride == nullptr) + { + return false; + } + + if (TrackIsAllowedWallEdges(ride->type, trackType, sequence, direction)) + { + return true; + } + + if (!(wall->wall.flags & WALL_SCENERY_IS_DOOR)) + { + return false; + } + + if (!(RideTypeDescriptors[ride->type].Flags & RIDE_TYPE_FLAG_ALLOW_DOORS_ON_TRACK)) + { + return false; + } + + *wallAcrossTrack = true; + if (z0 & 1) + { + return false; + } + + int32_t z; + if (sequence == 0) + { + if (TrackSequenceProperties[trackType][0] & TRACK_SEQUENCE_FLAG_DISALLOW_DOORS) + { + return false; + } + + if (TrackDefinitions[trackType].bank_start == 0) + { + if (!(TrackCoordinates[trackType].rotation_begin & 4)) + { + direction = direction_reverse(trackElement->GetDirection()); + if (direction == _edge) + { + const rct_preview_track* trackBlock = &TrackBlocks[trackType][sequence]; + z = TrackCoordinates[trackType].z_begin; + z = trackElement->base_height + ((z - trackBlock->z) * 8); + if (z == z0) + { + return true; + } + } + } + } + } + + const rct_preview_track* trackBlock = &TrackBlocks[trackType][sequence + 1]; + if (trackBlock->index != 0xFF) + { + return false; + } + + if (TrackDefinitions[trackType].bank_end != 0) + { + return false; + } + + direction = TrackCoordinates[trackType].rotation_end; + if (direction & 4) + { + return false; + } + + direction = (trackElement->GetDirection() + TrackCoordinates[trackType].rotation_end) & TILE_ELEMENT_DIRECTION_MASK; + if (direction != _edge) + { + return false; + } + + trackBlock = &TrackBlocks[trackType][sequence]; + z = TrackCoordinates[trackType].z_end; + z = trackElement->base_height + ((z - trackBlock->z) * 8); + return z == z0; +} + +/** + * + * rct2: 0x006E5C1A + */ +GameActions::Result::Ptr WallPlaceAction::WallCheckObstruction( + rct_scenery_entry* wall, int32_t z0, int32_t z1, bool* wallAcrossTrack) const +{ + int32_t entryType, sequence; + rct_scenery_entry* entry; + rct_large_scenery_tile* tile; + + *wallAcrossTrack = false; + gMapGroundFlags = ELEMENT_IS_ABOVE_GROUND; + if (map_is_location_at_edge(_loc)) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_OFF_EDGE_OF_MAP); + } + + TileElement* tileElement = map_get_first_element_at(_loc); + do + { + if (tileElement == nullptr) + break; + int32_t elementType = tileElement->GetType(); + if (elementType == TILE_ELEMENT_TYPE_SURFACE) + continue; + if (tileElement->IsGhost()) + continue; + if (z0 >= tileElement->clearance_height) + continue; + if (z1 <= tileElement->base_height) + continue; + if (elementType == TILE_ELEMENT_TYPE_WALL) + { + int32_t direction = tileElement->GetDirection(); + if (_edge == direction) + { + auto res = MakeResult(GameActions::Status::NoClearance, STR_NONE); + map_obstruction_set_error_text(tileElement, *res); + return res; + } + continue; + } + if (tileElement->GetOccupiedQuadrants() == 0) + continue; + auto res = MakeResult(GameActions::Status::NoClearance, STR_NONE); + switch (elementType) + { + case TILE_ELEMENT_TYPE_ENTRANCE: + map_obstruction_set_error_text(tileElement, *res); + return res; + case TILE_ELEMENT_TYPE_PATH: + if (tileElement->AsPath()->GetEdges() & (1 << _edge)) + { + map_obstruction_set_error_text(tileElement, *res); + return res; + } + break; + case TILE_ELEMENT_TYPE_LARGE_SCENERY: + entryType = tileElement->AsLargeScenery()->GetEntryIndex(); + sequence = tileElement->AsLargeScenery()->GetSequenceIndex(); + entry = get_large_scenery_entry(entryType); + tile = &entry->large_scenery.tiles[sequence]; + { + int32_t direction = ((_edge - tileElement->GetDirection()) & TILE_ELEMENT_DIRECTION_MASK) + 8; + if (!(tile->flags & (1 << direction))) + { + map_obstruction_set_error_text(tileElement, *res); + return res; + } + } + break; + case TILE_ELEMENT_TYPE_SMALL_SCENERY: + entry = tileElement->AsSmallScenery()->GetEntry(); + if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_NO_WALLS)) + { + map_obstruction_set_error_text(tileElement, *res); + return res; + } + break; + case TILE_ELEMENT_TYPE_TRACK: + if (!WallCheckObstructionWithTrack(wall, z0, tileElement->AsTrack(), wallAcrossTrack)) + { + return res; + } + break; + } + } while (!(tileElement++)->IsLastForTile()); + + return MakeResult(); +} diff --git a/src/openrct2/actions/WallPlaceAction.h b/src/openrct2/actions/WallPlaceAction.h new file mode 100644 index 0000000000..bdf98917a2 --- /dev/null +++ b/src/openrct2/actions/WallPlaceAction.h @@ -0,0 +1,127 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../ride/RideData.h" +#include "../ride/TrackData.h" +#include "../world/Scenery.h" +#include "GameAction.h" + +class WallPlaceActionResult final : public GameActions::Result +{ +public: + WallPlaceActionResult() + : GameActions::Result(GameActions::Status::Ok, STR_CANT_BUILD_PARK_ENTRANCE_HERE) + { + } + + WallPlaceActionResult(GameActions::Status err) + : GameActions::Result(err, STR_CANT_BUILD_PARK_ENTRANCE_HERE) + { + } + + WallPlaceActionResult(GameActions::Status err, rct_string_id msg) + : GameActions::Result(err, STR_CANT_BUILD_PARK_ENTRANCE_HERE, msg) + { + } + + WallPlaceActionResult(GameActions::Status error, rct_string_id msg, uint8_t* args) + : GameActions::Result(error, STR_CANT_BUILD_PARK_ENTRANCE_HERE, msg, args) + { + } + + TileElement* tileElement = nullptr; +}; + +DEFINE_GAME_ACTION(WallPlaceAction, GAME_COMMAND_PLACE_WALL, WallPlaceActionResult) +{ +private: + ObjectEntryIndex _wallType{ OBJECT_ENTRY_INDEX_NULL }; + CoordsXYZ _loc; + Direction _edge{ INVALID_DIRECTION }; + int32_t _primaryColour{ COLOUR_BLACK }; + int32_t _secondaryColour{ COLOUR_BLACK }; + int32_t _tertiaryColour{ COLOUR_BLACK }; + BannerIndex _bannerId{ BANNER_INDEX_NULL }; + +public: + WallPlaceAction() = default; + + WallPlaceAction( + ObjectEntryIndex wallType, const CoordsXYZ& loc, uint8_t edge, int32_t primaryColour, int32_t secondaryColour, + int32_t tertiaryColour) + : _wallType(wallType) + , _loc(loc) + , _edge(edge) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + , _tertiaryColour(tertiaryColour) + { + rct_scenery_entry* sceneryEntry = get_wall_entry(_wallType); + if (sceneryEntry != nullptr) + { + if (sceneryEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) + { + _bannerId = create_new_banner(0); + } + } + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + + uint16_t GetActionFlags() const override final + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + /** + * + * rct2: 0x006E5CBA + */ + bool WallCheckObstructionWithTrack(rct_scenery_entry * wall, int32_t z0, TrackElement * trackElement, bool* wallAcrossTrack) + const; + /** + * + * rct2: 0x006E5C1A + */ + GameActions::Result::Ptr WallCheckObstruction(rct_scenery_entry * wall, int32_t z0, int32_t z1, bool* wallAcrossTrack) + const; + + /** + * Gets whether the given track type can have a wall placed on the edge of the given direction. + * Some thin tracks for example are allowed to have walls either side of the track, but wider tracks can not. + */ + static bool TrackIsAllowedWallEdges(uint8_t rideType, uint8_t trackType, uint8_t trackSequence, uint8_t direction) + { + if (!ride_type_has_flag(rideType, RIDE_TYPE_FLAG_TRACK_NO_WALLS)) + { + if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_FLAT_RIDE)) + { + if (FlatRideTrackSequenceElementAllowedWallEdges[trackType][trackSequence] & (1 << direction)) + { + return true; + } + } + else + { + if (TrackSequenceElementAllowedWallEdges[trackType][trackSequence] & (1 << direction)) + { + return true; + } + } + } + return false; + } +}; diff --git a/src/openrct2/actions/WallPlaceAction.hpp b/src/openrct2/actions/WallPlaceAction.hpp deleted file mode 100644 index 33b01f3bd8..0000000000 --- a/src/openrct2/actions/WallPlaceAction.hpp +++ /dev/null @@ -1,677 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../ride/RideData.h" -#include "../ride/Track.h" -#include "../ride/TrackData.h" -#include "../ride/TrackDesign.h" -#include "../world/Banner.h" -#include "../world/LargeScenery.h" -#include "../world/MapAnimation.h" -#include "../world/Scenery.h" -#include "../world/SmallScenery.h" -#include "../world/Surface.h" -#include "../world/Wall.h" -#include "GameAction.h" - -class WallPlaceActionResult final : public GameActions::Result -{ -public: - WallPlaceActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_CANT_BUILD_PARK_ENTRANCE_HERE) - { - } - - WallPlaceActionResult(GameActions::Status err) - : GameActions::Result(err, STR_CANT_BUILD_PARK_ENTRANCE_HERE) - { - } - - WallPlaceActionResult(GameActions::Status err, rct_string_id msg) - : GameActions::Result(err, STR_CANT_BUILD_PARK_ENTRANCE_HERE, msg) - { - } - - WallPlaceActionResult(GameActions::Status error, rct_string_id msg, uint8_t* args) - : GameActions::Result(error, STR_CANT_BUILD_PARK_ENTRANCE_HERE, msg, args) - { - } - - TileElement* tileElement = nullptr; -}; - -DEFINE_GAME_ACTION(WallPlaceAction, GAME_COMMAND_PLACE_WALL, WallPlaceActionResult) -{ -private: - ObjectEntryIndex _wallType{ OBJECT_ENTRY_INDEX_NULL }; - CoordsXYZ _loc; - Direction _edge{ INVALID_DIRECTION }; - int32_t _primaryColour{ COLOUR_BLACK }; - int32_t _secondaryColour{ COLOUR_BLACK }; - int32_t _tertiaryColour{ COLOUR_BLACK }; - BannerIndex _bannerId{ BANNER_INDEX_NULL }; - -public: - WallPlaceAction() = default; - - WallPlaceAction( - ObjectEntryIndex wallType, const CoordsXYZ& loc, uint8_t edge, int32_t primaryColour, int32_t secondaryColour, - int32_t tertiaryColour) - : _wallType(wallType) - , _loc(loc) - , _edge(edge) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - , _tertiaryColour(tertiaryColour) - { - rct_scenery_entry* sceneryEntry = get_wall_entry(_wallType); - if (sceneryEntry != nullptr) - { - if (sceneryEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) - { - _bannerId = create_new_banner(0); - } - } - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - visitor.Visit("object", _wallType); - visitor.Visit("edge", _edge); - visitor.Visit("primaryColour", _primaryColour); - visitor.Visit("secondaryColour", _secondaryColour); - visitor.Visit("tertiaryColour", _tertiaryColour); - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_wallType); - if (sceneryEntry != nullptr) - { - if (sceneryEntry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - _bannerId = create_new_banner(0); - } - } - } - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_wallType) << DS_TAG(_loc) << DS_TAG(_edge) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) - << DS_TAG(_tertiaryColour) << DS_TAG(_bannerId); - } - - GameActions::Result::Ptr Query() const override - { - auto res = std::make_unique(); - res->ErrorTitle = STR_CANT_BUILD_PARK_ENTRANCE_HERE; - res->Position = _loc; - - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x += 16; - res->Position.y += 16; - - if (_loc.z == 0) - { - res->Position.z = tile_element_height(res->Position); - } - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::NotOwned); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) - && !gCheatsSandboxMode) - { - if (_loc.z == 0) - { - if (!map_is_location_in_park(_loc)) - { - return std::make_unique(GameActions::Status::NotOwned); - } - } - else if (!map_is_location_owned(_loc)) - { - return std::make_unique(GameActions::Status::NotOwned); - } - } - else if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY)) - { - log_error("Invalid x/y coordinates. x = %d y = %d", _loc.x, _loc.y); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - if (_edge > 3) - { - return std::make_unique(GameActions::Status::InvalidParameters); - } - - uint8_t edgeSlope = 0; - auto targetHeight = _loc.z; - if (targetHeight == 0) - { - auto* surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); - return std::make_unique(GameActions::Status::InvalidParameters); - } - targetHeight = surfaceElement->GetBaseZ(); - - uint8_t slope = surfaceElement->GetSlope(); - edgeSlope = LandSlopeToWallSlope[slope][_edge & 3]; - if (edgeSlope & EDGE_SLOPE_ELEVATED) - { - targetHeight += 16; - edgeSlope &= ~EDGE_SLOPE_ELEVATED; - } - } - - auto* surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - if (surfaceElement->GetWaterHeight() > 0) - { - uint16_t waterHeight = surfaceElement->GetWaterHeight(); - - if (targetHeight < waterHeight && !gCheatsDisableClearanceChecks) - { - return std::make_unique(GameActions::Status::Disallowed, STR_CANT_BUILD_THIS_UNDERWATER); - } - } - - if (targetHeight < surfaceElement->GetBaseZ() && !gCheatsDisableClearanceChecks) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - - if (!(edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS))) - { - uint8_t newEdge = (_edge + 2) & 3; - uint8_t newBaseHeight = surfaceElement->base_height; - newBaseHeight += 2; - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - if (targetHeight / 8 < newBaseHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - - if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) - { - newEdge = (newEdge - 1) & 3; - - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - newEdge = (newEdge + 2) & 3; - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - newBaseHeight += 2; - if (targetHeight / 8 < newBaseHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - newBaseHeight -= 2; - } - } - } - } - - newEdge = (_edge + 3) & 3; - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - if (targetHeight / 8 < newBaseHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - - if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) - { - newEdge = (newEdge - 1) & 3; - - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - newEdge = (newEdge + 2) & 3; - if (surfaceElement->GetSlope() & (1 << newEdge)) - { - newBaseHeight += 2; - if (targetHeight / 8 < newBaseHeight) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); - } - } - } - } - } - } - - rct_scenery_entry* wallEntry = get_wall_entry(_wallType); - - if (wallEntry == nullptr) - { - log_error("Wall Type not found %d", _wallType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - if (wallEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) - { - if (_bannerId == BANNER_INDEX_NULL) - { - log_error("Banner Index not specified."); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); - } - - auto banner = GetBanner(_bannerId); - if (!banner->IsNull()) - { - log_error("No free banners available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - } - - uint8_t clearanceHeight = targetHeight / 8; - if (edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) - { - if (wallEntry->wall.flags & WALL_SCENERY_CANT_BUILD_ON_SLOPE) - { - return std::make_unique( - GameActions::Status::Disallowed, STR_ERR_UNABLE_TO_BUILD_THIS_ON_SLOPE); - } - clearanceHeight += 2; - } - clearanceHeight += wallEntry->wall.height; - - bool wallAcrossTrack = false; - if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsDisableClearanceChecks) - { - auto result = WallCheckObstruction(wallEntry, targetHeight / 8, clearanceHeight, &wallAcrossTrack); - if (result->Error != GameActions::Status::Ok) - { - return result; - } - } - - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); - } - - res->Cost = wallEntry->wall.price; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = std::make_unique(); - res->ErrorTitle = STR_CANT_BUILD_PARK_ENTRANCE_HERE; - res->Position = _loc; - - res->Expenditure = ExpenditureType::Landscaping; - res->Position.x += 16; - res->Position.y += 16; - - if (res->Position.z == 0) - { - res->Position.z = tile_element_height(res->Position); - } - - uint8_t edgeSlope = 0; - auto targetHeight = _loc.z; - if (targetHeight == 0) - { - auto* surfaceElement = map_get_surface_element_at(_loc); - if (surfaceElement == nullptr) - { - log_error("Surface element not found at %d, %d.", _loc.x, _loc.y); - return std::make_unique(GameActions::Status::InvalidParameters); - } - targetHeight = surfaceElement->GetBaseZ(); - - uint8_t slope = surfaceElement->GetSlope(); - edgeSlope = LandSlopeToWallSlope[slope][_edge & 3]; - if (edgeSlope & EDGE_SLOPE_ELEVATED) - { - targetHeight += 16; - edgeSlope &= ~EDGE_SLOPE_ELEVATED; - } - } - auto targetLoc = CoordsXYZ(_loc, targetHeight); - - rct_scenery_entry* wallEntry = get_wall_entry(_wallType); - - if (wallEntry == nullptr) - { - log_error("Wall Type not found %d", _wallType); - return std::make_unique(GameActions::Status::InvalidParameters); - } - - uint8_t clearanceHeight = targetHeight / COORDS_Z_STEP; - if (edgeSlope & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) - { - clearanceHeight += 2; - } - clearanceHeight += wallEntry->wall.height; - - bool wallAcrossTrack = false; - if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsDisableClearanceChecks) - { - auto result = WallCheckObstruction(wallEntry, targetHeight / COORDS_Z_STEP, clearanceHeight, &wallAcrossTrack); - if (result->Error != GameActions::Status::Ok) - { - return result; - } - } - - if (!map_check_free_elements_and_reorganise(1)) - { - return MakeResult(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); - } - - if (wallEntry->wall.scrolling_mode != SCROLLING_MODE_NONE) - { - if (_bannerId == BANNER_INDEX_NULL) - { - log_error("Banner Index not specified."); - return std::make_unique( - GameActions::Status::InvalidParameters, STR_TOO_MANY_BANNERS_IN_GAME); - } - - auto banner = GetBanner(_bannerId); - if (!banner->IsNull()) - { - log_error("No free banners available"); - return std::make_unique(GameActions::Status::NoFreeElements); - } - - banner->text = {}; - banner->colour = COLOUR_WHITE; - banner->text_colour = COLOUR_WHITE; - banner->flags = BANNER_FLAG_IS_WALL; - banner->type = 0; // Banner must be deleted after this point in an early return - banner->position = TileCoordsXY(_loc); - - ride_id_t rideIndex = banner_get_closest_ride_index(targetLoc); - if (rideIndex != RIDE_ID_NULL) - { - banner->ride_index = rideIndex; - banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; - } - } - - TileElement* tileElement = tile_element_insert(targetLoc, 0b0000); - assert(tileElement != nullptr); - - map_animation_create(MAP_ANIMATION_TYPE_WALL, targetLoc); - - tileElement->SetType(TILE_ELEMENT_TYPE_WALL); - WallElement* wallElement = tileElement->AsWall(); - wallElement->clearance_height = clearanceHeight; - wallElement->SetDirection(_edge); - wallElement->SetSlope(edgeSlope); - - wallElement->SetPrimaryColour(_primaryColour); - wallElement->SetSecondaryColour(_secondaryColour); - - if (wallAcrossTrack) - { - wallElement->SetAcrossTrack(true); - } - - wallElement->SetEntryIndex(_wallType); - if (_bannerId != BANNER_INDEX_NULL) - { - wallElement->SetBannerIndex(_bannerId); - } - - if (wallEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) - { - wallElement->SetTertiaryColour(_tertiaryColour); - } - - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - wallElement->SetGhost(true); - } - - res->tileElement = tileElement; - map_invalidate_tile_zoom1({ _loc, wallElement->GetBaseZ(), wallElement->GetBaseZ() + 72 }); - - res->Cost = wallEntry->wall.price; - return res; - } - -private: - /** - * - * rct2: 0x006E5CBA - */ - bool WallCheckObstructionWithTrack(rct_scenery_entry * wall, int32_t z0, TrackElement * trackElement, bool* wallAcrossTrack) - const - { - track_type_t trackType = trackElement->GetTrackType(); - int32_t sequence = trackElement->GetSequenceIndex(); - int32_t direction = (_edge - trackElement->GetDirection()) & TILE_ELEMENT_DIRECTION_MASK; - auto ride = get_ride(trackElement->GetRideIndex()); - if (ride == nullptr) - { - return false; - } - - if (TrackIsAllowedWallEdges(ride->type, trackType, sequence, direction)) - { - return true; - } - - if (!(wall->wall.flags & WALL_SCENERY_IS_DOOR)) - { - return false; - } - - if (!(RideTypeDescriptors[ride->type].Flags & RIDE_TYPE_FLAG_ALLOW_DOORS_ON_TRACK)) - { - return false; - } - - *wallAcrossTrack = true; - if (z0 & 1) - { - return false; - } - - int32_t z; - if (sequence == 0) - { - if (TrackSequenceProperties[trackType][0] & TRACK_SEQUENCE_FLAG_DISALLOW_DOORS) - { - return false; - } - - if (TrackDefinitions[trackType].bank_start == 0) - { - if (!(TrackCoordinates[trackType].rotation_begin & 4)) - { - direction = direction_reverse(trackElement->GetDirection()); - if (direction == _edge) - { - const rct_preview_track* trackBlock = &TrackBlocks[trackType][sequence]; - z = TrackCoordinates[trackType].z_begin; - z = trackElement->base_height + ((z - trackBlock->z) * 8); - if (z == z0) - { - return true; - } - } - } - } - } - - const rct_preview_track* trackBlock = &TrackBlocks[trackType][sequence + 1]; - if (trackBlock->index != 0xFF) - { - return false; - } - - if (TrackDefinitions[trackType].bank_end != 0) - { - return false; - } - - direction = TrackCoordinates[trackType].rotation_end; - if (direction & 4) - { - return false; - } - - direction = (trackElement->GetDirection() + TrackCoordinates[trackType].rotation_end) & TILE_ELEMENT_DIRECTION_MASK; - if (direction != _edge) - { - return false; - } - - trackBlock = &TrackBlocks[trackType][sequence]; - z = TrackCoordinates[trackType].z_end; - z = trackElement->base_height + ((z - trackBlock->z) * 8); - return z == z0; - } - - /** - * - * rct2: 0x006E5C1A - */ - GameActions::Result::Ptr WallCheckObstruction(rct_scenery_entry * wall, int32_t z0, int32_t z1, bool* wallAcrossTrack) const - { - int32_t entryType, sequence; - rct_scenery_entry* entry; - rct_large_scenery_tile* tile; - - *wallAcrossTrack = false; - gMapGroundFlags = ELEMENT_IS_ABOVE_GROUND; - if (map_is_location_at_edge(_loc)) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_OFF_EDGE_OF_MAP); - } - - TileElement* tileElement = map_get_first_element_at(_loc); - do - { - if (tileElement == nullptr) - break; - int32_t elementType = tileElement->GetType(); - if (elementType == TILE_ELEMENT_TYPE_SURFACE) - continue; - if (tileElement->IsGhost()) - continue; - if (z0 >= tileElement->clearance_height) - continue; - if (z1 <= tileElement->base_height) - continue; - if (elementType == TILE_ELEMENT_TYPE_WALL) - { - int32_t direction = tileElement->GetDirection(); - if (_edge == direction) - { - auto res = MakeResult(GameActions::Status::NoClearance, STR_NONE); - map_obstruction_set_error_text(tileElement, *res); - return res; - } - continue; - } - if (tileElement->GetOccupiedQuadrants() == 0) - continue; - auto res = MakeResult(GameActions::Status::NoClearance, STR_NONE); - switch (elementType) - { - case TILE_ELEMENT_TYPE_ENTRANCE: - map_obstruction_set_error_text(tileElement, *res); - return res; - case TILE_ELEMENT_TYPE_PATH: - if (tileElement->AsPath()->GetEdges() & (1 << _edge)) - { - map_obstruction_set_error_text(tileElement, *res); - return res; - } - break; - case TILE_ELEMENT_TYPE_LARGE_SCENERY: - entryType = tileElement->AsLargeScenery()->GetEntryIndex(); - sequence = tileElement->AsLargeScenery()->GetSequenceIndex(); - entry = get_large_scenery_entry(entryType); - tile = &entry->large_scenery.tiles[sequence]; - { - int32_t direction = ((_edge - tileElement->GetDirection()) & TILE_ELEMENT_DIRECTION_MASK) + 8; - if (!(tile->flags & (1 << direction))) - { - map_obstruction_set_error_text(tileElement, *res); - return res; - } - } - break; - case TILE_ELEMENT_TYPE_SMALL_SCENERY: - entry = tileElement->AsSmallScenery()->GetEntry(); - if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_NO_WALLS)) - { - map_obstruction_set_error_text(tileElement, *res); - return res; - } - break; - case TILE_ELEMENT_TYPE_TRACK: - if (!WallCheckObstructionWithTrack(wall, z0, tileElement->AsTrack(), wallAcrossTrack)) - { - return res; - } - break; - } - } while (!(tileElement++)->IsLastForTile()); - - return MakeResult(); - } - - /** - * Gets whether the given track type can have a wall placed on the edge of the given direction. - * Some thin tracks for example are allowed to have walls either side of the track, but wider tracks can not. - */ - static bool TrackIsAllowedWallEdges(uint8_t rideType, uint8_t trackType, uint8_t trackSequence, uint8_t direction) - { - if (!ride_type_has_flag(rideType, RIDE_TYPE_FLAG_TRACK_NO_WALLS)) - { - if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_FLAT_RIDE)) - { - if (FlatRideTrackSequenceElementAllowedWallEdges[trackType][trackSequence] & (1 << direction)) - { - return true; - } - } - else - { - if (TrackSequenceElementAllowedWallEdges[trackType][trackSequence] & (1 << direction)) - { - return true; - } - } - } - return false; - } -}; diff --git a/src/openrct2/actions/WallRemoveAction.cpp b/src/openrct2/actions/WallRemoveAction.cpp new file mode 100644 index 0000000000..258b19a2a6 --- /dev/null +++ b/src/openrct2/actions/WallRemoveAction.cpp @@ -0,0 +1,109 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "WallRemoveAction.h" + +#include "../Cheats.h" +#include "../OpenRCT2.h" +#include "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Location.hpp" +#include "../world/Wall.h" + +void WallRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit(_loc); +} + +void WallRemoveAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); +} + +GameActions::Result::Ptr WallRemoveAction::Query() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + + if (!LocationValid(_loc)) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + const bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; + if (!isGhost && !(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(_loc)) + { + return std::make_unique( + GameActions::Status::NotOwned, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + TileElement* wallElement = GetFirstWallElementAt(_loc, isGhost); + if (wallElement == nullptr) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + res->Cost = 0; + return res; +} + +GameActions::Result::Ptr WallRemoveAction::Execute() const +{ + GameActions::Result::Ptr res = std::make_unique(); + res->Cost = 0; + res->Expenditure = ExpenditureType::Landscaping; + + const bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; + + TileElement* wallElement = GetFirstWallElementAt(_loc, isGhost); + if (wallElement == nullptr) + { + return std::make_unique( + GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = tile_element_height(res->Position); + + tile_element_remove_banner_entry(wallElement); + map_invalidate_tile_zoom1({ _loc, wallElement->GetBaseZ(), (wallElement->GetBaseZ()) + 72 }); + tile_element_remove(wallElement); + + return res; +} + +TileElement* WallRemoveAction::GetFirstWallElementAt(const CoordsXYZD& location, bool isGhost) const +{ + TileElement* tileElement = map_get_first_element_at(location); + if (!tileElement) + return nullptr; + + do + { + if (tileElement->GetType() != TILE_ELEMENT_TYPE_WALL) + continue; + if (tileElement->GetBaseZ() != location.z) + continue; + if (tileElement->GetDirection() != location.direction) + continue; + if (tileElement->IsGhost() != isGhost) + continue; + + return tileElement; + } while (!(tileElement++)->IsLastForTile()); + return nullptr; +} diff --git a/src/openrct2/actions/WallRemoveAction.h b/src/openrct2/actions/WallRemoveAction.h new file mode 100644 index 0000000000..26d12a7672 --- /dev/null +++ b/src/openrct2/actions/WallRemoveAction.h @@ -0,0 +1,33 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(WallRemoveAction, GAME_COMMAND_REMOVE_WALL, GameActions::Result) +{ +private: + CoordsXYZD _loc; + +public: + WallRemoveAction() = default; + WallRemoveAction(const CoordsXYZD& loc) + : _loc(loc) + { + } + + void AcceptParameters(GameActionParameterVisitor & visitor) override; + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + TileElement* GetFirstWallElementAt(const CoordsXYZD& location, bool isGhost) const; +}; diff --git a/src/openrct2/actions/WallRemoveAction.hpp b/src/openrct2/actions/WallRemoveAction.hpp deleted file mode 100644 index 79227447b4..0000000000 --- a/src/openrct2/actions/WallRemoveAction.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../Cheats.h" -#include "../OpenRCT2.h" -#include "../core/MemoryStream.h" -#include "../interface/Window.h" -#include "../localisation/StringIds.h" -#include "../management/Finance.h" -#include "../world/Location.hpp" -#include "../world/Wall.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(WallRemoveAction, GAME_COMMAND_REMOVE_WALL, GameActions::Result) -{ -private: - CoordsXYZD _loc; - -public: - WallRemoveAction() = default; - WallRemoveAction(const CoordsXYZD& loc) - : _loc(loc) - { - } - - void AcceptParameters(GameActionParameterVisitor & visitor) override - { - visitor.Visit(_loc); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc); - } - - GameActions::Result::Ptr Query() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - - if (!LocationValid(_loc)) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - const bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; - if (!isGhost && !(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(_loc)) - { - return std::make_unique( - GameActions::Status::NotOwned, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - TileElement* wallElement = GetFirstWallElementAt(_loc, isGhost); - if (wallElement == nullptr) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - res->Cost = 0; - return res; - } - - GameActions::Result::Ptr Execute() const override - { - GameActions::Result::Ptr res = std::make_unique(); - res->Cost = 0; - res->Expenditure = ExpenditureType::Landscaping; - - const bool isGhost = GetFlags() & GAME_COMMAND_FLAG_GHOST; - - TileElement* wallElement = GetFirstWallElementAt(_loc, isGhost); - if (wallElement == nullptr) - { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); - } - - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = tile_element_height(res->Position); - - tile_element_remove_banner_entry(wallElement); - map_invalidate_tile_zoom1({ _loc, wallElement->GetBaseZ(), (wallElement->GetBaseZ()) + 72 }); - tile_element_remove(wallElement); - - return res; - } - -private: - TileElement* GetFirstWallElementAt(const CoordsXYZD& location, bool isGhost) const - { - TileElement* tileElement = map_get_first_element_at(location); - if (!tileElement) - return nullptr; - - do - { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_WALL) - continue; - if (tileElement->GetBaseZ() != location.z) - continue; - if (tileElement->GetDirection() != location.direction) - continue; - if (tileElement->IsGhost() != isGhost) - continue; - - return tileElement; - } while (!(tileElement++)->IsLastForTile()); - return nullptr; - } -}; diff --git a/src/openrct2/actions/WallSetColourAction.cpp b/src/openrct2/actions/WallSetColourAction.cpp new file mode 100644 index 0000000000..f150aae7bb --- /dev/null +++ b/src/openrct2/actions/WallSetColourAction.cpp @@ -0,0 +1,132 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "WallSetColourAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../ride/Track.h" +#include "../ride/TrackData.h" +#include "../world/Banner.h" +#include "../world/LargeScenery.h" +#include "../world/MapAnimation.h" +#include "../world/Scenery.h" +#include "../world/SmallScenery.h" +#include "../world/Surface.h" + +void WallSetColourAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) << DS_TAG(_tertiaryColour); +} + +GameActions::Result::Ptr WallSetColourAction::Query() const +{ + auto res = MakeResult(); + res->ErrorTitle = STR_CANT_REPAINT_THIS; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + + res->Expenditure = ExpenditureType::Landscaping; + + if (!LocationValid(_loc)) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_in_park(_loc) && !gCheatsSandboxMode) + { + return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + auto wallElement = map_get_wall_element_at(_loc); + if (wallElement == nullptr) + { + log_error( + "Could not find wall element at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(wallElement->IsGhost())) + { + return res; + } + + rct_scenery_entry* sceneryEntry = wallElement->GetEntry(); + if (sceneryEntry == nullptr) + { + log_error("Could not find wall object"); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + + if (_primaryColour > 31) + { + log_error("Primary colour invalid: colour = %d", _primaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (_secondaryColour > 31) + { + log_error("Secondary colour invalid: colour = %d", _secondaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) + { + if (_tertiaryColour > 31) + { + log_error("Tertiary colour invalid: colour = %d", _tertiaryColour); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + } + return res; +} + +GameActions::Result::Ptr WallSetColourAction::Execute() const +{ + auto res = MakeResult(); + res->ErrorTitle = STR_CANT_REPAINT_THIS; + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = _loc.z; + res->Expenditure = ExpenditureType::Landscaping; + + auto wallElement = map_get_wall_element_at(_loc); + if (wallElement == nullptr) + { + log_error( + "Could not find wall element at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, _loc.direction); + return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); + } + + if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(wallElement->IsGhost())) + { + return res; + } + + rct_scenery_entry* sceneryEntry = wallElement->GetEntry(); + if (sceneryEntry == nullptr) + { + log_error("Could not find wall object"); + return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); + } + + wallElement->SetPrimaryColour(_primaryColour); + wallElement->SetSecondaryColour(_secondaryColour); + + if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) + { + wallElement->SetTertiaryColour(_tertiaryColour); + } + map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 72 }); + + return res; +} diff --git a/src/openrct2/actions/WallSetColourAction.h b/src/openrct2/actions/WallSetColourAction.h new file mode 100644 index 0000000000..3a83ea7218 --- /dev/null +++ b/src/openrct2/actions/WallSetColourAction.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(WallSetColourAction, GAME_COMMAND_SET_WALL_COLOUR, GameActions::Result) +{ +private: + CoordsXYZD _loc; + int32_t _primaryColour{}; + int32_t _secondaryColour{}; + int32_t _tertiaryColour{}; + +public: + WallSetColourAction() = default; + + WallSetColourAction(const CoordsXYZD& loc, int32_t primaryColour, int32_t secondaryColour, int32_t tertiaryColour) + : _loc(loc) + , _primaryColour(primaryColour) + , _secondaryColour(secondaryColour) + , _tertiaryColour(tertiaryColour) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; +}; diff --git a/src/openrct2/actions/WallSetColourAction.hpp b/src/openrct2/actions/WallSetColourAction.hpp deleted file mode 100644 index 99e91cc6c0..0000000000 --- a/src/openrct2/actions/WallSetColourAction.hpp +++ /dev/null @@ -1,162 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../ride/Track.h" -#include "../ride/TrackData.h" -#include "../world/Banner.h" -#include "../world/LargeScenery.h" -#include "../world/MapAnimation.h" -#include "../world/Scenery.h" -#include "../world/SmallScenery.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(WallSetColourAction, GAME_COMMAND_SET_WALL_COLOUR, GameActions::Result) -{ -private: - CoordsXYZD _loc; - int32_t _primaryColour{}; - int32_t _secondaryColour{}; - int32_t _tertiaryColour{}; - -public: - WallSetColourAction() = default; - - WallSetColourAction(const CoordsXYZD& loc, int32_t primaryColour, int32_t secondaryColour, int32_t tertiaryColour) - : _loc(loc) - , _primaryColour(primaryColour) - , _secondaryColour(secondaryColour) - , _tertiaryColour(tertiaryColour) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_loc) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) << DS_TAG(_tertiaryColour); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->ErrorTitle = STR_CANT_REPAINT_THIS; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - - res->Expenditure = ExpenditureType::Landscaping; - - if (!LocationValid(_loc)) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_in_park(_loc) && !gCheatsSandboxMode) - { - return MakeResult(GameActions::Status::NotOwned, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); - } - - auto wallElement = map_get_wall_element_at(_loc); - if (wallElement == nullptr) - { - log_error( - "Could not find wall element at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, - _loc.direction); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(wallElement->IsGhost())) - { - return res; - } - - rct_scenery_entry* sceneryEntry = wallElement->GetEntry(); - if (sceneryEntry == nullptr) - { - log_error("Could not find wall object"); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - - if (_primaryColour > 31) - { - log_error("Primary colour invalid: colour = %d", _primaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (_secondaryColour > 31) - { - log_error("Secondary colour invalid: colour = %d", _secondaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) - { - if (_tertiaryColour > 31) - { - log_error("Tertiary colour invalid: colour = %d", _tertiaryColour); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - } - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->ErrorTitle = STR_CANT_REPAINT_THIS; - res->Position.x = _loc.x + 16; - res->Position.y = _loc.y + 16; - res->Position.z = _loc.z; - res->Expenditure = ExpenditureType::Landscaping; - - auto wallElement = map_get_wall_element_at(_loc); - if (wallElement == nullptr) - { - log_error( - "Could not find wall element at: x = %d, y = %d, z = %d, direction = %u", _loc.x, _loc.y, _loc.z, - _loc.direction); - return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS); - } - - if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && !(wallElement->IsGhost())) - { - return res; - } - - rct_scenery_entry* sceneryEntry = wallElement->GetEntry(); - if (sceneryEntry == nullptr) - { - log_error("Could not find wall object"); - return MakeResult(GameActions::Status::Unknown, STR_CANT_REPAINT_THIS); - } - - wallElement->SetPrimaryColour(_primaryColour); - wallElement->SetSecondaryColour(_secondaryColour); - - if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) - { - wallElement->SetTertiaryColour(_tertiaryColour); - } - map_invalidate_tile_zoom1({ _loc, _loc.z, _loc.z + 72 }); - - return res; - } - -private: -}; diff --git a/src/openrct2/actions/WaterLowerAction.cpp b/src/openrct2/actions/WaterLowerAction.cpp new file mode 100644 index 0000000000..fe3670148d --- /dev/null +++ b/src/openrct2/actions/WaterLowerAction.cpp @@ -0,0 +1,154 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "WaterLowerAction.h" + +#include "../OpenRCT2.h" +#include "../audio/audio.h" +#include "WaterSetHeightAction.h" + +void WaterLowerAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range); +} + +GameActions::Result::Ptr WaterLowerAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr WaterLowerAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr WaterLowerAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + + // Keep big coordinates within map boundaries + auto aX = std::max(32, _range.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); + auto aY = std::max(32, _range.GetTop()); + auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + res->Position.x = ((validRange.GetLeft() + validRange.GetRight()) / 2) + 16; + res->Position.y = ((validRange.GetTop() + validRange.GetBottom()) / 2) + 16; + int16_t z = tile_element_height(res->Position); + int16_t waterHeight = tile_element_water_height(res->Position); + if (waterHeight != 0) + { + z = waterHeight; + } + res->Position.z = z; + res->Expenditure = ExpenditureType::Landscaping; + + uint8_t minHeight = GetLowestHeight(validRange); + bool hasChanged = false; + bool withinOwnership = false; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + withinOwnership = true; + + uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; + if (height == 0) + continue; + + if (height < minHeight) + continue; + + height -= 2; + auto waterSetHeightAction = WaterSetHeightAction({ x, y }, height); + waterSetHeightAction.SetFlags(GetFlags()); + auto result = isExecuting ? GameActions::ExecuteNested(&waterSetHeightAction) + : GameActions::QueryNested(&waterSetHeightAction); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + hasChanged = true; + } + else + { + result->ErrorTitle = STR_CANT_LOWER_WATER_LEVEL_HERE; + return result; + } + } + } + + if (!withinOwnership) + { + GameActions::Result::Ptr ownerShipResult = std::make_unique( + GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + ownerShipResult->ErrorTitle = STR_CANT_LOWER_WATER_LEVEL_HERE; + return ownerShipResult; + } + + if (isExecuting && hasChanged) + { + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::LayingOutWater, res->Position); + } + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + return res; +} + +uint8_t WaterLowerAction::GetLowestHeight(MapRange validRange) const +{ + // The lowest height to lower the water to is the highest water level in the selection + uint8_t minHeight{ 0 }; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; + if (height == 0) + continue; + + if (height > minHeight) + { + minHeight = height; + } + } + } + + return minHeight; +} diff --git a/src/openrct2/actions/WaterLowerAction.h b/src/openrct2/actions/WaterLowerAction.h new file mode 100644 index 0000000000..6d4a9a0d11 --- /dev/null +++ b/src/openrct2/actions/WaterLowerAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(WaterLowerAction, GAME_COMMAND_LOWER_WATER, GameActions::Result) +{ +private: + MapRange _range; + +public: + WaterLowerAction() = default; + WaterLowerAction(MapRange range) + : _range(range) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; + uint8_t GetLowestHeight(MapRange validRange) const; +}; diff --git a/src/openrct2/actions/WaterLowerAction.hpp b/src/openrct2/actions/WaterLowerAction.hpp deleted file mode 100644 index 9591e90cba..0000000000 --- a/src/openrct2/actions/WaterLowerAction.hpp +++ /dev/null @@ -1,173 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once -#include "../audio/audio.h" -#include "GameAction.h" -#include "WaterSetHeightAction.hpp" - -DEFINE_GAME_ACTION(WaterLowerAction, GAME_COMMAND_LOWER_WATER, GameActions::Result) -{ -private: - MapRange _range; - -public: - WaterLowerAction() = default; - WaterLowerAction(MapRange range) - : _range(range) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - res->Position.x = ((validRange.GetLeft() + validRange.GetRight()) / 2) + 16; - res->Position.y = ((validRange.GetTop() + validRange.GetBottom()) / 2) + 16; - int16_t z = tile_element_height(res->Position); - int16_t waterHeight = tile_element_water_height(res->Position); - if (waterHeight != 0) - { - z = waterHeight; - } - res->Position.z = z; - res->Expenditure = ExpenditureType::Landscaping; - - uint8_t minHeight = GetLowestHeight(validRange); - bool hasChanged = false; - bool withinOwnership = false; - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - - auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - withinOwnership = true; - - uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; - if (height == 0) - continue; - - if (height < minHeight) - continue; - - height -= 2; - auto waterSetHeightAction = WaterSetHeightAction({ x, y }, height); - waterSetHeightAction.SetFlags(GetFlags()); - auto result = isExecuting ? GameActions::ExecuteNested(&waterSetHeightAction) - : GameActions::QueryNested(&waterSetHeightAction); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - hasChanged = true; - } - else - { - result->ErrorTitle = STR_CANT_LOWER_WATER_LEVEL_HERE; - return result; - } - } - } - - if (!withinOwnership) - { - GameActions::Result::Ptr ownerShipResult = std::make_unique( - GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - ownerShipResult->ErrorTitle = STR_CANT_LOWER_WATER_LEVEL_HERE; - return ownerShipResult; - } - - if (isExecuting && hasChanged) - { - OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::LayingOutWater, res->Position); - } - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - return res; - } - -private: - uint8_t GetLowestHeight(MapRange validRange) const - { - // The lowest height to lower the water to is the highest water level in the selection - uint8_t minHeight{ 0 }; - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - - auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; - if (height == 0) - continue; - - if (height > minHeight) - { - minHeight = height; - } - } - } - - return minHeight; - } -}; diff --git a/src/openrct2/actions/WaterRaiseAction.cpp b/src/openrct2/actions/WaterRaiseAction.cpp new file mode 100644 index 0000000000..5503f7a0ba --- /dev/null +++ b/src/openrct2/actions/WaterRaiseAction.cpp @@ -0,0 +1,163 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "WaterRaiseAction.h" + +#include "../OpenRCT2.h" +#include "../audio/audio.h" +#include "WaterSetHeightAction.h" + +void WaterRaiseAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_range); +} + +GameActions::Result::Ptr WaterRaiseAction::Query() const +{ + return QueryExecute(false); +} + +GameActions::Result::Ptr WaterRaiseAction::Execute() const +{ + return QueryExecute(true); +} + +GameActions::Result::Ptr WaterRaiseAction::QueryExecute(bool isExecuting) const +{ + auto res = MakeResult(); + + // Keep big coordinates within map boundaries + auto aX = std::max(32, _range.GetLeft()); + auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); + auto aY = std::max(32, _range.GetTop()); + auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); + + MapRange validRange = MapRange{ aX, aY, bX, bY }; + + res->Position.x = ((validRange.GetLeft() + validRange.GetRight()) / 2) + 16; + res->Position.y = ((validRange.GetTop() + validRange.GetBottom()) / 2) + 16; + int32_t z = tile_element_height(res->Position); + int16_t waterHeight = tile_element_water_height(res->Position); + if (waterHeight != 0) + { + z = waterHeight; + } + res->Position.z = z; + res->Expenditure = ExpenditureType::Landscaping; + + auto maxHeight = GetHighestHeight(validRange) / COORDS_Z_STEP; + bool hasChanged = false; + bool withinOwnership = false; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!LocationValid({ x, y })) + continue; + + auto surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + withinOwnership = true; + + uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; + + if (surfaceElement->base_height > maxHeight) + continue; + + if (height != 0) + { + if (height > maxHeight) + continue; + height += 2; + } + else + { + height = surfaceElement->base_height + 2; + } + auto waterSetHeightAction = WaterSetHeightAction({ x, y }, height); + waterSetHeightAction.SetFlags(GetFlags()); + auto result = isExecuting ? GameActions::ExecuteNested(&waterSetHeightAction) + : GameActions::QueryNested(&waterSetHeightAction); + if (result->Error == GameActions::Status::Ok) + { + res->Cost += result->Cost; + hasChanged = true; + } + else + { + result->ErrorTitle = STR_CANT_RAISE_WATER_LEVEL_HERE; + return result; + } + } + } + + if (!withinOwnership) + { + GameActions::Result::Ptr ownerShipResult = std::make_unique( + GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + ownerShipResult->ErrorTitle = STR_CANT_RAISE_WATER_LEVEL_HERE; + return ownerShipResult; + } + + if (isExecuting && hasChanged) + { + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::LayingOutWater, res->Position); + } + // Force ride construction to recheck area + _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; + + return res; +} + +uint16_t WaterRaiseAction::GetHighestHeight(MapRange validRange) const +{ + // The highest height to raise the water to is the lowest water level in the selection + uint16_t maxHeight = 255 * COORDS_Z_STEP; + for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) + { + for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) + { + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(CoordsXY{ x, y })) + { + continue; + } + } + + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); + if (surfaceElement == nullptr) + continue; + + auto height = surfaceElement->GetBaseZ(); + if (surfaceElement->GetWaterHeight() > 0) + { + height = surfaceElement->GetWaterHeight(); + } + + if (maxHeight > height) + { + maxHeight = height; + } + } + } + + return maxHeight; +} diff --git a/src/openrct2/actions/WaterRaiseAction.h b/src/openrct2/actions/WaterRaiseAction.h new file mode 100644 index 0000000000..08d10818e9 --- /dev/null +++ b/src/openrct2/actions/WaterRaiseAction.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(WaterRaiseAction, GAME_COMMAND_RAISE_WATER, GameActions::Result) +{ +private: + MapRange _range; + +public: + WaterRaiseAction() = default; + WaterRaiseAction(MapRange range) + : _range(range) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + GameActions::Result::Ptr QueryExecute(bool isExecuting) const; + uint16_t GetHighestHeight(MapRange validRange) const; +}; diff --git a/src/openrct2/actions/WaterRaiseAction.hpp b/src/openrct2/actions/WaterRaiseAction.hpp deleted file mode 100644 index f18019bd24..0000000000 --- a/src/openrct2/actions/WaterRaiseAction.hpp +++ /dev/null @@ -1,183 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../audio/audio.h" -#include "GameAction.h" -#include "WaterSetHeightAction.hpp" - -DEFINE_GAME_ACTION(WaterRaiseAction, GAME_COMMAND_RAISE_WATER, GameActions::Result) -{ -private: - MapRange _range; - -public: - WaterRaiseAction() = default; - WaterRaiseAction(MapRange range) - : _range(range) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_range); - } - - GameActions::Result::Ptr Query() const override - { - return QueryExecute(false); - } - - GameActions::Result::Ptr Execute() const override - { - return QueryExecute(true); - } - -private: - GameActions::Result::Ptr QueryExecute(bool isExecuting) const - { - auto res = MakeResult(); - - // Keep big coordinates within map boundaries - auto aX = std::max(32, _range.GetLeft()); - auto bX = std::min(gMapSizeMaxXY, _range.GetRight()); - auto aY = std::max(32, _range.GetTop()); - auto bY = std::min(gMapSizeMaxXY, _range.GetBottom()); - - MapRange validRange = MapRange{ aX, aY, bX, bY }; - - res->Position.x = ((validRange.GetLeft() + validRange.GetRight()) / 2) + 16; - res->Position.y = ((validRange.GetTop() + validRange.GetBottom()) / 2) + 16; - int32_t z = tile_element_height(res->Position); - int16_t waterHeight = tile_element_water_height(res->Position); - if (waterHeight != 0) - { - z = waterHeight; - } - res->Position.z = z; - res->Expenditure = ExpenditureType::Landscaping; - - auto maxHeight = GetHighestHeight(validRange) / COORDS_Z_STEP; - bool hasChanged = false; - bool withinOwnership = false; - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!LocationValid({ x, y })) - continue; - - auto surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - withinOwnership = true; - - uint8_t height = surfaceElement->GetWaterHeight() / COORDS_Z_STEP; - - if (surfaceElement->base_height > maxHeight) - continue; - - if (height != 0) - { - if (height > maxHeight) - continue; - height += 2; - } - else - { - height = surfaceElement->base_height + 2; - } - auto waterSetHeightAction = WaterSetHeightAction({ x, y }, height); - waterSetHeightAction.SetFlags(GetFlags()); - auto result = isExecuting ? GameActions::ExecuteNested(&waterSetHeightAction) - : GameActions::QueryNested(&waterSetHeightAction); - if (result->Error == GameActions::Status::Ok) - { - res->Cost += result->Cost; - hasChanged = true; - } - else - { - result->ErrorTitle = STR_CANT_RAISE_WATER_LEVEL_HERE; - return result; - } - } - } - - if (!withinOwnership) - { - GameActions::Result::Ptr ownerShipResult = std::make_unique( - GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); - ownerShipResult->ErrorTitle = STR_CANT_RAISE_WATER_LEVEL_HERE; - return ownerShipResult; - } - - if (isExecuting && hasChanged) - { - OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::LayingOutWater, res->Position); - } - // Force ride construction to recheck area - _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK; - - return res; - } - -private: - uint16_t GetHighestHeight(MapRange validRange) const - { - // The highest height to raise the water to is the lowest water level in the selection - uint16_t maxHeight = 255 * COORDS_Z_STEP; - for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP) - { - for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) - { - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(CoordsXY{ x, y })) - { - continue; - } - } - - auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); - if (surfaceElement == nullptr) - continue; - - auto height = surfaceElement->GetBaseZ(); - if (surfaceElement->GetWaterHeight() > 0) - { - height = surfaceElement->GetWaterHeight(); - } - - if (maxHeight > height) - { - maxHeight = height; - } - } - } - - return maxHeight; - } -}; diff --git a/src/openrct2/actions/WaterSetHeightAction.cpp b/src/openrct2/actions/WaterSetHeightAction.cpp new file mode 100644 index 0000000000..3942c3167e --- /dev/null +++ b/src/openrct2/actions/WaterSetHeightAction.cpp @@ -0,0 +1,141 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "WaterSetHeightAction.h" + +#include "../OpenRCT2.h" +#include "../management/Finance.h" +#include "../world/Park.h" +#include "../world/Surface.h" + +void WaterSetHeightAction::Serialise(DataSerialiser& stream) +{ + GameAction::Serialise(stream); + + stream << DS_TAG(_coords) << DS_TAG(_height); +} + +GameActions::Result::Ptr WaterSetHeightAction::Query() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position = { _coords, _height * COORDS_Z_STEP }; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode + && gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) + { + return MakeResult(GameActions::Status::Disallowed, STR_NONE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); + } + + rct_string_id errorMsg = CheckParameters(); + if (errorMsg != STR_NONE) + { + return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, errorMsg); + } + + if (!LocationValid(_coords)) + { + return MakeResult(GameActions::Status::NotOwned, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_in_park(_coords)) + { + return MakeResult(GameActions::Status::Disallowed, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK); + } + } + + SurfaceElement* surfaceElement = map_get_surface_element_at(_coords); + if (surfaceElement == nullptr) + { + log_error("Could not find surface element at: x %u, y %u", _coords.x, _coords.y); + return MakeResult(GameActions::Status::Unknown, STR_NONE); + } + + int32_t zHigh = surfaceElement->GetBaseZ(); + int32_t zLow = _height * COORDS_Z_STEP; + if (surfaceElement->GetWaterHeight() > 0) + { + zHigh = surfaceElement->GetWaterHeight(); + } + if (zLow > zHigh) + { + int32_t temp = zHigh; + zHigh = zLow; + zLow = temp; + } + + if (auto res2 = MapCanConstructAt({ _coords, zLow, zHigh }, { 0b1111, 0b1111 }); res2->Error != GameActions::Status::Ok) + { + return MakeResult( + GameActions::Status::NoClearance, STR_NONE, res2->ErrorMessage.GetStringId(), res2->ErrorMessageArgs.data()); + } + if (surfaceElement->HasTrackThatNeedsWater()) + { + return MakeResult(GameActions::Status::Disallowed, STR_NONE); + } + + res->Cost = 250; + + return res; +} + +GameActions::Result::Ptr WaterSetHeightAction::Execute() const +{ + auto res = MakeResult(); + res->Expenditure = ExpenditureType::Landscaping; + res->Position = { _coords, _height * COORDS_Z_STEP }; + + int32_t surfaceHeight = tile_element_height(_coords); + footpath_remove_litter({ _coords, surfaceHeight }); + if (!gCheatsDisableClearanceChecks) + wall_remove_at_z({ _coords, surfaceHeight }); + + SurfaceElement* surfaceElement = map_get_surface_element_at(_coords); + if (surfaceElement == nullptr) + { + log_error("Could not find surface element at: x %u, y %u", _coords.x, _coords.y); + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + } + + if (_height > surfaceElement->base_height) + { + surfaceElement->SetWaterHeight(_height * COORDS_Z_STEP); + } + else + { + surfaceElement->SetWaterHeight(0); + } + map_invalidate_tile_full(_coords); + + res->Cost = 250; + + return res; +} + +rct_string_id WaterSetHeightAction::CheckParameters() const +{ + if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY) + { + return STR_OFF_EDGE_OF_MAP; + } + + if (_height < MINIMUM_WATER_HEIGHT) + { + return STR_TOO_LOW; + } + + if (_height > MAXIMUM_WATER_HEIGHT) + { + return STR_TOO_HIGH; + } + + return STR_NONE; +} diff --git a/src/openrct2/actions/WaterSetHeightAction.h b/src/openrct2/actions/WaterSetHeightAction.h new file mode 100644 index 0000000000..7cfdbbe14c --- /dev/null +++ b/src/openrct2/actions/WaterSetHeightAction.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "GameAction.h" + +DEFINE_GAME_ACTION(WaterSetHeightAction, GAME_COMMAND_SET_WATER_HEIGHT, GameActions::Result) +{ +private: + CoordsXY _coords; + uint8_t _height{}; + +public: + WaterSetHeightAction() = default; + WaterSetHeightAction(const CoordsXY& coords, uint8_t height) + : _coords(coords) + , _height(height) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override; + GameActions::Result::Ptr Query() const override; + GameActions::Result::Ptr Execute() const override; + +private: + rct_string_id CheckParameters() const; +}; diff --git a/src/openrct2/actions/WaterSetHeightAction.hpp b/src/openrct2/actions/WaterSetHeightAction.hpp deleted file mode 100644 index 423b4c372b..0000000000 --- a/src/openrct2/actions/WaterSetHeightAction.hpp +++ /dev/null @@ -1,163 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../OpenRCT2.h" -#include "../management/Finance.h" -#include "../world/Park.h" -#include "../world/Surface.h" -#include "GameAction.h" - -DEFINE_GAME_ACTION(WaterSetHeightAction, GAME_COMMAND_SET_WATER_HEIGHT, GameActions::Result) -{ -private: - CoordsXY _coords; - uint8_t _height{}; - -public: - WaterSetHeightAction() = default; - WaterSetHeightAction(const CoordsXY& coords, uint8_t height) - : _coords(coords) - , _height(height) - { - } - - uint16_t GetActionFlags() const override - { - return GameAction::GetActionFlags(); - } - - void Serialise(DataSerialiser & stream) override - { - GameAction::Serialise(stream); - - stream << DS_TAG(_coords) << DS_TAG(_height); - } - - GameActions::Result::Ptr Query() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position = { _coords, _height * COORDS_Z_STEP }; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode - && gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) - { - return MakeResult(GameActions::Status::Disallowed, STR_NONE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY); - } - - rct_string_id errorMsg = CheckParameters(); - if (errorMsg != STR_NONE) - { - return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, errorMsg); - } - - if (!LocationValid(_coords)) - { - return MakeResult(GameActions::Status::NotOwned, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK); - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) - { - if (!map_is_location_in_park(_coords)) - { - return MakeResult(GameActions::Status::Disallowed, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK); - } - } - - SurfaceElement* surfaceElement = map_get_surface_element_at(_coords); - if (surfaceElement == nullptr) - { - log_error("Could not find surface element at: x %u, y %u", _coords.x, _coords.y); - return MakeResult(GameActions::Status::Unknown, STR_NONE); - } - - int32_t zHigh = surfaceElement->GetBaseZ(); - int32_t zLow = _height * COORDS_Z_STEP; - if (surfaceElement->GetWaterHeight() > 0) - { - zHigh = surfaceElement->GetWaterHeight(); - } - if (zLow > zHigh) - { - int32_t temp = zHigh; - zHigh = zLow; - zLow = temp; - } - - if (auto res2 = MapCanConstructAt({ _coords, zLow, zHigh }, { 0b1111, 0b1111 }); res2->Error != GameActions::Status::Ok) - { - return MakeResult( - GameActions::Status::NoClearance, STR_NONE, res2->ErrorMessage.GetStringId(), res2->ErrorMessageArgs.data()); - } - if (surfaceElement->HasTrackThatNeedsWater()) - { - return MakeResult(GameActions::Status::Disallowed, STR_NONE); - } - - res->Cost = 250; - - return res; - } - - GameActions::Result::Ptr Execute() const override - { - auto res = MakeResult(); - res->Expenditure = ExpenditureType::Landscaping; - res->Position = { _coords, _height * COORDS_Z_STEP }; - - int32_t surfaceHeight = tile_element_height(_coords); - footpath_remove_litter({ _coords, surfaceHeight }); - if (!gCheatsDisableClearanceChecks) - wall_remove_at_z({ _coords, surfaceHeight }); - - SurfaceElement* surfaceElement = map_get_surface_element_at(_coords); - if (surfaceElement == nullptr) - { - log_error("Could not find surface element at: x %u, y %u", _coords.x, _coords.y); - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - } - - if (_height > surfaceElement->base_height) - { - surfaceElement->SetWaterHeight(_height * COORDS_Z_STEP); - } - else - { - surfaceElement->SetWaterHeight(0); - } - map_invalidate_tile_full(_coords); - - res->Cost = 250; - - return res; - } - -private: - rct_string_id CheckParameters() const - { - if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY) - { - return STR_OFF_EDGE_OF_MAP; - } - - if (_height < MINIMUM_WATER_HEIGHT) - { - return STR_TOO_LOW; - } - - if (_height > MAXIMUM_WATER_HEIGHT) - { - return STR_TOO_HIGH; - } - - return STR_NONE; - } -}; diff --git a/src/openrct2/interface/InteractiveConsole.cpp b/src/openrct2/interface/InteractiveConsole.cpp index 6526bcebc4..f762d76fd3 100644 --- a/src/openrct2/interface/InteractiveConsole.cpp +++ b/src/openrct2/interface/InteractiveConsole.cpp @@ -16,11 +16,11 @@ #include "../PlatformEnvironment.h" #include "../ReplayManager.h" #include "../Version.h" -#include "../actions/ClimateSetAction.hpp" -#include "../actions/RideSetPriceAction.hpp" -#include "../actions/RideSetSetting.hpp" -#include "../actions/SetCheatAction.hpp" -#include "../actions/StaffSetCostumeAction.hpp" +#include "../actions/ClimateSetAction.h" +#include "../actions/RideSetPriceAction.h" +#include "../actions/RideSetSettingAction.h" +#include "../actions/SetCheatAction.h" +#include "../actions/StaffSetCostumeAction.h" #include "../config/Config.h" #include "../core/Guard.hpp" #include "../core/Path.hpp" diff --git a/src/openrct2/interface/Screenshot.cpp b/src/openrct2/interface/Screenshot.cpp index 9370a1e94a..0c90e69f29 100644 --- a/src/openrct2/interface/Screenshot.cpp +++ b/src/openrct2/interface/Screenshot.cpp @@ -11,9 +11,10 @@ #include "../Context.h" #include "../Game.h" +#include "../GameState.h" #include "../Intro.h" #include "../OpenRCT2.h" -#include "../actions/SetCheatAction.hpp" +#include "../actions/SetCheatAction.h" #include "../audio/audio.h" #include "../core/Console.hpp" #include "../core/Imaging.h" diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 4f655f918d..43d1df1f5f 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -1,4 +1,3 @@ - ..\..\ @@ -53,87 +52,87 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + @@ -461,10 +460,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openrct2/management/Research.cpp b/src/openrct2/management/Research.cpp index b480943546..6e0e937168 100644 --- a/src/openrct2/management/Research.cpp +++ b/src/openrct2/management/Research.cpp @@ -11,7 +11,7 @@ #include "../Game.h" #include "../OpenRCT2.h" -#include "../actions/ParkSetResearchFundingAction.hpp" +#include "../actions/ParkSetResearchFundingAction.h" #include "../config/Config.h" #include "../core/Guard.hpp" #include "../core/Memory.hpp" diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index c8adb289ee..143bf3a8fe 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -14,9 +14,9 @@ #include "../GameStateSnapshots.h" #include "../OpenRCT2.h" #include "../PlatformEnvironment.h" -#include "../actions/LoadOrQuitAction.hpp" -#include "../actions/NetworkModifyGroupAction.hpp" -#include "../actions/PeepPickupAction.hpp" +#include "../actions/LoadOrQuitAction.h" +#include "../actions/NetworkModifyGroupAction.h" +#include "../actions/PeepPickupAction.h" #include "../core/Guard.hpp" #include "../core/Json.hpp" #include "../platform/Platform2.h" diff --git a/src/openrct2/peep/Staff.cpp b/src/openrct2/peep/Staff.cpp index 4be4313d67..2be4377529 100644 --- a/src/openrct2/peep/Staff.cpp +++ b/src/openrct2/peep/Staff.cpp @@ -12,8 +12,8 @@ #include "../Context.h" #include "../Game.h" #include "../Input.h" -#include "../actions/StaffHireNewAction.hpp" -#include "../actions/StaffSetOrdersAction.hpp" +#include "../actions/StaffHireNewAction.h" +#include "../actions/StaffSetOrdersAction.h" #include "../audio/audio.h" #include "../config/Config.h" #include "../interface/Viewport.h" @@ -31,6 +31,7 @@ #include "../ride/Track.h" #include "../scenario/Scenario.h" #include "../util/Util.h" +#include "../windows/Intent.h" #include "../world/Entrance.h" #include "../world/Footpath.h" #include "../world/Scenery.h" diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 5752ed82e5..cc917f964f 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -13,7 +13,7 @@ #include "../Game.h" #include "../GameState.h" #include "../ParkImporter.h" -#include "../actions/WallPlaceAction.hpp" +#include "../actions/WallPlaceAction.h" #include "../audio/audio.h" #include "../core/Collections.hpp" #include "../core/Console.hpp" diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 4b37886a04..3a9e7ee5b7 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -15,11 +15,11 @@ #include "../Game.h" #include "../Input.h" #include "../OpenRCT2.h" -#include "../actions/RideEntranceExitRemoveAction.hpp" -#include "../actions/RideSetSetting.hpp" -#include "../actions/RideSetStatus.hpp" -#include "../actions/RideSetVehiclesAction.hpp" -#include "../actions/TrackRemoveAction.hpp" +#include "../actions/RideEntranceExitRemoveAction.h" +#include "../actions/RideSetSettingAction.h" +#include "../actions/RideSetStatusAction.h" +#include "../actions/RideSetVehicleAction.h" +#include "../actions/TrackRemoveAction.h" #include "../audio/AudioMixer.h" #include "../audio/audio.h" #include "../common.h" diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 94d3967321..f21dc29267 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -10,25 +10,26 @@ #include "TrackDesign.h" #include "../Cheats.h" +#include "../Context.h" #include "../Game.h" #include "../OpenRCT2.h" #include "../TrackImporter.h" -#include "../actions/FootpathPlaceFromTrackAction.hpp" -#include "../actions/FootpathRemoveAction.hpp" -#include "../actions/LargeSceneryPlaceAction.hpp" -#include "../actions/LargeSceneryRemoveAction.hpp" -#include "../actions/MazePlaceTrackAction.hpp" -#include "../actions/RideCreateAction.hpp" -#include "../actions/RideEntranceExitPlaceAction.hpp" -#include "../actions/RideSetName.hpp" -#include "../actions/RideSetSetting.hpp" -#include "../actions/RideSetVehiclesAction.hpp" -#include "../actions/SmallSceneryPlaceAction.hpp" -#include "../actions/SmallSceneryRemoveAction.hpp" -#include "../actions/TrackPlaceAction.hpp" -#include "../actions/TrackRemoveAction.hpp" -#include "../actions/WallPlaceAction.hpp" -#include "../actions/WallRemoveAction.hpp" +#include "../actions/FootpathPlaceFromTrackAction.h" +#include "../actions/FootpathRemoveAction.h" +#include "../actions/LargeSceneryPlaceAction.h" +#include "../actions/LargeSceneryRemoveAction.h" +#include "../actions/MazePlaceTrackAction.h" +#include "../actions/RideCreateAction.h" +#include "../actions/RideEntranceExitPlaceAction.h" +#include "../actions/RideSetNameAction.h" +#include "../actions/RideSetSettingAction.h" +#include "../actions/RideSetVehicleAction.h" +#include "../actions/SmallSceneryPlaceAction.h" +#include "../actions/SmallSceneryRemoveAction.h" +#include "../actions/TrackPlaceAction.h" +#include "../actions/TrackRemoveAction.h" +#include "../actions/WallPlaceAction.h" +#include "../actions/WallRemoveAction.h" #include "../audio/audio.h" #include "../core/DataSerialiser.h" #include "../core/File.h" diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index 97d2a58dac..989d817869 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -13,7 +13,7 @@ #include "../Editor.h" #include "../Game.h" #include "../OpenRCT2.h" -#include "../actions/RideSetStatus.hpp" +#include "../actions/RideSetStatusAction.h" #include "../audio/AudioMixer.h" #include "../audio/audio.h" #include "../config/Config.h" diff --git a/src/openrct2/scripting/ScNetwork.hpp b/src/openrct2/scripting/ScNetwork.hpp index f2e67683fb..bd183c6549 100644 --- a/src/openrct2/scripting/ScNetwork.hpp +++ b/src/openrct2/scripting/ScNetwork.hpp @@ -12,9 +12,9 @@ #ifdef ENABLE_SCRIPTING # include "../Context.h" -# include "../actions/NetworkModifyGroupAction.hpp" -# include "../actions/PlayerKickAction.hpp" -# include "../actions/PlayerSetGroupAction.hpp" +# include "../actions/NetworkModifyGroupAction.h" +# include "../actions/PlayerKickAction.h" +# include "../actions/PlayerSetGroupAction.h" # include "../network/NetworkAction.h" # include "../network/network.h" # include "Duktape.hpp" diff --git a/src/openrct2/scripting/ScriptEngine.cpp b/src/openrct2/scripting/ScriptEngine.cpp index 635ee06f61..18dc9d1530 100644 --- a/src/openrct2/scripting/ScriptEngine.cpp +++ b/src/openrct2/scripting/ScriptEngine.cpp @@ -12,10 +12,10 @@ # include "ScriptEngine.h" # include "../PlatformEnvironment.h" -# include "../actions/CustomAction.hpp" +# include "../actions/CustomAction.h" # include "../actions/GameAction.h" -# include "../actions/RideCreateAction.hpp" -# include "../actions/StaffHireNewAction.hpp" +# include "../actions/RideCreateAction.h" +# include "../actions/StaffHireNewAction.h" # include "../config/Config.h" # include "../core/File.h" # include "../core/FileScanner.h" diff --git a/src/openrct2/windows/_legacy.cpp b/src/openrct2/windows/_legacy.cpp index a6f914e387..214ddb023f 100644 --- a/src/openrct2/windows/_legacy.cpp +++ b/src/openrct2/windows/_legacy.cpp @@ -11,7 +11,7 @@ #include "../Context.h" #include "../Game.h" #include "../Input.h" -#include "../actions/TrackPlaceAction.hpp" +#include "../actions/TrackPlaceAction.h" #include "../audio/audio.h" #include "../interface/Viewport.h" #include "../network/network.h" diff --git a/src/openrct2/world/Entrance.cpp b/src/openrct2/world/Entrance.cpp index ab0ca323a5..b5fbc0b81f 100644 --- a/src/openrct2/world/Entrance.cpp +++ b/src/openrct2/world/Entrance.cpp @@ -12,9 +12,9 @@ #include "../Cheats.h" #include "../Game.h" #include "../OpenRCT2.h" -#include "../actions/ParkEntranceRemoveAction.hpp" -#include "../actions/RideEntranceExitPlaceAction.hpp" -#include "../actions/RideEntranceExitRemoveAction.hpp" +#include "../actions/ParkEntranceRemoveAction.h" +#include "../actions/RideEntranceExitPlaceAction.h" +#include "../actions/RideEntranceExitRemoveAction.h" #include "../localisation/StringIds.h" #include "../management/Finance.h" #include "../network/network.h" diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 24ba945fa8..e740f4812e 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -11,9 +11,9 @@ #include "../Context.h" #include "../Game.h" #include "../OpenRCT2.h" -#include "../actions/FootpathPlaceAction.hpp" -#include "../actions/FootpathRemoveAction.hpp" -#include "../actions/LandSetRightsAction.hpp" +#include "../actions/FootpathPlaceAction.h" +#include "../actions/FootpathRemoveAction.h" +#include "../actions/LandSetRightsAction.h" #include "../core/Guard.hpp" #include "../interface/Window_internal.h" #include "../localisation/Localisation.h" @@ -23,6 +23,7 @@ #include "../object/ObjectList.h" #include "../object/ObjectManager.h" #include "../paint/VirtualFloor.h" +#include "../ride/RideData.h" #include "../ride/Station.h" #include "../ride/Track.h" #include "../ride/TrackData.h" diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 12c79af0ef..574c6403eb 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -14,17 +14,17 @@ #include "../Game.h" #include "../Input.h" #include "../OpenRCT2.h" -#include "../actions/BannerRemoveAction.hpp" -#include "../actions/FootpathRemoveAction.hpp" -#include "../actions/LandLowerAction.hpp" -#include "../actions/LandRaiseAction.hpp" -#include "../actions/LandSetHeightAction.hpp" -#include "../actions/LandSetRightsAction.hpp" -#include "../actions/LargeSceneryRemoveAction.hpp" -#include "../actions/ParkEntranceRemoveAction.hpp" -#include "../actions/SmallSceneryRemoveAction.hpp" -#include "../actions/WallRemoveAction.hpp" -#include "../actions/WaterSetHeightAction.hpp" +#include "../actions/BannerRemoveAction.h" +#include "../actions/FootpathRemoveAction.h" +#include "../actions/LandLowerAction.h" +#include "../actions/LandRaiseAction.h" +#include "../actions/LandSetHeightAction.h" +#include "../actions/LandSetRightsAction.h" +#include "../actions/LargeSceneryRemoveAction.h" +#include "../actions/ParkEntranceRemoveAction.h" +#include "../actions/SmallSceneryRemoveAction.h" +#include "../actions/WallRemoveAction.h" +#include "../actions/WaterSetHeightAction.h" #include "../audio/audio.h" #include "../config/Config.h" #include "../core/Guard.hpp" diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 4ce607a269..50816d93c6 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -15,7 +15,7 @@ #include "../Game.h" #include "../GameState.h" #include "../OpenRCT2.h" -#include "../actions/ParkSetParameterAction.hpp" +#include "../actions/ParkSetParameterAction.h" #include "../config/Config.h" #include "../core/Memory.hpp" #include "../interface/Colour.h" diff --git a/src/openrct2/world/Scenery.cpp b/src/openrct2/world/Scenery.cpp index 6503b0ffed..5240a7fdff 100644 --- a/src/openrct2/world/Scenery.cpp +++ b/src/openrct2/world/Scenery.cpp @@ -12,11 +12,11 @@ #include "../Cheats.h" #include "../Context.h" #include "../Game.h" -#include "../actions/BannerRemoveAction.hpp" -#include "../actions/FootpathAdditionRemoveAction.hpp" -#include "../actions/LargeSceneryRemoveAction.hpp" -#include "../actions/SmallSceneryRemoveAction.hpp" -#include "../actions/WallRemoveAction.hpp" +#include "../actions/BannerRemoveAction.h" +#include "../actions/FootpathAdditionRemoveAction.h" +#include "../actions/LargeSceneryRemoveAction.h" +#include "../actions/SmallSceneryRemoveAction.h" +#include "../actions/WallRemoveAction.h" #include "../common.h" #include "../localisation/Localisation.h" #include "../network/network.h" diff --git a/test/tests/PlayTests.cpp b/test/tests/PlayTests.cpp index ae6e58f096..c73dfc4526 100644 --- a/test/tests/PlayTests.cpp +++ b/test/tests/PlayTests.cpp @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include