1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-20 05:23:04 +01:00

Refactor how map animations are created and stored

This commit is contained in:
ζeh Matt
2025-05-07 01:40:11 +03:00
committed by mix
parent 829d146765
commit 769a85afb7
19 changed files with 299 additions and 641 deletions

View File

@@ -35,185 +35,88 @@
#include "tile_element/TrackElement.h"
#include "tile_element/WallElement.h"
#include <algorithm>
#include <set>
using namespace OpenRCT2;
using map_animation_invalidate_event_handler = bool (*)(const CoordsXYZ& loc);
static std::vector<MapAnimation> _mapAnimations;
constexpr size_t kMaxAnimatedObjects = 2000;
static bool InvalidateMapAnimation(const MapAnimation& obj);
static bool DoesAnimationExist(int32_t type, const CoordsXYZ& location)
struct TileCoordsXYCmp
{
for (const auto& a : _mapAnimations)
constexpr bool operator()(const TileCoordsXY& lhs, const TileCoordsXY& rhs) const noexcept
{
if (a.type == type && a.location == location)
// NOTE: Ordering should match GetFirstElementAt which is x + (y * size)
return std::tie(lhs.y, lhs.x) < std::tie(rhs.y, rhs.x);
}
};
// A list of tile coordinates which contains animated tile elements.
static std::set<TileCoordsXY, TileCoordsXYCmp> _mapAnimations;
static bool UpdateEntranceAnimation(const EntranceElement& entrance, const CoordsXYZ& loc, const int32_t baseZ)
{
if (entrance.GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE)
{
const auto ride = GetRide(entrance.GetRideIndex());
if (ride != nullptr)
{
// Animation already exists
return true;
const auto stationObj = ride->getStationObject();
if (stationObj != nullptr)
{
MapInvalidateTileZoom1({ loc, baseZ + stationObj->Height + 8, baseZ + stationObj->Height + 24 });
return true;
}
}
}
else if (entrance.GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE && entrance.GetSequenceIndex() == 0)
{
const int32_t direction = (entrance.GetDirection() + GetCurrentRotation()) & 3;
if (direction == TILE_ELEMENT_DIRECTION_SOUTH || direction == TILE_ELEMENT_DIRECTION_WEST)
{
MapInvalidateTileZoom1({ loc, baseZ + 32, baseZ + 64 });
}
return true;
}
return false;
}
static bool UpdatePathAnimation(const PathElement& path, const CoordsXYZ& loc, const int32_t baseZ)
{
if (path.IsQueue() && path.HasQueueBanner())
{
const int32_t direction = (path.GetQueueBannerDirection() + GetCurrentRotation()) & 3;
if (direction == TILE_ELEMENT_DIRECTION_NORTH || direction == TILE_ELEMENT_DIRECTION_EAST)
{
MapInvalidateTileZoom1({ loc, baseZ + 16, baseZ + 30 });
}
return true;
}
return false;
}
void MapAnimationCreate(int32_t type, const CoordsXYZ& loc)
static bool UpdateSmallSceneryAnimation(const SmallSceneryElement& scenery, const CoordsXYZ& loc, const int32_t baseZ)
{
if (!DoesAnimationExist(type, loc))
const auto entry = scenery.GetEntry();
if (entry == nullptr)
{
if (_mapAnimations.size() < kMaxAnimatedObjects)
{
// Create new animation
_mapAnimations.push_back({ static_cast<uint8_t>(type), loc });
}
else
{
LOG_ERROR("Exceeded the maximum number of animations");
}
}
}
/**
*
* rct2: 0x0068AFAD
*/
void MapAnimationInvalidateAll()
{
PROFILED_FUNCTION();
auto it = _mapAnimations.begin();
while (it != _mapAnimations.end())
{
if (InvalidateMapAnimation(*it))
{
// Map animation has finished, remove it
it = _mapAnimations.erase(it);
}
else
{
it++;
}
}
}
/**
*
* rct2: 0x00666670
*/
static bool MapAnimationInvalidateRideEntrance(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
auto tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Entrance)
continue;
if (tileElement->AsEntrance()->GetEntranceType() != ENTRANCE_TYPE_RIDE_ENTRANCE)
continue;
auto ride = GetRide(tileElement->AsEntrance()->GetRideIndex());
if (ride != nullptr)
{
auto stationObj = ride->getStationObject();
if (stationObj != nullptr)
{
int32_t height = loc.z + stationObj->Height + 8;
MapInvalidateTileZoom1({ loc, height, height + 16 });
}
}
return false;
} while (!(tileElement++)->IsLastForTile());
}
return true;
}
/**
*
* rct2: 0x006A7BD4
*/
static bool MapAnimationInvalidateQueueBanner(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
if (entry->HasFlag(
SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 | SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 | SMALL_SCENERY_FLAG_SWAMP_GOO
| SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS | SMALL_SCENERY_FLAG_IS_CLOCK))
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Path)
continue;
if (!(tileElement->AsPath()->IsQueue()))
continue;
if (!tileElement->AsPath()->HasQueueBanner())
continue;
int32_t direction = (tileElement->AsPath()->GetQueueBannerDirection() + GetCurrentRotation()) & 3;
if (direction == TILE_ELEMENT_DIRECTION_NORTH || direction == TILE_ELEMENT_DIRECTION_EAST)
// Don't apply anything to peeps when the scenery is a ghost.
if (!scenery.IsGhost())
{
MapInvalidateTileZoom1({ loc, loc.z + 16, loc.z + 30 });
}
return false;
} while (!(tileElement++)->IsLastForTile());
return true;
}
/**
*
* rct2: 0x006E32C9
*/
static bool MapAnimationInvalidateSmallScenery(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
auto tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::SmallScenery)
continue;
if (tileElement->IsGhost())
continue;
auto* sceneryEntry = tileElement->AsSmallScenery()->GetEntry();
if (sceneryEntry == nullptr)
continue;
if (sceneryEntry->HasFlag(
SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 | SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 | SMALL_SCENERY_FLAG_SWAMP_GOO
| SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS))
{
MapInvalidateTileZoom1({ loc, loc.z, tileElement->GetClearanceZ() });
return false;
}
if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_IS_CLOCK))
{
// Peep, looking at scenery
if (!(getGameState().currentTicks & 0x3FF) && GameIsNotPaused())
if (entry->HasFlag(SMALL_SCENERY_FLAG_IS_CLOCK) && !(getGameState().currentTicks & 0x3FF))
{
int32_t direction = tileElement->GetDirection();
auto quad = EntityTileList<Peep>(CoordsXY{ loc } - CoordsDirectionDelta[direction]);
const int32_t direction = scenery.GetDirection();
auto quad = EntityTileList<Peep>(CoordsXY{ loc.x, loc.y } - CoordsDirectionDelta[direction]);
for (auto peep : quad)
{
if (peep->State != PeepState::Walking)
if (peep->State != PeepState::Walking || peep->z != baseZ || peep->Action < PeepActionType::Idle)
continue;
if (peep->z != loc.z)
continue;
if (peep->Action < PeepActionType::Idle)
continue;
peep->Action = PeepActionType::CheckTime;
peep->AnimationFrameNum = 0;
peep->AnimationImageIdOffset = 0;
@@ -222,509 +125,302 @@ static bool MapAnimationInvalidateSmallScenery(const CoordsXYZ& loc)
break;
}
}
MapInvalidateTileZoom1({ loc, loc.z, tileElement->GetClearanceZ() });
return false;
}
const auto clearZ = scenery.GetClearanceZ();
MapInvalidateTileZoom1({ loc, baseZ, clearZ });
return true;
}
} while (!(tileElement++)->IsLastForTile());
return true;
return false;
}
/**
*
* rct2: 0x00666C63
*/
static bool MapAnimationInvalidateParkEntrance(const CoordsXYZ& loc)
static bool UpdateTrackAnimation(TrackElement& track, const CoordsXYZ& loc, const int32_t baseZ)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
const auto clearZ = track.GetClearanceZ();
switch (track.GetTrackType())
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Entrance)
continue;
if (tileElement->AsEntrance()->GetEntranceType() != ENTRANCE_TYPE_PARK_ENTRANCE)
continue;
if (tileElement->AsEntrance()->GetSequenceIndex())
continue;
case TrackElemType::Waterfall:
MapInvalidateTileZoom1({ loc, baseZ + 14, baseZ + 46 });
return true;
case TrackElemType::Rapids:
case TrackElemType::Whirlpool:
MapInvalidateTileZoom1({ loc, baseZ + 14, baseZ + 18 });
return true;
case TrackElemType::SpinningTunnel:
MapInvalidateTileZoom1({ loc, baseZ + 14, baseZ + 32 });
return true;
case TrackElemType::OnRidePhoto:
if (track.IsTakingPhoto())
{
MapInvalidateTileZoom1({ loc, baseZ, clearZ });
track.DecrementPhotoTimeout();
return true;
}
default:
break;
}
MapInvalidateTileZoom1({ loc, loc.z + 32, loc.z + 64 });
return false;
}
static bool UpdateLargeSceneryAnimation(const LargeSceneryElement& scenery, const CoordsXYZ& loc, const int32_t baseZ)
{
const auto entry = scenery.GetEntry();
if (entry != nullptr && (entry->flags & LARGE_SCENERY_FLAG_ANIMATED))
{
MapInvalidateTileZoom1({ loc, baseZ, baseZ + 16 });
return true;
}
return false;
}
static bool UpdateWallAnimation(WallElement& wall, const CoordsXYZ& loc, const int32_t baseZ)
{
const auto entry = wall.GetEntry();
if (entry == nullptr)
{
return false;
} while (!(tileElement++)->IsLastForTile());
}
return true;
}
/**
*
* rct2: 0x006CE29E
*/
static bool MapAnimationInvalidateTrackWaterfall(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
if (entry->flags & WALL_SCENERY_IS_DOOR)
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Track)
continue;
if (tileElement->AsTrack()->GetTrackType() == TrackElemType::Waterfall)
if (getGameState().currentTicks & 1)
{
MapInvalidateTileZoom1({ loc, loc.z + 14, loc.z + 46 });
return false;
}
} while (!(tileElement++)->IsLastForTile());
return true;
}
/**
*
* rct2: 0x006CE2F3
*/
static bool MapAnimationInvalidateTrackRapids(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Track)
continue;
if (tileElement->AsTrack()->GetTrackType() == TrackElemType::Rapids)
{
MapInvalidateTileZoom1({ loc, loc.z + 14, loc.z + 18 });
return false;
}
} while (!(tileElement++)->IsLastForTile());
return true;
}
/**
*
* rct2: 0x006CE39D
*/
static bool MapAnimationInvalidateTrackOnRidePhoto(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Track)
continue;
if (tileElement->AsTrack()->GetTrackType() == TrackElemType::OnRidePhoto)
{
MapInvalidateTileZoom1({ loc, loc.z, tileElement->GetClearanceZ() });
if (GameIsPaused())
{
return false;
}
if (tileElement->AsTrack()->IsTakingPhoto())
{
tileElement->AsTrack()->DecrementPhotoTimeout();
return false;
}
return true;
}
} while (!(tileElement++)->IsLastForTile());
return true;
}
bool removeAnim = true;
/**
*
* rct2: 0x006CE348
*/
static bool MapAnimationInvalidateTrackWhirlpool(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Track)
continue;
if (tileElement->AsTrack()->GetTrackType() == TrackElemType::Whirlpool)
{
MapInvalidateTileZoom1({ loc, loc.z + 14, loc.z + 18 });
return false;
}
} while (!(tileElement++)->IsLastForTile());
return true;
}
/**
*
* rct2: 0x006CE3FA
*/
static bool MapAnimationInvalidateTrackSpinningTunnel(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Track)
continue;
if (tileElement->AsTrack()->GetTrackType() == TrackElemType::SpinningTunnel)
{
MapInvalidateTileZoom1({ loc, loc.z + 14, loc.z + 32 });
return false;
}
} while (!(tileElement++)->IsLastForTile());
return true;
}
/**
*
* rct2: 0x0068DF8F
*/
static bool MapAnimationInvalidateRemove([[maybe_unused]] const CoordsXYZ& loc)
{
return true;
}
/**
*
* rct2: 0x006BA2BB
*/
static bool MapAnimationInvalidateBanner(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Banner)
continue;
MapInvalidateTileZoom1({ loc, loc.z, loc.z + 16 });
return false;
} while (!(tileElement++)->IsLastForTile());
return true;
}
/**
*
* rct2: 0x006B94EB
*/
static bool MapAnimationInvalidateLargeScenery(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
bool wasInvalidated = false;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::LargeScenery)
continue;
auto* sceneryEntry = tileElement->AsLargeScenery()->GetEntry();
if (sceneryEntry != nullptr && sceneryEntry->flags & LARGE_SCENERY_FLAG_ANIMATED)
{
MapInvalidateTileZoom1({ loc, loc.z, loc.z + 16 });
wasInvalidated = true;
}
} while (!(tileElement++)->IsLastForTile());
return !wasInvalidated;
}
/**
*
* rct2: 0x006E5B50
*/
static bool MapAnimationInvalidateWallDoor(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
if (getGameState().currentTicks & 1)
return false;
bool removeAnimation = true;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return removeAnimation;
do
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Wall)
continue;
auto* wallEntry = tileElement->AsWall()->GetEntry();
if (wallEntry == nullptr || !(wallEntry->flags & WALL_SCENERY_IS_DOOR))
continue;
if (GameIsPaused())
{
return false;
}
bool invalidate = false;
uint8_t currentFrame = tileElement->AsWall()->GetAnimationFrame();
const auto currentFrame = wall.GetAnimationFrame();
if (currentFrame != 0)
{
auto newFrame = currentFrame;
if (currentFrame == 15)
{
currentFrame = 0;
newFrame = 0;
}
else
{
removeAnimation = false;
removeAnim = false;
if (currentFrame != 5)
{
currentFrame++;
if (currentFrame == 13 && !(wallEntry->flags & WALL_SCENERY_LONG_DOOR_ANIMATION))
currentFrame = 15;
newFrame++;
invalidate = true;
if (newFrame == 13 && !(entry->flags & WALL_SCENERY_LONG_DOOR_ANIMATION))
newFrame = 15;
}
}
if (currentFrame != newFrame)
{
wall.SetAnimationFrame(newFrame);
MapInvalidateTileZoom1({ loc, baseZ, baseZ + 32 });
}
}
tileElement->AsWall()->SetAnimationFrame(currentFrame);
if (invalidate)
{
MapInvalidateTileZoom1({ loc, loc.z, loc.z + 32 });
}
} while (!(tileElement++)->IsLastForTile());
return removeAnimation;
}
/**
*
* rct2: 0x006E5EE4
*/
static bool MapAnimationInvalidateWall(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
bool wasInvalidated = false;
tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
return true;
do
{
if (tileElement->BaseHeight != tileLoc.z)
continue;
if (tileElement->GetType() != TileElementType::Wall)
continue;
auto* wallEntry = tileElement->AsWall()->GetEntry();
if (wallEntry == nullptr
|| (!(wallEntry->flags2 & WALL_SCENERY_2_ANIMATED) && wallEntry->scrolling_mode == kScrollingModeNone))
continue;
MapInvalidateTileZoom1({ loc, loc.z, loc.z + 16 });
wasInvalidated = true;
} while (!(tileElement++)->IsLastForTile());
return !wasInvalidated;
}
/**
*
* rct2: 0x009819DC
*/
static constexpr map_animation_invalidate_event_handler _animatedObjectEventHandlers[MAP_ANIMATION_TYPE_COUNT] = {
MapAnimationInvalidateRideEntrance, MapAnimationInvalidateQueueBanner, MapAnimationInvalidateSmallScenery,
MapAnimationInvalidateParkEntrance, MapAnimationInvalidateTrackWaterfall, MapAnimationInvalidateTrackRapids,
MapAnimationInvalidateTrackOnRidePhoto, MapAnimationInvalidateTrackWhirlpool, MapAnimationInvalidateTrackSpinningTunnel,
MapAnimationInvalidateRemove, MapAnimationInvalidateBanner, MapAnimationInvalidateLargeScenery,
MapAnimationInvalidateWallDoor, MapAnimationInvalidateWall,
};
/**
* @returns true if the animation should be removed.
*/
static bool InvalidateMapAnimation(const MapAnimation& a)
{
if (a.type < std::size(_animatedObjectEventHandlers))
{
return _animatedObjectEventHandlers[a.type](a.location);
return !removeAnim;
}
else if ((entry->flags2 & WALL_SCENERY_2_ANIMATED) || entry->scrolling_mode != kScrollingModeNone)
{
MapInvalidateTileZoom1({ loc, baseZ, baseZ + 16 });
return true;
}
return false;
}
static bool UpdateBannerAnimation([[maybe_unused]] const BannerElement& banner, const CoordsXYZ& loc, const int32_t baseZ)
{
MapInvalidateTileZoom1({ loc, baseZ, baseZ + 16 });
return true;
}
const std::vector<MapAnimation>& GetMapAnimations()
static bool UpdateTileAnimations(const TileCoordsXY& coords)
{
return _mapAnimations;
}
void ClearMapAnimations()
{
_mapAnimations.clear();
}
void MapAnimationAutoCreate()
{
ClearMapAnimations();
TileElementIterator it;
TileElementIteratorBegin(&it);
while (TileElementIteratorNext(&it))
auto tileElement = MapGetFirstElementAt(coords);
if (tileElement == nullptr)
{
MapAnimationAutoCreateAtTileElement(TileCoordsXY(it.x, it.y), it.element);
return false;
}
bool hasAnimations = false;
do
{
const auto baseZ = tileElement->GetBaseZ();
const CoordsXYZ loc{ coords.ToCoordsXY(), baseZ };
switch (tileElement->GetType())
{
case TileElementType::Entrance:
hasAnimations |= UpdateEntranceAnimation(*tileElement->AsEntrance(), loc, baseZ);
break;
case TileElementType::Path:
hasAnimations |= UpdatePathAnimation(*tileElement->AsPath(), loc, baseZ);
break;
case TileElementType::SmallScenery:
hasAnimations |= UpdateSmallSceneryAnimation(*tileElement->AsSmallScenery(), loc, baseZ);
break;
case TileElementType::Track:
hasAnimations |= UpdateTrackAnimation(*tileElement->AsTrack(), loc, baseZ);
break;
case TileElementType::Banner:
hasAnimations |= UpdateBannerAnimation(*tileElement->AsBanner(), loc, baseZ);
break;
case TileElementType::LargeScenery:
hasAnimations |= UpdateLargeSceneryAnimation(*tileElement->AsLargeScenery(), loc, baseZ);
break;
case TileElementType::Wall:
hasAnimations |= UpdateWallAnimation(*tileElement->AsWall(), loc, baseZ);
break;
default:
break;
}
} while (!(tileElement++)->IsLastForTile());
return hasAnimations;
}
void MapAnimationAutoCreateAtTileElement(TileCoordsXY coords, TileElement* el)
static bool IsElementAnimated(const TileElementBase& element, const bool skipDoors)
{
if (el == nullptr)
{
return;
}
auto loc = CoordsXYZ{ coords.ToCoordsXY(), el->GetBaseZ() };
switch (el->GetType())
switch (element.GetType())
{
case TileElementType::Banner:
MapAnimationCreate(MAP_ANIMATION_TYPE_BANNER, loc);
break;
return true;
case TileElementType::Wall:
{
auto wallEl = el->AsWall();
auto* entry = wallEl->GetEntry();
if (entry != nullptr && ((entry->flags2 & WALL_SCENERY_2_ANIMATED) || entry->scrolling_mode != kScrollingModeNone))
const auto wall = element.AsWall();
const auto entry = wall->GetEntry();
if (entry != nullptr)
{
MapAnimationCreate(MAP_ANIMATION_TYPE_WALL, loc);
if ((entry->flags2 & WALL_SCENERY_2_ANIMATED) || entry->scrolling_mode != kScrollingModeNone)
{
return true;
}
if (!skipDoors && (entry->flags & WALL_SCENERY_IS_DOOR))
{
return true;
}
}
break;
}
case TileElementType::SmallScenery:
{
auto sceneryEl = el->AsSmallScenery();
auto* sceneryEntry = sceneryEl->GetEntry();
if (sceneryEntry != nullptr && sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_ANIMATED))
const auto scenery = element.AsSmallScenery();
const auto entry = scenery->GetEntry();
if (entry != nullptr && entry->HasFlag(SMALL_SCENERY_FLAG_ANIMATED))
{
MapAnimationCreate(MAP_ANIMATION_TYPE_SMALL_SCENERY, loc);
return true;
}
break;
}
case TileElementType::LargeScenery:
{
auto sceneryEl = el->AsLargeScenery();
auto entry = sceneryEl->GetEntry();
const auto scenery = element.AsLargeScenery();
const auto entry = scenery->GetEntry();
if (entry != nullptr && (entry->flags & LARGE_SCENERY_FLAG_ANIMATED))
{
MapAnimationCreate(MAP_ANIMATION_TYPE_LARGE_SCENERY, loc);
return true;
}
break;
}
case TileElementType::Path:
{
auto path = el->AsPath();
const auto path = element.AsPath();
if (path->HasQueueBanner())
{
MapAnimationCreate(MAP_ANIMATION_TYPE_QUEUE_BANNER, loc);
return true;
}
break;
}
case TileElementType::Entrance:
{
auto entrance = el->AsEntrance();
switch (entrance->GetEntranceType())
const auto entrance = element.AsEntrance();
if (entrance->GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE && entrance->GetSequenceIndex() == 0)
{
case ENTRANCE_TYPE_PARK_ENTRANCE:
if (entrance->GetSequenceIndex() == 0)
{
MapAnimationCreate(MAP_ANIMATION_TYPE_PARK_ENTRANCE, loc);
}
break;
case ENTRANCE_TYPE_RIDE_ENTRANCE:
MapAnimationCreate(MAP_ANIMATION_TYPE_RIDE_ENTRANCE, loc);
break;
return true;
}
else if (entrance->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE)
{
return true;
}
break;
}
case TileElementType::Track:
{
auto track = el->AsTrack();
const auto track = element.AsTrack();
switch (track->GetTrackType())
{
case TrackElemType::Waterfall:
MapAnimationCreate(MAP_ANIMATION_TYPE_TRACK_WATERFALL, loc);
break;
case TrackElemType::Rapids:
MapAnimationCreate(MAP_ANIMATION_TYPE_TRACK_RAPIDS, loc);
break;
case TrackElemType::Whirlpool:
MapAnimationCreate(MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL, loc);
break;
case TrackElemType::SpinningTunnel:
MapAnimationCreate(MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL, loc);
break;
case TrackElemType::OnRidePhoto:
return true;
default:
break;
}
break;
}
case TileElementType::Surface:
default:
break;
}
return false;
}
void MapAnimation::Create(const CoordsXY coords)
{
_mapAnimations.insert(TileCoordsXY(coords));
}
void MapAnimation::CreateAll()
{
ClearAll();
TileElementIterator it;
TileElementIteratorBegin(&it);
while (TileElementIteratorNext(&it))
{
if (IsElementAnimated(*it.element, true))
{
_mapAnimations.insert(TileCoordsXY(it.x, it.y));
}
}
}
void ShiftAllMapAnimations(CoordsXY amount)
void MapAnimation::UpdateAll()
{
PROFILED_FUNCTION();
auto it = _mapAnimations.begin();
while (it != _mapAnimations.end())
{
if (UpdateTileAnimations(*it))
{
++it; // Tile was updated, keep it
}
else
{
it = _mapAnimations.erase(it); // No updates, remove tile
}
}
}
void MapAnimation::ClearAll()
{
_mapAnimations.clear();
}
void MapAnimation::ShiftAll(const CoordsXY amount)
{
if (amount.x == 0 && amount.y == 0)
return;
for (auto& a : _mapAnimations)
std::set<TileCoordsXY, TileCoordsXYCmp> newMapAnimations;
for (const auto& a : _mapAnimations)
{
a.location += amount;
newMapAnimations.insert(a + TileCoordsXY(amount));
}
_mapAnimations = std::move(newMapAnimations);
}