Export screen: widescreen frame, black sides, slots can be cleared

- cUI_Character (export) and cUI_Savegame draw inside the centred 1024x768
  frame (viewport) with the render target beside it cleared black; the
  export screen's 3D heroes were stretched across the wide viewport, away
  from their labels and hit areas.
- Export screen shows the game's erase button for an occupied slot and
  reloads the heroes after a delete. Overwriting was already the game's
  own path once clicks hit the right slot.
- game/ui/control.h: shared show/hide for cUI_Control2.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
khallaandClaude Opus 5.5 committed 2026-10-18 23:26:53 +02:00
1 parent c875d7d6b9
commit 72525cd5ba
9 files changed
+272 -13

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
# Character export screen (`src/mods/charexport.cpp`)
Request (2026-10-18): the export screen (Esc menu "Exportieren") was not
adapted to widescreen (layout and clicks shifted), slots could not be
cleared or overwritten; the screen and the save game window need black
beside the background picture.
## Layout
See `hud.md`, "Full-screen windows": the 3D scene was stretched across the
wide viewport; the window now draws with a viewport on the centred frame.
## cUI_Character
One window for the main menu's character selection / import and the export
screen (vtable 0x894fa8, render vf44 0x70f160, events vf10 0x70e860).
| Field | Meaning |
|---|---|
| +0x390 | mode: 4 selection, 5 export, 6 overwrite confirmation (7 import) |
| +0x394 | previous mode |
| +0x1b4 | 8 slot controls; hero id at +0x2f8 (0: empty) |
| +0x1d6 | selected slot (char, -1 none) |
| +0x3b4 | erase button ("UI_CHAR_ERASE_TOOLTIP") |
| Address | Function |
|---|---|
| 0x70c760 | SetMode (mode), ret 4; entering mode 5 reloads the heroes |
| 0x70c440 | SelectSlot (char slot), ret 4; shows the erase button in modes 4 / 7 only |
| 0x70d0f0 | ExecuteAction (action, slot, extra), ret 0xc: 6 export into slot (`Save\Hero%.2d.pax`), 9 export with confirmation if occupied |
| 0x70e650 | right-hand button: in mode 5 action 6 (empty slot) or 9 (occupied) |
| 0x7f01a0 | HeroSlots_DeleteHero (slot + 1), thiscall on 0x7d7c40(), ret 4 |
## Overwrite
Measured with a log: exporting to an occupied slot was already the game's own
path (action 9 -> mode 6 confirmation -> action 6). It only failed because
clicks hit the wrong place before the layout fix.
## Clear
The erase button is created for every mode, and its click handler (vf10)
does not check the mode: it opens the game's confirmation
(UI_CHAR_ERASE_CONFIRM, cUI_BusyDlg), whose answer (0x72087b) calls
DeleteHero. The mod shows the button in export mode whenever an occupied slot
is selected (after SetMode / SelectSlot). After DeleteHero, if the screen is
in export mode, it enters export mode again (reloads the heroes) and clears
the selection; otherwise the erased hero stayed until the next export.
+16
View File
@@ -126,3 +126,19 @@ offset, that reset reached past the render target, `SetViewport` failed and
the small viewport stayed set: the cursor (drawn after the UI) was only
visible inside it. A viewport at x 0 across the whole render width is now
passed unshifted.
## Full-screen windows: frame viewport and black sides (2026-10-18)
The character export screen (Esc menu "Exportieren", cUI_Character) and the
save game window (cUI_Savegame) cover the 1024 frame with a picture. Request:
black instead of the world beside it, and the export screen adapted to the
wide view. Measured on a screenshot: the export screen's 3D scene (heroes on
their stones) is projected for a 1024x768 viewport; across the widened one
it was stretched 1.8x wide, away from the slot labels and their hit areas.
Their render hooks (`HUD_RENDER_FRAMED`, `HUD_RENDER3_FRAMED`) run the window
inside `FrameScope`: while the window is visible, the render target left and
right of the centred frame is cleared black, then the viewport is set to the
frame (dx, 0, 1024x768) and restored afterwards. `Clear` clips to the
viewport, so the sides are cleared first. Both calls go to the unhooked
device methods (`IDirect3DDevice7` 10 Clear, 13 SetViewport, 15 GetViewport).