mirror of https://github.com/OpenRCT2/OpenRCT2.git
Remove next_in_quadrant (#13754)
* Use std::vector of quadrants * Prevent ptr invalidation issues * Remove next_in_quadrant * Make review changes * Rebuild next_in_quadrant for S6Export * Fix formatting * Constexpr where possible * Increment network version and update replays
This commit is contained in:
parent
3cc283adb2
commit
eb52391b9a
|
@ -44,8 +44,8 @@ set(TITLE_SEQUENCE_SHA1 "304d13a126c15bf2c86ff13b81a2f2cc1856ac8d")
|
||||||
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v1.0.20/objects.zip")
|
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v1.0.20/objects.zip")
|
||||||
set(OBJECTS_SHA1 "151424d24b1d49a167932b58319bedaa6ec368e9")
|
set(OBJECTS_SHA1 "151424d24b1d49a167932b58319bedaa6ec368e9")
|
||||||
|
|
||||||
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v0.0.29/replays.zip")
|
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v0.0.30/replays.zip")
|
||||||
set(REPLAYS_SHA1 "B64135F28A79758AD9FCB611625ADDB5C89FB40B")
|
set(REPLAYS_SHA1 "FD0949B81A7A267EA3A8F96CB02C460C8C21B923")
|
||||||
|
|
||||||
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
|
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
|
||||||
option(WITH_TESTS "Build tests")
|
option(WITH_TESTS "Build tests")
|
||||||
|
|
|
@ -48,8 +48,8 @@
|
||||||
<TitleSequencesSha1>304d13a126c15bf2c86ff13b81a2f2cc1856ac8d</TitleSequencesSha1>
|
<TitleSequencesSha1>304d13a126c15bf2c86ff13b81a2f2cc1856ac8d</TitleSequencesSha1>
|
||||||
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.0.20/objects.zip</ObjectsUrl>
|
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.0.20/objects.zip</ObjectsUrl>
|
||||||
<ObjectsSha1>151424d24b1d49a167932b58319bedaa6ec368e9</ObjectsSha1>
|
<ObjectsSha1>151424d24b1d49a167932b58319bedaa6ec368e9</ObjectsSha1>
|
||||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.29/replays.zip</ReplaysUrl>
|
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.30/replays.zip</ReplaysUrl>
|
||||||
<ReplaysSha1>B64135F28A79758AD9FCB611625ADDB5C89FB40B</ReplaysSha1>
|
<ReplaysSha1>FD0949B81A7A267EA3A8F96CB02C460C8C21B923</ReplaysSha1>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -200,7 +200,6 @@ struct GameStateSnapshots final : public IGameStateSnapshots
|
||||||
const SpriteBase& spriteBase, const SpriteBase& spriteCmp, GameStateSpriteChange_t& changeData) const
|
const SpriteBase& spriteBase, const SpriteBase& spriteCmp, GameStateSpriteChange_t& changeData) const
|
||||||
{
|
{
|
||||||
COMPARE_FIELD(SpriteBase, sprite_identifier);
|
COMPARE_FIELD(SpriteBase, sprite_identifier);
|
||||||
COMPARE_FIELD(SpriteBase, next_in_quadrant);
|
|
||||||
COMPARE_FIELD(SpriteBase, linked_list_index);
|
COMPARE_FIELD(SpriteBase, linked_list_index);
|
||||||
COMPARE_FIELD(SpriteBase, sprite_index);
|
COMPARE_FIELD(SpriteBase, sprite_index);
|
||||||
COMPARE_FIELD(SpriteBase, flags);
|
COMPARE_FIELD(SpriteBase, flags);
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
// This string specifies which version of network stream current build uses.
|
// This string specifies which version of network stream current build uses.
|
||||||
// It is used for making sure only compatible builds get connected, even within
|
// It is used for making sure only compatible builds get connected, even within
|
||||||
// single OpenRCT2 version.
|
// single OpenRCT2 version.
|
||||||
#define NETWORK_STREAM_VERSION "14"
|
#define NETWORK_STREAM_VERSION "15"
|
||||||
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
|
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
|
||||||
|
|
||||||
static Peep* _pickup_peep = nullptr;
|
static Peep* _pickup_peep = nullptr;
|
||||||
|
|
|
@ -981,6 +981,27 @@ void S6Exporter::RebuildEntityLinks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rebuild next_in_quadrant linked list entity indexs
|
||||||
|
for (auto x = 0; x < 255; ++x)
|
||||||
|
{
|
||||||
|
for (auto y = 0; y < 255; ++y)
|
||||||
|
{
|
||||||
|
uint16_t previous = SPRITE_INDEX_NULL;
|
||||||
|
for (auto* entity : EntityTileList(TileCoordsXY{ x, y }.ToCoordsXY()))
|
||||||
|
{
|
||||||
|
if (previous != SPRITE_INDEX_NULL)
|
||||||
|
{
|
||||||
|
_s6.sprites[previous].unknown.next_in_quadrant = entity->sprite_index;
|
||||||
|
}
|
||||||
|
previous = entity->sprite_index;
|
||||||
|
}
|
||||||
|
if (previous != SPRITE_INDEX_NULL)
|
||||||
|
{
|
||||||
|
_s6.sprites[previous].unknown.next_in_quadrant = SPRITE_INDEX_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void S6Exporter::ExportSprite(RCT2Sprite* dst, const rct_sprite* src)
|
void S6Exporter::ExportSprite(RCT2Sprite* dst, const rct_sprite* src)
|
||||||
|
@ -1046,8 +1067,8 @@ constexpr RCT12EntityLinkListOffset GetRCT2LinkListOffset(const SpriteBase* src)
|
||||||
void S6Exporter::ExportSpriteCommonProperties(RCT12SpriteBase* dst, const SpriteBase* src)
|
void S6Exporter::ExportSpriteCommonProperties(RCT12SpriteBase* dst, const SpriteBase* src)
|
||||||
{
|
{
|
||||||
dst->sprite_identifier = src->sprite_identifier;
|
dst->sprite_identifier = src->sprite_identifier;
|
||||||
dst->next_in_quadrant = src->next_in_quadrant;
|
|
||||||
dst->linked_list_type_offset = GetRCT2LinkListOffset(src);
|
dst->linked_list_type_offset = GetRCT2LinkListOffset(src);
|
||||||
|
dst->next_in_quadrant = SPRITE_INDEX_NULL;
|
||||||
dst->sprite_height_negative = src->sprite_height_negative;
|
dst->sprite_height_negative = src->sprite_height_negative;
|
||||||
dst->sprite_index = src->sprite_index;
|
dst->sprite_index = src->sprite_index;
|
||||||
dst->flags = src->flags;
|
dst->flags = src->flags;
|
||||||
|
|
|
@ -1656,7 +1656,6 @@ public:
|
||||||
void ImportSpriteCommonProperties(SpriteBase* dst, const RCT12SpriteBase* src)
|
void ImportSpriteCommonProperties(SpriteBase* dst, const RCT12SpriteBase* src)
|
||||||
{
|
{
|
||||||
dst->sprite_identifier = src->sprite_identifier;
|
dst->sprite_identifier = src->sprite_identifier;
|
||||||
dst->next_in_quadrant = src->next_in_quadrant;
|
|
||||||
dst->linked_list_index = static_cast<EntityListId>(EnumValue(src->linked_list_type_offset) >> 1);
|
dst->linked_list_index = static_cast<EntityListId>(EnumValue(src->linked_list_type_offset) >> 1);
|
||||||
dst->sprite_height_negative = src->sprite_height_negative;
|
dst->sprite_height_negative = src->sprite_height_negative;
|
||||||
dst->sprite_index = src->sprite_index;
|
dst->sprite_index = src->sprite_index;
|
||||||
|
|
|
@ -397,16 +397,20 @@ CoordsXY footpath_bridge_get_info_from_pos(const ScreenCoordsXY& screenCoords, i
|
||||||
*/
|
*/
|
||||||
void footpath_remove_litter(const CoordsXYZ& footpathPos)
|
void footpath_remove_litter(const CoordsXYZ& footpathPos)
|
||||||
{
|
{
|
||||||
auto quad = EntityTileList<Litter>(footpathPos);
|
std::vector<Litter*> removals;
|
||||||
for (auto litter : quad)
|
for (auto litter : EntityTileList<Litter>(footpathPos))
|
||||||
{
|
{
|
||||||
int32_t distanceZ = abs(litter->z - footpathPos.z);
|
int32_t distanceZ = abs(litter->z - footpathPos.z);
|
||||||
if (distanceZ <= 32)
|
if (distanceZ <= 32)
|
||||||
{
|
{
|
||||||
litter->Invalidate();
|
removals.push_back(litter);
|
||||||
sprite_remove(litter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto* litter : removals)
|
||||||
|
{
|
||||||
|
litter->Invalidate();
|
||||||
|
sprite_remove(litter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,13 +24,14 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
static rct_sprite _spriteList[MAX_SPRITES];
|
static rct_sprite _spriteList[MAX_SPRITES];
|
||||||
static std::array<std::list<uint16_t>, EnumValue(EntityListId::Count)> gEntityLists;
|
static std::array<std::list<uint16_t>, EnumValue(EntityListId::Count)> gEntityLists;
|
||||||
|
|
||||||
static bool _spriteFlashingList[MAX_SPRITES];
|
static bool _spriteFlashingList[MAX_SPRITES];
|
||||||
|
|
||||||
uint16_t gSpriteSpatialIndex[SPATIAL_INDEX_SIZE];
|
static std::array<std::vector<uint16_t>, SPATIAL_INDEX_SIZE> gSpriteSpatialIndex;
|
||||||
|
|
||||||
const rct_string_id litterNames[12] = { STR_LITTER_VOMIT,
|
const rct_string_id litterNames[12] = { STR_LITTER_VOMIT,
|
||||||
STR_LITTER_VOMIT,
|
STR_LITTER_VOMIT,
|
||||||
|
@ -45,7 +46,25 @@ const rct_string_id litterNames[12] = { STR_LITTER_VOMIT,
|
||||||
STR_SHOP_ITEM_SINGULAR_EMPTY_JUICE_CUP,
|
STR_SHOP_ITEM_SINGULAR_EMPTY_JUICE_CUP,
|
||||||
STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_BLUE };
|
STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_BLUE };
|
||||||
|
|
||||||
static size_t GetSpatialIndexOffset(int32_t x, int32_t y);
|
constexpr size_t GetSpatialIndexOffset(int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
size_t index = SPATIAL_INDEX_LOCATION_NULL;
|
||||||
|
if (x != LOCATION_NULL)
|
||||||
|
{
|
||||||
|
x = std::clamp(x, 0, 0xFFFF);
|
||||||
|
y = std::clamp(y, 0, 0xFFFF);
|
||||||
|
|
||||||
|
int16_t flooredX = floor2(x, 32);
|
||||||
|
uint8_t tileY = y >> 5;
|
||||||
|
index = (flooredX << 3) | tileY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= sizeof(gSpriteSpatialIndex))
|
||||||
|
{
|
||||||
|
return SPATIAL_INDEX_LOCATION_NULL;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
// Required for GetEntity to return a default
|
// Required for GetEntity to return a default
|
||||||
template<> bool SpriteBase::Is<SpriteBase>() const
|
template<> bool SpriteBase::Is<SpriteBase>() const
|
||||||
|
@ -116,7 +135,7 @@ SpriteBase* get_sprite(size_t spriteIndex)
|
||||||
return try_get_sprite(spriteIndex);
|
return try_get_sprite(spriteIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t sprite_get_first_in_quadrant(const CoordsXY& spritePos)
|
const std::vector<uint16_t>& GetEntityTileList(const CoordsXY& spritePos)
|
||||||
{
|
{
|
||||||
return gSpriteSpatialIndex[GetSpatialIndexOffset(spritePos.x, spritePos.y)];
|
return gSpriteSpatialIndex[GetSpatialIndexOffset(spritePos.x, spritePos.y)];
|
||||||
}
|
}
|
||||||
|
@ -242,6 +261,8 @@ void reset_sprite_list()
|
||||||
reset_sprite_spatial_index();
|
reset_sprite_spatial_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SpriteSpatialInsert(SpriteBase* sprite, const CoordsXY& newLoc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* rct2: 0x0069EBE4
|
* rct2: 0x0069EBE4
|
||||||
|
@ -250,40 +271,20 @@ void reset_sprite_list()
|
||||||
*/
|
*/
|
||||||
void reset_sprite_spatial_index()
|
void reset_sprite_spatial_index()
|
||||||
{
|
{
|
||||||
std::fill_n(gSpriteSpatialIndex, std::size(gSpriteSpatialIndex), SPRITE_INDEX_NULL);
|
for (auto& vec : gSpriteSpatialIndex)
|
||||||
|
{
|
||||||
|
vec.clear();
|
||||||
|
}
|
||||||
for (size_t i = 0; i < MAX_SPRITES; i++)
|
for (size_t i = 0; i < MAX_SPRITES; i++)
|
||||||
{
|
{
|
||||||
auto* spr = GetEntity(i);
|
auto* spr = GetEntity(i);
|
||||||
if (spr != nullptr && spr->sprite_identifier != SpriteIdentifier::Null)
|
if (spr != nullptr && spr->sprite_identifier != SpriteIdentifier::Null)
|
||||||
{
|
{
|
||||||
size_t index = GetSpatialIndexOffset(spr->x, spr->y);
|
SpriteSpatialInsert(spr, { spr->x, spr->y });
|
||||||
uint32_t nextSpriteId = gSpriteSpatialIndex[index];
|
|
||||||
gSpriteSpatialIndex[index] = spr->sprite_index;
|
|
||||||
spr->next_in_quadrant = nextSpriteId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t GetSpatialIndexOffset(int32_t x, int32_t y)
|
|
||||||
{
|
|
||||||
size_t index = SPATIAL_INDEX_LOCATION_NULL;
|
|
||||||
if (x != LOCATION_NULL)
|
|
||||||
{
|
|
||||||
x = std::clamp(x, 0, 0xFFFF);
|
|
||||||
y = std::clamp(y, 0, 0xFFFF);
|
|
||||||
|
|
||||||
int16_t flooredX = floor2(x, 32);
|
|
||||||
uint8_t tileY = y >> 5;
|
|
||||||
index = (flooredX << 3) | tileY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index >= sizeof(gSpriteSpatialIndex))
|
|
||||||
{
|
|
||||||
return SPATIAL_INDEX_LOCATION_NULL;
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef DISABLE_NETWORK
|
#ifndef DISABLE_NETWORK
|
||||||
|
|
||||||
rct_sprite_checksum sprite_checksum()
|
rct_sprite_checksum sprite_checksum()
|
||||||
|
@ -318,15 +319,6 @@ rct_sprite_checksum sprite_checksum()
|
||||||
copy.misc.sprite_left = copy.misc.sprite_right = copy.misc.sprite_top = copy.misc.sprite_bottom = 0;
|
copy.misc.sprite_left = copy.misc.sprite_right = copy.misc.sprite_top = copy.misc.sprite_bottom = 0;
|
||||||
copy.misc.sprite_width = copy.misc.sprite_height_negative = copy.misc.sprite_height_positive = 0;
|
copy.misc.sprite_width = copy.misc.sprite_height_negative = copy.misc.sprite_height_positive = 0;
|
||||||
|
|
||||||
// Next in quadrant might be a misc sprite, set first non-misc sprite in quadrant.
|
|
||||||
while (auto* nextSprite = GetEntity(copy.misc.next_in_quadrant))
|
|
||||||
{
|
|
||||||
if (nextSprite->sprite_identifier == SpriteIdentifier::Misc)
|
|
||||||
copy.misc.next_in_quadrant = nextSprite->next_in_quadrant;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy.misc.Is<Peep>())
|
if (copy.misc.Is<Peep>())
|
||||||
{
|
{
|
||||||
// Name is pointer and will not be the same across clients
|
// Name is pointer and will not be the same across clients
|
||||||
|
@ -365,14 +357,12 @@ static void sprite_reset(SpriteBase* sprite)
|
||||||
{
|
{
|
||||||
// Need to retain how the sprite is linked in lists
|
// Need to retain how the sprite is linked in lists
|
||||||
auto llto = sprite->linked_list_index;
|
auto llto = sprite->linked_list_index;
|
||||||
uint16_t next_in_quadrant = sprite->next_in_quadrant;
|
|
||||||
uint16_t sprite_index = sprite->sprite_index;
|
uint16_t sprite_index = sprite->sprite_index;
|
||||||
_spriteFlashingList[sprite_index] = false;
|
_spriteFlashingList[sprite_index] = false;
|
||||||
|
|
||||||
std::memset(sprite, 0, sizeof(rct_sprite));
|
std::memset(sprite, 0, sizeof(rct_sprite));
|
||||||
|
|
||||||
sprite->linked_list_index = llto;
|
sprite->linked_list_index = llto;
|
||||||
sprite->next_in_quadrant = next_in_quadrant;
|
|
||||||
sprite->sprite_index = sprite_index;
|
sprite->sprite_index = sprite_index;
|
||||||
sprite->sprite_identifier = SpriteIdentifier::Null;
|
sprite->sprite_identifier = SpriteIdentifier::Null;
|
||||||
}
|
}
|
||||||
|
@ -388,19 +378,10 @@ void sprite_clear_all_unused()
|
||||||
sprite_reset(sprite);
|
sprite_reset(sprite);
|
||||||
sprite->linked_list_index = EntityListId::Free;
|
sprite->linked_list_index = EntityListId::Free;
|
||||||
|
|
||||||
// sprite->next_in_quadrant will only end up as zero owing to corruption
|
|
||||||
// most likely due to previous builds not preserving it when resetting sprites
|
|
||||||
// We reset it to SPRITE_INDEX_NULL to prevent cycles in the sprite lists
|
|
||||||
if (sprite->next_in_quadrant == 0)
|
|
||||||
{
|
|
||||||
sprite->next_in_quadrant = SPRITE_INDEX_NULL;
|
|
||||||
}
|
|
||||||
_spriteFlashingList[sprite->sprite_index] = false;
|
_spriteFlashingList[sprite->sprite_index] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SpriteSpatialInsert(SpriteBase* sprite, const CoordsXY& newLoc);
|
|
||||||
|
|
||||||
static constexpr uint16_t MAX_MISC_SPRITES = 300;
|
static constexpr uint16_t MAX_MISC_SPRITES = 300;
|
||||||
static void AddToEntityList(const EntityListId linkedListIndex, SpriteBase* entity)
|
static void AddToEntityList(const EntityListId linkedListIndex, SpriteBase* entity)
|
||||||
{
|
{
|
||||||
|
@ -605,41 +586,25 @@ void sprite_misc_update_all()
|
||||||
static void SpriteSpatialInsert(SpriteBase* sprite, const CoordsXY& newLoc)
|
static void SpriteSpatialInsert(SpriteBase* sprite, const CoordsXY& newLoc)
|
||||||
{
|
{
|
||||||
size_t newIndex = GetSpatialIndexOffset(newLoc.x, newLoc.y);
|
size_t newIndex = GetSpatialIndexOffset(newLoc.x, newLoc.y);
|
||||||
|
auto& spatialVector = gSpriteSpatialIndex[newIndex];
|
||||||
auto* next = &gSpriteSpatialIndex[newIndex];
|
auto index = std::lower_bound(std::begin(spatialVector), std::end(spatialVector), sprite->sprite_index);
|
||||||
while (sprite->sprite_index < *next && *next != SPRITE_INDEX_NULL)
|
spatialVector.insert(index, sprite->sprite_index);
|
||||||
{
|
|
||||||
auto sprite2 = GetEntity(*next);
|
|
||||||
next = &sprite2->next_in_quadrant;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprite->next_in_quadrant = *next;
|
|
||||||
*next = sprite->sprite_index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SpriteSpatialRemove(SpriteBase* sprite)
|
static void SpriteSpatialRemove(SpriteBase* sprite)
|
||||||
{
|
{
|
||||||
size_t currentIndex = GetSpatialIndexOffset(sprite->x, sprite->y);
|
size_t currentIndex = GetSpatialIndexOffset(sprite->x, sprite->y);
|
||||||
auto* index = &gSpriteSpatialIndex[currentIndex];
|
auto& spatialVector = gSpriteSpatialIndex[currentIndex];
|
||||||
|
auto index = std::lower_bound(std::begin(spatialVector), std::end(spatialVector), sprite->sprite_index);
|
||||||
// This indicates that the spatial index data is incorrect.
|
if (index != std::end(spatialVector) && *index == sprite->sprite_index)
|
||||||
if (*index == SPRITE_INDEX_NULL)
|
{
|
||||||
|
spatialVector.erase(index, index + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
log_warning("Bad sprite spatial index. Rebuilding the spatial index...");
|
log_warning("Bad sprite spatial index. Rebuilding the spatial index...");
|
||||||
reset_sprite_spatial_index();
|
reset_sprite_spatial_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* sprite2 = GetEntity(*index);
|
|
||||||
while (sprite != sprite2)
|
|
||||||
{
|
|
||||||
index = &sprite2->next_in_quadrant;
|
|
||||||
if (*index == SPRITE_INDEX_NULL)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sprite2 = GetEntity(*index);
|
|
||||||
}
|
|
||||||
*index = sprite->next_in_quadrant;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SpriteSpatialMove(SpriteBase* sprite, const CoordsXY& newLoc)
|
static void SpriteSpatialMove(SpriteBase* sprite, const CoordsXY& newLoc)
|
||||||
|
@ -807,17 +772,22 @@ void litter_create(const CoordsXYZD& litterPos, LitterType type)
|
||||||
*/
|
*/
|
||||||
void litter_remove_at(const CoordsXYZ& litterPos)
|
void litter_remove_at(const CoordsXYZ& litterPos)
|
||||||
{
|
{
|
||||||
|
std::vector<Litter*> removals;
|
||||||
for (auto litter : EntityTileList<Litter>(litterPos))
|
for (auto litter : EntityTileList<Litter>(litterPos))
|
||||||
{
|
{
|
||||||
if (abs(litter->z - litterPos.z) <= 16)
|
if (abs(litter->z - litterPos.z) <= 16)
|
||||||
{
|
{
|
||||||
if (abs(litter->x - litterPos.x) <= 8 && abs(litter->y - litterPos.y) <= 8)
|
if (abs(litter->x - litterPos.x) <= 8 && abs(litter->y - litterPos.y) <= 8)
|
||||||
{
|
{
|
||||||
litter->Invalidate();
|
removals.push_back(litter);
|
||||||
sprite_remove(litter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto* litter : removals)
|
||||||
|
{
|
||||||
|
litter->Invalidate();
|
||||||
|
sprite_remove(litter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -231,7 +231,6 @@ uint16_t GetEntityListCount(EntityListId list);
|
||||||
|
|
||||||
constexpr const uint32_t SPATIAL_INDEX_SIZE = (MAXIMUM_MAP_SIZE_TECHNICAL * MAXIMUM_MAP_SIZE_TECHNICAL) + 1;
|
constexpr const uint32_t SPATIAL_INDEX_SIZE = (MAXIMUM_MAP_SIZE_TECHNICAL * MAXIMUM_MAP_SIZE_TECHNICAL) + 1;
|
||||||
constexpr const uint32_t SPATIAL_INDEX_LOCATION_NULL = SPATIAL_INDEX_SIZE - 1;
|
constexpr const uint32_t SPATIAL_INDEX_LOCATION_NULL = SPATIAL_INDEX_SIZE - 1;
|
||||||
extern uint16_t gSpriteSpatialIndex[SPATIAL_INDEX_SIZE];
|
|
||||||
|
|
||||||
extern const rct_string_id litterNames[12];
|
extern const rct_string_id litterNames[12];
|
||||||
|
|
||||||
|
@ -249,7 +248,7 @@ void litter_remove_at(const CoordsXYZ& litterPos);
|
||||||
uint16_t remove_floating_sprites();
|
uint16_t remove_floating_sprites();
|
||||||
void sprite_misc_explosion_cloud_create(const CoordsXYZ& cloudPos);
|
void sprite_misc_explosion_cloud_create(const CoordsXYZ& cloudPos);
|
||||||
void sprite_misc_explosion_flare_create(const CoordsXYZ& flarePos);
|
void sprite_misc_explosion_flare_create(const CoordsXYZ& flarePos);
|
||||||
uint16_t sprite_get_first_in_quadrant(const CoordsXY& spritePos);
|
const std::vector<uint16_t>& GetEntityTileList(const CoordsXY& spritePos);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// Balloon
|
// Balloon
|
||||||
|
@ -333,25 +332,75 @@ public:
|
||||||
using iterator_category = std::forward_iterator_tag;
|
using iterator_category = std::forward_iterator_tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T> class EntityTileIterator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::vector<uint16_t>::const_iterator iter;
|
||||||
|
std::vector<uint16_t>::const_iterator end;
|
||||||
|
T* Entity = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EntityTileIterator(std::vector<uint16_t>::const_iterator _iter, std::vector<uint16_t>::const_iterator _end)
|
||||||
|
: iter(_iter)
|
||||||
|
, end(_end)
|
||||||
|
{
|
||||||
|
++(*this);
|
||||||
|
}
|
||||||
|
EntityTileIterator& operator++()
|
||||||
|
{
|
||||||
|
Entity = nullptr;
|
||||||
|
|
||||||
|
while (iter != end && Entity == nullptr)
|
||||||
|
{
|
||||||
|
Entity = GetEntity<T>(*iter++);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityTileIterator operator++(int)
|
||||||
|
{
|
||||||
|
EntityTileIterator retval = *this;
|
||||||
|
++(*this);
|
||||||
|
return *iter;
|
||||||
|
}
|
||||||
|
bool operator==(EntityTileIterator other) const
|
||||||
|
{
|
||||||
|
return Entity == other.Entity;
|
||||||
|
}
|
||||||
|
bool operator!=(EntityTileIterator other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
T* operator*()
|
||||||
|
{
|
||||||
|
return Entity;
|
||||||
|
}
|
||||||
|
// iterator traits
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using value_type = T;
|
||||||
|
using pointer = const T*;
|
||||||
|
using reference = const T&;
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T = SpriteBase> class EntityTileList
|
template<typename T = SpriteBase> class EntityTileList
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
uint16_t FirstEntity = SPRITE_INDEX_NULL;
|
const std::vector<uint16_t>& vec;
|
||||||
using EntityTileIterator = EntityIterator<T, &SpriteBase::next_in_quadrant>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EntityTileList(const CoordsXY& loc)
|
EntityTileList(const CoordsXY& loc)
|
||||||
: FirstEntity(sprite_get_first_in_quadrant(loc))
|
: vec(GetEntityTileList(loc))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityTileIterator begin()
|
EntityTileIterator<T> begin()
|
||||||
{
|
{
|
||||||
return EntityTileIterator(FirstEntity);
|
return EntityTileIterator<T>(std::begin(vec), std::end(vec));
|
||||||
}
|
}
|
||||||
EntityTileIterator end()
|
EntityTileIterator<T> end()
|
||||||
{
|
{
|
||||||
return EntityTileIterator(SPRITE_INDEX_NULL);
|
return EntityTileIterator<T>(std::end(vec), std::end(vec));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ enum class SpriteIdentifier : uint8_t;
|
||||||
struct SpriteBase
|
struct SpriteBase
|
||||||
{
|
{
|
||||||
SpriteIdentifier sprite_identifier;
|
SpriteIdentifier sprite_identifier;
|
||||||
uint16_t next_in_quadrant;
|
|
||||||
// Valid values are EntityListId::...
|
// Valid values are EntityListId::...
|
||||||
EntityListId linked_list_index;
|
EntityListId linked_list_index;
|
||||||
// Height from centre of sprite to bottom
|
// Height from centre of sprite to bottom
|
||||||
|
|
|
@ -131,7 +131,6 @@ static void AdvanceGameTicks(uint32_t ticks, std::unique_ptr<IContext>& context)
|
||||||
static void CompareSpriteDataCommon(const SpriteBase& left, const SpriteBase& right)
|
static void CompareSpriteDataCommon(const SpriteBase& left, const SpriteBase& right)
|
||||||
{
|
{
|
||||||
COMPARE_FIELD(sprite_identifier);
|
COMPARE_FIELD(sprite_identifier);
|
||||||
COMPARE_FIELD(next_in_quadrant);
|
|
||||||
COMPARE_FIELD(linked_list_index);
|
COMPARE_FIELD(linked_list_index);
|
||||||
COMPARE_FIELD(sprite_index);
|
COMPARE_FIELD(sprite_index);
|
||||||
COMPARE_FIELD(flags);
|
COMPARE_FIELD(flags);
|
||||||
|
|
Loading…
Reference in New Issue