diff --git a/src/interface/viewport.c b/src/interface/viewport.c index e0e629f45d..ef09d18d8c 100644 --- a/src/interface/viewport.c +++ b/src/interface/viewport.c @@ -223,74 +223,37 @@ void viewport_update_pointers() *vp = NULL; } -void sub_689174(sint16* x, sint16* y, sint16 *z, uint8 curr_rotation){ +/** + * edx is assumed to be (and always is) the current rotation, so it is not needed as parameter. + * rct2: 0x00689174 + */ +void sub_689174(sint16* x, sint16* y, sint16 *z) +{ //RCT2_CALLFUNC_X(0x00689174, (int*)&x, (int*)&y, (int*)&z, &curr_rotation, (int*)&window, (int*)&viewport, &ebp); sint16 start_x = *x; sint16 start_y = *y; sint16 height = 0; - switch (curr_rotation){ - case 0: - for (int i = 0; i < 6; ++i){ - *x = start_y - start_x / 2 + height; - *y = start_y + start_x / 2 + height; - - height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); - // HACK: This is to prevent the x and y values being set to values outside - // of the map. This can happen when the height is larger than the map size. - if (*x > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16) && *y > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16)){ - *x = start_y - start_x / 2; - *y = start_y + start_x / 2; - } + rct_xy16 pos; + for (int i = 0; i < 6; i++) { + pos = viewport_coord_to_map_coord(start_x, start_y, height); + height = map_element_height((0xFFFF) & pos.x, (0xFFFF) & pos.y); + + // HACK: This is to prevent the x and y values being set to values outside + // of the map. This can happen when the height is larger than the map size. + sint16 max = RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16); + if (pos.x > max && pos.y > max) { + int x_corr[] = { -1, 1, 1, -1 }; + int y_corr[] = { -1, -1, 1, 1 }; + uint32 rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); + pos.x += x_corr[rotation] * height; + pos.y += y_corr[rotation] * height; } - break; - case 1: - for (int i = 0; i < 6; ++i){ - *x = -start_y - start_x / 2 - height; - *y = start_y - start_x / 2 + height; - - height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); - - // HACK: This is to prevent the x and y values being set to values outside - // of the map. This can happen when the height is larger than the map size. - if (*x > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16) && *y > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16)){ - *x = -start_y - start_x / 2; - *y = start_y - start_x / 2; - } - } - break; - case 2: - for (int i = 0; i < 6; ++i){ - *x = -start_y + start_x / 2 - height; - *y = -start_y - start_x / 2 - height; - - height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); - - // HACK: This is to prevent the x and y values being set to values outside - // of the map. This can happen when the height is larger than the map size. - if (*x > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16) && *y > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16)){ - *x = -start_y + start_x / 2; - *y = -start_y - start_x / 2; - } - } - break; - case 3: - for (int i = 0; i < 6; ++i){ - *x = start_x / 2 + start_y + height; - *y = start_x / 2 - start_y - height; - - height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); - - // HACK: This is to prevent the x and y values being set to values outside - // of the map. This can happen when the height is larger than the map size. - if (*x > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16) && *y > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16)){ - *x = start_y + start_x / 2; - *y = -start_y + start_x / 2; - } - } - break; } + + *x = pos.x; + *y = pos.y; *z = height; } @@ -494,8 +457,7 @@ void viewport_update_position(rct_window *window) sint16 y = viewport->view_height / 2 + window->saved_view_y; sint16 z; - int curr_rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); - sub_689174(&x, &y, &z, curr_rotation); + sub_689174(&x, &y, &z); viewport_set_underground_flag(0, window, viewport); //RCT2_CALLPROC_X(0x006E7A15, x, y, z, 0, (int)window, (int)viewport, 0); @@ -1491,18 +1453,117 @@ void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, in //RCT2_CALLPROC_X(0x00685CBF, left, top, 0, right, (int)viewport, (int)dpi, bottom); } +/** + * + * rct2: 0x00688972 + * In: + * screen_x: eax + * screen_y: ebx + * Out: + * x: ax + * y: bx + * map_element: edx ? + * viewport: edi + */ +void sub_688972(int screenX, int screenY, sint16 *x, sint16 *y, rct_viewport **viewport) { + int my_x, my_y, z; + rct_viewport *myViewport; + get_map_coordinates_from_pos(screenX, screenY, 0xFFFE, &my_x, &my_y, &z, NULL, &myViewport); + if (z == 0) { + *x = 0x8000; + return; + } + + RCT2_GLOBAL(0x00F1AD34, sint16) = my_x; + RCT2_GLOBAL(0x00F1AD36, sint16) = my_y; + RCT2_GLOBAL(0x00F1AD38, sint16) = my_x + 31; + RCT2_GLOBAL(0x00F1AD3A, sint16) = my_y + 31; + + rct_xy16 start_vp_pos = screen_coord_to_viewport_coord(myViewport, screenX, screenY); + rct_xy16 map_pos = { my_x + 16, my_y + 16 }; + + for (int i = 0; i < 5; i++) { + z = map_element_height(map_pos.x, map_pos.y); + map_pos = viewport_coord_to_map_coord(start_vp_pos.x, start_vp_pos.y, z); + map_pos.x = clamp(RCT2_GLOBAL(0x00F1AD34, sint16), map_pos.x, RCT2_GLOBAL(0x00F1AD38, sint16)); + map_pos.y = clamp(RCT2_GLOBAL(0x00F1AD36, sint16), map_pos.y, RCT2_GLOBAL(0x00F1AD3A, sint16)); + } + + *x = map_pos.x; + *y = map_pos.y; + + if (viewport != NULL) *viewport = myViewport; +} + /** * * rct2: 0x0068958D */ -void screen_pos_to_map_pos(short *x, short *y) +void screen_pos_to_map_pos(sint16 *x, sint16 *y, int *direction) { - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = *x; - ebx = *y; - RCT2_CALLFUNC_X(0x0068958D, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - *x = eax & 0xFFFF; - *y = ebx & 0xFFFF; + sub_688972(*x, *y, x, y, NULL); + if (*x == 0x8000) + return; + + int my_direction; + int dist_from_center_x = abs(*x % 32); + int dist_from_center_y = abs(*y % 32); + if (dist_from_center_x > 8 && dist_from_center_x < 24 && + dist_from_center_y > 8 && dist_from_center_y < 24) { + my_direction = 4; + } else { + sint16 mod_x = *x & 0x1F; + sint16 mod_y = *y & 0x1F; + if (mod_x <= 16) { + if (mod_y < 16) { + my_direction = 2; + } else { + my_direction = 3; + } + } else { + if (mod_y < 16) { + my_direction = 0; + } else { + my_direction = 1; + } + } + } + + *x = *x & ~0x1F; + *y = *y & ~0x1F; + if (direction != NULL) *direction = my_direction; +} + +rct_xy16 screen_coord_to_viewport_coord(rct_viewport *viewport, uint16 x, uint16 y) +{ + rct_xy16 ret; + ret.x = ((x - viewport->x) << viewport->zoom) + viewport->view_x; + ret.y = ((y - viewport->y) << viewport->zoom) + viewport->view_y; + return ret; +} + +rct_xy16 viewport_coord_to_map_coord(int x, int y, int z) +{ + rct_xy16 ret; + switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) { + case 0: + ret.x = -x / 2 + y + z; + ret.y = x / 2 + y + z; + break; + case 1: + ret.x = -x / 2 - y - z; + ret.y = -x / 2 + y + z; + break; + case 2: + ret.x = x / 2 - y - z; + ret.y = -x / 2 - y - z; + break; + case 3: + ret.x = x / 2 + y + z; + ret.y = x / 2 - y - z; + break; + } + return ret; } /** @@ -1676,28 +1737,29 @@ void viewport_set_visibility(uint8 mode) * y: cx * z: bl * mapElement: edx + * viewport: edi */ -void get_map_coordinates_from_pos(int screenX, int screenY, int flags, int *x, int *y, int *z, rct_map_element **mapElement) +void get_map_coordinates_from_pos(int screenX, int screenY, int flags, int *x, int *y, int *z, rct_map_element **mapElement, rct_viewport **viewport) { RCT2_GLOBAL(0x9AC154, uint16_t) = flags & 0xFFFF; RCT2_GLOBAL(0x9AC148, uint8_t) = 0; rct_window* window = window_find_from_point(screenX, screenY); if (window != NULL && window->viewport != NULL) { - rct_viewport* viewport = window->viewport; + rct_viewport* myviewport = window->viewport; RCT2_GLOBAL(0x9AC138 + 4, int16_t) = screenX; RCT2_GLOBAL(0x9AC138 + 6, int16_t) = screenY; - screenX -= (int)viewport->x; - screenY -= (int)viewport->y; - if (screenX >= 0 && screenX < (int)viewport->width && screenY >= 0 && screenY < (int)viewport->height) + screenX -= (int)myviewport->x; + screenY -= (int)myviewport->y; + if (screenX >= 0 && screenX < (int)myviewport->width && screenY >= 0 && screenY < (int)myviewport->height) { - screenX <<= viewport->zoom; - screenY <<= viewport->zoom; - screenX += (int)viewport->view_x; - screenY += (int)viewport->view_y; - RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_ZOOM, uint16_t) = viewport->zoom; - screenX &= (0xFFFF << viewport->zoom) & 0xFFFF; - screenY &= (0xFFFF << viewport->zoom) & 0xFFFF; + screenX <<= myviewport->zoom; + screenY <<= myviewport->zoom; + screenX += (int)myviewport->view_x; + screenY += (int)myviewport->view_y; + RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_ZOOM, uint16_t) = myviewport->zoom; + screenX &= (0xFFFF << myviewport->zoom) & 0xFFFF; + screenY &= (0xFFFF << myviewport->zoom) & 0xFFFF; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, int16_t) = screenX; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_Y, int16_t) = screenY; rct_drawpixelinfo* dpi = RCT2_ADDRESS(RCT2_ADDRESS_VIEWPORT_DPI, rct_drawpixelinfo); @@ -1713,6 +1775,7 @@ void get_map_coordinates_from_pos(int screenX, int screenY, int flags, int *x, i RCT2_CALLPROC_X(0x688217, 0, 0, 0, 0, 0, 0, 0); RCT2_CALLPROC_X(0x68862C, 0, 0, 0, 0, 0, 0, 0); } + if (viewport != NULL) *viewport = myviewport; } if (z != NULL) *z = RCT2_GLOBAL(0x9AC148, uint8_t); if (x != NULL) *x = (int)RCT2_GLOBAL(0x9AC14C, int16_t); diff --git a/src/interface/viewport.h b/src/interface/viewport.h index 27eae985d7..e53019738f 100644 --- a/src/interface/viewport.h +++ b/src/interface/viewport.h @@ -82,9 +82,12 @@ void viewport_update_position(rct_window *window); void viewport_render(rct_drawpixelinfo *dpi, rct_viewport *viewport, int left, int top, int right, int bottom); void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, int top, int right, int bottom); -void sub_689174(sint16* x, sint16* y, sint16 *z, uint8 curr_rotation); +void sub_689174(sint16* x, sint16* y, sint16 *z); -void screen_pos_to_map_pos(short *x, short *y); +rct_xy16 screen_coord_to_viewport_coord(rct_viewport *viewport, uint16 x, uint16 y); +rct_xy16 viewport_coord_to_map_coord(int x, int y, int z); +void sub_688972(int screenX, int screenY, sint16 *x, sint16 *y, rct_viewport **viewport); +void screen_pos_to_map_pos(sint16 *x, sint16 *y, int *direction); void show_gridlines(); void hide_gridlines(); @@ -94,7 +97,7 @@ 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); +void get_map_coordinates_from_pos(int screenX, int screenY, int flags, int *x, int *y, int *z, rct_map_element **mapElement, rct_viewport **viewport); int viewport_interaction_get_item_left(int x, int y, viewport_interaction_info *info); int viewport_interaction_left_over(int x, int y); diff --git a/src/interface/viewport_interaction.c b/src/interface/viewport_interaction.c index d20a8204c4..9a33a1821d 100644 --- a/src/interface/viewport_interaction.c +++ b/src/interface/viewport_interaction.c @@ -58,7 +58,7 @@ int viewport_interaction_get_item_left(int x, int y, viewport_interaction_info * if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && s6Info->var_000 != 6) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; - get_map_coordinates_from_pos(x, y, 0xFF79, &info->x, &info->y, &info->type, &info->mapElement); + get_map_coordinates_from_pos(x, y, 0xFF79, &info->x, &info->y, &info->type, &info->mapElement, NULL); mapElement = info->mapElement; sprite = (rct_sprite*)mapElement; @@ -178,7 +178,7 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && s6Info->var_000 != 6) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; - get_map_coordinates_from_pos(x, y, 9, &info->x, &info->y, &info->type, &info->mapElement); + get_map_coordinates_from_pos(x, y, 9, &info->x, &info->y, &info->type, &info->mapElement, NULL); mapElement = info->mapElement; sprite = (rct_sprite*)mapElement; diff --git a/src/interface/window.c b/src/interface/window.c index a08b345796..aacdba4538 100644 --- a/src/interface/window.c +++ b/src/interface/window.c @@ -1166,12 +1166,9 @@ void window_rotate_camera(rct_window *w) sint16 y = (viewport->height >> 1) + viewport->y; sint16 z; - uint8 rot = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); - - int ecx, edx, esi, edi = (int)viewport, ebp; //has something to do with checking if middle of the viewport is obstructed - RCT2_CALLFUNC_X(0x00688972, (int*)&x, (int*)&y, &ecx, &edx, &esi, &edi, &ebp); - rct_viewport *other = (rct_viewport*)edi; + rct_viewport *other; + sub_688972(x, y, &x, &y, &other); // other != viewport probably triggers on viewports in ride or guest window? // x is 0x8000 if middle of viewport is obstructed by another window? @@ -1179,12 +1176,12 @@ void window_rotate_camera(rct_window *w) x = (viewport->view_width >> 1) + viewport->view_x; y = (viewport->view_height >> 1) + viewport->view_y; - sub_689174(&x, &y, &z, rot); + sub_689174(&x, &y, &z); } else { z = map_element_height(x, y); } - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = (rot + 1) % 4; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) + 1) % 4; int new_x, new_y; center_2d_coordinates(x, y, z, &new_x, &new_y, viewport); diff --git a/src/windows/cheats.c b/src/windows/cheats.c index bc66a4d7ed..1c8a1a2abe 100644 --- a/src/windows/cheats.c +++ b/src/windows/cheats.c @@ -29,6 +29,7 @@ #include "../scenario.h" #include "../sprites.h" #include "../world/climate.h" +#include "../world/footpath.h" #include "../world/park.h" #include "../world/sprite.h" @@ -771,17 +772,16 @@ static void window_cheats_misc_tool_update() map_invalidate_selection_rect(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); - int temp_y = y + 16; - int eax = x, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - RCT2_CALLFUNC_X(0x689726, &eax, &temp_y, &ecx, &edx, &esi, &edi, &ebp); - if (eax != 0x8000){ + int map_x, map_y; + footpath_get_coordinates_from_pos(x, y + 16, &map_x, &map_y, NULL, NULL); + if (map_x != 0x8000){ RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 1; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = eax; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = eax; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = temp_y; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = temp_y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = map_x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = map_x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = map_y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = map_y; map_invalidate_selection_rect(); } @@ -798,9 +798,8 @@ static void window_cheats_misc_tool_down() if (widgetIndex != WIDX_ZERO_CLEARANCE) return; - int dest_x = x, dest_y = y, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - dest_y += 16; - RCT2_CALLFUNC_X(0x689726, &dest_x, &dest_y, &ecx, &edx, &esi, &edi, &ebp); + int dest_x, dest_y; + footpath_get_coordinates_from_pos(x, y + 16, &dest_x, &dest_y, NULL, NULL); if (dest_x == 0x8000)return; diff --git a/src/windows/footpath.c b/src/windows/footpath.c index d2de3966f0..da1c7b4437 100644 --- a/src/windows/footpath.c +++ b/src/windows/footpath.c @@ -673,7 +673,7 @@ static void window_footpath_set_provisional_path_at_point(int x, int y) map_invalidate_selection_rect(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 2); - get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement); + get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement, NULL); if (z == 0) { RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); @@ -716,7 +716,7 @@ static void window_footpath_set_selection_start_bridge_at_point(int screenX, int map_invalidate_selection_rect(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0) & ~(1 << 2); - sub_68A0C9(screenX, screenY, &x, &y, &direction, &mapElement); + footpath_bridge_get_info_from_pos(screenX, screenY, &x, &y, &direction, &mapElement); if (x == 0x8000) return; @@ -760,7 +760,7 @@ static void window_footpath_place_path_at_point(int x, int y) footpath_provisional_update(); - get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement); + get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement, NULL); if (z == 0) return; @@ -794,7 +794,7 @@ static void window_footpath_start_bridge_at_point(int screenX, int screenY) int x, y, z, direction; rct_map_element *mapElement; - sub_68A0C9(screenX, screenY, &x, &y, &direction, &mapElement); + footpath_bridge_get_info_from_pos(screenX, screenY, &x, &y, &direction, &mapElement); if (x == 0x8000) return; diff --git a/src/windows/guest.c b/src/windows/guest.c index b644c00486..c792b3cd11 100644 --- a/src/windows/guest.c +++ b/src/windows/guest.c @@ -32,6 +32,7 @@ #include "../interface/viewport.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../world/footpath.h" #include "dropdown.h" #include "error.h" @@ -1141,24 +1142,23 @@ void window_guest_overview_tool_update(){ map_invalidate_selection_rect(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); - int temp_y = y + 16; - int eax = x, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - RCT2_CALLFUNC_X(0x689726, &eax, &temp_y, &ecx, &edx, &esi, &edi, &ebp); - if (eax != 0x8000){ + int map_x, map_y; + footpath_get_coordinates_from_pos(x, y + 16, &map_x, &map_y, NULL, NULL); + if (map_x != 0x8000){ RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 1; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = eax; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = eax; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = temp_y; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = temp_y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = map_x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = map_x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = map_y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = map_y; map_invalidate_selection_rect(); } RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; int ebx; - get_map_coordinates_from_pos(x, y, 0, NULL, NULL, &ebx, NULL); + get_map_coordinates_from_pos(x, y, 0, NULL, NULL, &ebx, NULL, NULL); if (ebx == 0) return; @@ -1174,8 +1174,8 @@ void window_guest_overview_tool_update(){ ebx = (RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2])[22]; ebx += w->var_492 >> 2; - ebp = peep->tshirt_colour << 19; - ecx = peep->trousers_colour << 24; + int ebp = peep->tshirt_colour << 19; + int ecx = peep->trousers_colour << 24; ebx |= ebp | ecx | 0xA0000000; RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32) = ebx; @@ -1191,9 +1191,9 @@ void window_guest_overview_tool_down(){ if (widgetIndex != WIDX_PICKUP) return; - int dest_x = x, dest_y = y, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - dest_y += 16; - RCT2_CALLFUNC_X(0x689726, &dest_x, &dest_y, &ecx, &edx, &esi, &edi, &ebp); + int dest_x, dest_y; + rct_map_element *mapElement; + footpath_get_coordinates_from_pos(x, y + 16, &dest_x, &dest_y, NULL, &mapElement); if (dest_x == 0x8000)return; @@ -1205,7 +1205,7 @@ void window_guest_overview_tool_down(){ int tile_y = dest_y & 0xFFE0; int tile_x = dest_x & 0xFFE0; - int dest_z = ((uint8*)edx)[2] * 8 + 16; + int dest_z = mapElement->base_height * 8 + 16; if (!map_is_location_owned(tile_x, tile_y, dest_z)){ window_error_open(0x785,-1); diff --git a/src/windows/park.c b/src/windows/park.c index 2cc58b47d8..4e10bfe646 100644 --- a/src/windows/park.c +++ b/src/windows/park.c @@ -812,7 +812,7 @@ static void window_park_entrance_toolupdate() if (widgetIndex == WIDX_BUY_LAND_RIGHTS) { map_invalidate_selection_rect(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= 0xFFFE; - screen_pos_to_map_pos(&x, &y); + screen_pos_to_map_pos(&x, &y, NULL); if (x != SPRITE_LOCATION_NULL) { RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 1; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; diff --git a/src/windows/ride.c b/src/windows/ride.c index 7d646297e7..51584a8f6d 100644 --- a/src/windows/ride.c +++ b/src/windows/ride.c @@ -3541,7 +3541,7 @@ static void window_ride_set_track_colour_scheme(rct_window *w, int x, int y) int z; - get_map_coordinates_from_pos(x, y, -5, &x, &y, &z, &mapElement); + get_map_coordinates_from_pos(x, y, -5, &x, &y, &z, &mapElement, NULL); // Get map coordinates from point /*int eax, ebx, ecx, edx, esi, edi, ebp; eax = x; diff --git a/src/windows/staff.c b/src/windows/staff.c index 6b3703417e..8dfb1e503a 100644 --- a/src/windows/staff.c +++ b/src/windows/staff.c @@ -27,6 +27,7 @@ #include "../peep/peep.h" #include "../peep/staff.h" #include "../sprites.h" +#include "../world/footpath.h" #include "../world/sprite.h" #include "../world/scenery.h" #include "dropdown.h" @@ -1085,7 +1086,7 @@ void window_staff_overview_tool_update(){ RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; int z; - get_map_coordinates_from_pos(x, y, 0, NULL, NULL, &z, NULL); + get_map_coordinates_from_pos(x, y, 0, NULL, NULL, &z, NULL, NULL); if (z == 0) return; @@ -1115,9 +1116,9 @@ void window_staff_overview_tool_down(){ if (widgetIndex == WIDX_PICKUP){ - int dest_x = x, dest_y = y, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - dest_y += 16; - RCT2_CALLFUNC_X(0x689726, &dest_x, &dest_y, &ecx, &edx, &esi, &edi, &ebp); + int dest_x, dest_y; + rct_map_element *mapElement; + footpath_get_coordinates_from_pos(x, y + 16, &dest_x, &dest_y, NULL, &mapElement); if (dest_x == 0x8000)return; @@ -1129,7 +1130,7 @@ void window_staff_overview_tool_down(){ int tile_y = dest_y & 0xFFE0; int tile_x = dest_x & 0xFFE0; - int dest_z = ((uint8*)edx)[2] * 8 + 16; + int dest_z = mapElement->base_height * 8 + 16; if (!map_is_location_owned(tile_x, tile_y, dest_z)){ window_error_open(0x785, -1); @@ -1165,8 +1166,8 @@ void window_staff_overview_tool_down(){ RCT2_GLOBAL(0x9DE550, sint32) = -1; } else if (widgetIndex == WIDX_PATROL){ - int dest_x = x, dest_y = y, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - RCT2_CALLFUNC_X(0x689726, &dest_x, &dest_y, &ecx, &edx, &esi, &edi, &ebp); + int dest_x, dest_y; + footpath_get_coordinates_from_pos(x, y, &dest_x, &dest_y, NULL, NULL); if (dest_x == 0x8000)return; diff --git a/src/windows/track_place.c b/src/windows/track_place.c index 1023196bae..001c4ff014 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.c @@ -304,14 +304,69 @@ static void window_track_place_draw_mini_preview() * * rct2: 0x0068A15E */ -static void sub_68A15E(int x, int y, short *ax, short *bx) +static void sub_68A15E(int screenX, int screenY, short *x, short *y, int *direction, rct_map_element **mapElement) { - 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); + int my_x, my_y, z; + rct_map_element *myMapElement; + rct_viewport *viewport; + get_map_coordinates_from_pos(screenX, screenY, 0xFFF6, &my_x, &my_y, &z, &myMapElement, &viewport); + + if (z == 0) { + *x = 0x8000; + return; + } + + RCT2_GLOBAL(0x00F1AD3E, uint8) = z; + RCT2_GLOBAL(0x00F1AD30, rct_map_element*) = myMapElement; + + if (z == 4) { + // myMapElement appears to be water + z = myMapElement->properties.surface.terrain; + z = (z & MAP_ELEMENT_WATER_HEIGHT_MASK) << 4; + } + + RCT2_GLOBAL(0x00F1AD3C, uint16) = z; + RCT2_GLOBAL(0x00F1AD34, sint16) = my_x; + RCT2_GLOBAL(0x00F1AD36, sint16) = my_y; + RCT2_GLOBAL(0x00F1AD38, sint16) = my_x + 31; + RCT2_GLOBAL(0x00F1AD3A, sint16) = my_y + 31; + + rct_xy16 start_vp_pos = screen_coord_to_viewport_coord(viewport, screenX, screenY); + rct_xy16 map_pos = { my_x + 16, my_y + 16 }; + + for (int i = 0; i < 5; i++) { + if (RCT2_GLOBAL(0x00F1AD3E, uint8) != 4) { + z = map_element_height(map_pos.x, map_pos.y); + } else { + z = RCT2_GLOBAL(0x00F1AD3C, uint16); + } + map_pos = viewport_coord_to_map_coord(start_vp_pos.x, start_vp_pos.y, z); + map_pos.x = clamp(RCT2_GLOBAL(0x00F1AD34, sint16), map_pos.x, RCT2_GLOBAL(0x00F1AD38, sint16)); + map_pos.y = clamp(RCT2_GLOBAL(0x00F1AD36, sint16), map_pos.y, RCT2_GLOBAL(0x00F1AD3A, sint16)); + } + + // Determine to which edge the cursor is closest + int myDirection; + int mod_x = map_pos.x & 0x1F; + int mod_y = map_pos.y & 0x1F; + if (mod_x < mod_y) { + if (mod_x + mod_y < 32) { + myDirection = 0; + } else { + myDirection = 1; + } + } else { + if (mod_x + mod_y < 32) { + myDirection = 3; + } else { + myDirection = 2; + } + } + + *x = map_pos.x & ~0x1F; + *y = map_pos.y & ~0x1F; + if (direction != NULL) *direction = myDirection; + if (mapElement != NULL) *mapElement = myMapElement; } /** @@ -483,7 +538,7 @@ static void window_track_place_toolupdate() RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~7; // Get the tool map position - sub_68A15E(x, y, &x, &y); + sub_68A15E(x, y, &x, &y, NULL, NULL); if (x == (short)0x8000) { window_track_place_clear_provisional(); return; @@ -545,7 +600,7 @@ static void window_track_place_tooldown() map_invalidate_map_selection_tiles(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~7; - sub_68A15E(x, y, &x, &y); + sub_68A15E(x, y, &x, &y, NULL, NULL); if (x == (short)0x8000) return; diff --git a/src/windows/viewport.c b/src/windows/viewport.c index 924926ad1b..9fb7fcf6cc 100644 --- a/src/windows/viewport.c +++ b/src/windows/viewport.c @@ -176,7 +176,7 @@ static void window_viewport_mouseup() case WIDX_LOCATE: mainWindow = window_get_main(); if (mainWindow != NULL) { - get_map_coordinates_from_pos(w->x + (w->width / 2), w->y + (w->height / 2), 0, &x, &y, NULL, NULL); + get_map_coordinates_from_pos(w->x + (w->width / 2), w->y + (w->height / 2), 0, &x, &y, NULL, NULL, NULL); window_scroll_to_location(mainWindow, x, y, map_element_height(x, y)); } break; diff --git a/src/world/footpath.c b/src/world/footpath.c index 4a6ce75530..8a0f7c594e 100644 --- a/src/world/footpath.c +++ b/src/world/footpath.c @@ -21,6 +21,7 @@ #include "../addresses.h" #include "../game.h" #include "../localisation/localisation.h" +#include "../util/util.h" #include "footpath.h" #include "map.h" @@ -473,20 +474,137 @@ void footpath_provisional_update() footpath_provisional_remove(); } +/** + * Determines the location of the footpath at which we point with the cursor. If no footpath is underneath the cursor, + * then return the location of the ground tile. Besides the location it also computes the direction of the yellow arrow + * when we are going to build a footpath bridge/tunnel. + * rct2: 0x00689726 + * In: + * screenX: eax + * screenY: ebx + * Out: + * x: ax + * y: bx + * direction: ecx + * mapElement: edx + */ +void footpath_get_coordinates_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement) +{ + int z; + rct_map_element *myMapElement; + rct_viewport *viewport; + get_map_coordinates_from_pos(screenX, screenY, 0xFFDF, x, y, &z, &myMapElement, &viewport); + if (z != 6 || !(viewport->flags & (VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL))) { + get_map_coordinates_from_pos(screenX, screenY, 0xFFDE, x, y, &z, &myMapElement, &viewport); + if (z == 0) { + if (x != NULL) *x = 0x8000; + return; + } + } + + RCT2_GLOBAL(0x00F1AD3E, uint8) = z; + RCT2_GLOBAL(0x00F1AD30, rct_map_element*) = myMapElement; + + if (z == 6) { + // mapElement appears to be a footpath + z = myMapElement->base_height * 8; + if (myMapElement->properties.path.type & (1 << 2)) + z += 8; + } + + RCT2_GLOBAL(0x00F1AD3C, uint16) = z; + RCT2_GLOBAL(0x00F1AD34, sint16) = *x; + RCT2_GLOBAL(0x00F1AD36, sint16) = *y; + RCT2_GLOBAL(0x00F1AD38, sint16) = *x + 31; + RCT2_GLOBAL(0x00F1AD3A, sint16) = *y + 31; + + *x += 16; + *y += 16; + + rct_xy16 start_vp_pos = screen_coord_to_viewport_coord(viewport, screenX, screenY); + rct_xy16 map_pos = { *x, *y }; + + for (int i = 0; i < 5; i++) { + if (RCT2_GLOBAL(0x00F1AD3E, uint8) != 6) { + z = map_element_height(map_pos.x, map_pos.y); + } else { + z = RCT2_GLOBAL(0x00F1AD3C, uint16); + } + map_pos = viewport_coord_to_map_coord(start_vp_pos.x, start_vp_pos.y, z); + map_pos.x = clamp(RCT2_GLOBAL(0x00F1AD34, sint16), map_pos.x, RCT2_GLOBAL(0x00F1AD38, sint16)); + map_pos.y = clamp(RCT2_GLOBAL(0x00F1AD36, sint16), map_pos.y, RCT2_GLOBAL(0x00F1AD3A, sint16)); + } + + // Determine to which edge the cursor is closest + uint32 myDirection; + int mod_x = map_pos.x & 0x1F, mod_y = map_pos.y & 0x1F; + if (mod_x < mod_y) { + if (mod_x + mod_y < 32) { + myDirection = 0; + } else { + myDirection = 1; + } + } else { + if (mod_x + mod_y < 32) { + myDirection = 3; + } else { + myDirection = 2; + } + } + + if (x != NULL) *x = map_pos.x & ~0x1F; + if (y != NULL) *y = map_pos.y & ~0x1F; + if (direction != NULL) *direction = myDirection; + if (mapElement != NULL) *mapElement = myMapElement; + // We should get the rct_map_element from 0x00F1AD30 here, but we set it earlier to our myMapElement anyway. +} + /** * * rct2: 0x0068A0C9 + * screenX: eax + * screenY: ebx + * x: ax + * y: bx + * direction: cl + * mapElement: edx */ -void sub_68A0C9(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement) +void footpath_bridge_get_info_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement) { - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = screenX; - ebx = screenY; - RCT2_CALLFUNC_X(0x0068A0C9, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if (x != NULL) *x = *((uint16*)&eax); - if (y != NULL) *y = *((uint16*)&ebx); - if (direction != NULL) *direction = *((uint8*)&ecx); - if (mapElement != NULL) *mapElement = (rct_map_element*)edx; + // First check if we point at an entrance or exit. In that case, we would want the path coming from the entrance/exit. + int z; + rct_viewport *viewport; + get_map_coordinates_from_pos(screenX, screenY, 0xFFFB, x, y, &z, mapElement, &viewport); + if (z == 3 + && viewport->flags & (VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL) + && map_element_get_type(*mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) { + int ebp = (*mapElement)->properties.entrance.type << 4; + int bl = (*mapElement)->properties.entrance.index & 0xF; + if (RCT2_GLOBAL(0x0097B974 + ebp + bl, uint16) & 0xF) { + int bx = bitscanforward(RCT2_GLOBAL(0x0097B974 + ebp + bl, uint16)); + bx += (*mapElement)->type; + bx &= 3; + if (direction != NULL) *direction = bx; + return; + } + } + + get_map_coordinates_from_pos(screenX, screenY, 0xFFDA, x, y, &z, mapElement, &viewport); + if (z == 3 && map_element_get_type(*mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) { + int ebp = (*mapElement)->properties.entrance.type << 4; + int bl = (*mapElement)->properties.entrance.index & 0xF; // Seems to be always 0? + // The table at 0x0097B974 is only 48 bytes big + if (RCT2_GLOBAL(0x0097B974 + ebp + bl, uint16) & 0xF) { + int bx = bitscanforward(RCT2_GLOBAL(0x0097B974 + ebp + bl, uint16)); + bx += (*mapElement)->type; // First two bits seem to contain the direction of entrance/exit + bx &= 3; + if (direction != NULL) *direction = bx; + return; + } + } + + // We point at something else + footpath_get_coordinates_from_pos(screenX, screenY, x, y, direction, mapElement); } /** diff --git a/src/world/footpath.h b/src/world/footpath.h index 957c0c7f93..86574919b5 100644 --- a/src/world/footpath.h +++ b/src/world/footpath.h @@ -46,6 +46,7 @@ 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); void footpath_provisional_remove(); void footpath_provisional_update(); -void sub_68A0C9(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement); +void footpath_get_coordinates_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement); +void footpath_bridge_get_info_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement); #endif