Fix #4777: Check for enough free elements before placement

Previously multi tiled placements would only check for one free element before placing. This would cause a crash when it failed to allocate the next element on maps that were close to reaching their full capacity. Renamed sub_68B044 to map_check_free_elements_and_organise and gave it an argument value to check for enough free elements.
This commit is contained in:
Duncan 2016-11-13 22:44:08 +00:00 committed by Ted John
parent 4039172fb7
commit 6a90f9eb40
6 changed files with 34 additions and 29 deletions

View File

@ -8183,7 +8183,7 @@ static money32 place_ride_entrance_or_exit(sint16 x, sint16 y, sint16 z, uint8 d
gCommandPosition.x = x;
gCommandPosition.y = y;
if (!sub_68B044()) {
if (!map_check_free_elements_and_reorganise(1)) {
return MONEY32_UNDEFINED;
}

View File

@ -946,9 +946,7 @@ static money32 track_place(int rideIndex, int type, int originX, int originY, in
gGameCommandErrorText = STR_NOT_ALLOWED_TO_MODIFY_STATION;
return MONEY32_UNDEFINED;
}
if (!sub_68B044()) {
return MONEY32_UNDEFINED;
}
if (!(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED)) {
if (game_is_paused() && !gCheatsBuildInPauseMode) {
gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED;
@ -983,7 +981,7 @@ static money32 track_place(int rideIndex, int type, int originX, int originY, in
money32 cost = 0;
const rct_preview_track *trackBlock = get_track_def_from_ride(ride, type);
uint32 num_elements = 0;
// First check if any of the track pieces are outside the park
for (; trackBlock->index != 0xFF; trackBlock++) {
int x, y, z, offsetX, offsetY;
@ -1015,8 +1013,12 @@ static money32 track_place(int rideIndex, int type, int originX, int originY, in
gGameCommandErrorText = STR_LAND_NOT_OWNED_BY_PARK;
return MONEY32_UNDEFINED;
}
num_elements++;
}
if (!map_check_free_elements_and_reorganise(num_elements)) {
return MONEY32_UNDEFINED;
}
const uint16 *trackFlags = (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ?
FlatTrackFlags :
TrackFlags;
@ -1757,7 +1759,7 @@ static money32 set_maze_track(uint16 x, uint8 flags, uint8 direction, uint16 y,
money32 cost = 0;
if (!sub_68B044()) {
if (!map_check_free_elements_and_reorganise(1)) {
return MONEY32_UNDEFINED;
}

View File

@ -1558,7 +1558,7 @@ static money32 place_maze_design(uint8 flags, uint8 rideIndex, uint16 mazeEntry,
gCommandPosition.x = x + 8;
gCommandPosition.y = y + 8;
gCommandPosition.z = z;
if (!sub_68B044()) {
if (!map_check_free_elements_and_reorganise(1)) {
return MONEY32_UNDEFINED;
}

View File

@ -182,7 +182,7 @@ static money32 footpath_element_insert(int type, int x, int y, int z, int slope,
rct_map_element *mapElement;
int bl, zHigh;
if (!sub_68B044())
if (!map_check_free_elements_and_reorganise(1))
return MONEY32_UNDEFINED;
if ((flags & GAME_COMMAND_FLAG_APPLY) && !(flags & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST)))

View File

@ -2838,7 +2838,7 @@ void game_command_place_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi,
return;
}
if (!sub_68B044()) {
if (!map_check_free_elements_and_reorganise(1)) {
*ebx = MONEY32_UNDEFINED;
return;
}
@ -3036,7 +3036,7 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi
gCommandPosition.x += 16;
gCommandPosition.y += 16;
if(game_is_not_paused() || gCheatsBuildInPauseMode){
if (sub_68B044()) {
if (map_check_free_elements_and_reorganise(1)) {
if ((byte_9D8150 & 1) || (x <= gMapSizeMaxXY && y <= gMapSizeMaxXY)) {
rct_scenery_entry* scenery_entry = (rct_scenery_entry*)object_entry_groups[OBJECT_TYPE_SMALL_SCENERY].chunks[scenery_type];
if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE || !(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9)){
@ -3612,7 +3612,7 @@ void game_command_place_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi,
}
}
if (!sub_68B044()){
if (!map_check_free_elements_and_reorganise(1)){
*ebx = MONEY32_UNDEFINED;
return;
}
@ -3719,11 +3719,6 @@ void game_command_place_large_scenery(int* eax, int* ebx, int* ecx, int* edx, in
return;
}
if (!sub_68B044()) {
*ebx = MONEY32_UNDEFINED;
return;
}
rct_scenery_entry *scenery_entry = get_large_scenery_entry(entry_index);
if (scenery_entry == (rct_scenery_entry *)-1)
{
@ -3754,11 +3749,12 @@ void game_command_place_large_scenery(int* eax, int* ebx, int* ecx, int* edx, in
}
}
uint32 num_elements = 0;
sint16 maxHeight = 0xFFFF;
for (rct_large_scenery_tile* tile = scenery_entry->large_scenery.tiles;
tile->x_offset != -1;
tile++) {
num_elements++;
rct_xy16 curTile = {
.x = tile->x_offset,
@ -3769,7 +3765,7 @@ void game_command_place_large_scenery(int* eax, int* ebx, int* ecx, int* edx, in
curTile.x += x;
curTile.y += y;
if(curTile.x >= 0x1FFF || curTile.y >= 0x1FFF || curTile.x < 0 || curTile.y < 0){
continue;
}
@ -3794,6 +3790,11 @@ void game_command_place_large_scenery(int* eax, int* ebx, int* ecx, int* edx, in
if(z != 0){
maxHeight = z;
}
if (!map_check_free_elements_and_reorganise(num_elements)) {
*ebx = MONEY32_UNDEFINED;
return;
}
gCommandPosition.z = maxHeight;
uint8 tile_num = 0;
@ -4091,25 +4092,27 @@ void map_reorganise_elements()
/**
*
* rct2: 0x0068B044
* Returns true on space available for more elements
* Reorganises the map elements to check for space
*/
int sub_68B044()
bool map_check_free_elements_and_reorganise(int num_elements)
{
if (gNextFreeMapElement <= gMapElements + MAX_MAP_ELEMENTS)
return 1;
if ((gNextFreeMapElement + num_elements) <= gMapElements + MAX_MAP_ELEMENTS)
return true;
for (int i = 1000; i != 0; --i)
sub_68B089();
if (gNextFreeMapElement <= gMapElements + MAX_MAP_ELEMENTS)
return 1;
if ((gNextFreeMapElement + num_elements) <= gMapElements + MAX_MAP_ELEMENTS)
return true;
map_reorganise_elements();
if (gNextFreeMapElement <= gMapElements + MAX_MAP_ELEMENTS)
return 1;
if ((gNextFreeMapElement + num_elements) <= gMapElements + MAX_MAP_ELEMENTS)
return true;
else{
gGameCommandErrorText = STR_ERR_LANDSCAPE_DATA_AREA_FULL;
return 0;
return false;
}
}
@ -4121,7 +4124,7 @@ rct_map_element *map_element_insert(int x, int y, int z, int flags)
{
rct_map_element *originalMapElement, *newMapElement, *insertedElement;
if (!sub_68B044()) {
if (!map_check_free_elements_and_reorganise(1)) {
log_error("Cannot insert new element");
return NULL;
}
@ -5158,7 +5161,7 @@ static money32 place_park_entrance(int flags, sint16 x, sint16 y, sint16 z, uint
// ??
gCommandPosition.z = (z & 0xFF) << 4;
if (!sub_68B044()) {
if (!map_check_free_elements_and_reorganise(3)) {
return MONEY32_UNDEFINED;
}

View File

@ -428,7 +428,7 @@ void map_remove_all_rides();
void map_invalidate_map_selection_tiles();
void map_invalidate_selection_rect();
void map_reorganise_elements();
int sub_68B044();
bool map_check_free_elements_and_reorganise(int num_elements);
rct_map_element *map_element_insert(int x, int y, int z, int flags);
typedef int (CLEAR_FUNC)(rct_map_element** map_element, int x, int y, uint8 flags, money32* price);