From da329a08de4b837e2bdc68b2d7c41d9549fadfc4 Mon Sep 17 00:00:00 2001 From: Marijn van der Werf Date: Wed, 13 Jun 2018 15:12:51 +0200 Subject: [PATCH] Decompile and hook mouse wheel input processing --- src/openloco/openloco.vcxproj | 1 + src/openloco/ui/scrollview.cpp | 11 ++ src/openloco/ui/scrollview.h | 1 + src/openloco/windowmgr.cpp | 225 +++++++++++++++++++++++++++++++++ src/openloco/windowmgr.h | 2 + src/openloco/windows/map.cpp | 13 ++ 6 files changed, 253 insertions(+) create mode 100644 src/openloco/windows/map.cpp diff --git a/src/openloco/openloco.vcxproj b/src/openloco/openloco.vcxproj index 65ed3998..759abbec 100644 --- a/src/openloco/openloco.vcxproj +++ b/src/openloco/openloco.vcxproj @@ -66,6 +66,7 @@ + diff --git a/src/openloco/ui/scrollview.cpp b/src/openloco/ui/scrollview.cpp index 3a0cda25..5e98c70e 100644 --- a/src/openloco/ui/scrollview.cpp +++ b/src/openloco/ui/scrollview.cpp @@ -32,4 +32,15 @@ namespace openloco::ui::scrollview *output_scroll_area = (scroll_part)regs.cx; *scroll_id = regs.edx; } + + // 0x004CA1ED + void update_thumbs(window* window, widget_index widgetIndex) + { + registers regs; + + regs.esi = (uintptr_t)window; + regs.ebx = window->get_scroll_data_index(widgetIndex) * sizeof(scroll_area_t); + regs.edi = (uintptr_t)&window->widgets[widgetIndex]; + call(0x4CA1ED, regs); + } } diff --git a/src/openloco/ui/scrollview.h b/src/openloco/ui/scrollview.h index 919c8425..f7e188d3 100644 --- a/src/openloco/ui/scrollview.h +++ b/src/openloco/ui/scrollview.h @@ -30,4 +30,5 @@ namespace openloco::ui::scrollview int16_t* output_y, scroll_part* output_scroll_area, int32_t* scroll_id); + void update_thumbs(window* window, widget_index widgetIndex); } diff --git a/src/openloco/windowmgr.cpp b/src/openloco/windowmgr.cpp index 042db96c..0b798898 100644 --- a/src/openloco/windowmgr.cpp +++ b/src/openloco/windowmgr.cpp @@ -2,8 +2,11 @@ #include "companymgr.h" #include "console.h" #include "graphics/colours.h" +#include "input.h" #include "interop/interop.hpp" +#include "tutorial.h" #include "ui.h" +#include "ui/scrollview.h" #include using namespace openloco::interop; @@ -245,6 +248,16 @@ namespace openloco::ui::windowmgr close_topmost(); regs = backup; + return 0; + }); + + register_hook( + 0x004C6202, + [](registers& regs) -> uint8_t { + registers backup = regs; + all_wheel_input(); + regs = backup; + return 0; }); } @@ -799,4 +812,216 @@ namespace openloco::ui::windowmgr break; } } + + static loco_global _cursorWheel; + + static void window_scroll_wheel_input(ui::window *window, widget_index widgetIndex, int wheel) + { + int scrollIndex = window->get_scroll_data_index(widgetIndex); + scroll_area_t* scroll = &window->scroll_areas[scrollIndex]; + ui::widget_t* widget = &window->widgets[widgetIndex]; + + if (window->scroll_areas[scrollIndex].flags & 0b10000) + { + int size = widget->bottom - widget->top - 1; + if (scroll->flags & 0b1) + size -= 11; + size = std::max(0, scroll->v_bottom - size); + scroll->v_top = std::clamp(scroll->v_top + wheel, 0, size); + } + else if (window->scroll_areas[scrollIndex].flags & 0b1) + { + int size = widget->right - widget->left - 1; + if (scroll->flags & 0b10000) + size -= 11; + size = std::max(0, scroll->h_right - size); + scroll->h_left = std::clamp(scroll->h_left + wheel, 0, size); + } + + ui::scrollview::update_thumbs(window, widgetIndex); + invalidate_widget(window->type, window->number, widgetIndex); + } + + // 0x004C628E + static bool window_wheel_input(window* window, int wheel) + { + int widgetIndex = -1; + int scrollIndex = -1; + for (widget_t* widget = window->widgets; widget->type != widget_type::end; widget++) + { + widgetIndex++; + + if (widget->type != widget_type::scrollview) + continue; + + scrollIndex++; + if (window->scroll_areas[scrollIndex].flags & 0b10001) + { + window_scroll_wheel_input(window, widgetIndex, wheel); + return true; + } + } + + return false; + } + + // TODO: Move + static void sub_45EFDB(ui::window* window) + { + registers regs; + regs.esi = (uintptr_t)window; + call(0x0045EFDB, regs); + } + + // TODO: Move + static void sub_45F015(ui::window* window) + { + registers regs; + regs.esi = (uintptr_t)window; + call(0x0045F015, regs); + } + + // TODO: Move + static void sub_45F04F(ui::window* window) + { + registers regs; + regs.esi = (uintptr_t)window; + call(0x0045F04F, regs); + } + + // TODO: Move + static void sub_45F0ED(ui::window* window) + { + registers regs; + regs.esi = (uintptr_t)window; + call(0x0045F0ED, regs); + } + + // TODO: Move + static void sub_49771C() + { + // Might have something to do with town labels + call(0x0049771C); + } + + // TODO: Move + static void sub_48DDC3() + { + // Might have something to do with station labels + call(0x0048DDC3); + } + + void all_wheel_input() + { + int wheel = 0; + + while (true) + { + _cursorWheel -= 120; + + if (_cursorWheel < 0) + { + _cursorWheel += 120; + break; + } + + wheel -= 17; + } + + while (true) + { + _cursorWheel += 120; + + if (_cursorWheel > 0) + { + _cursorWheel -= 120; + break; + } + + wheel += 17; + } + + if (tutorial::state() != tutorial::tutorial_state::none) + return; + + if (input::has_flag(input::input_flags::flag5)) + { + if (openloco::is_title_mode()) + return; + + auto main = windowmgr::get_main(); + if (main != nullptr) + { + if (wheel > 0) + { + sub_45F04F(main); + } + else if (wheel < 0) + { + sub_45F0ED(main); + } + sub_49771C(); + sub_48DDC3(); + windows::map_center_on_view_point(); + } + + return; + } + + int32_t x = addr<0x0113E72C, int32_t>(); + int32_t y = addr<0x0113E730, int32_t>(); + auto window = find_at(x, y); + + if (window != nullptr) + { + if (window->type == window_type::main) + { + if (openloco::is_title_mode()) + return; + + if (wheel > 0) + { + sub_45F015(window); + } + else if (wheel < 0) + { + sub_45EFDB(window); + } + sub_49771C(); + sub_48DDC3(); + + return; + } + else + { + auto widgetIndex = window->find_widget_at(x, y); + if (widgetIndex != -1) + { + if (window->widgets[widgetIndex].type == widget_type::scrollview) + { + auto scrollIndex = window->get_scroll_data_index(widgetIndex); + if (window->scroll_areas[scrollIndex].flags & 0b10001) + { + window_scroll_wheel_input(window, widgetIndex, wheel); + return; + } + } + + if (window_wheel_input(window, wheel)) + { + return; + } + } + } + } + + for (ui::window* w = _windows_end - 1; w >= _windows; w--) + { + if (window_wheel_input(w, wheel)) + { + return; + } + } + } + } diff --git a/src/openloco/windowmgr.h b/src/openloco/windowmgr.h index c60d217a..f75af336 100644 --- a/src/openloco/windowmgr.h +++ b/src/openloco/windowmgr.h @@ -101,6 +101,7 @@ namespace openloco::ui::windowmgr void sub_4CEE0B(window* self); void sub_4B93A5(uint16_t arg); void close_topmost(); + void all_wheel_input(); } namespace openloco::ui::windows @@ -119,6 +120,7 @@ namespace openloco::ui::windows bool prompt_browse(browse_type type, char* path, const char* filter, const char* title); bool prompt_ok_cancel(string_id okButtonStringId); + void map_center_on_view_point(); } namespace openloco::ui::textinput diff --git a/src/openloco/windows/map.cpp b/src/openloco/windows/map.cpp new file mode 100644 index 00000000..32db13c3 --- /dev/null +++ b/src/openloco/windows/map.cpp @@ -0,0 +1,13 @@ +#include "../interop/interop.hpp" +#include "../windowmgr.h" + +using namespace openloco::interop; + +namespace openloco::ui::windows +{ + // 0x0046B5C0 + void map_center_on_view_point() + { + call(0x0046B5C0); + } +}