Add XScript definition files

This commit is contained in:
njohnson 2026-01-01 22:18:40 -05:00
parent 594774c8e8
commit 154fde9666
37 changed files with 798 additions and 0 deletions

View File

@ -0,0 +1,54 @@
type assetheader
{
u32 raw_type [ui, readonly, display="Raw Type"];
u32 asset_ptr [ui, readonly, display="Asset Ptr"];
// Lookup asset type name based on game/platform globals
asset_type = "UNKNOWN";
if (game == "COD4" && platform == "PC") {
// Corrected mapping based on actual file data
if (raw_type == 0) { asset_type = "xmodelpieces"; }
if (raw_type == 1) { asset_type = "physpreset"; }
if (raw_type == 2) { asset_type = "xanim"; }
if (raw_type == 3) { asset_type = "xmodel"; }
if (raw_type == 4) { asset_type = "material"; }
if (raw_type == 5) { asset_type = "techset"; } // Was pixelshader - CORRECTED
if (raw_type == 6) { asset_type = "image"; }
if (raw_type == 7) { asset_type = "pixelshader"; }
if (raw_type == 8) { asset_type = "vertexshader"; }
if (raw_type == 9) { asset_type = "vertexdecl"; }
if (raw_type == 10) { asset_type = "sound"; }
if (raw_type == 11) { asset_type = "sndcurve"; }
if (raw_type == 12) { asset_type = "loaded_sound"; }
if (raw_type == 13) { asset_type = "col_map_sp"; }
if (raw_type == 14) { asset_type = "col_map_mp"; }
if (raw_type == 15) { asset_type = "com_map"; }
if (raw_type == 16) { asset_type = "game_map_sp"; }
if (raw_type == 17) { asset_type = "game_map_mp"; }
if (raw_type == 18) { asset_type = "map_ents"; }
if (raw_type == 19) { asset_type = "fx_map"; }
if (raw_type == 20) { asset_type = "gfx_map"; }
if (raw_type == 21) { asset_type = "lightdef"; }
if (raw_type == 22) { asset_type = "ui_map"; }
if (raw_type == 23) { asset_type = "font"; }
if (raw_type == 24) { asset_type = "menufile"; }
if (raw_type == 25) { asset_type = "menu"; }
if (raw_type == 26) { asset_type = "localize"; }
if (raw_type == 27) { asset_type = "weapon"; }
if (raw_type == 28) { asset_type = "snddriverglobals"; }
if (raw_type == 29) { asset_type = "fx"; }
if (raw_type == 30) { asset_type = "impactfx"; }
if (raw_type == 31) { asset_type = "rawfile"; } // Was aitype - CORRECTED
if (raw_type == 32) { asset_type = "aitype"; }
if (raw_type == 33) { asset_type = "mptype"; }
if (raw_type == 34) { asset_type = "character"; }
if (raw_type == 35) { asset_type = "xmodelalias"; }
if (raw_type == 36) { asset_type = "stringtable"; }
}
asset_type = asset_type [ui, readonly, display="Asset Type"];
// Set display name to asset type
_name = asset_type;
}

View File

@ -0,0 +1,74 @@
type assetlist [display="Asset List"]
{
u32 stringlist_count [ui, readonly, display="String List Count"];
i32 stringlist_ptr [ui, readonly, display="String List Ptr"];
u32 asset_count [ui, readonly, display="Asset Count"];
i32 assets_ptr [ui, readonly, display="Assets Ptr"];
// Parse string list inline (don't use parse_here to avoid double-reading count/ptr)
stringlist = 0;
if (stringlist_ptr != 0) {
actual_count = stringlist_count - 1; // C++ code decrements count
// First pass: read string pointers (skip them - we don't use the values)
_str_ptrs_size = actual_count * 4;
if (_str_ptrs_size > 0) {
_str_ptrs_raw = read(_str_ptrs_size);
}
// Second pass: parse strings at current position
strings = 0;
repeat(actual_count) {
_str = parse_here("scriptstring"); // Underscore prefix = internal/temp variable
strings = push("strings", _str);
}
strings = strings [table="Strings", columns="ptr,value"];
_skip_tree_strings = 1; // Marker: don't show 'strings' array in tree
stringlist = strings; // For backward compatibility
}
if (assets_ptr != 0) {
// First pass: Parse all asset headers (for table display only, not tree)
assets = 0;
repeat(asset_count) {
_a = parse_here("assetheader"); // Headers are just metadata
// Attach stringlist if available
if (stringlist != 0) {
_a_stringlist = stringlist;
}
assets = push("assets", _a);
}
// Display headers in table widget only (not in tree)
assets = assets [table="Assets", columns="asset_ptr,raw_type,asset_type", format_asset_ptr="hex", format_raw_type="hex"];
_skip_tree_assets = 1; // Marker: don't show 'assets' array in tree
// Second pass: Parse actual asset data based on headers (for tree display)
parsed_assets = 0;
repeat(asset_count) {
_header = get(assets, _i);
_ptr = get(_header, "asset_ptr");
_type = get(_header, "asset_type");
// Parse inline asset data (ptr == -1 which is 4294967295 as u32)
if (_ptr == 4294967295) {
if (_type == "techset") {
_asset = parse_here("materialtechniqueset") [ui];
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "material") {
_asset = parse_here("material") [ui];
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "rawfile") {
_asset = parse_here("rawfile") [ui];
parsed_assets = push("parsed_assets", _asset);
}
}
}
}
}

View File

@ -0,0 +1,110 @@
type fastfile [root, display="Fast File"] byteorder LE
{
criteria {
// Simplified: just check file extension for now
require _ext == "ff";
}
// Read header bytes needed for detection
company_s = ascii(bytesat(0, 2));
filetype_s = ascii(bytesat(2, 2));
signage_s = ascii(bytesat(4, 1));
magic_s = ascii(bytesat(5, 3));
version_i = u32at(8);
// Detect game based on header signature
// For now, default to COD4 for IW fast files
// TODO: Add more sophisticated detection based on file size, asset types, etc.
detected_game = "UNKNOWN";
if (company_s == "IW" && filetype_s == "ff") {
detected_game = "COD4";
}
if (company_s == "Ta" && filetype_s == "ff") {
detected_game = "COD8";
}
// Read platform field (byte 12-16)
platform_u32 = u32at(12);
// Detect platform based on version and platform field
detected_platform = "UNKNOWN";
if (version_i == 5) {
// Version 5 = PC
detected_platform = "PC";
}
if (version_i == 6) {
// Version 6 = XBOX 360
detected_platform = "XBOX360";
}
if (version_i == 12) {
// Version 12 = PS3
detected_platform = "PS3";
}
if (version_i == 14) {
// Version 14 = WII
detected_platform = "WII";
}
if (version_i > 276 && version_i < 1000) {
// Modern COD uses platform_u32 field
if (platform_u32 == 0) {
detected_platform = "PC";
}
if (platform_u32 == 1) {
detected_platform = "XBOX360";
}
if (platform_u32 == 2) {
detected_platform = "PS3";
}
if (platform_u32 == 3) {
detected_platform = "WII";
}
if (platform_u32 == 4) {
detected_platform = "WIIU";
}
}
// Set globals early so they're available for all parsing
set_global("game", detected_game);
set_global("platform", detected_platform);
set_global("version", version_i);
set_global("company", company_s);
// ---- UI fields ----
company_s = company_s [ui, readonly, display="Company"];
filetype_s = filetype_s [ui, readonly, display="File Type"];
is_unsigned = (signage_s == "u") [ui, readonly, display="Is Unsigned"];
magic_s = magic_s [ui, readonly, display="Magic"];
version_i = version_i [ui, readonly, display="Version"];
game_s = detected_game [ui, readonly, display="Game"];
platform_s = detected_platform [ui, readonly, display="Platform"];
platform_u32 = platform_u32 [ui, readonly, display="Platform ID"];
if (version_i == 5) {
byteorder LE;
} else {
byteorder BE;
}
seek(0);
u16 company_u16;
u16 file_type_u16;
u8 u_char;
u8 v1;
u8 v0a;
u8 v0b;
u32 platform_u32;
// Read and decompress zone file
compressed_zone = read(EOF);
decompressed_zone = compressed_zone |> zlib;
zonefile = decompressed_zone |> parse zonefile;
// Export decompressed zone file (using _basename to get filename without extension)
write_file(_basename + ".zone", decompressed_zone);
}

View File

@ -0,0 +1,10 @@
type font [display="Font"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
// TODO: Add full font structure (glyph data, metrics, etc.)
}

View File

@ -0,0 +1,5 @@
type gfxdrawsurf [display="GFX Draw Surf"]
{
// 64-bit packed bitfield containing rendering pipeline information
u64 fields [ui, readonly, display="Fields"];
}

View File

@ -0,0 +1,16 @@
type gfxpixelshaderloaddef [display="GFX Pixel Shader Load Def"]
{
// Shader program bytecode
u32 program_size [ui, readonly, display="Program Size"];
if (program_size > 0) {
program = read(program_size) [ui, readonly, display="Program"];
}
u32 micro_code_size [ui, readonly, display="Micro Code Size"];
// Note: micro_code_size is always 0 for PC platform
if (micro_code_size > 0) {
micro_code = read(micro_code_size) [ui, readonly, display="Micro Code"];
}
}

View File

@ -0,0 +1,5 @@
type gfxstatebits [display="GFX State Bits"]
{
u32 load_bits_0 [ui, readonly, display="Load Bits 0"];
u32 load_bits_1 [ui, readonly, display="Load Bits 1"];
}

View File

@ -0,0 +1,9 @@
type gfxvertexshaderloaddef [display="GFX Vertex Shader Load Def"]
{
// Shader program bytecode
u32 program_size [ui, readonly, display="Program Size"];
if (program_size > 0) {
program = read(program_size) [ui, readonly, display="Program"];
}
}

View File

@ -0,0 +1,10 @@
type image [display="Image"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
// TODO: Add full image structure (texture data, format, dimensions, etc.)
}

View File

@ -0,0 +1,10 @@
type loaded_sound [display="Loaded Sound"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
// TODO: Add full loaded sound structure (audio data, format, etc.)
}

View File

@ -0,0 +1,14 @@
type localize [display="Localize Entry"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
i32 value_ptr [ui, readonly, display="Value Ptr"];
if (value_ptr == -1) {
value = cstring() [ui, readonly, display="Value"];
}
}

View File

@ -0,0 +1,79 @@
type material [display="Material"]
{
// Parse material info inline to get material_name_ptr
i32 material_name_ptr [ui, readonly, display="Material Name Ptr"];
u8 game_flags [ui, readonly, display="Game Flags"];
u8 sort_key [ui, readonly, display="Sort Key"];
u8 texture_atlas_row_count [ui, readonly, display="Texture Atlas Row Count"];
u8 texture_atlas_column_count [ui, readonly, display="Texture Atlas Column Count"];
draw_surf = parse_here("gfxdrawsurf") [ui];
u32 surface_type_bits [ui, readonly, display="Surface Type Bits"];
u16 hash_index [ui, readonly, display="Hash Index"];
skip(2); // padding
// State bits entry array (34 bytes)
state_bits_entries_raw = read(34);
state_bits_entries_raw = state_bits_entries_raw [ui, readonly, display="State Bits Entries"];
u8 texture_count [ui, readonly, display="Texture Count"];
u8 constant_count [ui, readonly, display="Constant Count"];
u8 state_bits_count [ui, readonly, display="State Bits Count"];
u8 state_flags [ui, readonly, display="State Flags"];
u8 camera_region [ui, readonly, display="Camera Region"];
skip(1); // padding
// Pointers to sub-assets
i32 technique_set_ptr [ui, readonly, display="Technique Set Ptr"];
i32 texture_table_ptr [ui, readonly, display="Texture Table Ptr"];
i32 constant_table_ptr [ui, readonly, display="Constant Table Ptr"];
i32 state_bits_table_ptr [ui, readonly, display="State Bits Table Ptr"];
// Material name string (parse if inline)
if (material_name_ptr == -1) {
material_name = cstring() [ui, readonly, display="Material Name"];
_name = material_name; // Set display name
}
// Parse sub-assets if inline
if (technique_set_ptr == -1) {
technique_set = parse_here("materialtechniqueset") [ui];
}
if (texture_table_ptr == -1) {
texture_defs = 0;
if (texture_count > 0) {
repeat(texture_count) {
_texture_def = parse_here("materialtexturedef") [ui];
texture_defs = push("texture_defs", _texture_def);
}
}
texture_defs = texture_defs [ui];
}
if (constant_table_ptr == -1) {
constant_defs = 0;
if (constant_count > 0) {
repeat(constant_count) {
_constant_def = parse_here("materialconstantdef") [ui];
constant_defs = push("constant_defs", _constant_def);
}
}
constant_defs = constant_defs [ui];
}
if (state_bits_table_ptr == -1) {
state_bits = 0;
if (state_bits_count > 0) {
repeat(state_bits_count) {
_state_bit = parse_here("gfxstatebits") [ui];
state_bits = push("state_bits", _state_bit);
}
}
state_bits = state_bits [ui];
}
}

View File

@ -0,0 +1,7 @@
type materialargumentdef [display="Material Argument Def"]
{
u16 arg_type [ui, readonly, display="Type"];
u16 offset [ui, readonly, display="Offset"];
u16 size [ui, readonly, display="Size"];
u16 buffer [ui, readonly, display="Buffer"];
}

View File

@ -0,0 +1,13 @@
type materialconstantdef [display="Material Constant Def"]
{
u32 name_hash [ui, readonly, display="Name Hash"];
// Name is 12 bytes of raw data (null-padded string)
name_bytes = read(12);
name = ascii(name_bytes) [ui, readonly, display="Name"];
u32 literal_1 [ui, readonly, display="Literal 1"];
u32 literal_2 [ui, readonly, display="Literal 2"];
u32 literal_3 [ui, readonly, display="Literal 3"];
u32 literal_4 [ui, readonly, display="Literal 4"];
}

View File

@ -0,0 +1,16 @@
type materialinfo [display="Material Info"]
{
i32 material_name_ptr [ui, readonly, display="Material Name Ptr"];
u8 game_flags [ui, readonly, display="Game Flags"];
u8 sort_key [ui, readonly, display="Sort Key"];
u8 texture_atlas_row_count [ui, readonly, display="Texture Atlas Row Count"];
u8 texture_atlas_column_count [ui, readonly, display="Texture Atlas Column Count"];
draw_surf = parse_here("gfxdrawsurf") [ui];
u32 surface_type_bits [ui, readonly, display="Surface Type Bits"];
u16 hash_index [ui, readonly, display="Hash Index"];
skip(2); // padding
}

View File

@ -0,0 +1,24 @@
type materialpass [display="Material Pass"]
{
// Vertex declaration
vertex_decl = parse_here("materialvertexdeclaration") [ui];
// Vertex shader
vertex_shader = parse_here("materialvertexshader") [ui];
// Pixel shader (reusing existing pixelshader type)
pixel_shader = parse_here("pixelshader") [ui];
// Shader arguments
u8 arg_count [ui, readonly, display="Arg Count"];
u8 padding;
// Parse argument array
arguments = 0;
if (arg_count > 0) {
repeat(arg_count) {
_arg = parse_here("materialshaderargument") [ui];
arguments = push("arguments", _arg);
}
}
}

View File

@ -0,0 +1,8 @@
type materialshaderargument [display="Material Shader Argument"]
{
u16 arg_type [ui, readonly, display="Type"];
u16 dest [ui, readonly, display="Dest"];
// Argument definition
arg_def = parse_here("materialargumentdef") [ui];
}

View File

@ -0,0 +1,10 @@
type materialstreamrouting [display="Material Stream Routing"]
{
i32 routing_name_ptr [ui, readonly, display="Routing Name Ptr"];
// Parse routing name if inline
if (routing_name_ptr == -1) {
routing_name = cstring() [ui, readonly, display="Routing Name"];
_name = routing_name;
}
}

View File

@ -0,0 +1,22 @@
type materialtechnique [display="Material Technique"]
{
i32 technique_name_ptr [ui, readonly, display="Technique Name Ptr"];
// Parse technique name if inline
if (technique_name_ptr == -1) {
technique_name = cstring() [ui, readonly, display="Technique Name"];
_name = technique_name;
}
u16 flags [ui, readonly, display="Flags"];
u16 pass_count [ui, readonly, display="Pass Count"];
// Parse material passes
passes = 0;
if (pass_count > 0) {
repeat(pass_count) {
_pass = parse_here("materialpass") [ui];
passes = push("passes", _pass);
}
}
}

View File

@ -0,0 +1,65 @@
type materialtechniqueset [display="Material Technique Set"]
{
i32 technique_set_name_ptr [ui, readonly, display="Technique Set Name Ptr"];
u8 world_vert_format [ui, readonly, display="World Vert Format"];
u8 has_been_uploaded [ui, readonly, display="Has Been Uploaded"];
skip(2); // padding
skip(4); // more padding
// Technique count depends on game/platform
technique_count = 0;
if (game == "COD4") {
if (platform == "PC") {
technique_count = 34;
}
if (platform == "XBOX360") {
technique_count = 26;
}
if (platform == "PS3") {
technique_count = 26;
}
}
if (game == "COD5") {
if (platform == "PC") {
technique_count = 59;
}
if (platform == "XBOX360") {
technique_count = 51;
}
if (platform == "PS3") {
technique_count = 51;
}
}
technique_count = technique_count [ui, readonly, display="Technique Count"];
// Save position after technique count
_ptrs_start_pos = pos();
// Read technique pointers as raw bytes
if (technique_count > 0) {
_ptrs_size = technique_count * 4;
_technique_ptrs_raw = read(_ptrs_size);
}
// Parse technique set name if inline
if (technique_set_name_ptr == -1) {
technique_set_name = cstring() [ui, readonly, display="Technique Set Name"];
_name = technique_set_name;
}
// Second pass: Parse each technique if ptr == -1 (inline)
techniques = 0;
if (technique_count > 0) {
repeat(technique_count) {
_ptr_offset = _ptrs_start_pos + (_i * 4);
_ptr = u32at(_ptr_offset);
if (_ptr == 4294967295) { // -1 as u32
_technique = parse_here("materialtechnique") [ui];
techniques = push("techniques", _technique);
}
}
}
}

View File

@ -0,0 +1,10 @@
type materialtexturedef [display="Material Texture Def"]
{
u32 name_hash [ui, readonly, display="Name Hash"];
u8 name_start [ui, readonly, display="Name Start"];
u8 name_end [ui, readonly, display="Name End"];
u8 sampler_state [ui, readonly, display="Sampler State"];
u8 semantic [ui, readonly, display="Semantic"];
def_info = parse_here("materialtexturedefinfo") [ui];
}

View File

@ -0,0 +1,4 @@
type materialtexturedefinfo [display="Material Texture Def Info"]
{
i32 texture_ptr [ui, readonly, display="Texture Ptr"];
}

View File

@ -0,0 +1,18 @@
type materialvertexdeclaration [display="Material Vertex Declaration"]
{
i32 decl_name_ptr [ui, readonly, display="Decl Name Ptr"];
// Parse declaration name if inline
if (decl_name_ptr == -1) {
decl_name = cstring() [ui, readonly, display="Decl Name"];
_name = decl_name;
}
u8 stream_count [ui, readonly, display="Stream Count"];
u8 has_opt_stream [ui, readonly, display="Has Opt Stream"];
skip(2); // padding
// Vertex stream routing
routing = parse_here("materialvertexstreamrouting") [ui];
}

View File

@ -0,0 +1,13 @@
type materialvertexshader [display="Material Vertex Shader"]
{
i32 shader_name_ptr [ui, readonly, display="Shader Name Ptr"];
// Parse shader name if inline
if (shader_name_ptr == -1) {
shader_name = cstring() [ui, readonly, display="Shader Name"];
_name = shader_name;
}
// Vertex shader program
program = parse_here("materialvertexshaderprogram") [ui];
}

View File

@ -0,0 +1,9 @@
type materialvertexshaderprogram [display="Material Vertex Shader Program"]
{
i32 vertex_shader_ptr [ui, readonly, display="Vertex Shader Ptr"];
// If vertex shader ptr is 0, parse load def
if (vertex_shader_ptr == 0) {
load_def = parse_here("gfxvertexshaderloaddef") [ui];
}
}

View File

@ -0,0 +1,5 @@
type materialvertexstreamrouting [display="Material Vertex Stream Routing"]
{
// Parse stream routing data
data = parse_here("materialstreamrouting") [ui];
}

View File

@ -0,0 +1,10 @@
type menu [display="Menu"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
// TODO: Add full menu structure (items, properties, events, etc.)
}

View File

@ -0,0 +1,17 @@
type pixelshader [display="Pixel Shader"]
{
// Shader name pointer
i32 shader_name_ptr [ui, readonly, display="Shader Name Ptr"];
// Shader program structure
program = parse_here("pixelshaderprogram") [ui];
// Parse shader name if inline
if (shader_name_ptr == -1) {
shader_name = cstring() [ui, readonly, display="Shader Name"];
_name = shader_name; // Set display name
}
// TODO: Parse program LoadDef and ParseProgram
// This requires understanding the shader program structure
}

View File

@ -0,0 +1,9 @@
type pixelshaderprogram [display="Pixel Shader Program"]
{
i32 pixel_shader_ptr [ui, readonly, display="Pixel Shader Ptr"];
// If pixel shader ptr is 0 (not -1), parse load def
if (pixel_shader_ptr == 0) {
load_def = parse_here("gfxpixelshaderloaddef") [ui];
}
}

View File

@ -0,0 +1,16 @@
type rawfile [display="Raw File"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
i32 compression_type [ui, readonly, display="Compression Type"];
i32 data_ptr [ui, readonly, display="Data Ptr"];
u32 data_len [ui, readonly, display="Data Length"];
if (data_ptr == -1 && data_len > 0) {
raw_data = read(data_len) [ui, readonly, display="Raw Data"];
}
}

View File

@ -0,0 +1,9 @@
type scriptstring [display="Script String"]
{
i32 ptr [ui, readonly, display="Ptr"];
if (ptr == -1) {
// Read null-terminated string (C-style string)
value = cstring() [ui, readonly, display="Value"];
}
}

View File

@ -0,0 +1,26 @@
type scriptstringlist [display="Script String List"]
{
u32 raw_count [ui, readonly, display="Raw Count"];
i32 strings_ptr [ui, readonly, display="Strings Ptr"];
// C++ code decrements count by 1
count = raw_count - 1 [ui, readonly, display="Count"];
if (strings_ptr == -1) {
// Two-pass parsing (matching C++ XScriptStringList::ParseData)
// Pass 1: Read all string pointers
repeat(count) {
i32 str_ptr;
string_ptrs = push("string_ptrs", str_ptr);
}
// Pass 2: Parse all strings (reads null-terminated string data)
// Note: Each string should check if its ptr == -1 before parsing
repeat(count) {
str = parse_here("scriptstring");
strings = push("strings", str);
}
strings = strings [ui, table="Strings", columns="ptr,value"];
}
}

View File

@ -0,0 +1,10 @@
type sound [display="Sound"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
// TODO: Add full sound alias structure
}

View File

@ -0,0 +1,35 @@
type stringtable_asset [display="String Table"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
u32 column_count [ui, readonly, display="Column Count"];
u32 row_count [ui, readonly, display="Row Count"];
i32 values_ptr [ui, readonly, display="Values Ptr"];
// Parse string table values if inline
if (values_ptr == -1 && row_count > 0 && column_count > 0) {
cell_count = row_count * column_count [ui, readonly, display="Cell Count"];
// Read all cell pointers and values in one pass
cells = 0;
repeat(cell_count) {
i32 cell_ptr;
// Store cell pointer for reference
current_cell_ptr = cell_ptr;
}
// Read all cell values
repeat(cell_count) {
// For now, assume all cells have inline string data
// TODO: Handle cell_ptr properly to skip non-inline cells
cell_value = cstring();
cells = push("cells", cell_value);
}
cells = cells [ui, table="Cells", columns="value"];
}
}

View File

@ -0,0 +1,10 @@
type weapon [display="Weapon"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
// TODO: Add full weapon definition structure (stats, animations, effects, etc.)
}

View File

@ -0,0 +1,12 @@
type xmodel [display="XModel"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
// TODO: Add full XModel structure
// For now, just read the name as a placeholder
// Full structure includes: LODs, surfaces, bones, collision, etc.
}

View File

@ -0,0 +1,24 @@
type zonefile [display="Zone File"]
{
// Access global variables set by fastfile
// game_name = game; // Example: access the global 'game' variable
// platform_id = platform; // Example: access the global 'platform' variable
content_len = u32at(pos()) [ui, readonly, display="Content Length"]; // peek-style
u32 content_len_raw; // actually consume it
remaining_after_len = size() - pos();
// If we can afford 10 dwords, assume "non-COD5 header layout"
if (remaining_after_len >= (10 * 4)) {
header_kind = 0 [ui, readonly, display="Header Kind"]; // 0 = non-COD5
repeat(10) { u32 header_dw; }
content_len_total = content_len_raw + 44 [ui, readonly, display="Computed Total Size"];
} else {
header_kind = 1 [ui, readonly, display="Header Kind"]; // 1 = COD5-like
repeat(8) { u32 header_dw; }
content_len_total = content_len_raw + 36 [ui, readonly, display="Computed Total Size"];
}
assetlist_obj = parse_here("assetlist");
}