1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-24 15:24:30 +01:00

Reorg entity import to follow export design (#14177)

* Add CreateEntityAt

* Reorg entity import to follow export design

* Move definitions just because gcc refuses to fix bugs

* Use CreateEntityAt

* Fix freeid allocation

* Streamline freeId reset and add statics
This commit is contained in:
Duncan
2021-03-26 05:48:38 +00:00
committed by GitHub
parent 0a47d2157a
commit a4a08ea8b4
4 changed files with 350 additions and 275 deletions

View File

@@ -218,7 +218,7 @@ public:
scenario_rand_seed(_s6.scenario_srand_0, _s6.scenario_srand_1);
ImportTileElements();
ImportSprites();
ImportEntities();
gInitialCash = _s6.initial_cash;
gBankLoan = _s6.current_loan;
@@ -1321,153 +1321,19 @@ public:
}
}
void ImportSprites()
void ImportEntities()
{
for (int32_t i = 0; i < RCT2_MAX_SPRITES; i++)
{
auto src = &_s6.sprites[i];
auto dst = GetEntity(i);
ImportSprite(reinterpret_cast<rct_sprite*>(dst), src);
}
RebuildEntityLists();
}
void ImportSprite(rct_sprite* dst, const RCT2Sprite* src)
{
std::memset(&dst->pad_00, 0, sizeof(rct_sprite));
switch (src->unknown.sprite_identifier)
{
case RCT12SpriteIdentifier::Null:
ImportSpriteCommonProperties(reinterpret_cast<SpriteBase*>(dst), &src->unknown);
break;
case RCT12SpriteIdentifier::Vehicle:
ImportSpriteVehicle(&dst->vehicle, &src->vehicle);
break;
case RCT12SpriteIdentifier::Peep:
ImportSpritePeep(&dst->peep, &src->peep);
break;
case RCT12SpriteIdentifier::Misc:
ImportSpriteMisc(&dst->misc, &src->unknown);
break;
case RCT12SpriteIdentifier::Litter:
ImportSpriteLitter(&dst->litter, &src->litter);
break;
default:
ImportSpriteCommonProperties(reinterpret_cast<SpriteBase*>(dst), reinterpret_cast<const RCT12SpriteBase*>(src));
log_warning("Sprite identifier %d can not be imported.", src->unknown.sprite_identifier);
break;
ImportEntity(_s6.sprites[i].unknown);
}
}
void ImportSpriteVehicle(Vehicle* dst, const RCT2SpriteVehicle* src)
template<typename OpenRCT2_T> void ImportEntity(const RCT12SpriteBase& src);
void ImportEntityPeep(Peep* dst, const RCT2SpritePeep* src)
{
const auto& ride = _s6.rides[src->ride];
ImportSpriteCommonProperties(static_cast<SpriteBase*>(dst), src);
dst->SubType = Vehicle::Type(src->type);
dst->vehicle_sprite_type = src->vehicle_sprite_type;
dst->bank_rotation = src->bank_rotation;
dst->remaining_distance = src->remaining_distance;
dst->velocity = src->velocity;
dst->acceleration = src->acceleration;
dst->ride = src->ride;
dst->vehicle_type = src->vehicle_type;
dst->colours = src->colours;
dst->track_progress = src->track_progress;
dst->TrackLocation = { src->track_x, src->track_y, src->track_z };
if (src->boat_location.isNull() || static_cast<RideMode>(ride.mode) != RideMode::BoatHire
|| src->status != static_cast<uint8_t>(Vehicle::Status::TravellingBoat))
{
dst->BoatLocation.setNull();
dst->SetTrackDirection(src->GetTrackDirection());
dst->SetTrackType(src->GetTrackType());
// RotationControlToggle and Booster are saved as the same track piece ID
// Which one the vehicle is using must be determined
if (GetRideTypeDescriptor(ride.type).HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE))
{
dst->SetTrackType(RCT12FlatTrackTypeToOpenRCT2(src->GetTrackType()));
}
else if (src->GetTrackType() == TrackElemType::RotationControlToggleAlias)
{
// Merging hacks mean the track type that's appropriate for the ride type is not necessarily the track type the
// ride is on. It's possible to create unwanted behavior if a user layers spinning control track on top of
// booster track but this is unlikely since only two rides have spinning control track - by default they load as
// booster
TileElement* tileElement2 = map_get_track_element_at_of_type_seq(
dst->TrackLocation, TrackElemType::RotationControlToggle, 0);
if (tileElement2 != nullptr)
dst->SetTrackType(TrackElemType::RotationControlToggle);
}
}
else
{
dst->BoatLocation = TileCoordsXY{ src->boat_location.x, src->boat_location.y }.ToCoordsXY();
dst->SetTrackDirection(0);
dst->SetTrackType(0);
}
dst->next_vehicle_on_train = src->next_vehicle_on_train;
dst->prev_vehicle_on_ride = src->prev_vehicle_on_ride;
dst->next_vehicle_on_ride = src->next_vehicle_on_ride;
dst->var_44 = src->var_44;
dst->mass = src->mass;
dst->update_flags = src->update_flags;
dst->SwingSprite = src->SwingSprite;
dst->current_station = src->current_station;
dst->current_time = src->current_time;
dst->crash_z = src->crash_z;
Vehicle::Status statusSrc = Vehicle::Status::MovingToEndOfStation;
if (src->status <= static_cast<uint8_t>(Vehicle::Status::StoppedByBlockBrakes))
{
statusSrc = static_cast<Vehicle::Status>(src->status);
}
dst->status = statusSrc;
dst->sub_state = src->sub_state;
for (size_t i = 0; i < std::size(src->peep); i++)
{
dst->peep[i] = src->peep[i];
dst->peep_tshirt_colours[i] = src->peep_tshirt_colours[i];
}
dst->num_seats = src->num_seats;
dst->num_peeps = src->num_peeps;
dst->next_free_seat = src->next_free_seat;
dst->restraints_position = src->restraints_position;
dst->crash_x = src->crash_x;
dst->sound2_flags = src->sound2_flags;
dst->spin_sprite = src->spin_sprite;
dst->sound1_id = static_cast<OpenRCT2::Audio::SoundId>(src->sound1_id);
dst->sound1_volume = src->sound1_volume;
dst->sound2_id = static_cast<OpenRCT2::Audio::SoundId>(src->sound2_id);
dst->sound2_volume = src->sound2_volume;
dst->sound_vector_factor = src->sound_vector_factor;
dst->time_waiting = src->time_waiting;
dst->speed = src->speed;
dst->powered_acceleration = src->powered_acceleration;
dst->dodgems_collision_direction = src->dodgems_collision_direction;
dst->animation_frame = src->animation_frame;
dst->var_C8 = src->var_C8;
dst->var_CA = src->var_CA;
dst->scream_sound_id = static_cast<OpenRCT2::Audio::SoundId>(src->scream_sound_id);
dst->TrackSubposition = VehicleTrackSubposition{ src->TrackSubposition };
dst->var_CE = src->var_CE;
dst->var_CF = src->var_CF;
dst->lost_time_out = src->lost_time_out;
dst->vertical_drop_countdown = src->vertical_drop_countdown;
dst->var_D3 = src->var_D3;
dst->mini_golf_current_animation = src->mini_golf_current_animation;
dst->mini_golf_flags = src->mini_golf_flags;
dst->ride_subtype = RCTEntryIndexToOpenRCT2EntryIndex(src->ride_subtype);
dst->colours_extended = src->colours_extended;
dst->seat_rotation = src->seat_rotation;
dst->target_seat_rotation = src->target_seat_rotation;
}
void ImportSpritePeep(Peep* dst, const RCT2SpritePeep* src)
{
ImportSpriteCommonProperties(static_cast<SpriteBase*>(dst), src);
ImportEntityCommonProperties(static_cast<SpriteBase*>(dst), src);
if (is_user_string_id(src->name_string_idx))
{
dst->SetName(GetUserString(src->name_string_idx));
@@ -1578,107 +1444,6 @@ public:
dst->FavouriteRideRating = src->favourite_ride_rating;
}
void ImportSpriteMisc(MiscEntity* cdst, const RCT12SpriteBase* csrc)
{
ImportSpriteCommonProperties(cdst, csrc);
switch (RCT12MiscEntityType(csrc->type))
{
case RCT12MiscEntityType::SteamParticle:
{
auto src = static_cast<const RCT12SpriteSteamParticle*>(csrc);
auto dst = static_cast<SteamParticle*>(cdst);
dst->time_to_move = src->time_to_move;
dst->frame = src->frame;
break;
}
case RCT12MiscEntityType::MoneyEffect:
{
auto src = static_cast<const RCT12SpriteMoneyEffect*>(csrc);
auto dst = static_cast<MoneyEffect*>(cdst);
dst->MoveDelay = src->move_delay;
dst->NumMovements = src->num_movements;
dst->Vertical = src->vertical;
dst->Value = src->value;
dst->OffsetX = src->offset_x;
dst->Wiggle = src->wiggle;
break;
}
case RCT12MiscEntityType::CrashedVehicleParticle:
{
auto src = static_cast<const RCT12SpriteCrashedVehicleParticle*>(csrc);
auto dst = static_cast<VehicleCrashParticle*>(cdst);
dst->frame = src->frame;
dst->time_to_live = src->time_to_live;
dst->frame = src->frame;
dst->colour[0] = src->colour[0];
dst->colour[1] = src->colour[1];
dst->crashed_sprite_base = src->crashed_sprite_base;
dst->velocity_x = src->velocity_x;
dst->velocity_y = src->velocity_y;
dst->velocity_z = src->velocity_z;
dst->acceleration_x = src->acceleration_x;
dst->acceleration_y = src->acceleration_y;
dst->acceleration_z = src->acceleration_z;
break;
}
case RCT12MiscEntityType::ExplosionCloud:
case RCT12MiscEntityType::ExplosionFlare:
case RCT12MiscEntityType::CrashSplash:
{
auto src = static_cast<const RCT12SpriteParticle*>(csrc);
auto dst = static_cast<MiscEntity*>(cdst);
dst->frame = src->frame;
break;
}
case RCT12MiscEntityType::JumpingFountainWater:
case RCT12MiscEntityType::JumpingFountainSnow:
{
auto* src = static_cast<const RCT12SpriteJumpingFountain*>(csrc);
auto* dst = static_cast<JumpingFountain*>(cdst);
dst->NumTicksAlive = src->num_ticks_alive;
dst->frame = src->frame;
dst->FountainFlags = src->fountain_flags;
dst->TargetX = src->target_x;
dst->TargetY = src->target_y;
dst->Iteration = src->iteration;
dst->FountainType = RCT12MiscEntityType(src->type) == RCT12MiscEntityType::JumpingFountainSnow
? JumpingFountainType::Snow
: JumpingFountainType::Water;
break;
}
case RCT12MiscEntityType::Balloon:
{
auto src = static_cast<const RCT12SpriteBalloon*>(csrc);
auto dst = static_cast<Balloon*>(cdst);
dst->popped = src->popped;
dst->time_to_move = src->time_to_move;
dst->frame = src->frame;
dst->colour = src->colour;
break;
}
case RCT12MiscEntityType::Duck:
{
auto src = static_cast<const RCT12SpriteDuck*>(csrc);
auto dst = static_cast<Duck*>(cdst);
dst->frame = src->frame;
dst->target_x = src->target_x;
dst->target_y = src->target_y;
dst->state = static_cast<Duck::DuckState>(src->state);
break;
}
default:
log_warning("Misc. sprite type %d can not be imported.", csrc->type);
break;
}
}
void ImportSpriteLitter(Litter* dst, const RCT12SpriteLitter* src)
{
ImportSpriteCommonProperties(dst, src);
dst->SubType = LitterType(src->type);
dst->creationTick = src->creationTick;
}
constexpr EntityType GetEntityTypeFromRCT2Sprite(const RCT12SpriteBase* src)
{
EntityType output = EntityType::Null;
@@ -1742,7 +1507,7 @@ public:
return output;
}
void ImportSpriteCommonProperties(SpriteBase* dst, const RCT12SpriteBase* src)
void ImportEntityCommonProperties(SpriteBase* dst, const RCT12SpriteBase* src)
{
dst->Type = GetEntityTypeFromRCT2Sprite(src);
dst->sprite_height_negative = src->sprite_height_negative;
@@ -1760,6 +1525,8 @@ public:
dst->sprite_direction = src->sprite_direction;
}
void ImportEntity(const RCT12SpriteBase& src);
std::string GetUserString(rct_string_id stringId)
{
const auto originalString = _s6.custom_strings[(stringId - USER_STRING_START) % 1024];
@@ -1793,6 +1560,288 @@ public:
}
};
template<> void S6Importer::ImportEntity<Vehicle>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<Vehicle>(baseSrc.sprite_index);
auto src = static_cast<const RCT2SpriteVehicle*>(&baseSrc);
const auto& ride = _s6.rides[src->ride];
ImportEntityCommonProperties(dst, src);
dst->SubType = Vehicle::Type(src->type);
dst->vehicle_sprite_type = src->vehicle_sprite_type;
dst->bank_rotation = src->bank_rotation;
dst->remaining_distance = src->remaining_distance;
dst->velocity = src->velocity;
dst->acceleration = src->acceleration;
dst->ride = src->ride;
dst->vehicle_type = src->vehicle_type;
dst->colours = src->colours;
dst->track_progress = src->track_progress;
dst->TrackLocation = { src->track_x, src->track_y, src->track_z };
if (src->boat_location.isNull() || static_cast<RideMode>(ride.mode) != RideMode::BoatHire
|| src->status != static_cast<uint8_t>(Vehicle::Status::TravellingBoat))
{
dst->BoatLocation.setNull();
dst->SetTrackDirection(src->GetTrackDirection());
dst->SetTrackType(src->GetTrackType());
// RotationControlToggle and Booster are saved as the same track piece ID
// Which one the vehicle is using must be determined
if (GetRideTypeDescriptor(ride.type).HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE))
{
dst->SetTrackType(RCT12FlatTrackTypeToOpenRCT2(src->GetTrackType()));
}
else if (src->GetTrackType() == TrackElemType::RotationControlToggleAlias)
{
// Merging hacks mean the track type that's appropriate for the ride type is not necessarily the track type the
// ride is on. It's possible to create unwanted behavior if a user layers spinning control track on top of
// booster track but this is unlikely since only two rides have spinning control track - by default they load as
// booster
TileElement* tileElement2 = map_get_track_element_at_of_type_seq(
dst->TrackLocation, TrackElemType::RotationControlToggle, 0);
if (tileElement2 != nullptr)
dst->SetTrackType(TrackElemType::RotationControlToggle);
}
}
else
{
dst->BoatLocation = TileCoordsXY{ src->boat_location.x, src->boat_location.y }.ToCoordsXY();
dst->SetTrackDirection(0);
dst->SetTrackType(0);
}
dst->next_vehicle_on_train = src->next_vehicle_on_train;
dst->prev_vehicle_on_ride = src->prev_vehicle_on_ride;
dst->next_vehicle_on_ride = src->next_vehicle_on_ride;
dst->var_44 = src->var_44;
dst->mass = src->mass;
dst->update_flags = src->update_flags;
dst->SwingSprite = src->SwingSprite;
dst->current_station = src->current_station;
dst->current_time = src->current_time;
dst->crash_z = src->crash_z;
Vehicle::Status statusSrc = Vehicle::Status::MovingToEndOfStation;
if (src->status <= static_cast<uint8_t>(Vehicle::Status::StoppedByBlockBrakes))
{
statusSrc = static_cast<Vehicle::Status>(src->status);
}
dst->status = statusSrc;
dst->sub_state = src->sub_state;
for (size_t i = 0; i < std::size(src->peep); i++)
{
dst->peep[i] = src->peep[i];
dst->peep_tshirt_colours[i] = src->peep_tshirt_colours[i];
}
dst->num_seats = src->num_seats;
dst->num_peeps = src->num_peeps;
dst->next_free_seat = src->next_free_seat;
dst->restraints_position = src->restraints_position;
dst->crash_x = src->crash_x;
dst->sound2_flags = src->sound2_flags;
dst->spin_sprite = src->spin_sprite;
dst->sound1_id = static_cast<OpenRCT2::Audio::SoundId>(src->sound1_id);
dst->sound1_volume = src->sound1_volume;
dst->sound2_id = static_cast<OpenRCT2::Audio::SoundId>(src->sound2_id);
dst->sound2_volume = src->sound2_volume;
dst->sound_vector_factor = src->sound_vector_factor;
dst->time_waiting = src->time_waiting;
dst->speed = src->speed;
dst->powered_acceleration = src->powered_acceleration;
dst->dodgems_collision_direction = src->dodgems_collision_direction;
dst->animation_frame = src->animation_frame;
dst->var_C8 = src->var_C8;
dst->var_CA = src->var_CA;
dst->scream_sound_id = static_cast<OpenRCT2::Audio::SoundId>(src->scream_sound_id);
dst->TrackSubposition = VehicleTrackSubposition{ src->TrackSubposition };
dst->var_CE = src->var_CE;
dst->var_CF = src->var_CF;
dst->lost_time_out = src->lost_time_out;
dst->vertical_drop_countdown = src->vertical_drop_countdown;
dst->var_D3 = src->var_D3;
dst->mini_golf_current_animation = src->mini_golf_current_animation;
dst->mini_golf_flags = src->mini_golf_flags;
dst->ride_subtype = RCTEntryIndexToOpenRCT2EntryIndex(src->ride_subtype);
dst->colours_extended = src->colours_extended;
dst->seat_rotation = src->seat_rotation;
dst->target_seat_rotation = src->target_seat_rotation;
}
template<> void S6Importer::ImportEntity<Guest>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<Guest>(baseSrc.sprite_index);
auto src = static_cast<const RCT2SpritePeep*>(&baseSrc);
ImportEntityPeep(dst, src);
}
template<> void S6Importer::ImportEntity<Staff>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<Staff>(baseSrc.sprite_index);
auto src = static_cast<const RCT2SpritePeep*>(&baseSrc);
ImportEntityPeep(dst, src);
}
template<> void S6Importer::ImportEntity<SteamParticle>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<SteamParticle>(baseSrc.sprite_index);
auto src = static_cast<const RCT12SpriteSteamParticle*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->time_to_move = src->time_to_move;
dst->frame = src->frame;
}
template<> void S6Importer::ImportEntity<MoneyEffect>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<MoneyEffect>(baseSrc.sprite_index);
auto src = static_cast<const RCT12SpriteMoneyEffect*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->MoveDelay = src->move_delay;
dst->NumMovements = src->num_movements;
dst->Vertical = src->vertical;
dst->Value = src->value;
dst->OffsetX = src->offset_x;
dst->Wiggle = src->wiggle;
}
template<> void S6Importer::ImportEntity<VehicleCrashParticle>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<VehicleCrashParticle>(baseSrc.sprite_index);
auto src = static_cast<const RCT12SpriteCrashedVehicleParticle*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->frame = src->frame;
dst->time_to_live = src->time_to_live;
dst->frame = src->frame;
dst->colour[0] = src->colour[0];
dst->colour[1] = src->colour[1];
dst->crashed_sprite_base = src->crashed_sprite_base;
dst->velocity_x = src->velocity_x;
dst->velocity_y = src->velocity_y;
dst->velocity_z = src->velocity_z;
dst->acceleration_x = src->acceleration_x;
dst->acceleration_y = src->acceleration_y;
dst->acceleration_z = src->acceleration_z;
}
template<> void S6Importer::ImportEntity<ExplosionCloud>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<ExplosionCloud>(baseSrc.sprite_index);
auto src = static_cast<const RCT12SpriteParticle*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->frame = src->frame;
}
template<> void S6Importer::ImportEntity<ExplosionFlare>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<ExplosionFlare>(baseSrc.sprite_index);
auto src = static_cast<const RCT12SpriteParticle*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->frame = src->frame;
}
template<> void S6Importer::ImportEntity<CrashSplashParticle>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<CrashSplashParticle>(baseSrc.sprite_index);
auto src = static_cast<const RCT12SpriteParticle*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->frame = src->frame;
}
template<> void S6Importer::ImportEntity<JumpingFountain>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<JumpingFountain>(baseSrc.sprite_index);
auto src = static_cast<const RCT12SpriteJumpingFountain*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->NumTicksAlive = src->num_ticks_alive;
dst->frame = src->frame;
dst->FountainFlags = src->fountain_flags;
dst->TargetX = src->target_x;
dst->TargetY = src->target_y;
dst->Iteration = src->iteration;
dst->FountainType = RCT12MiscEntityType(src->type) == RCT12MiscEntityType::JumpingFountainSnow ? JumpingFountainType::Snow
: JumpingFountainType::Water;
}
template<> void S6Importer::ImportEntity<Balloon>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<Balloon>(baseSrc.sprite_index);
auto src = static_cast<const RCT12SpriteBalloon*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->popped = src->popped;
dst->time_to_move = src->time_to_move;
dst->frame = src->frame;
dst->colour = src->colour;
}
template<> void S6Importer::ImportEntity<Duck>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<Duck>(baseSrc.sprite_index);
auto src = static_cast<const RCT12SpriteDuck*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->frame = src->frame;
dst->target_x = src->target_x;
dst->target_y = src->target_y;
dst->state = static_cast<Duck::DuckState>(src->state);
}
template<> void S6Importer::ImportEntity<Litter>(const RCT12SpriteBase& baseSrc)
{
auto dst = CreateEntityAt<Litter>(baseSrc.sprite_index);
auto src = static_cast<const RCT12SpriteLitter*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
dst->SubType = LitterType(src->type);
dst->creationTick = src->creationTick;
}
void S6Importer::ImportEntity(const RCT12SpriteBase& src)
{
switch (GetEntityTypeFromRCT2Sprite(&src))
{
case EntityType::Vehicle:
ImportEntity<Vehicle>(src);
break;
case EntityType::Guest:
ImportEntity<Guest>(src);
break;
case EntityType::Staff:
ImportEntity<Staff>(src);
break;
case EntityType::SteamParticle:
ImportEntity<SteamParticle>(src);
break;
case EntityType::MoneyEffect:
ImportEntity<MoneyEffect>(src);
break;
case EntityType::CrashedVehicleParticle:
ImportEntity<VehicleCrashParticle>(src);
break;
case EntityType::ExplosionCloud:
ImportEntity<ExplosionCloud>(src);
break;
case EntityType::ExplosionFlare:
ImportEntity<ExplosionFlare>(src);
break;
case EntityType::CrashSplash:
ImportEntity<CrashSplashParticle>(src);
break;
case EntityType::JumpingFountain:
ImportEntity<JumpingFountain>(src);
break;
case EntityType::Balloon:
ImportEntity<Balloon>(src);
break;
case EntityType::Duck:
ImportEntity<Duck>(src);
break;
case EntityType::Litter:
ImportEntity<Litter>(src);
break;
default:
// Null elements do not need imported
break;
}
}
std::unique_ptr<IParkImporter> ParkImporter::CreateS6(IObjectRepository& objectRepository)
{
return std::make_unique<S6Importer>(objectRepository);

View File

@@ -28,7 +28,6 @@ const std::list<uint16_t>& GetEntityList(const EntityType id);
uint16_t GetEntityListCount(EntityType list);
uint16_t GetMiscEntityCount();
uint16_t GetNumFreeEntities();
void RebuildEntityLists();
const std::vector<uint16_t>& GetEntityTileList(const CoordsXY& spritePos);
template<typename T> class EntityTileIterator

View File

@@ -24,6 +24,7 @@
#include <algorithm>
#include <cmath>
#include <iterator>
#include <numeric>
#include <vector>
static rct_sprite _spriteList[MAX_ENTITIES];
@@ -200,28 +201,21 @@ void SpriteBase::Invalidate()
viewports_invalidate(sprite_left, sprite_top, sprite_right, sprite_bottom, maxZoom);
}
void RebuildEntityLists()
static void ResetEntityLists()
{
for (auto& list : gEntityLists)
{
list.clear();
}
}
static void ResetFreeIds()
{
_freeIdList.clear();
for (auto& ent : _spriteList)
{
if (ent.misc.Type == EntityType::Null)
{
_freeIdList.push_back(ent.misc.sprite_index);
}
else
{
gEntityLists[EnumValue(ent.misc.Type)].push_back(ent.misc.sprite_index);
}
}
_freeIdList.resize(MAX_ENTITIES);
// List needs to be back to front to simplify removing
std::sort(std::begin(_freeIdList), std::end(_freeIdList), std::greater<uint16_t>());
std::iota(std::rbegin(_freeIdList), std::rend(_freeIdList), 0);
}
const std::list<uint16_t>& GetEntityList(const EntityType id)
@@ -250,7 +244,8 @@ void reset_sprite_list()
_spriteFlashingList[i] = false;
}
RebuildEntityLists();
ResetEntityLists();
ResetFreeIds();
reset_sprite_spatial_index();
}
@@ -412,6 +407,27 @@ uint16_t GetMiscEntityCount()
return count;
}
static void PrepareNewEntity(SpriteBase* base, const EntityType type)
{
// Need to reset all sprite data, as the uninitialised values
// may contain garbage and cause a desync later on.
sprite_reset(base);
base->Type = type;
AddToEntityList(base);
base->x = LOCATION_NULL;
base->y = LOCATION_NULL;
base->z = 0;
base->sprite_width = 0x10;
base->sprite_height_negative = 0x14;
base->sprite_height_positive = 0x8;
base->flags = 0;
base->sprite_left = LOCATION_NULL;
SpriteSpatialInsert(base, { LOCATION_NULL, 0 });
}
rct_sprite* create_sprite(EntityType type)
{
if (_freeIdList.size() == 0)
@@ -439,27 +455,30 @@ rct_sprite* create_sprite(EntityType type)
}
_freeIdList.pop_back();
// Need to reset all sprite data, as the uninitialised values
// may contain garbage and cause a desync later on.
sprite_reset(sprite);
sprite->Type = type;
AddToEntityList(sprite);
sprite->x = LOCATION_NULL;
sprite->y = LOCATION_NULL;
sprite->z = 0;
sprite->sprite_width = 0x10;
sprite->sprite_height_negative = 0x14;
sprite->sprite_height_positive = 0x8;
sprite->flags = 0;
sprite->sprite_left = LOCATION_NULL;
SpriteSpatialInsert(sprite, { LOCATION_NULL, 0 });
PrepareNewEntity(sprite, type);
return reinterpret_cast<rct_sprite*>(sprite);
}
SpriteBase* CreateEntityAt(const uint16_t index, const EntityType type)
{
auto id = std::lower_bound(std::rbegin(_freeIdList), std::rend(_freeIdList), index);
if (id == std::rend(_freeIdList) || *id != index)
{
return nullptr;
}
auto* entity = GetEntity(index);
if (entity == nullptr)
{
return nullptr;
}
_freeIdList.erase(std::next(id).base());
PrepareNewEntity(entity, type);
return entity;
}
/**
*
* rct2: 0x00673200

View File

@@ -194,6 +194,14 @@ template<typename T> T* CreateEntity()
{
return reinterpret_cast<T*>(create_sprite(T::cEntityType));
}
// Use only with imports that must happen at a specified index
SpriteBase* CreateEntityAt(const uint16_t index, const EntityType type);
// Use only with imports that must happen at a specified index
template<typename T> T* CreateEntityAt(const uint16_t index)
{
return static_cast<T*>(CreateEntityAt(index, T::cEntityType));
}
void reset_sprite_list();
void reset_sprite_spatial_index();
void sprite_clear_all_unused();