- The game's cheater detection killed the hero ("Hase!") whenever its
protected stat mirror was stale; the mirror is now refreshed from the hero
whenever it is unlocked, stream checks never punish, loadHero no longer
sets the cheater flag (docs/anticheat.md).
- saveHero wrote the items of weapon sets 1-5 only: its loop runs over all 7
sets, so sets 6-7 survive a world loading the hero from the hero file.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
249 lines
12 KiB
Markdown
249 lines
12 KiB
Markdown
# To do
|
||
|
||
## Fixed: aura visuals missing after loading (2026-10-15)
|
||
|
||
Saving marks effect objects (cObjectFX) dead; loading keeps the buff but drops
|
||
the aura effect (type 842) that follows the hero. `src/mods/aura_restore.cpp`
|
||
recreates it after a load for Heldenmut (0x3f7) and Klingenblick (0x3f8). Spell
|
||
auras (Steinhaut, Lichtschild, ...) use other effects; the user confirmed on
|
||
2026-10-17 that their visuals are back after loading too.
|
||
|
||
## Data-driven arts instead of hardcoded art ids
|
||
|
||
Asked 2026-10-15: naming single arts as constants (`kArtHeldenmut`,
|
||
`kArtFlammenwerfer`, ... in `src/game/engine/arts.h`) does not scale. Mods
|
||
should decide by an art's properties, read from the game's own data:
|
||
|
||
- the definition tables `g_spellDefs` (`0x950a38`, 71 x 0x94) and
|
||
`g_combatMoveDefs` (`0x94ddb0`, 95 x 0x78): id, icon name, launch type,
|
||
usable mounted, ... (`tools/arttable.mjs` dumps them; most fields unnamed);
|
||
- map the remaining fields (regeneration group, lasting effect / aura,
|
||
duration, ...) and expose them as an `ArtInfo` lookup in `src/game/`;
|
||
- where the game itself hardcodes ids (e.g. the arts that always count as
|
||
magic in `cCreatureArts::AddGroupRegen`, the "already active" switch in
|
||
`IsValidArtTarget`), keep one table of those ids with the reason, instead of
|
||
named constants spread over the mods;
|
||
- optionally an own data file (JSON next to the DLL) for mod-side settings per
|
||
art, if we need values the game does not have.
|
||
|
||
## Art ranges: scaling and indicators
|
||
|
||
Asked 2026-10-15 (after making periodic aura hits strike everything in
|
||
range, docs/aura-hits.md):
|
||
|
||
- art ranges should scale with the art's level, and possibly with new
|
||
attributes;
|
||
- possibly show a range indicator (e.g. a ring around the hero for auras, or
|
||
at the cursor for aimed arts).
|
||
|
||
Known so far: the periodic-hit aura (effect kind 0x12) uses
|
||
`(cCreatureArts +0x56 + 20) * 10` world units, measured from the owner with
|
||
`cCreature::DistanceTo` (`0x536f20`); what +0x56 is (level? a stat?) is not
|
||
mapped yet. Other arts' ranges are not mapped. Fits the data-driven arts
|
||
item above (range as a property of an art, one place to compute it).
|
||
|
||
## Rename life leech to "omnivamp"
|
||
|
||
Asked 2026-10-15: life leech (property 0x349, "Lebensentzug") becomes
|
||
"omnivamp". To do: the in-game texts (item property, tooltips, character
|
||
window). The leech code is the game's (`0x5707a4`.., property 0x349, in the
|
||
damage code `0x56aff0`); it credits the hit's attacker (order +0x1c). Omnivamp usually means healing from all damage,
|
||
not only weapon hits: aura hits (docs/aura-hits.md) now name their attacker
|
||
so the game applies it;
|
||
other damage sources (spells, combat arts' extra hits, damage over time) may
|
||
follow.
|
||
|
||
## Map and map zoom in widened views
|
||
|
||
Reported 2026-10-15: the map (and zooming it) does not support the widened
|
||
render sizes yet. 2026-10-16: TAB map fixed (viewport shifted), M map spans
|
||
the render width (docs/hud.md, "Large map"), zoomed view and its markers included.
|
||
Confirmed in-game 2026-10-16.
|
||
|
||
## Quest dialog glitches in widened views
|
||
|
||
Reported 2026-10-15: accepting a quest, the dialog window "kept glitching"
|
||
and button clicks were not detected correctly. Probably the HUD layer
|
||
(src/mods/hud.cpp: windows shifted while they render / handle events): the
|
||
dialog may not be covered, or shifted twice. Details asked from the user.
|
||
|
||
## WASD walks around walls (caves)
|
||
|
||
Reported 2026-10-15: in caves WASD movement behaves "as if the player tries
|
||
to find another way to the target location if a wall comes up". WASD sends a
|
||
walk order to a point 300 world units ahead (docs/wasd.md); when that point is
|
||
behind a wall the pathfinder plans a detour. Idea: find the game's straight
|
||
line / walkability check and shorten the target when the line is blocked (or
|
||
stop / slide along the wall). Related to the pathfinder item above.
|
||
|
||
## Esc closes an open dialog first
|
||
|
||
Asked 2026-10-15: with any dialog open (quest, trader, inventory, ...), Esc
|
||
should close that dialog instead of opening the game menu (ESC menu,
|
||
`cUI_EscMenu`). Esc is handled in the engine / UI manager hotkeys
|
||
(docs/wasd.md: engine `0x618130`, UI manager `0x757120`).
|
||
|
||
## In-DLL smoke tests (later)
|
||
|
||
A test mode inside the mod DLL, started by an ini setting or command-line flag,
|
||
so builds can be checked without play-testing and without driving the real
|
||
mouse/keyboard like `tools/autotest-load.ps1`:
|
||
|
||
1. load a fixed test save;
|
||
2. play scripted input through the existing hooks (keys, casting arts, weapon
|
||
set switches, save + reload);
|
||
3. take back-buffer screenshots at checkpoints and log checks to
|
||
`sacredK.log` (aura effect present after reload, slot 6-7 inventories
|
||
survive a save, ...);
|
||
4. exit the game.
|
||
|
||
## Better pathfinder (mouse clicks and monsters)
|
||
|
||
Replace the game's pathfinding with a more reliable and efficient one, for
|
||
click-to-move and for monster AI. What we know so far:
|
||
|
||
- Walk orders are `cEvent_creature` command 4 with a ground target (+0x18/+0x1c),
|
||
sent through `cEngine::SendCreatureOrder` (`0x6170d0`), which snaps the
|
||
target to a walkable point (`0x616b70`) and hands it to
|
||
`cCreature::ReceiveOrder` (`0x52e400`, vf18, ~6400 decompiled lines).
|
||
- Far targets (~2000 world units) are rejected or followed badly.
|
||
- Still to map: the path search itself, the sector/tile collision data it
|
||
reads, and how monster AI issues its moves.
|
||
|
||
## Key bindings moved for WASD movement (temporary)
|
||
|
||
W, A and S were game hotkeys. With WASD movement (`src/mods/wasd.cpp`) their
|
||
actions moved to other keys for now; choose final bindings (and update the
|
||
in-game texts/tooltips that name the old keys):
|
||
|
||
| Key | Action | Temporary key (sacredK.ini) |
|
||
|---|---|---|
|
||
| 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 | - |
|
||
|
||
## Hard-coded game keys left (2026-10-19)
|
||
|
||
Noted after the key bindings page (docs/options.md): these game keys are
|
||
still hard-coded, not on the page. Each would go the way M / Tab / Alt went:
|
||
switch the game's key off at its source (switch index byte or compare), add
|
||
a binding that calls the same game code.
|
||
|
||
| Key | Where | What (as read, not all measured) |
|
||
|---|---|---|
|
||
| I / F / C | UI manager letter switch (`0x757120`, cases at index bytes `0x75868c` + char − 'C') | inventory window with tab 1 / 2 / 3 (`cCommand_onInvOpen`; again: close) |
|
||
| L | same | quest book `UI_WND_QUESTBOOK` toggle |
|
||
| H | same | toggles UI manager flag 0x200 (unmeasured) |
|
||
| T | same | toggles UI manager flag 0x1000 (unmeasured) |
|
||
| N | same | network info `UI_WND_NETINFO` (multiplayer only) |
|
||
| O | same, only while the options window is open | closes options (applies them) |
|
||
| S | same (`0x757775`) | save game window; works only while S is not bound (it is: *Nach unten*). *Spiel speichern* already calls this code. |
|
||
| A | engine `cEngine::ReceiveEvent` (`0x618130`, compare at `0x6188e7`) | pick up items nearby; same situation as S (A is *Nach links*); *Gegenstände aufheben* calls the code |
|
||
| P | engine (compare at `0x6188f0`) | pause, single player only |
|
||
| `` ` `` / ^ / `\` (key codes 0x60, 0x5e, 0xdc) | engine (`0x6188cf`), UI manager (`0x75758c`, `0x75759c`) | console |
|
||
| Esc | engine, UI manager `HandleEsc` | closes windows / ESC menu (escape.cpp builds on it) |
|
||
| Shift + Space | engine potion table (off with the potion keys) | - |
|
||
|
||
Digits 0-9 are taken by the skill keys (input.cpp `Reserved`). Bound keys are
|
||
swallowed before the game sees them, so a game key only acts while it is not
|
||
bound to something else: rebinding *Nach links* away from A brings back the
|
||
game's A (pickup), same for S. Individual windows may have more keys of
|
||
their own (not surveyed).
|
||
|
||
## Potion stacks
|
||
|
||
Asked 2026-10-17 (after the potion counts on the bottom bar,
|
||
`src/mods/potioncounts.cpp`): potions of the same type (e.g. minor healing)
|
||
stack in one inventory cell, up to 20 per stack (a full stack starts a new
|
||
one). Drag, sell and drop move the whole stack, as with any other item. The
|
||
counts on the potion slots then add up the stacks. In progress, see
|
||
docs/item-stacks.md (open: sale price per stack, splitting on the ground).
|
||
|
||
## Walking animation after loading (2026-10-17)
|
||
|
||
The hero sometimes plays a walking animation after a save game load while
|
||
standing still. Not reproduced yet: a load log (hero mode, action, animation
|
||
fields, orders) showed nothing unusual; right after a load the game itself
|
||
sends one walk order (0x4) while the hero is idle. Measure again when it shows.
|
||
|
||
## Multiplayer with characters (2026-10-19)
|
||
|
||
Characters became one file each with a world per difficulty
|
||
(`docs/characters.md`); vanilla multiplayer picks exported `Heronn.pax`
|
||
heroes, which no longer exist. Later: give multiplayer the shared hero of a
|
||
character file (the session's hero file +0x3a3c, as `SelectHeroSlot` does),
|
||
and decide what a multiplayer game does to the character's progress.
|
||
|
||
## Characters: open parts of the rework (2026-10-20)
|
||
|
||
From the characters rework (`docs/characters.md`, request of 2026-10-19):
|
||
|
||
- **Unlock difficulties by story completion.** Bronze and Silber stay open;
|
||
difficulty d >= 2 opens when the story on d - 1 is completed. The counters
|
||
are one byte per difficulty in cStatsManager +0x5704 (read 0x424be0) and
|
||
travel in the save header (+0x88..+0x98) and the hero file. Done
|
||
2026-10-20 (docs/characters.md).
|
||
- **Autosave interval in the options window.** Done 2026-10-20: Allgemein
|
||
page, "Spielstände" frame (docs/options.md).
|
||
- Quickload (row 0, `GAME00.PAK`) does not know characters; not needed
|
||
(user, 2026-10-20).
|
||
|
||
## Two saves in a row (2026-10-20, not reproduced)
|
||
|
||
Once two real saves ("saved", not "autosaved") went into the same character
|
||
1.8 s apart, about 77 s after loading, with the timed autosave off. Save
|
||
flag 0x40 is set in cEngine::ReceiveEvent at 0x618876 (quicksave),
|
||
0x618f08 and 0x6190c5 (save event 0xf: +0xc row, +0x18 autosave flag). A
|
||
log of the event that sets the flag (dwords 0..9) did not catch it again;
|
||
add it back if it shows.
|
||
|
||
Once (2026-10-20, not reproduced) an autosave seemed to fire right after a
|
||
new world started through the hero chain (Character08: hero world loaded,
|
||
then the new world). The log of that run had no save at all; the timed
|
||
autosave counts from the game start (OnGameStart).
|
||
|
||
## Savegames screen redesign ("Spielen")
|
||
|
||
Asked 2026-10-20: redesign the load window (cUI_Savegame, the "Spielen"
|
||
screen, characters.cpp): show a render of the selected character, use the
|
||
space far better. No 16:9 artwork exists for the game (user, 2026-10-20):
|
||
we design our own UIs, using the width beyond the 1024 frame (now drawn in
|
||
a centred 1024x768 viewport with black sides, hud.cpp FrameScope). Design
|
||
for 16:9 (1920x1080, 1365x768 UI units), not ultrawide (user). Screen done
|
||
2026-10-20 (docs/characters.md, "Spielen screen"; docs/screens.md). Hero
|
||
in 3D done 2026-10-20. Open: list scrolling beyond 9 characters, larger
|
||
heading font.
|
||
|
||
## Fine-tuning the Spielen and options screens (2026-10-21)
|
||
|
||
The user is very satisfied with the menu rework for now (rock background on
|
||
all menu screens, centred menu frame, logo, Spielen screen with the 3D
|
||
hero), but both the Spielen screen and the options window still need a lot
|
||
of fine-tuning. Details to be collected when we get to it; known so far:
|
||
list scrolling beyond 9 characters, larger heading font, the options
|
||
window's layout in the width beyond its 1024 frame.
|
||
|
||
## Quest book: all quests, unknown ones as "???" (2026-10-25)
|
||
|
||
Request: every quest appears in the quest book; quests not yet activated show
|
||
as "???", so a player knows how many quests an area holds without being told
|
||
where they are. Notes: the quest table (g_quests 0xaa9e98, 0x124 per quest,
|
||
game/engine/quests.h) lists all quests of the campaign, including the generic
|
||
repeatable ones (ids 2600..3599, cloned by Quest_End) and DQ_ dynamic quests;
|
||
which of them count for an area, and how the book groups by area, is still to
|
||
be measured.
|
||
|
||
## Megamap zoomed view: markers shifted (2026-10-25)
|
||
|
||
Reported: on the M map, clicking a location to zoom in shows the markers on
|
||
the zoomed map wrong / shifted (megamap.cpp).
|
||
|
||
## Load / save progress screen: rock background (2026-10-25)
|
||
|
||
Reported: the progress screen shown while loading / saving does not use the
|
||
rock-wall background of the other menu screens yet (hud::RenderMenuFrame,
|
||
docs/screens.md). The GDI progress screen is DxDriver7_LoadingScreen
|
||
0x6469d0 (1024x768, game/addresses.h); pictures PAK\loading0/1.bmp,
|
||
loadgame.bmp, savegame.bmp, LoadingUW00/01.bmp.
|