Fix #5096: Crash on park with out of bounds sprite coordinates

This commit is contained in:
Michał Janiszewski 2017-01-28 22:12:07 +01:00 committed by Ted John
parent cb1911280a
commit f6cc743da6
2 changed files with 45 additions and 47 deletions

View file

@ -18,6 +18,7 @@
- Fix: [#4968] Completing a scenario does not save the name that is entered.
- Fix: [#4996] Objects unloaded after loading landscape.
- Fix: [#5003] Able to remove entrance/exit of unedittable rides (such as in Volcania).
- Fix: [#5096] Failure to open parks with out of bounds sprite coordinates.
- Fix: [#5114] Some entertainer costumes never select-able.
0.0.5 (2016-12-27)

View file

@ -14,7 +14,6 @@
*****************************************************************************/
#pragma endregion
#include "../rct2/addresses.h"
#include "../audio/audio.h"
#include "../cheats.h"
#include "../game.h"
@ -22,6 +21,7 @@
#include "../localisation/date.h"
#include "../localisation/localisation.h"
#include "../OpenRCT2.h"
#include "../rct2/addresses.h"
#include "../scenario/scenario.h"
#include "fountain.h"
#include "sprite.h"
@ -36,11 +36,15 @@ uint16 *gSpriteListCount = RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LISTS_COUNT, uint16)
static rct_sprite *_spriteList = RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite);
#endif
#define SPATIAL_INDEX_LOCATION_NULL 0x10000
uint16 gSpriteSpatialIndex[0x10001];
static rct_xyz16 _spritelocations1[MAX_SPRITES];
static rct_xyz16 _spritelocations2[MAX_SPRITES];
static size_t GetSpatialIndexOffset(sint32 x, sint32 y);
rct_sprite *get_sprite(size_t sprite_idx)
{
openrct2_assert(sprite_idx < MAX_SPRITES, "Tried getting sprite %u", sprite_idx);
@ -148,18 +152,11 @@ void reset_sprite_list()
*/
void reset_sprite_spatial_index()
{
memset(gSpriteSpatialIndex, -1, 0x10001 * sizeof(uint16));
memset(gSpriteSpatialIndex, -1, sizeof(gSpriteSpatialIndex));
for (size_t i = 0; i < MAX_SPRITES; i++) {
rct_sprite *spr = get_sprite(i);
if (spr->unknown.sprite_identifier != SPRITE_IDENTIFIER_NULL) {
uint32 index;
if (spr->unknown.x == SPRITE_LOCATION_NULL) {
index = 0x10000;
} else {
sint16 x = floor2(spr->unknown.x, 32);
uint8 tileY = spr->unknown.y >> 5;
index = (x << 3) | tileY;
}
size_t index = GetSpatialIndexOffset(spr->unknown.x, spr->unknown.y);
uint16 nextSpriteId = gSpriteSpatialIndex[index];
gSpriteSpatialIndex[index] = spr->unknown.sprite_index;
spr->unknown.next_in_quadrant = nextSpriteId;
@ -167,6 +164,22 @@ void reset_sprite_spatial_index()
}
}
static size_t GetSpatialIndexOffset(sint32 x, sint32 y)
{
size_t index = SPATIAL_INDEX_LOCATION_NULL;
if (x != SPRITE_LOCATION_NULL) {
x = clamp(0, x, 0xFFFF);
y = clamp(0, y, 0xFFFF);
sint16 flooredX = floor2(x, 32);
uint8 tileY = y >> 5;
index = (flooredX << 3) | tileY;
}
openrct2_assert(index < sizeof(gSpriteSpatialIndex), "GetSpatialIndexOffset out of range");
return index;
}
#ifndef DISABLE_NETWORK
static uint8 _spriteChecksum[EVP_MAX_MD_SIZE + 1];
@ -289,8 +302,8 @@ rct_sprite *create_sprite(uint8 bl)
sprite->flags = 0;
sprite->sprite_left = SPRITE_LOCATION_NULL;
sprite->next_in_quadrant = gSpriteSpatialIndex[0x10000];
gSpriteSpatialIndex[0x10000] = sprite->sprite_index;
sprite->next_in_quadrant = gSpriteSpatialIndex[SPATIAL_INDEX_LOCATION_NULL];
gSpriteSpatialIndex[SPATIAL_INDEX_LOCATION_NULL] = sprite->sprite_index;
return (rct_sprite*)sprite;
}
@ -495,46 +508,36 @@ void sprite_misc_update_all()
* @param z (dx)
* @param sprite (esi)
*/
void sprite_move(sint16 x, sint16 y, sint16 z, rct_sprite* sprite){
if (x < 0 || y < 0 || x > 0x1FFF || y > 0x1FFF)
void sprite_move(sint16 x, sint16 y, sint16 z, rct_sprite *sprite)
{
if (x < 0 || y < 0 || x > 0x1FFF || y > 0x1FFF) {
x = SPRITE_LOCATION_NULL;
sint32 new_position = x;
if (x == SPRITE_LOCATION_NULL)new_position = 0x10000;
else{
new_position &= 0x1FE0;
new_position = (y >> 5) | (new_position << 3);
}
sint32 current_position = sprite->unknown.x;
if (sprite->unknown.x == SPRITE_LOCATION_NULL)current_position = 0x10000;
else{
current_position &= 0x1FE0;
current_position = (sprite->unknown.y >> 5) | (current_position << 3);
}
if (new_position != current_position){
uint16* sprite_idx = &gSpriteSpatialIndex[current_position];
rct_sprite* sprite2 = get_sprite(*sprite_idx);
while (sprite != sprite2){
sprite_idx = &sprite2->unknown.next_in_quadrant;
sprite2 = get_sprite(*sprite_idx);
size_t newIndex = GetSpatialIndexOffset(x, y);
size_t currentIndex = GetSpatialIndexOffset(sprite->unknown.x, sprite->unknown.y);
if (newIndex != currentIndex) {
uint16 *spriteIndex = &gSpriteSpatialIndex[currentIndex];
rct_sprite *sprite2 = get_sprite(*spriteIndex);
while (sprite != sprite2) {
spriteIndex = &sprite2->unknown.next_in_quadrant;
sprite2 = get_sprite(*spriteIndex);
}
*sprite_idx = sprite->unknown.next_in_quadrant;
*spriteIndex = sprite->unknown.next_in_quadrant;
sint32 temp_sprite_idx = gSpriteSpatialIndex[new_position];
gSpriteSpatialIndex[new_position] = sprite->unknown.sprite_index;
sprite->unknown.next_in_quadrant = temp_sprite_idx;
sint32 tempSpriteIndex = gSpriteSpatialIndex[newIndex];
gSpriteSpatialIndex[newIndex] = sprite->unknown.sprite_index;
sprite->unknown.next_in_quadrant = tempSpriteIndex;
}
if (x == SPRITE_LOCATION_NULL){
if (x == SPRITE_LOCATION_NULL) {
sprite->unknown.sprite_left = SPRITE_LOCATION_NULL;
sprite->unknown.x = x;
sprite->unknown.y = y;
sprite->unknown.z = z;
return;
} else {
sprite_set_coordinates(x, y, z, sprite);
}
sprite_set_coordinates(x, y, z, sprite);
}
void sprite_set_coordinates(sint16 x, sint16 y, sint16 z, rct_sprite *sprite){
@ -577,13 +580,7 @@ void sprite_remove(rct_sprite *sprite)
user_string_free(sprite->unknown.name_string_idx);
sprite->unknown.sprite_identifier = SPRITE_IDENTIFIER_NULL;
uint32 quadrantIndex = sprite->unknown.x;
if (sprite->unknown.x == SPRITE_LOCATION_NULL) {
quadrantIndex = 0x10000;
} else {
quadrantIndex = (floor2(sprite->unknown.x, 32) << 3) | (sprite->unknown.y >> 5);
}
size_t quadrantIndex = GetSpatialIndexOffset(sprite->unknown.x, sprite->unknown.y);
uint16 *spriteIndex = &gSpriteSpatialIndex[quadrantIndex];
rct_sprite *quadrantSprite;
while ((quadrantSprite = get_sprite(*spriteIndex)) != sprite) {