diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 24a4964a88..6e09ee9292 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ 2A43D2C22225B91A00E8F73B /* LoadOrQuitAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2A43D2BF2225B91A00E8F73B /* LoadOrQuitAction.hpp */; }; 2A5354E922099C4F00A5440F /* Network.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A5354E822099C4F00A5440F /* Network.cpp */; }; 2A5C1368221E9F9000F8C245 /* TrackRemoveAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2A5C1367221E9F9000F8C245 /* TrackRemoveAction.hpp */; }; + 2A61CAFB2229E5C50095AD67 /* RideEntranceExitPlaceAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2A61CAFA2229E5C50095AD67 /* RideEntranceExitPlaceAction.hpp */; }; 2AA050322209A8E300D3A922 /* StaffSetCostumeAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2AA050302209A8E300D3A922 /* StaffSetCostumeAction.hpp */; }; 2AA050332209A8E300D3A922 /* StaffSetOrdersAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2AA050312209A8E300D3A922 /* StaffSetOrdersAction.hpp */; }; 2AAFD7FA220DD2DC002461A4 /* TrackPlaceAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2AAFD7F9220DD2DC002461A4 /* TrackPlaceAction.hpp */; }; @@ -638,6 +639,7 @@ 2A5354EA22099C7200A5440F /* CircularBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircularBuffer.h; sourceTree = ""; }; 2A5354EB22099D7700A5440F /* SignSetStyleAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SignSetStyleAction.hpp; sourceTree = ""; }; 2A5C1367221E9F9000F8C245 /* TrackRemoveAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrackRemoveAction.hpp; sourceTree = ""; }; + 2A61CAFA2229E5C50095AD67 /* RideEntranceExitPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideEntranceExitPlaceAction.hpp; sourceTree = ""; }; 2AA050302209A8E300D3A922 /* StaffSetCostumeAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetCostumeAction.hpp; sourceTree = ""; }; 2AA050312209A8E300D3A922 /* StaffSetOrdersAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetOrdersAction.hpp; sourceTree = ""; }; 2AAFD7F9220DD2DC002461A4 /* TrackPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrackPlaceAction.hpp; sourceTree = ""; }; @@ -2024,6 +2026,7 @@ C6352B871F477032006CCEE3 /* actions */ = { isa = PBXGroup; children = ( + 2A61CAFA2229E5C50095AD67 /* RideEntranceExitPlaceAction.hpp */, 2ACBAB162226850A0034FB91 /* RideSetSetting.hpp */, 2A43D2B92225B8D900E8F73B /* LoadOrQuitAction.hpp */, 2A43D2B72225B8D900E8F73B /* RideSetVehiclesAction.hpp */, @@ -3346,6 +3349,7 @@ 2AAFD7FA220DD2DC002461A4 /* TrackPlaceAction.hpp in Headers */, 933F2CBB20935668001B33FD /* LocalisationService.h in Headers */, 2A5C1368221E9F9000F8C245 /* TrackRemoveAction.hpp in Headers */, + 2A61CAFB2229E5C50095AD67 /* RideEntranceExitPlaceAction.hpp in Headers */, C6352B861F477022006CCEE3 /* Endianness.h in Headers */, 93CBA4CC20A7504500867D56 /* ImageImporter.h in Headers */, 2AAFD7FE220DD374002461A4 /* PauseToggleAction.hpp in Headers */, diff --git a/src/openrct2-ui/windows/MazeConstruction.cpp b/src/openrct2-ui/windows/MazeConstruction.cpp index 438f6023c0..9f60d6146f 100644 --- a/src/openrct2-ui/windows/MazeConstruction.cpp +++ b/src/openrct2-ui/windows/MazeConstruction.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -364,38 +365,32 @@ static void window_maze_construction_entrance_tooldown(int32_t x, int32_t y, rct return; ride_id_t rideIndex = gRideEntranceExitPlaceRideIndex; - uint8_t entranceExitType = gRideEntranceExitPlaceType; - if (entranceExitType == ENTRANCE_TYPE_RIDE_ENTRANCE) - { - gGameCommandErrorTitle = STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION; - } - else - { - gGameCommandErrorTitle = STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION; - } - money32 cost = game_do_command( - x, GAME_COMMAND_FLAG_APPLY | (direction_reverse(direction) << 8), y, rideIndex | (entranceExitType << 8), - GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, gRideEntranceExitPlaceStationIndex, 0); + auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction( + { x, y }, direction_reverse(direction), rideIndex, gRideEntranceExitPlaceStationIndex, + gRideEntranceExitPlaceType == ENTRANCE_TYPE_RIDE_EXIT); - if (cost == MONEY32_UNDEFINED) - return; + rideEntranceExitPlaceAction.SetCallback([=](const GameAction* ga, const GameActionResult* result) { + if (result->Error != GA_ERROR::OK) + return; - audio_play_sound_at_location(SOUND_PLACE_ITEM, gCommandPosition.x, gCommandPosition.y, gCommandPosition.z); + audio_play_sound_at_location(SOUND_PLACE_ITEM, result->Position.x, result->Position.y, result->Position.z); - Ride* ride = get_ride(rideIndex); - if (ride_are_all_possible_entrances_and_exits_built(ride)) - { - tool_cancel(); - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_NO_TRACK)) - window_close(w); - } - else - { - gRideEntranceExitPlaceType = entranceExitType ^ 1; - window_invalidate_by_class(WC_RIDE_CONSTRUCTION); - gCurrentToolWidget.widget_index = entranceExitType ? WIDX_MAZE_ENTRANCE : WIDX_MAZE_EXIT; - } + Ride* ride = get_ride(rideIndex); + if (ride_are_all_possible_entrances_and_exits_built(ride)) + { + tool_cancel(); + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_NO_TRACK)) + window_close_by_class(WC_RIDE_CONSTRUCTION); + } + else + { + gRideEntranceExitPlaceType = gRideEntranceExitPlaceType ^ 1; + window_invalidate_by_class(WC_RIDE_CONSTRUCTION); + gCurrentToolWidget.widget_index = gRideEntranceExitPlaceType ? WIDX_MAZE_ENTRANCE : WIDX_MAZE_EXIT; + } + }); + auto res = GameActions::Execute(&rideEntranceExitPlaceAction); } /** diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index 9c1ab3f314..9e11e4bee9 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -3938,15 +3939,35 @@ static void ride_construction_tooldown_entrance_exit(int32_t screenX, int32_t sc if (gRideEntranceExitPlaceDirection == 255) return; - gGameCommandErrorTitle = (gRideEntranceExitPlaceType == ENTRANCE_TYPE_RIDE_ENTRANCE) - ? STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION - : STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION; + auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction( + { _unkF44188.x, _unkF44188.y }, direction_reverse(gRideEntranceExitPlaceDirection), gRideEntranceExitPlaceRideIndex, + gRideEntranceExitPlaceStationIndex, gRideEntranceExitPlaceType == ENTRANCE_TYPE_RIDE_EXIT); - game_command_callback = game_command_callback_place_ride_entrance_or_exit; - game_do_command( - _unkF44188.x, (GAME_COMMAND_FLAG_APPLY) | (direction_reverse(gRideEntranceExitPlaceDirection) << 8), _unkF44188.y, - gRideEntranceExitPlaceRideIndex | (gRideEntranceExitPlaceType << 8), GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, - gRideEntranceExitPlaceStationIndex, 0); + rideEntranceExitPlaceAction.SetCallback([=](const GameAction* ga, const GameActionResult* result) { + if (result->Error != GA_ERROR::OK) + return; + + audio_play_sound_at_location(SOUND_PLACE_ITEM, result->Position.x, result->Position.y, result->Position.z); + + Ride* ride = get_ride(gRideEntranceExitPlaceRideIndex); + if (ride_are_all_possible_entrances_and_exits_built(ride)) + { + tool_cancel(); + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_NO_TRACK)) + { + window_close_by_class(WC_RIDE_CONSTRUCTION); + } + } + else + { + gRideEntranceExitPlaceType = gRideEntranceExitPlaceType ^ 1; + window_invalidate_by_class(WC_RIDE_CONSTRUCTION); + gCurrentToolWidget.widget_index = (gRideEntranceExitPlaceType == ENTRANCE_TYPE_RIDE_ENTRANCE) + ? WC_RIDE_CONSTRUCTION__WIDX_ENTRANCE + : WC_RIDE_CONSTRUCTION__WIDX_EXIT; + } + }); + auto res = GameActions::Execute(&rideEntranceExitPlaceAction); } void window_ride_construction_keyboard_shortcut_turn_left() diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 8d7e6dad6c..9f30610492 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -93,7 +93,7 @@ static GAME_COMMAND_CALLBACK_POINTER * const game_command_callback_table[] = { nullptr, nullptr, game_command_callback_place_banner, - game_command_callback_place_ride_entrance_or_exit, + nullptr, game_command_callback_hire_new_staff_member, game_command_callback_pickup_guest, game_command_callback_pickup_staff @@ -1272,7 +1272,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = { nullptr, game_command_set_ride_name, nullptr, - game_command_place_ride_entrance_or_exit, + nullptr, nullptr, nullptr, nullptr, diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index 0d53950e37..0745b7a184 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -18,19 +18,19 @@ struct rct_s6_data; enum GAME_COMMAND { - GAME_COMMAND_SET_RIDE_APPEARANCE, // GA - GAME_COMMAND_SET_LAND_HEIGHT, // GA - GAME_COMMAND_TOGGLE_PAUSE, // GA - GAME_COMMAND_PLACE_TRACK, // GA - GAME_COMMAND_REMOVE_TRACK, // GA - GAME_COMMAND_LOAD_OR_QUIT, // GA - GAME_COMMAND_CREATE_RIDE, // GA - GAME_COMMAND_DEMOLISH_RIDE, // GA - GAME_COMMAND_SET_RIDE_STATUS, // GA - GAME_COMMAND_SET_RIDE_VEHICLES, // GA - GAME_COMMAND_SET_RIDE_NAME, // GA - GAME_COMMAND_SET_RIDE_SETTING, // GA - GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, + GAME_COMMAND_SET_RIDE_APPEARANCE, // GA + GAME_COMMAND_SET_LAND_HEIGHT, // GA + GAME_COMMAND_TOGGLE_PAUSE, // GA + GAME_COMMAND_PLACE_TRACK, // GA + GAME_COMMAND_REMOVE_TRACK, // GA + GAME_COMMAND_LOAD_OR_QUIT, // GA + GAME_COMMAND_CREATE_RIDE, // GA + GAME_COMMAND_DEMOLISH_RIDE, // GA + GAME_COMMAND_SET_RIDE_STATUS, // GA + GAME_COMMAND_SET_RIDE_VEHICLES, // GA + GAME_COMMAND_SET_RIDE_NAME, // GA + GAME_COMMAND_SET_RIDE_SETTING, // GA + GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, // GA GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, // GA GAME_COMMAND_REMOVE_SCENERY, // GA GAME_COMMAND_PLACE_SCENERY, // GA diff --git a/src/openrct2/ReplayManager.cpp b/src/openrct2/ReplayManager.cpp index 3c3ce2e97f..a15298b2e6 100644 --- a/src/openrct2/ReplayManager.cpp +++ b/src/openrct2/ReplayManager.cpp @@ -15,6 +15,7 @@ #include "ParkImporter.h" #include "PlatformEnvironment.h" #include "actions/GameAction.h" +#include "actions/RideEntranceExitPlaceAction.hpp" #include "actions/RideSetSetting.hpp" #include "actions/TrackPlaceAction.hpp" #include "config/Config.h" @@ -503,6 +504,17 @@ namespace OpenRCT2 result.action->SetFlags(command.ebx & 0xFF); break; } + case GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT: + { + CoordsXY loc = { (int32_t)(command.eax & 0xFFFF), (int32_t)(command.ecx & 0xFFFF) }; + Direction direction = (command.ebx >> 8) & 0xFF; + ride_id_t rideId = command.edx & 0xFF; + uint8_t stationNum = command.edi & 0xFF; + bool isExit = ((command.edx >> 8) & 0xFF) != 0; + result.action = std::make_unique(loc, direction, rideId, stationNum, isExit); + result.action->SetFlags(command.ebx & 0xFF); + break; + } default: throw std::runtime_error("Deprecated game command requires replay translation."); } diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index 58bbb829c0..db6a21e0c6 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -26,6 +26,7 @@ #include "PlacePeepSpawnAction.hpp" #include "RideCreateAction.hpp" #include "RideDemolishAction.hpp" +#include "RideEntranceExitPlaceAction.hpp" #include "RideEntranceExitRemoveAction.hpp" #include "RideSetAppearanceAction.hpp" #include "RideSetColourScheme.hpp" @@ -64,6 +65,7 @@ namespace GameActions Register(); Register(); Register(); + Register(); Register(); Register(); Register(); diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.hpp b/src/openrct2/actions/RideEntranceExitPlaceAction.hpp new file mode 100644 index 0000000000..8ef9533354 --- /dev/null +++ b/src/openrct2/actions/RideEntranceExitPlaceAction.hpp @@ -0,0 +1,285 @@ +/***************************************************************************** + * Copyright (c) 2014-2019 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.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, GameActionResult) +{ +private: + CoordsXY _loc; + Direction _direction; + NetworkRideId_t _rideIndex; + uint8_t _stationNum; + bool _isExit; + +public: + RideEntranceExitPlaceAction() = default; + + RideEntranceExitPlaceAction(CoordsXY loc, Direction direction, ride_id_t rideIndex, uint8_t stationNum, bool isExit) + : _loc(loc) + , _direction(direction) + , _rideIndex(rideIndex) + , _stationNum(stationNum) + , _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); + } + + GameActionResult::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(GA_ERROR::NO_FREE_ELEMENTS, errorTitle); + } + + if (_rideIndex >= MAX_RIDES || _rideIndex == RIDE_ID_NULL) + { + log_warning("Invalid game command for ride %u", _rideIndex); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, errorTitle); + } + + Ride* ride = get_ride(_rideIndex); + if (ride == nullptr || ride->type == RIDE_TYPE_NULL) + { + log_warning("Invalid game command for ride %u", _rideIndex); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, errorTitle); + } + + if (_stationNum > MAX_STATIONS) + { + log_warning("Invalid station number for ride. stationNum: %u", _stationNum); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, errorTitle); + } + + if (ride->status != RIDE_STATUS_CLOSED) + { + return MakeResult(GA_ERROR::NOT_CLOSED, errorTitle, STR_MUST_BE_CLOSED_FIRST); + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) + { + return MakeResult(GA_ERROR::DISALLOWED, errorTitle, STR_NOT_ALLOWED_TO_MODIFY_STATION); + } + + 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.x * 32, location.y * 32 }, _rideIndex, _stationNum, _isExit); + rideEntranceExitRemove.SetFlags(GetFlags()); + + auto result = GameActions::QueryNested(&rideEntranceExitRemove); + if (result->Error != GA_ERROR::OK) + { + return result; + } + } + + auto z = ride->stations[_stationNum].Height * 8; + gCommandPosition.z = z; + + if (!gCheatsSandboxMode && !map_is_location_owned(_loc.x, _loc.y, z)) + { + return MakeResult(GA_ERROR::NOT_OWNED, errorTitle); + } + + int8_t clear_z = (z / 8) + (_isExit ? 5 : 7); + auto cost = MONEY32_UNDEFINED; + if (!map_can_construct_with_clear_at( + _loc.x, _loc.y, z / 8, clear_z, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags(), &cost, + CREATE_CROSSING_MODE_NONE)) + { + return MakeResult(GA_ERROR::NO_CLEARANCE, errorTitle, gGameCommandErrorText, gCommonFormatArgs); + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) + { + return MakeResult(GA_ERROR::DISALLOWED, errorTitle, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); + } + + if (z / 8 > MaxRideEntranceOrExitHeight) + { + return MakeResult(GA_ERROR::DISALLOWED, errorTitle, STR_TOO_HIGH); + } + + auto res = MakeResult(); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = tile_element_height(_loc.x, _loc.y); + res->ExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; + return res; + } + + GameActionResult::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; + Ride* ride = get_ride(_rideIndex); + if (ride == nullptr || ride->type == RIDE_TYPE_NULL) + { + log_warning("Invalid game command for ride %u", _rideIndex); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, errorTitle); + } + + 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.x * 32, location.y * 32 }, _rideIndex, _stationNum, _isExit); + rideEntranceExitRemove.SetFlags(GetFlags()); + + auto result = GameActions::ExecuteNested(&rideEntranceExitRemove); + if (result->Error != GA_ERROR::OK) + { + return result; + } + } + + auto z = ride->stations[_stationNum].Height * 8; + gCommandPosition.z = z; + + if (!(GetFlags() & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter(_loc.x, _loc.y, z); + wall_remove_at_z(_loc.x, _loc.y, z); + } + + int8_t clear_z = (z / 8) + (_isExit ? 5 : 7); + auto cost = MONEY32_UNDEFINED; + if (!map_can_construct_with_clear_at( + _loc.x, _loc.y, z / 8, clear_z, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags(), &cost, + CREATE_CROSSING_MODE_NONE)) + { + return MakeResult(GA_ERROR::NO_CLEARANCE, errorTitle, gGameCommandErrorText, gCommonFormatArgs); + } + + auto res = MakeResult(); + res->Position.x = _loc.x + 16; + res->Position.y = _loc.y + 16; + res->Position.z = tile_element_height(_loc.x, _loc.y); + res->ExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; + + TileElement* tileElement = tile_element_insert(_loc.x / 32, _loc.y / 32, z / 8, 0b1111); + assert(tileElement != nullptr); + tileElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); + tileElement->SetDirection(_direction); + tileElement->clearance_height = 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, { _loc.x / 32, _loc.y / 32, z / 8, (uint8_t)tileElement->GetDirection() }); + } + else + { + ride_set_entrance_location( + ride, _stationNum, { _loc.x / 32, _loc.y / 32, z / 8, (uint8_t)tileElement->GetDirection() }); + ride->stations[_stationNum].LastPeepInQueue = SPRITE_INDEX_NULL; + ride->stations[_stationNum].QueueLength = 0; + + map_animation_create(MAP_ANIMATION_TYPE_RIDE_ENTRANCE, _loc.x, _loc.y, z / 8); + } + + footpath_queue_chain_reset(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + maze_entrance_hedge_removal(_loc.x, _loc.y, tileElement); + } + + footpath_connect_edges(_loc.x, _loc.y, tileElement, GetFlags()); + footpath_update_queue_chains(); + + map_invalidate_tile_full(_loc.x, _loc.y); + + return res; + } + + static GameActionResult::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(GA_ERROR::NO_FREE_ELEMENTS, errorTitle); + } + + if (!gCheatsSandboxMode && !map_is_location_owned(loc.x, loc.y, loc.z)) + { + return MakeResult(GA_ERROR::NOT_OWNED, errorTitle); + } + + int16_t baseZ = loc.z / 8; + int16_t clearZ = baseZ + (isExit ? 5 : 7); + auto cost = MONEY32_UNDEFINED; + if (!map_can_construct_with_clear_at( + loc.x, loc.y, baseZ, clearZ, &map_place_non_scenery_clear_func, { 0b1111, 0 }, 0, &cost, + CREATE_CROSSING_MODE_NONE)) + { + return MakeResult(GA_ERROR::NO_CLEARANCE, errorTitle, gGameCommandErrorText, gCommonFormatArgs); + } + + if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) + { + return MakeResult(GA_ERROR::DISALLOWED, errorTitle, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); + } + + if (baseZ > MaxRideEntranceOrExitHeight) + { + return MakeResult(GA_ERROR::DISALLOWED, errorTitle, STR_TOO_HIGH); + } + auto res = MakeResult(); + res->Position.x = loc.x + 16; + res->Position.y = loc.y + 16; + res->Position.z = tile_element_height(loc.x, loc.y); + res->ExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; + return res; + } +}; diff --git a/src/openrct2/core/DataSerialiserTraits.h b/src/openrct2/core/DataSerialiserTraits.h index f776c8b477..e415f18bab 100644 --- a/src/openrct2/core/DataSerialiserTraits.h +++ b/src/openrct2/core/DataSerialiserTraits.h @@ -331,9 +331,9 @@ template<> struct DataSerializerTraits } static void decode(IStream* stream, CoordsXY& coords) { - auto x = ByteSwapBE(stream->ReadValue()); - auto y = ByteSwapBE(stream->ReadValue()); - coords = CoordsXY(x, y); + auto x = ByteSwapBE(stream->ReadValue()); + auto y = ByteSwapBE(stream->ReadValue()); + coords = CoordsXY{ x, y }; } static void log(IStream* stream, const CoordsXY& coords) { diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 8718f856c0..e303210a27 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -31,7 +31,7 @@ // This string specifies which version of network stream current build uses. // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -#define NETWORK_STREAM_VERSION "50" +#define NETWORK_STREAM_VERSION "51" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION static Peep* _pickup_peep = nullptr; diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index 52c6c72100..65e347e8c9 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -1166,8 +1166,6 @@ rct_vehicle* ride_get_broken_vehicle(Ride* ride); void window_ride_construction_do_station_check(); void window_ride_construction_do_entrance_exit_check(); -void game_command_callback_place_ride_entrance_or_exit( - int32_t eax, int32_t ebx, int32_t ecx, int32_t edx, int32_t esi, int32_t edi, int32_t ebp); void ride_delete(Ride* ride); void ride_renew(Ride* ride); diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 1a717d31c1..049c03e316 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -13,6 +13,7 @@ #include "../Game.h" #include "../OpenRCT2.h" #include "../actions/LargeSceneryRemoveAction.hpp" +#include "../actions/RideEntranceExitPlaceAction.hpp" #include "../actions/RideSetSetting.hpp" #include "../actions/RideSetVehiclesAction.hpp" #include "../actions/SmallSceneryPlaceAction.hpp" @@ -1217,9 +1218,8 @@ static int32_t track_design_place_maze(rct_track_td6* td6, int16_t x, int16_t y, if (_trackDesignPlaceOperation == PTD_OPERATION_1) { - cost = game_do_command( - mapCoord.x, 0 | rotation << 8, mapCoord.y, (z / 16) & 0xFF, - GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, -1, 0); + auto res = RideEntranceExitPlaceAction::TrackPlaceQuery({ mapCoord.x, mapCoord.y, z }, false); + cost = res->Error == GA_ERROR::OK ? res->Cost : MONEY32_UNDEFINED; } else { @@ -1232,9 +1232,10 @@ static int32_t track_design_place_maze(rct_track_td6* td6, int16_t x, int16_t y, flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5 | GAME_COMMAND_FLAG_GHOST; } - cost = game_do_command( - mapCoord.x, flags | rotation << 8, mapCoord.y, ride->id, GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, - 0, 0); + auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction(mapCoord, rotation, ride->id, 0, false); + rideEntranceExitPlaceAction.SetFlags(flags); + auto res = GameActions::ExecuteNested(&rideEntranceExitPlaceAction); + cost = res->Error == GA_ERROR::OK ? res->Cost : MONEY32_UNDEFINED; } if (cost != MONEY32_UNDEFINED) { @@ -1251,9 +1252,8 @@ static int32_t track_design_place_maze(rct_track_td6* td6, int16_t x, int16_t y, if (_trackDesignPlaceOperation == PTD_OPERATION_1) { - cost = game_do_command( - mapCoord.x, 0 | rotation << 8, mapCoord.y, ((z / 16) & 0xFF) | (1 << 8), - GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, -1, 0); + auto res = RideEntranceExitPlaceAction::TrackPlaceQuery({ mapCoord.x, mapCoord.y, z }, true); + cost = res->Error == GA_ERROR::OK ? res->Cost : MONEY32_UNDEFINED; } else { @@ -1266,9 +1266,10 @@ static int32_t track_design_place_maze(rct_track_td6* td6, int16_t x, int16_t y, flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5 | GAME_COMMAND_FLAG_GHOST; } - cost = game_do_command( - mapCoord.x, flags | rotation << 8, mapCoord.y, ride->id | (1 << 8), - GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, 0, 0); + auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction(mapCoord, rotation, ride->id, 0, true); + rideEntranceExitPlaceAction.SetFlags(flags); + auto res = GameActions::ExecuteNested(&rideEntranceExitPlaceAction); + cost = res->Error == GA_ERROR::OK ? res->Cost : MONEY32_UNDEFINED; } if (cost != MONEY32_UNDEFINED) { @@ -1573,10 +1574,10 @@ static bool track_design_place_ride(rct_track_td6* td6, int16_t x, int16_t y, in case PTD_OPERATION_GET_COST: { rotation = (rotation + entrance->direction) & 3; - uint8_t isExit = 0; + bool isExit = false; if (entrance->direction & (1 << 7)) { - isExit = 1; + isExit = true; } if (_trackDesignPlaceOperation != PTD_OPERATION_1) @@ -1601,29 +1602,33 @@ static bool track_design_place_ride(rct_track_td6* td6, int16_t x, int16_t y, in } int32_t stationIndex = tile_element->AsTrack()->GetStationIndex(); - uint8_t bl = 1; + uint8_t flags = GAME_COMMAND_FLAG_APPLY; if (_trackDesignPlaceOperation == PTD_OPERATION_GET_COST) { - bl = 41; + flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5; } if (_trackDesignPlaceOperation == PTD_OPERATION_4) { - bl = 105; + flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5 + | GAME_COMMAND_FLAG_GHOST; } if (_trackDesignPlaceOperation == PTD_OPERATION_1) { - bl = 0; + flags = 0; } gGameCommandErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - money32 cost = game_do_command( - x, bl | (rotation << 8), y, ride->id | (isExit << 8), GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, - stationIndex, 0); - _trackDesignPlaceCost += cost; + auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction( + { x, y }, rotation, ride->id, stationIndex, isExit); + rideEntranceExitPlaceAction.SetFlags(flags); + auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&rideEntranceExitPlaceAction) + : GameActions::QueryNested(&rideEntranceExitPlaceAction); - if (cost == MONEY32_UNDEFINED) + _trackDesignPlaceCost += res->Cost; + + if (res->Error != GA_ERROR::OK) { - _trackDesignPlaceCost = cost; + _trackDesignPlaceCost = MONEY32_UNDEFINED; return false; } _trackDesignPlaceStateEntranceExitPlaced = true; @@ -1635,19 +1640,16 @@ static bool track_design_place_ride(rct_track_td6* td6, int16_t x, int16_t y, in z = (entrance->z == (int8_t)(uint8_t)0x80) ? -1 : entrance->z; z *= 8; z += gTrackPreviewOrigin.z; - z >>= 4; - gGameCommandErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - money32 cost = game_do_command( - x, 0 | (rotation << 8), y, z | (isExit << 8), GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, -1, 0); - if (cost == MONEY32_UNDEFINED) + auto res = RideEntranceExitPlaceAction::TrackPlaceQuery({ x, y, z }, false); + if (res->Error != GA_ERROR::OK) { - _trackDesignPlaceCost = cost; + _trackDesignPlaceCost = MONEY32_UNDEFINED; return false; } else { - _trackDesignPlaceCost += cost; + _trackDesignPlaceCost += res->Cost; _trackDesignPlaceStateEntranceExitPlaced = true; } } diff --git a/src/openrct2/windows/_legacy.cpp b/src/openrct2/windows/_legacy.cpp index dea46e7649..207255dd2b 100644 --- a/src/openrct2/windows/_legacy.cpp +++ b/src/openrct2/windows/_legacy.cpp @@ -108,30 +108,6 @@ uint8_t _rideConstructionState2; bool _stationConstructed; bool _deferClose; -void game_command_callback_place_ride_entrance_or_exit( - [[maybe_unused]] int32_t eax, [[maybe_unused]] int32_t ebx, [[maybe_unused]] int32_t ecx, [[maybe_unused]] int32_t edx, - [[maybe_unused]] int32_t esi, [[maybe_unused]] int32_t edi, [[maybe_unused]] int32_t ebp) -{ - audio_play_sound_at_location(SOUND_PLACE_ITEM, gCommandPosition.x, gCommandPosition.y, gCommandPosition.z); - - Ride* ride = get_ride(gRideEntranceExitPlaceRideIndex); - if (ride_are_all_possible_entrances_and_exits_built(ride)) - { - tool_cancel(); - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_NO_TRACK)) - { - window_close_by_class(WC_RIDE_CONSTRUCTION); - } - } - else - { - gRideEntranceExitPlaceType ^= 1; - gCurrentToolWidget.widget_index = (gRideEntranceExitPlaceType == ENTRANCE_TYPE_RIDE_ENTRANCE) - ? WC_RIDE_CONSTRUCTION__WIDX_ENTRANCE - : WC_RIDE_CONSTRUCTION__WIDX_EXIT; - } -} - /** * * rct2: 0x006CA162 diff --git a/src/openrct2/world/Entrance.cpp b/src/openrct2/world/Entrance.cpp index 1422c26c5d..489d68ee04 100644 --- a/src/openrct2/world/Entrance.cpp +++ b/src/openrct2/world/Entrance.cpp @@ -12,6 +12,7 @@ #include "../Cheats.h" #include "../Game.h" #include "../OpenRCT2.h" +#include "../actions/RideEntranceExitPlaceAction.hpp" #include "../actions/RideEntranceExitRemoveAction.hpp" #include "../localisation/StringIds.h" #include "../management/Finance.h" @@ -87,238 +88,15 @@ static money32 ParkEntranceRemove(int16_t x, int16_t y, uint8_t z, uint8_t flags return 0; } -static money32 RideEntranceExitPlace( - int16_t x, int16_t y, int16_t z, uint8_t direction, uint8_t flags, ride_id_t rideIndex, uint8_t stationNum, bool isExit) -{ - // 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 - - money32 cost = 0; - gCommandPosition.x = x; - gCommandPosition.y = y; - - if (!map_check_free_elements_and_reorganise(1)) - { - return MONEY32_UNDEFINED; - } - - if (!(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) && game_is_paused() && !gCheatsBuildInPauseMode) - { - gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; - return MONEY32_UNDEFINED; - } - - if (stationNum == 0xFF) - { - z *= 16; - if (flags & GAME_COMMAND_FLAG_APPLY) - { - return MONEY32_UNDEFINED; - } - - if (!gCheatsSandboxMode && !map_is_location_owned(x, y, z)) - { - return MONEY32_UNDEFINED; - } - - int16_t clear_z = z / 8 + (isExit ? 5 : 7); - - if (!map_can_construct_with_clear_at( - x, y, z / 8, clear_z, &map_place_non_scenery_clear_func, { 0b1111, 0 }, flags, &cost, - CREATE_CROSSING_MODE_NONE)) - { - return MONEY32_UNDEFINED; - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) - { - gGameCommandErrorText = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; - return MONEY32_UNDEFINED; - } - - if (z / 8 > 244) - { - gGameCommandErrorText = STR_TOO_HIGH; - return MONEY32_UNDEFINED; - } - } - else - { - if (rideIndex >= MAX_RIDES) - { - log_warning("Invalid game command for ride %u", rideIndex); - return MONEY32_UNDEFINED; - } - - Ride* ride = get_ride(rideIndex); - if (ride->type == RIDE_TYPE_NULL) - { - log_warning("Invalid game command for ride %u", rideIndex); - return MONEY32_UNDEFINED; - } - - if (ride->status != RIDE_STATUS_CLOSED) - { - gGameCommandErrorText = STR_MUST_BE_CLOSED_FIRST; - return MONEY32_UNDEFINED; - } - - if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) - { - gGameCommandErrorText = STR_NOT_ALLOWED_TO_MODIFY_STATION; - return MONEY32_UNDEFINED; - } - - ride_clear_for_construction(ride); - ride_remove_peeps(ride); - - bool requiresRemove = false; - LocationXY16 removeCoord = { 0, 0 }; - - if (isExit) - { - const auto exit = ride_get_exit_location(ride, stationNum); - if (!exit.isNull()) - { - if (flags & GAME_COMMAND_FLAG_GHOST) - { - gGameCommandErrorText = 0; - return MONEY32_UNDEFINED; - } - - removeCoord.x = exit.x * 32; - removeCoord.y = exit.y * 32; - requiresRemove = true; - } - } - else - { - const auto entrance = ride_get_entrance_location(ride, stationNum); - if (!entrance.isNull()) - { - if (flags & GAME_COMMAND_FLAG_GHOST) - { - gGameCommandErrorText = 0; - return MONEY32_UNDEFINED; - } - - removeCoord.x = entrance.x * 32; - removeCoord.y = entrance.y * 32; - requiresRemove = true; - } - } - - if (requiresRemove) - { - auto rideEntranceExitRemove = RideEntranceExitRemoveAction( - { removeCoord.x, removeCoord.y }, rideIndex, stationNum, isExit); - rideEntranceExitRemove.SetFlags(flags); - - auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&rideEntranceExitRemove) - : GameActions::QueryNested(&rideEntranceExitRemove); - if (res->Error != GA_ERROR::OK) - { - return MONEY32_UNDEFINED; - } - } - - z = ride->stations[stationNum].Height * 8; - gCommandPosition.z = z; - - if ((flags & GAME_COMMAND_FLAG_APPLY) && !(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) - && !(flags & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter(x, y, z); - wall_remove_at_z(x, y, z); - } - - if (!gCheatsSandboxMode && !map_is_location_owned(x, y, z)) - { - return MONEY32_UNDEFINED; - } - - int8_t clear_z = (z / 8) + (isExit ? 5 : 7); - - if (!map_can_construct_with_clear_at( - x, y, z / 8, clear_z, &map_place_non_scenery_clear_func, { 0b1111, 0 }, flags, &cost, - CREATE_CROSSING_MODE_NONE)) - { - return MONEY32_UNDEFINED; - } - - if (gMapGroundFlags & ELEMENT_IS_UNDERWATER) - { - gGameCommandErrorText = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; - return MONEY32_UNDEFINED; - } - - if (z / 8 > 244) - { - gGameCommandErrorText = STR_TOO_HIGH; - return MONEY32_UNDEFINED; - } - - if (flags & GAME_COMMAND_FLAG_APPLY) - { - LocationXYZ16 coord; - coord.x = x + 16; - coord.y = y + 16; - coord.z = tile_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - - TileElement* tileElement = tile_element_insert(x / 32, y / 32, z / 8, 0xF); - assert(tileElement != nullptr); - tileElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); - tileElement->SetDirection(direction); - tileElement->clearance_height = clear_z; - tileElement->AsEntrance()->SetEntranceType(isExit ? ENTRANCE_TYPE_RIDE_EXIT : ENTRANCE_TYPE_RIDE_ENTRANCE); - tileElement->AsEntrance()->SetStationIndex(stationNum); - tileElement->AsEntrance()->SetRideIndex(rideIndex); - - if (flags & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } - - if (isExit) - { - ride_set_exit_location(ride, stationNum, { x / 32, y / 32, z / 8, (uint8_t)tileElement->GetDirection() }); - } - else - { - ride_set_entrance_location(ride, stationNum, { x / 32, y / 32, z / 8, (uint8_t)tileElement->GetDirection() }); - ride->stations[stationNum].LastPeepInQueue = SPRITE_INDEX_NULL; - ride->stations[stationNum].QueueLength = 0; - - map_animation_create(MAP_ANIMATION_TYPE_RIDE_ENTRANCE, x, y, z / 8); - } - - footpath_queue_chain_reset(); - - if (!(flags & GAME_COMMAND_FLAG_GHOST)) - { - maze_entrance_hedge_removal(x, y, tileElement); - } - - footpath_connect_edges(x, y, tileElement, flags); - footpath_update_queue_chains(); - - map_invalidate_tile_full(x, y); - } - } - - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; - return cost; -} - static money32 RideEntranceExitPlaceGhost( ride_id_t rideIndex, int16_t x, int16_t y, uint8_t direction, uint8_t placeType, uint8_t stationNum) { - return game_do_command( - x, - (GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5 | GAME_COMMAND_FLAG_GHOST) - | (direction << 8), - y, rideIndex | (placeType << 8), GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, stationNum, 0); + auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction( + { x, y }, direction, rideIndex, stationNum, placeType == ENTRANCE_TYPE_RIDE_EXIT); + rideEntranceExitPlaceAction.SetFlags(GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST); + auto res = GameActions::Execute(&rideEntranceExitPlaceAction); + + return res->Error == GA_ERROR::OK ? res->Cost : MONEY32_UNDEFINED; } /** @@ -410,19 +188,6 @@ money32 ride_entrance_exit_place_ghost( return result; } -/** - * - * rct2: 0x006660A8 - */ -void game_command_place_ride_entrance_or_exit( - int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, - [[maybe_unused]] int32_t* ebp) -{ - *ebx = RideEntranceExitPlace( - *eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, (*ebx >> 8) & 0xFF, *ebx & 0xFF, *edx & 0xFF, *edi & 0xFF, - ((*edx >> 8) & 0xFF) != 0); -} - /** * Replaces the outer hedge walls for an entrance placement removal. * rct2: 0x00666D6F diff --git a/src/openrct2/world/Entrance.h b/src/openrct2/world/Entrance.h index eff7bd5f35..740791b3f6 100644 --- a/src/openrct2/world/Entrance.h +++ b/src/openrct2/world/Entrance.h @@ -37,6 +37,8 @@ extern uint8_t gParkEntranceGhostDirection; #define MAX_PARK_ENTRANCES 4 +constexpr int32_t MaxRideEntranceOrExitHeight = 244; + extern std::vector gParkEntrances; extern CoordsXYZD gRideEntranceExitGhostPosition;