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:
1 parent
732d9c2abb
commit
34a119433a
16 files changed
+1391
-468
No files matched your search
+52
-45
@@ -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`).
|
||||
@@ -117,3 +117,18 @@ 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.
|
||||
@@ -0,0 +1,39 @@
|
||||
# 16:9 menu screens
|
||||
|
||||
Request (2026-10-20): the game's menu screens are laid out for 1024x768; we
|
||||
design our own UIs for them. There is no 16:9 artwork for the game, so the
|
||||
background is our own (option 3 of the ones discussed: dark, no picture), and
|
||||
the approach is shared by all menu screens. Target: 16:9, 1920x1080, which is
|
||||
1365x768 in UI units; wider screens only get more background at the sides
|
||||
(not designed for ultrawide).
|
||||
|
||||
## How a screen works
|
||||
|
||||
- `mods/screen.{h,cpp}`: a screen replaces a full-screen window's drawing and
|
||||
mouse handling. Its render hook calls `screen::Render(window, device, body,
|
||||
context)`: the background across the whole render target, then the body in
|
||||
canvas coordinates (1365x768, centred: `hud::RenderCanvas`, the HUD
|
||||
layer's offset machinery with `Anchor::Canvas`; drawing, the cursor and the
|
||||
window's hit tests shifted alike). Mouse events go through `screen::Handle`
|
||||
(`hud::HandleCanvas`). Keys stay the window's.
|
||||
- In the main menu the game renders a classic 1024x768 frame (presented 4:3).
|
||||
While a screen's window is shown, `widescreen::SetWideMenuScreen` makes the
|
||||
menu thread render and present the full width.
|
||||
- Parts: `screen::Panel` (dark backdrop and the game's frame, `cUI_Frame`,
|
||||
game/ui/frame.h, made anew when its rect changes), `screen::Button` (a
|
||||
button of the game's with the look of one of the window's,
|
||||
`game::NewButtonLike`), `screen::Text`, `screen::Fill`,
|
||||
`screen::DoubleClick`. Spacing constants from measurements: frames reach
|
||||
0x20 beyond their rects and need a height of about 0x40, buttons reach 0x21.
|
||||
Frames are built of 64-unit pieces: widths and heights in steps of 64
|
||||
(`screen::kFrameStep`), other sizes leave gaps (screenshot 2026-10-20).
|
||||
- Fonts (logged 2026-10-20): font 0 is another class (no line height field);
|
||||
the TrueType fonts 1..7 have line heights 20, 19, 25, 31, 25, 28, 13.
|
||||
Screens use font 1; 4 or 6 would suit headings.
|
||||
- Inside the canvas scope the HUD layer does not stretch "full 1024 layout"
|
||||
quads (`g_canvasScope`).
|
||||
|
||||
## Screens
|
||||
|
||||
- Spielen (the load window, cUI_Savegame): docs/characters.md, "Spielen
|
||||
screen".
|
||||
+17
-9
@@ -184,12 +184,10 @@ From the characters rework (`docs/characters.md`, request of 2026-10-19):
|
||||
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** (now only
|
||||
`sacredK.ini` `[characters] AutosaveMinutes`).
|
||||
- **Quickload (row 0) does not know characters.** Ctrl+Z saves into the
|
||||
current character, but the quickload event (0x116, engine +0x68 = row,
|
||||
flag 0x200) loads `GAME00.PAK`, which is not listed; make it reload the
|
||||
current character's world (or its newer autosave).
|
||||
- **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)
|
||||
|
||||
@@ -200,10 +198,20 @@ flag 0x40 is set in cEngine::ReceiveEvent at 0x618876 (quicksave),
|
||||
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. The user looks for 16:9 artwork so the screens can be
|
||||
widened beyond the 1024 frame (now drawn in a centred 1024x768 viewport with
|
||||
black sides, hud.cpp FrameScope).
|
||||
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). Open:
|
||||
the render of the selected hero (the hero panel shows text only; reuse
|
||||
cUI_Character's 3D hero?), list scrolling beyond 9 characters, larger
|
||||
heading font.
|
||||
Reference in new issue
Block a user