From 3a8f85b7d24aba9d074aac30107f3f4b66ea7c00 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Thu, 18 Dec 2014 22:31:05 +0000 Subject: [PATCH 1/2] implement footpath remove and create, bugs exist --- src/game.c | 8 +- src/windows/footpath.c | 2 +- src/world/footpath.c | 353 ++++++++++++++++++++++++++++++++++++++++- src/world/footpath.h | 2 + 4 files changed, 358 insertions(+), 7 deletions(-) diff --git a/src/game.c b/src/game.c index 07e8fba1a7..9befcfdf14 100644 --- a/src/game.c +++ b/src/game.c @@ -875,9 +875,9 @@ static uint32 game_do_command_table[58] = { 0x006E0E01, 0x006E08F4, 0x006E650F, - 0x006A61DE, + 0, 0x006A68AE, - 0x006A67C0, + 0, 0, // use new_game_command_table, original: 0x00663CCD, // 20 0x006B53E9, 0x00698D6C, // text input @@ -938,9 +938,9 @@ static GAME_COMMAND_POINTER* new_game_command_table[58] = { game_command_emptysub, game_command_emptysub, game_command_emptysub, + game_command_place_footpath, game_command_emptysub, - game_command_emptysub, - game_command_emptysub, + game_command_remove_footpath, game_command_change_surface_style, // 20 game_command_emptysub, game_command_emptysub, diff --git a/src/windows/footpath.c b/src/windows/footpath.c index 43fbc96495..6796dc2257 100644 --- a/src/windows/footpath.c +++ b/src/windows/footpath.c @@ -703,7 +703,7 @@ static void window_footpath_place_path_at_point(int x, int y) // Try and place path RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_CANT_BUILD_FOOTPATH_HERE; - cost = footpath_place(selectedType, x, y, z, presentType, (1 << 0)); + cost = footpath_place(selectedType, x, y, z, presentType, GAME_COMMAND_FLAG_APPLY); if (cost == MONEY32_UNDEFINED) { RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 1; diff --git a/src/world/footpath.c b/src/world/footpath.c index 9d995daafc..09960e21ae 100644 --- a/src/world/footpath.c +++ b/src/world/footpath.c @@ -20,9 +20,358 @@ #include "../addresses.h" #include "../game.h" +#include "../localisation/localisation.h" #include "footpath.h" #include "map.h" +enum { + FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED = 1 << 3 +}; + +/** + * + * rct2: 0x006A65AD + */ +static void automatically_set_peep_spawn(int x, int y, int z) +{ + rct2_peep_spawn *peepSpawn = (rct2_peep_spawn*)RCT2_ADDRESS_PEEP_SPAWNS; + int direction = 0; + if (x != 32) { + direction++; + if (y != RCT2_GLOBAL(0x001358830, uint16) - 32) { + direction++; + if (x != RCT2_GLOBAL(0x001358830, uint16) - 32) { + direction++; + if (y != 32) + return; + } + } + } + + peepSpawn->x = (RCT2_GLOBAL(0x00981D6C + (direction * 4), uint16) * 15) + 16; + peepSpawn->y = (RCT2_GLOBAL(0x00981D6E + (direction * 4), uint16) * 15) + 16; + peepSpawn->direction = direction; + peepSpawn->z = z / 2; +} + +rct_map_element *map_get_footpath_element(int x, int y, int z) +{ + rct_map_element *mapElement; + + mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + do { + if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH && mapElement->base_height == z) + return mapElement; + } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + + return NULL; +} + +rct_map_element *map_get_footpath_element_slope(int x, int y, int z, int slope) +{ + rct_map_element *mapElement; + + mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + do { + if ( + (mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH && + mapElement->base_height == z && + (mapElement->properties.path.type & 7) == slope + ) { + return mapElement; + } + } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + + return NULL; +} + +static money32 footpath_element_insert(int type, int x, int y, int z, int slope, int flags) +{ + rct_map_element *mapElement; + int bl, zHigh; + + if (!sub_68B044()) + return MONEY32_UNDEFINED; + + if ((flags & GAME_COMMAND_FLAG_APPLY) && !(flags & ((1 << 3) | (1 << 6)))) + RCT2_CALLPROC_X(0x00673883, x, 0, y, RCT2_GLOBAL(0x009DEA62, uint16), 0, 0, 0); + + // loc_6A649D: + RCT2_GLOBAL(0x00F3EFD9, money32) += MONEY(12, 00); + + bl = 15; + zHigh = z + 4; + if (slope & 4) { + bl = RCT2_ADDRESS(0x0098D7EC, uint8)[slope & 3]; + zHigh += 2; + } + + RCT2_GLOBAL(0x00F3EF84, uint16) = x; + RCT2_GLOBAL(0x00F3EF86, uint16) = y; + + // Ugh, hack until 0x006A6733 is written + RCT2_GLOBAL(0x00F3EF7C, uint32) = (uint32)(&flags - 8); + + if (!map_can_construct_with_clear_at(x, y, z, zHigh, (void*)0x006A6733, bl)) + return MONEY32_UNDEFINED; + + RCT2_GLOBAL(0x00F3EFA4, uint8) = RCT2_GLOBAL(0x00F1AD60, uint8); + if (RCT2_GLOBAL(0x00F1AD60, uint8) & 4) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CANT_BUILD_THIS_UNDERWATER; + return MONEY32_UNDEFINED; + } + + mapElement = map_get_surface_element_at((x / 32), (y / 32)); + + int supportHeight = z - mapElement->base_height; + RCT2_GLOBAL(0x00F3EFD9, money32) += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / 2) * MONEY(5, 00); + + if (flags & GAME_COMMAND_FLAG_APPLY) { + mapElement = map_element_insert(x / 32, y / 32, z, 0x0F); + mapElement->type = MAP_ELEMENT_TYPE_PATH; + mapElement->clearance_height = z + 4 + (slope & 4 ? 2 : 0); + mapElement->properties.path.type = (type << 4) | (slope & 7); + mapElement->type |= type >> 7; + mapElement->properties.path.additions = RCT2_GLOBAL(0x00F3EF88, uint8); + mapElement->properties.path.addition_status = 255; + mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; + if (flags & (1 << 6)) + mapElement->flags |= 1 << 4; + + RCT2_GLOBAL(0x00F3EFF4, uint32) = 0x00F3EFF8; + + if (!(flags & (1 << 7))) + sub_6A6AA7(x, y, mapElement); + + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !(flags & (1 << 6))) + automatically_set_peep_spawn(x, y, mapElement->base_height / 2); + + if (!(mapElement->properties.path.type & 4) && !(flags & (1 << 6))) { + int ttt = mapElement->properties.path.type; + z = mapElement->base_height; + RCT2_CALLPROC_X(0x006E5935, x, (ttt & 3) ^ 2, y, ((z + 6) << 8) | z, 0, 0, 0); + RCT2_CALLPROC_X(0x006E5935, x, (ttt & 3), y, ((z + 6) << 8) | z, 0, 0, 0); + mapElement = map_get_footpath_element(x / 32, y / 32, z); + } + + if (!(flags & (1 << 7))) + RCT2_CALLPROC_X(0x006A6C66, x, flags, y, 0, (int)mapElement, 0, 0); + + RCT2_CALLPROC_EBPSAFE(0x006A759F); + map_invalidate_tile_full(x, y); + } + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); +} + +static money32 footpath_element_update(int x, int y, rct_map_element *mapElement, int type, int flags) +{ + if ((mapElement->properties.path.type >> 4) != (type & 0x0F) || (mapElement->type & 1) != (type >> 7)) { + RCT2_GLOBAL(0x00F3EFD9, money32) += MONEY(6, 00); + } else if (RCT2_GLOBAL(0x00F3EF88, uint16) != 0) { + if ( + !(flags & (1 << 6)) && + (mapElement->properties.path.additions & 0x0F) == RCT2_GLOBAL(0x00F3EF88, uint16) && + !(mapElement->flags & MAP_ELEMENT_FLAG_BROKEN) + ) { + if (flags & (1 << 4)) + return MONEY32_UNDEFINED; + + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); + } + + if (RCT2_GLOBAL(0x00F3EF88, uint16) != 0) { + uint8 *unk = RCT2_ADDRESS(0x009ADA50, uint8*)[RCT2_GLOBAL(0x00F3EF88, uint16)]; + uint16 unk6 = RCT2_GLOBAL(unk + 6, uint16); + + if ((unk6 & 0x80) && (mapElement->properties.path.type & 4)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH; + return MONEY32_UNDEFINED; + } + + if ((unk6 & 0x40) && (mapElement->type & 1)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA; + return MONEY32_UNDEFINED; + } + + if ((unk6 & 0x30) && (mapElement->properties.path.edges & 0x0F) == 0x0F) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_NONE; + return MONEY32_UNDEFINED; + } + + if ((unk6 & 0x100) && !(mapElement->type & 1)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA; + return MONEY32_UNDEFINED; + } + + RCT2_GLOBAL(0x00F3EFD9, money32) += RCT2_GLOBAL(unk + 10, money16); + } + + if (flags & (1 << 4)) + return MONEY32_UNDEFINED; + + if (!(flags & (1 << 6))) { + if (mapElement->properties.path.additions & 0x0F) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_NONE; + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) + mapElement->properties.path.additions |= 0x80; + } + + if (!(flags & GAME_COMMAND_FLAG_APPLY)) + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); + + if ( + ( + RCT2_GLOBAL(0x00F3EF88, uint16) != 0 && + !(flags & (1 << 6)) + ) || + ( + RCT2_GLOBAL(0x00F3EF88, uint16) == 0 || + (mapElement->properties.path.additions & 0x80) + ) + ) { + mapElement->properties.path.additions &= ~0x80; + } + + mapElement->properties.path.additions = (mapElement->properties.path.additions & 0xF0) | RCT2_GLOBAL(0x00F3EF88, uint8); + mapElement->flags &= ~0x20; + if (RCT2_GLOBAL(0x00F3EF88, uint16) != 0) { + uint8 *unk = RCT2_ADDRESS(0x009ADA50, uint8*)[RCT2_GLOBAL(0x00F3EF88, uint16)]; + uint16 unk6 = RCT2_GLOBAL(unk + 6, uint16); + if (unk6 & 1) + mapElement->properties.path.addition_status = 255; + } + map_invalidate_tile_full(x, y); + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); + } + + if (flags & (1 << 4)) + return MONEY32_UNDEFINED; + + if (flags & GAME_COMMAND_FLAG_APPLY) { + RCT2_GLOBAL(0x00F3EFF4, uint32) = 0x00F3EFF8; + + if (!(flags & (1 << 7))) + sub_6A6AA7(x, y, mapElement); + + mapElement->properties.path.type = (mapElement->properties.path.type & 0x0F) | (type << 4); + mapElement->type = (mapElement->type & 0xFE) | (type >> 7); + mapElement->properties.path.additions = (mapElement->properties.path.additions & 0xF0) | RCT2_GLOBAL(0x00F3EF88, uint8); + mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; + } + + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); +} + +static money32 footpath_place_real(int type, int x, int y, int z, int slope, int flags) +{ + rct_map_element *mapElement; + + RCT2_GLOBAL(0x0141F56C, uint8) = 12; + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z * 8; + + if (!(flags & FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED) && RCT2_GLOBAL(0x009DEA6E, uint8) != 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) + RCT2_CALLPROC_X(0x0069A48B, x, 0, y, z * 8, 0, 0, 0); + + RCT2_GLOBAL(0x00F3EFD9, money32) = 0; + RCT2_GLOBAL(0x00F3EFA4, uint8) = 0; + RCT2_GLOBAL(0x00F3EF88, uint16) = 0; // di + + if (x >= RCT2_GLOBAL(0x01358830, uint16) || y >= RCT2_GLOBAL(0x01358830, uint16)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_OFF_EDGE_OF_MAP; + return MONEY32_UNDEFINED; + } + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_owned(x, y, z * 8)) + return MONEY32_UNDEFINED; + + if (slope & 8) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_LAND_SLOPE_UNSUITABLE; + return MONEY32_UNDEFINED; + } + + if (z < 2) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_LOW; + return MONEY32_UNDEFINED; + } + + if (z > 248) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_HIGH; + return MONEY32_UNDEFINED; + } + + mapElement = map_get_footpath_element_slope((x / 32), (y / 32), z, slope); + if (mapElement == NULL) + return footpath_element_insert(type, x, y, z, slope, flags); + else + return footpath_element_update(x, y, mapElement, type, flags); +} + +money32 footpath_remove_real(int x, int y, int z, int flags) +{ + rct_map_element *mapElement; + + RCT2_GLOBAL(0x0141F56C, uint8) = 12; + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z * 8; + + if (!(flags & FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED) && RCT2_GLOBAL(0x009DEA6E, uint8) != 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + return MONEY32_UNDEFINED; + } + + if (flags & (1 << 0)) { + RCT2_CALLPROC_X(0x0069A48B, x, 0, y, z * 8, 0, 0, 0); + RCT2_CALLPROC_X(0x00673883, x, 0, y, z * 8, 0, 0, 0); + } + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_owned(x, y, z * 8)) + return MONEY32_UNDEFINED; + + mapElement = map_get_footpath_element(x / 32, y / 32, z); + if (mapElement != NULL && (flags & (1 << 0))) { + RCT2_GLOBAL(0x00F3EFF4, uint32) = 0x00F3EFF8; + RCT2_CALLPROC_X(0x006BA23E, 0, 0, 0, 0, (int)mapElement, 0, 0); + sub_6A6AA7(x, y, mapElement); + map_invalidate_tile_full(x, y); + map_element_remove(mapElement); + RCT2_CALLPROC_EBPSAFE(0x006A759F); + } + + return (flags & (1 << 5)) || (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) ? 0 : -MONEY(10,00); +} + +/** + * + * rct2: 0x006A61DE + */ +void game_command_place_footpath(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + if (*ebx & (1 << 5)) + RCT2_CALLFUNC_X(0x006A61DE, eax, ebx, ecx, edx, esi, edi, ebp); + else + *ebx = footpath_place_real((*edx >> 8) & 0xFF, *eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, (*ebx >> 8) & 0xFF, *ebx & 0xFF); +} + +/** + * + * rct2: 0x006A67C0 + */ +void game_command_remove_footpath(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + *ebx = footpath_remove_real((*eax & 0xFFFF), (*ecx & 0xFFFF), (*edx & 0xFF), (*ebx & 0xFF)); +} + money32 footpath_place(int type, int x, int y, int z, int slope, int flags) { return game_do_command(x, (slope << 8) | flags, y, (type << 8) | z, GAME_COMMAND_PLACE_PATH, 0, 0); @@ -43,7 +392,7 @@ money32 footpath_provisional_set(int type, int x, int y, int z, int slope) footpath_provisional_remove(); - cost = footpath_place(type, x, y, z, slope, (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 0)); + cost = footpath_place(type, x, y, z, slope, (1 << 6) | (1 << 5) | (1 << 4) | FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_APPLY); if (cost != MONEY32_UNDEFINED) { RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_X, uint16) = x; RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Y, uint16) = y; @@ -69,7 +418,7 @@ void footpath_provisional_remove() RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Z, uint16), - (1 << 0) | (1 << 3) | (1 << 5) + (1 << 0) | FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED | (1 << 5) ); } } diff --git a/src/world/footpath.h b/src/world/footpath.h index 7eeea6d4c1..1b282e6c93 100644 --- a/src/world/footpath.h +++ b/src/world/footpath.h @@ -36,6 +36,8 @@ typedef struct { uint8 flags; // 0x0B } rct_path_type; +void game_command_place_footpath(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_remove_footpath(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); money32 footpath_place(int type, int x, int y, int z, int slope, int flags); void footpath_remove(int x, int y, int z, int flags); money32 footpath_provisional_set(int type, int x, int y, int z, int slope); From c0e45189727d0eab027da030c3762c27dbe9f6a7 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Fri, 13 Feb 2015 20:55:49 +0000 Subject: [PATCH 2/2] refactor some of the footpath code after merging --- src/world/banner.h | 1 + src/world/footpath.c | 105 +++++++++++++++++++++++++++++++------------ src/world/footpath.h | 4 +- src/world/map.c | 41 +++++++++++++++++ src/world/map.h | 2 + 5 files changed, 122 insertions(+), 31 deletions(-) diff --git a/src/world/banner.h b/src/world/banner.h index 8496a132a1..f9e7822c96 100644 --- a/src/world/banner.h +++ b/src/world/banner.h @@ -23,6 +23,7 @@ #include "../common.h" +#define BANNER_NULL 255 #define MAX_BANNERS 250 typedef struct { diff --git a/src/world/footpath.c b/src/world/footpath.c index 09960e21ae..d52452fdb2 100644 --- a/src/world/footpath.c +++ b/src/world/footpath.c @@ -24,10 +24,22 @@ #include "footpath.h" #include "map.h" +void sub_673883(int x, int y, int z); +void sub_69A48B(int x, int y, int z); +void sub_6A6C66(int x, int y, rct_map_element *mapElement, int flags); +void sub_6A759F(); + enum { FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED = 1 << 3 }; +const rct_xy16 word_981D6C[] = { + { -1, 0 }, + { 0, 1 }, + { 1, 0 }, + { 0, -1 } +}; + /** * * rct2: 0x006A65AD @@ -48,8 +60,8 @@ static void automatically_set_peep_spawn(int x, int y, int z) } } - peepSpawn->x = (RCT2_GLOBAL(0x00981D6C + (direction * 4), uint16) * 15) + 16; - peepSpawn->y = (RCT2_GLOBAL(0x00981D6E + (direction * 4), uint16) * 15) + 16; + peepSpawn->x = (word_981D6C[direction].x * 15) + 16; + peepSpawn->y = (word_981D6C[direction].y * 15) + 16; peepSpawn->direction = direction; peepSpawn->z = z / 2; } @@ -58,11 +70,11 @@ rct_map_element *map_get_footpath_element(int x, int y, int z) { rct_map_element *mapElement; - mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + mapElement = map_get_first_element_at(x, y); do { - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH && mapElement->base_height == z) + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH && mapElement->base_height == z) return mapElement; - } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } while (!map_element_is_last_for_tile(mapElement++)); return NULL; } @@ -71,16 +83,16 @@ rct_map_element *map_get_footpath_element_slope(int x, int y, int z, int slope) { rct_map_element *mapElement; - mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + mapElement = map_get_first_element_at(x, y); do { if ( - (mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH && + map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH && mapElement->base_height == z && (mapElement->properties.path.type & 7) == slope ) { return mapElement; } - } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } while (!map_element_is_last_for_tile(mapElement++)); return NULL; } @@ -88,13 +100,13 @@ rct_map_element *map_get_footpath_element_slope(int x, int y, int z, int slope) static money32 footpath_element_insert(int type, int x, int y, int z, int slope, int flags) { rct_map_element *mapElement; - int bl, zHigh; + int bl, zHigh, direction; if (!sub_68B044()) return MONEY32_UNDEFINED; - if ((flags & GAME_COMMAND_FLAG_APPLY) && !(flags & ((1 << 3) | (1 << 6)))) - RCT2_CALLPROC_X(0x00673883, x, 0, y, RCT2_GLOBAL(0x009DEA62, uint16), 0, 0, 0); + if ((flags & GAME_COMMAND_FLAG_APPLY) && !(flags & (FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED | (1 << 6)))) + sub_673883(x, y, RCT2_GLOBAL(0x009DEA62, uint16)); // loc_6A649D: RCT2_GLOBAL(0x00F3EFD9, money32) += MONEY(12, 00); @@ -146,18 +158,18 @@ static money32 footpath_element_insert(int type, int x, int y, int z, int slope, if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !(flags & (1 << 6))) automatically_set_peep_spawn(x, y, mapElement->base_height / 2); - if (!(mapElement->properties.path.type & 4) && !(flags & (1 << 6))) { - int ttt = mapElement->properties.path.type; + if ((mapElement->properties.path.type & 4) && !(flags & (1 << 6))) { + direction = mapElement->properties.path.type & 3; z = mapElement->base_height; - RCT2_CALLPROC_X(0x006E5935, x, (ttt & 3) ^ 2, y, ((z + 6) << 8) | z, 0, 0, 0); - RCT2_CALLPROC_X(0x006E5935, x, (ttt & 3), y, ((z + 6) << 8) | z, 0, 0, 0); + map_remove_intersecting_walls(x, y, z, z + 6, direction ^ 2); + map_remove_intersecting_walls(x, y, z, z + 6, direction); mapElement = map_get_footpath_element(x / 32, y / 32, z); } if (!(flags & (1 << 7))) - RCT2_CALLPROC_X(0x006A6C66, x, flags, y, 0, (int)mapElement, 0, 0); + sub_6A6C66(x, y, mapElement, flags); - RCT2_CALLPROC_EBPSAFE(0x006A759F); + sub_6A759F(); map_invalidate_tile_full(x, y); } return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); @@ -280,7 +292,7 @@ static money32 footpath_place_real(int type, int x, int y, int z, int slope, int } if (flags & GAME_COMMAND_FLAG_APPLY) - RCT2_CALLPROC_X(0x0069A48B, x, 0, y, z * 8, 0, 0, 0); + sub_69A48B(x, y, z * 8); RCT2_GLOBAL(0x00F3EFD9, money32) = 0; RCT2_GLOBAL(0x00F3EFA4, uint8) = 0; @@ -310,10 +322,9 @@ static money32 footpath_place_real(int type, int x, int y, int z, int slope, int } mapElement = map_get_footpath_element_slope((x / 32), (y / 32), z, slope); - if (mapElement == NULL) - return footpath_element_insert(type, x, y, z, slope, flags); - else - return footpath_element_update(x, y, mapElement, type, flags); + return mapElement == NULL ? + footpath_element_insert(type, x, y, z, slope, flags) : + footpath_element_update(x, y, mapElement, type, flags); } money32 footpath_remove_real(int x, int y, int z, int flags) @@ -330,22 +341,22 @@ money32 footpath_remove_real(int x, int y, int z, int flags) return MONEY32_UNDEFINED; } - if (flags & (1 << 0)) { - RCT2_CALLPROC_X(0x0069A48B, x, 0, y, z * 8, 0, 0, 0); - RCT2_CALLPROC_X(0x00673883, x, 0, y, z * 8, 0, 0, 0); + if (flags & GAME_COMMAND_FLAG_APPLY) { + sub_69A48B(x, y, z * 8); + sub_673883(x, y, z * 8); } if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_owned(x, y, z * 8)) return MONEY32_UNDEFINED; mapElement = map_get_footpath_element(x / 32, y / 32, z); - if (mapElement != NULL && (flags & (1 << 0))) { + if (mapElement != NULL && (flags & GAME_COMMAND_FLAG_APPLY)) { RCT2_GLOBAL(0x00F3EFF4, uint32) = 0x00F3EFF8; RCT2_CALLPROC_X(0x006BA23E, 0, 0, 0, 0, (int)mapElement, 0, 0); sub_6A6AA7(x, y, mapElement); map_invalidate_tile_full(x, y); map_element_remove(mapElement); - RCT2_CALLPROC_EBPSAFE(0x006A759F); + sub_6A759F(); } return (flags & (1 << 5)) || (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) ? 0 : -MONEY(10,00); @@ -355,7 +366,7 @@ money32 footpath_remove_real(int x, int y, int z, int flags) * * rct2: 0x006A61DE */ -void game_command_place_footpath(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +void game_command_place_footpath(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) { if (*ebx & (1 << 5)) RCT2_CALLFUNC_X(0x006A61DE, eax, ebx, ecx, edx, esi, edi, ebp); @@ -367,7 +378,7 @@ void game_command_place_footpath(int* eax, int* ebx, int* ecx, int* edx, int* es * * rct2: 0x006A67C0 */ -void game_command_remove_footpath(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +void game_command_remove_footpath(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) { *ebx = footpath_remove_real((*eax & 0xFFFF), (*ecx & 0xFFFF), (*edx & 0xFF), (*ebx & 0xFF)); } @@ -455,4 +466,40 @@ void sub_68A0C9(int screenX, int screenY, int *x, int *y, int *direction, rct_ma if (y != NULL) *y = *((uint16*)&ebx); if (direction != NULL) *direction = *((uint8*)&ecx); if (mapElement != NULL) *mapElement = (rct_map_element*)edx; +} + +/** + * + * rct2: 0x00673883 + */ +void sub_673883(int x, int y, int z) +{ + RCT2_CALLPROC_X(0x00673883, x, 0, y, z, 0, 0, 0); +} + +/** + * + * rct2: 0x0069A48B + */ +void sub_69A48B(int x, int y, int z) +{ + RCT2_CALLPROC_X(0x0069A48B, x, 0, y, z, 0, 0, 0); +} + +/** + * + * rct2: 0x006A6C66 + */ +void sub_6A6C66(int x, int y, rct_map_element *mapElement, int flags) +{ + RCT2_CALLPROC_X(0x006A6C66, x, flags, y, 0, (int)mapElement, 0, 0); +} + +/** + * + * rct2: 0x006A759F + */ +void sub_6A759F() +{ + RCT2_CALLPROC_EBPSAFE(0x006A759F); } \ No newline at end of file diff --git a/src/world/footpath.h b/src/world/footpath.h index 1b282e6c93..d722d7838f 100644 --- a/src/world/footpath.h +++ b/src/world/footpath.h @@ -36,8 +36,8 @@ typedef struct { uint8 flags; // 0x0B } rct_path_type; -void game_command_place_footpath(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); -void game_command_remove_footpath(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_place_footpath(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_remove_footpath(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); money32 footpath_place(int type, int x, int y, int z, int slope, int flags); void footpath_remove(int x, int y, int z, int flags); money32 footpath_provisional_set(int type, int x, int y, int z, int slope); diff --git a/src/world/map.c b/src/world/map.c index 8eb938467b..b15d1d8a6d 100644 --- a/src/world/map.c +++ b/src/world/map.c @@ -20,9 +20,11 @@ #include "../addresses.h" #include "../game.h" +#include "../interface/window.h" #include "../localisation/date.h" #include "../localisation/localisation.h" #include "../management/finance.h" +#include "banner.h" #include "climate.h" #include "map.h" #include "park.h" @@ -1085,4 +1087,43 @@ int map_can_construct_with_clear_at(int x, int y, int zLow, int zHigh, void *cle int map_can_construct_at(int x, int y, int zLow, int zHigh, uint8 bl) { return map_can_construct_with_clear_at(x, y, zLow, zHigh, (void*)0xFFFFFFFF, bl); +} + +/** + * + * rct2: 0x006E5935 + */ +void map_remove_intersecting_walls(int x, int y, int z0, int z1, int direction) +{ + int bannerIndex; + rct_banner *banner; + rct_map_element *mapElement; + rct_scenery_entry *sceneryEntry; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) + continue; + + if (mapElement->clearance_height <= z0 || mapElement->base_height >= z1) + continue; + + if (direction != (mapElement->type & 3)) + continue; + + sceneryEntry = g_wallSceneryEntries[mapElement->properties.fence.slope]; + if (sceneryEntry->wall.var_0D != 255) { + bannerIndex = mapElement->properties.fence.item[0]; + banner = &gBanners[bannerIndex]; + if (banner->type != BANNER_NULL) { + window_close_by_number(WC_BANNER, bannerIndex); + banner->type = BANNER_NULL; + user_string_free(banner->string_idx); + } + } + + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->base_height * 8 + 72); + map_element_remove(mapElement); + mapElement -= 1; + } while (!map_element_is_last_for_tile(mapElement++)); } \ No newline at end of file diff --git a/src/world/map.h b/src/world/map.h index eb83a32c6a..c4d21bebf8 100644 --- a/src/world/map.h +++ b/src/world/map.h @@ -273,4 +273,6 @@ void map_element_iterator_begin(map_element_iterator *it); int map_element_iterator_next(map_element_iterator *it); void map_element_iterator_restart_for_tile(map_element_iterator *it); +void map_remove_intersecting_walls(int x, int y, int z0, int z1, int direction); + #endif