Widescreen: keep original size, extend view horizontally; fix player/camera

- Default render size is 768 high and as wide as the monitor aspect
  (1835x768 on 3440x1440), scaled up: everything keeps the size players
  know and the view only grows sideways. Height=0 keeps native 1:1.
- Ground: 818/888 clip limits, screen centre floats and integer
  immediates, ground quad list (capped at 1749) moved with the tile list.
- 3D: cGranny ortho (+-512 x +-384, incl. HUD items) scaled; inverse
  projection 0x623a20 (1/1024, 1/768) follows the render size, which fixes
  the camera following the player ("outside world") and the missing
  player / ESC menu.
- tools: game-input.ps1 + autotest-load.ps1 drive the game (load the first
  save game, screenshots in-game and with the ESC menu).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
khallaandClaude Opus 5.5 committed 2026-10-14 01:48:08 +02:00
1 parent 795fe8f087
commit df31c9c105
6 files changed
+324 -45

No files matched your search

+15
View File
@@ -23,3 +23,18 @@ $env:GHIDRA_HEADLESS_MAXMEM = "8G"
`ApplyRtti.java` recovers the MSVC 6 RTTI that Ghidra's own script misses:
410 vtables, ~1200 extra functions, methods named `Class::vfNN`.
## Automated in-game test
`autotest-load.ps1` starts the game through the launcher, clicks
"Spiel laden" -> "Laden" -> "Ok" (first save game), takes screenshots in-game
and with the ESC menu open, and stops the game. `-Ini` appends temporary
settings to `build\x86-debug\sacred_re.ini` (restored afterwards), e.g.
```powershell
.\tools\autotest-load.ps1 -Name ws_off -Ini "[widescreen]`r`nEnabled=0"
```
Click positions assume the classic menu layout scaled onto a 3440x1440
monitor. `game-input.ps1` has the building blocks (start, click, key,
screenshot). Don't touch mouse/keyboard while a test runs.
+36
View File
@@ -0,0 +1,36 @@
# Automated smoke test: start the game, load the first save game, take
# screenshots in-game and with the ESC menu open, then stop the game.
#
# .\tools\autotest-load.ps1 -Name ws_on # current sacred_re.ini
# .\tools\autotest-load.ps1 -Name ws_off -Ini "[widescreen]`r`nEnabled=0"
#
# -Ini temporarily appends settings to build\x86-debug\sacred_re.ini.
# Click positions are for the classic (menu) layout scaled onto a 3440x1440
# monitor; adjust for other monitors. Don't touch mouse/keyboard while it runs.
param(
[string]$Name = "autotest",
[string]$Ini = "",
[int]$LoadSeconds = 30
)
$ErrorActionPreference = "Stop"
. (Join-Path $PSScriptRoot "game-input.ps1")
$root = Split-Path $PSScriptRoot
$iniPath = Join-Path $root "build\x86-debug\sacred_re.ini"
$iniBackup = if (Test-Path $iniPath) { Get-Content $iniPath -Raw } else { "" }
if ($Ini) { Set-Content $iniPath ($iniBackup + "`r`n" + $Ini + "`r`n") -Encoding ASCII }
$game = $null
try {
$game = Start-Sacred
Click-At 1720 779 -AfterMs 4000 # main menu: "Spiel laden"
Click-At 2382 568 -AfterMs 2000 # load screen: "Laden" (first save selected)
Click-At 1551 826 -AfterMs ($LoadSeconds * 1000) # confirm: "Ok"
Save-Screen "screenshots\${Name}_ingame.png" | Out-Null
Press-Key 0x1B -AfterMs 2500 # ESC menu
Save-Screen "screenshots\${Name}_esc.png" | Out-Null
"game alive at end: $(-not $game.HasExited)"
} finally {
Stop-Sacred $game
if ($Ini) { Set-Content $iniPath $iniBackup -Encoding ASCII -NoNewline }
}
+63
View File
@@ -0,0 +1,63 @@
# Drive the game for automated tests: start it, click, press keys, take
# screenshots. Dot-source it: . .\tools\game-input.ps1
#
# Start-Sacred # launcher, returns the sacred.exe process
# Click-At 1720 779 # screen pixels (left click)
# Press-Key 0x1B # virtual key (ESC)
# Save-Screen screenshots\x.png # primary monitor area of the game
# Stop-Sacred $game # only the given process
#
# Input goes to the foreground window: don't touch mouse/keyboard meanwhile.
Add-Type -AssemblyName System.Drawing
Add-Type -Namespace SacredRe -Name Input -MemberDefinition @'
[DllImport("user32.dll")] public static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll")] public static extern void mouse_event(uint flags, uint dx, uint dy, uint data, System.UIntPtr extra);
[DllImport("user32.dll")] public static extern void keybd_event(byte vk, byte scan, uint flags, System.UIntPtr extra);
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(System.IntPtr window);
'@
$script:Root = Split-Path $PSScriptRoot
function Start-Sacred([string]$Arguments = "log", [int]$WaitSeconds = 18) {
if (Get-Process sacred -ErrorAction SilentlyContinue) { throw "sacred.exe is already running" }
$null = Start-Process (Join-Path $script:Root "build\x86-debug\sacred_re.exe") -ArgumentList $Arguments
Start-Sleep $WaitSeconds
$game = Get-Process sacred -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $game) { throw "sacred.exe did not start (or crashed)" }
[SacredRe.Input]::SetForegroundWindow($game.MainWindowHandle) | Out-Null
$game
}
function Stop-Sacred($Game) {
if ($Game -and -not $Game.HasExited) {
Stop-Process -Id $Game.Id -Force
$Game.WaitForExit(10000) | Out-Null
}
}
function Click-At([int]$X, [int]$Y, [int]$AfterMs = 800) {
[SacredRe.Input]::SetCursorPos($X, $Y) | Out-Null
Start-Sleep -Milliseconds 150
[SacredRe.Input]::mouse_event(0x0002, 0, 0, 0, [UIntPtr]::Zero) # left down
Start-Sleep -Milliseconds 80
[SacredRe.Input]::mouse_event(0x0004, 0, 0, 0, [UIntPtr]::Zero) # left up
Start-Sleep -Milliseconds $AfterMs
}
function Press-Key([byte]$VirtualKey, [int]$AfterMs = 800) {
[SacredRe.Input]::keybd_event($VirtualKey, 0, 0, [UIntPtr]::Zero)
Start-Sleep -Milliseconds 80
[SacredRe.Input]::keybd_event($VirtualKey, 0, 2, [UIntPtr]::Zero) # key up
Start-Sleep -Milliseconds $AfterMs
}
function Save-Screen([string]$Path, [int]$Width = 3440, [int]$Height = 1440) {
$bitmap = New-Object System.Drawing.Bitmap $Width, $Height
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
$graphics.CopyFromScreen(0, 0, 0, 0, $bitmap.Size)
$full = if ([IO.Path]::IsPathRooted($Path)) { $Path } else { Join-Path $script:Root $Path }
$bitmap.Save($full)
$graphics.Dispose(); $bitmap.Dispose()
$full
}