Expand Call of Duty XScript definitions

Add new asset type definitions:
- GfxWorld and related structures (cells, lights, probes)
- Menu system (menudef, itemdef, windowdef, listboxdef)
- Sound system (soundalias, soundfile, speakermap, sndcurve)
- D3D resources (vertex/index buffers)
- Font glyphs and expression entries

Update existing definitions with improved field annotations
and UI display properties.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
njohnson 2026-01-07 16:36:40 -05:00
parent 381b28c11f
commit 0fa26e5256
70 changed files with 1971 additions and 224 deletions

View File

@ -7,44 +7,41 @@ type assetheader
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"; }
// COD4 PC zone file asset type mapping
// Note: No pixelshader or vertexshader on PC
if (raw_type == 0x00) { asset_type = "xmodelpieces"; }
if (raw_type == 0x01) { asset_type = "physpreset"; }
if (raw_type == 0x02) { asset_type = "xanim"; }
if (raw_type == 0x03) { asset_type = "xmodel"; }
if (raw_type == 0x04) { asset_type = "material"; }
if (raw_type == 0x05) { asset_type = "techset"; }
if (raw_type == 0x06) { asset_type = "image"; }
if (raw_type == 0x07) { asset_type = "sound"; }
if (raw_type == 0x08) { asset_type = "sndcurve"; }
if (raw_type == 0x09) { asset_type = "loaded_sound"; }
if (raw_type == 0x0A) { asset_type = "col_map_sp"; }
if (raw_type == 0x0B) { asset_type = "col_map_mp"; }
if (raw_type == 0x0C) { asset_type = "com_map"; }
if (raw_type == 0x0D) { asset_type = "game_map_sp"; }
if (raw_type == 0x0E) { asset_type = "game_map_mp"; }
if (raw_type == 0x0F) { asset_type = "map_ents"; }
if (raw_type == 0x10) { asset_type = "gfx_map"; }
if (raw_type == 0x11) { asset_type = "lightdef"; }
if (raw_type == 0x12) { asset_type = "ui_map"; }
if (raw_type == 0x13) { asset_type = "font"; }
if (raw_type == 0x14) { asset_type = "menufile"; }
if (raw_type == 0x15) { asset_type = "menu"; }
if (raw_type == 0x16) { asset_type = "localize"; }
if (raw_type == 0x17) { asset_type = "weapon"; }
if (raw_type == 0x18) { asset_type = "snddriverglobals"; }
if (raw_type == 0x19) { asset_type = "fx"; }
if (raw_type == 0x1A) { asset_type = "impactfx"; }
if (raw_type == 0x1B) { asset_type = "aitype"; }
if (raw_type == 0x1C) { asset_type = "mptype"; }
if (raw_type == 0x1D) { asset_type = "character"; }
if (raw_type == 0x1E) { asset_type = "xmodelalias"; }
if (raw_type == 0x1F) { asset_type = "rawfile"; }
if (raw_type == 0x20) { asset_type = "stringtable"; }
}
asset_type = asset_type [ui, readonly, display="Asset Type"];

View File

@ -9,9 +9,9 @@ type assetlist [display="Asset List"]
// 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
actual_count = stringlist_count - 1;
// First pass: read string pointers (skip them - we don't use the values)
// First pass: read string pointers (skip them)
_str_ptrs_size = actual_count * 4;
if (_str_ptrs_size > 0) {
_str_ptrs_raw = read(_str_ptrs_size);
@ -20,22 +20,21 @@ type assetlist [display="Asset List"]
// Second pass: parse strings at current position
strings = 0;
repeat(actual_count) {
_str = parse_here("scriptstring"); // Underscore prefix = internal/temp variable
_str = parse_here("scriptstring");
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
_skip_tree_strings = 1;
stringlist = strings;
}
if (assets_ptr != 0) {
// First pass: Parse all asset headers (for table display only, not tree)
// First pass: Parse all asset headers
assets = 0;
repeat(asset_count) {
_a = parse_here("assetheader"); // Headers are just metadata
_a = parse_here("assetheader");
// Attach stringlist if available
if (stringlist != 0) {
_a_stringlist = stringlist;
}
@ -43,11 +42,10 @@ type assetlist [display="Asset List"]
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
_skip_tree_assets = 1;
// Second pass: Parse actual asset data based on headers (for tree display)
// Second pass: Parse actual asset data based on headers
parsed_assets = 0;
repeat(asset_count) {
_header = get(assets, _i);
@ -57,15 +55,67 @@ type assetlist [display="Asset List"]
// Parse inline asset data (ptr == -1 which is 4294967295 as u32)
if (_ptr == 4294967295) {
if (_type == "techset") {
_asset = parse_here("materialtechniqueset") [ui];
_asset = parse_here("materialtechniqueset");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "material") {
_asset = parse_here("material") [ui];
_asset = parse_here("material");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "rawfile") {
_asset = parse_here("rawfile") [ui];
_asset = parse_here("rawfile");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "gfx_map") {
_asset = parse_here("gfxworld");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "image") {
_asset = parse_here("image");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "pixelshader") {
_asset = parse_here("pixelshader");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "font") {
_asset = parse_here("font");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "localize") {
_asset = parse_here("localize");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "menu") {
_asset = parse_here("menu");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "sound") {
_asset = parse_here("sound");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "loaded_sound") {
_asset = parse_here("loaded_sound");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "sndcurve") {
_asset = parse_here("sndcurve");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "xmodel") {
_asset = parse_here("xmodel");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "stringtable") {
_asset = parse_here("stringtable_asset");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "weapon") {
_asset = parse_here("weapon");
parsed_assets = push("parsed_assets", _asset);
}
if (_type == "menufile" || _type == "menulist") {
_asset = parse_here("menulist");
parsed_assets = push("parsed_assets", _asset);
}
}

View File

@ -0,0 +1,8 @@
type columninfo [display="Column Info"]
{
// columnInfo_s - 16 bytes total
i32 pos [ui, readonly, display="Pos"];
i32 width [ui, readonly, display="Width"];
i32 max_chars [ui, readonly, display="Max Chars"];
i32 alignment [ui, readonly, display="Alignment"];
}

View File

@ -0,0 +1,8 @@
type d3dindexbuffer [display="D3D Index Buffer"]
{
// D3D Resource base (24 bytes)
resource = parse_here("d3dresource");
u32 address [ui, readonly, display="Address"];
u32 size [ui, readonly, display="Size"];
}

View File

@ -0,0 +1,9 @@
type d3dresource [display="D3D Resource"]
{
u32 common [ui, readonly, display="Common"];
u32 reference_count [ui, readonly, display="Reference Count"];
u32 fence [ui, readonly, display="Fence"];
u32 read_fence [ui, readonly, display="Read Fence"];
u32 identifier [ui, readonly, display="Identifier"];
u32 base_flush [ui, readonly, display="Base Flush"];
}

View File

@ -0,0 +1,9 @@
type d3dvertexbuffer [display="D3D Vertex Buffer"]
{
// D3D Resource base (24 bytes)
resource = parse_here("d3dresource");
// GPU Vertex Fetch Constant / Raw Request (8 bytes - 2 x u32 packed bitfields)
u32 fetch_w0 [ui, readonly, display="Fetch W0"];
u32 fetch_w1 [ui, readonly, display="Fetch W1"];
}

View File

@ -0,0 +1,12 @@
type editfielddef [display="Edit Field Def"]
{
// editFieldDef_s - 32 bytes total
f32 min_val [ui, readonly, display="Min Val"];
f32 max_val [ui, readonly, display="Max Val"];
f32 def_val [ui, readonly, display="Def Val"];
f32 range [ui, readonly, display="Range"];
i32 max_chars [ui, readonly, display="Max Chars"];
i32 max_chars_goto_next [ui, readonly, display="Max Chars Goto Next"];
i32 max_paint_chars [ui, readonly, display="Max Paint Chars"];
i32 paint_offset [ui, readonly, display="Paint Offset"];
}

View File

@ -0,0 +1,28 @@
type expressionentry [display="Expression Entry"]
{
// expressionEntry struct from IW3_Assets.h
// Total: 12 bytes (int type + 8 byte union)
// int type - EET_OPERATOR(0) or EET_OPERAND(1)
i32 entry_type [ui, readonly, display="Type"];
// entryInternalData union - 8 bytes
// If type == 0 (operator): int op (4 bytes) + 4 padding
// If type == 1 (operand): Operand struct (dataType + internals = 8 bytes)
if (entry_type == 0) {
// Operator - just an int
i32 op_code [ui, readonly, display="Op Code"];
i32 _padding [ui, readonly];
} else {
// Operand - dataType (4) + value union (4)
// dataType: 0=INT, 1=FLOAT, 2=STRING
i32 data_type [ui, readonly, display="Data Type"];
i32 value_raw [ui, readonly, display="Value/Ptr"];
// If data_type == 2 (STRING) and value is -1, string is inline
if (data_type == 2 && value_raw == -1) {
string_val = cstring() [ui, readonly, display="String Value"];
}
}
}

View File

@ -13,8 +13,6 @@ type fastfile [root, display="Fast File"] byteorder LE
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") {
@ -32,23 +30,18 @@ type fastfile [root, display="Fast File"] byteorder LE
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";
}
@ -103,8 +96,10 @@ type fastfile [root, display="Fast File"] byteorder LE
// 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)
// Export decompressed zone file FIRST (before parsing)
write_file(_basename + ".zone", decompressed_zone);
// Then parse the zone structure
zonefile = decompressed_zone |> parse zonefile;
}

View File

@ -1,10 +1,34 @@
type font [display="Font"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
i32 pixel_height [ui, readonly, display="Pixel Height"];
i32 glyph_count [ui, readonly, display="Glyph Count"];
i32 material_ptr [ui, readonly, display="Material Ptr"];
i32 glow_material_ptr [ui, readonly, display="Glow Material Ptr"];
i32 glyphs_ptr [ui, readonly, display="Glyphs Ptr"];
// Parse inline name
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
// TODO: Add full font structure (glyph data, metrics, etc.)
// Parse inline material
if (material_ptr == -1) {
material = parse_here("material");
}
// Parse inline glow material
if (glow_material_ptr == -1) {
glow_material = parse_here("material");
}
// Parse inline glyphs
if (glyphs_ptr == -1 && glyph_count > 0) {
glyphs = 0;
repeat(glyph_count) {
_glyph = parse_here("glyph");
glyphs = push("glyphs", _glyph);
}
}
}

View File

@ -0,0 +1,20 @@
type gfxcell [display="GFX Cell"]
{
// Bounds (6 floats)
mins = read(12) [ui, readonly, display="Mins"];
maxs = read(12) [ui, readonly, display="Maxs"];
i32 aabb_tree_count [ui, readonly, display="AABB Tree Count"];
i32 aabb_tree_ptr [ui, readonly, display="AABB Tree Ptr"];
i32 portal_count [ui, readonly, display="Portal Count"];
i32 portals_ptr [ui, readonly, display="Portals Ptr"];
i32 cull_group_count [ui, readonly, display="Cull Group Count"];
i32 cull_groups_ptr [ui, readonly, display="Cull Groups Ptr"];
u8 reflection_probe_count [ui, readonly, display="Reflection Probe Count"];
i32 reflection_probes_ptr [ui, readonly, display="Reflection Probes Ptr"];
// Note: Array data would be parsed if pointers are valid
}

View File

@ -0,0 +1,20 @@
type gfximageloaddef [display="GFX Image Load Def"]
{
u8 level_count [ui, readonly, display="Level Count"];
u8 flags [ui, readonly, display="Flags"];
// Dimensions (3 x u16)
u16 dimension_0 [ui, readonly, display="Dimension 0"];
u16 dimension_1 [ui, readonly, display="Dimension 1"];
u16 dimension_2 [ui, readonly, display="Dimension 2"];
u32 format [ui, readonly, display="Format"];
// Resource size - when inline, this contains the size of pixel data that follows
i32 resource_size [ui, readonly, display="Resource Size"];
// Read pixel data if present (resource_size > 0 indicates inline data)
if (resource_size > 0) {
pixel_data = read(resource_size) [ui, readonly, display="Pixel Data"];
}
}

View File

@ -0,0 +1,28 @@
type gfxlight [display="GFX Light"]
{
u8 light_type [ui, readonly, display="Type"];
u8 can_use_shadow_map [ui, readonly, display="Can Use Shadow Map"];
skip(2); // padding
// Color (3 floats)
color = read(12) [ui, readonly, display="Color RGB"];
// Direction (3 floats)
dir = read(12) [ui, readonly, display="Direction"];
// Origin (3 floats)
origin = read(12) [ui, readonly, display="Origin"];
// Other params
radius = read(4) [ui, readonly, display="Radius"];
cos_half_fov_outer = read(4) [ui, readonly, display="Cos Half FOV Outer"];
cos_half_fov_inner = read(4) [ui, readonly, display="Cos Half FOV Inner"];
i32 exponent [ui, readonly, display="Exponent"];
u32 spot_shadow_index [ui, readonly, display="Spot Shadow Index"];
i32 def_ptr [ui, readonly, display="Def Ptr"];
if (def_ptr == -1) {
def = parse_here("gfxlightdef");
}
}

View File

@ -0,0 +1,15 @@
type gfxlightdef [display="GFX Light Def"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
// Attenuation (GfxLightImage)
attenuation = parse_here("gfxlightimage");
u32 lmap_lookup_start [ui, readonly, display="LMap Lookup Start"];
// Parse name if inline
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
}

View File

@ -0,0 +1,25 @@
type gfxlightgrid [display="GFX Light Grid"]
{
// PC version: 56 bytes (mins/maxs are uint16_t[3], not float[3])
u8 has_light_regions [ui, readonly, display="Has Light Regions"];
skip(3); // padding
u32 sun_primary_light_index [ui, readonly, display="Sun Primary Light Index"];
// Bounds are uint16_t[3] on PC (6 bytes each)
mins = read(6) [ui, readonly, display="Mins"];
maxs = read(6) [ui, readonly, display="Maxs"];
u32 row_axis [ui, readonly, display="Row Axis"];
u32 col_axis [ui, readonly, display="Col Axis"];
i32 row_data_start_ptr [ui, readonly, display="Row Data Start Ptr"];
u32 raw_row_data_size [ui, readonly, display="Raw Row Data Size"];
i32 raw_row_data_ptr [ui, readonly, display="Raw Row Data Ptr"];
u32 entry_count [ui, readonly, display="Entry Count"];
i32 entries_ptr [ui, readonly, display="Entries Ptr"];
u32 color_count [ui, readonly, display="Color Count"];
i32 colors_ptr [ui, readonly, display="Colors Ptr"];
}

View File

@ -0,0 +1,10 @@
type gfxlightimage [display="GFX Light Image"]
{
i32 image_ptr [ui, readonly, display="Image Ptr"];
u8 sampler_state [ui, readonly, display="Sampler State"];
skip(3); // padding
if (image_ptr == -1) {
image = parse_here("image");
}
}

View File

@ -0,0 +1,13 @@
type gfxlightmaparray [display="GFX Lightmap Array"]
{
i32 primary_ptr [ui, readonly, display="Primary Ptr"];
i32 secondary_ptr [ui, readonly, display="Secondary Ptr"];
// Images parsed inline if ptr == -1
if (primary_ptr == -1) {
primary = parse_here("image");
}
if (secondary_ptr == -1) {
secondary = parse_here("image");
}
}

View File

@ -0,0 +1,8 @@
type gfxreflectionprobe [display="GFX Reflection Probe"]
{
// Origin (3 floats = 12 bytes)
origin = read(12) [ui, readonly, display="Origin"];
// Reflection image
reflection_image = parse_here("image");
}

View File

@ -0,0 +1,12 @@
type gfxstreamingaabbtree [display="GFX Streaming AABB Tree"]
{
u16 first_item [ui, readonly, display="First Item"];
u16 item_count [ui, readonly, display="Item Count"];
u16 first_child [ui, readonly, display="First Child"];
u16 child_count [ui, readonly, display="Child Count"];
// Bounds (6 floats)
// Note: Using read() since we don't have float type yet
mins = read(12) [ui, readonly, display="Mins"];
maxs = read(12) [ui, readonly, display="Maxs"];
}

View File

@ -0,0 +1,10 @@
type gfxtexture [display="GFX Texture"]
{
// GfxTexture is a union of different texture types
// For inline data (-1 or -2), parse load def
i32 base_map_ptr [ui, readonly, display="Base Map Ptr"];
if (base_map_ptr == -1 || base_map_ptr == -2) {
load_def = parse_here("gfximageloaddef");
}
}

View File

@ -0,0 +1,155 @@
type gfxworld [display="GFX World"]
{
// ========================================
// GfxWorld Header - PC VERSION (732 bytes)
// ========================================
// Name pointers (8 bytes)
i32 name_ptr [ui, readonly, display="Name Ptr"];
i32 basename_ptr [ui, readonly, display="Base Name Ptr"];
// Counts and indices (16 bytes)
i32 plane_count [ui, readonly, display="Plane Count"];
i32 node_count [ui, readonly, display="Node Count"];
i32 index_count [ui, readonly, display="Index Count"];
i32 indices_ptr [ui, readonly, display="Indices Ptr"];
// PC has no D3DIndexBuffer - just surfaceCount + unk (8 bytes)
i32 surface_count [ui, readonly, display="Surface Count"];
i32 unk [ui, readonly, display="Unknown"];
// Sky data (16 bytes)
i32 sky_surf_count [ui, readonly, display="Sky Surf Count"];
i32 sky_start_surfs_ptr [ui, readonly, display="Sky Start Surfs Ptr"];
i32 sky_image_ptr [ui, readonly, display="Sky Image Ptr"];
u8 sky_sampler_state [ui, readonly, display="Sky Sampler State"];
skip(3); // padding
// Vertex data (4 + 8 = 12 bytes)
u32 vertex_count [ui, readonly, display="Vertex Count"];
vertex_data = parse_here("gfxworldvertexdata");
// Vertex layer data (4 + 8 = 12 bytes)
u32 vertex_layer_data_size [ui, readonly, display="Vertex Layer Data Size"];
vertex_layer_data = parse_here("gfxworldvertexlayerdata");
// Sun light parse params - EMBEDDED (128 bytes on PC - name is char[64])
sun_parse = parse_here("sunlightparseparams");
// Sun light pointer (4 bytes)
i32 sun_light_ptr [ui, readonly, display="Sun Light Ptr"];
// Sun color from BSP (12 bytes)
sun_color = read(12) [ui, readonly, display="Sun Color"];
// Light counts and reflection probes (24 bytes)
u32 sun_primary_light_index [ui, readonly, display="Sun Primary Light Index"];
u32 primary_light_count [ui, readonly, display="Primary Light Count"];
i32 cull_group_count [ui, readonly, display="Cull Group Count"];
u32 reflection_probe_count [ui, readonly, display="Reflection Probe Count"];
i32 reflection_probes_ptr [ui, readonly, display="Reflection Probes Ptr"];
i32 reflection_probe_textures_ptr [ui, readonly, display="Reflection Probe Textures Ptr"];
// DPVS planes - EMBEDDED (16 bytes)
dpvs_planes = parse_here("gfxworlddpvsplanes");
// Cells and lightmaps (16 bytes)
i32 cell_bits_count [ui, readonly, display="Cell Bits Count"];
i32 cells_ptr [ui, readonly, display="Cells Ptr"];
i32 lightmap_count [ui, readonly, display="Lightmap Count"];
i32 lightmaps_ptr [ui, readonly, display="Lightmaps Ptr"];
// Light grid - EMBEDDED (56 bytes on PC - mins/maxs are uint16)
light_grid = parse_here("gfxlightgrid");
// Texture pointers (16 bytes)
i32 lightmaps_primary_ptr [ui, readonly, display="Lightmaps Primary Ptr"];
i32 lightmaps_secondary_ptr [ui, readonly, display="Lightmaps Secondary Ptr"];
i32 model_count [ui, readonly, display="Model Count"];
i32 models_ptr [ui, readonly, display="Models Ptr"];
// Bounds (24 bytes)
mins = read(12) [ui, readonly, display="Mins"];
maxs = read(12) [ui, readonly, display="Maxs"];
// Checksum and material memory (12 bytes)
u32 checksum [ui, readonly, display="Checksum"];
i32 material_memory_count [ui, readonly, display="Material Memory Count"];
i32 material_memory_ptr [ui, readonly, display="Material Memory Ptr"];
// Sun flare - EMBEDDED (96 bytes)
sun_flare = parse_here("sunflare");
// Outdoor lookup matrix (64 bytes)
outdoor_lookup_matrix = read(64) [ui, readonly, display="Outdoor Lookup Matrix"];
// Final pointers (40 bytes)
i32 outdoor_image_ptr [ui, readonly, display="Outdoor Image Ptr"];
i32 cell_caster_bits_ptr [ui, readonly, display="Cell Caster Bits Ptr"];
i32 scene_dyn_model_ptr [ui, readonly, display="Scene Dyn Model Ptr"];
i32 scene_dyn_brush_ptr [ui, readonly, display="Scene Dyn Brush Ptr"];
i32 primary_light_ent_shadow_vis_ptr [ui, readonly, display="Primary Light Ent Shadow Vis Ptr"];
i32 primary_light_dyn_ent_shadow_vis_ptr_0 [ui, readonly, display="Primary Light Dyn Ent Shadow Vis Ptr 0"];
i32 primary_light_dyn_ent_shadow_vis_ptr_1 [ui, readonly, display="Primary Light Dyn Ent Shadow Vis Ptr 1"];
i32 primary_light_for_model_dyn_ent_ptr [ui, readonly, display="Primary Light For Model Dyn Ent Ptr"];
i32 shadow_geom_ptr [ui, readonly, display="Shadow Geom Ptr"];
i32 light_region_ptr [ui, readonly, display="Light Region Ptr"];
// DPVS static - EMBEDDED (104 bytes on PC - has 3 extra fields)
dpvs = parse_here("gfxworlddpvsstatic");
// DPVS dynamic - EMBEDDED (48 bytes)
dpvs_dyn = parse_here("gfxworlddpvsdynamic");
// ========================================
// Inline data (after header, ptr == -1)
// ========================================
// Parse names if inline
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
if (basename_ptr == -1) {
basename = cstring() [ui, readonly, display="Base Name"];
}
// Indices array - only if inline (ptr == -1)
if (indices_ptr == -1 && index_count > 0) {
indices = read(index_count * 2) [ui, readonly, display="Indices"];
}
// Sky start surfs - only if inline
if (sky_start_surfs_ptr == -1 && sky_surf_count > 0) {
sky_start_surfs = read(sky_surf_count * 4) [ui, readonly, display="Sky Start Surfs"];
}
// Sky image - only if inline
if (sky_image_ptr == -1) {
sky_image = parse_here("image");
}
// Sun light - only if inline
if (sun_light_ptr == -1) {
sun_light = parse_here("gfxlight");
}
// Reflection probes - only if inline
if (reflection_probes_ptr == -1 && reflection_probe_count > 0) {
reflection_probes = 0;
repeat(reflection_probe_count) {
_probe = parse_here("gfxreflectionprobe");
reflection_probes = push("reflection_probes", _probe);
}
}
// Reflection probe textures - only if inline
if (reflection_probe_textures_ptr == -1 && reflection_probe_count > 0) {
reflection_probe_textures = 0;
repeat(reflection_probe_count) {
_tex = parse_here("gfxtexture");
reflection_probe_textures = push("reflection_probe_textures", _tex);
}
}
}

View File

@ -0,0 +1,20 @@
type gfxworlddpvsdynamic [display="GFX World DPVS Dynamic"]
{
// Fixed fields - dynEntClientWordCount[2] and dynEntClientCount[2]
u32 dyn_ent_client_word_count_0 [ui, readonly, display="Dyn Ent Client Word Count 0"];
u32 dyn_ent_client_word_count_1 [ui, readonly, display="Dyn Ent Client Word Count 1"];
u32 dyn_ent_client_count_0 [ui, readonly, display="Dyn Ent Client Count 0"];
u32 dyn_ent_client_count_1 [ui, readonly, display="Dyn Ent Client Count 1"];
// Pointers
i32 dyn_ent_cell_bits_ptr_0 [ui, readonly, display="Dyn Ent Cell Bits Ptr 0"];
i32 dyn_ent_cell_bits_ptr_1 [ui, readonly, display="Dyn Ent Cell Bits Ptr 1"];
i32 dyn_ent_vis_data_ptr_0_0 [ui, readonly, display="Dyn Ent Vis Data Ptr 0-0"];
i32 dyn_ent_vis_data_ptr_0_1 [ui, readonly, display="Dyn Ent Vis Data Ptr 0-1"];
i32 dyn_ent_vis_data_ptr_0_2 [ui, readonly, display="Dyn Ent Vis Data Ptr 0-2"];
i32 dyn_ent_vis_data_ptr_1_0 [ui, readonly, display="Dyn Ent Vis Data Ptr 1-0"];
i32 dyn_ent_vis_data_ptr_1_1 [ui, readonly, display="Dyn Ent Vis Data Ptr 1-1"];
i32 dyn_ent_vis_data_ptr_1_2 [ui, readonly, display="Dyn Ent Vis Data Ptr 1-2"];
// Note: Full array parsing not implemented
}

View File

@ -0,0 +1,10 @@
type gfxworlddpvsplanes [display="GFX World DPVS Planes"]
{
// Fixed header fields
i32 cell_count [ui, readonly, display="Cell Count"];
i32 planes_ptr [ui, readonly, display="Planes Ptr"];
i32 nodes_ptr [ui, readonly, display="Nodes Ptr"];
i32 scene_ent_cell_bits_ptr [ui, readonly, display="Scene Ent Cell Bits Ptr"];
// Note: Arrays are parsed separately based on pointers
}

View File

@ -0,0 +1,32 @@
type gfxworlddpvsstatic [display="GFX World DPVS Static"]
{
// PC version: 104 bytes (has 3 extra fields vs 360)
u32 smodel_count [ui, readonly, display="SModel Count"];
u32 static_surface_count [ui, readonly, display="Static Surface Count"];
u32 lit_surfs_begin [ui, readonly, display="Lit Surfs Begin"];
u32 lit_surfs_end [ui, readonly, display="Lit Surfs End"];
u32 decal_surfs_begin [ui, readonly, display="Decal Surfs Begin"];
u32 decal_surfs_end [ui, readonly, display="Decal Surfs End"];
u32 emissive_surfs_begin [ui, readonly, display="Emissive Surfs Begin"];
u32 emissive_surfs_end [ui, readonly, display="Emissive Surfs End"];
u32 unk [ui, readonly, display="Unknown"];
u32 lod_data_count [ui, readonly, display="LOD Data Count"];
u32 surface_casts_sun_shadow_count [ui, readonly, display="Surface Casts Sun Shadow Count"];
// Pointers to arrays
i32 smodel_vis_data_ptr_0 [ui, readonly, display="SModel Vis Data Ptr 0"];
i32 smodel_vis_data_ptr_1 [ui, readonly, display="SModel Vis Data Ptr 1"];
i32 smodel_vis_data_ptr_2 [ui, readonly, display="SModel Vis Data Ptr 2"];
i32 surface_vis_data_ptr_0 [ui, readonly, display="Surface Vis Data Ptr 0"];
i32 surface_vis_data_ptr_1 [ui, readonly, display="Surface Vis Data Ptr 1"];
i32 surface_vis_data_ptr_2 [ui, readonly, display="Surface Vis Data Ptr 2"];
i32 lod_data_ptr [ui, readonly, display="LOD Data Ptr"];
i32 sorted_surf_index_ptr [ui, readonly, display="Sorted Surf Index Ptr"];
i32 smodel_insts_ptr [ui, readonly, display="SModel Insts Ptr"];
i32 surfaces_ptr [ui, readonly, display="Surfaces Ptr"];
i32 cull_groups_ptr [ui, readonly, display="Cull Groups Ptr"];
i32 smodel_draw_insts_ptr [ui, readonly, display="SModel Draw Insts Ptr"];
i32 surface_materials_ptr [ui, readonly, display="Surface Materials Ptr"];
i32 surface_casts_sun_shadow_ptr [ui, readonly, display="Surface Casts Sun Shadow Ptr"];
i32 usage_count [ui, readonly, display="Usage Count"];
}

View File

@ -0,0 +1,10 @@
type gfxworldstreaminfo [display="GFX World Stream Info"]
{
// Fixed 16-byte header (embedded in GfxWorld header)
i32 aabb_tree_count [ui, readonly, display="AABB Tree Count"];
i32 aabb_trees_ptr [ui, readonly, display="AABB Trees Ptr"];
i32 leaf_ref_count [ui, readonly, display="Leaf Ref Count"];
i32 leaf_refs_ptr [ui, readonly, display="Leaf Refs Ptr"];
// Note: Arrays are parsed separately after the main header
}

View File

@ -0,0 +1,6 @@
type gfxworldvertexdata [display="GFX World Vertex Data"]
{
// PC version: 8 bytes (2 pointers)
i32 vertices_ptr [ui, readonly, display="Vertices Ptr"];
i32 world_vb_ptr [ui, readonly, display="World VB Ptr"];
}

View File

@ -0,0 +1,6 @@
type gfxworldvertexlayerdata [display="GFX World Vertex Layer Data"]
{
// PC version: 8 bytes (2 pointers)
i32 data_ptr [ui, readonly, display="Data Ptr"];
i32 layer_vb_ptr [ui, readonly, display="Layer VB Ptr"];
}

View File

@ -0,0 +1,17 @@
type glyph [display="Glyph"]
{
u16 letter [ui, readonly, display="Letter"];
i8 x0 [ui, readonly, display="X0"];
i8 y0 [ui, readonly, display="Y0"];
i8 dx [ui, readonly, display="DX"];
i8 pixel_width [ui, readonly, display="Pixel Width"];
i8 pixel_height [ui, readonly, display="Pixel Height"];
i8 pitch [ui, readonly, display="Pitch"];
// UV coordinates (4 floats = 16 bytes)
// Read as raw bytes since we don't have float type yet
uv_coords = read(16) [ui, readonly, display="UV Coords"];
// Padding to align to 32 bytes total (8 + 16 = 24, need 8 more)
skip(8);
}

View File

@ -1,10 +1,41 @@
type image [display="Image"]
{
// GfxImage struct - 32 bytes total on PC COD4
u32 map_type [ui, readonly, display="Map Type"];
// GfxTexture union - on PC this is just a D3D texture ptr (or -1/-2 for inline loaddef)
i32 texture_ptr [ui, readonly, display="Texture Ptr"];
// Picmip (2 bytes)
u8 picmip_0 [ui, readonly, display="Picmip 0"];
u8 picmip_1 [ui, readonly, display="Picmip 1"];
u8 semantic [ui, readonly, display="Semantic"];
u8 track [ui, readonly, display="Track"];
// Card memory (2 x u32 = 8 bytes)
u32 card_memory_0 [ui, readonly, display="Card Memory 0"];
u32 card_memory_1 [ui, readonly, display="Card Memory 1"];
u16 width [ui, readonly, display="Width"];
u16 height [ui, readonly, display="Height"];
u16 depth [ui, readonly, display="Depth"];
u8 category [ui, readonly, display="Category"];
u8 delay_load_pixels [ui, readonly, display="Delay Load Pixels"];
// Name pointer
i32 name_ptr [ui, readonly, display="Name Ptr"];
// Parse inline name if ptr is -1
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
// TODO: Add full image structure (texture data, format, dimensions, etc.)
// GfxImageLoadDef parsed if texture ptr is -1 or -2 (inline data)
// On PC, images with streaming data have loaddef inline
if (texture_ptr == -1 || texture_ptr == -2) {
load_def = parse_here("gfximageloaddef");
}
}

View File

@ -0,0 +1,251 @@
type itemdef [display="Item Def"]
{
// itemDef_s struct from IW3_Assets.h
// Total fixed size: ~368 bytes
// ============ WindowDef_t embedded (156 bytes) ============
window = parse_here("windowdef") [display="Window"];
// ============ Text Rect (24 bytes) ============
text_rect = parse_here("rectdef") [display="Text Rect"];
// ============ Item Properties ============
i32 item_type [ui, readonly, display="Type"];
i32 data_type [ui, readonly, display="Data Type"];
i32 alignment [ui, readonly, display="Alignment"];
i32 font_enum [ui, readonly, display="Font Enum"];
i32 text_align_mode [ui, readonly, display="Text Align Mode"];
f32 text_align_x [ui, readonly, display="Text Align X"];
f32 text_align_y [ui, readonly, display="Text Align Y"];
f32 text_scale [ui, readonly, display="Text Scale"];
i32 text_style [ui, readonly, display="Text Style"];
i32 game_msg_window_index [ui, readonly, display="Game Msg Window Index"];
i32 game_msg_window_mode [ui, readonly, display="Game Msg Window Mode"];
// Pointers
i32 text_ptr [ui, readonly, display="Text Ptr"];
i32 item_flags [ui, readonly, display="Item Flags"];
i32 parent_ptr [ui, readonly, display="Parent Ptr"];
i32 mouse_enter_text_ptr [ui, readonly, display="Mouse Enter Text Ptr"];
i32 mouse_exit_text_ptr [ui, readonly, display="Mouse Exit Text Ptr"];
i32 mouse_enter_ptr [ui, readonly, display="Mouse Enter Ptr"];
i32 mouse_exit_ptr [ui, readonly, display="Mouse Exit Ptr"];
i32 action_ptr [ui, readonly, display="Action Ptr"];
i32 on_accept_ptr [ui, readonly, display="On Accept Ptr"];
i32 on_focus_ptr [ui, readonly, display="On Focus Ptr"];
i32 leave_focus_ptr [ui, readonly, display="Leave Focus Ptr"];
i32 dvar_ptr [ui, readonly, display="Dvar Ptr"];
i32 dvar_test_ptr [ui, readonly, display="Dvar Test Ptr"];
i32 on_key_ptr [ui, readonly, display="On Key Ptr"];
i32 enable_dvar_ptr [ui, readonly, display="Enable Dvar Ptr"];
i32 dvar_flags [ui, readonly, display="Dvar Flags"];
i32 focus_sound_ptr [ui, readonly, display="Focus Sound Ptr"];
f32 special [ui, readonly, display="Special"];
i32 cursor_pos [ui, readonly, display="Cursor Pos"];
i32 type_data_ptr [ui, readonly, display="Type Data Ptr"];
i32 image_track [ui, readonly, display="Image Track"];
// ============ Expressions (8 x statement_s = 64 bytes) ============
visible_exp = parse_here("statement") [display="Visible Exp"];
text_exp = parse_here("statement") [display="Text Exp"];
material_exp = parse_here("statement") [display="Material Exp"];
rect_x_exp = parse_here("statement") [display="Rect X Exp"];
rect_y_exp = parse_here("statement") [display="Rect Y Exp"];
rect_w_exp = parse_here("statement") [display="Rect W Exp"];
rect_h_exp = parse_here("statement") [display="Rect H Exp"];
forecolor_a_exp = parse_here("statement") [display="Forecolor A Exp"];
// ============================================================
// INLINE DATA PARSING (zone file streaming order)
// ============================================================
// 1. Window name (if name_ptr == -1)
_win_name_ptr = get(window, "name_ptr");
if (_win_name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
// 2. Window group (if group_ptr == -1)
_win_group_ptr = get(window, "group_ptr");
if (_win_group_ptr == -1) {
group = cstring() [ui, readonly, display="Group"];
}
// 3. Window background Material (if background_ptr == -1)
_win_bg_ptr = get(window, "background_ptr");
if (_win_bg_ptr == -1) {
background = parse_here("material") [display="Background"];
}
// 4. Text string (if text_ptr == -1)
if (text_ptr == -1) {
text = cstring() [ui, readonly, display="Text"];
}
// 5. Mouse/action handlers (if ptr == -1)
if (mouse_enter_text_ptr == -1) {
mouse_enter_text = cstring() [ui, readonly, display="Mouse Enter Text"];
}
if (mouse_exit_text_ptr == -1) {
mouse_exit_text = cstring() [ui, readonly, display="Mouse Exit Text"];
}
if (mouse_enter_ptr == -1) {
mouse_enter = cstring() [ui, readonly, display="Mouse Enter"];
}
if (mouse_exit_ptr == -1) {
mouse_exit = cstring() [ui, readonly, display="Mouse Exit"];
}
if (action_ptr == -1) {
action = cstring() [ui, readonly, display="Action"];
}
if (on_accept_ptr == -1) {
on_accept = cstring() [ui, readonly, display="On Accept"];
}
if (on_focus_ptr == -1) {
on_focus = cstring() [ui, readonly, display="On Focus"];
}
if (leave_focus_ptr == -1) {
leave_focus = cstring() [ui, readonly, display="Leave Focus"];
}
// 6. Dvar strings (if ptr == -1)
if (dvar_ptr == -1) {
dvar = cstring() [ui, readonly, display="Dvar"];
}
if (dvar_test_ptr == -1) {
dvar_test = cstring() [ui, readonly, display="Dvar Test"];
}
// 7. OnKey handler (if on_key_ptr == -1)
if (on_key_ptr == -1) {
on_key = parse_here("itemkeyhandler") [display="On Key"];
}
// 8. Enable dvar (if enable_dvar_ptr == -1)
if (enable_dvar_ptr == -1) {
enable_dvar = cstring() [ui, readonly, display="Enable Dvar"];
}
// 9. Focus sound (if focus_sound_ptr == -1)
if (focus_sound_ptr == -1) {
focus_sound = parse_here("sound") [display="Focus Sound"];
}
// 10. Type-specific data (typeData)
// ITEM_TYPE_LISTBOX = 6
// ITEM_TYPE_EDITFIELD = 4, NUMERICFIELD = 9, VALIDFILEFIELD = 16, DECIMALFIELD = 17, UPREDITFIELD = 18
// ITEM_TYPE_MULTI = 12
// ITEM_TYPE_DVARENUM = 13
if (type_data_ptr == -1) {
if (item_type == 6) {
type_data = parse_here("listboxdef") [display="List Box Data"];
}
if (item_type == 4 || item_type == 9 || item_type == 16 || item_type == 17 || item_type == 18) {
type_data = parse_here("editfielddef") [display="Edit Field Data"];
}
if (item_type == 12) {
type_data = parse_here("multidef") [display="Multi Data"];
}
if (item_type == 13) {
type_data = cstring() [ui, readonly, display="Enum Dvar Name"];
}
}
// ============ Expression Entries ============
// Parse expression entries for all 8 statements
// 11. Visible expression entries
_vis_num = get(visible_exp, "num_entries");
_vis_ptr = get(visible_exp, "entries_ptr");
if (_vis_ptr == -1 && _vis_num > 0) {
_vis_ptr_size = _vis_num * 4;
_vis_ptrs = read(_vis_ptr_size) [display="Visible Entry Ptrs"];
repeat(_vis_num) {
_vis_entry = parse_here("expressionentry") [display="Visible Entry"];
}
}
// 12. Text expression entries
_txt_num = get(text_exp, "num_entries");
_txt_ptr = get(text_exp, "entries_ptr");
if (_txt_ptr == -1 && _txt_num > 0) {
_txt_ptr_size = _txt_num * 4;
_txt_ptrs = read(_txt_ptr_size) [display="Text Entry Ptrs"];
repeat(_txt_num) {
_txt_entry = parse_here("expressionentry") [display="Text Entry"];
}
}
// 13. Material expression entries
_mat_num = get(material_exp, "num_entries");
_mat_ptr = get(material_exp, "entries_ptr");
if (_mat_ptr == -1 && _mat_num > 0) {
_mat_ptr_size = _mat_num * 4;
_mat_ptrs = read(_mat_ptr_size) [display="Material Entry Ptrs"];
repeat(_mat_num) {
_mat_entry = parse_here("expressionentry") [display="Material Entry"];
}
}
// 14. Rect X expression entries
_rx_num = get(rect_x_exp, "num_entries");
_rx_ptr = get(rect_x_exp, "entries_ptr");
if (_rx_ptr == -1 && _rx_num > 0) {
_rx_ptr_size = _rx_num * 4;
_rx_ptrs = read(_rx_ptr_size) [display="Rect X Entry Ptrs"];
repeat(_rx_num) {
_rx_entry = parse_here("expressionentry") [display="Rect X Entry"];
}
}
// 15. Rect Y expression entries
_ry_num = get(rect_y_exp, "num_entries");
_ry_ptr = get(rect_y_exp, "entries_ptr");
if (_ry_ptr == -1 && _ry_num > 0) {
_ry_ptr_size = _ry_num * 4;
_ry_ptrs = read(_ry_ptr_size) [display="Rect Y Entry Ptrs"];
repeat(_ry_num) {
_ry_entry = parse_here("expressionentry") [display="Rect Y Entry"];
}
}
// 16. Rect W expression entries
_rw_num = get(rect_w_exp, "num_entries");
_rw_ptr = get(rect_w_exp, "entries_ptr");
if (_rw_ptr == -1 && _rw_num > 0) {
_rw_ptr_size = _rw_num * 4;
_rw_ptrs = read(_rw_ptr_size) [display="Rect W Entry Ptrs"];
repeat(_rw_num) {
_rw_entry = parse_here("expressionentry") [display="Rect W Entry"];
}
}
// 17. Rect H expression entries
_rh_num = get(rect_h_exp, "num_entries");
_rh_ptr = get(rect_h_exp, "entries_ptr");
if (_rh_ptr == -1 && _rh_num > 0) {
_rh_ptr_size = _rh_num * 4;
_rh_ptrs = read(_rh_ptr_size) [display="Rect H Entry Ptrs"];
repeat(_rh_num) {
_rh_entry = parse_here("expressionentry") [display="Rect H Entry"];
}
}
// 18. Forecolor A expression entries
_fc_num = get(forecolor_a_exp, "num_entries");
_fc_ptr = get(forecolor_a_exp, "entries_ptr");
if (_fc_ptr == -1 && _fc_num > 0) {
_fc_ptr_size = _fc_num * 4;
_fc_ptrs = read(_fc_ptr_size) [display="Forecolor A Entry Ptrs"];
repeat(_fc_num) {
_fc_entry = parse_here("expressionentry") [display="Forecolor A Entry"];
}
}
}

View File

@ -0,0 +1,16 @@
type itemkeyhandler [display="Item Key Handler"]
{
i32 key [ui, readonly, display="Key"];
i32 action_ptr [ui, readonly, display="Action Ptr"];
i32 next_ptr [ui, readonly, display="Next Ptr"];
// Parse inline action
if (action_ptr == -1) {
action = cstring() [ui, readonly, display="Action"];
}
// Parse inline next handler (linked list)
if (next_ptr == -1) {
next = parse_here("itemkeyhandler");
}
}

View File

@ -0,0 +1,45 @@
type listboxdef [display="List Box Def"]
{
// listBoxDef_s - fixed part: 340 bytes total
i32 mouse_pos [ui, readonly, display="Mouse Pos"];
i32 start_pos [ui, readonly, display="Start Pos"];
i32 end_pos [ui, readonly, display="End Pos"];
i32 draw_padding [ui, readonly, display="Draw Padding"];
f32 element_width [ui, readonly, display="Element Width"];
f32 element_height [ui, readonly, display="Element Height"];
i32 element_style [ui, readonly, display="Element Style"];
i32 num_columns [ui, readonly, display="Num Columns"];
// columnInfo_s columnInfo[16] - 256 bytes
repeat(16) {
_col = parse_here("columninfo") [display="Column"];
}
i32 double_click_ptr [ui, readonly, display="Double Click Ptr"];
i32 not_selectable [ui, readonly, display="Not Selectable"];
i32 no_scroll_bars [ui, readonly, display="No Scroll Bars"];
i32 use_paging [ui, readonly, display="Use Paging"];
// selectBorder[4] - 16 bytes
f32 select_border_x [ui, readonly, display="Select Border X"];
f32 select_border_y [ui, readonly, display="Select Border Y"];
f32 select_border_w [ui, readonly, display="Select Border W"];
f32 select_border_h [ui, readonly, display="Select Border H"];
// disableColor[4] - 16 bytes
f32 disable_color_r [ui, readonly, display="Disable R"];
f32 disable_color_g [ui, readonly, display="Disable G"];
f32 disable_color_b [ui, readonly, display="Disable B"];
f32 disable_color_a [ui, readonly, display="Disable A"];
i32 select_icon_ptr [ui, readonly, display="Select Icon Ptr"];
// Inline data
if (double_click_ptr == -1) {
double_click = cstring() [ui, readonly, display="Double Click"];
}
if (select_icon_ptr == -1) {
select_icon = parse_here("material") [display="Select Icon"];
}
}

View File

@ -2,9 +2,25 @@ type loaded_sound [display="Loaded Sound"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
// snd_info_t structure
i32 rate [ui, readonly, display="Sample Rate"];
i32 bits [ui, readonly, display="Bits"];
i32 channels [ui, readonly, display="Channels"];
i32 samples [ui, readonly, display="Samples"];
i32 block_size [ui, readonly, display="Block Size"];
i32 format [ui, readonly, display="Format"];
i32 data_len [ui, readonly, display="Data Length"];
i32 data_ptr [ui, readonly, display="Data Ptr"];
// Parse inline name
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
// TODO: Add full loaded sound structure (audio data, format, etc.)
// Parse inline audio data
if (data_ptr == -1 && data_len > 0) {
audio_data = read(data_len) [ui, readonly, display="Audio Data"];
}
}

View File

@ -1,14 +1,19 @@
type localize [display="Localize Entry"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
}
// Value comes first in the structure
i32 value_ptr [ui, readonly, display="Value Ptr"];
// Then name
i32 name_ptr [ui, readonly, display="Name Ptr"];
// Parse inline value
if (value_ptr == -1) {
value = cstring() [ui, readonly, display="Value"];
}
// Parse inline name
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
}

View File

@ -1,79 +1,82 @@
type material [display="Material"]
{
// Parse material info inline to get material_name_ptr
// Material struct - PC COD4 format (80 bytes header)
// Verified against old XPlor C++ code and COD4x_Server source
// ============ MaterialInfo (24 bytes) ============
// Name pointer (4 bytes)
i32 material_name_ptr [ui, readonly, display="Material Name Ptr"];
// Info bytes (4 bytes): game_flags, sort_key, atlas counts
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];
// Draw surface - 8 bytes (uint64_t packed bitfield)
draw_surf = read(8) [ui, readonly, display="Draw Surf"];
// Surface type bits (4 bytes)
u32 surface_type_bits [ui, readonly, display="Surface Type Bits"];
// Hash index + padding (4 bytes)
u16 hash_index [ui, readonly, display="Hash Index"];
skip(2);
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"];
// ============ Material body (56 bytes) ============
// State bits entry array - 34 bytes (TECHNIQUE_COUNT = 34)
state_bits_entry = read(34) [ui, readonly, display="State Bits Entry"];
// Counts (6 bytes: 5 fields + 1 padding)
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);
skip(1); // padding
// Pointers to sub-assets
// Pointers (16 bytes)
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"];
// ============ Inline data (after header) ============
// 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
_name = material_name;
}
// Parse sub-assets if inline
// Parse technique set if inline
if (technique_set_ptr == -1) {
technique_set = parse_here("materialtechniqueset") [ui];
technique_set = parse_here("materialtechniqueset");
}
if (texture_table_ptr == -1) {
// Parse texture defs if inline
if (texture_table_ptr == -1 && texture_count > 0) {
texture_defs = 0;
if (texture_count > 0) {
repeat(texture_count) {
_texture_def = parse_here("materialtexturedef") [ui];
_texture_def = parse_here("materialtexturedef");
texture_defs = push("texture_defs", _texture_def);
}
}
texture_defs = texture_defs [ui];
}
if (constant_table_ptr == -1) {
// Parse constant defs if inline
if (constant_table_ptr == -1 && constant_count > 0) {
constant_defs = 0;
if (constant_count > 0) {
repeat(constant_count) {
_constant_def = parse_here("materialconstantdef") [ui];
_constant_def = parse_here("materialconstantdef");
constant_defs = push("constant_defs", _constant_def);
}
}
constant_defs = constant_defs [ui];
}
if (state_bits_table_ptr == -1) {
// Parse state bits if inline
if (state_bits_table_ptr == -1 && state_bits_count > 0) {
state_bits = 0;
if (state_bits_count > 0) {
repeat(state_bits_count) {
_state_bit = parse_here("gfxstatebits") [ui];
_state_bit = parse_here("gfxstatebits");
state_bits = push("state_bits", _state_bit);
}
}
state_bits = state_bits [ui];
}
}

View File

@ -1,7 +1,10 @@
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"];
// MaterialArgumentDef is a 4-byte union on PC:
// - float* literalConst (pointer)
// - MaterialArgumentCodeConst codeConst (u16 index + u16 firstRow)
// - u32 codeSampler
// - u32 nameHash
// We just read it as raw bytes since interpretation depends on arg type
value = read(4) [ui, readonly, display="Value"];
}

View File

@ -7,7 +7,7 @@ type materialinfo [display="Material Info"]
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];
draw_surf = parse_here("gfxdrawsurf");
u32 surface_type_bits [ui, readonly, display="Surface Type Bits"];
u16 hash_index [ui, readonly, display="Hash Index"];

View File

@ -1,23 +1,37 @@
type materialpass [display="Material Pass"]
{
// Vertex declaration
vertex_decl = parse_here("materialvertexdeclaration") [ui];
// Pointers first (header)
i32 vertex_decl_ptr [ui, readonly, display="Vertex Decl Ptr"];
i32 vertex_shader_ptr [ui, readonly, display="Vertex Shader Ptr"];
i32 pixel_shader_ptr [ui, readonly, display="Pixel Shader Ptr"];
// Vertex shader
vertex_shader = parse_here("materialvertexshader") [ui];
// Arg counts (COD4 uses u8)
u8 per_prim_arg_count [ui, readonly, display="Per Prim Arg Count"];
u8 per_obj_arg_count [ui, readonly, display="Per Obj Arg Count"];
u8 stable_arg_count [ui, readonly, display="Stable Arg Count"];
u8 custom_sampler_flags [ui, readonly, display="Custom Sampler Flags"];
// Pixel shader (reusing existing pixelshader type)
pixel_shader = parse_here("pixelshader") [ui];
i32 args_ptr [ui, readonly, display="Args Ptr"];
// Shader arguments
u8 arg_count [ui, readonly, display="Arg Count"];
u8 padding;
// Now parse inline data if pointers are -1
if (vertex_decl_ptr == -1) {
vertex_decl = parse_here("materialvertexdeclaration");
}
// Parse argument array
if (vertex_shader_ptr == -1) {
vertex_shader = parse_here("materialvertexshader");
}
if (pixel_shader_ptr == -1) {
pixel_shader = parse_here("pixelshader");
}
// Parse args if ptr is -1 (inline)
_arg_count = stable_arg_count + per_obj_arg_count + per_prim_arg_count;
if (args_ptr == -1 && _arg_count > 0) {
arguments = 0;
if (arg_count > 0) {
repeat(arg_count) {
_arg = parse_here("materialshaderargument") [ui];
repeat(_arg_count) {
_arg = parse_here("materialshaderargument");
arguments = push("arguments", _arg);
}
}

View File

@ -4,5 +4,5 @@ type materialshaderargument [display="Material Shader Argument"]
u16 dest [ui, readonly, display="Dest"];
// Argument definition
arg_def = parse_here("materialargumentdef") [ui];
arg_def = parse_here("materialargumentdef");
}

View File

@ -1,10 +1,6 @@
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;
}
// Stream routing arrays - 16 bytes each
source = read(16) [ui, readonly, display="Source"];
dest = read(16) [ui, readonly, display="Dest"];
}

View File

@ -2,21 +2,65 @@ type materialtechnique [display="Material Technique"]
{
i32 technique_name_ptr [ui, readonly, display="Technique Name Ptr"];
// Parse technique name if inline
u16 flags [ui, readonly, display="Flags"];
u16 pass_count [ui, readonly, display="Pass Count"];
// COD zone streaming order:
// 1. All pass HEADERS (20 bytes each)
// 2. Technique name (if inline)
// 3. Inline data for each pass (vertex_decl, vertex_shader, pixel_shader, args)
// First pass: Read all pass headers (20 bytes each) and store key values
// MaterialPass header = vertex_decl_ptr(4) + vertex_shader_ptr(4) + pixel_shader_ptr(4) +
// arg_counts(4) + args_ptr(4) = 20 bytes
_pass_headers_start = pos();
_pass_header_size = 20;
if (pass_count > 0) {
_total_header_bytes = pass_count * _pass_header_size;
pass_headers_raw = read(_total_header_bytes);
}
// Parse technique name (comes AFTER headers, BEFORE inline data)
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;
// Second pass: Parse inline data for each pass based on stored header values
// Just parse sequentially - data is laid out in order
if (pass_count > 0) {
repeat(pass_count) {
_pass = parse_here("materialpass") [ui];
passes = push("passes", _pass);
_base = _pass_headers_start + (_i * _pass_header_size);
_vertex_decl_ptr = i32at(_base);
_vertex_shader_ptr = i32at(_base + 4);
_pixel_shader_ptr = i32at(_base + 8);
_per_prim_arg_count = u8at(_base + 12);
_per_obj_arg_count = u8at(_base + 13);
_stable_arg_count = u8at(_base + 14);
_args_ptr = i32at(_base + 16);
// Parse vertex declaration if inline
if (_vertex_decl_ptr == -1) {
_vd = parse_here("materialvertexdeclaration");
}
// Parse vertex shader if inline
if (_vertex_shader_ptr == -1) {
_vs = parse_here("materialvertexshader");
}
// Parse pixel shader if inline
if (_pixel_shader_ptr == -1) {
_ps = parse_here("pixelshader");
}
// Parse shader arguments if inline
_arg_count = _stable_arg_count + _per_obj_arg_count + _per_prim_arg_count;
if (_args_ptr == -1 && _arg_count > 0) {
repeat(_arg_count) {
_arg = parse_here("materialshaderargument");
}
}
}
}
}

View File

@ -5,8 +5,7 @@ type materialtechniqueset [display="Material Technique Set"]
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
skip(2); // padding to align to 4 bytes (total header = 8 bytes)
// Technique count depends on game/platform
technique_count = 0;
@ -35,6 +34,19 @@ type materialtechniqueset [display="Material Technique Set"]
technique_count = technique_count [ui, readonly, display="Technique Count"];
// Check if this looks like a valid techset
// In stub/minimal techsets (like in _load files), name_ptr is often a small positive value
// indicating a reference to another zone. world_vert_format and has_been_uploaded should be 0-1.
_is_valid_techset = 1;
if (world_vert_format > 1) {
_is_valid_techset = 0;
}
if (has_been_uploaded > 1) {
_is_valid_techset = 0;
}
// Only parse technique pointers and inline data for valid techsets
if (_is_valid_techset == 1) {
// Save position after technique count
_ptrs_start_pos = pos();
@ -47,7 +59,7 @@ type materialtechniqueset [display="Material Technique Set"]
// 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;
_name = strip(technique_set_name, ",");
}
// Second pass: Parse each technique if ptr == -1 (inline)
@ -57,9 +69,10 @@ type materialtechniqueset [display="Material Technique Set"]
_ptr_offset = _ptrs_start_pos + (_i * 4);
_ptr = u32at(_ptr_offset);
if (_ptr == 4294967295) { // -1 as u32
_technique = parse_here("materialtechnique") [ui];
_technique = parse_here("materialtechnique");
techniques = push("techniques", _technique);
}
}
}
}
}

View File

@ -1,10 +1,15 @@
type materialtexturedef [display="Material Texture Def"]
{
// MaterialTextureDef - 12 bytes total
// The image pointer is just a reference to a GfxImage asset that's
// streamed separately in the zone file - NOT inline within the material
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];
// GfxImage* image - pointer to image asset (resolved elsewhere in zone)
// -1 means "needs fixup", but image data is a separate asset entry
i32 image_ptr [ui, readonly, display="Image Ptr"];
}

View File

@ -1,4 +1,9 @@
type materialtexturedefinfo [display="Material Texture Def Info"]
{
i32 texture_ptr [ui, readonly, display="Texture Ptr"];
// Parse inline image if pointer is -1
if (texture_ptr == -1) {
image = parse_here("image");
}
}

View File

@ -1,18 +1,12 @@
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;
}
// No name pointer in this structure!
u8 stream_count [ui, readonly, display="Stream Count"];
u8 has_opt_stream [ui, readonly, display="Has Opt Stream"];
u8 has_optional_source [ui, readonly, display="Has Optional Source"];
u8 is_loaded [ui, readonly, display="Is Loaded"];
skip(2); // padding
skip(1); // padding
// Vertex stream routing
routing = parse_here("materialvertexstreamrouting") [ui];
routing = parse_here("materialvertexstreamrouting");
}

View File

@ -2,12 +2,14 @@ type materialvertexshader [display="Material Vertex Shader"]
{
i32 shader_name_ptr [ui, readonly, display="Shader Name Ptr"];
// Parse shader name if inline
// Vertex shader program (parse header first)
program = parse_here("materialvertexshaderprogram");
// Parse shader name AFTER program (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];
// Note: LoadDef program data parsing happens in materialvertexshaderprogram
}

View File

@ -1,9 +1,9 @@
type materialvertexshaderprogram [display="Material Vertex Shader Program"]
{
// On PC COD4, this is just a D3D shader pointer
// No load def bytecode on PC - shaders are pre-compiled D3D bytecode
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];
}
// NOTE: On console platforms, this would have a GfxVertexShaderLoadDef
// but PC uses D3D compiled shaders directly
}

View File

@ -1,5 +1,8 @@
type materialvertexstreamrouting [display="Material Vertex Stream Routing"]
{
// Parse stream routing data
data = parse_here("materialstreamrouting") [ui];
// Stream routing data (32 bytes: source[16] + dest[16])
data = parse_here("materialstreamrouting");
// Vertex declaration pointer
i32 decl_ptr [ui, readonly, display="Decl Ptr"];
}

View File

@ -1,10 +1,67 @@
type menu [display="Menu"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
// windowDef_t embedded structure (156 bytes)
window = parse_here("windowdef");
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
i32 font_ptr [ui, readonly, display="Font Ptr"];
i32 full_screen [ui, readonly, display="Full Screen"];
i32 item_count [ui, readonly, display="Item Count"];
i32 font_index [ui, readonly, display="Font Index"];
i32 cursor_item [ui, readonly, display="Cursor Item"];
i32 fade_cycle [ui, readonly, display="Fade Cycle"];
// Fade values (3 floats = 12 bytes)
fade_values = read(12) [ui, readonly, display="Fade Clamp/Amount/InAmount"];
// Blur radius (float = 4 bytes)
blur_radius = read(4) [ui, readonly, display="Blur Radius"];
// Event handler pointers
i32 on_open_ptr [ui, readonly, display="OnOpen Ptr"];
i32 on_close_ptr [ui, readonly, display="OnClose Ptr"];
i32 on_esc_ptr [ui, readonly, display="OnESC Ptr"];
i32 on_key_ptr [ui, readonly, display="OnKey Ptr"];
i32 sound_name_ptr [ui, readonly, display="Sound Name Ptr"];
i32 items_ptr [ui, readonly, display="Items Ptr"];
i32 allowed_binding_ptr [ui, readonly, display="Allowed Binding Ptr"];
i32 sound_loop_ptr [ui, readonly, display="Sound Loop Ptr"];
i32 image_track [ui, readonly, display="Image Track"];
// Parse inline font
if (font_ptr == -1) {
font = cstring() [ui, readonly, display="Font"];
}
// TODO: Add full menu structure (items, properties, events, etc.)
// Parse inline strings
if (on_open_ptr == -1) {
on_open = cstring() [ui, readonly, display="OnOpen"];
}
if (on_close_ptr == -1) {
on_close = cstring() [ui, readonly, display="OnClose"];
}
if (on_esc_ptr == -1) {
on_esc = cstring() [ui, readonly, display="OnESC"];
}
if (on_key_ptr == -1) {
on_key = parse_here("itemkeyhandler");
}
if (sound_name_ptr == -1) {
sound_name = cstring() [ui, readonly, display="Sound Name"];
}
if (allowed_binding_ptr == -1) {
allowed_binding = cstring() [ui, readonly, display="Allowed Binding"];
}
if (sound_loop_ptr == -1) {
sound_loop = cstring() [ui, readonly, display="Sound Loop"];
}
// Parse inline items
if (items_ptr == -1 && item_count > 0) {
items = 0;
repeat(item_count) {
_item = parse_here("itemdef");
items = push("items", _item);
}
}
}

View File

@ -0,0 +1,159 @@
type menudef [display="Menu Definition"]
{
// MenuDef_t structure from OpenAssetTools IW3_Assets.h
// Fixed part: 272 bytes total
// ============ WindowDef_t embedded (156 bytes) ============
window = parse_here("windowdef") [display="Window"];
// ============ Menu Properties ============
i32 font_ptr [ui, readonly, display="Font Ptr"];
i32 full_screen [ui, readonly, display="Full Screen"];
i32 item_count [ui, readonly, display="Item Count"];
i32 font_index [ui, readonly, display="Font Index"];
i32 cursor_item [ui, readonly, display="Cursor Item"];
i32 fade_cycle [ui, readonly, display="Fade Cycle"];
// Fade values (16 bytes)
f32 fade_clamp [ui, readonly, display="Fade Clamp"];
f32 fade_amount [ui, readonly, display="Fade Amount"];
f32 fade_in_amount [ui, readonly, display="Fade In Amount"];
f32 blur_radius [ui, readonly, display="Blur Radius"];
// Event handler pointers
i32 on_open_ptr [ui, readonly, display="OnOpen Ptr"];
i32 on_close_ptr [ui, readonly, display="OnClose Ptr"];
i32 on_esc_ptr [ui, readonly, display="OnESC Ptr"];
i32 on_key_ptr [ui, readonly, display="OnKey Ptr"];
// Visible expression (statement_s = 8 bytes)
visible_exp = parse_here("statement") [display="Visible Exp"];
// More pointers
i32 allowed_binding_ptr [ui, readonly, display="Allowed Binding Ptr"];
i32 sound_name_ptr [ui, readonly, display="Sound Name Ptr"];
i32 image_track [ui, readonly, display="Image Track"];
// Focus color (16 bytes)
f32 focus_color_r [ui, readonly, display="Focus R"];
f32 focus_color_g [ui, readonly, display="Focus G"];
f32 focus_color_b [ui, readonly, display="Focus B"];
f32 focus_color_a [ui, readonly, display="Focus A"];
// Disable color (16 bytes)
f32 disable_color_r [ui, readonly, display="Disable R"];
f32 disable_color_g [ui, readonly, display="Disable G"];
f32 disable_color_b [ui, readonly, display="Disable B"];
f32 disable_color_a [ui, readonly, display="Disable A"];
// Rect expressions (2 x statement_s = 16 bytes)
rect_x_exp = parse_here("statement") [display="Rect X Exp"];
rect_y_exp = parse_here("statement") [display="Rect Y Exp"];
// Items pointer
i32 items_ptr [ui, readonly, display="Items Ptr"];
// ============================================================
// INLINE DATA PARSING (exact order from zone file streaming)
// ============================================================
// 1. Window name (if name_ptr == -1)
_win_name_ptr = get(window, "name_ptr");
if (_win_name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
// 2. Window group (if group_ptr == -1)
_win_group_ptr = get(window, "group_ptr");
if (_win_group_ptr == -1) {
group = cstring() [ui, readonly, display="Group"];
}
// 3. Window background Material (if background_ptr == -1)
_win_bg_ptr = get(window, "background_ptr");
if (_win_bg_ptr == -1) {
background = parse_here("material") [display="Background"];
}
// 4. Font (if font_ptr == -1)
if (font_ptr == -1) {
font = cstring() [ui, readonly, display="Font"];
}
// 5. OnOpen script (if on_open_ptr == -1)
if (on_open_ptr == -1) {
on_open = cstring() [ui, readonly, display="OnOpen"];
}
// 6. OnClose script (if on_close_ptr == -1)
if (on_close_ptr == -1) {
on_close = cstring() [ui, readonly, display="OnClose"];
}
// 7. OnESC script (if on_esc_ptr == -1)
if (on_esc_ptr == -1) {
on_esc = cstring() [ui, readonly, display="OnESC"];
}
// 8. OnKey handler chain (if on_key_ptr == -1)
if (on_key_ptr == -1) {
on_key = parse_here("itemkeyhandler") [display="OnKey"];
}
// 9. Visible expression entries (if entries_ptr == -1)
_vis_num = get(visible_exp, "num_entries");
_vis_ptr = get(visible_exp, "entries_ptr");
if (_vis_ptr == -1 && _vis_num > 0 ) {
// Read pointer array
_vis_ptr_size = _vis_num * 4;
_vis_ptrs = read(_vis_ptr_size) [display="Visible Entry Ptrs"];
// Parse each expression entry
repeat(_vis_num) {
_vis_entry = parse_here("expressionentry") [display="Visible Entry"];
}
}
// 10. Allowed binding (if allowed_binding_ptr == -1)
if (allowed_binding_ptr == -1) {
allowed_binding = cstring() [ui, readonly, display="Allowed Binding"];
}
// 11. Sound name (if sound_name_ptr == -1)
if (sound_name_ptr == -1) {
sound_name = cstring() [ui, readonly, display="Sound Name"];
}
// 12. Rect X expression entries (if entries_ptr == -1)
_rx_num = get(rect_x_exp, "num_entries");
_rx_ptr = get(rect_x_exp, "entries_ptr");
if (_rx_ptr == -1 && _rx_num > 0 ) {
_rx_ptr_size = _rx_num * 4;
_rx_ptrs = read(_rx_ptr_size) [display="Rect X Entry Ptrs"];
repeat(_rx_num) {
_rx_entry = parse_here("expressionentry") [display="Rect X Entry"];
}
}
// 13. Rect Y expression entries (if entries_ptr == -1)
_ry_num = get(rect_y_exp, "num_entries");
_ry_ptr = get(rect_y_exp, "entries_ptr");
if (_ry_ptr == -1 && _ry_num > 0 ) {
_ry_ptr_size = _ry_num * 4;
_ry_ptrs = read(_ry_ptr_size) [display="Rect Y Entry Ptrs"];
repeat(_ry_num) {
_ry_entry = parse_here("expressionentry") [display="Rect Y Entry"];
}
}
// 14. Items array (if items_ptr == -1 and item_count > 0)
if (items_ptr == -1 && item_count > 0 ) {
// Array of item_count pointers (4 bytes each)
_items_ptr_size = item_count * 4;
_items_ptrs = read(_items_ptr_size) [display="Item Ptrs"];
// Then item_count itemdefs follow (each -1 pointer means inline)
repeat(item_count) {
_item = parse_here("itemdef") [display="Item"];
}
}
}

View File

@ -0,0 +1,35 @@
type menulist [display="Menu List"]
{
// MenuList header (12 bytes)
i32 name_ptr [ui, readonly, display="Name Ptr"];
u32 menu_count [ui, readonly, display="Menu Count"];
i32 menus_ptr [ui, readonly, display="Menus Ptr"];
// Name string (if inline)
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
// Menu definitions (if inline)
if (menus_ptr == -1 && menu_count > 0 ) {
// First pass: parse all menu pointers
menu_ptrs = 0;
repeat(menu_count) {
_ptr = parse_here("menuptr");
menu_ptrs = push("menu_ptrs", _ptr);
}
// Second pass: parse menudefs for inline pointers
menus = 0;
repeat(menu_count) {
_ptr_obj = get(menu_ptrs, _i);
_ptr_val = get(_ptr_obj, "ptr");
if (_ptr_val == -1) {
_menu = parse_here("menudef");
menus = push("menus", _menu);
}
}
menus = menus [table="Menus", columns="name"];
}
}

View File

@ -0,0 +1,4 @@
type menuptr [display="Menu Ptr"]
{
i32 ptr [ui, readonly, display="Ptr"];
}

View File

@ -0,0 +1,51 @@
type multidef [display="Multi Def"]
{
// multiDef_s - fixed part: 392 bytes total
// const char* dvarList[32] + const char* dvarStr[32] + float dvarValue[32] + int count + int strDef
// Read all 32 dvarList pointers
i32 dvar_list_ptr_0; i32 dvar_list_ptr_1; i32 dvar_list_ptr_2; i32 dvar_list_ptr_3;
i32 dvar_list_ptr_4; i32 dvar_list_ptr_5; i32 dvar_list_ptr_6; i32 dvar_list_ptr_7;
i32 dvar_list_ptr_8; i32 dvar_list_ptr_9; i32 dvar_list_ptr_10; i32 dvar_list_ptr_11;
i32 dvar_list_ptr_12; i32 dvar_list_ptr_13; i32 dvar_list_ptr_14; i32 dvar_list_ptr_15;
i32 dvar_list_ptr_16; i32 dvar_list_ptr_17; i32 dvar_list_ptr_18; i32 dvar_list_ptr_19;
i32 dvar_list_ptr_20; i32 dvar_list_ptr_21; i32 dvar_list_ptr_22; i32 dvar_list_ptr_23;
i32 dvar_list_ptr_24; i32 dvar_list_ptr_25; i32 dvar_list_ptr_26; i32 dvar_list_ptr_27;
i32 dvar_list_ptr_28; i32 dvar_list_ptr_29; i32 dvar_list_ptr_30; i32 dvar_list_ptr_31;
// Read all 32 dvarStr pointers
i32 dvar_str_ptr_0; i32 dvar_str_ptr_1; i32 dvar_str_ptr_2; i32 dvar_str_ptr_3;
i32 dvar_str_ptr_4; i32 dvar_str_ptr_5; i32 dvar_str_ptr_6; i32 dvar_str_ptr_7;
i32 dvar_str_ptr_8; i32 dvar_str_ptr_9; i32 dvar_str_ptr_10; i32 dvar_str_ptr_11;
i32 dvar_str_ptr_12; i32 dvar_str_ptr_13; i32 dvar_str_ptr_14; i32 dvar_str_ptr_15;
i32 dvar_str_ptr_16; i32 dvar_str_ptr_17; i32 dvar_str_ptr_18; i32 dvar_str_ptr_19;
i32 dvar_str_ptr_20; i32 dvar_str_ptr_21; i32 dvar_str_ptr_22; i32 dvar_str_ptr_23;
i32 dvar_str_ptr_24; i32 dvar_str_ptr_25; i32 dvar_str_ptr_26; i32 dvar_str_ptr_27;
i32 dvar_str_ptr_28; i32 dvar_str_ptr_29; i32 dvar_str_ptr_30; i32 dvar_str_ptr_31;
// float dvarValue[32] - 128 bytes
dvar_values = read(128) [display="Dvar Values"];
i32 count [ui, readonly, display="Count"];
i32 str_def [ui, readonly, display="Str Def"];
// Parse inline dvarList strings (only for -1 pointers, up to count)
if (dvar_list_ptr_0 == -1 && count > 0) { dvar_list_0 = cstring(); }
if (dvar_list_ptr_1 == -1 && count > 1) { dvar_list_1 = cstring(); }
if (dvar_list_ptr_2 == -1 && count > 2) { dvar_list_2 = cstring(); }
if (dvar_list_ptr_3 == -1 && count > 3) { dvar_list_3 = cstring(); }
if (dvar_list_ptr_4 == -1 && count > 4) { dvar_list_4 = cstring(); }
if (dvar_list_ptr_5 == -1 && count > 5) { dvar_list_5 = cstring(); }
if (dvar_list_ptr_6 == -1 && count > 6) { dvar_list_6 = cstring(); }
if (dvar_list_ptr_7 == -1 && count > 7) { dvar_list_7 = cstring(); }
// Parse inline dvarStr strings (only for -1 pointers, up to count)
if (dvar_str_ptr_0 == -1 && count > 0) { dvar_str_0 = cstring(); }
if (dvar_str_ptr_1 == -1 && count > 1) { dvar_str_1 = cstring(); }
if (dvar_str_ptr_2 == -1 && count > 2) { dvar_str_2 = cstring(); }
if (dvar_str_ptr_3 == -1 && count > 3) { dvar_str_3 = cstring(); }
if (dvar_str_ptr_4 == -1 && count > 4) { dvar_str_4 = cstring(); }
if (dvar_str_ptr_5 == -1 && count > 5) { dvar_str_5 = cstring(); }
if (dvar_str_ptr_6 == -1 && count > 6) { dvar_str_6 = cstring(); }
if (dvar_str_ptr_7 == -1 && count > 7) { dvar_str_7 = cstring(); }
}

View File

@ -4,7 +4,7 @@ type pixelshader [display="Pixel Shader"]
i32 shader_name_ptr [ui, readonly, display="Shader Name Ptr"];
// Shader program structure
program = parse_here("pixelshaderprogram") [ui];
program = parse_here("pixelshaderprogram");
// Parse shader name if inline
if (shader_name_ptr == -1) {

View File

@ -1,9 +1,9 @@
type pixelshaderprogram [display="Pixel Shader Program"]
{
// On PC COD4, this is just a D3D shader pointer (or -1 for inline D3D shader)
// No load def bytecode on PC - shaders are pre-compiled D3D bytecode
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];
}
// NOTE: On console platforms, this would have a GfxPixelShaderLoadDef
// but PC uses D3D compiled shaders directly
}

View File

@ -1,16 +1,18 @@
type rawfile [display="Raw File"]
{
// Header: name_ptr, length, buffer_ptr (12 bytes)
i32 name_ptr [ui, readonly, display="Name Ptr"];
i32 len [ui, readonly, display="Length"];
i32 buffer_ptr [ui, readonly, display="Buffer Ptr"];
// Name string (if inline)
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = 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"];
// Data buffer (if inline) - read len + 1 bytes for null terminator
if (buffer_ptr == -1 && len > 0) {
raw_data = read(len + 1) [ui, readonly, display="Raw Data"];
}
}

View File

@ -0,0 +1,10 @@
type rectdef [display="Rect Definition"]
{
// RectDef - 24 bytes
f32 x [ui, readonly, display="X"];
f32 y [ui, readonly, display="Y"];
f32 w [ui, readonly, display="Width"];
f32 h [ui, readonly, display="Height"];
i32 horz_align [ui, readonly, display="Horz Align"];
i32 vert_align [ui, readonly, display="Vert Align"];
}

View File

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

View File

@ -0,0 +1,19 @@
type sndcurve [display="Sound Curve"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
u16 knot_count [ui, readonly, display="Knot Count"];
skip(2); // padding
i32 knots_ptr [ui, readonly, display="Knots Ptr"];
// Parse inline name
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
// Parse inline knots (each knot is 2 floats = 8 bytes)
if (knots_ptr == -1 && knot_count > 0) {
_knots_size = knot_count * 8;
knots = read(_knots_size) [ui, readonly, display="Knots"];
}
}

View File

@ -1,10 +1,21 @@
type sound [display="Sound"]
type sound [display="Sound Alias List"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
i32 head_ptr [ui, readonly, display="Head Ptr"];
i32 count [ui, readonly, display="Count"];
// Parse inline name
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
// TODO: Add full sound alias structure
// Parse inline sound aliases
if (head_ptr == -1 && count > 0) {
aliases = 0;
repeat(count) {
_alias = parse_here("soundalias");
aliases = push("aliases", _alias);
}
}
}

View File

@ -0,0 +1,75 @@
type soundalias [display="Sound Alias"]
{
i32 alias_name_ptr [ui, readonly, display="Alias Name Ptr"];
i32 subtitle_ptr [ui, readonly, display="Subtitle Ptr"];
i32 secondary_alias_name_ptr [ui, readonly, display="Secondary Alias Name Ptr"];
i32 chain_alias_name_ptr [ui, readonly, display="Chain Alias Name Ptr"];
i32 sound_file_ptr [ui, readonly, display="Sound File Ptr"];
i32 sequence [ui, readonly, display="Sequence"];
// Volume (read as raw bytes - 2 floats)
vol_min_max = read(8) [ui, readonly, display="Vol Min/Max"];
// Pitch (read as raw bytes - 2 floats)
pitch_min_max = read(8) [ui, readonly, display="Pitch Min/Max"];
// Distance (read as raw bytes - 2 floats)
dist_min_max = read(8) [ui, readonly, display="Dist Min/Max"];
// Velocity min (float)
velocity_min = read(4) [ui, readonly, display="Velocity Min"];
i32 flags [ui, readonly, display="Flags"];
// Master priority/percentage (3 floats)
master_values = read(12) [ui, readonly, display="Master Priority/Percentage"];
// Probability (float)
probability = read(4) [ui, readonly, display="Probability"];
// LFE/Center percentage (2 floats)
lfe_center = read(8) [ui, readonly, display="LFE/Center Percentage"];
i32 start_delay [ui, readonly, display="Start Delay"];
i32 volume_falloff_curve_ptr [ui, readonly, display="Volume Falloff Curve Ptr"];
// Envelope values (3 floats)
envelope_values = read(12) [ui, readonly, display="Envelope Min/Max/Percentage"];
i32 speaker_map_ptr [ui, readonly, display="Speaker Map Ptr"];
// Parse inline strings
if (alias_name_ptr == -1) {
alias_name = cstring() [ui, readonly, display="Alias Name"];
_name = alias_name;
}
if (subtitle_ptr == -1) {
subtitle = cstring() [ui, readonly, display="Subtitle"];
}
if (secondary_alias_name_ptr == -1) {
secondary_alias_name = cstring() [ui, readonly, display="Secondary Alias Name"];
}
if (chain_alias_name_ptr == -1) {
chain_alias_name = cstring() [ui, readonly, display="Chain Alias Name"];
}
// Parse inline sound file
if (sound_file_ptr == -1) {
sound_file = parse_here("soundfile");
}
// Parse inline volume falloff curve
if (volume_falloff_curve_ptr == -1) {
volume_falloff_curve = parse_here("sndcurve");
}
// Parse inline speaker map
if (speaker_map_ptr == -1) {
speaker_map = parse_here("speakermap");
}
}

View File

@ -0,0 +1,15 @@
type soundfile [display="Sound File"]
{
u8 exists [ui, readonly, display="Exists"];
u8 sound_type [ui, readonly, display="Type"];
skip(2); // padding
// Sound union - either loaded_sound or streamed
// For loaded sound:
i32 sound_ptr [ui, readonly, display="Sound Ptr"];
// Parse inline loaded sound
if (sound_ptr == -1) {
loaded_sound = parse_here("loaded_sound");
}
}

View File

@ -0,0 +1,18 @@
type speakermap [display="Speaker Map"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
u8 is_default [ui, readonly, display="Is Default"];
skip(3); // padding
i32 channel_maps_ptr [ui, readonly, display="Channel Maps Ptr"];
// Parse inline name
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
// Channel maps (2 entries of SpeakerChannelMap, each 16 bytes)
if (channel_maps_ptr == -1) {
channel_maps = read(32) [ui, readonly, display="Channel Maps"];
}
}

View File

@ -0,0 +1,17 @@
type statement [display="Statement"]
{
// statement_s - 8 bytes header ONLY
// Expression entries are parsed by the parent type (menudef/itemdef)
// at the correct position in the zone streaming order
//
// When entries_ptr == -1 (inline), the parent must parse:
// 1. Array of numEntries pointers (4 bytes each)
// 2. For each pointer, an expressionEntry (12 bytes)
// 3. For string operands with -1 value, inline string
i32 num_entries [ui, readonly, display="Num Entries"];
i32 entries_ptr [ui, readonly, display="Entries Ptr"];
// Expression entries are NOT parsed here because they follow
// other inline data in the parent struct's streaming order
}

View File

@ -2,34 +2,29 @@ type stringtable_asset [display="String Table"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
i32 column_count [ui, readonly, display="Column Count"];
i32 row_count [ui, readonly, display="Row Count"];
i32 values_ptr [ui, readonly, display="Values Ptr"];
// Parse inline name
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = 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"];
cell_count = row_count * column_count;
// Read all cell pointers and values in one pass
// First read all cell pointers (each is 4 bytes)
_cell_ptrs_size = cell_count * 4;
cell_ptrs = read(_cell_ptrs_size) [ui, readonly, display="Cell Pointers"];
// Then read all cell string values
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"];
_cell_value = cstring();
cells = push("cells", _cell_value);
}
}
}

View File

@ -0,0 +1,47 @@
type sunflare [display="Sun Flare"]
{
u8 has_valid_data [ui, readonly, display="Has Valid Data"];
skip(3); // padding
i32 sprite_material_ptr [ui, readonly, display="Sprite Material Ptr"];
i32 flare_material_ptr [ui, readonly, display="Flare Material Ptr"];
// Sprite/flare params (floats)
sprite_size = read(4) [ui, readonly, display="Sprite Size"];
flare_min_size = read(4) [ui, readonly, display="Flare Min Size"];
flare_min_dot = read(4) [ui, readonly, display="Flare Min Dot"];
flare_max_size = read(4) [ui, readonly, display="Flare Max Size"];
flare_max_dot = read(4) [ui, readonly, display="Flare Max Dot"];
flare_max_alpha = read(4) [ui, readonly, display="Flare Max Alpha"];
i32 flare_fade_in_time [ui, readonly, display="Flare Fade In Time"];
i32 flare_fade_out_time [ui, readonly, display="Flare Fade Out Time"];
// Blind params
blind_min_dot = read(4) [ui, readonly, display="Blind Min Dot"];
blind_max_dot = read(4) [ui, readonly, display="Blind Max Dot"];
blind_max_darken = read(4) [ui, readonly, display="Blind Max Darken"];
i32 blind_fade_in_time [ui, readonly, display="Blind Fade In Time"];
i32 blind_fade_out_time [ui, readonly, display="Blind Fade Out Time"];
// Glare params
glare_min_dot = read(4) [ui, readonly, display="Glare Min Dot"];
glare_max_dot = read(4) [ui, readonly, display="Glare Max Dot"];
glare_max_lighten = read(4) [ui, readonly, display="Glare Max Lighten"];
i32 glare_fade_in_time [ui, readonly, display="Glare Fade In Time"];
i32 glare_fade_out_time [ui, readonly, display="Glare Fade Out Time"];
// Sun FX position (3 floats)
sun_fx_position = read(12) [ui, readonly, display="Sun FX Position"];
// Parse materials if inline
if (sprite_material_ptr == -1) {
sprite_material = parse_here("material");
}
if (flare_material_ptr == -1) {
flare_material = parse_here("material");
}
}

View File

@ -0,0 +1,21 @@
type sunlightparseparams [display="Sun Light Parse Params"]
{
// PC version: Fixed 128-byte struct (embedded in GfxWorld header)
// Name is a fixed 64-byte char array, NOT a pointer!
name = read(64) [ui, readonly, display="Name"];
// Ambient settings
ambient_scale = read(4) [ui, readonly, display="Ambient Scale"];
ambient_color = read(12) [ui, readonly, display="Ambient Color"];
// Diffuse/Sun settings
diffuse_fraction = read(4) [ui, readonly, display="Diffuse Fraction"];
sun_light = read(4) [ui, readonly, display="Sun Light"];
sun_color = read(12) [ui, readonly, display="Sun Color"];
diffuse_color = read(12) [ui, readonly, display="Diffuse Color"];
// Flags and angles
u8 diffuse_color_has_been_set [ui, readonly, display="Diffuse Color Has Been Set"];
skip(3); // padding
angles = read(12) [ui, readonly, display="Angles"];
}

View File

@ -1,10 +1,121 @@
type weapon [display="Weapon"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
// WeaponDef is extremely large in CoD4 (1000+ bytes)
// This is a simplified version focusing on the key fields
i32 name_ptr [ui, readonly, display="Name Ptr"];
i32 display_name_ptr [ui, readonly, display="Display Name Ptr"];
i32 ai_overlay_description_ptr [ui, readonly, display="AI Overlay Desc Ptr"];
// Gun model pointers
i32 gun_model_ptr [ui, readonly, display="Gun Model Ptr"];
i32 hand_model_ptr [ui, readonly, display="Hand Model Ptr"];
// Mode name (for alternate fire modes)
i32 mode_name_ptr [ui, readonly, display="Mode Name Ptr"];
// Player anim type
i32 player_anim_type [ui, readonly, display="Player Anim Type"];
// Weapon type and class
i32 weapon_type [ui, readonly, display="Weapon Type"];
i32 weapon_class [ui, readonly, display="Weapon Class"];
i32 penetrate_type [ui, readonly, display="Penetrate Type"];
i32 impact_type [ui, readonly, display="Impact Type"];
i32 inventory_type [ui, readonly, display="Inventory Type"];
i32 fire_type [ui, readonly, display="Fire Type"];
// Offhand class
i32 offhand_class [ui, readonly, display="Offhand Class"];
// Stance
i32 stance [ui, readonly, display="Stance"];
// View model pointers
i32 view_flash_effect_ptr [ui, readonly, display="View Flash Effect Ptr"];
i32 world_flash_effect_ptr [ui, readonly, display="World Flash Effect Ptr"];
// Sounds
i32 pickup_sound_ptr [ui, readonly, display="Pickup Sound Ptr"];
i32 pickup_sound_player_ptr [ui, readonly, display="Pickup Sound Player Ptr"];
i32 ammo_pickup_sound_ptr [ui, readonly, display="Ammo Pickup Sound Ptr"];
i32 ammo_pickup_sound_player_ptr [ui, readonly, display="Ammo Pickup Sound Player Ptr"];
i32 projectile_sound_ptr [ui, readonly, display="Projectile Sound Ptr"];
i32 pullback_sound_ptr [ui, readonly, display="Pullback Sound Ptr"];
i32 pullback_sound_player_ptr [ui, readonly, display="Pullback Sound Player Ptr"];
i32 fire_sound_ptr [ui, readonly, display="Fire Sound Ptr"];
i32 fire_sound_player_ptr [ui, readonly, display="Fire Sound Player Ptr"];
i32 fire_loop_sound_ptr [ui, readonly, display="Fire Loop Sound Ptr"];
i32 fire_loop_sound_player_ptr [ui, readonly, display="Fire Loop Sound Player Ptr"];
i32 fire_stop_sound_ptr [ui, readonly, display="Fire Stop Sound Ptr"];
i32 fire_stop_sound_player_ptr [ui, readonly, display="Fire Stop Sound Player Ptr"];
i32 fire_last_sound_ptr [ui, readonly, display="Fire Last Sound Ptr"];
i32 fire_last_sound_player_ptr [ui, readonly, display="Fire Last Sound Player Ptr"];
i32 empty_fire_sound_ptr [ui, readonly, display="Empty Fire Sound Ptr"];
i32 empty_fire_sound_player_ptr [ui, readonly, display="Empty Fire Sound Player Ptr"];
i32 melee_swipe_sound_ptr [ui, readonly, display="Melee Swipe Sound Ptr"];
i32 melee_swipe_sound_player_ptr [ui, readonly, display="Melee Swipe Sound Player Ptr"];
i32 melee_hit_sound_ptr [ui, readonly, display="Melee Hit Sound Ptr"];
i32 melee_miss_sound_ptr [ui, readonly, display="Melee Miss Sound Ptr"];
i32 rechamber_sound_ptr [ui, readonly, display="Rechamber Sound Ptr"];
i32 rechamber_sound_player_ptr [ui, readonly, display="Rechamber Sound Player Ptr"];
i32 reload_sound_ptr [ui, readonly, display="Reload Sound Ptr"];
i32 reload_sound_player_ptr [ui, readonly, display="Reload Sound Player Ptr"];
i32 reload_empty_sound_ptr [ui, readonly, display="Reload Empty Sound Ptr"];
i32 reload_empty_sound_player_ptr [ui, readonly, display="Reload Empty Sound Player Ptr"];
i32 reload_start_sound_ptr [ui, readonly, display="Reload Start Sound Ptr"];
i32 reload_start_sound_player_ptr [ui, readonly, display="Reload Start Sound Player Ptr"];
i32 reload_end_sound_ptr [ui, readonly, display="Reload End Sound Ptr"];
i32 reload_end_sound_player_ptr [ui, readonly, display="Reload End Sound Player Ptr"];
i32 deploy_sound_ptr [ui, readonly, display="Deploy Sound Ptr"];
i32 deploy_sound_player_ptr [ui, readonly, display="Deploy Sound Player Ptr"];
i32 finish_deploy_sound_ptr [ui, readonly, display="Finish Deploy Sound Ptr"];
i32 finish_deploy_sound_player_ptr [ui, readonly, display="Finish Deploy Sound Player Ptr"];
i32 breakdown_sound_ptr [ui, readonly, display="Breakdown Sound Ptr"];
i32 breakdown_sound_player_ptr [ui, readonly, display="Breakdown Sound Player Ptr"];
i32 finish_breakdown_sound_ptr [ui, readonly, display="Finish Breakdown Sound Ptr"];
i32 finish_breakdown_sound_player_ptr [ui, readonly, display="Finish Breakdown Sound Player Ptr"];
i32 detonate_sound_ptr [ui, readonly, display="Detonate Sound Ptr"];
i32 detonate_sound_player_ptr [ui, readonly, display="Detonate Sound Player Ptr"];
i32 night_vision_wear_sound_ptr [ui, readonly, display="Night Vision Wear Sound Ptr"];
i32 night_vision_wear_sound_player_ptr [ui, readonly, display="Night Vision Wear Sound Player Ptr"];
i32 night_vision_remove_sound_ptr [ui, readonly, display="Night Vision Remove Sound Ptr"];
i32 night_vision_remove_sound_player_ptr [ui, readonly, display="Night Vision Remove Sound Player Ptr"];
i32 alt_switch_sound_ptr [ui, readonly, display="Alt Switch Sound Ptr"];
i32 alt_switch_sound_player_ptr [ui, readonly, display="Alt Switch Sound Player Ptr"];
i32 raise_sound_ptr [ui, readonly, display="Raise Sound Ptr"];
i32 raise_sound_player_ptr [ui, readonly, display="Raise Sound Player Ptr"];
i32 first_raise_sound_ptr [ui, readonly, display="First Raise Sound Ptr"];
i32 first_raise_sound_player_ptr [ui, readonly, display="First Raise Sound Player Ptr"];
i32 put_away_sound_ptr [ui, readonly, display="Put Away Sound Ptr"];
i32 put_away_sound_player_ptr [ui, readonly, display="Put Away Sound Player Ptr"];
// Read remaining weapon data as raw bytes
// The full structure has many more fields (damage, range, spread, etc.)
// This reads enough to cover the core structure (around 800+ more bytes)
weapon_data = read(800) [ui, readonly, display="Weapon Data"];
// Parse inline name
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
// TODO: Add full weapon definition structure (stats, animations, effects, etc.)
// Parse inline display name
if (display_name_ptr == -1) {
display_name = cstring() [ui, readonly, display="Display Name"];
}
// Parse inline AI overlay description
if (ai_overlay_description_ptr == -1) {
ai_overlay_description = cstring() [ui, readonly, display="AI Overlay Description"];
}
// Parse inline mode name
if (mode_name_ptr == -1) {
mode_name = cstring() [ui, readonly, display="Mode Name"];
}
// Note: Many more inline assets would follow (models, effects, sounds, etc.)
// This is a simplified version
}

View File

@ -0,0 +1,58 @@
type windowdef [display="Window Definition"]
{
// WindowDef structure - 156 bytes total (fixed part only)
// Inline data (name, group, background) parsed by menudef after
// Name pointer (4 bytes)
i32 name_ptr [ui, readonly, display="Name Ptr"];
// Primary rect (24 bytes)
rect = parse_here("rectdef") [display="Rect"];
// Client rect (24 bytes)
rect_client = parse_here("rectdef") [display="Rect Client"];
// Group pointer (4 bytes)
i32 group_ptr [ui, readonly, display="Group Ptr"];
// Style properties (16 bytes)
i32 style [ui, readonly, display="Style"];
i32 border [ui, readonly, display="Border"];
i32 owner_draw [ui, readonly, display="Owner Draw"];
i32 owner_draw_flags [ui, readonly, display="Owner Draw Flags"];
// Border size float (4 bytes)
f32 border_size [ui, readonly, display="Border Size"];
// Flags (12 bytes)
i32 static_flags [ui, readonly, display="Static Flags"];
i32 dynamic_flags [ui, readonly, display="Dynamic Flags"];
i32 next_time [ui, readonly, display="Next Time"];
// Fore color (16 bytes)
f32 fore_color_r [ui, readonly, display="Fore R"];
f32 fore_color_g [ui, readonly, display="Fore G"];
f32 fore_color_b [ui, readonly, display="Fore B"];
f32 fore_color_a [ui, readonly, display="Fore A"];
// Back color (16 bytes)
f32 back_color_r [ui, readonly, display="Back R"];
f32 back_color_g [ui, readonly, display="Back G"];
f32 back_color_b [ui, readonly, display="Back B"];
f32 back_color_a [ui, readonly, display="Back A"];
// Border color (16 bytes)
f32 border_color_r [ui, readonly, display="Border R"];
f32 border_color_g [ui, readonly, display="Border G"];
f32 border_color_b [ui, readonly, display="Border B"];
f32 border_color_a [ui, readonly, display="Border A"];
// Outline color (16 bytes)
f32 outline_color_r [ui, readonly, display="Outline R"];
f32 outline_color_g [ui, readonly, display="Outline G"];
f32 outline_color_b [ui, readonly, display="Outline B"];
f32 outline_color_a [ui, readonly, display="Outline A"];
// Background material pointer (4 bytes)
i32 background_ptr [ui, readonly, display="Background Ptr"];
}

View File

@ -2,11 +2,49 @@ type xmodel [display="XModel"]
{
i32 name_ptr [ui, readonly, display="Name Ptr"];
u8 num_bones [ui, readonly, display="Num Bones"];
u8 num_root_bones [ui, readonly, display="Num Root Bones"];
u8 num_surfaces [ui, readonly, display="Num Surfaces"];
i8 lod_ramp_type [ui, readonly, display="LOD Ramp Type"];
// Model surfaces pointers (4 LODs)
i32 model_surfs_ptr_0 [ui, readonly, display="Model Surfs Ptr LOD0"];
i32 model_surfs_ptr_1 [ui, readonly, display="Model Surfs Ptr LOD1"];
i32 model_surfs_ptr_2 [ui, readonly, display="Model Surfs Ptr LOD2"];
i32 model_surfs_ptr_3 [ui, readonly, display="Model Surfs Ptr LOD3"];
// LOD info (4 floats = 16 bytes)
lod_info = read(16) [ui, readonly, display="LOD Info"];
i32 coll_surfs_ptr [ui, readonly, display="Coll Surfs Ptr"];
i32 num_coll_surfs [ui, readonly, display="Num Coll Surfs"];
i32 contents [ui, readonly, display="Contents"];
i32 bone_info_ptr [ui, readonly, display="Bone Info Ptr"];
// Bounds (6 floats = 24 bytes for mins + maxs)
bounds = read(24) [ui, readonly, display="Bounds"];
// Radius (float)
radius = read(4) [ui, readonly, display="Radius"];
i32 phys_preset_ptr [ui, readonly, display="Phys Preset Ptr"];
i32 phys_collmap_ptr [ui, readonly, display="Phys Collmap Ptr"];
u16 flags [ui, readonly, display="Flags"];
skip(2); // padding
// Parse inline name
if (name_ptr == -1) {
name = cstring() [ui, readonly, display="Name"];
_name = name;
}
// TODO: Add full XModel structure
// For now, just read the name as a placeholder
// Full structure includes: LODs, surfaces, bones, collision, etc.
// Note: Full XModel inline parsing would require:
// - XModelSurfs for each LOD
// - XBoneInfo array
// - Collision surfaces
// - Physics preset
// - Physics collision map
// These are complex nested structures
}