mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-27 16:54:52 +01:00
Refactor map animations and dynamically create on park load (#9705)
This commit is contained in:
committed by
Michael Steenbeek
parent
1a6e5b5548
commit
c3234b1442
@@ -25,53 +25,42 @@
|
||||
#include "SmallScenery.h"
|
||||
#include "Sprite.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using map_animation_invalidate_event_handler = bool (*)(int32_t x, int32_t y, int32_t baseZ);
|
||||
|
||||
static bool map_animation_invalidate(rct_map_animation* obj);
|
||||
static std::vector<MapAnimation> _mapAnimations;
|
||||
|
||||
uint16_t gNumMapAnimations;
|
||||
rct_map_animation gAnimatedObjects[MAX_ANIMATED_OBJECTS];
|
||||
constexpr size_t MAX_ANIMATED_OBJECTS = 2000;
|
||||
|
||||
static bool InvalidateMapAnimation(const MapAnimation& obj);
|
||||
|
||||
static bool DoesAnimationExist(int32_t type, const CoordsXYZ& location)
|
||||
{
|
||||
for (const auto& a : _mapAnimations)
|
||||
{
|
||||
if (a.type == type && a.location.x == location.x && a.location.y == location.y && a.location.z == location.z)
|
||||
{
|
||||
// Animation already exists
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x0068AF67
|
||||
*
|
||||
* @param type (dh)
|
||||
* @param x (ax)
|
||||
* @param y (cx)
|
||||
* @param z (dl)
|
||||
*/
|
||||
void map_animation_create(int32_t type, int32_t x, int32_t y, int32_t z)
|
||||
{
|
||||
rct_map_animation* aobj = &gAnimatedObjects[0];
|
||||
int32_t numAnimatedObjects = gNumMapAnimations;
|
||||
if (numAnimatedObjects >= MAX_ANIMATED_OBJECTS)
|
||||
auto location = CoordsXYZ{ x, y, z };
|
||||
if (!DoesAnimationExist(type, location))
|
||||
{
|
||||
log_error("Exceeded the maximum number of animations");
|
||||
return;
|
||||
if (_mapAnimations.size() < MAX_ANIMATED_OBJECTS)
|
||||
{
|
||||
// Create new animation
|
||||
_mapAnimations.push_back({ (uint8_t)type, location });
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("Exceeded the maximum number of animations");
|
||||
}
|
||||
}
|
||||
for (int32_t i = 0; i < numAnimatedObjects; i++, aobj++)
|
||||
{
|
||||
if (aobj->x != x)
|
||||
continue;
|
||||
if (aobj->y != y)
|
||||
continue;
|
||||
if (aobj->baseZ != z)
|
||||
continue;
|
||||
if (aobj->type != type)
|
||||
continue;
|
||||
// Animation already exists
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new animation
|
||||
gNumMapAnimations++;
|
||||
aobj->type = type;
|
||||
aobj->x = x;
|
||||
aobj->y = y;
|
||||
aobj->baseZ = z;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,22 +69,17 @@ void map_animation_create(int32_t type, int32_t x, int32_t y, int32_t z)
|
||||
*/
|
||||
void map_animation_invalidate_all()
|
||||
{
|
||||
rct_map_animation* aobj = &gAnimatedObjects[0];
|
||||
int32_t numAnimatedObjects = gNumMapAnimations;
|
||||
while (numAnimatedObjects > 0)
|
||||
auto it = _mapAnimations.begin();
|
||||
while (it != _mapAnimations.end())
|
||||
{
|
||||
if (map_animation_invalidate(aobj))
|
||||
if (InvalidateMapAnimation(*it))
|
||||
{
|
||||
// Remove animated object
|
||||
gNumMapAnimations--;
|
||||
numAnimatedObjects--;
|
||||
if (numAnimatedObjects > 0)
|
||||
memmove(aobj, aobj + 1, numAnimatedObjects * sizeof(rct_map_animation));
|
||||
// Map animation has finished, remove it
|
||||
it = _mapAnimations.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
numAnimatedObjects--;
|
||||
aobj++;
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -598,9 +582,117 @@ static constexpr const map_animation_invalidate_event_handler _animatedObjectEve
|
||||
/**
|
||||
* @returns true if the animation should be removed.
|
||||
*/
|
||||
static bool map_animation_invalidate(rct_map_animation* obj)
|
||||
static bool InvalidateMapAnimation(const MapAnimation& a)
|
||||
{
|
||||
assert(obj->type < MAP_ANIMATION_TYPE_COUNT);
|
||||
|
||||
return _animatedObjectEventHandlers[obj->type](obj->x, obj->y, obj->baseZ);
|
||||
if (a.type < std::size(_animatedObjectEventHandlers))
|
||||
{
|
||||
return _animatedObjectEventHandlers[a.type](a.location.x, a.location.y, a.location.z);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<MapAnimation>& GetMapAnimations()
|
||||
{
|
||||
return _mapAnimations;
|
||||
}
|
||||
|
||||
static void ClearMapAnimations()
|
||||
{
|
||||
_mapAnimations.clear();
|
||||
}
|
||||
|
||||
void AutoCreateMapAnimations()
|
||||
{
|
||||
ClearMapAnimations();
|
||||
|
||||
tile_element_iterator it;
|
||||
tile_element_iterator_begin(&it);
|
||||
while (tile_element_iterator_next(&it))
|
||||
{
|
||||
auto el = it.element;
|
||||
auto loc = CoordsXYZ{ it.x * 32, it.y * 32, el->base_height };
|
||||
switch (el->GetType())
|
||||
{
|
||||
case TILE_ELEMENT_TYPE_BANNER:
|
||||
map_animation_create(MAP_ANIMATION_TYPE_BANNER, loc.x, loc.y, loc.z);
|
||||
break;
|
||||
case TILE_ELEMENT_TYPE_WALL:
|
||||
{
|
||||
auto wallEl = el->AsWall();
|
||||
auto entry = wallEl->GetEntry();
|
||||
if (entry != nullptr
|
||||
&& ((entry->wall.flags2 & WALL_SCENERY_2_ANIMATED) || entry->wall.scrolling_mode != SCROLLING_MODE_NONE))
|
||||
{
|
||||
map_animation_create(MAP_ANIMATION_TYPE_WALL, loc.x, loc.y, loc.z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
|
||||
{
|
||||
auto sceneryEl = el->AsSmallScenery();
|
||||
auto entry = sceneryEl->GetEntry();
|
||||
if (entry != nullptr && scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_ANIMATED))
|
||||
{
|
||||
map_animation_create(MAP_ANIMATION_TYPE_SMALL_SCENERY, loc.x, loc.y, loc.z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
|
||||
{
|
||||
auto sceneryEl = el->AsLargeScenery();
|
||||
auto entry = sceneryEl->GetEntry();
|
||||
if (entry != nullptr && (entry->large_scenery.flags & LARGE_SCENERY_FLAG_ANIMATED))
|
||||
{
|
||||
map_animation_create(MAP_ANIMATION_TYPE_LARGE_SCENERY, loc.x, loc.y, loc.z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TILE_ELEMENT_TYPE_PATH:
|
||||
{
|
||||
auto path = el->AsPath();
|
||||
if (path->HasQueueBanner())
|
||||
{
|
||||
map_animation_create(MAP_ANIMATION_TYPE_QUEUE_BANNER, loc.x, loc.y, loc.z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TILE_ELEMENT_TYPE_ENTRANCE:
|
||||
{
|
||||
auto entrance = el->AsEntrance();
|
||||
switch (entrance->GetEntranceType())
|
||||
{
|
||||
case ENTRANCE_TYPE_PARK_ENTRANCE:
|
||||
if (entrance->GetSequenceIndex() == 0)
|
||||
{
|
||||
map_animation_create(MAP_ANIMATION_TYPE_PARK_ENTRANCE, loc.x, loc.y, loc.z);
|
||||
}
|
||||
break;
|
||||
case ENTRANCE_TYPE_RIDE_ENTRANCE:
|
||||
map_animation_create(MAP_ANIMATION_TYPE_RIDE_ENTRANCE, loc.x, loc.y, loc.z);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TILE_ELEMENT_TYPE_TRACK:
|
||||
{
|
||||
auto track = el->AsTrack();
|
||||
switch (track->GetTrackType())
|
||||
{
|
||||
case TRACK_ELEM_WATERFALL:
|
||||
map_animation_create(MAP_ANIMATION_TYPE_TRACK_WATERFALL, loc.x, loc.y, loc.z);
|
||||
break;
|
||||
case TRACK_ELEM_RAPIDS:
|
||||
map_animation_create(MAP_ANIMATION_TYPE_TRACK_RAPIDS, loc.x, loc.y, loc.z);
|
||||
break;
|
||||
case TRACK_ELEM_WHIRLPOOL:
|
||||
map_animation_create(MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL, loc.x, loc.y, loc.z);
|
||||
break;
|
||||
case TRACK_ELEM_SPINNING_TUNNEL:
|
||||
map_animation_create(MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL, loc.x, loc.y, loc.z);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user