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:
1 parent
5df7efc198
commit
5bccb0734e
16 files changed
+2052
-64
No files matched your search
@@ -256,3 +256,41 @@ SHORT WINAPI GetAsyncKeyStateWhenFocused(int key) {
|
||||
}
|
||||
return GetAsyncKeyStateWhenFocused_original(key);
|
||||
}
|
||||
|
||||
// The game's "bring the window to the front" (0x810af0, thiscall (window,
|
||||
// timeout ms), ret 8; WinMain calls it three times): ShowWindow, then
|
||||
// SetForegroundWindow until the window is in front and SetFocus until it has
|
||||
// the focus. WinMain passes 0xffffffff, which never times out. Windows refuses
|
||||
// the foreground to a process when the user clicked or typed elsewhere while
|
||||
// it started, so the game hung at startup (2026-10-20, four times; main
|
||||
// thread in this loop, log ending at WM_ACTIVATEAPP(1, 0)). Now it asks for a
|
||||
// limited time, with the input of the window in front attached (which Windows
|
||||
// allows), and carries on in the background otherwise; a click brings it up.
|
||||
constexpr DWORD kForegroundWaitMs = 2000;
|
||||
|
||||
bool __fastcall BringWindowToFront(void* self, void* edx, HWND window, DWORD timeout);
|
||||
RE_HOOK(0x00810af0, BringWindowToFront);
|
||||
bool __fastcall BringWindowToFront(void*, void*, HWND window, DWORD timeout) {
|
||||
ShowWindow(window, SW_SHOW);
|
||||
const DWORD wait = std::min(timeout, kForegroundWaitMs);
|
||||
const DWORD start = GetTickCount();
|
||||
while (GetForegroundWindow() != window && GetTickCount() - start < wait) {
|
||||
const DWORD front = GetWindowThreadProcessId(GetForegroundWindow(), nullptr);
|
||||
const DWORD self = GetCurrentThreadId();
|
||||
const bool attached = front && front != self && AttachThreadInput(front, self, TRUE);
|
||||
BringWindowToTop(window);
|
||||
SetForegroundWindow(window);
|
||||
if (attached) {
|
||||
AttachThreadInput(front, self, FALSE);
|
||||
}
|
||||
Sleep(10);
|
||||
}
|
||||
const bool inFront = GetForegroundWindow() == window;
|
||||
if (inFront) {
|
||||
SetFocus(window);
|
||||
} else {
|
||||
re::Log("borderless: the game window did not get to the front, starting in the background");
|
||||
}
|
||||
UpdateWindow(window);
|
||||
return inFront;
|
||||
}
|
||||
Reference in new issue
Block a user