The 0xBBE heat-sink BANK was built as a plain HeatSink, so the numeric-R cockpit gauge binding HeatSink/AmbientTemperature (L4GAUGE.CFG:4552) had no publisher -> the LAST unresolved config attribute. Reconstruct AggregateHeatSink : HeatSink (ctor @4ae8d0, own GUID 0x50e590), byte-exact + static_assert-locked (heatSinkCount@0x1D0, ambientTemperature @0x1D4=300, helper@0x1D8 0xC link node, sizeof 0x1E4 == factory alloc @9993). Publish HeatSinkCount + AmbientTemperature via a dense-prefix attribute table chained to HeatSink::NextAttributeID (shared HeatSink table unchanged, so CoolantMass/CoolantCapacity keep resolving). Move CreateHeatSinkBankSubsystem into heatfamily_reslice.cpp (needs the class def) and build the real class at factory case 0xBBE; mech.cpp unchanged. DELIBERATE DEVIATION (documented in the class): keep the base HeatSinkSimulation the HeatSink ctor installs; do NOT reimplement the authentic Performance @4ae73c -- it derefs a raw self+0xE0 -> [+0x158] that does not map in our compiled layout (AV/NaN, and runs for EVERY mech), and ambientTemperature is a frozen constant so the gauge reads 300 either way. Authentic relaxation model deferred. Verified: [attr] HeatSink/AmbientTemperature OK; all 50 config attribute bindings resolve (0 NULL); no every-mech crash; combat TARGET DESTROYED, FIRED #41+, un-regressed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
54 lines
2.4 KiB
PowerShell
54 lines
2.4 KiB
PowerShell
# Capture a window (by title substring) or the full virtual screen to a PNG.
|
|
# Usage: powershell -File shot.ps1 <out.png> [titleSubstring]
|
|
param([string]$Out = "shot.png", [string]$Title = "")
|
|
Add-Type -AssemblyName System.Windows.Forms, System.Drawing
|
|
Add-Type @"
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
public class W {
|
|
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out R r);
|
|
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
|
|
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);
|
|
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
|
|
[DllImport("user32.dll")] public static extern int GetWindowText(IntPtr h, System.Text.StringBuilder s, int n);
|
|
[DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr p);
|
|
public delegate bool EnumProc(IntPtr h, IntPtr p);
|
|
public struct R { public int L, T, Rr, B; }
|
|
}
|
|
"@
|
|
function Cap($rect, $path) {
|
|
$w = $rect.Rr - $rect.L; $h = $rect.B - $rect.T
|
|
if ($w -le 0 -or $h -le 0) { return $false }
|
|
$bmp = New-Object System.Drawing.Bitmap $w, $h
|
|
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
|
$g.CopyFromScreen($rect.L, $rect.T, 0, 0, (New-Object System.Drawing.Size($w, $h)))
|
|
$bmp.Save($path, [System.Drawing.Imaging.ImageFormat]::Png)
|
|
$g.Dispose(); $bmp.Dispose(); return $true
|
|
}
|
|
if ($Title -ne "") {
|
|
$found = @()
|
|
$cb = [W+EnumProc]{ param($h,$p)
|
|
if ([W]::IsWindowVisible($h)) {
|
|
$sb = New-Object System.Text.StringBuilder 256
|
|
[void][W]::GetWindowText($h, $sb, 256)
|
|
$t = $sb.ToString()
|
|
if ($t -like "*$Title*") { $script:found += @{H=$h; T=$t} }
|
|
}
|
|
return $true
|
|
}
|
|
[void][W]::EnumWindows($cb, [IntPtr]::Zero)
|
|
Write-Host "Matched windows:"; $found | ForEach-Object { Write-Host " '$($_.T)'" }
|
|
$i = 0
|
|
foreach ($f in $found) {
|
|
$r = New-Object W+R; [void][W]::GetWindowRect($f.H, [ref]$r)
|
|
[void][W]::SetForegroundWindow($f.H); Start-Sleep -Milliseconds 250
|
|
$p = $Out -replace '\.png$', "_$i.png"
|
|
if (Cap $r $p) { Write-Host "saved $p ($($r.Rr-$r.L)x$($r.B-$r.T)) '$($f.T)'" }
|
|
$i++
|
|
}
|
|
} else {
|
|
$vs = [System.Windows.Forms.SystemInformation]::VirtualScreen
|
|
$r = New-Object W+R; $r.L=$vs.Left; $r.T=$vs.Top; $r.Rr=$vs.Right; $r.B=$vs.Bottom
|
|
[void](Cap $r $Out); Write-Host "saved $Out (full screen $($vs.Width)x$($vs.Height))"
|
|
}
|