Characters: one file per character with a world per difficulty

- CharacterNN.sacredK holds the shared hero and one world per difficulty,
  plus an autosave file; the game works in save\characters\_work
- Load window: one row per character, a difficulty dialog on Laden
  (worlds, newer autosaves, "(neu)" starts a new game with the shared
  hero), Umbenennen, delete moves the character to characters\deleted
- The world keeps its own portals and hero position when the shared hero
  is put on
- K and the Esc menu's "Speichern" save directly (quicksave path)
- One-time migration of the old save rows and exported heroes, after a
  backup
- Startup no longer hangs in the game's foreground loop (0x810af0)
- Text overrides apply to our own text ids too; shared cUI_Button2
  helpers in game/ui/button.h

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 01:41:42 +02:00
1 parent 5df7efc198
commit 5bccb0734e
16 files changed
+2052 -64

No files matched your search

+3 -20
View File
@@ -26,7 +26,7 @@
// AllyPotion=None ; kind 1 on the weakest ally (the game's own potion keys
// ; Space/B/Q/W/E/R are switched off)
// PickUp=Q ; what A did (pick up items nearby; Q's own action slot is given up)
// SaveGame=K ; what S did (save game window)
// SaveGame=K ; save the game at once (S opened the save window)
// Map=M ; open / close the map (the game's M is switched off)
// OverviewMap=Tab ; the overview map while held (the game's Tab is switched off)
// Labels=Alt ; names of items and creatures while held (the game's Alt is switched off)
@@ -45,6 +45,7 @@
#include "game/engine/items.h"
#include "game/engine/orders.h"
#include "game/ui/windows.h"
#include "mods/characters.h"
#include "mods/skillbar.h"
#include "mods/skillkeys.h"
#include "re/config.h"
@@ -252,24 +253,6 @@ void OnTick(uint8_t* engine) {
}
}
// The save game window, as the UI manager's S hotkey opens it (0x757775):
// only with the window built (manager slot 0x2b) and no blocking window open;
// it posts an engine event (code 0x13, 5, 1; with 0 for the kernel's second
// argument) and shows UI_WND_SAVEGAME.
constexpr int kSaveGameSlot = 0x2b;
constexpr uint32_t kEngineEventVtable = 0x0088eb38;
constexpr uint32_t kEngineEventSaveGame = 0x13;
void OpenSaveGame() {
uint32_t* ui = game::UiManager();
if (!ui || !ui[kSaveGameSlot] || !game::UiCanOpenWindow(ui)) {
return;
}
uint32_t event[9] = {kEngineEventVtable, kEngineEventSaveGame, 5, 1};
game::PostEvent(event, 0);
game::SendWindowCommand(ui, "UI_WND_SAVEGAME", game::WindowCommand::Show);
}
// The map (cUI_Megamap, manager slot 0x25), as the UI manager's M hotkey
// toggles it (cUI_Manager::ReceiveEvent 0x757120): open, M closes it; else
// nothing while one of the windows it checks first is open (slots 0x2b save
@@ -376,7 +359,7 @@ void Press(const Binding& binding, int vk) {
mods::skillbar::SelectWeaponSet(slot);
break;
case Kind::SaveGame:
OpenSaveGame();
characters::RequestSave(); // at once, no save window
break;
case Kind::PickUp:
g_pickUp = true;