more work done
This commit is contained in:
parent
5cc5612f4e
commit
d323bb28fc
68 changed files with 714 additions and 19 deletions
166
scripts/_tmp_parse_combat_dat.py
Normal file
166
scripts/_tmp_parse_combat_dat.py
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import struct
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
MAGIC_DATA_OFF = 33000
|
||||
|
||||
|
||||
OPCODE_NAMES = {
|
||||
0x81: "set_unused_field53",
|
||||
0x82: "clear_unused_field53",
|
||||
0x84: "set_target_objid",
|
||||
0x85: "anim_walk",
|
||||
0x86: "anim_run",
|
||||
0x87: "anim_retreat",
|
||||
0x88: "turn_left_90",
|
||||
0x89: "turn_right_90",
|
||||
0x8A: "fire_small_if_clear",
|
||||
0x8B: "fire_large_if_clear",
|
||||
0x8C: "anim_stand",
|
||||
0x8D: "pathfind_home",
|
||||
0x8E: "pathfind_target",
|
||||
0x8F: "pathfind_midpoint",
|
||||
0x92: "anim_kneel_and_fire",
|
||||
0x93: "sleep_scaled",
|
||||
0x94: "loiter",
|
||||
0x95: "face_target",
|
||||
0x96: "set_activity",
|
||||
0x97: "switch_tactic",
|
||||
0x98: "teleport_home",
|
||||
0x99: "terminate",
|
||||
0x9A: "jump_if_dist_lt_481",
|
||||
0x9B: "jump_if_dist_gt_160",
|
||||
0x9C: "jump_if_shot_blocked",
|
||||
0x9D: "jump_if_shot_clear",
|
||||
0x9E: "random_jump_nonzero",
|
||||
0x9F: "loop_begin",
|
||||
0xA6: "pathfind_marker_frame",
|
||||
0xA7: "face_north",
|
||||
0xA8: "face_south",
|
||||
0xA9: "face_east",
|
||||
0xAA: "face_west",
|
||||
0xAB: "face_northeast",
|
||||
0xAC: "face_southwest",
|
||||
0xAD: "face_southeast",
|
||||
0xAE: "face_northwest",
|
||||
0xAF: "var_set",
|
||||
0xB0: "var_add",
|
||||
0xB1: "var_sub",
|
||||
0xB2: "var_mul",
|
||||
0xB3: "var_div",
|
||||
0xB4: "var_store_curdir",
|
||||
0xB5: "set_dir_raw",
|
||||
0xB6: "var_store_curdir_again",
|
||||
0xB7: "anim_kneeling_retreat",
|
||||
0xB8: "anim_kneeling_advance",
|
||||
0xB9: "anim_kneeling_slow_retreat",
|
||||
0xC0: "jump",
|
||||
0xC1: "loop_end",
|
||||
0xFF: "flip_to_block1_restart",
|
||||
}
|
||||
|
||||
|
||||
def format_word(value: int) -> str:
|
||||
if value >= MAGIC_DATA_OFF:
|
||||
return f"var[{value - MAGIC_DATA_OFF}]"
|
||||
return f"0x{value:04x} ({value})"
|
||||
|
||||
|
||||
def decode_block(block: bytes, start_offset: int) -> list[str]:
|
||||
pc = 0
|
||||
lines: list[str] = []
|
||||
|
||||
def need_word(use_data: bool) -> int:
|
||||
nonlocal pc
|
||||
value = struct.unpack_from("<H", block, pc)[0]
|
||||
pc += 2
|
||||
return value
|
||||
|
||||
while pc < len(block):
|
||||
opcode_offset = start_offset + pc
|
||||
opcode = block[pc]
|
||||
pc += 1
|
||||
opname = OPCODE_NAMES.get(opcode, f"opcode_{opcode:02x}")
|
||||
operands: list[str] = []
|
||||
|
||||
if opcode in {0x81, 0x84, 0x93, 0x94, 0x96, 0x97, 0x9A, 0x9B, 0x9C, 0x9D, 0xB5, 0xC0, 0x9F}:
|
||||
operands.append(format_word(need_word(True)))
|
||||
elif opcode == 0x9E:
|
||||
operands.append(format_word(need_word(True)))
|
||||
operands.append(format_word(need_word(True)))
|
||||
elif opcode == 0xA6:
|
||||
operands.append(f"frame={format_word(need_word(True))}")
|
||||
elif opcode in {0xAF}:
|
||||
operands.append(format_word(need_word(True)))
|
||||
operands.append(format_word(need_word(False)))
|
||||
elif opcode in {0xB0, 0xB1, 0xB2, 0xB3}:
|
||||
operands.append(format_word(need_word(False)))
|
||||
operands.append(format_word(need_word(True)))
|
||||
elif opcode in {0xB4, 0xB6}:
|
||||
operands.append(format_word(need_word(False)))
|
||||
|
||||
text = opname
|
||||
if operands:
|
||||
text += " " + ", ".join(operands)
|
||||
lines.append(f"0x{opcode_offset:04x}: {text}")
|
||||
|
||||
return lines
|
||||
|
||||
|
||||
def read_u32(data: bytes, offset: int) -> int:
|
||||
return struct.unpack_from("<I", data, offset)[0]
|
||||
|
||||
|
||||
def read_u16(data: bytes, offset: int) -> int:
|
||||
return struct.unpack_from("<H", data, offset)[0]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
path = Path("STATIC/COMBAT.DAT")
|
||||
data = path.read_bytes()
|
||||
|
||||
print(f"file={path} size={len(data)}")
|
||||
print(f"header_magic_fill={data[:0x56].hex()[:32]}...")
|
||||
|
||||
entries = []
|
||||
for index in range(64):
|
||||
off = 0x80 + index * 8
|
||||
rec_off = read_u32(data, off)
|
||||
rec_len = read_u32(data, off + 4)
|
||||
if rec_off == 0 and rec_len == 0:
|
||||
continue
|
||||
entries.append((index, rec_off, rec_len))
|
||||
|
||||
print(f"entry_count={len(entries)}")
|
||||
for index, rec_off, rec_len in entries:
|
||||
rec = data[rec_off:rec_off + rec_len]
|
||||
name = rec[:16].split(b"\0", 1)[0].decode("ascii")
|
||||
block_offsets = [read_u16(rec, 16 + i * 2) for i in range(4)]
|
||||
valid_blocks = [value for value in block_offsets if value and value < rec_len]
|
||||
print(
|
||||
f"[{index:02d}] off=0x{rec_off:04x} len=0x{rec_len:04x}"
|
||||
f" name={name:<16} block_offsets={block_offsets}"
|
||||
f" body_len={rec_len - min(valid_blocks) if valid_blocks else 0}"
|
||||
)
|
||||
|
||||
for block_no, block_off in enumerate(block_offsets[:2]):
|
||||
if not block_off or block_off >= rec_len:
|
||||
continue
|
||||
next_offsets = sorted(value for value in block_offsets[:2] if value > block_off and value < rec_len)
|
||||
block_end = next_offsets[0] if next_offsets else rec_len
|
||||
block = rec[block_off:block_end]
|
||||
print(
|
||||
f" block{block_no}: start=0x{block_off:04x} end=0x{block_end:04x}"
|
||||
f" size={block_end - block_off:02d} bytes={block.hex(' ')}"
|
||||
)
|
||||
for line in decode_block(block, block_off):
|
||||
print(f" {line}")
|
||||
|
||||
trailing_offsets = block_offsets[2:]
|
||||
print(f" extra_offsets_unused={trailing_offsets}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue