Arts with launch type 2 (buffs, auras, heals) are only valid on allies or without a target; with an enemy under the cursor the game dropped the order. Orders of a player hero for such arts lose a non-ally target, which casts them on the hero. The launch type comes from the art definition tables (game/engine/arts.h, tools/arttable.mjs). Also: skill keys check the relocated taskbar slots (all 7), Ghidra data labels (g_ names in names.txt). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
38 lines
1.6 KiB
JavaScript
38 lines
1.6 KiB
JavaScript
// Dump sacred.exe's combat-art definition tables (see docs/skill-slots.md).
|
|
// node tools/arttable.mjs <exe> [id...] (ids hex, e.g. 3f7; none: all)
|
|
import { readFileSync } from "node:fs";
|
|
|
|
const [exePath, ...ids] = process.argv.slice(2);
|
|
const file = readFileSync(exePath);
|
|
const pe = file.readUInt32LE(0x3c);
|
|
const sections = file.readUInt16LE(pe + 6);
|
|
const optional = file.readUInt16LE(pe + 20);
|
|
const imageBase = file.readUInt32LE(pe + 52);
|
|
const table = pe + 24 + optional;
|
|
function offset(va) {
|
|
for (let i = 0; i < sections; i++) {
|
|
const s = table + i * 40;
|
|
const vsize = file.readUInt32LE(s + 8), vaddr = file.readUInt32LE(s + 12);
|
|
const raw = file.readUInt32LE(s + 20), rawSize = file.readUInt32LE(s + 16);
|
|
const rva = va - imageBase;
|
|
if (rva >= vaddr && rva < vaddr + vsize) return rva - vaddr < rawSize ? rva - vaddr + raw : -1;
|
|
}
|
|
return -1;
|
|
}
|
|
const tables = [
|
|
{ name: "A", base: 0x94ddb0, stride: 0x78, end: 0x950a38 },
|
|
{ name: "B", base: 0x950a38, stride: 0x94, end: 0x953344 },
|
|
];
|
|
const wanted = new Set(ids.map((t) => parseInt(t, 16)));
|
|
for (const t of tables) {
|
|
for (let va = t.base; va < t.end; va += t.stride) {
|
|
const o = offset(va);
|
|
if (o < 0) { console.log(t.name, va.toString(16), "(no file data: filled at runtime)"); break; }
|
|
const id = file.readUInt16LE(o);
|
|
if (wanted.size && !wanted.has(id)) continue;
|
|
const words = [];
|
|
for (let k = 0; k < t.stride; k += 4) words.push(file.readUInt32LE(o + k).toString(16).padStart(8, "0"));
|
|
console.log(`${t.name} ${va.toString(16)} id ${id.toString(16)}: ${words.join(" ")}`);
|
|
}
|
|
}
|