diff --git a/src/string_ids.h b/src/string_ids.h index 4d22b3eb56..f4bd4f45bc 100644 --- a/src/string_ids.h +++ b/src/string_ids.h @@ -1177,7 +1177,8 @@ enum { STR_CLICK_ON_DESIGN_TO_BUILD_IT_TIP = 3111, STR_CLICK_ON_DESIGN_TO_RENAME_OR_DELETE_IT = 3112, - + STR_SELECT_A_DIFFERENT_DESIGN = 3113, + STR_GO_BACK_TO_DESIGN_SELECTION_WINDOW_TIP = 3114, STR_SAVE_TRACK_DESIGN = 3115, STR_SAVE_TRACK_DESIGN_NOT_POSSIBLE = 3116, diff --git a/src/track.h b/src/track.h index 4c4fa6c203..1bdf348969 100644 --- a/src/track.h +++ b/src/track.h @@ -22,6 +22,7 @@ #define _TRACK_H_ #include "rct2.h" +#include "ride.h" typedef struct { uint8 type; diff --git a/src/viewport.c b/src/viewport.c index f1aa777363..25b4fe062b 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 = screenX; + ebx = screenY; + 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.h b/src/window.h index 8f74ccef9b..47b749b222 100644 --- a/src/window.h +++ b/src/window.h @@ -398,6 +398,9 @@ enum PROMPT_MODE { // rct2: 0x01420078 extern rct_window* g_window_list; +// rct2: 0x00F635EE +extern ride_list_item _window_track_list_item; + void window_dispatch_update_all(); void window_update_all(); rct_window *window_create(int x, int y, int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags); 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_list.c b/src/window_track_list.c index fb08c63d53..784e99427a 100644 --- a/src/window_track_list.c +++ b/src/window_track_list.c @@ -93,7 +93,7 @@ static void* window_track_list_events[] = { (uint32*)window_track_list_scrollpaint }; -static ride_list_item _window_track_list_item; +ride_list_item _window_track_list_item; void window_track_list_format_name(char *dst, const char *src, char colour) { diff --git a/src/window_track_place.c b/src/window_track_place.c index 678384c295..be3b367c0e 100644 --- a/src/window_track_place.c +++ b/src/window_track_place.c @@ -18,10 +18,403 @@ * along with this program. If not, see . *****************************************************************************/ +#include #include "addresses.h" +#include "audio.h" +#include "game.h" +#include "sprites.h" +#include "string_ids.h" +#include "track.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, + WIDX_CLOSE, + WIDX_ROTATE, + WIDX_MIRROR, + WIDX_SELECT_DIFFERENT_DESIGN, + WIDX_PRICE +}; + +static rct_widget window_track_place_widgets[] = { + { WWT_FRAME, 0, 0, 199, 0, 123, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 198, 1, 14, 3155, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 187, 197, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_FLATBTN, 0, 173, 196, 83, 106, SPR_ROTATE_ARROW, STR_ROTATE_90_TIP }, + { WWT_FLATBTN, 0, 173, 196, 59, 82, 5170, STR_MIRROR_IMAGE_TIP }, + { WWT_DROPDOWN_BUTTON, 0, 4, 195, 109, 120, STR_SELECT_A_DIFFERENT_DESIGN, STR_GO_BACK_TO_DESIGN_SELECTION_WINDOW_TIP }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WIDGETS_END }, +}; + +static void window_track_place_emptysub() { } +static void window_track_place_close(); +static void window_track_place_mouseup(); +static void window_track_place_update(rct_window *w); +static void window_track_place_toolupdate(); +static void window_track_place_tooldown(); +static void window_track_place_toolabort(); +static void window_track_place_unknown14(); +static void window_track_place_paint(); + +static void* window_track_place_events[] = { + window_track_place_close, + window_track_place_mouseup, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_update, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_toolupdate, + window_track_place_tooldown, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_toolabort, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_unknown14, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_paint, + 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); +} + +/** + * Size: 0x0A + */ +typedef struct { + uint8 var_00; + sint16 x; + sint16 y; + uint8 pad_05[3]; + uint8 var_08; + uint8 unk_09; +} rct_preview_track; + +/** + * Size: 0x04 + */ +typedef struct { + union { + uint32 all; + struct { + sint8 x; + sint8 y; + uint8 unk_2; + uint8 type; + }; + }; +} rct_preview_maze; + +#define swap(x, y) x = x ^ y; y = x ^ y; x = x ^ y; + +/** + * + * rct2: 0x006D1845 + */ +static void window_track_place_draw_mini_preview() +{ + rct_track_design *design = (rct_track_design*)0x009D8178; + uint8 *pixel, colour, *trackPtr, bits; + int i, rotation, pass, x, y, pixelX, pixelY, originX, originY, minX, minY, maxX, maxY; + rct_preview_maze *mazeBlock; + rct_preview_track *trackBlock; + + window_track_place_clear_mini_preview(); + + minX = 0; + minY = 0; + maxX = 0; + maxY = 0; + + // First pass is used to determine the width and height of the image so it can centre it + for (pass = 0; pass < 2; pass++) { + originX = 0; + originY = 0; + if (pass == 1) { + originX -= ((maxX + minX) >> 6) << 5; + originY -= ((maxY + minY) >> 6) << 5; + } + + if (design->type != RIDE_TYPE_MAZE) { + #pragma region Track + + rotation = RCT2_GLOBAL(0x00F440AE, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); + trackPtr = design->preview[0]; + + while (*trackPtr != 255) { + int trackType = *trackPtr; + if (trackType == 101) + trackType = 255; + + // Station track is a lighter colour + colour = RCT2_ADDRESS(0x0099BA64, uint8)[trackType * 16] & 0x10 ? 222 : 218; + + // Follow a single track piece shape + trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[trackType]; + while (trackBlock->var_00 != 255) { + x = originX; + y = originY; + + switch (rotation & 3) { + case 0: + x += trackBlock->x; + y += trackBlock->y; + break; + case 1: + x += trackBlock->y; + y -= trackBlock->x; + break; + case 2: + x -= trackBlock->x; + y -= trackBlock->y; + break; + case 3: + x -= trackBlock->y; + y += trackBlock->x; + break; + } + + if (pass == 0) { + minX = min(minX, x); + maxX = max(maxX, x); + minY = min(minY, y); + maxY = max(maxY, y); + } else { + pixelX = 80 + ((y / 32) - (x / 32)) * 4; + pixelY = 38 + ((y / 32) + (x / 32)) * 2; + if (pixelX <= 160 && pixelY <= 75) { + pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX]; + + bits = trackBlock->var_08 << (rotation & 3); + bits = (bits & 0x0F) | ((bits & 0xF0) >> 4); + + for (i = 0; i < 4; i++) { + if (bits & 1) pixel[338 + i] = colour; + if (bits & 2) pixel[168 + i] = colour; + if (bits & 4) pixel[ 2 + i] = colour; + if (bits & 8) pixel[172 + i] = colour; + } + } + } + trackBlock++; + } + + // Change rotation and next position based on track curvature + rotation &= 3; + trackType *= 10; + switch (rotation) { + case 0: + originX += RCT2_GLOBAL(0x009968C1 + trackType, sint16); + originY += RCT2_GLOBAL(0x009968C3 + trackType, sint16); + break; + case 1: + originX += RCT2_GLOBAL(0x009968C3 + trackType, sint16); + originY -= RCT2_GLOBAL(0x009968C1 + trackType, sint16); + break; + case 2: + originX -= RCT2_GLOBAL(0x009968C1 + trackType, sint16); + originY -= RCT2_GLOBAL(0x009968C3 + trackType, sint16); + break; + case 3: + originX -= RCT2_GLOBAL(0x009968C3 + trackType, sint16); + originY += RCT2_GLOBAL(0x009968C1 + trackType, sint16); + break; + } + rotation += RCT2_ADDRESS(0x009968BC, uint8)[trackType] - RCT2_ADDRESS(0x009968BB, uint8)[trackType]; + rotation &= 3; + if (RCT2_ADDRESS(0x009968BC, uint8)[trackType] & 4) + rotation |= 4; + if (!(rotation & 4)) { + originX += RCT2_GLOBAL(0x00993CCC + (rotation * 4), sint16); + originY += RCT2_GLOBAL(0x00993CCE + (rotation * 4), sint16); + } + trackPtr += 2; + } + + #pragma endregion + } else { + #pragma region Maze + + rotation = (RCT2_GLOBAL(0x00F440AE, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) & 3; + mazeBlock = (rct_preview_maze*)design->preview[0]; + while (mazeBlock->all != 0) { + x = mazeBlock->x * 32; + y = mazeBlock->y * 32; + switch (rotation) { + case 1: + x = -x; + swap(x, y); + break; + case 2: + x = -x; + y = -y; + break; + case 3: + x = -x; + swap(x, y); + break; + } + x += originX; + y += originY; + + // Entrance or exit is a lighter colour + colour = mazeBlock->type == 8 || mazeBlock->type == 128 ? 222 : 218; + + if (pass == 0) { + minX = min(minX, x); + maxX = max(maxX, x); + minY = min(minY, y); + maxY = max(maxY, y); + } else { + pixelX = 80 + ((y / 32) - (x / 32)) * 4; + pixelY = 38 + ((y / 32) + (x / 32)) * 2; + if (pixelX <= 160 && pixelY <= 75) { + pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX]; + + for (i = 0; i < 4; i++) { + pixel[338 + i] = colour; + pixel[168 + i] = colour; + pixel[ 2 + i] = colour; + pixel[172 + i] = colour; + } + } + } + mazeBlock++; + } + + #pragma endregion + } + } +} + +/** + * + * rct2: 0x0068A15E + */ +static void 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; + } +} + +/** + * + * rct2: 0x006D17C6 + */ +static int window_track_place_get_base_z(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); +} + +static void window_track_place_attempt_placement(int x, int y, int z, int bl, money32 *cost, uint8 *rideIndex) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + money32 result; + + eax = x; + ebx = bl; + ecx = y; + edi = z; + result = game_do_command_p(GAME_COMMAND_47, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + if (cost != NULL) *cost = result; + if (rideIndex != NULL) *rideIndex = edi & 0xFF; +} + /** * * rct2: 0x006CFCA0 @@ -31,11 +424,12 @@ void window_track_place_open() rct_window *w; window_close_construction_windows(); - RCT2_GLOBAL(0x00F44168, void*) = rct2_malloc(13104); - RCT2_CALLPROC_EBPSAFE(0x006D182E); - w = window_create(0, 29, 200, 124, (uint32*)0x0099405C, WC_TRACK_DESIGN_PLACE, 0); - w->widgets = (rct_widget*)0x009D7F18; + _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; w->enabled_widgets = 4 | 8 | 0x10 | 0x20; window_init_scroll_widgets(w); w->colours[0] = 24; @@ -45,8 +439,240 @@ 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(); +} + +/** + * + * rct2: 0x006D0119 + */ +static void window_track_place_close() +{ + window_track_place_clear_provisional(); + viewport_set_visibility(0); + RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~6; + hide_gridlines(); + free(_window_track_place_mini_preview); +} + +/** + * + * rct2: 0x006CFEAC + */ +static void window_track_place_mouseup() +{ + rct_window *w; + short widgetIndex; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_ROTATE: + window_track_place_clear_provisional(); + RCT2_GLOBAL(0x00F440AE, uint16) = (RCT2_GLOBAL(0x00F440AE, uint16) + 1) & 3; + window_invalidate(w); + _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); + _window_track_place_last_x = 0xFFFF; + window_track_place_draw_mini_preview(); + break; + case WIDX_SELECT_DIFFERENT_DESIGN: + window_close(w); + window_track_list_open(_window_track_list_item); + break; + } +} + +/** + * + * rct2: 0x006CFCA0 + */ +static void window_track_place_update(rct_window *w) +{ + if (!(RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3))) + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_TRACK_DESIGN_PLACE) + window_close(w); +} + +/** + * + * rct2: 0x006CFF2D + */ +static void window_track_place_toolupdate() +{ + rct_window *w; + short widgetIndex, x, y; + int i, z; + money32 cost; + uint8 rideIndex; + + window_tool_get_registers(w, widgetIndex, x, y); + + 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 = window_track_place_get_base_z(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++) { + window_track_place_attempt_placement(x, y, z, 105, &cost, &rideIndex); + if (cost != MONEY32_UNDEFINED) { + RCT2_GLOBAL(0x00F440EB, uint16) = rideIndex; + _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); +} + +/** + * + * rct2: 0x006CFF34 + */ +static void window_track_place_tooldown() +{ + rct_window *w; + short widgetIndex, x, y, z; + int i; + money32 cost; + uint8 rideIndex; + + window_tool_get_registers(w, widgetIndex, x, y); + + window_track_place_clear_provisional(); + RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~7; + + sub_68A15E(x, y, &x, &y); + if (x == (short)0x8000) + return; + + // Try increasing Z until a feasible placement is found + z = window_track_place_get_base_z(x, y); + for (i = 0; i < 7; i++) { + RCT2_GLOBAL(0x009A8C29, uint8) |= 1; + window_track_place_attempt_placement(x, y, z, 1, &cost, &rideIndex); + RCT2_GLOBAL(0x009A8C29, uint8) &= ~1; + + if (cost != MONEY32_UNDEFINED) { + window_close_by_id(WC_ERROR, 0); + sound_play_panned(SOUND_PLACE_ITEM, 0x8001, x, y, z); + + RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; + if (RCT2_GLOBAL(0x00F4414E, uint8) & 1) { + window_ride_main_open(rideIndex); + window_close(w); + } else { + RCT2_CALLPROC_X(0x006CC3FB, 0, 0, 0, rideIndex, 0, 0, 0); + w = window_find_by_id(0x80 | WC_RIDE_CONSTRUCTION, 0); + RCT2_CALLPROC_X(w->event_handlers[WE_MOUSE_UP], 0, 0, 0, 29, (int)w, 0, 0); + } + return; + } + + // Check if player did not have enough funds + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) == 827) + break; + + z += 8; + } + + // Unable to build track + sound_play_panned(SOUND_ERROR, 0x8001, x, y, z); +} + +/** + * + * rct2: 0x006D015C + */ +static void window_track_place_toolabort() +{ + window_track_place_clear_provisional(); +} + +/** + * + * rct2: 0x006CFF01 + */ +static void window_track_place_unknown14() +{ + window_track_place_draw_mini_preview(); +} + +/** + * + * rct2: 0x006CFD9D + */ +static void window_track_place_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi, *clippedDpi; + rct_g1_element tmpElement, *subsituteElement, *g1Elements = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element); + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + // Draw mini tile preview + clippedDpi = clip_drawpixelinfo(dpi, w->x + 4, 168, w->y + 18, 78); + if (clippedDpi != NULL) { + subsituteElement = &g1Elements[0]; + tmpElement = *subsituteElement; + 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; + gfx_draw_sprite(clippedDpi, 0, 0, 0, 0); + *subsituteElement = tmpElement; + } + + // 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