From d92a4d9418bb59ecc700d52e03b3f36b76f56955 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Tue, 4 Nov 2014 03:34:12 +0000 Subject: [PATCH] implement clear scenery game command, try out removing paths feature --- src/game.c | 4 +- src/game.h | 6 +- src/input.c | 2 +- src/localisation/string_ids.h | 3 + src/windows/game_top_toolbar.c | 91 ++++++++++++++-- src/windows/sign.c | 2 +- src/world/map.c | 186 +++++++++++++++++++++++++++++++++ src/world/map.h | 2 + src/world/scenery.h | 3 +- 9 files changed, 283 insertions(+), 16 deletions(-) diff --git a/src/game.c b/src/game.c index 8421a95786..7654cbbf3a 100644 --- a/src/game.c +++ b/src/game.c @@ -878,7 +878,7 @@ static uint32 game_do_command_table[58] = { 0x006B909A, 0x006BA16A, 0x006648E3, - 0x0068DF91 + 0 }; void game_command_emptysub(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) {} @@ -941,7 +941,7 @@ static GAME_COMMAND_POINTER* new_game_command_table[58] = { game_command_emptysub, game_command_emptysub, game_command_emptysub, - game_command_emptysub + game_command_clear_scenery }; #pragma endregion diff --git a/src/game.h b/src/game.h index 196b476334..6a55485f62 100644 --- a/src/game.h +++ b/src/game.h @@ -36,7 +36,7 @@ enum GAME_COMMAND { GAME_COMMAND_11, GAME_COMMAND_12, GAME_COMMAND_13, - GAME_COMMAND_14, + GAME_COMMAND_REMOVE_SCENERY, GAME_COMMAND_15, GAME_COMMAND_16, GAME_COMMAND_PLACE_PATH, // 17 @@ -64,7 +64,7 @@ enum GAME_COMMAND { GAME_COMMAND_SET_PARK_ENTRANCE_FEE, // 39 GAME_COMMAND_SET_STAFF_COLOUR, // 40 GAME_COMMAND_41, - GAME_COMMAND_42, + GAME_COMMAND_REMOVE_FENCE, GAME_COMMAND_43, GAME_COMMAND_44, GAME_COMMAND_SET_CURRENT_LOAN, // 45 @@ -79,7 +79,7 @@ enum GAME_COMMAND { GAME_COMMAND_54, GAME_COMMAND_55, GAME_COMMAND_56, // Set land owned (possibly does other things) - GAME_COMMAND_57 + GAME_COMMAND_CLEAR_SCENERY }; typedef void (GAME_COMMAND_POINTER)(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); diff --git a/src/input.c b/src/input.c index 6ec0f334f8..cd3a70bade 100644 --- a/src/input.c +++ b/src/input.c @@ -854,7 +854,7 @@ static void game_handle_input_mouse(int x, int y, int state) 1, ecx, (map_element->type & 0x3) | (map_element->base_height << 8), - GAME_COMMAND_42, + GAME_COMMAND_REMOVE_FENCE, 0, 0); } diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index 00029e9b53..2e2845f046 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -652,6 +652,8 @@ enum { STR_STAFF_MECHANICS_TAB_TIP = 2211, STR_STAFF_SECURITY_TAB_TIP = 2212, STR_STAFF_ENTERTAINERS_TAB_TIP = 2213, + + STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED = 2214, STR_CELSIUS_VALUE = 2216, STR_FAHRENHEIT_VALUE = 2217, @@ -981,6 +983,7 @@ enum { STR_NO_RECENT_AWARDS = 2848, + STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY = 2853, STR_ENTRANCE_NOT_CONNECTED = 2854, STR_EXIT_NOT_CONNECTED = 2855, diff --git a/src/windows/game_top_toolbar.c b/src/windows/game_top_toolbar.c index 343260c369..52ba3d2918 100644 --- a/src/windows/game_top_toolbar.c +++ b/src/windows/game_top_toolbar.c @@ -106,9 +106,11 @@ static void window_game_top_toolbar_emptysub() { } static void window_game_top_toolbar_mouseup(); static void window_game_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); static void window_game_top_toolbar_dropdown(); +static void window_game_top_toolbar_tool_update(); +static void window_game_top_toolbar_tool_down(); +static void window_game_top_toolbar_tool_drag(); static void window_game_top_toolbar_invalidate(); static void window_game_top_toolbar_paint(); -static void window_game_top_toolbar_tool_down(); static void* window_game_top_toolbar_events[] = { window_game_top_toolbar_emptysub, @@ -120,9 +122,9 @@ static void* window_game_top_toolbar_events[] = { window_game_top_toolbar_emptysub, window_game_top_toolbar_emptysub, window_game_top_toolbar_emptysub, - (void*)0x0066CB25, //Update + window_game_top_toolbar_tool_update, window_game_top_toolbar_tool_down, - (void*)0x0066CB4E, + window_game_top_toolbar_tool_drag, (void*)0x0066CC5B, (void*)0x0066CA58, window_game_top_toolbar_emptysub, @@ -665,6 +667,34 @@ static void window_game_top_toolbar_scenery_tool_down(short x, short y, rct_wind } } +/** + * + * rct2: 0x0066CB25 + */ +static void window_game_top_toolbar_tool_update() +{ + short widgetIndex; + rct_window *w; + short x, y; + + window_tool_get_registers(w, widgetIndex, x, y); + + switch (widgetIndex){ + case WIDX_CLEAR_SCENERY: + RCT2_CALLPROC_X(0x0068E213, x, y, 0, widgetIndex, (int)w, 0, 0); + break; + case WIDX_LAND: + RCT2_CALLPROC_X(0x00664280, x, y, 0, widgetIndex, (int)w, 0, 0); + break; + case WIDX_WATER: + RCT2_CALLPROC_X(0x006E6BDC, x, y, 0, widgetIndex, (int)w, 0, 0); + break; + case WIDX_SCENERY: + RCT2_CALLPROC_X(0x006E287B, x, y, 0, widgetIndex, (int)w, 0, 0); + break; + } +} + /** * rct2: 0x0066CB73 */ @@ -677,9 +707,8 @@ static void window_game_top_toolbar_tool_down(){ switch (widgetIndex){ case WIDX_CLEAR_SCENERY: - if (!RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16)&(1 << 0)){ - return; - } + if (!RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0)) + break; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3438; @@ -688,10 +717,11 @@ static void window_game_top_toolbar_tool_down(){ 1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16), 0, - GAME_COMMAND_57, + GAME_COMMAND_CLEAR_SCENERY, RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) - ); + ); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 12; break; case WIDX_LAND: RCT2_CALLPROC_X(0x66CBF3, x, y, 0, widgetIndex, (int)w, 0, 0); @@ -703,4 +733,49 @@ static void window_game_top_toolbar_tool_down(){ window_game_top_toolbar_scenery_tool_down(x, y, w, widgetIndex); break; } +} + +/** + * + * rct2: 0x0066CB4E + */ +static void window_game_top_toolbar_tool_drag() +{ + short widgetIndex; + rct_window *w; + short x, y; + + window_tool_get_registers(w, widgetIndex, x, y); + + switch (widgetIndex){ + case WIDX_CLEAR_SCENERY: + if (window_find_by_class(WC_ERROR) != NULL) + break; + + if (!RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0)) + break; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3438; + + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16), + 0, + GAME_COMMAND_CLEAR_SCENERY, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) + ); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 12; + break; + case WIDX_LAND: + RCT2_CALLPROC_X(0x00664454, x, y, 0, widgetIndex, (int)w, 0, 0); + break; + case WIDX_WATER: + RCT2_CALLPROC_X(0x006E6D4B, x, y, 0, widgetIndex, (int)w, 0, 0); + break; + case WIDX_SCENERY: + RCT2_CALLPROC_X(0x006E2CBC, x, y, 0, widgetIndex, (int)w, 0, 0); + break; + } } \ No newline at end of file diff --git a/src/windows/sign.c b/src/windows/sign.c index 060d07f378..a47f8ab2c7 100644 --- a/src/windows/sign.c +++ b/src/windows/sign.c @@ -584,7 +584,7 @@ static void window_sign_small_mouseup() 1 | ((map_element->type & 0x3) << 8), y, (map_element->base_height << 8) | (map_element->type & 0x3), - GAME_COMMAND_42, + GAME_COMMAND_REMOVE_FENCE, 0, 0); break; diff --git a/src/world/map.c b/src/world/map.c index b889a96bd5..11b22e7763 100644 --- a/src/world/map.c +++ b/src/world/map.c @@ -20,8 +20,11 @@ #include "../addresses.h" #include "../localisation/date.h" +#include "../localisation/localisation.h" #include "climate.h" #include "map.h" +#include "park.h" +#include "scenery.h" int _sub_6A876D_save_x; int _sub_6A876D_save_y; @@ -455,4 +458,187 @@ int sub_664F72(int x, int y, int z){ RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 0x6C1; return 1; +} + +/** + * + * rct2: 0x006E0E01 + */ +money32 map_try_clear_scenery(int x, int y, rct_map_element *mapElement, int flags) +{ + money32 cost; + rct_scenery_entry *entry; + + entry = g_smallSceneryEntries[mapElement->properties.scenery.type]; + cost = entry->small_scenery.removal_price * 10; + + RCT2_GLOBAL(0x0141F56C, uint8) = 12; + RCT2_GLOBAL(0x009DEA5E, uint32) = x * 32 + 16; + RCT2_GLOBAL(0x009DEA60, uint32) = y * 32 + 16; + RCT2_GLOBAL(0x009DEA62, uint32) = mapElement->base_height * 8; + + x *= 32; + y *= 32; + + if (!(flags & 0x40) && RCT2_GLOBAL(0x009DEA6E, uint8) != 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + return MONEY32_UNDEFINED; + } + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !(flags & 0x40)) { + // Check if allowed to remove item + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_TREE_REMOVAL) { + if (entry->small_scenery.height > 64) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY; + return MONEY32_UNDEFINED; + } + } + + // Check if the land is owned + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR)) + if (sub_664F72(x, y, RCT2_GLOBAL(0x009DEA62, uint32))) + return MONEY32_UNDEFINED; + } + + if ((flags & 0x40) && !(mapElement->flags & 0x10)) + return 0; + + // Remove element + if (flags & 1) { + RCT2_CALLPROC_X(0x006EC6D7, x, 0, y, 0, 0, 0, 0); + RCT2_CALLPROC_X(0x0068B280, 0, 0, 0, 0, (int)mapElement, 0, 0); + } + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : cost; +} + +/** + * + * rct2: 0x006E5597 + */ +money32 sub_6E5597(int x, int y, int dl, int dh, int bl) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x * 32; + ecx = y * 32; + ebx = bl & 0xFF; + edx = ((dh & 0xFF) << 8) | (dl & 0xFF); + RCT2_CALLFUNC_X(0x006E5597, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return ebx; +} + +money32 sub_6A67C0(int x, int y, int z, int flags) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x * 32; + ecx = y * 32; + ebx = flags & 0xFF; + edx = z & 0xFF; + RCT2_CALLFUNC_X(0x006A67C0, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return ebx; +} + +// This will cause clear scenery to remove paths +// This should be a flag for the game command which can be set via a checkbox on the clear scenery window. +// #define CLEAR_SCENERY_REMOVES_PATHS + +/** + * + * rct2: 0x0068DFE4 + */ +money32 map_clear_scenery_from_tile(int x, int y, int flags) +{ + int type; + money32 cost, totalCost; + rct_map_element *mapElement; + + totalCost = 0; + +restart_from_beginning: + mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + do { + type = mapElement->type & MAP_ELEMENT_TYPE_MASK; + switch (type) { + case MAP_ELEMENT_TYPE_PATH: +#ifdef CLEAR_SCENERY_REMOVES_PATHS + cost = sub_6A67C0(x, y, mapElement->base_height, flags); + if (cost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + + totalCost += cost; + if (flags & 1) + goto restart_from_beginning; +#endif + break; + case MAP_ELEMENT_TYPE_SCENERY: + cost = map_try_clear_scenery(x, y, mapElement, flags); + if (cost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + + totalCost += cost; + if (flags & 1) + goto restart_from_beginning; + + break; + case MAP_ELEMENT_TYPE_FENCE: + cost = sub_6E5597(x, y, mapElement->type & 3, mapElement->base_height, flags); + if (cost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + + totalCost += cost; + if (flags & 1) + goto restart_from_beginning; + + break; + } + } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + + return totalCost; +} + +money32 map_clear_scenery(int x0, int y0, int x1, int y1, int flags) +{ + int x, y, z; + money32 totalCost, cost; + + RCT2_GLOBAL(0x0141F56C, uint8) = 12; + + x = (x0 + x1) / 2 + 16; + y = (y0 + y1) / 2 + 16; + z = map_element_height(x, y); + RCT2_GLOBAL(0x009DEA5E, uint16) = x; + RCT2_GLOBAL(0x009DEA60, uint16) = y; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + + x0 = clamp(0, x0, 255); + y0 = clamp(0, y0, 255); + x1 = clamp(0, x1, 255); + y1 = clamp(0, y1, 255); + + totalCost = 0; + for (y = y0; y <= y1; y++) { + for (x = x0; x <= x1; x++) { + cost = map_clear_scenery_from_tile(x, y, flags); + if (cost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + + totalCost += cost; + } + } + + return totalCost; +} + +/** + * + * rct2: 0x0068DF91 + */ +void game_command_clear_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + *ebx = map_clear_scenery( + (*eax & 0xFFFF) / 32, + (*ecx & 0xFFFF) / 32, + (*edi & 0xFFFF) / 32, + (*ebp & 0xFFFF) / 32, + *ebx & 0xFF + ); } \ No newline at end of file diff --git a/src/world/map.h b/src/world/map.h index 9b9fadf384..113d69d2d8 100644 --- a/src/world/map.h +++ b/src/world/map.h @@ -209,6 +209,8 @@ int sub_664F72(int x, int y, int z); void fountain_update_all(); +void game_command_clear_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]) diff --git a/src/world/scenery.h b/src/world/scenery.h index e87c490634..30d4ad1559 100644 --- a/src/world/scenery.h +++ b/src/world/scenery.h @@ -28,7 +28,8 @@ typedef struct { uint8 height; // 0x0A uint8 tool_id; // 0x0B uint16 price; // 0x0C - uint8 pad_0E[12]; + uint16 removal_price; // 0x0E + uint8 pad_10[0x0A]; uint8 scenery_tab_id; // 0x1A } rct_small_scenery_entry;