Files
khallaandClaude Opus 5.5 9bc557cd95 Preferred monitor: chosen in Optionen > Allgemein, used at the next start
The Internet-Optionen frame becomes Bildschirm with a Monitor dropdown
(Hauptmonitor or a connected monitor, kept by device path in
[display] Monitor=). The borderless window and the render size use that
monitor, falling back to the main monitor when it is not connected.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 16:06:20 +01:00

164 lines
9.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 `sacredK.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 `sacredK.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.
## Beute: loot filter (2026-10-19)
The page holds the loot filter (`docs/loot-filter.md`): the game's pickup
choice (PICKUPAUTO radio buttons, their labels, the separator; matched by
pointer and control name at +0x30) is never shown, a framed table below the
auto-pickup frame sets a mode per category. Its frame is made like the key
page's (`AddFrame`).
## Allgemein: autosave interval (2026-10-20)
Request: the silent autosave's interval (docs/characters.md, Save) settable
in the options, not only in `sacredK.ini`. The general frame moved up into
the auto-pickup frame's place; it is taller than the frames beside it, so the
new frame goes below the lowest frame of the left column. It copies the
right column's lowest frame (Internet-Optionen): its height and the gap the
right column leaves between its frames, measured from the window's frames
when it is made (a lower frame broke its side ornaments, a smaller gap joined
the borders: screenshots 2026-10-20). One row *Autosave (Min.)*: Aus / 5 /
10 / 15 / 30 (the key page's box colour is not seen on the dark backdrop: a
lighter one). A click selects, OK writes
`[characters] AutosaveMinutes` (`characters::SetAutosaveMinutes`, the timer
uses it at once), Cancel drops it.
## Allgemein: preferred monitor (2026-10-25)
Request: a setting for the monitor the game starts on; with none set, or the
preferred monitor not connected, the system's main monitor.
- `src/mods/monitor.cpp`: the monitors (`EnumDisplayMonitors`), named and
told apart through the display configuration (`QueryDisplayConfig`,
`DisplayConfigGetDeviceInfo`: the GDI name `\.\DISPLAYn` of each path's
source, the monitor's EDID name and device path of its target). The device
path is the id: it stays the same across restarts and when monitors are
rearranged, unlike `\.\DISPLAYn`. Kept in `sacredK.ini`
`[display] Monitor=` (empty: the main monitor).
- `GameMonitorRect` is asked where the screen is decided at startup: the
borderless window covers that monitor (`borderless.cpp`), and the render
size follows its aspect ratio (`widescreen.cpp` `ApplyRenderSize`). The
log line `monitor: <name> WxH at (x,y)` says which one was used and why.
A change applies at the next start.
- In the options (user's choice of place): the *Internet-Optionen* frame
(Datendurchsatz, multiplayer only) becomes *Bildschirm*. Its controls
(`UI_CFG_LANSPEED` label, DSL / ISDN radio buttons, everything inside
`UI_FRAME_INTERNET`) and the title label `UI_LABEL_WAN` are hidden; the
game keeps the saved Datendurchsatz. The title text (key `UI_CFG_WAN`) is
overridden with "Bildschirm" before the window is made.
- One row: *Monitor* and a box with the choice (Hauptmonitor, then each
monitor as "name (WxH)", "Nicht verbunden" for a preferred monitor that is
missing). A click opens the list upwards (the frame is the lowest one); a
click on an entry picks it, any click closes the list. A changed choice
shows "Ab dem nächsten Spielstart" below the box. OK saves, Cancel drops.