Characters: 16:9 "Spielen" screen, autosave interval option

- Shared screen kit (mods/screen, docs/screens.md): a 1365x768 canvas
  centred in the render width on our own dark background, the game's
  frames and buttons; the main menu renders full width while it is shown.
- The load window (cUI_Savegame) is replaced by the Spielen screen:
  character list, hero panel, campaign x difficulty grid, save/autosave
  choice, rename/delete/reset/new character dialogs.
- Migrated characters without a shared hero load their hero's world
  first, then start the new world.
- Options, Allgemein: autosave interval (Aus/5/10/15/30 minutes).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
khallaandClaude Opus 5.5 committed 2026-10-20 23:20:45 +02:00
1 parent 732d9c2abb
commit 34a119433a
16 files changed
+1391 -468

No files matched your search

+52 -45
View File
@@ -177,26 +177,55 @@ of both vectors, deleted) and UI_LABEL_LOADGAME ("Spielstände", shows
UI_WND_SAVEGAME) moves to the top with the text "Spielen"; the others move up,
keeping the gap before "Beenden".
### Load window (cUI_Savegame)
### Spielen screen (cUI_Savegame)
Request 2026-10-20: redesign the load window, 16:9, using the space (layout
agreed: characters left, the character in the middle, worlds right, buttons
below; our own background). Built on the shared screen kit
(docs/screens.md); the window's own drawing and mouse handling are not used.
- The window still scans: before each scan (0x71e330) one preview
`GAMEnn.PAK` per character is written into `_work`; row nn = character nn.
Its entries are only needed for the load.
- Left: the characters, newest save first (name, class, level; "im Spiel" for
the one being played). Click selects, double click plays.
- Middle: name, class and level, the world played last with its date. (A
render of the hero is planned.)
- Right: a grid campaigns x difficulties. A cell shows the save's date,
"+ Autosave" when the autosave is newer, "Story abgeschlossen", "Neu" for a
difficulty that is open but has no world, "–" when closed. Open: Bronze and
Silber, every difficulty up to the highest with a world in either campaign,
and the one after each difficulty whose story the shared hero completed
(hero header +0xed..); new worlds need the shared hero, not in multiplayer
(byte 0x182cb6c). Click selects, double click plays. With a newer autosave
"Laden von:" picks the save or the autosave (default: the autosave).
"Welt zurücksetzen" for a saved world (not the character being played).
- Buttons: Neuer Charakter (main menu only), Umbenennen, Löschen (not for the
character being played), Zurück (action 0xc), Spielen.
- Spielen: a saved world loads through the window's load action (4, with its
"really load?" confirmation in a game): the window's selection is set to
its first entry and `g_loadRow` names the row, which `Engine_Load` takes
instead of the entry's. A new world starts a game (below; in a game after
stopping the running one). The window's own load / default actions (Enter)
run Spielen too; its delete actions (7, 8) are ignored.
- Dialogs over the screen: rename (keys go to the field through the input
key capture; the name is only in the hero header chunk 0xc3 (+8, UTF-16,
0x40 chars): rewritten in the hero, every world and the autosave, plus
`meta.name`), campaign of a new character, confirmations of reset and
delete. Buttons are cUI_Button2 copies of the load button
(`game::NewButtonLike`) with our own text ids and overrides.
- Delete moves the character file and its autosave to `charactersdeleted`.
- Neuer Charakter: sets `g_campaign`, hides the window and shows UI_CHARACTER
(the game's character creation, as the main menu's campaign entries did).
The first save makes the character file.
- Reset (decided 2026-10-20) removes the world section (a copy goes to
`charactersdeletedCharacterNN.sacredK.<section>.PAK`) and an autosave of
that world, and clears the shared hero's story completion of that
difficulty (hero header +0xed + d); the game counts it per difficulty, so
the next difficulty closes in both campaigns unless a world keeps it open.
### Character window (cUI_Character)
- Before each scan (0x71e330) one preview `GAMEnn.PAK` per character is
written into `_work` (header, thumbnail, world time, description
"Name - Klasse"); row nn = character nn. The preview's campaign field is
the running campaign, so the window lists every character. The row's
second line (call 0x71db2a to SetText 0x736f00) shows
"Stufe N - Campaign - difficulty".
- Laden (action 4 / 0xb) opens the world dialog when there is more than one
choice: per campaign worlds, newer autosaves "(Autosave)", and "(neu)" for
every difficulty without a world up to the highest open one (needs the
shared hero; not in multiplayer, byte 0x182cb6c). Open: Bronze and Silber,
every difficulty up to the highest with a world in either campaign, and the
one after each difficulty whose story the shared hero completed (hero
header +0xed..). `g_campaign` is set to the chosen world's before loading
or starting.
- "Neuer Charakter" (two places below Löschen; main menu only) asks for the
campaign, sets `g_campaign`, hides the window and shows UI_CHARACTER (the
game's character creation, as the main menu's campaign entries did). The
first save makes the character file.
- Vanilla made no new heroes for the Underworld: `cUI_Character::Show`
(vf24 0x70e2a0) switches to mode 7 in single player with `g_campaign` 1
(0x70e3e8), the import of an exported hero of level 25+ (0x70eedc); with no
@@ -209,30 +238,6 @@ keeping the gap before "Beenden".
- Class selection without "Importieren" (request 2026-10-20): button +0x3a0
(caption UI_IMPORT in modes 0/1); its modes-0/1 draw (0x70f67e) is removed,
its click (0x70eab4 / 0x70eac7, SetMode(7)) jumps to the handler's end.
- Load window without "Speichern" (request 2026-10-20; saving is direct):
button +0x820 (action 1, disabled in load mode, so its click falls through)
is not drawn (jump over 0x71ddbc); Löschen (+0x8dc) takes its rect, our
buttons follow below it.
- "Umbenennen" (below Löschen; not for the character being played) asks for
a name; keys go to the field through the input key capture. The name is
only in the hero header chunk 0xc3 (+8, UTF-16, 0x40 chars): rewritten in
the hero, every world and the autosave, plus `meta.name`. Confirmed: the
game loads renamed characters without complaint.
- Dialog buttons are cUI_Button2 copies of the load button
(`game::NewButtonLike`); their captions are our own text ids with
overrides (texts.cpp checks overrides for our ids too).
- "Zurücksetzen" (below Umbenennen; a selected character with the shared
hero and a world, not the one being played) lists the character's worlds,
then asks "<Welt> zurücksetzen?". A reset (decided 2026-10-20) removes the
world section (a copy goes to `charactersdeletedCharacterNN.sacredK.<section>.PAK`)
and an autosave of that world, and clears the shared hero's story
completion of that difficulty (hero header +0xed + d); the game counts it
per difficulty, so the next difficulty closes in both campaigns unless a
world keeps it open. The hero keeps everything else.
- The dialog is one generic list: each kind fills a title and entries
(FillDialog), "Abbrechen" last.
### Load
`cEngine::Load` (0x61b790) of a listed row: the chosen world and the hero are
@@ -265,7 +270,8 @@ Silent autosave: 10 minutes after the last save of any kind (or the game's
start), `SaveOnTick` does the direct save marked as an autosave, so it goes
into the autosave file. While a window is open or a save runs it waits for
the next tick. A character never saved yet gets its character file from it.
Interval: `sacredK.ini` `[characters] AutosaveMinutes` (default 10, 0 off).
Interval: options window, *Allgemein*, *Autosave (Min.)* (docs/options.md); kept in
`sacredK.ini` `[characters] AutosaveMinutes` (default 10, 0 off).
Direct save (K key, Esc menu "Speichern"): on the next engine tick, as the
quicksave does (0x618ebb): `cUI_Manager::CanOpenWindow` (0x75a690),
@@ -299,5 +305,6 @@ kept, the newest file overall is the shared hero.
## Open
- Quickload (row 0) does not know characters.
- Quickload (row 0) does not know characters (not needed, user 2026-10-20).
- Spielen screen: a render of the hero; scrolling the list beyond 9 characters.
- Multiplayer (see `todo.md`).