diff --git a/src/viewport.c b/src/viewport.c index f1aa777363..3f412edc4f 100644 --- a/src/viewport.c +++ b/src/viewport.c @@ -1088,3 +1088,27 @@ void viewport_set_visibility(uint8 mode) window_invalidate(window); } } + +/** + * + * rct2: 0x00685ADC + * screenX: eax + * screenY: ebx + * flags: edx + * x: ax + * y: cx + * z: bl + * mapElement: edx + */ +void get_map_coordinates_from_pos(int screenX, int screenY, int flags, int *x, int *y, int *z, rct_map_element **mapElement) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = y; + edx = flags; + RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + if (x != NULL) *x = *((uint8*)&eax); + if (y != NULL) *y = *((uint8*)&ecx); + if (z != NULL) *z = *((uint8*)&ebx); + if (mapElement != NULL) *mapElement = (rct_map_element*)edx; +} \ No newline at end of file diff --git a/src/viewport.h b/src/viewport.h index dfbcfb8c5c..c1dbd0c7c8 100644 --- a/src/viewport.h +++ b/src/viewport.h @@ -65,4 +65,6 @@ void show_construction_rights(); void hide_construction_rights(); void viewport_set_visibility(uint8 mode); +void get_map_coordinates_from_pos(int screenX, int screenY, int flags, int *x, int *y, int *z, rct_map_element **mapElement); + #endif diff --git a/src/window_footpath.c b/src/window_footpath.c index 582f9198fe..62c1e5ada5 100644 --- a/src/window_footpath.c +++ b/src/window_footpath.c @@ -615,16 +615,7 @@ static void window_footpath_set_provisional_path_at_point(int x, int y) RCT2_CALLPROC_EBPSAFE(0x0068AAE1); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~4; - // Get map coordinates from point - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x; - ebx = y; - edx = -34; - RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - x = eax & 0xFFFF; - z = ebx & 0xFF; - y = ecx & 0xFFFF; - mapElement = (rct_map_element*)edx; + get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement); if (z == 0) { RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~1; @@ -697,17 +688,7 @@ static void window_footpath_place_path_at_point(int x, int y) RCT2_CALLPROC_EBPSAFE(0x006A7831); - // Get map coordinates from point - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x; - ebx = y; - edx = -34; - RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - x = eax & 0xFFFF; - z = ebx & 0xFF; - y = ecx & 0xFFFF; - mapElement = (rct_map_element*)edx; - + get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement); if (z == 0) return; diff --git a/src/window_peep.c b/src/window_peep.c index 2238f77de6..5dbd0d03d8 100644 --- a/src/window_peep.c +++ b/src/window_peep.c @@ -1153,11 +1153,11 @@ void window_peep_overview_tool_update(){ } RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; - eax = x; - int ebx = y; - edx = 0; - RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if ((ebx & 0xFF) == 0) return; + + int ebx; + get_map_coordinates_from_pos(x, y, 0, NULL, NULL, &ebx, NULL); + if (ebx == 0) + return; x--; y += 16; diff --git a/src/window_track_place.c b/src/window_track_place.c index cfcd377603..a0cd1371dd 100644 --- a/src/window_track_place.c +++ b/src/window_track_place.c @@ -18,13 +18,19 @@ * along with this program. If not, see . *****************************************************************************/ +#include #include "addresses.h" +#include "game.h" #include "sprites.h" #include "string_ids.h" #include "viewport.h" #include "widget.h" #include "window.h" +#define TRACK_MINI_PREVIEW_WIDTH 168 +#define TRACK_MINI_PREVIEW_HEIGHT 78 +#define TRACK_MINI_PREVIEW_SIZE (TRACK_MINI_PREVIEW_WIDTH * TRACK_MINI_PREVIEW_HEIGHT) + enum { WIDX_BACKGROUND, WIDX_TITLE, @@ -87,6 +93,108 @@ static void* window_track_place_events[] = { window_track_place_emptysub }; +static uint8 *_window_track_place_mini_preview; +static sint16 _window_track_place_last_x; +static sint16 _window_track_place_last_y; + +static uint8 _window_track_place_last_was_valid; +static sint16 _window_track_place_last_valid_x; +static sint16 _window_track_place_last_valid_y; +static sint16 _window_track_place_last_valid_z; +static money32 _window_track_place_last_cost; + +/** + * + * rct2: 0x006D182E + */ +static void window_track_place_clear_mini_preview() +{ + memset(_window_track_place_mini_preview, 220, TRACK_MINI_PREVIEW_SIZE); +} + +/** + * + * rct2: 0x006D1845 + */ +static void window_track_place_draw_mini_preview() +{ + RCT2_GLOBAL(0x00F44168, uint8*) = _window_track_place_mini_preview; + RCT2_CALLPROC_EBPSAFE(0x006D1845); +} + +/** + * + * rct2: 0x0068A15E + */ +static short sub_68A15E(int x, int y, short *ax, short *bx) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = y; + RCT2_CALLFUNC_X(0x0068A15E, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + *ax = *((short*)&eax); + *bx = *((short*)&ebx); +} + +/** + * Seems to highlight the surface tiles to match the track layout at the given position but also returns some Z value. + * rct2: 0x006D01B3 + */ +static int sub_6D01B3(int bl, int x, int y, int z) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = bl; + ecx = y; + edx = z; + esi = 0; + edi = 0; + ebp = 0; + RCT2_CALLFUNC_X(0x006D01B3, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return *((short*)&ebx); +} + +/** + * + * rct2: 0x006D017F + */ +static void window_track_place_clear_provisional() +{ + if (_window_track_place_last_was_valid) { + sub_6D01B3( + (RCT2_GLOBAL(0x00F440EB, uint8) << 8) | 6, + _window_track_place_last_valid_x, + _window_track_place_last_valid_y, + _window_track_place_last_valid_z + ); + _window_track_place_last_was_valid = 0; + } +} + +static int sub_6D17C6(int x, int y) +{ + rct_map_element *mapElement; + int z; + + mapElement = map_get_surface_element_at(x >> 5, y >> 5); + z = mapElement->base_height * 8; + + // Increase Z above slope + if (mapElement->properties.surface.slope & 0x0F) { + z += 16; + + // Increase Z above double slope + if (mapElement->properties.surface.slope & 0x10) + z += 16; + } + + // Increase Z above water + if (mapElement->properties.surface.terrain & 0x1F) + z = max(z, (mapElement->properties.surface.terrain & 0x1F) << 4); + + return z + sub_6D01B3(3, x, y, z); +} + /** * * rct2: 0x006CFCA0 @@ -96,8 +204,9 @@ void window_track_place_open() rct_window *w; window_close_construction_windows(); - RCT2_GLOBAL(0x00F44168, void*) = rct2_malloc(13104); - RCT2_CALLPROC_EBPSAFE(0x006D182E); + + _window_track_place_mini_preview = malloc(TRACK_MINI_PREVIEW_SIZE); + window_track_place_clear_mini_preview(); w = window_create(0, 29, 200, 124, (uint32*)window_track_place_events, WC_TRACK_DESIGN_PLACE, 0); w->widgets = window_track_place_widgets; @@ -110,10 +219,10 @@ void window_track_place_open() RCT2_GLOBAL(0x009DE518, uint32) |= 6; window_push_others_right(w); show_gridlines(); - RCT2_GLOBAL(0x00F440D9, uint32) |= 0x80000000; - RCT2_GLOBAL(0x00F440DD, uint16) = 0xFFFF; + _window_track_place_last_cost = MONEY32_UNDEFINED; + _window_track_place_last_x = 0xFFFF; RCT2_GLOBAL(0x00F440AE, uint8) = (-RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)) & 3; - RCT2_CALLPROC_EBPSAFE(0x006D1845); + window_track_place_draw_mini_preview(); } /** @@ -122,12 +231,12 @@ void window_track_place_open() */ static void window_track_place_close() { - RCT2_CALLPROC_EBPSAFE(0x006D017F); + window_track_place_clear_provisional(); viewport_set_visibility(0); RCT2_CALLPROC_EBPSAFE(0x0068AB1B); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~6; hide_gridlines(); - rct2_free(RCT2_GLOBAL(0x00F44168, void*)); + free(_window_track_place_mini_preview); } /** @@ -146,18 +255,18 @@ static void window_track_place_mouseup() window_close(w); break; case WIDX_ROTATE: - RCT2_CALLPROC_EBPSAFE(0x006D017F); + window_track_place_clear_provisional(); RCT2_GLOBAL(0x00F440AE, uint16) = (RCT2_GLOBAL(0x00F440AE, uint16) + 1) & 3; window_invalidate(w); - RCT2_GLOBAL(0x00F440DD, uint16) = 0xFFFF; - RCT2_CALLPROC_EBPSAFE(0x006D1845); + _window_track_place_last_x = 0xFFFF; + window_track_place_draw_mini_preview(); break; case WIDX_MIRROR: RCT2_CALLPROC_EBPSAFE(0x006D2436); RCT2_GLOBAL(0x00F440AE, uint16) = (-RCT2_GLOBAL(0x00F440AE, uint16)) & 3; window_invalidate(w); - RCT2_GLOBAL(0x00F440DD, uint16) = 0xFFFF; - RCT2_CALLPROC_EBPSAFE(0x006D1845); + _window_track_place_last_x = 0xFFFF; + window_track_place_draw_mini_preview(); break; case WIDX_SELECT_DIFFERENT_DESIGN: window_close(w); @@ -185,10 +294,67 @@ static void window_track_place_toolupdate() { rct_window *w; short widgetIndex, x, y; + int i, z; + money32 cost; window_tool_get_registers(w, widgetIndex, x, y); - RCT2_CALLPROC_X(0x006CFF2D, x, y, 0, widgetIndex, (int)w, 0, 0); + RCT2_CALLPROC_X(0x006CFF2D, x, y, 0, widgetIndex, (int)w, 0, 0); return; + + // BUG: After placing layout, path tiles aren't connected, even though they were in the provisional appearance + + RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~7; + + // Get the tool map position + sub_68A15E(x, y, &x, &y); + if (x == (short)0x8000) { + window_track_place_clear_provisional(); + return; + } + + // Check if tool map position has changed since last update + if (x == _window_track_place_last_x && y == _window_track_place_last_y) { + sub_6D01B3(0, x, y, 0); + return; + } + + cost = MONEY32_UNDEFINED; + + // Get base Z position + z = sub_6D17C6(x, y); + if (RCT2_GLOBAL(0x009DEA6E, uint8) == 0) { + window_track_place_clear_provisional(); + + // Try increasing Z until a feasible placement is found + for (i = 0; i < 7; i++) { + int eax, ebx, ecx, edx, esi, edi, ebp; + + eax = x; + ebx = 105; + ecx = y; + edi = z; + cost = game_do_command_p(GAME_COMMAND_47, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + if (cost != MONEY32_UNDEFINED) { + RCT2_GLOBAL(0x00F440EB, uint16) = *((short*)&edi); + _window_track_place_last_valid_x = x; + _window_track_place_last_valid_y = y; + _window_track_place_last_valid_z = z; + _window_track_place_last_was_valid = 1; + break; + } + z += 8; + } + } + + _window_track_place_last_x = x; + _window_track_place_last_y = y; + if (cost != _window_track_place_last_cost) { + _window_track_place_last_cost = cost; + widget_invalidate(WC_TRACK_DESIGN_PLACE, 0, WIDX_PRICE); + } + + sub_6D01B3(0, x, y, z); } /** @@ -211,7 +377,7 @@ static void window_track_place_tooldown() */ static void window_track_place_toolabort() { - RCT2_CALLPROC_EBPSAFE(0x006D017F); + window_track_place_clear_provisional(); } /** @@ -220,7 +386,7 @@ static void window_track_place_toolabort() */ static void window_track_place_unknown14() { - RCT2_CALLPROC_EBPSAFE(0x006D1845); + window_track_place_draw_mini_preview(); } /** @@ -242,9 +408,9 @@ static void window_track_place_paint() if (clippedDpi != NULL) { subsituteElement = &g1Elements[0]; tmpElement = *subsituteElement; - subsituteElement->offset = RCT2_GLOBAL(0x00F44168, uint8*); - subsituteElement->width = 168; - subsituteElement->height = 78; + subsituteElement->offset = _window_track_place_mini_preview; + subsituteElement->width = TRACK_MINI_PREVIEW_WIDTH; + subsituteElement->height = TRACK_MINI_PREVIEW_HEIGHT; subsituteElement->x_offset = 0; subsituteElement->y_offset = 0; subsituteElement->flags = 0; @@ -252,10 +418,8 @@ static void window_track_place_paint() *subsituteElement = tmpElement; } - if (RCT2_GLOBAL(0x00F440D9, money32) == 0x80000000) - return; - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) - return; - - gfx_draw_string_centred(dpi, STR_COST_LABEL, w->x + 88, w->y + 94, 0, (money32*)0x00F440D9); + // Price + if (_window_track_place_last_cost != MONEY32_UNDEFINED) + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) + gfx_draw_string_centred(dpi, STR_COST_LABEL, w->x + 88, w->y + 94, 0, &_window_track_place_last_cost); } \ No newline at end of file