diff --git a/src/mods/hud.cpp b/src/mods/hud.cpp index 7d441c3..dfa2f2a 100644 --- a/src/mods/hud.cpp +++ b/src/mods/hud.cpp @@ -431,6 +431,10 @@ int CursorOffsetX() { return g_cursorDx; } +int DrawOffsetX() { + return g_offsetX; +} + void* CursorFor(void* cursor) { return g_cursorDx != 0 && cursor == g_cursorShadow.real ? g_cursorShadow.bytes : cursor; } diff --git a/src/mods/hud.h b/src/mods/hud.h index 7c2cf6c..402cb7c 100644 --- a/src/mods/hud.h +++ b/src/mods/hud.h @@ -9,6 +9,10 @@ void OnDevice(void* device); // the current thread (0 outside): polled mouse positions are reduced by it. int CursorOffsetX(); +// Horizontal offset the current thread's UI drawing is shifted by (the +// outermost hooked window's; 0 outside). +int DrawOffsetX(); + // The mouse cursor object as the current thread should see it: inside a moved // window, a private copy with x shifted by CursorOffsetX(). void* CursorFor(void* cursor); diff --git a/src/mods/input.cpp b/src/mods/input.cpp index 39315e3..cedab60 100644 --- a/src/mods/input.cpp +++ b/src/mods/input.cpp @@ -10,8 +10,10 @@ // hotkey post that hotkey's key event to the game's event kernel, the way the window // procedure does (the kernel dispatches it right away, on the window thread). // -// While a text field has the keyboard, or Ctrl / Alt is held, keys pass -// through unchanged. +// While a text field has the keyboard, keys pass through unchanged. (Keys +// with Ctrl / Alt held used to pass too; GetKeyState reports Alt as held after +// Alt+Tab until it is pressed again in the game, which switched the bindings +// off. Alt+key arrives as WM_SYSKEYDOWN and is not handled here anyway.) // // sacred_re.ini (key names: A-Z, 0-9, F1-F24, Space, None): // [keys] @@ -173,10 +175,6 @@ void Release(const Binding& binding, int vk) { } } -bool ModifierHeld() { - return (GetKeyState(VK_CONTROL) & 0x8000) != 0 || (GetKeyState(VK_MENU) & 0x8000) != 0; -} - // Virtual keys whose WM_KEYDOWN was taken: their WM_CHAR / WM_KEYUP are // swallowed too, even if the state changed in between. bool g_taken[256] = {}; @@ -212,7 +210,7 @@ bool HandleWindowMessage(HWND, UINT message, WPARAM wParam, LPARAM lParam) { const bool repeat = (lParam & (1 << 30)) != 0; if (!repeat) { g_taken[vk] = false; - if (ModifierHeld() || TypingIntoTextField()) { + if (TypingIntoTextField()) { return false; } const Binding* binding = BindingFor(vk); diff --git a/src/mods/megamap.cpp b/src/mods/megamap.cpp index 4cbc4e2..c9d7abc 100644 --- a/src/mods/megamap.cpp +++ b/src/mods/megamap.cpp @@ -10,11 +10,13 @@ // the zoom buttons at the bottom stay centred. The window is drawn and clicked // unshifted (mods/hud.cpp, Anchor::Screen). See docs/hud.md. +#include #include #include #include #include "game/addresses.h" +#include "mods/hud.h" #include "mods/megamap.h" #include "mods/widescreen.h" #include "re/hook.h" @@ -37,12 +39,16 @@ constexpr uint32_t kScrollLimit = 0x006c9edd; // The view centre 200h: the zoom-in frame (0x6ca53f) and the image centred // on it (0x6ca637, 0x6ca645). constexpr uint32_t kCentreImmediates[] = {0x006ca53f, 0x006ca637, 0x006ca645}; -// fsub/fld/fadd [512.0]: centring the scroll on the hero (opening the map -// 0x6c7bfe, 0x6cb27a), the zoomed view (0x6ccb7f) and its quest markers -// (0x6cf782). -constexpr uint32_t kCentreFloatUses[] = {0x006c7bfe, 0x006cb27a, 0x006ccb7f, 0x006cf782}; -// fld [768.0] as an x: markers in the zoomed view at 768 - d (0x6ce156), the -// centre plus 256. +// fsub [512.0]: centring the scroll on the hero (opening the map 0x6c7bfe, +// 0x6cb27a). +constexpr uint32_t kCentreFloatUses[] = {0x006c7bfe, 0x006cb27a}; +// The zoomed view (0x6cc950, cdecl) is drawn by the large map and by the TAB +// overview map (cUI_OverviewMap 0x6c69d0, a centred window: shifted by the +// HUD layer). Its centre: fld [512.0] (0x6ccb7f), quest markers fadd [512.0] +// (0x6cf782), other markers fld [768.0] as an x, 768 - d = centre + 256 +// (0x6ce156). It is set on every call from the window's draw offset. +constexpr uint32_t kZoomView = 0x006cc950; +constexpr uint32_t kZoomCentreUses[] = {0x006ccb7f, 0x006cf782}; constexpr uint32_t kZoomMarkerX = 0x006ce156; constexpr float kZoomMarkerFromCentre = 256.0f; // The dark band around the view (10 vertices, mov [esp+..], imm32): its right @@ -52,6 +58,7 @@ constexpr uint32_t kBandRightInner[] = {0x006ca7bc, 0x006ca84c}; constexpr int kBandWidth = 70; float g_halfWidth = 512.0f; +float g_zoomCentre = 512.0f; float g_zoomMarkerX = 768.0f; uint32_t FloatBits(float value) { @@ -172,7 +179,9 @@ void PatchLayout(int width) { for (uint32_t instruction : kCentreFloatUses) { failed += !re::RedirectOperand(instruction, game::addr::kScreenHalfWidthF, &g_halfWidth); } - g_zoomMarkerX = g_halfWidth + kZoomMarkerFromCentre; + for (uint32_t instruction : kZoomCentreUses) { + failed += !re::RedirectOperand(instruction, game::addr::kScreenHalfWidthF, &g_zoomCentre); + } failed += !re::RedirectOperand(kZoomMarkerX, game::addr::kScreenHeightF, &g_zoomMarkerX); failed += re::PatchAll(kBandRightOuter, FloatBits(1024.0f), FloatBits(static_cast(width))); failed += re::PatchAll(kBandRightInner, FloatBits(1024.0f - kBandWidth), @@ -180,10 +189,31 @@ void PatchLayout(int width) { re::Log("megamap: view width %d%s", width, failed ? " (some patches FAILED)" : ""); } +// Before each zoomed view: its centre in the coordinates of the window that +// draws it (the large map is unshifted: width / 2; a centred window, which +// the HUD layer shifts: 512). +void __cdecl SetZoomCentre() { + const int width = std::max(mods::widescreen::RenderWidth(), kLayoutWidth); + g_zoomCentre = width / 2.0f - static_cast(mods::hud::DrawOffsetX()); + g_zoomMarkerX = g_zoomCentre + kZoomMarkerFromCentre; +} + } // namespace mods::megamap namespace game { +// The zoomed view (0x6cc950, cdecl): sets its centre, then runs it unchanged. +void ZoomView(); +RE_HOOK(mods::megamap::kZoomView, ZoomView); +__declspec(naked) void ZoomView() { + __asm { + pushad + call mods::megamap::SetZoomCentre + popad + jmp dword ptr [ZoomView_original] + } +} + // cUI_Megamap::Show (vf24 0x6c7930, the argument: show / hide). void __fastcall UiMegamap_Show(void* self, void* edx, int show); RE_HOOK(0x006c7930, UiMegamap_Show);