diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 4718adad9c..f1e15ab889 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -481,13 +481,12 @@ void game_fix_save_vars() if (surfaceElement == nullptr) { log_error("Null map element at x = %d and y = %d. Fixing...", x, y); - auto tileElement = tile_element_insert(TileCoordsXYZ{ x, y, 14 }.ToCoordsXYZ(), 0b0000); - if (tileElement == nullptr) + surfaceElement = TileElementInsert(TileCoordsXYZ{ x, y, 14 }.ToCoordsXYZ(), 0b0000); + if (surfaceElement == nullptr) { log_error("Unable to fix: Map element limit reached."); return; } - surfaceElement = tileElement->AsSurface(); } // Fix the invisible border tiles. diff --git a/src/openrct2/actions/BannerPlaceAction.cpp b/src/openrct2/actions/BannerPlaceAction.cpp index ffb68b5bd9..ec506bc35d 100644 --- a/src/openrct2/actions/BannerPlaceAction.cpp +++ b/src/openrct2/actions/BannerPlaceAction.cpp @@ -140,26 +140,22 @@ GameActions::Result::Ptr BannerPlaceAction::Execute() const 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(); + + auto* bannerElement = TileElementInsert({ _loc, _loc.z + (2 * COORDS_Z_STEP) }, 0b0000); + Guard::Assert(bannerElement != nullptr); + bannerElement->SetClearanceZ(_loc.z + PATH_CLEARANCE); bannerElement->SetPosition(_loc.direction); bannerElement->ResetAllowedEdges(); bannerElement->SetIndex(_bannerIndex); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - bannerElement->SetGhost(true); - } + bannerElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST); + map_invalidate_tile_full(_loc); map_animation_create(MAP_ANIMATION_TYPE_BANNER, CoordsXYZ{ _loc, bannerElement->GetBaseZ() }); diff --git a/src/openrct2/actions/FootpathPlaceAction.cpp b/src/openrct2/actions/FootpathPlaceAction.cpp index 5c9f465b34..33c00b3dfa 100644 --- a/src/openrct2/actions/FootpathPlaceAction.cpp +++ b/src/openrct2/actions/FootpathPlaceAction.cpp @@ -340,34 +340,25 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions:: } else { - auto tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); - tileElement->SetType(TILE_ELEMENT_TYPE_PATH); - PathElement* pathElement = tileElement->AsPath(); + auto* pathElement = TileElementInsert(_loc, 0b1111); + Guard::Assert(pathElement != nullptr); + 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->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED); + pathElement->SetIsQueue(_type & FOOTPATH_ELEMENT_INSERT_QUEUE); pathElement->SetAddition(0); pathElement->SetRideIndex(RIDE_ID_NULL); pathElement->SetAdditionStatus(255); pathElement->SetIsBroken(false); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - pathElement->SetGhost(true); - } + pathElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST); + footpath_queue_chain_reset(); if (!(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY)) { - footpath_remove_edges_at(_loc, tileElement); + footpath_remove_edges_at(_loc, pathElement->as()); } if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) { diff --git a/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp b/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp index aee4964bdb..ea9407091c 100644 --- a/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp +++ b/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp @@ -230,31 +230,22 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(Game } else { - auto tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); - tileElement->SetType(TILE_ELEMENT_TYPE_PATH); - PathElement* pathElement = tileElement->AsPath(); + auto* pathElement = TileElementInsert(_loc, 0b1111); + Guard::Assert(pathElement != nullptr); + 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->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED); + pathElement->SetIsQueue(_type & FOOTPATH_ELEMENT_INSERT_QUEUE); 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); - } + pathElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST); + map_invalidate_tile_full(_loc); } diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.cpp b/src/openrct2/actions/LargeSceneryPlaceAction.cpp index 8172d3d825..ea9c3b86f6 100644 --- a/src/openrct2/actions/LargeSceneryPlaceAction.cpp +++ b/src/openrct2/actions/LargeSceneryPlaceAction.cpp @@ -277,19 +277,17 @@ GameActions::Result::Ptr LargeSceneryPlaceAction::Execute() const } } - TileElement* newTileElement = tile_element_insert( + auto* newSceneryElement = TileElementInsert( 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(); + Guard::Assert(newSceneryElement != nullptr); + newSceneryElement->SetClearanceZ(zHigh); SetNewLargeSceneryElement(*newSceneryElement, tileNum); + map_animation_create(MAP_ANIMATION_TYPE_LARGE_SCENERY, { curTile, zLow }); if (tileNum == 0) { - res->tileElement = newTileElement; + res->tileElement = newSceneryElement->as(); } map_invalidate_tile_full(curTile); } diff --git a/src/openrct2/actions/MazePlaceTrackAction.cpp b/src/openrct2/actions/MazePlaceTrackAction.cpp index e0411563e6..fbb63a27c6 100644 --- a/src/openrct2/actions/MazePlaceTrackAction.cpp +++ b/src/openrct2/actions/MazePlaceTrackAction.cpp @@ -168,25 +168,19 @@ GameActions::Result::Ptr MazePlaceTrackAction::Execute() const auto startLoc = _loc.ToTileStart(); - auto tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); + auto* trackElement = TileElementInsert(_loc, 0b1111); + Guard::Assert(trackElement != 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); - } + trackElement->SetClearanceZ(clearanceHeight); + trackElement->SetTrackType(TrackElemType::Maze); + trackElement->SetRideIndex(_rideIndex); + trackElement->SetMazeEntry(_mazeEntry); + trackElement->SetGhost(flags & GAME_COMMAND_FLAG_GHOST); map_invalidate_tile_full(startLoc); ride->maze_tiles++; - ride->stations[0].SetBaseZ(tileElement->GetBaseZ()); + ride->stations[0].SetBaseZ(trackElement->GetBaseZ()); ride->stations[0].Start = { 0, 0 }; if (ride->maze_tiles == 1) diff --git a/src/openrct2/actions/MazeSetTrackAction.cpp b/src/openrct2/actions/MazeSetTrackAction.cpp index 9fe32e09ca..d71e53a26b 100644 --- a/src/openrct2/actions/MazeSetTrackAction.cpp +++ b/src/openrct2/actions/MazeSetTrackAction.cpp @@ -181,20 +181,16 @@ GameActions::Result::Ptr MazeSetTrackAction::Execute() const auto startLoc = _loc.ToTileStart(); - tileElement = tile_element_insert(_loc, 0b1111); - assert(tileElement != nullptr); + auto* trackElement = TileElementInsert(_loc, 0b1111); + Guard::Assert(trackElement != nullptr); - tileElement->SetClearanceZ(_loc.z + MAZE_CLEARANCE_HEIGHT); - tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); + trackElement->SetClearanceZ(_loc.z + MAZE_CLEARANCE_HEIGHT); + trackElement->SetTrackType(TrackElemType::Maze); + trackElement->SetRideIndex(_rideIndex); + trackElement->SetMazeEntry(0xFFFF); + trackElement->SetGhost(flags & GAME_COMMAND_FLAG_GHOST); - tileElement->AsTrack()->SetTrackType(TrackElemType::Maze); - tileElement->AsTrack()->SetRideIndex(_rideIndex); - tileElement->AsTrack()->SetMazeEntry(0xFFFF); - - if (flags & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } + tileElement = trackElement->as(); map_invalidate_tile_full(startLoc); diff --git a/src/openrct2/actions/PlaceParkEntranceAction.cpp b/src/openrct2/actions/PlaceParkEntranceAction.cpp index 9472879212..661a69e1b9 100644 --- a/src/openrct2/actions/PlaceParkEntranceAction.cpp +++ b/src/openrct2/actions/PlaceParkEntranceAction.cpp @@ -138,30 +138,19 @@ GameActions::Result::Ptr PlaceParkEntranceAction::Execute() const } } - 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; - } + auto* entranceElement = TileElementInsert(CoordsXYZ{ entranceLoc, zLow }, 0b1111); + Guard::Assert(entranceElement != nullptr); + entranceElement->SetClearanceZ(zHigh); - - if (flags & GAME_COMMAND_FLAG_GHOST) - { - newElement->SetGhost(true); - } - + entranceElement->SetGhost(flags & GAME_COMMAND_FLAG_GHOST); entranceElement->SetDirection(_loc.direction); entranceElement->SetSequenceIndex(index); entranceElement->SetEntranceType(ENTRANCE_TYPE_PARK_ENTRANCE); entranceElement->SetPathType(gFootpathSelectedId); - if (!(flags & GAME_COMMAND_FLAG_GHOST)) + if (!entranceElement->IsGhost()) { - footpath_connect_edges(entranceLoc, newElement, GAME_COMMAND_FLAG_APPLY); + footpath_connect_edges(entranceLoc, entranceElement->as(), GAME_COMMAND_FLAG_APPLY); } update_park_fences(entranceLoc); @@ -170,7 +159,7 @@ GameActions::Result::Ptr PlaceParkEntranceAction::Execute() const 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() }); + map_invalidate_tile({ entranceLoc, entranceElement->GetBaseZ(), entranceElement->GetClearanceZ() }); if (index == 0) { diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.cpp b/src/openrct2/actions/RideEntranceExitPlaceAction.cpp index 8a85b86b05..bdea025199 100644 --- a/src/openrct2/actions/RideEntranceExitPlaceAction.cpp +++ b/src/openrct2/actions/RideEntranceExitPlaceAction.cpp @@ -176,27 +176,23 @@ GameActions::Result::Ptr RideEntranceExitPlaceAction::Execute() const 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); + auto* entranceElement = TileElementInsert(CoordsXYZ{ _loc, z }, 0b1111); + Guard::Assert(entranceElement != nullptr); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } + entranceElement->SetDirection(_direction); + entranceElement->SetClearanceZ(clear_z); + entranceElement->SetEntranceType(_isExit ? ENTRANCE_TYPE_RIDE_EXIT : ENTRANCE_TYPE_RIDE_ENTRANCE); + entranceElement->SetStationIndex(_stationNum); + entranceElement->SetRideIndex(_rideIndex); + entranceElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST); if (_isExit) { - ride_set_exit_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, tileElement->GetDirection() })); + ride_set_exit_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, entranceElement->GetDirection() })); } else { - ride_set_entrance_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, tileElement->GetDirection() })); + ride_set_entrance_location(ride, _stationNum, TileCoordsXYZD(CoordsXYZD{ _loc, z, entranceElement->GetDirection() })); ride->stations[_stationNum].LastPeepInQueue = SPRITE_INDEX_NULL; ride->stations[_stationNum].QueueLength = 0; @@ -207,10 +203,10 @@ GameActions::Result::Ptr RideEntranceExitPlaceAction::Execute() const if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) { - maze_entrance_hedge_removal({ _loc, tileElement }); + maze_entrance_hedge_removal({ _loc, entranceElement->as() }); } - footpath_connect_edges(_loc, tileElement, GetFlags()); + footpath_connect_edges(_loc, entranceElement->as(), GetFlags()); footpath_update_queue_chains(); map_invalidate_tile_full(_loc); diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.cpp b/src/openrct2/actions/SmallSceneryPlaceAction.cpp index 9668cf5e88..e8701443de 100644 --- a/src/openrct2/actions/SmallSceneryPlaceAction.cpp +++ b/src/openrct2/actions/SmallSceneryPlaceAction.cpp @@ -430,28 +430,24 @@ GameActions::Result::Ptr SmallSceneryPlaceAction::Execute() const 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(); + auto* sceneryElement = TileElementInsert( + CoordsXYZ{ _loc, zLow }, quarterTile.GetBaseQuarterOccupied()); + Guard::Assert(sceneryElement != nullptr); + + sceneryElement->SetDirection(_loc.direction); sceneryElement->SetSceneryQuadrant(quadrant); sceneryElement->SetEntryIndex(_sceneryType); sceneryElement->SetAge(0); sceneryElement->SetPrimaryColour(_primaryColour); sceneryElement->SetSecondaryColour(_secondaryColour); sceneryElement->SetClearanceZ(sceneryElement->GetBaseZ() + sceneryEntry->small_scenery.height + 7); - + sceneryElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST); if (supportsRequired) { sceneryElement->SetNeedsSupports(); } - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - sceneryElement->SetGhost(true); - } + res->tileElement = sceneryElement->as(); map_invalidate_tile_full(_loc); if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_ANIMATED)) diff --git a/src/openrct2/actions/TrackPlaceAction.cpp b/src/openrct2/actions/TrackPlaceAction.cpp index 0bbc903265..1a2edd27a9 100644 --- a/src/openrct2/actions/TrackPlaceAction.cpp +++ b/src/openrct2/actions/TrackPlaceAction.cpp @@ -592,58 +592,51 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const 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); - } + auto* trackElement = TileElementInsert(mapLoc, quarterTile.GetBaseQuarterOccupied()); + Guard::Assert(trackElement != nullptr); - tileElement->AsTrack()->SetSequenceIndex(trackBlock->index); - tileElement->AsTrack()->SetRideIndex(_rideIndex); - tileElement->AsTrack()->SetTrackType(_trackType); - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - tileElement->SetGhost(true); - } + trackElement->SetClearanceZ(clearanceZ); + trackElement->SetDirection(_origin.direction); + trackElement->SetHasChain(_trackPlaceFlags & CONSTRUCTION_LIFT_HILL_SELECTED); + trackElement->SetSequenceIndex(trackBlock->index); + trackElement->SetRideIndex(_rideIndex); + trackElement->SetTrackType(_trackType); + trackElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST); switch (_trackType) { case TrackElemType::Waterfall: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_WATERFALL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + map_animation_create(MAP_ANIMATION_TYPE_TRACK_WATERFALL, CoordsXYZ{ mapLoc, trackElement->GetBaseZ() }); break; case TrackElemType::Rapids: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_RAPIDS, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + map_animation_create(MAP_ANIMATION_TYPE_TRACK_RAPIDS, CoordsXYZ{ mapLoc, trackElement->GetBaseZ() }); break; case TrackElemType::Whirlpool: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + map_animation_create(MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL, CoordsXYZ{ mapLoc, trackElement->GetBaseZ() }); break; case TrackElemType::SpinningTunnel: - map_animation_create(MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL, CoordsXYZ{ mapLoc, tileElement->GetBaseZ() }); + map_animation_create(MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL, CoordsXYZ{ mapLoc, trackElement->GetBaseZ() }); break; } if (TrackTypeHasSpeedSetting(_trackType)) { - tileElement->AsTrack()->SetBrakeBoosterSpeed(_brakeSpeed); + trackElement->SetBrakeBoosterSpeed(_brakeSpeed); } else if (ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_HAS_LANDSCAPE_DOORS)) { - tileElement->AsTrack()->SetDoorAState(LANDSCAPE_DOOR_CLOSED); - tileElement->AsTrack()->SetDoorBState(LANDSCAPE_DOOR_CLOSED); + trackElement->SetDoorAState(LANDSCAPE_DOOR_CLOSED); + trackElement->SetDoorBState(LANDSCAPE_DOOR_CLOSED); } else { - tileElement->AsTrack()->SetSeatRotation(_seatRotation); + trackElement->SetSeatRotation(_seatRotation); } if (_trackPlaceFlags & RIDE_TYPE_ALTERNATIVE_TRACK_TYPE) { - tileElement->AsTrack()->SetInverted(true); + trackElement->SetInverted(true); } - tileElement->AsTrack()->SetColourScheme(_colour); + trackElement->SetColourScheme(_colour); if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { @@ -689,13 +682,15 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const ride->UpdateMaxVehicles(); } + auto* tileElement = trackElement->as(); + 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); + tileElement = waterSurfaceElement->as(); } } diff --git a/src/openrct2/actions/WallPlaceAction.cpp b/src/openrct2/actions/WallPlaceAction.cpp index 0d87c4c4f6..6002be50fa 100644 --- a/src/openrct2/actions/WallPlaceAction.cpp +++ b/src/openrct2/actions/WallPlaceAction.cpp @@ -397,24 +397,16 @@ GameActions::Result::Ptr WallPlaceAction::Execute() const } } - TileElement* tileElement = tile_element_insert(targetLoc, 0b0000); - assert(tileElement != nullptr); + auto* wallElement = TileElementInsert(targetLoc, 0b0000); + Guard::Assert(wallElement != 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->SetAcrossTrack(wallAcrossTrack); wallElement->SetEntryIndex(_wallType); if (_bannerId != BANNER_INDEX_NULL) @@ -427,12 +419,11 @@ GameActions::Result::Ptr WallPlaceAction::Execute() const wallElement->SetTertiaryColour(_tertiaryColour); } - if (GetFlags() & GAME_COMMAND_FLAG_GHOST) - { - wallElement->SetGhost(true); - } + wallElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST); - res->tileElement = tileElement; + res->tileElement = wallElement->as(); + + map_animation_create(MAP_ANIMATION_TYPE_WALL, targetLoc); map_invalidate_tile_zoom1({ _loc, wallElement->GetBaseZ(), wallElement->GetBaseZ() + 72 }); res->Cost = wallEntry->wall.price; diff --git a/src/openrct2/scripting/ScTile.hpp b/src/openrct2/scripting/ScTile.hpp index 7840664191..de745a8269 100644 --- a/src/openrct2/scripting/ScTile.hpp +++ b/src/openrct2/scripting/ScTile.hpp @@ -835,13 +835,13 @@ namespace OpenRCT2::Scripting // Insert corrupt element at the end of the list for this tile // Note: Z = MAX_ELEMENT_HEIGHT to guarantee this - TileElement* insertedElement = tile_element_insert({ _coords, MAX_ELEMENT_HEIGHT }, 0); + TileElement* insertedElement = tile_element_insert( + { _coords, MAX_ELEMENT_HEIGHT }, 0, TileElementType::Corrupt); if (insertedElement == nullptr) { // TODO: Show error return; } - insertedElement->SetType(TILE_ELEMENT_TYPE_CORRUPT); // Since inserting a new element may move the tile elements in memory, we have to update the local pointer _element = map_get_first_element_at(_coords) + elementIndex; @@ -1661,7 +1661,7 @@ namespace OpenRCT2::Scripting auto numToInsert = numElements - currentNumElements; for (size_t i = 0; i < numToInsert; i++) { - tile_element_insert(pos, 0); + tile_element_insert(pos, 0, TileElementType::Surface); } // Copy data to element span @@ -1706,7 +1706,7 @@ namespace OpenRCT2::Scripting std::vector data(first, first + origNumElements); auto pos = TileCoordsXYZ(TileCoordsXY(_coords), 0).ToCoordsXYZ(); - auto newElement = tile_element_insert(pos, 0); + auto newElement = tile_element_insert(pos, 0, TileElementType::Surface); if (newElement == nullptr) { auto ctx = GetDukContext(); diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 8c6e99f95a..2d6de3c057 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -1108,7 +1108,7 @@ bool map_check_free_elements_and_reorganise(int32_t numElements) * * rct2: 0x0068B1F6 */ -TileElement* tile_element_insert(const CoordsXYZ& loc, int32_t occupiedQuadrants) +TileElement* tile_element_insert(const CoordsXYZ& loc, int32_t occupiedQuadrants, TileElementType type) { const auto& tileLoc = TileCoordsXYZ(loc); TileElement *originalTileElement, *newTileElement, *insertedElement; @@ -1154,6 +1154,7 @@ TileElement* tile_element_insert(const CoordsXYZ& loc, int32_t occupiedQuadrants // Insert new map element insertedElement = newTileElement; newTileElement->type = 0; + newTileElement->SetType(static_cast(type)); newTileElement->SetBaseZ(loc.z); newTileElement->Flags = 0; newTileElement->SetLastForTile(isLastForTile); diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 038fceb1c8..f98fca3bcd 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -213,7 +213,13 @@ void map_invalidate_map_selection_tiles(); void map_invalidate_selection_rect(); void map_reorganise_elements(); bool map_check_free_elements_and_reorganise(int32_t num_elements); -TileElement* tile_element_insert(const CoordsXYZ& loc, int32_t occupiedQuadrants); +TileElement* tile_element_insert(const CoordsXYZ& loc, int32_t occupiedQuadrants, TileElementType type); + +template T* TileElementInsert(const CoordsXYZ& loc, int32_t occupiedQuadrants) +{ + auto* element = tile_element_insert(loc, occupiedQuadrants, T::ElementType); + return element->template as(); +} namespace GameActions { diff --git a/src/openrct2/world/MapGen.cpp b/src/openrct2/world/MapGen.cpp index 24439c282c..3f05c8340b 100644 --- a/src/openrct2/world/MapGen.cpp +++ b/src/openrct2/world/MapGen.cpp @@ -240,12 +240,12 @@ static void mapgen_place_tree(int32_t type, const CoordsXY& loc) } int32_t surfaceZ = tile_element_height(loc.ToTileCentre()); - TileElement* tileElement = tile_element_insert({ loc, surfaceZ }, 0b1111); - assert(tileElement != nullptr); - tileElement->SetClearanceZ(surfaceZ + sceneryEntry->small_scenery.height); - tileElement->SetType(TILE_ELEMENT_TYPE_SMALL_SCENERY); - tileElement->SetDirection(util_rand() & 3); - SmallSceneryElement* sceneryElement = tileElement->AsSmallScenery(); + + auto* sceneryElement = TileElementInsert({ loc, surfaceZ }, 0b1111); + Guard::Assert(sceneryElement != nullptr); + + sceneryElement->SetClearanceZ(surfaceZ + sceneryEntry->small_scenery.height); + sceneryElement->SetDirection(util_rand() & 3); sceneryElement->SetEntryIndex(type); sceneryElement->SetAge(0); sceneryElement->SetPrimaryColour(COLOUR_YELLOW); diff --git a/src/openrct2/world/TileElement.h b/src/openrct2/world/TileElement.h index 905674ac42..d9d6c7186a 100644 --- a/src/openrct2/world/TileElement.h +++ b/src/openrct2/world/TileElement.h @@ -56,6 +56,7 @@ enum class TileElementType : uint8_t Corrupt = (8 << 2), }; +struct TileElement; struct SurfaceElement; struct PathElement; struct TrackElement; @@ -102,11 +103,19 @@ struct TileElementBase template const TType* as() const { - return static_cast(GetType()) == TType::ElementType ? reinterpret_cast(this) : nullptr; + if constexpr (std::is_same_v) + return reinterpret_cast(this); + else + return static_cast(GetType()) == TType::ElementType ? reinterpret_cast(this) + : nullptr; } + template TType* as() { - return static_cast(GetType()) == TType::ElementType ? reinterpret_cast(this) : nullptr; + if constexpr (std::is_same_v) + return reinterpret_cast(this); + else + return static_cast(GetType()) == TType::ElementType ? reinterpret_cast(this) : nullptr; } const SurfaceElement* AsSurface() const diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index 21c00286ec..717f142e3f 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -88,13 +88,13 @@ GameActionResultPtr tile_inspector_insert_corrupt_at(const CoordsXY& loc, int16_ { // Create new corrupt element TileElement* corruptElement = tile_element_insert( - { loc, (-1 * COORDS_Z_STEP) }, 0b0000); // Ugly hack: -1 guarantees this to be placed first + { loc, (-1 * COORDS_Z_STEP) }, 0b0000, + TileElementType::Corrupt); // Ugly hack: -1 guarantees this to be placed first if (corruptElement == nullptr) { log_warning("Failed to insert corrupt element."); return std::make_unique(GameActions::Status::Unknown, STR_NONE); } - corruptElement->SetType(TILE_ELEMENT_TYPE_CORRUPT); // Set the base height to be the same as the selected element TileElement* const selectedElement = map_get_nth_element_at(loc, elementIndex + 1); @@ -382,7 +382,7 @@ GameActionResultPtr tile_inspector_paste_element_at(const CoordsXY& loc, TileEle // The occupiedQuadrants will be automatically set when the element is copied over, so it's not necessary to set them // correctly _here_. - TileElement* const pastedElement = tile_element_insert({ loc, element.GetBaseZ() }, 0b0000); + TileElement* const pastedElement = tile_element_insert({ loc, element.GetBaseZ() }, 0b0000, TileElementType::Surface); bool lastForTile = pastedElement->IsLastForTile(); *pastedElement = element;