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>
This commit is contained in:
1 parent
72525cd5ba
commit
838b1aa491
27 files changed
+1423
-184
No files matched your search
+111
@@ -0,0 +1,111 @@
|
||||
# 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.
|
||||
@@ -19,10 +19,13 @@ one of them.
|
||||
|
||||
## Mod (src/mods/teleportpotion.cpp)
|
||||
|
||||
- Every item type of potion kind 5 counts. Their names (text 0x428700 of each
|
||||
type) are replaced in every game text (`game::ReplaceInTexts`): the item
|
||||
names and the bottom bar's quick-select tooltip ("Trank der Konzentration
|
||||
[R]", its own text id). The shortest name is replaced, so stage words stay.
|
||||
- Every item type of potion kind 5 counts. Their name, "Trank der
|
||||
Konzentration", is replaced in every game text from the DLL's start
|
||||
(`game::ReplaceInTexts`, applied where the game fetches a text): the item
|
||||
names (stage words in front stay) and the bottom bar's quick-select tooltip
|
||||
("Trank der Konzentration [R]", its own text id). Before (until
|
||||
2026-10-19) the names were collected from the item types at game start, so
|
||||
the main menu (options' key bindings) still had the old name.
|
||||
- cCreature::UseItem (hooked in itemstack.cpp) asks `teleportpotion::UseItem`
|
||||
first: for the hero's Teleportationstrank it posts the teleporter's event
|
||||
with the hero's mask instead of the drink.
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@ in-game texts/tooltips that name the old keys):
|
||||
|
||||
| Key | Action | Temporary key (sacred_re.ini) |
|
||||
|---|---|---|
|
||||
| W | action slot 3 (`cEngine::UseActionSlot`, like Q/E/R/B/Space) | G (`[keys] ActionSlot3`) |
|
||||
| W | potion kind 3 (`cEngine::UseActionSlot`, like Q/E/R/B/Space) | game potion keys switched off; `[keys] Potion1-5` (docs/options.md) |
|
||||
| A | pick up items nearby (creature event 0x113) | Q (`[keys] PickUp`, 2026-10-17; was V) |
|
||||
| S | save game window (`UI_WND_SAVEGAME`) | K (`[keys] SaveGame`) |
|
||||
| D | unbound | - |
|
||||
|
||||
Reference in new issue
Block a user