- Volition VPP: Unified BE/LE types using inheritance pattern - THQA PAK: Child types now inherit byte order from parent - Various XScript definition updates and fixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
163 lines
6.2 KiB
Plaintext
163 lines
6.2 KiB
Plaintext
// Asura Engine archive format
|
|
// Used by Rebellion games: Sniper Elite series, AVP 2010, etc.
|
|
// Archives contain chunks like FCSR (resources), TSXT (textures), LFSR (lists), etc.
|
|
|
|
type asura_archive ui("Asura Archive") byteorder BE
|
|
{
|
|
criteria {
|
|
// Match "Asura " signature (8 bytes with trailing spaces)
|
|
require ascii(bytesat(0, 8)) == "Asura ";
|
|
}
|
|
|
|
// Store base name for chunk naming (use full filename, not basename)
|
|
base_name = _name;
|
|
|
|
// Set display name for this archive
|
|
set_name(base_name + ".asr");
|
|
|
|
// Asura signature
|
|
signature = ascii(read(8)) ui("Signature");
|
|
|
|
// Track chunk indices (separate counter per type for naming)
|
|
chunk_index = 0;
|
|
ctx_set("_fcsr_idx", 0);
|
|
ctx_set("_tsxt_idx", 0);
|
|
ctx_set("_lfsr_idx", 0);
|
|
ctx_set("_stsa_idx", 0);
|
|
ctx_set("_txet_idx", 0);
|
|
ctx_set("_gsms_idx", 0);
|
|
ctx_set("_itne_idx", 0);
|
|
ctx_set("_stuc_idx", 0);
|
|
ctx_set("_catc_idx", 0);
|
|
ctx_set("_rttc_idx", 0);
|
|
ctx_set("_vetc_idx", 0);
|
|
ctx_set("_pose_idx", 0);
|
|
ctx_set("_pvet_idx", 0);
|
|
ctx_set("_tatc_idx", 0);
|
|
ctx_set("_ttat_idx", 0);
|
|
ctx_set("_tvet_idx", 0);
|
|
ctx_set("_ucat_idx", 0);
|
|
ctx_set("_uvet_idx", 0);
|
|
ctx_set("_unk_idx", 0);
|
|
|
|
// Parse chunks until end of file (need at least 16 bytes for header)
|
|
while (pos() + 16 <= size()) {
|
|
// Save chunk start position
|
|
chunk_start = pos();
|
|
|
|
// Peek at chunk header to get ID and size
|
|
peek_id = ascii(read(4));
|
|
u32 peek_size;
|
|
|
|
// Seek back to chunk start for proper parsing
|
|
seek(chunk_start);
|
|
|
|
// Validate chunk - if peek_size is 0 or invalid, stop parsing
|
|
if (peek_size == 0 || peek_size > size() - chunk_start) {
|
|
remaining = size() - pos();
|
|
if (remaining > 0) {
|
|
raw_tail = read(remaining) ui("Raw Tail Data");
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Set chunk name before parsing (child will inherit this)
|
|
set_name(base_name + ".chunk" + chunk_index);
|
|
|
|
// Dispatch to appropriate chunk type based on ID and push to arrays
|
|
// Note: increment index AFTER parse so chunk can read current value
|
|
if (peek_id == "FCSR" || peek_id == "RSCF") {
|
|
chunk = parse_here("fcsr_chunk");
|
|
push("fcsr_chunks", chunk);
|
|
ctx_set("_fcsr_idx", ctx_get("_fcsr_idx") + 1);
|
|
} else if (peek_id == "TSXT" || peek_id == "TXST") {
|
|
chunk = parse_here("tsxt_chunk");
|
|
push("tsxt_chunks", chunk);
|
|
ctx_set("_tsxt_idx", ctx_get("_tsxt_idx") + 1);
|
|
} else if (peek_id == "LFSR" || peek_id == "RSFL") {
|
|
chunk = parse_here("lfsr_chunk");
|
|
push("lfsr_chunks", chunk);
|
|
ctx_set("_lfsr_idx", ctx_get("_lfsr_idx") + 1);
|
|
} else if (peek_id == "STSA" || peek_id == "ASTS") {
|
|
chunk = parse_here("stsa_chunk");
|
|
push("stsa_chunks", chunk);
|
|
ctx_set("_stsa_idx", ctx_get("_stsa_idx") + 1);
|
|
} else if (peek_id == "TXET" || peek_id == "TEXT") {
|
|
chunk = parse_here("txet_chunk");
|
|
push("txet_chunks", chunk);
|
|
ctx_set("_txet_idx", ctx_get("_txet_idx") + 1);
|
|
} else if (peek_id == "GSMS" || peek_id == "SMSG") {
|
|
chunk = parse_here("gsms_chunk");
|
|
push("gsms_chunks", chunk);
|
|
ctx_set("_gsms_idx", ctx_get("_gsms_idx") + 1);
|
|
} else if (peek_id == "ITNE" || peek_id == "ENTI") {
|
|
chunk = parse_here("itne_chunk");
|
|
push("itne_chunks", chunk);
|
|
ctx_set("_itne_idx", ctx_get("_itne_idx") + 1);
|
|
} else if (peek_id == "STUC" || peek_id == "CUTS") {
|
|
chunk = parse_here("stuc_chunk");
|
|
push("stuc_chunks", chunk);
|
|
ctx_set("_stuc_idx", ctx_get("_stuc_idx") + 1);
|
|
} else if (peek_id == "CATC") {
|
|
chunk = parse_here("catc_chunk");
|
|
push("catc_chunks", chunk);
|
|
ctx_set("_catc_idx", ctx_get("_catc_idx") + 1);
|
|
} else if (peek_id == "RTTC") {
|
|
chunk = parse_here("rttc_chunk");
|
|
push("rttc_chunks", chunk);
|
|
ctx_set("_rttc_idx", ctx_get("_rttc_idx") + 1);
|
|
} else if (peek_id == "VETC") {
|
|
chunk = parse_here("vetc_chunk");
|
|
push("vetc_chunks", chunk);
|
|
ctx_set("_vetc_idx", ctx_get("_vetc_idx") + 1);
|
|
} else if (peek_id == "POSE") {
|
|
chunk = parse_here("pose_chunk");
|
|
push("pose_chunks", chunk);
|
|
ctx_set("_pose_idx", ctx_get("_pose_idx") + 1);
|
|
} else if (peek_id == "PVET") {
|
|
chunk = parse_here("pvet_chunk");
|
|
push("pvet_chunks", chunk);
|
|
ctx_set("_pvet_idx", ctx_get("_pvet_idx") + 1);
|
|
} else if (peek_id == "TATC") {
|
|
chunk = parse_here("tatc_chunk");
|
|
push("tatc_chunks", chunk);
|
|
ctx_set("_tatc_idx", ctx_get("_tatc_idx") + 1);
|
|
} else if (peek_id == "TTAT") {
|
|
chunk = parse_here("ttat_chunk");
|
|
push("ttat_chunks", chunk);
|
|
ctx_set("_ttat_idx", ctx_get("_ttat_idx") + 1);
|
|
} else if (peek_id == "TVET") {
|
|
chunk = parse_here("tvet_chunk");
|
|
push("tvet_chunks", chunk);
|
|
ctx_set("_tvet_idx", ctx_get("_tvet_idx") + 1);
|
|
} else if (peek_id == "UCAT") {
|
|
chunk = parse_here("ucat_chunk");
|
|
push("ucat_chunks", chunk);
|
|
ctx_set("_ucat_idx", ctx_get("_ucat_idx") + 1);
|
|
} else if (peek_id == "UVET") {
|
|
chunk = parse_here("uvet_chunk");
|
|
push("uvet_chunks", chunk);
|
|
ctx_set("_uvet_idx", ctx_get("_uvet_idx") + 1);
|
|
} else {
|
|
// Unknown chunk type - parse as generic chunk
|
|
chunk = parse_here("asura_chunk");
|
|
push("unknown_chunks", chunk);
|
|
ctx_set("_unk_idx", ctx_get("_unk_idx") + 1);
|
|
}
|
|
|
|
// Increment chunk index
|
|
chunk_index = chunk_index + 1;
|
|
|
|
// Seek to next chunk (chunk_start + peek_size)
|
|
next_chunk = chunk_start + peek_size;
|
|
if (next_chunk > size()) {
|
|
break;
|
|
}
|
|
seek(next_chunk);
|
|
}
|
|
|
|
// Restore archive name and show total count
|
|
set_name(base_name + ".asr");
|
|
chunk_count = chunk_index ui("Total Chunks");
|
|
}
|