mirror of https://github.com/OpenRCT2/OpenRCT2.git
Refactor map animations and dynamically create on park load (#9705)
This commit is contained in:
parent
1a6e5b5548
commit
c3234b1442
|
@ -546,6 +546,7 @@ namespace OpenRCT2
|
|||
gCurrentLoadedPath = path;
|
||||
gFirstTimeSaving = true;
|
||||
game_fix_save_vars();
|
||||
AutoCreateMapAnimations();
|
||||
sprite_position_tween_reset();
|
||||
gScreenAge = 0;
|
||||
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
|
||||
|
|
|
@ -456,7 +456,7 @@ public:
|
|||
map_invalidate_tile_full(_loc.x, _loc.y);
|
||||
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_ANIMATED))
|
||||
{
|
||||
map_animation_create(2, _loc.x, _loc.y, sceneryElement->base_height);
|
||||
map_animation_create(MAP_ANIMATION_TYPE_SMALL_SCENERY, _loc.x, _loc.y, sceneryElement->base_height);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
|
@ -675,7 +675,7 @@ struct rct1_s4
|
|||
uint16_t view_y;
|
||||
uint8_t view_zoom;
|
||||
uint8_t view_rotation;
|
||||
rct_map_animation map_animations[RCT1_MAX_ANIMATED_OBJECTS];
|
||||
RCT12MapAnimation map_animations[RCT1_MAX_ANIMATED_OBJECTS];
|
||||
uint32_t num_map_animations;
|
||||
uint8_t unk_1CADBC[12];
|
||||
uint16_t scrolling_text_step;
|
||||
|
|
|
@ -189,7 +189,6 @@ public:
|
|||
ImportRideMeasurements();
|
||||
ImportSprites();
|
||||
ImportTileElements();
|
||||
ImportMapAnimations();
|
||||
ImportPeepSpawns();
|
||||
ImportFinance();
|
||||
ImportResearch();
|
||||
|
@ -1800,18 +1799,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void ImportMapAnimations()
|
||||
{
|
||||
// This is sketchy, ideally we should try to re-create them
|
||||
rct_map_animation* s4Animations = _s4.map_animations;
|
||||
for (size_t i = 0; i < RCT1_MAX_ANIMATED_OBJECTS; i++)
|
||||
{
|
||||
gAnimatedObjects[i] = s4Animations[i];
|
||||
gAnimatedObjects[i].baseZ /= 2;
|
||||
}
|
||||
gNumMapAnimations = _s4.num_map_animations;
|
||||
}
|
||||
|
||||
void ImportFinance()
|
||||
{
|
||||
gParkEntranceFee = _s4.park_entrance_fee;
|
||||
|
|
|
@ -540,6 +540,15 @@ struct RCT12Banner
|
|||
};
|
||||
assert_struct_size(RCT12Banner, 8);
|
||||
|
||||
struct RCT12MapAnimation
|
||||
{
|
||||
uint8_t baseZ;
|
||||
uint8_t type;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
};
|
||||
assert_struct_size(RCT12MapAnimation, 6);
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
bool is_user_string_id(rct_string_id stringId);
|
||||
|
|
|
@ -353,9 +353,8 @@ void S6Exporter::Export()
|
|||
_s6.saved_view_y = gSavedViewY;
|
||||
_s6.saved_view_zoom = gSavedViewZoom;
|
||||
_s6.saved_view_rotation = gSavedViewRotation;
|
||||
std::memcpy(_s6.map_animations, gAnimatedObjects, sizeof(_s6.map_animations));
|
||||
_s6.num_map_animations = gNumMapAnimations;
|
||||
// pad_0138B582
|
||||
|
||||
ExportMapAnimations();
|
||||
|
||||
_s6.ride_ratings_calc_data = gRideRatingsCalcData;
|
||||
ExportRideMeasurements();
|
||||
|
@ -1282,6 +1281,23 @@ void S6Exporter::ExportBanner(RCT12Banner& dst, const Banner& src)
|
|||
}
|
||||
}
|
||||
|
||||
void S6Exporter::ExportMapAnimations()
|
||||
{
|
||||
const auto& mapAnimations = GetMapAnimations();
|
||||
auto numAnimations = std::min(mapAnimations.size(), std::size(_s6.map_animations));
|
||||
_s6.num_map_animations = (uint16_t)numAnimations;
|
||||
for (size_t i = 0; i < numAnimations; i++)
|
||||
{
|
||||
const auto& src = mapAnimations[i];
|
||||
auto& dst = _s6.map_animations[i];
|
||||
|
||||
dst.type = src.type;
|
||||
dst.x = src.location.x;
|
||||
dst.y = src.location.y;
|
||||
dst.baseZ = src.location.z;
|
||||
}
|
||||
}
|
||||
|
||||
opt::optional<uint16_t> S6Exporter::AllocateUserString(const std::string_view& value)
|
||||
{
|
||||
auto nextId = _userStrings.size();
|
||||
|
|
|
@ -66,6 +66,7 @@ private:
|
|||
void ExportRideMeasurement(RCT12RideMeasurement& dst, const RideMeasurement& src);
|
||||
void ExportBanners();
|
||||
void ExportBanner(RCT12Banner& dst, const Banner& src);
|
||||
void ExportMapAnimations();
|
||||
|
||||
opt::optional<uint16_t> AllocateUserString(const std::string_view& value);
|
||||
void ExportUserStrings();
|
||||
|
|
|
@ -382,13 +382,6 @@ public:
|
|||
gSavedViewZoom = _s6.saved_view_zoom;
|
||||
gSavedViewRotation = _s6.saved_view_rotation;
|
||||
|
||||
for (size_t i = 0; i < RCT2_MAX_ANIMATED_OBJECTS; i++)
|
||||
{
|
||||
gAnimatedObjects[i] = _s6.map_animations[i];
|
||||
}
|
||||
gNumMapAnimations = _s6.num_map_animations;
|
||||
// pad_0138B582
|
||||
|
||||
gRideRatingsCalcData = _s6.ride_ratings_calc_data;
|
||||
ImportRideMeasurements();
|
||||
gNextGuestNumber = _s6.next_guest_index;
|
||||
|
@ -1545,6 +1538,7 @@ void load_from_sv6(const char* path)
|
|||
objectMgr.LoadObjects(result.RequiredObjects.data(), result.RequiredObjects.size());
|
||||
s6Importer->Import();
|
||||
game_fix_save_vars();
|
||||
AutoCreateMapAnimations();
|
||||
sprite_position_tween_reset();
|
||||
gScreenAge = 0;
|
||||
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
|
||||
|
@ -1583,6 +1577,7 @@ void load_from_sc6(const char* path)
|
|||
objManager.LoadObjects(result.RequiredObjects.data(), result.RequiredObjects.size());
|
||||
s6Importer->Import();
|
||||
game_fix_save_vars();
|
||||
AutoCreateMapAnimations();
|
||||
sprite_position_tween_reset();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -260,7 +260,7 @@ struct rct_s6_data
|
|||
uint16_t saved_view_y;
|
||||
uint8_t saved_view_zoom;
|
||||
uint8_t saved_view_rotation;
|
||||
rct_map_animation map_animations[RCT2_MAX_ANIMATED_OBJECTS];
|
||||
RCT12MapAnimation map_animations[RCT2_MAX_ANIMATED_OBJECTS];
|
||||
uint16_t num_map_animations;
|
||||
uint8_t pad_0138B582[2];
|
||||
rct_ride_rating_calc_data ride_ratings_calc_data;
|
||||
|
|
|
@ -333,7 +333,6 @@ BannerElement* map_get_banner_element_at(int32_t x, int32_t y, int32_t z, uint8_
|
|||
*/
|
||||
void map_init(int32_t size)
|
||||
{
|
||||
gNumMapAnimations = 0;
|
||||
gNextFreeTileElementPointerIndex = 0;
|
||||
|
||||
for (int32_t i = 0; i < MAX_TILE_TILE_ELEMENT_POINTERS; i++)
|
||||
|
@ -362,6 +361,7 @@ void map_init(int32_t size)
|
|||
gMapBaseZ = 7;
|
||||
map_update_tile_pointers();
|
||||
map_remove_out_of_range_elements();
|
||||
AutoCreateMapAnimations();
|
||||
|
||||
auto intent = Intent(INTENT_ACTION_MAP);
|
||||
context_broadcast_intent(&intent);
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
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");
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,25 +7,18 @@
|
|||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _MAP_ANIMATION_H_
|
||||
#define _MAP_ANIMATION_H_
|
||||
#pragma once
|
||||
|
||||
#include "../common.h"
|
||||
#include "Location.hpp"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
/**
|
||||
* Animated object
|
||||
* size: 0x06
|
||||
*/
|
||||
struct rct_map_animation
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
struct MapAnimation
|
||||
{
|
||||
uint8_t baseZ;
|
||||
uint8_t type;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint8_t type{};
|
||||
CoordsXYZ location{};
|
||||
};
|
||||
assert_struct_size(rct_map_animation, 6);
|
||||
#pragma pack(pop)
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -46,12 +39,7 @@ enum
|
|||
MAP_ANIMATION_TYPE_COUNT
|
||||
};
|
||||
|
||||
#define MAX_ANIMATED_OBJECTS 2000
|
||||
|
||||
extern uint16_t gNumMapAnimations;
|
||||
extern rct_map_animation gAnimatedObjects[MAX_ANIMATED_OBJECTS];
|
||||
|
||||
void map_animation_create(int32_t type, int32_t x, int32_t y, int32_t z);
|
||||
void map_animation_invalidate_all();
|
||||
|
||||
#endif
|
||||
const std::vector<MapAnimation>& GetMapAnimations();
|
||||
void AutoCreateMapAnimations();
|
||||
|
|
Loading…
Reference in New Issue