From 9ee4b64fa110e37830f61da747cbe0cceb45376b Mon Sep 17 00:00:00 2001 From: zsilencer Date: Tue, 12 May 2015 13:08:36 -0600 Subject: [PATCH] game_command_place_scenery --- src/game.c | 4 +- src/game.h | 2 +- src/ride/track.c | 2 +- src/windows/top_toolbar.c | 2 +- src/world/map.c | 189 ++++++++++++++++++++++++++++++++++++++ src/world/map.h | 1 + 6 files changed, 195 insertions(+), 5 deletions(-) diff --git a/src/game.c b/src/game.c index 9a099c0ec7..f54569d783 100644 --- a/src/game.c +++ b/src/game.c @@ -900,7 +900,7 @@ static uint32 game_do_command_table[58] = { 0x006660A8, 0x0066640B, 0, - 0x006E08F4, + 0, 0x006E650F, 0, 0x006A68AE, @@ -963,7 +963,7 @@ static GAME_COMMAND_POINTER* new_game_command_table[58] = { game_command_emptysub, game_command_emptysub, game_command_remove_scenery, - game_command_emptysub, + game_command_place_scenery, game_command_emptysub, game_command_place_footpath, game_command_emptysub, diff --git a/src/game.h b/src/game.h index 102bd7d1c5..2b2e4cf914 100644 --- a/src/game.h +++ b/src/game.h @@ -39,7 +39,7 @@ enum GAME_COMMAND { GAME_COMMAND_12, GAME_COMMAND_13, GAME_COMMAND_REMOVE_SCENERY, - GAME_COMMAND_15, + GAME_COMMAND_PLACE_SCENERY, GAME_COMMAND_16, GAME_COMMAND_PLACE_PATH, // 17 GAME_COMMAND_18, diff --git a/src/ride/track.c b/src/ride/track.c index 41f3b395b6..31a473102c 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -1169,7 +1169,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o bl | (entry_index << 8), mapCoord.y, quadrant | (scenery->primary_colour << 8), - GAME_COMMAND_15, + GAME_COMMAND_PLACE_SCENERY, rotation | (scenery->secondary_colour << 16), z ); diff --git a/src/windows/top_toolbar.c b/src/windows/top_toolbar.c index e2984ac975..1489f651ab 100644 --- a/src/windows/top_toolbar.c +++ b/src/windows/top_toolbar.c @@ -1356,7 +1356,7 @@ static void window_top_toolbar_scenery_tool_down(short x, short y, rct_window* w RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1161; - int cost = game_do_command(cur_grid_x, ebx, cur_grid_y, parameter_2, GAME_COMMAND_15, RCT2_GLOBAL(0x00F64EC0, uint8) | (parameter_3 & 0xFFFF0000), RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16)); + int cost = game_do_command(cur_grid_x, ebx, cur_grid_y, parameter_2, GAME_COMMAND_PLACE_SCENERY, RCT2_GLOBAL(0x00F64EC0, uint8) | (parameter_3 & 0xFFFF0000), RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16)); RCT2_GLOBAL(0x009A8C29, uint8) &= ~1; diff --git a/src/world/map.c b/src/world/map.c index b328292405..32d7f39ad4 100644 --- a/src/world/map.c +++ b/src/world/map.c @@ -1814,6 +1814,195 @@ void game_command_place_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi, *ebx = MONEY32_UNDEFINED; } +/** + * + * rct2: 0x006E08F4 + */ +void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + RCT2_GLOBAL(0x141F56C, uint8) = 12; + int x = (uint16)*eax; + int y = (uint16)*ecx; + uint8 color2 = *edi >> 16; + uint8 rotation = *edi; + int z = *ebp; + uint8 scenery_type = *ebx >> 8; + uint8 quadrant = *edx; + uint8 color1 = *edx >> 8; + int F64F1D = 0; + int F64EC8 = z; + int base_height = map_element_height(x, y); + if(base_height & 0xFFFF0000){ + base_height >>= 16; + } + RCT2_GLOBAL(0x009DEA5E, uint16) = x; + RCT2_GLOBAL(0x009DEA60, uint16) = y; + RCT2_GLOBAL(0x009DEA62, uint16) = base_height; + if(F64EC8){ + base_height = F64EC8; + RCT2_GLOBAL(0x009DEA62, uint16) = base_height; + } + RCT2_GLOBAL(0x009DEA5E, uint16) += 16; + RCT2_GLOBAL(0x009DEA60, uint16) += 16; + if(RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0){ + if(sub_68B044()){ + if(RCT2_GLOBAL(0x009D8150, uint8) & 1 || (x <= RCT2_GLOBAL(0x01358836, uint16) && y <= RCT2_GLOBAL(0x01358836, uint16))){ + 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 | SMALL_SCENERY_FLAG24 | SMALL_SCENERY_FLAG25)) || scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9){ + base_height = 0; + } + int x2 = x; + int y2 = y; + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){ + x2 += 16; + y2 += 16; + }else{ + x2 += RCT2_ADDRESS(0x009A3E74, uint8)[(quadrant & 3) * 2] - 1; + y2 += RCT2_ADDRESS(0x009A3E75, uint8)[(quadrant & 3) * 2] - 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(!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_owned(x, y, F64EC8)){ + *ebx = MONEY32_UNDEFINED; + return; + } + if(*ebx & GAME_COMMAND_FLAG_APPLY && !(*ebx & 0x40)){ + sub_673883(x, y, F64EC8); + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG19){ + RCT2_CALLPROC_X(0x006E588E, x, scenery_entry->small_scenery.height, y, F64EC8, 0, 0, 0); + } + } + 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(map_element->properties.surface.terrain & 0x1F){ + int water_height = ((map_element->properties.surface.terrain & 0x1F) * 16) - 1; + if(water_height > F64EC8){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CANT_BUILD_THIS_UNDERWATER; + *ebx = MONEY32_UNDEFINED; + return; + } + } + if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG18)){ + if(F64F1D != 0){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 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){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + *ebx = MONEY32_UNDEFINED; + return; + } + } + } + if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE) || z != 0 || F64F1D != 0 || !(map_element->properties.surface.slope & 0x1F)){ + if(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){ + // this stuff that uses rol and ror are untested, couldnt find any scenery with these flags + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG25){ + bp ^= 2; + bp += rotation; + bp &= 3; + bl = 0xBB; + bl = (bl << bp) | (bl >> (8 - bp)); //rol + bl &= 0xF; + }else{ + bp += rotation; + bp &= 1; + bl = 0xA; + bl = (bl >> bp) | (bl << (8 - bp)); //ror + } + } + }else{ + bp ^= 2; + bp += rotation; + bp &= 3; + bl = 0x33; + bl = (bl << bp) | (bl >> (8 - bp)); //rol + bl &= 0xF; + } + if(z == 0){ + bl |= 0xF0; + } + RCT2_GLOBAL(0x00F64F22, uint16) = x; + RCT2_GLOBAL(0x00F64F24, uint16) = y; + RCT2_GLOBAL(0x00F64F1E, uint32) = (uint32)(ebx - 1); //0x006E0D6E uses [F64F1E+4] to read ebx value + if(map_can_construct_with_clear_at(x, y, zLow, zHigh, (void*)0x006E0D6E, bl)){ + RCT2_GLOBAL(0x00F64F14, uint8) = RCT2_GLOBAL(0x00F1AD60, uint8) & 0x3; + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + int flags = (bl & 0xf); + rct_map_element* new_map_element = map_element_insert(x / 32, y / 32, zLow, flags); + RCT2_GLOBAL(0x00F64EBC, rct_map_element*) = 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 = color1; + new_map_element->properties.scenery.colour_2 = color2; + 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(*ebx & 0x40){ + new_map_element->flags |= 0x10; + } + map_invalidate_tile_full(x, y); + if(scenery_entry->small_scenery.flags & 0x10){ + map_animation_create(2, x, y, new_map_element->base_height); + } + } + *ebx = (scenery_entry->small_scenery.price * 10); + if(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } + return; + } + }else{ + if(F64F1D == 0){ + if((map_element->properties.surface.terrain & 0x1F) || (map_element->base_height * 8) != F64EC8){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_LEVEL_LAND_REQUIRED; + }else{ + goto l_6E0B78; + } + }else{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + } + } + }else{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_LEVEL_LAND_REQUIRED; + } + } + } + }else{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + } + *ebx = MONEY32_UNDEFINED; +} + /** * * rct2: 0x006EC6D7 diff --git a/src/world/map.h b/src/world/map.h index 5d2f9985a1..6e3ba65b85 100644 --- a/src/world/map.h +++ b/src/world/map.h @@ -295,6 +295,7 @@ void game_command_raise_water(int* eax, int* ebx, int* ecx, int* edx, int* esi, void game_command_lower_water(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); void game_command_remove_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); void game_command_place_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); #define GET_MAP_ELEMENT(x) (&(RCT2_ADDRESS(RCT2_ADDRESS_MAP_ELEMENTS, rct_map_element)[x])) #define TILE_MAP_ELEMENT_POINTER(x) (RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[x])