Files
sacred_k/docs/options.md
T
khallaandClaude Opus 5.5 838b1aa491 Options: tabs Allgemein / Beute / Tastenbelegung with key bindings
- Options window in three tabs; the auto-pickup settings move to Beute;
  sliders move with their page; black sides like the save game screen.
- Tastenbelegung: every binding settable (click, press key; Esc cancels,
  Backspace unbinds), "Alle zurücksetzen" as a game button, saved on OK.
- Potions bindable (default unbound), named by the game's potion texts; the
  game's own potion hotkeys are off; bar tooltips show the bound key.
- Map (M), overview map (Tab, held) and labels (Alt, held) bindable; the
  game's own M / Tab / Alt handling is switched off.
- Save game key calls the game's save window code instead of a posted key.
- Teleportationstrank: fixed text replacement from startup (also the
  Ausdauertrank items, potion kind 5 as well).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 00:38:34 +02:00

6.6 KiB
Raw Blame History

Options window: tabs and key bindings

Request (2026-10-18): the settings screen gets three tabs: Allgemein, Beute (loot filter; first iteration: the game's loot options moved there from the common page) and Tastenbelegung (key bindings, so far only settable in sacred_re.ini). Code: src/mods/options.cpp; bindings in src/mods/input.cpp.

The window (cUI_Options)

  • vtable 0x89505c, constructor 0x716570 (name, rect, parent, flags; ret 0x18), destructor 0x7165f0; controls built by 0x7184e0.
  • vf44 0x716640 (renderer, ?, ?; ret 0xc): window render (0x727040), then drives the sliders while the mouse is held. vf10 0x716b30: events.
  • 0x717ea0 loads the settings into the controls when the window is shown; 0x717460 (thiscall, plain ret) writes them back — called for OK.
  • Controls: vector at +0x90 (begin) / +0x94 (end); the 16 background tiles are in the window's own list +0x78. Buttons: +0x158 Cancel, +0x15c OK. Pickup: radio buttons +0x16c/+0x170/+0x174 (PICKUPAUTO 0/1/2), checkbox +0x178 (PICKUPANIM).
  • Layout (1024x768): frames at x 0x40 / 0x220, y 0x40 / 0x120 / 0x200, borders 0x14 outside, labels above (y 0x20 / 0x100 / 0x1e0). Left: graphics, auto-pickup (AUTOCOLLECT), general; right: sound volume, 3D sound, internet. OK / Cancel at y 0x284.
  • cUI_Frame (vtable 0x8955ac): its render 0x73a540 does not test the visible flag, only +0xdc (set to 1 by its constructors).

How the mod works

  • After the constructor: every control in +0x90 is put on a page by its position — left column middle row → Beute, everything else → Allgemein, OK / Cancel on all pages. The auto-pickup group moves up one row (to the top of its page), the general group below it moves up into its place.
  • A cUI_TabSheet (game/ui/tabs.h) at the top frames' border; its headers (default row layout) sit above the frame labels.
  • Each frame (vf44) the controls not on the active page are hidden (visible flag, frames also +0xdc); controls hidden by the mod are shown again on their page. The game re-shows controls when the window opens, so this runs every frame.
  • Tastenbelegung is drawn by the mod: rows per binding, grouped (Kampfkünste, Waffensets, Bewegung, Aktionen), a key box per row. A click on a box captures the next key press (input::SetKeyCapture, swallowed before the game sees it): Esc cancels, Backspace unbinds, a bindable key is taken (and removed from any other action). The page works on a copy loaded when the window opens; OK (0x717460) saves it to [keys] in sacred_re.ini, Cancel drops it.
  • Movement keys (W/A/S/D) are bindings now (MoveUp/Left/Down/Right); mods/wasd.cpp polls the bound keys.

Follow-ups (2026-10-18)

  • Pages moved down 24 px (kContentShift) for room below the tab headers.
  • Alle zurücksetzen (left of OK / Cancel) sets every binding back to its default; saved with OK like any other change.
  • Potion bindings Trank 1–5 and Trank 1 für Gefährten (default: no key). They call cEngine::UseActionSlot (0x613040, thiscall (kind, on ally), ret 8) on the engine tick. The game's own potion hotkeys are off: its engine hotkey switch (cEngine::ReceiveEvent, index bytes 0x619adc per upper-case character − 0x20, targets 0x619ac0) had Space → kind 1 (Shift: 5), B → kind 1 on the weakest ally, Q 2, W 3, E 4, R 5; those six entries now point at index 6 (no hotkey). ActionSlot3 (W's action on G) is gone.
  • The window is drawn like the save game / export screens: black beside the 1024 frame (hud::RenderFramed).
  • Key bindings page: a backdrop (0x724ed0) and a frame (0x739f90) per column, created with the window's controls and shown only on that page. (Drawing the window's existing ones at other rects did not fit: a frame's border pieces keep the place they were made at.)
  • Pages move down 24 px under the tab headers. A slider (cUI_Scrollbar, vtable 0x895664) moves with its parts: minus, plus, track and knob are embedded controls (+0x94 / +0x110 / +0x18c / +0x208) with rects in window coordinates, and the knob is placed from +0x78 / +0x7c each frame.
  • Key page layout (2026-10-19): the two frames span the other pages' frame area (top row's top to the bottom of Internet-Optionen); the hints sit in the bottom row next to Alle zurücksetzen, since they hold for the whole page.
  • Potion kinds are named by the bottom bar's tooltip texts: PotionTooltipText 0x43fa90 (kind) → text id by key, e.g. <color=FFFFFF80>Heiltrank <colorw=FFFFFFFF>[SPC] (kinds 1–5: Heiltrank, Sog der Hölle, Trank des Mentors, Antidot der Viper, Trank der Konzentration / Teleportationstrank; read in scripts/de/SRglbl.res). Shown, the tags are colour codes (backslash, letter, 8 hex digits: \dFFFFFF80Heiltrank \wFFFFFFFF[SPC]); game::PotionKindName strips them and the key; the tooltips get the bound key in the brackets, or none (game::SetTextOverride, mods/potioncounts.cpp).
  • No posted game keys any more: Spiel speichern calls what the UI manager's S case (0x757775) does: save window built (manager slot 0x2b), CanOpenWindow 0x75a690, engine event (vtable 0x88eb38, 0x13, 5, 1), then window command show (0x11) for UI_WND_SAVEGAME (game/ui/windows.h, shared with escape.cpp's hide 0x12).

Karte, Minikarte, Beschriftungen (2026-10-19)

Request: M (map), Tab (minimap) and Alt (text overlay) bindable too.

  • M: the UI manager's letter switch (cUI_Manager::ReceiveEvent 0x757120, upper-case character − 'C', index bytes 0x75868c, targets 0x758660) shows UI_WND_MEGAMAP (slot 0x25) unless a blocking window is open; while the map is open its own branch (cmp 'M' at 0x757f86) hides it. Switched off (M → index 10, the compare → -1); the Karte binding does the same checks and sends the window command.
  • Tab: the in-game window procedure 0x8110d0 shows UI_WND_OVERVIEWMAP on key down (switch on vk − 9: index bytes 0x812124, case 0x81146d) and hides it on key up (0x812270, case 0x8117f8). Switched off (Tab → the "other key" indices 4 / 3); Minikarte (halten) shows / hides it on the bound key's down / up.
  • Alt: no message, the game polls GetAsyncKeyState(VK_MENU) for its name overlay in seven places (DrawObjectLabels 0x627260, PickObjectAt 0x626d30, cEngine 0x60f1d0 / 0x611f10 / 0x617360, cCreature 0x599880, the map's debug teleport 0x6c7ec0). Their call [GetAsyncKeyState] read our pointer instead: LabelsKeyState returns the bound key's state.
  • Alt and F10 come as WM_SYSKEYDOWN: the key capture takes those too.
  • Key page: 20 lines per column (line 25 px) to fit the three rows.