From b6c73f8bef1fac7abc8d1040b5e2628d186d96ad Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Tue, 15 Nov 2016 20:35:45 +0000 Subject: [PATCH] Refactor place scenery --- src/world/map.c | 377 +++++++++++++++++++++++++++--------------------- 1 file changed, 213 insertions(+), 164 deletions(-) diff --git a/src/world/map.c b/src/world/map.c index edaf1c2266..108f7d4652 100644 --- a/src/world/map.c +++ b/src/world/map.c @@ -3014,191 +3014,240 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi int y = (uint16)*ecx; uint8 colour2 = *edi >> 16; uint8 rotation = *edi; - int z = *ebp; uint8 scenery_type = *ebx >> 8; uint8 flags = *ebx & 0xFF; uint8 quadrant = *edx; uint8 colour1 = *edx >> 8; money32 clearCost = 0; - int F64F1D = 0; - int F64EC8 = z; + bool isOnWater = false; + int targetHeight = *ebp; + bool supportsRequired = false; + if (targetHeight != 0) { + supportsRequired = true; + } int base_height = map_element_height(x, y); + // If on water if(base_height & 0xFFFF0000){ base_height >>= 16; } gCommandPosition.x = x; gCommandPosition.y = y; gCommandPosition.z = base_height; - if(F64EC8){ - base_height = F64EC8; + if(targetHeight != 0){ + base_height = targetHeight; gCommandPosition.z = base_height; } gCommandPosition.x += 16; gCommandPosition.y += 16; - if(game_is_not_paused() || gCheatsBuildInPauseMode){ - 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)){ - if(scenery_entry->small_scenery.flags & (SMALL_SCENERY_FLAG9 | SMALL_SCENERY_FLAG24 | SMALL_SCENERY_FLAG25)){ - quadrant = 0; - } - } - int x2 = x; - int y2 = y; - if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){ - x2 += 16; - y2 += 16; - }else{ - x2 += ScenerySubTileOffsets[quadrant & 3].x - 1; - y2 += ScenerySubTileOffsets[quadrant & 3].y - 1; - } - int base_height2 = map_element_height(x2, y2); - if(base_height2 & 0xFFFF0000){ - base_height2 >>= 16; - if(F64EC8 == 0){ - F64F1D = 1; - } - } - if(F64EC8 == 0){ - F64EC8 = base_height2; - } - if(!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(x, y, F64EC8)){ - *ebx = MONEY32_UNDEFINED; - return; - } - if(flags & GAME_COMMAND_FLAG_APPLY && !(flags & 0x40)){ - footpath_remove_litter(x, y, F64EC8); - if(!gCheatsDisableClearanceChecks && (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_ALLOW_WALLS)) { - map_remove_walls_at(x, y, F64EC8, F64EC8 + scenery_entry->small_scenery.height); - } - } - rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); - while(map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SURFACE){ - map_element++; - } - if(!gCheatsDisableClearanceChecks && (map_element->properties.surface.terrain & 0x1F)){ - int water_height = ((map_element->properties.surface.terrain & 0x1F) * 16) - 1; - if(water_height > F64EC8){ - gGameCommandErrorText = STR_CANT_BUILD_THIS_UNDERWATER; - *ebx = MONEY32_UNDEFINED; - return; - } - } - if(!gCheatsDisableClearanceChecks && !(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG18)){ - if(F64F1D != 0){ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; - *ebx = MONEY32_UNDEFINED; - return; - } - if(map_element->properties.surface.terrain & 0x1F){ - if(((map_element->properties.surface.terrain & 0x1F) * 16) > F64EC8){ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; - *ebx = MONEY32_UNDEFINED; - return; - } - } - } - if(gCheatsDisableClearanceChecks || !(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE) || z != 0 || F64F1D != 0 || !(map_element->properties.surface.slope & 0x1F)){ - if(gCheatsDisableSupportLimits || scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG18 || z == 0){ - l_6E0B78: ; - int bp = quadrant; - int zLow = F64EC8 / 8; - int zHigh = zLow + ((scenery_entry->small_scenery.height + 7) / 8); - int bl = 0xF; - if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)){ - bp ^= 2; - bl = 1; - bl <<= bp; - } - if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG24)){ - if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9 && scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){ - if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG25){ - bp ^= 2; - bp += rotation; - bp &= 3; - bl = 0xBB; - bl = rol8(bl, bp); - bl &= 0xF; - }else{ - bp += rotation; - bp &= 1; - bl = 0xA; - bl >>= bp; - } - } - }else{ - bp ^= 2; - bp += rotation; - bp &= 3; - bl = 0x33; - bl = rol8(bl, bp); - bl &= 0xF; - } - if(z == 0){ - bl |= 0xF0; - } - if(gCheatsDisableClearanceChecks || map_can_construct_with_clear_at(x, y, zLow, zHigh, &map_place_scenery_clear_func, bl, flags, &clearCost)){ - gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_1 | ELEMENT_IS_UNDERGROUND); - if(flags & GAME_COMMAND_FLAG_APPLY){ - if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) { - rct_xyz16 coord; - coord.x = x + 16; - coord.y = y + 16; - coord.z = map_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - } - int collisionQuadrants = (bl & 0xf); - rct_map_element* new_map_element = map_element_insert(x / 32, y / 32, zLow, collisionQuadrants); - assert(new_map_element != NULL); - gSceneryMapElement = new_map_element; - uint8 type = quadrant << 6; - type |= MAP_ELEMENT_TYPE_SCENERY; - type |= rotation; - new_map_element->type = type; - new_map_element->properties.scenery.type = scenery_type; - new_map_element->properties.scenery.age = 0; - new_map_element->properties.scenery.colour_1 = colour1; - new_map_element->properties.scenery.colour_2 = colour2; - new_map_element->clearance_height = new_map_element->base_height + ((scenery_entry->small_scenery.height + 7) / 8); - if(z != 0){ - new_map_element->properties.scenery.colour_1 |= 0x20; - } - if(flags & 0x40){ - new_map_element->flags |= 0x10; - } - map_invalidate_tile_full(x, y); - if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_ANIMATED){ - map_animation_create(2, x, y, new_map_element->base_height); - } - } - *ebx = (scenery_entry->small_scenery.price * 10) + clearCost; - if(gParkFlags & PARK_FLAGS_NO_MONEY){ - *ebx = 0; - } - return; - } - }else{ - if(F64F1D == 0){ - if((map_element->properties.surface.terrain & 0x1F) || (map_element->base_height * 8) != F64EC8){ - gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED; - }else{ - goto l_6E0B78; - } - }else{ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; - } - } - }else{ - gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED; - } + if (game_is_paused() && !gCheatsBuildInPauseMode) { + gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (!map_check_free_elements_and_reorganise(1)) { + *ebx = MONEY32_UNDEFINED; + return; + } + + if (!(byte_9D8150 & 1) && (x > gMapSizeMaxXY || y > gMapSizeMaxXY)) { + *ebx = MONEY32_UNDEFINED; + return; + } + + 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)){ + if(scenery_entry->small_scenery.flags & (SMALL_SCENERY_FLAG9 | SMALL_SCENERY_FLAG24 | SMALL_SCENERY_FLAG25)){ + quadrant = 0; + } + } + + // Check if sub tile height is any different compared to actual surface tile height + int x2 = x; + int y2 = y; + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){ + x2 += 16; + y2 += 16; + }else{ + x2 += ScenerySubTileOffsets[quadrant & 3].x - 1; + y2 += ScenerySubTileOffsets[quadrant & 3].y - 1; + } + base_height = map_element_height(x2, y2); + // If on water + if(base_height & 0xFFFF0000){ + // base_height2 is now the water height + base_height >>= 16; + if(targetHeight == 0){ + isOnWater = true; + } + } + if(targetHeight == 0){ + targetHeight = base_height; + } + + if(!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && + !gCheatsSandboxMode && + !map_is_location_owned(x, y, targetHeight)){ + + *ebx = MONEY32_UNDEFINED; + return; + } + + if(flags & GAME_COMMAND_FLAG_APPLY && !(flags & 0x40)){ + footpath_remove_litter(x, y, targetHeight); + if(!gCheatsDisableClearanceChecks && (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_ALLOW_WALLS)) { + map_remove_walls_at(x, y, targetHeight, targetHeight + scenery_entry->small_scenery.height); + } + } + + rct_map_element* surface_element = map_get_surface_element_at(x / 32, y / 32); + + if(!gCheatsDisableClearanceChecks && (surface_element->properties.surface.terrain & 0x1F)){ + int water_height = ((surface_element->properties.surface.terrain & 0x1F) * 16) - 1; + if(water_height > targetHeight){ + gGameCommandErrorText = STR_CANT_BUILD_THIS_UNDERWATER; + *ebx = MONEY32_UNDEFINED; + return; + } + } + + if(!gCheatsDisableClearanceChecks && !(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG18)){ + if(isOnWater){ + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + *ebx = MONEY32_UNDEFINED; + return; + } + + if(surface_element->properties.surface.terrain & 0x1F){ + if(((surface_element->properties.surface.terrain & 0x1F) * 16) > targetHeight){ + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + *ebx = MONEY32_UNDEFINED; + return; + } + } + } + + if (!gCheatsDisableClearanceChecks && + (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE) && + !supportsRequired && + !isOnWater && + (surface_element->properties.surface.slope & 0x1F)) { + + gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (!gCheatsDisableSupportLimits && + !(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG18) && + supportsRequired) { + + if(!isOnWater){ + if((surface_element->properties.surface.terrain & 0x1F) || + (surface_element->base_height * 8) != targetHeight){ + + gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED; + *ebx = MONEY32_UNDEFINED; + return; + } + + }else{ + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + *ebx = MONEY32_UNDEFINED; + return; + } + } + + int bp = quadrant; + int zLow = targetHeight / 8; + int zHigh = zLow + ((scenery_entry->small_scenery.height + 7) / 8); + int bl = 0xF; + if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)){ + bp ^= 2; + bl = 1; + bl <<= bp; + } + if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG24)){ + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9 && scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){ + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG25){ + bp ^= 2; + bp += rotation; + bp &= 3; + bl = 0xBB; + bl = rol8(bl, bp); + bl &= 0xF; + }else{ + bp += rotation; + bp &= 1; + bl = 0xA; + bl >>= bp; } } }else{ - gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + bp ^= 2; + bp += rotation; + bp &= 3; + bl = 0x33; + bl = rol8(bl, bp); + bl &= 0xF; + } + if(!supportsRequired){ + bl |= 0xF0; + } + + if (!gCheatsDisableClearanceChecks && + !map_can_construct_with_clear_at(x, y, zLow, zHigh, &map_place_scenery_clear_func, bl, flags, &clearCost)) { + *ebx = MONEY32_UNDEFINED; + return; + } + + gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_1 | ELEMENT_IS_UNDERGROUND); + + *ebx = (scenery_entry->small_scenery.price * 10) + clearCost; + if(gParkFlags & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } + + if (!flags & GAME_COMMAND_FLAG_APPLY) { + return; + } + + if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) { + rct_xyz16 coord; + coord.x = x + 16; + coord.y = y + 16; + coord.z = map_element_height(coord.x, coord.y); + network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); + } + + int collisionQuadrants = (bl & 0xf); + rct_map_element* new_map_element = map_element_insert(x / 32, y / 32, zLow, collisionQuadrants); + assert(new_map_element != NULL); + gSceneryMapElement = new_map_element; + uint8 type = quadrant << 6; + type |= MAP_ELEMENT_TYPE_SCENERY; + type |= rotation; + new_map_element->type = type; + new_map_element->properties.scenery.type = scenery_type; + new_map_element->properties.scenery.age = 0; + new_map_element->properties.scenery.colour_1 = colour1; + new_map_element->properties.scenery.colour_2 = colour2; + new_map_element->clearance_height = new_map_element->base_height + ((scenery_entry->small_scenery.height + 7) / 8); + + if(supportsRequired){ + new_map_element->properties.scenery.colour_1 |= 0x20; + } + + if(flags & GAME_COMMAND_FLAG_GHOST){ + new_map_element->flags |= MAP_ELEMENT_FLAG_GHOST; + } + + map_invalidate_tile_full(x, y); + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_ANIMATED){ + map_animation_create(2, x, y, new_map_element->base_height); } - *ebx = MONEY32_UNDEFINED; } static bool map_is_location_at_edge(int x, int y)