diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 95409e492a..5469d23c44 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -63,6 +63,7 @@ + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index b9706a8846..b1d0f73016 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -443,6 +443,9 @@ Source\Interface + + Source\Interface + diff --git a/src/input.c b/src/input.c index 096ca1c0fd..efd171f542 100644 --- a/src/input.c +++ b/src/input.c @@ -60,302 +60,116 @@ void invalidate_scroll(); static rct_mouse_data* get_mouse_input(); void map_element_right_click(int type, rct_map_element *mapElement, int x, int y); int sub_6EDE88(int x, int y, rct_map_element **mapElement, int *outX, int *outY); +int get_next_key(); +static void game_handle_input_mouse(int x, int y, int state); +void game_handle_edge_scroll(); +void game_handle_key_scroll(); +static void input_leftmousedown(int x, int y, rct_window *w, int widgetIndex); +void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_window* w, rct_widget* widget); +void sub_6ED990(char cursor_id); + +#pragma region Mouse input /** * - * rct2: 0x006E95F9 + * rct2: 0x006EA627 */ -static void input_leftmousedown(int x, int y, rct_window *w, int widgetIndex) +void game_handle_input() { - // RCT2_CALLPROC_X(0x006E95F9, x, y, state, widgetIndex, w, widget, 0); + rct_window *w; + int x, y, state; - rct_windowclass windowClass = 255; - rct_windownumber windowNumber = 0; - rct_widget *widget; - - if (w != NULL) { - windowClass = w->classification; - windowNumber = w->number; + if (RCT2_GLOBAL(0x009DEA64, uint16) & 2) { + RCT2_GLOBAL(0x009DEA64, uint16) &= ~2; + game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 2, 0); } - window_close_by_class(WC_ERROR); - window_close_by_class(WC_TOOLTIP); + if (RCT2_GLOBAL(0x009ABDF2, uint8) != 0) { + for (w = g_window_list; w < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); w++) + RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_07], 0, 0, 0, 0, (int)w, 0, 0); - w = window_find_by_number(windowClass, windowNumber); - if (w == NULL) - return; + sub_6EA73F(); + RCT2_CALLPROC_EBPSAFE(0x006E8346); // update_cursor_position - w = window_bring_to_front(w); - if (widgetIndex == -1) - return; + for (;;) { + game_get_next_input(&x, &y, &state); + if (state == 0) + break; - widget = &w->widgets[widgetIndex]; - - switch (widget->type) { - case WWT_FRAME: - case WWT_RESIZE: - if (!(w->flags & WF_RESIZABLE)) - break; - if (w->min_width == w->max_width && w->min_height == w->max_height) - break; - if (x < w->x + w->width - 19 || y < w->y + w->height - 19) - break; - - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESIZING; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) = windowClass; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) = windowNumber; - break; - case WWT_VIEWPORT: - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_VIEWPORT_LEFT; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) = windowClass; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) = windowNumber; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) - break; - - w = window_find_by_number( - RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), - RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) - ); - if (w == NULL) - break; - - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DOWN], x, y, 0, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), (int)w, 0, 0); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_4; - break; - case WWT_CAPTION: - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_DRAGGING; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) = windowClass; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) = windowNumber; - break; - case WWT_SCROLL: - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_SCROLL_LEFT; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = windowClass; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber) = windowNumber; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) = y; - - int eax, ebx, scroll_area, scroll_id; - scroll_id = 0; // safety - widget_scroll_get_part(w, widget, x, y, &eax, &ebx, &scroll_area, &scroll_id); - - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_AREA, uint16) = scroll_area; - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_ID, uint32) = scroll_id * sizeof(rct_scroll);//We do this because scroll id is not all decompiled - RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_15], RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_ID, uint32), ebx, scroll_area, scroll_id, (int)w, (int)widget, 0); - if (scroll_area == SCROLL_PART_VIEW){ - RCT2_CALLPROC_X(w->event_handlers[WE_SCROLL_MOUSEDOWN], scroll_id / sizeof(rct_scroll), ebx, eax, ebx, (int)w, (int)widget, 0); - break; + game_handle_input_mouse(x, y, state & 0xFF); } - rct_widget* widg = &w->widgets[widgetIndex]; - rct_scroll* scroll = &w->scrolls[scroll_id]; + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5) { + game_handle_input_mouse(x, y, state); + } else if (x != 0x80000000) { + x = clamp(0, x, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 1); + y = clamp(0, y, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - 1); - int widget_width = widg->right - widg->left - 1; - if (scroll->flags & VSCROLLBAR_VISIBLE) - widget_width -= 11; - widget_width = max(scroll->h_right - widget_width, 0); - - int widget_height = widg->bottom - widg->top - 1; - if (scroll->flags & HSCROLLBAR_VISIBLE) - widget_height -= 11; - widget_height = max(scroll->v_bottom - widget_height, 0); - - switch (scroll_area) { - case SCROLL_PART_HSCROLLBAR_LEFT: - scroll->h_left = max(scroll->h_left - 3, 0); - break; - case SCROLL_PART_HSCROLLBAR_RIGHT: - scroll->h_left = min(scroll->h_left + 3, widget_width); - break; - case SCROLL_PART_HSCROLLBAR_LEFT_TROUGH: - scroll->h_left = max(scroll->h_left - widget_width , 0); - break; - case SCROLL_PART_HSCROLLBAR_RIGHT_TROUGH: - scroll->h_left = min(scroll->h_left + widget_width, widget_width); - break; - case SCROLL_PART_VSCROLLBAR_TOP: - scroll->v_top = max(scroll->v_top - 3, 0); - break; - case SCROLL_PART_VSCROLLBAR_BOTTOM: - scroll->v_top = min(scroll->v_top + 3, widget_height); - break; - case SCROLL_PART_VSCROLLBAR_TOP_TROUGH: - scroll->v_top = max(scroll->v_top - widget_height, 0); - break; - case SCROLL_PART_VSCROLLBAR_BOTTOM_TROUGH: - scroll->v_top = min(scroll->v_top + widget_height, widget_height); - break; - default: - break; + game_handle_input_mouse(x, y, state); + process_mouse_over(x, y); + process_mouse_tool(x, y); } - widget_scroll_update_thumbs(w, widgetIndex); - window_invalidate_by_number(widgetIndex, w->classification); - break; - default: - if (!widget_is_enabled(w, widgetIndex)) - break; - if (widget_is_disabled(w, widgetIndex)) - break; - - sound_play_panned(SOUND_CLICK_1, w->x + (widget->left + widget->right) / 2, 0, 0, 0); - - // Set new cursor down widget - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = windowClass; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber) = windowNumber; - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_WIDGET_PRESSED; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_WIDGET_PRESSED; - RCT2_GLOBAL(0x009DE528, uint16) = 1; - - widget_invalidate_by_number(windowClass, windowNumber, widgetIndex); - RCT2_CALLPROC_WE_MOUSE_DOWN(w->event_handlers[WE_MOUSE_DOWN], widgetIndex, w, widget); - break; } + + for (w = g_window_list; w < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); w++) + RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_08], 0, 0, 0, 0,(int) w, 0, 0); } -/* rct2: 0x6E8DA7 */ -void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_window* w, rct_widget* widget ){ - //RCT2_CALLPROC_X(0x006E8DA7, x, y, state, widgetIndex, (int)w, (int)widget, 0); +/** + * + * rct2: 0x006E83C7 + */ +static void game_get_next_input(int *x, int *y, int *state) +{ + rct_mouse_data* eax = get_mouse_input(); + if (eax == NULL) { + *x = gCursorState.x; + *y = gCursorState.y; + *state = 0; + return; + } + + *x = eax->x; + *y = eax->y; + *state = eax->state; + + //int eax, ebx, ecx, edx, esi, edi, ebp; + //RCT2_CALLFUNC_X(0x006E83C7, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + //*x = eax & 0xFFFF; + //*y = ebx & 0xFFFF; + //*state = ecx & 0xFF; //return; - RCT2_GLOBAL(0x1420054, uint16) = x; - RCT2_GLOBAL(0x1420056, uint16) = y; - rct_windowclass cursor_w_class; - rct_windownumber cursor_w_number; - cursor_w_class = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass); - cursor_w_number = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber); - int cursor_widgetIndex = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint32); + //int on_tutorial = RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8); + //if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5) { + // if (on_tutorial == 1) { - rct_window* cursor_w = window_find_by_number(cursor_w_class, cursor_w_number); - if (cursor_w == NULL) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; - return; - } + // } else { + // RCT2_CALLPROC_EBPSAFE(0x00407074); + // } + // if (on_tutorial == 2) { - switch (state){ - case 0: - if (!w || cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) - break; + // } - if (w->disabled_widgets & (1ULL << widgetIndex)) - break; + //} else { - if (RCT2_GLOBAL(0x9DE528, uint16) != 0) RCT2_GLOBAL(0x9DE528, uint16)++; + //} +} - if (w->var_020 & (1ULL << widgetIndex) && - RCT2_GLOBAL(0x9DE528, uint16) >= 0x10 && - (!(RCT2_GLOBAL(0x9DE528, uint16) & 0x3))){ - RCT2_CALLPROC_WE_MOUSE_DOWN(w->event_handlers[WE_MOUSE_DOWN], widgetIndex, w, widget); - } +/** + * + * rct2: 0x00407074 + */ +static rct_mouse_data* get_mouse_input() +{ + uint32 read_index = RCT2_GLOBAL(RCT2_ADDRESS_MOUSE_READ_INDEX, uint32); - if (RCT2_GLOBAL(0x9DE518, uint32) & 1) return; + // check if that location has been written to yet + if (read_index == RCT2_GLOBAL(RCT2_ADDRESS_MOUSE_WRITE_INDEX, uint32)) + return NULL; - RCT2_GLOBAL(0x9DE518, uint32) |= 1; - widget_invalidate_by_number(cursor_w_class, cursor_w_number, widgetIndex); - return; - case 3: - case 2: - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 5){ - if (w) { - int dropdown_index = 0; - - if (w->classification == WC_DROPDOWN){ - dropdown_index = dropdown_index_from_point(x, y, w); - if (dropdown_index == -1)goto dropdown_cleanup; - - // _dropdown_unknown?? highlighted? - if (dropdown_index < 32 && RCT2_GLOBAL(0x009DED34, sint32) & (1 << dropdown_index))goto dropdown_cleanup; - - // gDropdownItemsFormat[dropdown_index] will not work until all windows that use dropdown decompiled - if (RCT2_ADDRESS(0x9DEBA4, uint16)[dropdown_index] == 0)goto dropdown_cleanup; - } - else{ - if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) - goto dropdown_cleanup; - dropdown_index = -1; - if (RCT2_GLOBAL(0x9DE518, uint32) & 2){ - if (!(RCT2_GLOBAL(0x9DE518, uint32) & 4)){ - RCT2_GLOBAL(0x9DE518, uint32) |= (1 << 2); - return; - } - } - } - - window_close_by_class(WC_DROPDOWN); - cursor_w = window_find_by_number(cursor_w_class, cursor_w_number); - if (RCT2_GLOBAL(0x9DE518, uint32) & 1){ - RCT2_GLOBAL(0x9DE518, uint32) &= 0xFFFE; - widget_invalidate_by_number(cursor_w_class, cursor_w_number, cursor_widgetIndex); - } - - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = cursor_widgetIndex; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = cursor_w_class; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = cursor_w_number; - RCT2_CALLPROC_X(cursor_w->event_handlers[WE_DROPDOWN], dropdown_index, 0, 0, cursor_widgetIndex, (int)cursor_w, 0, 0); - } - dropdown_cleanup: - window_close_by_class(WC_DROPDOWN); - } - if (state == 3) return; - - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = cursor_widgetIndex; - - if (!w) - break; - - int mid_point_x = (widget->left + widget->right) / 2 + w->x; - sound_play_panned(5, mid_point_x, 0, 0, 0); - if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) - break; - - if (w->disabled_widgets & (1ULL << widgetIndex)) - break; - - widget_invalidate_by_number(cursor_w_class, cursor_w_number, widgetIndex); - window_event_helper(w, widgetIndex, WE_MOUSE_UP); - default: - return; - } - - RCT2_GLOBAL(0x9DE528, uint16) = 0; - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) != 5){ - // Hold down widget and drag outside of area?? - if (RCT2_GLOBAL(0x9DE518, uint32) & 1){ - RCT2_GLOBAL(0x9DE518, uint32) &= 0xFFFE; - widget_invalidate_by_number(cursor_w_class, cursor_w_number, cursor_widgetIndex); - } - return; - } - - if (!w) return; - - if (w->classification == WC_DROPDOWN){ - int dropdown_index = dropdown_index_from_point(x, y, w); - - if (dropdown_index == -1) return; - - // _dropdown_unknown?? highlighted? - if (dropdown_index < 32 && RCT2_GLOBAL(0x009DED34, sint32) & (1 << dropdown_index))return; - - // gDropdownItemsFormat[dropdown_index] will not work until all windows that use dropdown decompiled - if (RCT2_ADDRESS(0x9DEBA4, uint16)[dropdown_index] == 0)return; - - // _dropdown_highlighted_index - RCT2_GLOBAL(0x009DEBA2, sint16) = dropdown_index; - window_invalidate_by_class(WC_DROPDOWN); - } + RCT2_GLOBAL(RCT2_ADDRESS_MOUSE_READ_INDEX, uint32) = (read_index + 1) % 64; + return &mouse_buffer[read_index]; } /** @@ -495,19 +309,10 @@ static void game_handle_input_mouse(int x, int y, int state) RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; if (RCT2_GLOBAL(0x009DE540, sint16) < 500) { // Right click - { - int x, y, type; - rct_map_element* mapElement; - - type = sub_6EDE88( - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, sint16), - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, sint16), - &mapElement, - &x, - &y - ); - map_element_right_click(type, mapElement, x, y); - } + viewport_interaction_right_click( + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, sint16) + ); } } @@ -714,6 +519,441 @@ static void game_handle_input_mouse(int x, int y, int state) } } +/** +* +* rct2: 0x006ED833 +*/ +void process_mouse_over(int x, int y) +{ + rct_window* window; + rct_window* subWindow; + + int widgetId; + int cursorId; + int eax, ebx, ecx, edx, esi, edi, ebp; + + cursorId = CURSOR_ARROW; + RCT2_GLOBAL(0x9A9808, sint16) = -1; + window = window_find_from_point(x, y); + + if (window != NULL) { + widgetId = window_find_widget_from_point(window, x, y); + RCT2_GLOBAL(0x1420046, sint16) = (widgetId & 0xFFFF); + if (widgetId != -1) { + switch (window->widgets[widgetId].type){ + case WWT_VIEWPORT: + if ((RCT2_GLOBAL(0x9DE518, int) & 0x8) == 0) + { + edx = cursorId; + eax = x; + ebx = y; + //Find out if there is a clickable item under pointer + RCT2_CALLFUNC_X(0X6ED9D0, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + if ((ebx & 0xFF) == 2 || (ebx & 0xFF) == 8 || (ebx & 0xFF) == 3) + { + sub_6ED990(CURSOR_HAND_POINT); + return; + } + break; + } + cursorId = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8); + subWindow = window_find_by_number( + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) + ); + ebp = (int)subWindow; + if (subWindow == NULL) + { + break; + } + ebx = ebx & 0xFFFFFF00; + edi = cursorId; + esi = (int) subWindow; + RCT2_CALLFUNC_X(subWindow->event_handlers[WE_UNKNOWN_0E], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + cursorId = edi; + if ((ebx & 0xFF) != 0) + { + sub_6ED990(cursorId); + return; + } + break; + case WWT_FRAME: + case WWT_RESIZE: + if (!(window->flags & 0x100)) + { + break; + } + if (window->min_width == window->max_width && window->min_height == window->max_height) + { + break; + } + if (x < window->x + window->width - 0x13) + { + break; + } + if (y < window->y + window->height - 0x13) + { + break; + } + cursorId = CURSOR_DIAGONAL_ARROWS; + break; + case WWT_SCROLL: + RCT2_GLOBAL(0x9DE558, uint16) = x; + RCT2_GLOBAL(0x9DE55A, uint16) = y; + int output_x, output_y, output_scroll_area, scroll_id; + widget_scroll_get_part(window, window->widgets, x, y, &output_x, &output_y, &output_scroll_area, &scroll_id); + cursorId = scroll_id; + if (output_scroll_area != SCROLL_PART_VIEW) + { + cursorId = CURSOR_ARROW; + break; + } + //Fall through to default + default: + ecx = x; + edx = y; + eax = widgetId; + ebx = 0xFFFFFFFF; + edi = (int)&window->widgets[widgetId]; + + RCT2_CALLFUNC_X(window->event_handlers[WE_UNKNOWN_17], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + if (ebx == 0xFFFFFFFF) + { + cursorId = CURSOR_ARROW; + break; + } + cursorId = ebx; + break; + } + } + } + + viewport_interaction_hover(x, y); + sub_6ED990(cursorId); +} + +/** + * + * rct2: 0x006ED801 + */ +void process_mouse_tool(int x, int y) +{ + if (RCT2_GLOBAL(0x9DE518, uint32) & (1 << 3)) + { + rct_window* w = window_find_by_number( + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8), + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, uint16) + ); + + if (!w) + tool_cancel(); + else + RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_UPDATE], x, y, 0, RCT2_GLOBAL(0x9DE546, uint16), (int)w, 0, 0); + + } +} + +/** + * + * rct2: 0x006E95F9 + */ +static void input_leftmousedown(int x, int y, rct_window *w, int widgetIndex) +{ + // RCT2_CALLPROC_X(0x006E95F9, x, y, state, widgetIndex, w, widget, 0); + + rct_windowclass windowClass = 255; + rct_windownumber windowNumber = 0; + rct_widget *widget; + + if (w != NULL) { + windowClass = w->classification; + windowNumber = w->number; + } + + window_close_by_class(WC_ERROR); + window_close_by_class(WC_TOOLTIP); + + w = window_find_by_number(windowClass, windowNumber); + if (w == NULL) + return; + + w = window_bring_to_front(w); + if (widgetIndex == -1) + return; + + widget = &w->widgets[widgetIndex]; + + switch (widget->type) { + case WWT_FRAME: + case WWT_RESIZE: + if (!(w->flags & WF_RESIZABLE)) + break; + if (w->min_width == w->max_width && w->min_height == w->max_height) + break; + if (x < w->x + w->width - 19 || y < w->y + w->height - 19) + break; + + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESIZING; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) = windowNumber; + break; + case WWT_VIEWPORT: + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_VIEWPORT_LEFT; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) = windowNumber; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + break; + + w = window_find_by_number( + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) + ); + if (w == NULL) + break; + + RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DOWN], x, y, 0, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), (int)w, 0, 0); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_4; + break; + case WWT_CAPTION: + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_DRAGGING; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) = windowNumber; + break; + case WWT_SCROLL: + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_SCROLL_LEFT; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber) = windowNumber; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) = y; + + int eax, ebx, scroll_area, scroll_id; + scroll_id = 0; // safety + widget_scroll_get_part(w, widget, x, y, &eax, &ebx, &scroll_area, &scroll_id); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_AREA, uint16) = scroll_area; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_ID, uint32) = scroll_id * sizeof(rct_scroll);//We do this because scroll id is not all decompiled + RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_15], RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_ID, uint32), ebx, scroll_area, scroll_id, (int)w, (int)widget, 0); + if (scroll_area == SCROLL_PART_VIEW){ + RCT2_CALLPROC_X(w->event_handlers[WE_SCROLL_MOUSEDOWN], scroll_id / sizeof(rct_scroll), ebx, eax, ebx, (int)w, (int)widget, 0); + break; + } + + rct_widget* widg = &w->widgets[widgetIndex]; + rct_scroll* scroll = &w->scrolls[scroll_id]; + + int widget_width = widg->right - widg->left - 1; + if (scroll->flags & VSCROLLBAR_VISIBLE) + widget_width -= 11; + widget_width = max(scroll->h_right - widget_width, 0); + + int widget_height = widg->bottom - widg->top - 1; + if (scroll->flags & HSCROLLBAR_VISIBLE) + widget_height -= 11; + widget_height = max(scroll->v_bottom - widget_height, 0); + + switch (scroll_area) { + case SCROLL_PART_HSCROLLBAR_LEFT: + scroll->h_left = max(scroll->h_left - 3, 0); + break; + case SCROLL_PART_HSCROLLBAR_RIGHT: + scroll->h_left = min(scroll->h_left + 3, widget_width); + break; + case SCROLL_PART_HSCROLLBAR_LEFT_TROUGH: + scroll->h_left = max(scroll->h_left - widget_width , 0); + break; + case SCROLL_PART_HSCROLLBAR_RIGHT_TROUGH: + scroll->h_left = min(scroll->h_left + widget_width, widget_width); + break; + case SCROLL_PART_VSCROLLBAR_TOP: + scroll->v_top = max(scroll->v_top - 3, 0); + break; + case SCROLL_PART_VSCROLLBAR_BOTTOM: + scroll->v_top = min(scroll->v_top + 3, widget_height); + break; + case SCROLL_PART_VSCROLLBAR_TOP_TROUGH: + scroll->v_top = max(scroll->v_top - widget_height, 0); + break; + case SCROLL_PART_VSCROLLBAR_BOTTOM_TROUGH: + scroll->v_top = min(scroll->v_top + widget_height, widget_height); + break; + default: + break; + } + widget_scroll_update_thumbs(w, widgetIndex); + window_invalidate_by_number(widgetIndex, w->classification); + break; + default: + if (!widget_is_enabled(w, widgetIndex)) + break; + if (widget_is_disabled(w, widgetIndex)) + break; + + sound_play_panned(SOUND_CLICK_1, w->x + (widget->left + widget->right) / 2, 0, 0, 0); + + // Set new cursor down widget + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber) = windowNumber; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_WIDGET_PRESSED; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_WIDGET_PRESSED; + RCT2_GLOBAL(0x009DE528, uint16) = 1; + + widget_invalidate_by_number(windowClass, windowNumber, widgetIndex); + RCT2_CALLPROC_WE_MOUSE_DOWN(w->event_handlers[WE_MOUSE_DOWN], widgetIndex, w, widget); + break; + } +} + +/** + * + * rct2: 0x006E8DA7 + */ +void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_window* w, rct_widget* widget ){ + //RCT2_CALLPROC_X(0x006E8DA7, x, y, state, widgetIndex, (int)w, (int)widget, 0); + //return; + RCT2_GLOBAL(0x1420054, uint16) = x; + RCT2_GLOBAL(0x1420056, uint16) = y; + + rct_windowclass cursor_w_class; + rct_windownumber cursor_w_number; + cursor_w_class = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass); + cursor_w_number = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber); + int cursor_widgetIndex = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint32); + + rct_window* cursor_w = window_find_by_number(cursor_w_class, cursor_w_number); + if (cursor_w == NULL) { + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; + return; + } + + switch (state){ + case 0: + if (!w || cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) + break; + + if (w->disabled_widgets & (1ULL << widgetIndex)) + break; + + if (RCT2_GLOBAL(0x9DE528, uint16) != 0) RCT2_GLOBAL(0x9DE528, uint16)++; + + if (w->var_020 & (1ULL << widgetIndex) && + RCT2_GLOBAL(0x9DE528, uint16) >= 0x10 && + (!(RCT2_GLOBAL(0x9DE528, uint16) & 0x3))){ + RCT2_CALLPROC_WE_MOUSE_DOWN(w->event_handlers[WE_MOUSE_DOWN], widgetIndex, w, widget); + } + + if (RCT2_GLOBAL(0x9DE518, uint32) & 1) return; + + RCT2_GLOBAL(0x9DE518, uint32) |= 1; + widget_invalidate_by_number(cursor_w_class, cursor_w_number, widgetIndex); + return; + case 3: + case 2: + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 5){ + if (w) { + int dropdown_index = 0; + + if (w->classification == WC_DROPDOWN){ + dropdown_index = dropdown_index_from_point(x, y, w); + if (dropdown_index == -1)goto dropdown_cleanup; + + // _dropdown_unknown?? highlighted? + if (dropdown_index < 32 && RCT2_GLOBAL(0x009DED34, sint32) & (1 << dropdown_index))goto dropdown_cleanup; + + // gDropdownItemsFormat[dropdown_index] will not work until all windows that use dropdown decompiled + if (RCT2_ADDRESS(0x9DEBA4, uint16)[dropdown_index] == 0)goto dropdown_cleanup; + } + else{ + if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) + goto dropdown_cleanup; + dropdown_index = -1; + if (RCT2_GLOBAL(0x9DE518, uint32) & 2){ + if (!(RCT2_GLOBAL(0x9DE518, uint32) & 4)){ + RCT2_GLOBAL(0x9DE518, uint32) |= (1 << 2); + return; + } + } + } + + window_close_by_class(WC_DROPDOWN); + cursor_w = window_find_by_number(cursor_w_class, cursor_w_number); + if (RCT2_GLOBAL(0x9DE518, uint32) & 1){ + RCT2_GLOBAL(0x9DE518, uint32) &= 0xFFFE; + widget_invalidate_by_number(cursor_w_class, cursor_w_number, cursor_widgetIndex); + } + + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = cursor_widgetIndex; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = cursor_w_class; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = cursor_w_number; + RCT2_CALLPROC_X(cursor_w->event_handlers[WE_DROPDOWN], dropdown_index, 0, 0, cursor_widgetIndex, (int)cursor_w, 0, 0); + } + dropdown_cleanup: + window_close_by_class(WC_DROPDOWN); + } + if (state == 3) return; + + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = cursor_widgetIndex; + + if (!w) + break; + + int mid_point_x = (widget->left + widget->right) / 2 + w->x; + sound_play_panned(5, mid_point_x, 0, 0, 0); + if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) + break; + + if (w->disabled_widgets & (1ULL << widgetIndex)) + break; + + widget_invalidate_by_number(cursor_w_class, cursor_w_number, widgetIndex); + window_event_helper(w, widgetIndex, WE_MOUSE_UP); + default: + return; + } + + RCT2_GLOBAL(0x9DE528, uint16) = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) != 5){ + // Hold down widget and drag outside of area?? + if (RCT2_GLOBAL(0x9DE518, uint32) & 1){ + RCT2_GLOBAL(0x9DE518, uint32) &= 0xFFFE; + widget_invalidate_by_number(cursor_w_class, cursor_w_number, cursor_widgetIndex); + } + return; + } + + if (!w) return; + + if (w->classification == WC_DROPDOWN){ + int dropdown_index = dropdown_index_from_point(x, y, w); + + if (dropdown_index == -1) return; + + // _dropdown_unknown?? highlighted? + if (dropdown_index < 32 && RCT2_GLOBAL(0x009DED34, sint32) & (1 << dropdown_index))return; + + // gDropdownItemsFormat[dropdown_index] will not work until all windows that use dropdown decompiled + if (RCT2_ADDRESS(0x9DEBA4, uint16)[dropdown_index] == 0)return; + + // _dropdown_highlighted_index + RCT2_GLOBAL(0x009DEBA2, sint16) = dropdown_index; + window_invalidate_by_class(WC_DROPDOWN); + } +} + /** * * rct2: 0x006E9253 @@ -827,105 +1067,9 @@ static void input_mouseover_widget_flatbutton_invalidate() } } -void game_handle_edge_scroll() -{ - rct_window *mainWindow; - int scrollX, scrollY; +#pragma endregion - mainWindow = window_get_main(); - if (mainWindow == NULL) - return; - if ((mainWindow->flags & WF_2) || (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9)) - return; - if (mainWindow->viewport == NULL) - return; - - scrollX = 0; - scrollY = 0; - - // Scroll left / right - if (gCursorState.x == 0) - scrollX = -1; - else if (gCursorState.x == RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 1) - scrollX = 1; - - // Scroll up / down - if (gCursorState.y == 0) - scrollY = -1; - else if (gCursorState.y == RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 1) - scrollY = 1; - - // Scroll viewport - if (scrollX != 0) { - mainWindow->saved_view_x += scrollX * (12 << mainWindow->viewport->zoom); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; - } - if (scrollY != 0) { - mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; - } -} - -void game_handle_key_scroll() -{ - rct_window *mainWindow; - int scrollX, scrollY; - - mainWindow = window_get_main(); - if (mainWindow == NULL) - return; - if ((mainWindow->flags & WF_2) || (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9)) - return; - if (mainWindow->viewport == NULL) - return; - - rct_window *textWindow; - - textWindow = window_find_by_class(WC_TEXTINPUT); - if (textWindow) return; - - scrollX = 0; - scrollY = 0; - - // Scroll left / right - if (gKeysState[SDL_SCANCODE_LEFT]) - scrollX = -1; - else if (gKeysState[SDL_SCANCODE_RIGHT]) - scrollX = 1; - - // Scroll up / down - if (gKeysState[SDL_SCANCODE_UP]) - scrollY = -1; - else if (gKeysState[SDL_SCANCODE_DOWN]) - scrollY = 1; - - // Scroll viewport - if (scrollX != 0) { - mainWindow->saved_view_x += scrollX * (12 << mainWindow->viewport->zoom); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; - } - if (scrollY != 0) { - mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; - } -} - -/** - * - * rct2: 0x00406CD2 - */ -int get_next_key() -{ - int i; - for (i = 0; i < 221; i++) { - if (gKeysPressed[i]) { - gKeysPressed[i] = 0; - return i; - } - } - - return 0; -} +#pragma region Keyboard input /** * @@ -1011,110 +1155,22 @@ void game_handle_keyboard_input() /** * - * rct2: 0x006EA627 + * rct2: 0x00406CD2 */ -void game_handle_input() +int get_next_key() { - rct_window *w; - int x, y, state; - - if (RCT2_GLOBAL(0x009DEA64, uint16) & 2) { - RCT2_GLOBAL(0x009DEA64, uint16) &= ~2; - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 2, 0); - } - - if (RCT2_GLOBAL(0x009ABDF2, uint8) != 0) { - for (w = g_window_list; w < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); w++) - RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_07], 0, 0, 0, 0, (int)w, 0, 0); - - sub_6EA73F(); - RCT2_CALLPROC_EBPSAFE(0x006E8346); // update_cursor_position - - for (;;) { - game_get_next_input(&x, &y, &state); - if (state == 0) - break; - - game_handle_input_mouse(x, y, state & 0xFF); - } - - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5) { - game_handle_input_mouse(x, y, state); - } else if (x != 0x80000000) { - x = clamp(0, x, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 1); - y = clamp(0, y, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - 1); - - game_handle_input_mouse(x, y, state); - process_mouse_over(x, y); - process_mouse_tool(x, y); + int i; + for (i = 0; i < 221; i++) { + if (gKeysPressed[i]) { + gKeysPressed[i] = 0; + return i; } } - for (w = g_window_list; w < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); w++) - RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_08], 0, 0, 0, 0,(int) w, 0, 0); + return 0; } -/** - * - * rct2: 0x006E83C7 - */ -static void game_get_next_input(int *x, int *y, int *state) -{ - rct_mouse_data* eax = get_mouse_input(); - if (eax == NULL) { - *x = gCursorState.x; - *y = gCursorState.y; - *state = 0; - return; - } - - *x = eax->x; - *y = eax->y; - *state = eax->state; - - //int eax, ebx, ecx, edx, esi, edi, ebp; - //RCT2_CALLFUNC_X(0x006E83C7, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - //*x = eax & 0xFFFF; - //*y = ebx & 0xFFFF; - //*state = ecx & 0xFF; - //return; - - //int on_tutorial = RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8); - //if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5) { - // if (on_tutorial == 1) { - - // } else { - // RCT2_CALLPROC_EBPSAFE(0x00407074); - // } - // if (on_tutorial == 2) { - - // } - - //} else { - - //} -} - -/** - * - * rct2: 0x006ED801 - */ -void process_mouse_tool(int x, int y) -{ - if (RCT2_GLOBAL(0x9DE518, uint32) & (1 << 3)) - { - rct_window* w = window_find_by_number( - RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8), - RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, uint16) - ); - - if (!w) - tool_cancel(); - else - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_UPDATE], x, y, 0, RCT2_GLOBAL(0x9DE546, uint16), (int)w, 0, 0); - - } -} +#pragma endregion /** * @@ -1136,131 +1192,7 @@ void sub_6ED990(char cursor_id){ RCT2_GLOBAL(0x14241BC, uint32) = 0; } -/** -* -* rct2: 0x006ED833 -*/ -void process_mouse_over(int x, int y) -{ - rct_window* window; - rct_window* subWindow; - int widgetId; - int cursorId; - int eax, ebx, ecx, edx, esi, edi, ebp; - - cursorId = CURSOR_ARROW; - RCT2_GLOBAL(0x9A9808, sint16) = -1; - window = window_find_from_point(x, y); - - if (window != NULL) - { - widgetId = window_find_widget_from_point(window, x, y); - RCT2_GLOBAL(0x1420046, sint16) = (widgetId & 0xFFFF); - if (widgetId != -1) - { - - switch (window->widgets[widgetId].type){ - case WWT_VIEWPORT: - if ((RCT2_GLOBAL(0x9DE518, int) & 0x8) == 0) - { - edx = cursorId; - eax = x; - ebx = y; - //Find out if there is a clickable item under pointer - RCT2_CALLFUNC_X(0X6ED9D0, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - - if ((ebx & 0xFF) == 2 || (ebx & 0xFF) == 8 || (ebx & 0xFF) == 3) - { - sub_6ED990(CURSOR_HAND_POINT); - return; - } - break; - } - cursorId = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8); - subWindow = window_find_by_number( - RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), - RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) - ); - ebp = (int)subWindow; - if (subWindow == NULL) - { - break; - } - ebx = ebx & 0xFFFFFF00; - edi = cursorId; - esi = (int) subWindow; - RCT2_CALLFUNC_X(subWindow->event_handlers[WE_UNKNOWN_0E], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - cursorId = edi; - if ((ebx & 0xFF) != 0) - { - sub_6ED990(cursorId); - return; - } - break; - case WWT_FRAME: - case WWT_RESIZE: - if (!(window->flags & 0x100)) - { - break; - } - if (window->min_width == window->max_width && window->min_height == window->max_height) - { - break; - } - if (x < window->x + window->width - 0x13) - { - break; - } - if (y < window->y + window->height - 0x13) - { - break; - } - cursorId = CURSOR_DIAGONAL_ARROWS; - break; - case WWT_SCROLL: - RCT2_GLOBAL(0x9DE558, uint16) = x; - RCT2_GLOBAL(0x9DE55A, uint16) = y; - int output_x, output_y, output_scroll_area, scroll_id; - widget_scroll_get_part(window, window->widgets, x, y, &output_x, &output_y, &output_scroll_area, &scroll_id); - cursorId = scroll_id; - if (output_scroll_area != SCROLL_PART_VIEW) - { - cursorId = CURSOR_ARROW; - break; - } - //Fall through to default - default: - ecx = x; - edx = y; - eax = widgetId; - ebx = 0xFFFFFFFF; - edi = (int)&window->widgets[widgetId]; - - RCT2_CALLFUNC_X(window->event_handlers[WE_UNKNOWN_17], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if (ebx == 0xFFFFFFFF) - { - cursorId = CURSOR_ARROW; - break; - } - cursorId = ebx; - break; - } - } - } - - { - int outX, outY; - rct_map_element *mapElement; - - sub_6EDE88(x, y, &mapElement, &outX, &outY); - // RCT2_CALLPROC_X(0x6EDE88, x, y, ecx, cursorId, esi, edi, ebp); - //itemUnderCursor(&eax, &ebx, &ecx, &edx); - - sub_6ED990(cursorId); - } - return; -} /** * @@ -1304,330 +1236,85 @@ void store_mouse_input(int state) RCT2_GLOBAL(RCT2_ADDRESS_MOUSE_WRITE_INDEX, uint32) = next_write_index; } - -/** - * rct2: 0x00407074 - */ -static rct_mouse_data* get_mouse_input() +void game_handle_edge_scroll() { - uint32 read_index = RCT2_GLOBAL(RCT2_ADDRESS_MOUSE_READ_INDEX, uint32); + rct_window *mainWindow; + int scrollX, scrollY; - // check if that location has been written to yet - if (read_index == RCT2_GLOBAL(RCT2_ADDRESS_MOUSE_WRITE_INDEX, uint32)) - return NULL; + mainWindow = window_get_main(); + if (mainWindow == NULL) + return; + if ((mainWindow->flags & WF_2) || (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9)) + return; + if (mainWindow->viewport == NULL) + return; - RCT2_GLOBAL(RCT2_ADDRESS_MOUSE_READ_INDEX, uint32) = (read_index + 1) % 64; - return &mouse_buffer[read_index]; -} + scrollX = 0; + scrollY = 0; -static void sub_6E57A9(rct_map_element *mapElement, int x, int y) -{ - rct_scenery_entry* sceneryEntry; + // Scroll left / right + if (gCursorState.x == 0) + scrollX = -1; + else if (gCursorState.x == RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 1) + scrollX = 1; - sceneryEntry = g_wallSceneryEntries[mapElement->properties.fence.slope]; - if (sceneryEntry->wall.var_0D != 0xFF){ - window_sign_small_open(mapElement->properties.fence.item[0]); - } else { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1158; - game_do_command( - x, - 1, - y, - (mapElement->type & 0x3) | (mapElement->base_height << 8), - GAME_COMMAND_REMOVE_FENCE, - 0, - 0 - ); + // Scroll up / down + if (gCursorState.y == 0) + scrollY = -1; + else if (gCursorState.y == RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 1) + scrollY = 1; + + // Scroll viewport + if (scrollX != 0) { + mainWindow->saved_view_x += scrollX * (12 << mainWindow->viewport->zoom); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; + } + if (scrollY != 0) { + mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; } } -static void sub_6B88DC(rct_map_element *mapElement, int x, int y) +void game_handle_key_scroll() { - int ebx; - rct_scenery_entry* sceneryEntry; + rct_window *mainWindow; + int scrollX, scrollY; - ebx = mapElement->properties.scenerymultiple.type; - ebx |= (mapElement->properties.scenerymultiple.index & 0x3) << 8; - sceneryEntry = g_largeSceneryEntries[ebx]; + mainWindow = window_get_main(); + if (mainWindow == NULL) + return; + if ((mainWindow->flags & WF_2) || (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9)) + return; + if (mainWindow->viewport == NULL) + return; - if (sceneryEntry->large_scenery.var_11 != 0xFF){ - int id = (mapElement->type & 0xC0) | - ((mapElement->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | - ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5); - window_sign_open(id); - } else { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1158; - game_do_command( - x, - 1 | ((mapElement->type & 0x3) << 8), - y, - mapElement->base_height | ((mapElement->properties.scenerymultiple.index >> 2) << 8), - GAME_COMMAND_44, - 0, - 0 - ); + rct_window *textWindow; + + textWindow = window_find_by_class(WC_TEXTINPUT); + if (textWindow) return; + + scrollX = 0; + scrollY = 0; + + // Scroll left / right + if (gKeysState[SDL_SCANCODE_LEFT]) + scrollX = -1; + else if (gKeysState[SDL_SCANCODE_RIGHT]) + scrollX = 1; + + // Scroll up / down + if (gKeysState[SDL_SCANCODE_UP]) + scrollY = -1; + else if (gKeysState[SDL_SCANCODE_DOWN]) + scrollY = 1; + + // Scroll viewport + if (scrollX != 0) { + mainWindow->saved_view_x += scrollX * (12 << mainWindow->viewport->zoom); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; } -} - -static void sub_6A614A(rct_map_element *mapElement, int x, int y) -{ - int z; - rct_window *w; - rct_map_element *mapElement2; - - z = mapElement->base_height; - - w = window_find_by_class(WC_FOOTPATH); - if (w != NULL) - RCT2_CALLPROC_EBPSAFE(0x006A7831); - - mapElement2 = TILE_MAP_ELEMENT_POINTER((y / 32) * 256 + (x / 32)); - do { - if ((mapElement2->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH && mapElement2->base_height == z) { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_REMOVE_FOOTPATH_FROM_HERE; - game_do_command(x, 1, y, z, GAME_COMMAND_REMOVE_PATH, 0, 0); - } - } while (!((mapElement2++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); -} - -static void sub_6E08D2(rct_map_element *mapElement, int x, int y) -{ - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_REMOVE_THIS; - game_do_command( - x, - (mapElement->type << 8) | 1, - y, - (mapElement->properties.scenery.type << 8) | mapElement->base_height, - GAME_COMMAND_REMOVE_SCENERY, - 0, - 0 - ); -} - -static void sub_6A61AB(rct_map_element *mapElement, int x, int y) -{ - int type; - - type = mapElement->properties.scenery.type >> 4; - if (mapElement->type & 0x80) - type |= 0x80; - - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_REMOVE_THIS; - game_do_command( - x, - ((mapElement->properties.scenery.type & 7) << 8) | 1, - y, - (type << 8) | mapElement->base_height, - GAME_COMMAND_PLACE_PATH, - 0, - 0 - ); -} - -int sub_6EDE88(int x, int y, rct_map_element **outMapElement, int *outX, int *outY) -{ - { - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x; - ebx = y; - RCT2_CALLFUNC_X(0x006EDE88, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - - *outMapElement = (rct_map_element*)edx; - *outX = eax & 0xFFFF; - *outY = ecx & 0xFFFF; - return ebx & 0xFF; - } - - rct_s6_info *s6Info = (rct_s6_info*)0x00141F570; - rct_map_element *mapElement; - rct_scenery_entry *sceneryEntry; - rct_banner *banner; - rct_ride *ride; - int i, outZ; - - // No click input for title screen or track manager - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TITLE_DEMO | SCREEN_FLAGS_TRACK_MANAGER)) - return 0; - - // - if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && s6Info->var_000 != 6) - return 0; - - get_map_coordinates_from_pos(x, y, 9, outX, outY, &outZ, &mapElement); - *outMapElement = mapElement; - - switch (outZ) { - case 3: - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) - return 0; - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH) - return 0; - - ride = GET_RIDE(mapElement->properties.track.ride_index); - if (ride->status != RIDE_STATUS_CLOSED) - return 0; - - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; - - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_ENTRANCE) { - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = - mapElement->properties.track.type == ENTRANCE_TYPE_RIDE_ENTRANCE ? 1335 : 1337; - - goto loc_6EE1A7; - } - - if (mapElement->properties.track.type == 1 || mapElement->properties.track.type == 2 || mapElement->properties.track.type == 3) { - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 1333; - goto loc_6EE1A7; - } - - if (!sub_664F72(x, y, mapElement->base_height << 4)) - return 0; - - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = ride->name; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 4, uint32) = ride->name_arguments; - return 3; - - loc_6EE1A7: - if (ride->num_stations > 1) - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16)++; - - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 4, uint16) = ride->name; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 6, uint32) = ride->name_arguments; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 10, uint16) = RideNameConvention[ride->type].station_name + 2; - - int edi = (mapElement->properties.track.sequence & 0x70) >> 4; - for (i = edi; i >= 0; i--) - if (ride->station_starts[i] == 0xFFFF) - edi--; - edi++; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 12, uint16) = edi; - return 3; - - case 2: - if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || mapElement->type != 0) - return 0; - - mapElement += 6; - ride = GET_RIDE(mapElement->type); - if (ride->status == RIDE_STATUS_CLOSED) { - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = ride->name; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 4, uint32) = ride->name_arguments; - } - return 2; - - case 12: - banner = &gBanners[mapElement->properties.banner.index]; - sceneryEntry = g_bannerSceneryEntries[banner->type]; - - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; - return 12; - - case 9: - sceneryEntry = g_wallSceneryEntries[mapElement->properties.scenery.type]; - if (sceneryEntry->wall.var_0D != 255) { - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; - return 9; - } - - case 10: - sceneryEntry = g_largeSceneryEntries[mapElement->properties.scenerymultiple.type & 0x3FF]; - if (sceneryEntry->large_scenery.var_11 != 255) { - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; - return 10; - } - } - - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & 0x48) != 0x48) - if (window_find_by_class(WC_RIDE_CONSTRUCTION) == NULL && window_find_by_class(WC_FOOTPATH) == NULL) - return 0; - - switch (outZ) { - case 5: - sceneryEntry = g_smallSceneryEntries[mapElement->properties.scenery.type]; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; - return 5; - - case 6: - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 1425; - if (mapElement->type & 1) - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 1426; - return 6; - - case 7: - sceneryEntry = g_pathBitSceneryEntries[mapElement->properties.scenery.age & 0x0F]; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; - if (mapElement->flags & 0x20) { - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 3124; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 4, uint16) = sceneryEntry->name; - } else { - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; - } - return 7; - - case 9: - sceneryEntry = g_wallSceneryEntries[mapElement->properties.scenery.type]; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; - return 9; - - case 10: - sceneryEntry = g_largeSceneryEntries[mapElement->properties.scenery.type & 0x3FF]; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; - return 10; - - case 8: - if (RCT2_ADDRESS_SCREEN_FLAGS & SCREEN_FLAGS_SCENARIO_EDITOR) - return 0; - - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) != MAP_ELEMENT_TYPE_ENTRANCE) - return 0; - - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 3192; - return 8; - } - - return 0; -} - -void map_element_right_click(int type, rct_map_element *mapElement, int x, int y) -{ - switch (type) { - case 2: - if (mapElement->type == 0) - RCT2_CALLPROC_X(0x006B4857, x, 0, y, (int)mapElement, 0, 0, 0); - break; - case 3: - ride_modify(mapElement, x, y); - break; - case 5: - sub_6E08D2(mapElement, x, y); - break; - case 6: - sub_6A614A(mapElement, x, y); - break; - case 7: - sub_6A61AB(mapElement, x, y); - break; - case 8: - RCT2_CALLPROC_X(0x00666C0E, x, 0, y, (int)mapElement, 0, 0, 0); - break; - case 9: - sub_6E57A9(mapElement, x, y); - break; - case 10: - sub_6B88DC(mapElement, x, y); - break; - case 12: - window_banner_open(mapElement->properties.banner.index); - break; + if (scrollY != 0) { + mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; } } \ No newline at end of file diff --git a/src/interface/viewport.h b/src/interface/viewport.h index c1dbd0c7c8..7c37228bab 100644 --- a/src/interface/viewport.h +++ b/src/interface/viewport.h @@ -42,6 +42,20 @@ enum { VIEWPORT_FLAG_15 = (1 << 15) }; +enum { + VIEWPORT_INTERACTION_ITEM_NONE, + + VIEWPORT_INTERACTION_ITEM_2 = 2, + VIEWPORT_INTERACTION_ITEM_RIDE = 3, + VIEWPORT_INTERACTION_ITEM_SCENERY = 5, + VIEWPORT_INTERACTION_ITEM_FOOTPATH, + VIEWPORT_INTERACTION_ITEM_FOOTPATH_ITEM, + VIEWPORT_INTERACTION_ITEM_PARK_ENTRANCE, + VIEWPORT_INTERACTION_ITEM_WALL, + VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY, + VIEWPORT_INTERACTION_ITEM_BANNER = 12, + +}; // rct2: 0x014234BC extern rct_viewport* g_viewport_list; @@ -67,4 +81,8 @@ 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); +int viewport_interaction_get_item(int x, int y, rct_map_element **outMapElement, int *outX, int *outY); +void viewport_interaction_hover(int x, int y); +void viewport_interaction_right_click(int x, int y); + #endif diff --git a/src/interface/viewport_interaction.c b/src/interface/viewport_interaction.c new file mode 100644 index 0000000000..adf2beccd8 --- /dev/null +++ b/src/interface/viewport_interaction.c @@ -0,0 +1,389 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "../addresses.h" +#include "../game.h" +#include "../localisation/localisation.h" +#include "../ride/ride.h" +#include "../ride/ride_data.h" +#include "../scenario.h" +#include "../world/banner.h" +#include "../world/map.h" +#include "../world/scenery.h" +#include "viewport.h" + +static void viewport_interaction_remove_scenery(rct_map_element *mapElement, int x, int y); +static void viewport_interaction_remove_footpath(rct_map_element *mapElement, int x, int y); +static void viewport_interaction_remove_footpath_item(rct_map_element *mapElement, int x, int y); +static void viewport_interaction_remove_park_entrance(rct_map_element *mapElement, int x, int y); +static void viewport_interaction_remove_park_wall(rct_map_element *mapElement, int x, int y); +static void viewport_interaction_remove_large_scenery(rct_map_element *mapElement, int x, int y); + +/** + * + * rct2: 0x006EDE88 + */ +int viewport_interaction_get_item(int x, int y, rct_map_element **outMapElement, int *outX, int *outY) +{ + { + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = y; + RCT2_CALLFUNC_X(0x006EDE88, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + *outMapElement = (rct_map_element*)edx; + *outX = eax & 0xFFFF; + *outY = ecx & 0xFFFF; + return ebx & 0xFF; + } + + rct_s6_info *s6Info = (rct_s6_info*)0x00141F570; + rct_map_element *mapElement; + rct_scenery_entry *sceneryEntry; + rct_banner *banner; + rct_ride *ride; + int i, outZ; + + // No click input for title screen or track manager + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TITLE_DEMO | SCREEN_FLAGS_TRACK_MANAGER)) + return 0; + + // + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && s6Info->var_000 != 6) + return 0; + + get_map_coordinates_from_pos(x, y, 9, outX, outY, &outZ, &mapElement); + *outMapElement = mapElement; + + switch (outZ) { + case VIEWPORT_INTERACTION_ITEM_2: + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || mapElement->type != 0) + return 0; + + mapElement += 6; + ride = GET_RIDE(mapElement->type); + if (ride->status == RIDE_STATUS_CLOSED) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = ride->name; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 4, uint32) = ride->name_arguments; + } + return 2; + + case VIEWPORT_INTERACTION_ITEM_RIDE: + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) + return 0; + if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH) + return 0; + + ride = GET_RIDE(mapElement->properties.track.ride_index); + if (ride->status != RIDE_STATUS_CLOSED) + return 0; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; + + if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_ENTRANCE) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = + mapElement->properties.track.type == ENTRANCE_TYPE_RIDE_ENTRANCE ? 1335 : 1337; + } else if (mapElement->properties.track.type == 1 || mapElement->properties.track.type == 2 || mapElement->properties.track.type == 3) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 1333; + } else { + if (!sub_664F72(x, y, mapElement->base_height << 4)) + return 0; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = ride->name; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 4, uint32) = ride->name_arguments; + return 3; + } + + if (ride->num_stations > 1) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16)++; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 4, uint16) = ride->name; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 6, uint32) = ride->name_arguments; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 10, uint16) = RideNameConvention[ride->type].station_name + 2; + + int edi = (mapElement->properties.track.sequence & 0x70) >> 4; + for (i = edi; i >= 0; i--) + if (ride->station_starts[i] == 0xFFFF) + edi--; + edi++; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 12, uint16) = edi; + return 3; + + case VIEWPORT_INTERACTION_ITEM_WALL: + sceneryEntry = g_wallSceneryEntries[mapElement->properties.scenery.type]; + if (sceneryEntry->wall.var_0D != 255) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; + return 9; + } + + case VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY: + sceneryEntry = g_largeSceneryEntries[mapElement->properties.scenerymultiple.type & 0x3FF]; + if (sceneryEntry->large_scenery.var_11 != 255) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; + return 10; + } + + case VIEWPORT_INTERACTION_ITEM_BANNER: + banner = &gBanners[mapElement->properties.banner.index]; + sceneryEntry = g_bannerSceneryEntries[banner->type]; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; + return 12; + } + + if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & 0x48) != 0x48) + if (window_find_by_class(WC_RIDE_CONSTRUCTION) == NULL && window_find_by_class(WC_FOOTPATH) == NULL) + return 0; + + switch (outZ) { + case VIEWPORT_INTERACTION_ITEM_SCENERY: + sceneryEntry = g_smallSceneryEntries[mapElement->properties.scenery.type]; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; + return 5; + + case VIEWPORT_INTERACTION_ITEM_FOOTPATH: + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 1425; + if (mapElement->type & 1) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 1426; + return 6; + + case VIEWPORT_INTERACTION_ITEM_FOOTPATH_ITEM: + sceneryEntry = g_pathBitSceneryEntries[mapElement->properties.scenery.age & 0x0F]; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; + if (mapElement->flags & 0x20) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 3124; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 4, uint16) = sceneryEntry->name; + } else { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; + } + return 7; + + case VIEWPORT_INTERACTION_ITEM_PARK_ENTRANCE: + if (RCT2_ADDRESS_SCREEN_FLAGS & SCREEN_FLAGS_SCENARIO_EDITOR) + return 0; + + if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) != MAP_ELEMENT_TYPE_ENTRANCE) + return 0; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 3192; + return 8; + + case VIEWPORT_INTERACTION_ITEM_WALL: + sceneryEntry = g_wallSceneryEntries[mapElement->properties.scenery.type]; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; + return 9; + + case VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY: + sceneryEntry = g_largeSceneryEntries[mapElement->properties.scenery.type & 0x3FF]; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = sceneryEntry->name; + return 10; + } + + return 0; +} + +void viewport_interaction_hover(int x, int y) +{ + rct_map_element *mapElement; + + viewport_interaction_get_item(x, y, &mapElement, &x, &y); +} + +/** + * + * rct2: 0x006E8A62 + */ +void viewport_interaction_right_click(int x, int y) +{ + rct_map_element *mapElement; + + switch (viewport_interaction_get_item(x, y, &mapElement, &x, &y)) { + case 2: + if (mapElement->type == 0) + RCT2_CALLPROC_X(0x006B4857, x, 0, y, (int)mapElement, 0, 0, 0); + break; + case VIEWPORT_INTERACTION_ITEM_RIDE: + ride_modify(mapElement, x, y); + break; + case VIEWPORT_INTERACTION_ITEM_SCENERY: + viewport_interaction_remove_scenery(mapElement, x, y); + break; + case VIEWPORT_INTERACTION_ITEM_FOOTPATH: + viewport_interaction_remove_footpath(mapElement, x, y); + break; + case VIEWPORT_INTERACTION_ITEM_FOOTPATH_ITEM: + viewport_interaction_remove_footpath_item(mapElement, x, y); + break; + case VIEWPORT_INTERACTION_ITEM_PARK_ENTRANCE: + viewport_interaction_remove_park_entrance(mapElement, x, y); + break; + case VIEWPORT_INTERACTION_ITEM_WALL: + viewport_interaction_remove_park_wall(mapElement, x, y); + break; + case VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY: + viewport_interaction_remove_large_scenery(mapElement, x, y); + break; + case VIEWPORT_INTERACTION_ITEM_BANNER: + window_banner_open(mapElement->properties.banner.index); + break; + } +} + +/** + * + * rct2: 0x006E08D2 + */ +static void viewport_interaction_remove_scenery(rct_map_element *mapElement, int x, int y) +{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_REMOVE_THIS; + game_do_command( + x, + (mapElement->type << 8) | 1, + y, + (mapElement->properties.scenery.type << 8) | mapElement->base_height, + GAME_COMMAND_REMOVE_SCENERY, + 0, + 0 + ); +} + +/** + * + * rct2: 0x006A614A + */ +static void viewport_interaction_remove_footpath(rct_map_element *mapElement, int x, int y) +{ + int z; + rct_window *w; + rct_map_element *mapElement2; + + z = mapElement->base_height; + + w = window_find_by_class(WC_FOOTPATH); + if (w != NULL) + RCT2_CALLPROC_EBPSAFE(0x006A7831); + + mapElement2 = TILE_MAP_ELEMENT_POINTER((y / 32) * 256 + (x / 32)); + do { + if ((mapElement2->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH && mapElement2->base_height == z) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_REMOVE_FOOTPATH_FROM_HERE; + game_do_command(x, 1, y, z, GAME_COMMAND_REMOVE_PATH, 0, 0); + } + } while (!((mapElement2++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); +} + +/** + * + * rct2: 0x006A61AB + */ +static void viewport_interaction_remove_footpath_item(rct_map_element *mapElement, int x, int y) +{ + int type; + + type = mapElement->properties.scenery.type >> 4; + if (mapElement->type & 0x80) + type |= 0x80; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_REMOVE_THIS; + game_do_command( + x, + ((mapElement->properties.scenery.type & 7) << 8) | 1, + y, + (type << 8) | mapElement->base_height, + GAME_COMMAND_PLACE_PATH, + 0, + 0 + ); +} + +/** + * + * rct2: 0x00666C0E + */ +static void viewport_interaction_remove_park_entrance(rct_map_element *mapElement, int x, int y) +{ + RCT2_CALLPROC_X(0x00666C0E, x, 0, y, (int)mapElement, 0, 0, 0); +} + +/** + * + * rct2: 0x006E57A9 + */ +static void viewport_interaction_remove_park_wall(rct_map_element *mapElement, int x, int y) +{ + rct_scenery_entry* sceneryEntry; + + sceneryEntry = g_wallSceneryEntries[mapElement->properties.fence.slope]; + if (sceneryEntry->wall.var_0D != 0xFF){ + window_sign_small_open(mapElement->properties.fence.item[0]); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1158; + game_do_command( + x, + 1, + y, + (mapElement->type & 0x3) | (mapElement->base_height << 8), + GAME_COMMAND_REMOVE_FENCE, + 0, + 0 + ); + } +} + +/** + * + * rct2: 0x006B88DC + */ +static void viewport_interaction_remove_large_scenery(rct_map_element *mapElement, int x, int y) +{ + int ebx; + rct_scenery_entry* sceneryEntry; + + ebx = mapElement->properties.scenerymultiple.type; + ebx |= (mapElement->properties.scenerymultiple.index & 0x3) << 8; + sceneryEntry = g_largeSceneryEntries[ebx]; + + if (sceneryEntry->large_scenery.var_11 != 0xFF){ + int id = (mapElement->type & 0xC0) | + ((mapElement->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | + ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5); + window_sign_open(id); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1158; + game_do_command( + x, + 1 | ((mapElement->type & 0x3) << 8), + y, + mapElement->base_height | ((mapElement->properties.scenerymultiple.index >> 2) << 8), + GAME_COMMAND_44, + 0, + 0 + ); + } +} \ No newline at end of file