Implement GetSprite and use it in a number of places

This will eventually replace all of the get_sprite and try_get_sprite calls

Further use of GetSprite

Use GetSprite in all remaining easy to use functions

Correct formatting

Rename GetSprite to GetEntity

Make suggested changes

Remove const to allow for building

Fix crashes due to next sprite
This commit is contained in:
duncanspumpkin 2020-06-06 11:32:37 +01:00
parent 0f12382895
commit 904e6c6987
33 changed files with 323 additions and 361 deletions

View File

@ -604,7 +604,7 @@ static void window_guest_common_invalidate(rct_window* w)
*/
void window_guest_disable_widgets(rct_window* w)
{
Peep* peep = &get_sprite(w->number)->peep;
Peep* peep = GetEntity<Peep>(w->number);
uint64_t disabled_widgets = 0;
if (peep_can_be_picked_up(peep))

View File

@ -1739,7 +1739,7 @@ rct_window* window_ride_open_vehicle(Vehicle* vehicle)
rct_window* w2 = window_find_by_number(WC_PEEP, peepSpriteIndex);
if (w2 == nullptr)
{
Peep* peep = &(get_sprite(peepSpriteIndex)->peep);
Peep* peep = GetEntity<Peep>(peepSpriteIndex);
auto intent = Intent(WC_PEEP);
intent.putExtra(INTENT_EXTRA_PEEP, peep);
context_open_intent(&intent);
@ -2551,7 +2551,7 @@ static void window_ride_main_update(rct_window* w)
if (vehicleSpriteIndex == SPRITE_INDEX_NULL)
return;
Vehicle* vehicle = &(get_sprite(vehicleSpriteIndex)->vehicle);
Vehicle* vehicle = GetEntity<Vehicle>(vehicleSpriteIndex);
if (vehicle->status != VEHICLE_STATUS_TRAVELLING && vehicle->status != VEHICLE_STATUS_TRAVELLING_CABLE_LIFT
&& vehicle->status != VEHICLE_STATUS_TRAVELLING_DODGEMS
&& vehicle->status != VEHICLE_STATUS_TRAVELLING_BOAT)
@ -2757,21 +2757,16 @@ static rct_string_id window_ride_get_status_overall_view(rct_window* w, void* ar
*/
static rct_string_id window_ride_get_status_vehicle(rct_window* w, void* arguments)
{
Vehicle* vehicle;
int32_t vehicleIndex;
uint16_t vehicleSpriteIndex;
rct_string_id stringId;
auto ride = get_ride(w->number);
if (ride == nullptr)
return 0;
vehicleIndex = w->ride.view - 1;
vehicleSpriteIndex = ride->vehicles[vehicleIndex];
auto vehicleIndex = w->ride.view - 1;
auto vehicleSpriteIndex = ride->vehicles[vehicleIndex];
if (vehicleSpriteIndex == SPRITE_INDEX_NULL)
return 0;
vehicle = &(get_sprite(vehicleSpriteIndex)->vehicle);
auto vehicle = GetEntity<Vehicle>(vehicleSpriteIndex);
if (vehicle->status != VEHICLE_STATUS_CRASHING && vehicle->status != VEHICLE_STATUS_CRASHED)
{
int32_t trackType = vehicle->GetTrackType();
@ -2787,7 +2782,7 @@ static rct_string_id window_ride_get_status_vehicle(rct_window* w, void* argumen
}
}
stringId = VehicleStatusNames[vehicle->status];
auto stringId = VehicleStatusNames[vehicle->status];
// Get speed in mph
*(reinterpret_cast<uint16_t*>(reinterpret_cast<uintptr_t>(arguments) + 2)) = (abs(vehicle->velocity) * 9) >> 18;
@ -4156,11 +4151,11 @@ static void window_ride_maintenance_dropdown(rct_window* w, rct_widgetindex widg
case BREAKDOWN_RESTRAINTS_STUCK_OPEN:
case BREAKDOWN_DOORS_STUCK_CLOSED:
case BREAKDOWN_DOORS_STUCK_OPEN:
vehicle = &(get_sprite(ride->vehicles[ride->broken_vehicle])->vehicle);
vehicle = GetEntity<Vehicle>(ride->vehicles[ride->broken_vehicle]);
vehicle->ClearUpdateFlag(VEHICLE_UPDATE_FLAG_BROKEN_CAR);
break;
case BREAKDOWN_VEHICLE_MALFUNCTION:
vehicle = &(get_sprite(ride->vehicles[ride->broken_vehicle])->vehicle);
vehicle = GetEntity<Vehicle>(ride->vehicles[ride->broken_vehicle]);
vehicle->ClearUpdateFlag(VEHICLE_UPDATE_FLAG_BROKEN_TRAIN);
break;
}
@ -4380,7 +4375,7 @@ static void window_ride_maintenance_paint(rct_window* w, rct_drawpixelinfo* dpi)
}
else
{
auto peep = (&(get_sprite(ride->mechanic)->peep))->AsStaff();
auto peep = GetEntity<Peep>(ride->mechanic)->AsStaff();
if (peep != nullptr && peep->IsMechanic())
{
peep->FormatNameTo(gCommonFormatArgs);

View File

@ -336,7 +336,8 @@ rct_window* window_staff_open(Peep* peep)
window_staff_disable_widgets(w);
window_init_scroll_widgets(w);
window_staff_viewport_init(w);
if (get_sprite(w->number)->peep.State == PEEP_STATE_PICKED)
if (GetEntity<Peep>(w->number)->State == PEEP_STATE_PICKED)
window_event_mouse_up_call(w, WIDX_CHECKBOX_3);
return w;
@ -348,7 +349,7 @@ rct_window* window_staff_open(Peep* peep)
*/
void window_staff_disable_widgets(rct_window* w)
{
Peep* peep = &get_sprite(w->number)->peep;
Peep* peep = GetEntity<Peep>(w->number);
uint64_t disabled_widgets = (1 << WIDX_TAB_4);
if (peep->StaffType == STAFF_TYPE_SECURITY)

View File

@ -124,7 +124,7 @@ static void window_staff_fire_paint(rct_window *w, rct_drawpixelinfo *dpi)
{
window_draw_widgets(w, dpi);
Peep* peep = &get_sprite(w->number)->peep;
Peep* peep = GetEntity<Peep>(w->number);
peep->FormatNameTo(gCommonFormatArgs);

View File

@ -648,7 +648,7 @@ static void window_title_command_editor_tool_down(
}
else if (spriteIdentifier == SPRITE_IDENTIFIER_LITTER)
{
Litter* litter = &(get_sprite(spriteIndex)->litter);
Litter* litter = GetEntity<Litter>(spriteIndex);
if (litter->type < std::size(litterNames))
{
validSprite = true;

View File

@ -309,7 +309,7 @@ namespace Editor
//
for (int32_t i = 0; i < MAX_SPRITES; i++)
{
auto peep = get_sprite(i)->generic.As<Peep>();
auto peep = GetEntity<Peep>(i);
if (peep != nullptr)
{
peep->SetName({});

View File

@ -614,10 +614,10 @@ void reset_all_sprite_quadrant_placements()
{
for (size_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* spr = get_sprite(i);
if (spr->generic.sprite_identifier != SPRITE_IDENTIFIER_NULL)
auto* spr = GetEntity(i);
if (spr->sprite_identifier != SPRITE_IDENTIFIER_NULL)
{
spr->generic.MoveTo({ spr->generic.x, spr->generic.y, spr->generic.z });
spr->MoveTo({ spr->x, spr->y, spr->z });
}
}
}

View File

@ -132,6 +132,7 @@ struct GameStateSnapshots final : public IGameStateSnapshots
virtual void Capture(GameStateSnapshot_t& snapshot) override final
{
// TODO refactor to not use this as a proxy for getting a pointer to the sprite array
snapshot.SerialiseSprites(get_sprite(0), MAX_SPRITES, true);
// log_info("Snapshot size: %u bytes", static_cast<uint32_t>(snapshot.storedSprites.GetLength()));

View File

@ -427,13 +427,10 @@ private:
void RemoveLitter() const
{
Litter* litter;
uint16_t spriteIndex, nextSpriteIndex;
for (spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL; spriteIndex = nextSpriteIndex)
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL;)
{
litter = &(get_sprite(spriteIndex)->litter);
nextSpriteIndex = litter->next;
auto litter = GetEntity<Litter>(spriteIndex);
spriteIndex = litter->next;
sprite_remove(litter);
}

View File

@ -1573,11 +1573,11 @@ static int32_t cc_mp_desync(InteractiveConsole& console, const arguments_t& argv
for (int i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* sprite = get_sprite(i);
if (sprite->generic.sprite_identifier == SPRITE_IDENTIFIER_NULL)
auto* sprite = GetEntity(i);
if (sprite->sprite_identifier == SPRITE_IDENTIFIER_NULL)
continue;
auto peep = sprite->generic.As<Peep>();
auto peep = sprite->As<Peep>();
if (peep != nullptr)
peeps.push_back(peep);
}

View File

@ -175,8 +175,8 @@ void viewport_create(
if (flags & VIEWPORT_FOCUS_TYPE_SPRITE)
{
w->viewport_target_sprite = sprite;
rct_sprite* centre_sprite = get_sprite(sprite);
centrePos = { centre_sprite->generic.x, centre_sprite->generic.y, centre_sprite->generic.z };
auto* centre_sprite = GetEntity(sprite);
centrePos = { centre_sprite->x, centre_sprite->y, centre_sprite->z };
}
else
{
@ -619,14 +619,14 @@ void viewport_update_sprite_follow(rct_window* window)
{
if (window->viewport_target_sprite != SPRITE_INDEX_NULL && window->viewport)
{
rct_sprite* sprite = get_sprite(window->viewport_target_sprite);
auto* sprite = GetEntity(window->viewport_target_sprite);
int32_t height = (tile_element_height({ sprite->generic.x, sprite->generic.y })) - 16;
int32_t underground = sprite->generic.z < height;
int32_t height = (tile_element_height({ sprite->x, sprite->y })) - 16;
int32_t underground = sprite->z < height;
viewport_set_underground_flag(underground, window, window->viewport);
auto centreLoc = centre_2d_coordinates({ sprite->generic.x, sprite->generic.y, sprite->generic.z }, window->viewport);
auto centreLoc = centre_2d_coordinates({ sprite->x, sprite->y, sprite->z }, window->viewport);
if (centreLoc)
{
window->savedViewPos = *centreLoc;

View File

@ -19,10 +19,10 @@ void rct_window::ScrollToViewport()
if (viewport_focus_sprite.type & VIEWPORT_FOCUS_TYPE_SPRITE)
{
rct_sprite* sprite = get_sprite(viewport_focus_sprite.sprite_id);
newX = sprite->generic.x;
newY = sprite->generic.y;
newZ = sprite->generic.z;
auto* sprite = GetEntity(viewport_focus_sprite.sprite_id);
newX = sprite->x;
newY = sprite->y;
newZ = sprite->z;
}
else
{

View File

@ -35,12 +35,6 @@ void sprite_paint_setup(paint_session* session, const uint16_t x, const uint16_t
return;
}
uint16_t sprite_idx = sprite_get_first_in_quadrant(x, y);
if (sprite_idx == SPRITE_INDEX_NULL)
{
return;
}
rct_drawpixelinfo* dpi = &session->DPI;
if (dpi->zoom_level > 2)
{
@ -49,22 +43,22 @@ void sprite_paint_setup(paint_session* session, const uint16_t x, const uint16_t
const bool highlightPathIssues = (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES);
for (const rct_sprite* spr = get_sprite(sprite_idx); sprite_idx != SPRITE_INDEX_NULL;
sprite_idx = spr->generic.next_in_quadrant)
for (uint16_t sprite_idx = sprite_get_first_in_quadrant(x, y); sprite_idx != SPRITE_INDEX_NULL;)
{
spr = get_sprite(sprite_idx);
auto spr = GetEntity(sprite_idx);
sprite_idx = spr->next_in_quadrant;
if (highlightPathIssues)
{
if (spr->generic.Is<Peep>())
const auto peep = spr->As<Peep>();
if (peep != nullptr)
{
const Peep* peep = reinterpret_cast<const Peep*>(spr);
if (!(peep->AssignedPeepType == PEEP_TYPE_STAFF && peep->StaffType == STAFF_TYPE_HANDYMAN))
{
continue;
}
}
else if (spr->generic.sprite_identifier != SPRITE_IDENTIFIER_LITTER)
else if (spr->sprite_identifier != SPRITE_IDENTIFIER_LITTER)
{
continue;
}
@ -76,15 +70,15 @@ void sprite_paint_setup(paint_session* session, const uint16_t x, const uint16_t
// height of the slope element, and consequently clipped.
if ((session->ViewFlags & VIEWPORT_FLAG_CLIP_VIEW))
{
if (spr->generic.z > (gClipHeight * COORDS_Z_STEP))
if (spr->z > (gClipHeight * COORDS_Z_STEP))
{
continue;
}
if (spr->generic.x < gClipSelectionA.x || spr->generic.x > gClipSelectionB.x)
if (spr->x < gClipSelectionA.x || spr->x > gClipSelectionB.x)
{
continue;
}
if (spr->generic.y < gClipSelectionA.y || spr->generic.y > gClipSelectionB.y)
if (spr->y < gClipSelectionA.y || spr->y > gClipSelectionB.y)
{
continue;
}
@ -92,41 +86,42 @@ void sprite_paint_setup(paint_session* session, const uint16_t x, const uint16_t
dpi = &session->DPI;
if (dpi->y + dpi->height <= spr->generic.sprite_top || spr->generic.sprite_bottom <= dpi->y
|| dpi->x + dpi->width <= spr->generic.sprite_left || spr->generic.sprite_right <= dpi->x)
if (dpi->y + dpi->height <= spr->sprite_top || spr->sprite_bottom <= dpi->y || dpi->x + dpi->width <= spr->sprite_left
|| spr->sprite_right <= dpi->x)
{
continue;
}
int32_t image_direction = session->CurrentRotation;
image_direction <<= 3;
image_direction += spr->generic.sprite_direction;
image_direction += spr->sprite_direction;
image_direction &= 0x1F;
session->CurrentlyDrawnItem = spr;
session->SpritePosition.x = spr->generic.x;
session->SpritePosition.y = spr->generic.y;
session->SpritePosition.x = spr->x;
session->SpritePosition.y = spr->y;
session->InteractionType = VIEWPORT_INTERACTION_ITEM_SPRITE;
switch (spr->generic.sprite_identifier)
switch (spr->sprite_identifier)
{
case SPRITE_IDENTIFIER_VEHICLE:
vehicle_paint(session, reinterpret_cast<const Vehicle*>(spr), image_direction);
vehicle_paint(session, spr->As<Vehicle>(), image_direction);
#ifdef __ENABLE_LIGHTFX__
if (lightfx_for_vehicles_is_available())
{
lightfx_add_lights_magic_vehicle(reinterpret_cast<Vehicle*>(const_cast<rct_sprite*>(spr)));
lightfx_add_lights_magic_vehicle(spr->As<Vehicle>());
}
#endif
break;
case SPRITE_IDENTIFIER_PEEP:
peep_paint(session, reinterpret_cast<const Peep*>(spr), image_direction);
peep_paint(session, spr->As<Peep>(), image_direction);
break;
case SPRITE_IDENTIFIER_MISC:
misc_paint(session, spr, image_direction);
// TODO: Update misc_paint to take a specific sprite type
misc_paint(session, reinterpret_cast<rct_sprite*>(spr), image_direction);
break;
case SPRITE_IDENTIFIER_LITTER:
litter_paint(session, reinterpret_cast<const Litter*>(spr), image_direction);
litter_paint(session, spr->As<Litter>(), image_direction);
break;
default:
assert(false);

View File

@ -3012,10 +3012,10 @@ static PeepThoughtType peep_assess_surroundings(int16_t centre_x, int16_t centre
}
}
Litter* litter;
for (uint16_t sprite_idx = gSpriteListHead[SPRITE_LIST_LITTER]; sprite_idx != SPRITE_INDEX_NULL; sprite_idx = litter->next)
for (uint16_t sprite_idx = gSpriteListHead[SPRITE_LIST_LITTER]; sprite_idx != SPRITE_INDEX_NULL;)
{
litter = &(get_sprite(sprite_idx)->litter);
auto litter = GetEntity<Litter>(sprite_idx);
sprite_idx = litter->next;
int16_t dist_x = abs(litter->x - centre_x);
int16_t dist_y = abs(litter->y - centre_y);
@ -5477,24 +5477,25 @@ void Guest::UpdateWalking()
return;
// Check if there is a peep watching (and if there is place for us)
uint16_t sprite_id = sprite_get_first_in_quadrant(x, y);
for (rct_sprite* sprite; sprite_id != SPRITE_INDEX_NULL; sprite_id = sprite->generic.next_in_quadrant)
for (uint16_t sprite_id = sprite_get_first_in_quadrant(x, y); sprite_id != SPRITE_INDEX_NULL;)
{
sprite = get_sprite(sprite_id);
auto sprite = GetEntity(sprite_id);
sprite_id = sprite->next_in_quadrant;
auto peep = sprite->As<Peep>();
if (!sprite->generic.Is<Peep>())
if (peep == nullptr)
continue;
if (sprite->peep.State != PEEP_STATE_WATCHING)
if (peep->State != PEEP_STATE_WATCHING)
continue;
if (z != sprite->peep.z)
if (z != peep->z)
continue;
if ((sprite->peep.Var37 & 0x3) != chosen_edge)
if ((peep->Var37 & 0x3) != chosen_edge)
continue;
positions_free &= ~(1 << ((sprite->peep.Var37 & 0x1C) >> 2));
positions_free &= ~(1 << ((peep->Var37 & 0x1C) >> 2));
}
if (!positions_free)
@ -6060,27 +6061,28 @@ bool Guest::UpdateWalkingFindBench()
for (; !(edges & (1 << chosen_edge));)
chosen_edge = (chosen_edge + 1) & 0x3;
uint16_t sprite_id = sprite_get_first_in_quadrant(x, y);
uint8_t free_edge = 3;
// Check if there is no peep sitting in chosen_edge
for (rct_sprite* sprite; sprite_id != SPRITE_INDEX_NULL; sprite_id = sprite->generic.next_in_quadrant)
for (uint16_t sprite_id = sprite_get_first_in_quadrant(x, y); sprite_id != SPRITE_INDEX_NULL;)
{
sprite = get_sprite(sprite_id);
auto sprite = GetEntity(sprite_id);
sprite_id = sprite->next_in_quadrant;
auto peep = sprite->As<Peep>();
if (!sprite->generic.Is<Peep>())
if (peep == nullptr)
continue;
if (sprite->peep.State != PEEP_STATE_SITTING)
if (peep->State != PEEP_STATE_SITTING)
continue;
if (z != sprite->peep.z)
if (z != peep->z)
continue;
if ((sprite->peep.Var37 & 0x3) != chosen_edge)
if ((peep->Var37 & 0x3) != chosen_edge)
continue;
free_edge &= ~(1 << ((sprite->peep.Var37 & 0x4) >> 2));
free_edge &= ~(1 << ((peep->Var37 & 0x4) >> 2));
}
if (!free_edge)
@ -6255,14 +6257,14 @@ static void peep_update_walking_break_scenery(Peep* peep)
if (edges == 0xF)
return;
uint16_t sprite_id = sprite_get_first_in_quadrant(peep->x, peep->y);
// Check if a peep is already sitting on the bench. If so, do not vandalise it.
for (rct_sprite* sprite; sprite_id != SPRITE_INDEX_NULL; sprite_id = sprite->generic.next_in_quadrant)
for (uint16_t sprite_id = sprite_get_first_in_quadrant(peep->x, peep->y); sprite_id != SPRITE_INDEX_NULL;)
{
sprite = get_sprite(sprite_id);
auto sprite = GetEntity(sprite_id);
sprite_id = sprite->next_in_quadrant;
auto peep2 = sprite->As<Peep>();
if (!sprite->generic.Is<Peep>() || (sprite->peep.State != PEEP_STATE_SITTING) || (peep->z != sprite->peep.z))
if (peep2 == nullptr || (peep2->State != PEEP_STATE_SITTING) || (peep->z != peep2->z))
{
continue;
}

View File

@ -2678,13 +2678,13 @@ static void peep_footpath_move_forward(Peep* peep, int16_t x, int16_t y, TileEle
uint16_t crowded = 0;
uint8_t litter_count = 0;
uint8_t sick_count = 0;
uint16_t sprite_id = sprite_get_first_in_quadrant(x, y);
for (rct_sprite* sprite; sprite_id != SPRITE_INDEX_NULL; sprite_id = sprite->generic.next_in_quadrant)
for (uint16_t sprite_id = sprite_get_first_in_quadrant(x, y); sprite_id != SPRITE_INDEX_NULL;)
{
sprite = get_sprite(sprite_id);
if (sprite->generic.Is<Peep>())
auto sprite = GetEntity(sprite_id);
sprite_id = sprite->next_in_quadrant;
if (auto other_peep = sprite->As<Peep>(); other_peep != nullptr)
{
Peep* other_peep = reinterpret_cast<Peep*>(sprite);
if (other_peep->State != PEEP_STATE_WALKING)
continue;
@ -2693,9 +2693,8 @@ static void peep_footpath_move_forward(Peep* peep, int16_t x, int16_t y, TileEle
crowded++;
continue;
}
else if (sprite->generic.sprite_identifier == SPRITE_IDENTIFIER_LITTER)
else if (auto litter = sprite->As<Litter>(); litter != nullptr)
{
Litter* litter = reinterpret_cast<Litter*>(sprite);
if (abs(litter->z - peep->NextLoc.z) > 16)
continue;

View File

@ -994,7 +994,7 @@ enum
*/
#define FOR_ALL_PEEPS(sprite_index, peep) \
for ((sprite_index) = gSpriteListHead[SPRITE_LIST_PEEP]; (sprite_index) != SPRITE_INDEX_NULL; (sprite_index) = peep->next) \
if (((peep) = GET_PEEP(sprite_index)) != nullptr || 1)
if (((peep) = GetEntity<Peep>(sprite_index)) != nullptr || 1)
#define FOR_ALL_GUESTS(sprite_index, peep) \
FOR_ALL_PEEPS (sprite_index, peep) \

View File

@ -126,7 +126,7 @@ bool staff_hire_new_member(STAFF_TYPE staffType, ENTERTAINER_COSTUME entertainer
return;
// Open window for new staff.
Peep* peep = &get_sprite(res->peepSriteIndex)->peep;
auto peep = GetEntity<Peep>(res->peepSriteIndex);
auto intent = Intent(WC_PEEP);
intent.putExtra(INTENT_EXTRA_PEEP, peep);
context_open_intent(&intent);
@ -443,11 +443,10 @@ static uint8_t staff_handyman_direction_to_nearest_litter(Peep* peep)
{
uint16_t nearestLitterDist = 0xFFFF;
Litter* nearestLitter = nullptr;
Litter* litter = nullptr;
for (uint16_t litterIndex = gSpriteListHead[SPRITE_LIST_LITTER]; litterIndex != 0xFFFF; litterIndex = litter->next)
for (uint16_t litterIndex = gSpriteListHead[SPRITE_LIST_LITTER]; litterIndex != SPRITE_INDEX_NULL;)
{
litter = &get_sprite(litterIndex)->litter;
auto litter = GetEntity<Litter>(litterIndex);
litterIndex = litter->next;
uint16_t distance = abs(litter->x - peep->x) + abs(litter->y - peep->y) + abs(litter->z - peep->z) * 4;
@ -1817,24 +1816,25 @@ static int32_t peep_update_patrolling_find_sweeping(Peep* peep)
if (!(peep->StaffOrders & STAFF_ORDERS_SWEEPING))
return 0;
uint16_t sprite_id = sprite_get_first_in_quadrant(peep->x, peep->y);
for (rct_sprite* sprite = nullptr; sprite_id != SPRITE_INDEX_NULL; sprite_id = sprite->generic.next_in_quadrant)
for (uint16_t sprite_id = sprite_get_first_in_quadrant(peep->x, peep->y); sprite_id != SPRITE_INDEX_NULL;)
{
sprite = get_sprite(sprite_id);
auto sprite = GetEntity(sprite_id);
sprite_id = sprite->next_in_quadrant;
auto litter = sprite->As<Litter>();
if (sprite->generic.sprite_identifier != SPRITE_IDENTIFIER_LITTER)
if (litter == nullptr)
continue;
uint16_t z_diff = abs(peep->z - sprite->litter.z);
uint16_t z_diff = abs(peep->z - litter->z);
if (z_diff >= 16)
continue;
peep->SetState(PEEP_STATE_SWEEPING);
peep->Var37 = 0;
peep->DestinationX = sprite->litter.x;
peep->DestinationY = sprite->litter.y;
peep->DestinationX = litter->x;
peep->DestinationY = litter->y;
peep->DestinationTolerance = 5;
return 1;
}

View File

@ -1341,10 +1341,9 @@ private:
}
for (size_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* sprite = get_sprite(i);
if (sprite->generic.sprite_identifier == SPRITE_IDENTIFIER_VEHICLE)
auto vehicle = GetEntity<Vehicle>(i);
if (vehicle != nullptr)
{
Vehicle* vehicle = reinterpret_cast<Vehicle*>(sprite);
FixVehiclePeepLinks(vehicle, spriteIndexMap);
}
}

View File

@ -945,7 +945,7 @@ void S6Exporter::ExportSprites()
sprite_clear_all_unused();
for (int32_t i = 0; i < RCT2_MAX_SPRITES; i++)
{
ExportSprite(&_s6.sprites[i], get_sprite(i));
ExportSprite(&_s6.sprites[i], reinterpret_cast<const rct_sprite*>(GetEntity(i)));
}
for (int32_t i = 0; i < SPRITE_LIST_COUNT; i++)

View File

@ -1282,8 +1282,8 @@ public:
for (int32_t i = 0; i < RCT2_MAX_SPRITES; i++)
{
auto src = &_s6.sprites[i];
auto dst = get_sprite(i);
ImportSprite(dst, src);
auto dst = GetEntity(i);
ImportSprite(reinterpret_cast<rct_sprite*>(dst), src);
}
for (int32_t i = 0; i < SPRITE_LIST_COUNT; i++)

View File

@ -831,10 +831,9 @@ size_t Ride::FormatStatusTo(void* argsV) const
mode == RIDE_MODE_RACE && !(lifecycle_flags & RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING)
&& race_winner != SPRITE_INDEX_NULL)
{
auto sprite = get_sprite(race_winner);
if (sprite != nullptr && sprite->generic.Is<Peep>())
auto peep = GetEntity<Peep>(race_winner);
if (peep != nullptr)
{
auto peep = sprite->generic.As<Peep>();
ft.Add<rct_string_id>(STR_RACE_WON_BY);
peep->FormatNameTo(ft);
}
@ -2739,10 +2738,12 @@ Staff* ride_get_mechanic(Ride* ride)
{
if (ride->mechanic != SPRITE_INDEX_NULL)
{
auto peep = (&(get_sprite(ride->mechanic)->peep))->AsStaff();
if (peep != nullptr && peep->IsMechanic())
auto peep = GetEntity<Peep>(ride->mechanic);
if (peep != nullptr)
{
return peep;
auto staff = peep->AsStaff();
if (staff != nullptr && staff->IsMechanic())
return staff;
}
}
return nullptr;

View File

@ -281,7 +281,7 @@ static void ride_race_init_vehicle_speeds(Ride* ride)
if (vehicle->num_peeps != 0)
{
Peep* peep = &get_sprite(vehicle->peep[0])->peep;
auto peep = GetEntity<Peep>(vehicle->peep[0]);
// Easter egg names should only work on guests
Guest* guest = peep->AsGuest();

View File

@ -1321,9 +1321,11 @@ void vehicle_sounds_update()
vehicle_sounds_update_window_setup();
for (uint16_t i = gSpriteListHead[SPRITE_LIST_TRAIN_HEAD]; i != SPRITE_INDEX_NULL; i = get_sprite(i)->vehicle.next)
for (uint16_t i = gSpriteListHead[SPRITE_LIST_TRAIN_HEAD]; i != SPRITE_INDEX_NULL;)
{
get_sprite(i)->vehicle.UpdateSoundParams(vehicleSoundParamsList);
auto vehicle = GetEntity<Vehicle>(i);
i = vehicle->next;
vehicle->UpdateSoundParams(vehicleSoundParamsList);
}
// Stop all playing sounds that no longer have priority to play after vehicle_update_sound_params
@ -5632,12 +5634,7 @@ void Vehicle::UpdateSound()
*/
SoundId Vehicle::UpdateScreamSound()
{
uint32_t r;
uint16_t spriteIndex;
rct_ride_entry* rideEntry;
Vehicle* vehicle2;
rideEntry = get_ride_entry(ride_subtype);
rct_ride_entry* rideEntry = get_ride_entry(ride_subtype);
rct_ride_entry_vehicle* vehicleEntry = &rideEntry->vehicles[vehicle_type];
@ -5650,10 +5647,11 @@ SoundId Vehicle::UpdateScreamSound()
if (velocity > -0x2C000)
return SoundId::Null;
spriteIndex = sprite_index;
do
for (uint16_t spriteIndex = sprite_index; spriteIndex != SPRITE_INDEX_NULL;)
{
vehicle2 = &(get_sprite(spriteIndex)->vehicle);
auto vehicle2 = GetEntity<Vehicle>(spriteIndex);
spriteIndex = vehicle2->next_vehicle_on_train;
if (vehicle2->vehicle_sprite_type < 1)
continue;
if (vehicle2->vehicle_sprite_type <= 4)
@ -5662,17 +5660,18 @@ SoundId Vehicle::UpdateScreamSound()
continue;
if (vehicle2->vehicle_sprite_type <= 15)
goto produceScream;
} while ((spriteIndex = vehicle2->next_vehicle_on_train) != SPRITE_INDEX_NULL);
}
return SoundId::Null;
}
if (velocity < 0x2C000)
return SoundId::Null;
spriteIndex = sprite_index;
do
for (uint16_t spriteIndex = sprite_index; spriteIndex != SPRITE_INDEX_NULL;)
{
vehicle2 = &(get_sprite(spriteIndex)->vehicle);
auto vehicle2 = GetEntity<Vehicle>(spriteIndex);
spriteIndex = vehicle2->next_vehicle_on_train;
if (vehicle2->vehicle_sprite_type < 5)
continue;
if (vehicle2->vehicle_sprite_type <= 8)
@ -5681,13 +5680,13 @@ SoundId Vehicle::UpdateScreamSound()
continue;
if (vehicle2->vehicle_sprite_type <= 23)
goto produceScream;
} while ((spriteIndex = vehicle2->next_vehicle_on_train) != SPRITE_INDEX_NULL);
}
return SoundId::Null;
produceScream:
if (scream_sound_id == SoundId::Null)
{
r = scenario_rand();
auto r = scenario_rand();
if (totalNumPeeps >= static_cast<int32_t>(r % 16))
{
switch (vehicleEntry->sound_range)
@ -9713,17 +9712,12 @@ rct_ride_entry_vehicle* Vehicle::Entry() const
int32_t Vehicle::NumPeepsUntilTrainTail() const
{
const Vehicle* vehicle = this;
uint16_t spriteIndex;
int32_t numPeeps = 0;
for (;;)
for (uint16_t spriteIndex = sprite_index; spriteIndex != SPRITE_INDEX_NULL;)
{
numPeeps += vehicle->num_peeps;
const Vehicle* vehicle = GetEntity<Vehicle>(spriteIndex);
spriteIndex = vehicle->next_vehicle_on_train;
if (spriteIndex == SPRITE_INDEX_NULL)
break;
vehicle = &(get_sprite(spriteIndex)->vehicle);
numPeeps += vehicle->num_peeps;
}
return numPeeps;

View File

@ -48,7 +48,7 @@ static void paint_crooked_house_structure(
{
if (ride->vehicles[0] != SPRITE_INDEX_NULL)
{
rct_sprite* sprite = get_sprite(ride->vehicles[0]);
auto sprite = GetEntity(ride->vehicles[0]);
session->InteractionType = VIEWPORT_INTERACTION_ITEM_SPRITE;
session->CurrentlyDrawnItem = sprite;
}

View File

@ -1216,13 +1216,13 @@ void vehicle_visual_mini_golf_player(
if (rideEntry == nullptr)
return;
rct_sprite* sprite = get_sprite(vehicle->peep[0]);
auto* peep = GetEntity<Peep>(vehicle->peep[0]);
uint8_t frame = mini_golf_peep_animation_frames[vehicle->mini_golf_current_animation][vehicle->animation_frame];
uint32_t ebx = (frame << 2) + (imageDirection >> 3);
uint32_t image_id = rideEntry->vehicles[0].base_image_id + 1 + ebx;
uint32_t peep_palette = sprite->peep.TshirtColour << 19 | sprite->peep.TrousersColour << 24 | 0x0A0000000;
uint32_t peep_palette = peep->TshirtColour << 19 | peep->TrousersColour << 24 | 0x0A0000000;
sub_98197C(session, image_id | peep_palette, 0, 0, 1, 1, 11, z, 0, 0, z + 5);
}

View File

@ -162,7 +162,7 @@ namespace OpenRCT2::Scripting
SpriteBase* GetEntity() const
{
return &get_sprite(_id)->generic;
return ::GetEntity(_id);
}
public:
@ -746,7 +746,7 @@ namespace OpenRCT2::Scripting
protected:
Peep* GetPeep() const
{
return get_sprite(_id)->generic.As<Peep>();
return ::GetEntity<Peep>(_id);
}
};

View File

@ -89,10 +89,10 @@ namespace OpenRCT2::Scripting
if (id >= 0 && id < MAX_SPRITES)
{
auto spriteId = static_cast<uint16_t>(id);
auto sprite = get_sprite(spriteId);
if (sprite != nullptr && sprite->generic.sprite_identifier != SPRITE_IDENTIFIER_NULL)
auto sprite = GetEntity(spriteId);
if (sprite != nullptr && sprite->sprite_identifier != SPRITE_IDENTIFIER_NULL)
{
return GetEntityAsDukValue(sprite);
return GetEntityAsDukValue(reinterpret_cast<rct_sprite*>(sprite));
}
}
duk_push_null(_context);
@ -131,49 +131,35 @@ namespace OpenRCT2::Scripting
}
std::vector<DukValue> result;
auto spriteId = gSpriteListHead[targetList];
while (spriteId != SPRITE_INDEX_NULL)
for (auto spriteId = gSpriteListHead[targetList]; spriteId != SPRITE_INDEX_NULL;)
{
auto sprite = get_sprite(spriteId);
if (sprite == nullptr)
auto sprite = GetEntity(spriteId);
spriteId = sprite->next;
// Only the misc list checks the type property
if (targetList != SPRITE_LIST_MISC || sprite->type == targetType)
{
break;
}
else
{
// Only the misc list checks the type property
if (targetList != SPRITE_LIST_MISC || sprite->generic.type == targetType)
if (targetList == SPRITE_LIST_PEEP)
{
if (targetList == SPRITE_LIST_PEEP)
{
if (sprite->peep.AssignedPeepType == PEEP_TYPE_STAFF)
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScStaff>(spriteId)));
else
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScGuest>(spriteId)));
}
else if (targetList == SPRITE_LIST_TRAIN_HEAD)
{
auto carId = spriteId;
while (carId != SPRITE_INDEX_NULL)
{
auto car = get_sprite(carId);
if (car == nullptr)
{
break;
}
else
{
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScVehicle>(carId)));
carId = car->vehicle.next_vehicle_on_train;
}
}
}
if (sprite->As<Peep>()->AssignedPeepType == PEEP_TYPE_STAFF)
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScStaff>(sprite->sprite_index)));
else
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScGuest>(sprite->sprite_index)));
}
else if (targetList == SPRITE_LIST_TRAIN_HEAD)
{
for (auto carId = sprite->sprite_index; carId != SPRITE_INDEX_NULL;)
{
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScEntity>(spriteId)));
auto car = GetEntity<Vehicle>(carId);
carId = car->next_vehicle_on_train;
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScVehicle>(carId)));
}
}
spriteId = sprite->generic.next;
else
{
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScEntity>(sprite->sprite_index)));
}
}
}
return result;

View File

@ -363,12 +363,10 @@ void duck_press(Duck* duck)
void duck_remove_all()
{
uint16_t nextSpriteIndex;
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_MISC]; spriteIndex != SPRITE_INDEX_NULL;
spriteIndex = nextSpriteIndex)
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_MISC]; spriteIndex != SPRITE_INDEX_NULL;)
{
SpriteGeneric* sprite = &(get_sprite(spriteIndex)->generic);
nextSpriteIndex = sprite->next;
auto sprite = GetEntity(spriteIndex);
spriteIndex = sprite->next;
if (sprite->type == SPRITE_MISC_DUCK)
{
sprite->Invalidate1();

View File

@ -390,21 +390,20 @@ CoordsXY footpath_bridge_get_info_from_pos(const ScreenCoordsXY& screenCoords, i
*/
void footpath_remove_litter(const CoordsXYZ& footpathPos)
{
uint16_t spriteIndex = sprite_get_first_in_quadrant(footpathPos.x, footpathPos.y);
while (spriteIndex != SPRITE_INDEX_NULL)
for (uint16_t spriteIndex = sprite_get_first_in_quadrant(footpathPos.x, footpathPos.y); spriteIndex != SPRITE_INDEX_NULL;)
{
Litter* sprite = &get_sprite(spriteIndex)->litter;
uint16_t nextSpriteIndex = sprite->next_in_quadrant;
if (sprite->sprite_identifier == SPRITE_IDENTIFIER_LITTER)
auto sprite = GetEntity(spriteIndex);
spriteIndex = sprite->next_in_quadrant;
Litter* litter = sprite->As<Litter>();
if (litter != nullptr)
{
int32_t distanceZ = abs(sprite->z - footpathPos.z);
int32_t distanceZ = abs(litter->z - footpathPos.z);
if (distanceZ <= 32)
{
sprite->Invalidate0();
sprite_remove(sprite);
litter->Invalidate0();
sprite_remove(litter);
}
}
spriteIndex = nextSpriteIndex;
}
}
@ -414,14 +413,13 @@ void footpath_remove_litter(const CoordsXYZ& footpathPos)
*/
void footpath_interrupt_peeps(const CoordsXYZ& footpathPos)
{
uint16_t spriteIndex = sprite_get_first_in_quadrant(footpathPos.x, footpathPos.y);
while (spriteIndex != SPRITE_INDEX_NULL)
for (auto spriteIndex = sprite_get_first_in_quadrant(footpathPos.x, footpathPos.y); spriteIndex != SPRITE_INDEX_NULL;)
{
auto* entity = get_sprite(spriteIndex);
uint16_t nextSpriteIndex = entity->generic.next_in_quadrant;
if (entity->generic.Is<Peep>())
auto entity = GetEntity(spriteIndex);
spriteIndex = entity->next_in_quadrant;
auto peep = entity->As<Peep>();
if (peep != nullptr)
{
Peep* peep = &entity->peep;
if (peep->State == PEEP_STATE_SITTING || peep->State == PEEP_STATE_WATCHING)
{
if (peep->z == footpathPos.z)
@ -434,7 +432,6 @@ void footpath_interrupt_peeps(const CoordsXYZ& footpathPos)
}
}
}
spriteIndex = nextSpriteIndex;
}
}

View File

@ -159,12 +159,8 @@ static bool map_animation_invalidate_queue_banner(const CoordsXYZ& loc)
static bool map_animation_invalidate_small_scenery(const CoordsXYZ& loc)
{
TileCoordsXYZ tileLoc{ loc };
TileElement* tileElement;
rct_scenery_entry* sceneryEntry;
rct_sprite* sprite;
Peep* peep;
tileElement = map_get_first_element_at(loc);
auto tileElement = map_get_first_element_at(loc);
if (tileElement == nullptr)
return true;
do
@ -176,7 +172,7 @@ static bool map_animation_invalidate_small_scenery(const CoordsXYZ& loc)
if (tileElement->IsGhost())
continue;
sceneryEntry = tileElement->AsSmallScenery()->GetEntry();
auto sceneryEntry = tileElement->AsSmallScenery()->GetEntry();
if (sceneryEntry == nullptr)
continue;
@ -198,14 +194,14 @@ static bool map_animation_invalidate_small_scenery(const CoordsXYZ& loc)
int32_t x2 = loc.x - CoordsDirectionDelta[direction].x;
int32_t y2 = loc.y - CoordsDirectionDelta[direction].y;
uint16_t spriteIdx = sprite_get_first_in_quadrant(x2, y2);
for (; spriteIdx != SPRITE_INDEX_NULL; spriteIdx = sprite->generic.next_in_quadrant)
for (uint16_t spriteIdx = sprite_get_first_in_quadrant(x2, y2); spriteIdx != SPRITE_INDEX_NULL;)
{
sprite = get_sprite(spriteIdx);
if (!sprite->generic.Is<Peep>())
auto sprite = GetEntity(spriteIdx);
spriteIdx = sprite->next_in_quadrant;
auto peep = sprite->As<Peep>();
if (peep == nullptr)
continue;
peep = &sprite->peep;
if (peep->State != PEEP_STATE_WALKING)
continue;
if (peep->z != loc.z)

View File

@ -469,12 +469,11 @@ int32_t Park::CalculateParkRating() const
// Litter
{
Litter* litter;
int32_t litterCount = 0;
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL;
spriteIndex = litter->next)
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL;)
{
litter = &(get_sprite(spriteIndex)->litter);
auto litter = GetEntity<Litter>(spriteIndex);
spriteIndex = litter->next;
// Ignore recently dropped litter
if (litter->creationTick - gScenarioTicks >= 7680)

View File

@ -52,6 +52,12 @@ static CoordsXYZ _spritelocations2[MAX_SPRITES];
static size_t GetSpatialIndexOffset(int32_t x, int32_t y);
static void move_sprite_to_list(SpriteBase* sprite, SPRITE_LIST newListIndex);
// Required for GetEntity to return a default
template<> bool SpriteBase::Is<SpriteBase>() const
{
return true;
}
template<> bool SpriteBase::Is<Litter>() const
{
return sprite_identifier == SPRITE_IDENTIFIER_LITTER;
@ -111,6 +117,11 @@ rct_sprite* get_sprite(size_t sprite_idx)
return &_spriteList[sprite_idx];
}
SpriteBase* GetEntity(size_t sprite_idx)
{
return GetEntity<SpriteBase>(sprite_idx);
}
uint16_t sprite_get_first_in_quadrant(int32_t x, int32_t y)
{
return gSpriteSpatialIndex[GetSpatialIndexOffset(x, y)];
@ -174,24 +185,24 @@ void reset_sprite_list()
_spriteFlashingList[i] = false;
}
rct_sprite* previous_spr = nullptr;
SpriteBase* previous_spr = nullptr;
for (int32_t i = 0; i < MAX_SPRITES; ++i)
{
rct_sprite* spr = get_sprite(i);
spr->generic.sprite_identifier = SPRITE_IDENTIFIER_NULL;
spr->generic.sprite_index = i;
spr->generic.next = SPRITE_INDEX_NULL;
spr->generic.linked_list_index = SPRITE_LIST_FREE;
auto* spr = GetEntity(i);
spr->sprite_identifier = SPRITE_IDENTIFIER_NULL;
spr->sprite_index = i;
spr->next = SPRITE_INDEX_NULL;
spr->linked_list_index = SPRITE_LIST_FREE;
if (previous_spr != nullptr)
{
spr->generic.previous = previous_spr->generic.sprite_index;
previous_spr->generic.next = i;
spr->previous = previous_spr->sprite_index;
previous_spr->next = i;
}
else
{
spr->generic.previous = SPRITE_INDEX_NULL;
spr->previous = SPRITE_INDEX_NULL;
gSpriteListHead[SPRITE_LIST_FREE] = i;
}
_spriteFlashingList[i] = false;
@ -214,13 +225,13 @@ void reset_sprite_spatial_index()
std::fill_n(gSpriteSpatialIndex, std::size(gSpriteSpatialIndex), SPRITE_INDEX_NULL);
for (size_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* spr = get_sprite(i);
if (spr->generic.sprite_identifier != SPRITE_IDENTIFIER_NULL)
auto* spr = GetEntity(i);
if (spr->sprite_identifier != SPRITE_IDENTIFIER_NULL)
{
size_t index = GetSpatialIndexOffset(spr->generic.x, spr->generic.y);
size_t index = GetSpatialIndexOffset(spr->x, spr->y);
uint32_t nextSpriteId = gSpriteSpatialIndex[index];
gSpriteSpatialIndex[index] = spr->generic.sprite_index;
spr->generic.next_in_quadrant = nextSpriteId;
gSpriteSpatialIndex[index] = spr->sprite_index;
spr->next_in_quadrant = nextSpriteId;
}
}
}
@ -267,6 +278,7 @@ rct_sprite_checksum sprite_checksum()
_spriteHashAlg->Clear();
for (size_t i = 0; i < MAX_SPRITES; i++)
{
// TODO create a way to copy only the specific type
auto sprite = get_sprite(i);
if (sprite->generic.sprite_identifier != SPRITE_IDENTIFIER_NULL
&& sprite->generic.sprite_identifier != SPRITE_IDENTIFIER_MISC)
@ -278,10 +290,10 @@ rct_sprite_checksum sprite_checksum()
copy.generic.sprite_width = copy.generic.sprite_height_negative = copy.generic.sprite_height_positive = 0;
// Next in quadrant might be a misc sprite, set first non-misc sprite in quadrant.
while (auto* nextSprite = get_sprite(copy.generic.next_in_quadrant))
while (auto* nextSprite = GetEntity(copy.generic.next_in_quadrant))
{
if (nextSprite->generic.sprite_identifier == SPRITE_IDENTIFIER_MISC)
copy.generic.next_in_quadrant = nextSprite->generic.next_in_quadrant;
if (nextSprite->sprite_identifier == SPRITE_IDENTIFIER_MISC)
copy.generic.next_in_quadrant = nextSprite->next_in_quadrant;
else
break;
}
@ -346,21 +358,14 @@ static void sprite_reset(SpriteBase* sprite)
*/
void sprite_clear_all_unused()
{
SpriteGeneric* sprite;
uint16_t spriteIndex, nextSpriteIndex;
spriteIndex = gSpriteListHead[SPRITE_LIST_FREE];
while (spriteIndex != SPRITE_INDEX_NULL)
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_FREE]; spriteIndex != SPRITE_INDEX_NULL;)
{
sprite = &get_sprite(spriteIndex)->generic;
nextSpriteIndex = sprite->next;
auto sprite = GetEntity(spriteIndex);
spriteIndex = sprite->next;
sprite_reset(sprite);
sprite->linked_list_index = SPRITE_LIST_FREE;
// This shouldn't be necessary, as sprite_reset() preserves the index
// but it has been left in as a safety net in case the index isn't set correctly
sprite->sprite_index = spriteIndex;
// 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
@ -368,8 +373,7 @@ void sprite_clear_all_unused()
{
sprite->next_in_quadrant = SPRITE_INDEX_NULL;
}
_spriteFlashingList[spriteIndex] = false;
spriteIndex = nextSpriteIndex;
_spriteFlashingList[sprite->sprite_index] = false;
}
}
@ -397,7 +401,7 @@ rct_sprite* create_sprite(SPRITE_IDENTIFIER spriteIdentifier, SPRITE_LIST linked
}
}
SpriteGeneric* sprite = &(get_sprite(gSpriteListHead[SPRITE_LIST_FREE]))->generic;
auto* sprite = GetEntity(gSpriteListHead[SPRITE_LIST_FREE]);
move_sprite_to_list(sprite, linkedListIndex);
@ -467,13 +471,13 @@ static void move_sprite_to_list(SpriteBase* sprite, SPRITE_LIST newListIndex)
else
{
// Hook up sprite->previous->next to sprite->next, removing the sprite from its old list
get_sprite(sprite->previous)->generic.next = sprite->next;
GetEntity(sprite->previous)->next = sprite->next;
}
// Similarly, hook up sprite->next->previous to sprite->previous
if (sprite->next != SPRITE_INDEX_NULL)
{
get_sprite(sprite->next)->generic.previous = sprite->previous;
GetEntity(sprite->next)->previous = sprite->previous;
}
sprite->previous = SPRITE_INDEX_NULL; // We become the new head of the target list, so there's no previous sprite
@ -485,7 +489,7 @@ static void move_sprite_to_list(SpriteBase* sprite, SPRITE_LIST newListIndex)
if (sprite->next != SPRITE_INDEX_NULL)
{
// Fix the chain by settings sprite->next->previous to sprite_index
get_sprite(sprite->next)->generic.previous = sprite->sprite_index;
GetEntity(sprite->next)->previous = sprite->sprite_index;
}
// These globals are probably counters for each sprite list?
@ -627,15 +631,11 @@ static void sprite_misc_update(rct_sprite* sprite)
*/
void sprite_misc_update_all()
{
rct_sprite* sprite;
uint16_t spriteIndex;
spriteIndex = gSpriteListHead[SPRITE_LIST_MISC];
while (spriteIndex != SPRITE_INDEX_NULL)
for (auto spriteIndex = gSpriteListHead[SPRITE_LIST_MISC]; spriteIndex != SPRITE_INDEX_NULL;)
{
sprite = get_sprite(spriteIndex);
spriteIndex = sprite->generic.next;
sprite_misc_update(sprite);
auto sprite = GetEntity(spriteIndex);
spriteIndex = sprite->next;
sprite_misc_update(reinterpret_cast<rct_sprite*>(sprite));
}
}
@ -647,7 +647,7 @@ static void SpriteSpatialInsert(SpriteBase* sprite, const CoordsXY& newLoc)
auto* next = &gSpriteSpatialIndex[newIndex];
while (sprite->sprite_index < *next && *next != SPRITE_INDEX_NULL)
{
auto sprite2 = &get_sprite(*next)->generic;
auto sprite2 = GetEntity(*next);
next = &sprite2->next_in_quadrant;
}
@ -667,7 +667,7 @@ static void SpriteSpatialRemove(SpriteBase* sprite)
reset_sprite_spatial_index();
}
auto* sprite2 = &get_sprite(*index)->generic;
auto* sprite2 = GetEntity(*index);
while (sprite != sprite2)
{
index = &sprite2->next_in_quadrant;
@ -675,7 +675,7 @@ static void SpriteSpatialRemove(SpriteBase* sprite)
{
break;
}
sprite2 = &get_sprite(*index)->generic;
sprite2 = GetEntity(*index);
}
*index = sprite->next_in_quadrant;
}
@ -756,7 +756,7 @@ void sprite_remove(SpriteBase* sprite)
size_t quadrantIndex = GetSpatialIndexOffset(sprite->x, sprite->y);
uint16_t* spriteIndex = &gSpriteSpatialIndex[quadrantIndex];
SpriteBase* quadrantSprite;
while (*spriteIndex != SPRITE_INDEX_NULL && (quadrantSprite = &get_sprite(*spriteIndex)->generic) != sprite)
while (*spriteIndex != SPRITE_INDEX_NULL && (quadrantSprite = GetEntity(*spriteIndex)) != sprite)
{
spriteIndex = &quadrantSprite->next_in_quadrant;
}
@ -806,11 +806,10 @@ void litter_create(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t t
{
Litter* newestLitter = nullptr;
uint32_t newestLitterCreationTick = 0;
for (uint16_t nextSpriteIndex, spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL;
spriteIndex = nextSpriteIndex)
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL;)
{
Litter* litter = &get_sprite(spriteIndex)->litter;
nextSpriteIndex = litter->next;
Litter* litter = GetEntity<Litter>(spriteIndex);
spriteIndex = litter->next;
if (newestLitterCreationTick <= litter->creationTick)
{
newestLitterCreationTick = litter->creationTick;
@ -846,15 +845,13 @@ void litter_create(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t t
*/
void litter_remove_at(int32_t x, int32_t y, int32_t z)
{
uint16_t spriteIndex = sprite_get_first_in_quadrant(x, y);
while (spriteIndex != SPRITE_INDEX_NULL)
for (uint16_t spriteIndex = sprite_get_first_in_quadrant(x, y); spriteIndex != SPRITE_INDEX_NULL;)
{
rct_sprite* sprite = get_sprite(spriteIndex);
uint16_t nextSpriteIndex = sprite->generic.next_in_quadrant;
if (sprite->generic.sprite_identifier == SPRITE_IDENTIFIER_LITTER)
auto* sprite = GetEntity(spriteIndex);
spriteIndex = sprite->next_in_quadrant;
auto* litter = sprite->As<Litter>();
if (litter != nullptr)
{
Litter* litter = &sprite->litter;
if (abs(litter->z - z) <= 16)
{
if (abs(litter->x - x) <= 8 && abs(litter->y - y) <= 8)
@ -864,7 +861,6 @@ void litter_remove_at(int32_t x, int32_t y, int32_t z)
}
}
}
spriteIndex = nextSpriteIndex;
}
}
@ -877,26 +873,24 @@ uint16_t remove_floating_sprites()
uint16_t removed = 0;
for (uint16_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* rctSprite = get_sprite(i);
if (rctSprite->generic.Is<Balloon>())
auto* entity = GetEntity(i);
if (entity->Is<Balloon>())
{
sprite_remove(&rctSprite->generic);
sprite_misc_update(rctSprite);
sprite_remove(entity);
removed++;
}
else if (rctSprite->generic.Is<Duck>())
else if (entity->Is<Duck>())
{
if (rctSprite->generic.As<Duck>()->IsFlying())
auto* duck = entity->As<Duck>();
if (duck->IsFlying())
{
rctSprite->duck.Remove();
sprite_misc_update(rctSprite);
duck->Remove();
removed++;
}
}
else if (rctSprite->generic.Is<MoneyEffect>())
else if (entity->Is<MoneyEffect>())
{
sprite_remove(&rctSprite->generic);
sprite_misc_update(rctSprite);
sprite_remove(entity);
removed++;
}
}
@ -906,9 +900,9 @@ uint16_t remove_floating_sprites()
/**
* Determines whether it's worth tweening a sprite or not when frame smoothing is on.
*/
static bool sprite_should_tween(rct_sprite* sprite)
static bool sprite_should_tween(SpriteBase* sprite)
{
switch (sprite->generic.sprite_identifier)
switch (sprite->sprite_identifier)
{
case SPRITE_IDENTIFIER_PEEP:
case SPRITE_IDENTIFIER_VEHICLE:
@ -946,7 +940,7 @@ void sprite_position_tween_all(float alpha)
for (uint16_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* sprite = get_sprite(i);
auto* sprite = GetEntity(i);
if (sprite_should_tween(sprite))
{
auto posA = _spritelocations1[i];
@ -957,8 +951,8 @@ void sprite_position_tween_all(float alpha)
}
sprite_set_coordinates(
std::round(posB.x * alpha + posA.x * inv), std::round(posB.y * alpha + posA.y * inv),
std::round(posB.z * alpha + posA.z * inv), &sprite->generic);
sprite->generic.Invalidate2();
std::round(posB.z * alpha + posA.z * inv), sprite);
sprite->Invalidate2();
}
}
}
@ -970,13 +964,13 @@ void sprite_position_tween_restore()
{
for (uint16_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* sprite = get_sprite(i);
auto* sprite = GetEntity(i);
if (sprite_should_tween(sprite))
{
sprite->generic.Invalidate2();
sprite->Invalidate2();
auto pos = _spritelocations2[i];
sprite_set_coordinates(pos.x, pos.y, pos.z, &sprite->generic);
sprite_set_coordinates(pos.x, pos.y, pos.z, sprite);
}
}
}
@ -985,10 +979,10 @@ void sprite_position_tween_reset()
{
for (uint16_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* sprite = get_sprite(i);
_spritelocations1[i].x = _spritelocations2[i].x = sprite->generic.x;
_spritelocations1[i].y = _spritelocations2[i].y = sprite->generic.y;
_spritelocations1[i].z = _spritelocations2[i].z = sprite->generic.z;
auto* sprite = GetEntity(i);
_spritelocations1[i].x = _spritelocations2[i].x = sprite->x;
_spritelocations1[i].y = _spritelocations2[i].y = sprite->y;
_spritelocations1[i].z = _spritelocations2[i].z = sprite->z;
}
}
@ -1004,72 +998,72 @@ bool sprite_get_flashing(SpriteBase* sprite)
return _spriteFlashingList[sprite->sprite_index];
}
static rct_sprite* find_sprite_list_cycle(uint16_t sprite_idx)
static SpriteBase* find_sprite_list_cycle(uint16_t sprite_idx)
{
if (sprite_idx == SPRITE_INDEX_NULL)
{
return nullptr;
}
const rct_sprite* fast = get_sprite(sprite_idx);
const rct_sprite* slow = fast;
const SpriteBase* fast = GetEntity(sprite_idx);
const SpriteBase* slow = fast;
bool increment_slow = false;
rct_sprite* cycle_start = nullptr;
while (fast->generic.sprite_index != SPRITE_INDEX_NULL)
SpriteBase* cycle_start = nullptr;
while (fast->sprite_index != SPRITE_INDEX_NULL)
{
// increment fast every time, unless reached the end
if (fast->generic.next == SPRITE_INDEX_NULL)
if (fast->next == SPRITE_INDEX_NULL)
{
break;
}
else
{
fast = get_sprite(fast->generic.next);
fast = GetEntity(fast->next);
}
// increment slow only every second iteration
if (increment_slow)
{
slow = get_sprite(slow->generic.next);
slow = GetEntity(slow->next);
}
increment_slow = !increment_slow;
if (fast == slow)
{
cycle_start = get_sprite(slow->generic.sprite_index);
cycle_start = GetEntity(slow->sprite_index);
break;
}
}
return cycle_start;
}
static rct_sprite* find_sprite_quadrant_cycle(uint16_t sprite_idx)
static SpriteBase* find_sprite_quadrant_cycle(uint16_t sprite_idx)
{
if (sprite_idx == SPRITE_INDEX_NULL)
{
return nullptr;
}
const rct_sprite* fast = get_sprite(sprite_idx);
const rct_sprite* slow = fast;
const SpriteBase* fast = GetEntity(sprite_idx);
const SpriteBase* slow = fast;
bool increment_slow = false;
rct_sprite* cycle_start = nullptr;
while (fast->generic.sprite_index != SPRITE_INDEX_NULL)
SpriteBase* cycle_start = nullptr;
while (fast->sprite_index != SPRITE_INDEX_NULL)
{
// increment fast every time, unless reached the end
if (fast->generic.next_in_quadrant == SPRITE_INDEX_NULL)
if (fast->next_in_quadrant == SPRITE_INDEX_NULL)
{
break;
}
else
{
fast = get_sprite(fast->generic.next_in_quadrant);
fast = GetEntity(fast->next_in_quadrant);
}
// increment slow only every second iteration
if (increment_slow)
{
slow = get_sprite(slow->generic.next_in_quadrant);
slow = GetEntity(slow->next_in_quadrant);
}
increment_slow = !increment_slow;
if (fast == slow)
{
cycle_start = get_sprite(slow->generic.sprite_index);
cycle_start = GetEntity(slow->sprite_index);
break;
}
}
@ -1078,14 +1072,13 @@ static rct_sprite* find_sprite_quadrant_cycle(uint16_t sprite_idx)
static bool index_is_in_list(uint16_t index, enum SPRITE_LIST sl)
{
uint16_t sprite_index = gSpriteListHead[sl];
while (sprite_index != SPRITE_INDEX_NULL)
for (uint16_t sprite_index = gSpriteListHead[sl]; sprite_index != SPRITE_INDEX_NULL;
sprite_index = GetEntity(sprite_index)->next)
{
if (sprite_index == index)
{
return true;
}
sprite_index = get_sprite(sprite_index)->generic.next;
}
return false;
}
@ -1094,31 +1087,31 @@ int32_t check_for_sprite_list_cycles(bool fix)
{
for (int32_t i = 0; i < SPRITE_LIST_COUNT; i++)
{
rct_sprite* cycle_start = find_sprite_list_cycle(gSpriteListHead[i]);
auto* cycle_start = find_sprite_list_cycle(gSpriteListHead[i]);
if (cycle_start != nullptr)
{
if (fix)
{
// Fix head list, but only in reverse order
// This is likely not needed, but just in case
get_sprite(gSpriteListHead[i])->generic.previous = SPRITE_INDEX_NULL;
GetEntity(gSpriteListHead[i])->previous = SPRITE_INDEX_NULL;
// Store the leftover part of cycle to be fixed
uint16_t cycle_next = cycle_start->generic.next;
uint16_t cycle_next = cycle_start->next;
// Break the cycle
cycle_start->generic.next = SPRITE_INDEX_NULL;
cycle_start->next = SPRITE_INDEX_NULL;
// Now re-add remainder of the cycle back to list, safely.
// Add each sprite to the list until we encounter one that is already part of the list.
while (!index_is_in_list(cycle_next, static_cast<SPRITE_LIST>(i)))
{
rct_sprite* spr = get_sprite(cycle_next);
auto* spr = GetEntity(cycle_next);
cycle_start->generic.next = cycle_next;
spr->generic.previous = cycle_start->generic.sprite_index;
cycle_next = spr->generic.next;
spr->generic.next = SPRITE_INDEX_NULL;
cycle_start->next = cycle_next;
spr->previous = cycle_start->sprite_index;
cycle_next = spr->next;
spr->next = SPRITE_INDEX_NULL;
cycle_start = spr;
}
}
@ -1137,32 +1130,32 @@ int32_t fix_disjoint_sprites()
{
// Find reachable sprites
bool reachable[MAX_SPRITES] = { false };
uint16_t sprite_idx = gSpriteListHead[SPRITE_LIST_FREE];
rct_sprite* null_list_tail = nullptr;
while (sprite_idx != SPRITE_INDEX_NULL)
SpriteBase* null_list_tail = nullptr;
for (uint16_t sprite_idx = gSpriteListHead[SPRITE_LIST_FREE]; sprite_idx != SPRITE_INDEX_NULL;)
{
reachable[sprite_idx] = true;
// cache the tail, so we don't have to walk the list twice
null_list_tail = get_sprite(sprite_idx);
sprite_idx = null_list_tail->generic.next;
null_list_tail = GetEntity(sprite_idx);
sprite_idx = null_list_tail->next;
}
int32_t count = 0;
// Find all null sprites
for (sprite_idx = 0; sprite_idx < MAX_SPRITES; sprite_idx++)
for (uint16_t sprite_idx = 0; sprite_idx < MAX_SPRITES; sprite_idx++)
{
rct_sprite* spr = get_sprite(sprite_idx);
if (spr->generic.sprite_identifier == SPRITE_IDENTIFIER_NULL)
auto* spr = GetEntity(sprite_idx);
if (spr->sprite_identifier == SPRITE_IDENTIFIER_NULL)
{
openrct2_assert(null_list_tail != nullptr, "Null list is empty, yet found null sprites");
spr->generic.sprite_index = sprite_idx;
spr->sprite_index = sprite_idx;
if (!reachable[sprite_idx])
{
// Add the sprite directly to the list
null_list_tail->generic.next = sprite_idx;
spr->generic.next = SPRITE_INDEX_NULL;
spr->generic.previous = null_list_tail->generic.sprite_index;
null_list_tail->next = sprite_idx;
spr->next = SPRITE_INDEX_NULL;
spr->previous = null_list_tail->sprite_index;
null_list_tail = spr;
count++;
reachable[sprite_idx] = true;
@ -1176,26 +1169,26 @@ int32_t check_for_spatial_index_cycles(bool fix)
{
for (uint32_t i = 0; i < SPATIAL_INDEX_LOCATION_NULL; i++)
{
rct_sprite* cycle_start = find_sprite_quadrant_cycle(gSpriteSpatialIndex[i]);
auto* cycle_start = find_sprite_quadrant_cycle(gSpriteSpatialIndex[i]);
if (cycle_start != nullptr)
{
if (fix)
{
// Store the leftover part of cycle to be fixed
uint16_t cycle_next = cycle_start->generic.next_in_quadrant;
uint16_t cycle_next = cycle_start->next_in_quadrant;
// Break the cycle
cycle_start->generic.next_in_quadrant = SPRITE_INDEX_NULL;
cycle_start->next_in_quadrant = SPRITE_INDEX_NULL;
// Now re-add remainder of the cycle back to list, safely.
// Add each sprite to the list until we encounter one that is already part of the list.
while (!index_is_in_list(cycle_next, static_cast<SPRITE_LIST>(i)))
{
rct_sprite* spr = get_sprite(cycle_next);
auto* spr = GetEntity(cycle_next);
cycle_start->generic.next_in_quadrant = cycle_next;
cycle_next = spr->generic.next_in_quadrant;
spr->generic.next_in_quadrant = SPRITE_INDEX_NULL;
cycle_start->next_in_quadrant = cycle_next;
cycle_next = spr->next_in_quadrant;
spr->next_in_quadrant = SPRITE_INDEX_NULL;
cycle_start = spr;
}
}

View File

@ -193,6 +193,15 @@ enum
rct_sprite* try_get_sprite(size_t spriteIndex);
rct_sprite* get_sprite(size_t sprite_idx);
template<typename T> T* GetEntity(size_t sprite_idx)
{
auto spr = reinterpret_cast<SpriteBase*>(get_sprite(sprite_idx));
if (spr == nullptr)
return nullptr;
return spr->As<T>();
}
SpriteBase* GetEntity(size_t sprite_idx);
extern uint16_t gSpriteListHead[SPRITE_LIST_COUNT];
extern uint16_t gSpriteListCount[SPRITE_LIST_COUNT];