1
0
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:
Ted John
2019-08-03 21:18:33 +01:00
committed by Michael Steenbeek
parent 1a6e5b5548
commit c3234b1442
12 changed files with 192 additions and 103 deletions

View File

@@ -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;
}
}
}
}