- Introduced new file `vm_mask_ladder.tsv` containing detailed mappings for Crusader USECODE VM masks and their associated descriptors. - Added comprehensive documentation in `scummvm-crusader-reference.md` outlining the structure, findings, and implications for reverse-engineering the Crusader engine within ScummVM. - Created `usecode-roundtrip-ir.md` to document the plan for converting Crusader USECODE bytes into a human-readable format, detailing the container layout, event names, and intrinsic tables. - Implemented a PowerShell script `temp_usecode_sample.ps1` for extracting and analyzing USECODE data from the Crusader FLX files, providing insights into class and event structures.
68 lines
2.7 KiB
PowerShell
68 lines
2.7 KiB
PowerShell
$base = 'K:\ghidra\Crusader_Decomp'
|
|
$flxPath = Join-Path $base 'USECODE\EUSECODE.FLX'
|
|
$tsvPath = Join-Path $base 'USECODE\EUSECODE_extracted\entry_index.tsv'
|
|
$flx = [System.IO.File]::ReadAllBytes($flxPath)
|
|
$rows = Import-Csv $tsvPath -Delimiter "`t"
|
|
$labels = @(
|
|
'EVENT','NPCTRIG','SURCAMNS','JELYHACK','REE_BOOT','SURCAMEW','SFXTRIG',
|
|
'AND_BOOT','BRO_BOOT','COR_BOOT','VAR_BOOT','FLAMEBOX','NOSTRIL','STEAMBOX'
|
|
)
|
|
|
|
function Hex([byte[]]$bytes) {
|
|
(($bytes | ForEach-Object { $_.ToString('X2') }) -join ' ')
|
|
}
|
|
|
|
$nameRow = $rows | Where-Object { $_.entry_index -eq '0' } | Select-Object -First 1
|
|
$nameOff = [Convert]::ToInt32(($nameRow.data_offset -replace '^0x',''), 16)
|
|
$nameSize = [Convert]::ToInt32(($nameRow.extracted_size -replace '^0x',''), 16)
|
|
|
|
'label,objidx,classid,u32_8_11,scummvm_base,scummvm_count,boundary_count,name_lookup,first24'
|
|
foreach ($label in $labels) {
|
|
$row = $rows | Where-Object { $_.primary_label -eq $label } | Select-Object -First 1
|
|
if (-not $row) { continue }
|
|
|
|
$table = [Convert]::ToInt32(($row.table_offset -replace '^0x',''), 16)
|
|
$data = [Convert]::ToInt32(($row.data_offset -replace '^0x',''), 16)
|
|
$size = [Convert]::ToInt32(($row.extracted_size -replace '^0x',''), 16)
|
|
$objidx = ($table - 0x80) / 8
|
|
$classid = $objidx - 2
|
|
$chunk = $flx[$data..($data + $size - 1)]
|
|
$u32 = [BitConverter]::ToUInt32($chunk, 8)
|
|
$baseOff = $u32 - 1
|
|
$scCount = [math]::Floor(($baseOff + 19) / 6)
|
|
if ((($u32 - 20) % 6) -eq 0) {
|
|
$boundaryCount = [int](($u32 - 20) / 6)
|
|
} else {
|
|
$boundaryCount = -1
|
|
}
|
|
|
|
$namePos = $nameOff + 4 + (13 * $classid)
|
|
$nameBytes = [System.Collections.Generic.List[byte]]::new()
|
|
for ($i = $namePos; $i -lt [Math]::Min($namePos + 13, $nameOff + $nameSize); $i++) {
|
|
$byte = $flx[$i]
|
|
if ($byte -eq 0) { break }
|
|
[void]$nameBytes.Add($byte)
|
|
}
|
|
$lookup = [System.Text.Encoding]::ASCII.GetString($nameBytes.ToArray())
|
|
$first24 = Hex $chunk[0..23]
|
|
"$label,$objidx,$classid,0x$('{0:X8}' -f $u32),0x$('{0:X8}' -f $baseOff),$scCount,$boundaryCount,$lookup,$first24"
|
|
}
|
|
|
|
''
|
|
'first20_groups'
|
|
$groupMap = @{}
|
|
foreach ($label in $labels) {
|
|
$row = $rows | Where-Object { $_.primary_label -eq $label } | Select-Object -First 1
|
|
if (-not $row) { continue }
|
|
$data = [Convert]::ToInt32(($row.data_offset -replace '^0x',''), 16)
|
|
$size = [Convert]::ToInt32(($row.extracted_size -replace '^0x',''), 16)
|
|
$chunk = $flx[$data..($data + $size - 1)]
|
|
$key = Hex $chunk[0..19]
|
|
if (-not $groupMap.ContainsKey($key)) {
|
|
$groupMap[$key] = [System.Collections.Generic.List[string]]::new()
|
|
}
|
|
[void]$groupMap[$key].Add($label)
|
|
}
|
|
foreach ($key in $groupMap.Keys) {
|
|
(($groupMap[$key] -join '|') + ' => ' + $key)
|
|
}
|