Unofficial MARATHON Specs release version v0.0 - January 19, 1995 brought to you by: freidin@phoenix.princeton.edu (Bernie Freidin) special thanks to: pjcreath@phoenix.princeton.edu (Peter Creath) omv@cool-toys.mit.edu (Danimal) bhines@sdcc13.ucsd.edu (Clef) MORBID@resnova.com ...and of course: jon3@quads.uchicago.edu (Jason Jones) ------------------------------------------------------------------------------ GENERAL INFORMATION ------------------------------------------------------------------------------ Marathon consists of the following files: %"Marathon" (application program) %"Shapes" (contains graphics) %"Sounds" (contains sounds) %"Map" (contains level information) %"Music" (contains music information, but *not* the samples of the notes) %"Physics Model" (optional - contains physics information) %saved games (contains mostly level information) %films (contains sequence of keystrokes) The following information is contained in each file: "Marathon" (type 'APPL', creator '26.2') Program code, and the usual assortment of resources found in most Mac applications. The only interesting things here are the resources of type 'term', which contain the text displayed on the computer terminals in the game. "Shapes" (type 'shps') All graphic data for textures, sprites, and interfaces, stored as resources of type '.256'. There are also 'clut' resources (color tables), and 'PICT' resources that contain the pictures displayed between levels. I'm not sure whether the color tables here are used, or the color tables stored in the main application. See below for more information on the format of '.256' resources. "Sounds" (type 'sndz') All game sounds. These are stored as ordinary Mac 'snd ' resources, of format 1. See Inside Macintosh for more information. "Map" (type 'scen') Map information for all levels, stored in the data fork. See below for more information. "Music" (type 'msik') Music sequencing information, stored in the data fork. Exact format unknown, but is supposedly it is some form of MIDI . "Physics Model" (type 'phys') Physical infomation, stored in the data fork. There is also a 'text' resource put in by Jason giving a short description of some of the format for this file. See below for more information. saved games (type 'sgam') Same information as "Map" files, stored in the data fork. There should be only one level, however, and the 'EPNT' chunk is replaced by a 'PNTS' chunk (see below). Also contained in these files is a 'PICT' resource of a portion of the level map (as seen in the preview box), and a 'STR ' resource containing the level name. films (type 'film') Contains keystroke information necessary to replay a game. Exact format unknown. #define NONE -1 typedef long fixed; typedef unsigned short angle; typedef struct shape_descriptor { char set; char frame; }; typedef short world_distance; typedef struct world_point2d { world_distance x, y; }; ------------------------------------------------------------------------------ SHAPES INFORMATION ------------------------------------------------------------------------------ Header format: Each '.256' resource starts with a 544 byte header: enum /* shapes classes */ { _shapeUnused, _shapeTexture, /* RAW */ _shapeSprite, /* RLE */ _shapeInterface, /* RAW */ _shapeScenery /* RLE */ }; %_shapeUnused: not used %_shapeTexture: usually 128x128 pixels, but not always %_shapeSprite: all monsters, guns, objects.. %_shapeInterface: everything that doesn't go in the window %_shapeScenery: ??? struct shapes_header /* 544 bytes */ { short type; short class; unsigned short flags; short color_count; short palette_count; long first_palette_address; short high_level_shapes_count; long high_level_shapes_table; short low_level_shapes_count; long low_level_shapes_table; short image_count; long image_table; short scale_factor; long size; short unused[253]; }; %type: always equals 3 %class: see above %flags: %color_count: number of color entries in each palette %palette_count: number of palettes (different palettes are used for different "variations" of monsters) %first_palette_address: offset to first palette %high_level_shapes_count: number of high-level shapes %high_level_shapes_table: offset to table of addresses of high-level shape records %low_level_shapes_count: number of low-level shapes %low_level_shapes_table: offset to table of addresses of low-level shape records %image_count: number of images %image_table: offset to table of addresses of images %size: size of entire resource Palettes: Each palette contain color_count entries, where each entry has the following structure: struct color_entry /* 8 bytes */ { short entry_number; /* ranges from 0 to color_count - 1 */ unsigned short red; unsigned short green; unsigned short blue; }; The palettes are stored consecutively with no gaps between. High-level shapes: These describe an entire animated sequence, complete with sound effects and frame rate information. The exact format is as follows: enum /* high-level shape flags */ { }; enum /* high-level shape types */ { }; struct high_level_shape /* 88 bytes */ { short type; unsigned short flags; char name_length; char name[33]; short view_count; short frames_per_view; short ticks_per_frame; short key_frame; short transfer_mode; short transfer_mode_period; /* in ticks */ short first_frame_sound; short key_frame_sound; short last_frame_sound; short scale_factor; short unused[15]; //frame information }; %type: see above %flags: see above %name_length: length of name string (i.e. this is a Pascal string) %name: ASCII string %view_count: number of angles at which this animation can be viewed. This should only be 1, 2, 5, or 8. %frames_per_view: number of frames of animation %ticks_per_frame: speed of animation %key_frame: frame at which "something happens"? %transfer_mode: %transfer_mode_period: absolutely no idea.. %first_frame_sound: 'snd ' resource to play at start of animation %key_frame_sound: 'snd ' resource to play at key frame %last_frame_sound: 'snd ' resource to play at end of animation %scale_factor: After this comes the frame information, which is a series of 2-byte words, each corresponding to a low-level shape. There will be view_count * frames_per_view entries, followed by 2 bytes of zero signifying to end of the animation. Note that if view_count equals 5, then it's really 8 * frames_per_view entries. Low-level shapes: These describe just one non-animated sprite, or one frame of an animated sequence. The exact format is as follows: enum /* low-level shape flags */ { _lowShapeXMirror = 0x8000, _lowShapeYMirror = 0x4000, _lowShapeKeyObscure = 0x2000 } %_lowShapeXMirror: indicates that the sprite is to be drawn from right to left rather than left to right %_lowShapeYMirror: similar to _lowShapeXMirror, but affects drawing vertically rather than horizontally. It doesn't seem to be implemented %_lowShapeKeyObscure: ??? struct low_level_shape /* 36 bytes */ { unsigned short flags; fixed minimum_light_intensity; short image_index; short x_origin, y_origin; short x_key, y_key; short left, right, top, bottom; short world_x_origin, world_y_origin; short unused[4]; }; %flags: see above %minimum_light_intensity: minimum light value that can be assigned to this image. Used for "bright" sprites, such as explosions, that are never supposed to be dark. %image_index: indicates which image is used to draw this low-level shape %x_origin, y_origin: center of shape? Who knows.. %x_key, y_key: no idea.. %left, top, right, bottom: defines the bounding rectangle? %world_x_origin, world_y_origin: no idea.. Images: These contain the actual graphic data for the images. First is a header, then follows the scan start address table, and then the pixel data. The exact format of the pixel data depends on the type of shape (RAW or RLE). struct image_header /* 26 bytes */ { short width; short height; short unknown[11]; /* ??? */ }; %width: width of image %height: height of image Next comes the scan start addresses. These are run-time calculated, so there is no need to provide valid information here. However, the right amount of space must be reserved for this block. The size of the block will be width * 4, plus 4 bytes at the end (unknown?). And finally comes the actual image data. In RAW format, this is just a block of bytes, where each byte corresponds to one pixel. The pixels are stored top to bottom, then right to left. The color of a pixel can be determined by using the pixel value as an index into the palette. RLE format is a little different. It starts with a 2-byte command word. If this word is greater than zero, it signifies the start of a vertical run of pixels. The pixel data follows immediately, and the number of pixels is equal to the command word. If the command word is negative, it signifies the start of a vertical "skip" in which no pixels are drawn (a hole). The length of the skip will be equal to negative the value of the command word. If the command word is zero, it signifies the start of the next vertical column, which will start one pixel to the right of the start of the first column. The command words are repeated until the entire sprite is drawn. ------------------------------------------------------------------------------ PHYSICS MODEL INFORMATION ------------------------------------------------------------------------------ The Physics Model contains information on gravity, weapon speed, monster behavior, and many other things. I'm not sure where the default physics information is stored (there doesn't appear to be any in the Marathon application, nor the Map files..). Like the Map file, the Physics Model is made up of a number of "chunks", each of which contains a number of "entries". The following chunk types are known: Chunk types: 'mons': Monster information 'effe': Effect information 'proj': Projectile information 'phys': Physics information 'weap': Weapon information Each chunk starts with a header, which has the following format: struct physics_chunk_header /* 12 bytes */ { long chunk_type; short unused[2]; short entry_count; short entry_size; }; %chunk_type: 4 character ASCII string signifying chunk type %entry_count: number of entries in chunk %entry_size: size of each entry Why do the Physics Model chunks follow a different format from the Map chunks? ------------------------------------------------------------------------------ 'mons' chunk: ------------------------------------------------------------------------------ The Monster chunk defines every monster in the game, including non-hostiles. A couple of things to note - first, different 'colored' monsters are defined seperately. Second, the monster chunk references the effects chunk for animations when they get hit, the projectile chunk for the projectiles they shoot (in the attack structure), and the shapes directly for their moving shapes. enum /* monster flags */ { _monsterOmniscent = 0x00000001, _monsterFly = 0x00000002, _monsterAlien = 0x00000004, _monsterMajor = 0x00000008, _monsterMinor = 0x00000010, _monsterNoDrop = 0x00000020, _monsterFloat = 0x00000040, _monsterNoAttack = 0x00000080, _monsterSnipe = 0x00000100, _monsterInvisible = 0x00000200, _monsterSubInvisible = 0x00000400, _monsterKamakazi = 0x00000800, _monsterBerserk = 0x00001000, _monsterEnlarged = 0x00002000, _monsterDelayedHardDeath = 0x00004000, _monsterFiresSymmetrically = 0x00008000, _monsterNuclearHardDeath = 0x00010000, _monsterNoFireBackwards = 0x00020000, _monsterFlammable = 0x00040000 }; %_monsterOmniscent: %_monsterFly: monster can fly %_monsterAlien: moves slower on lower levels %_monsterMajor: type -1 is minor? %_monsterMinor: type +1 is major? %_monsterNoDrop: low levels cannot skip monster %_monsterFloat: %_monsterNoAttack: civilian, constantly runs to safety %_monsterSnipe: use long range weapon to attack from ledges %_monsterInvisible: monster is invisible %_monsterSubInvisible: monster is partially invisible %_monsterKamakazi: explodes if close to player, causing damage %_monsterBerserk: goes berserk when below 25% vitality %_monsterEnlarged: 25% larger %_monsterDelayedHardDeath: always dies soft, then switches to hard? %_monsterFiresSymmetrically: %_monsterNuclearHardDeath: screen turns white and slowly recovers %_monsterNoFireBackwards: can't turn more than 135 degrees to fire %_monsterFlammable: susceptible to flame unit Monsters unable to open doors have door retry masks of NONE Monsters unable to switch levels have min,max ledge deltas of 0 Monsters unstopped by bullets have hit frames of NONE enum /* attack types */ { }; struct attack_struct /* 16 bytes */ { short type; short repetitions; angle error; world_distance range; short attack_shape; world_distance dx; world_distance dy; world_distance dz; }; %type: see above %repetitions: number of repetitions of attack %error: error added to firing angle %range: range of attack %attack_shape: attack occurs when keyframe is displayed %dx,dy,dz: attack vector (dx=out,dy=right,dz=up) enum /* damage flags */ { }; enum /* damage types */ { }; struct damage_struct /* 12 bytes */ { short type; unsigned short flags; short base; short random; fixed scale; }; %type: see above %flags: see above %base: base damage %random: random factor %scale: ?? struct monster_entry /* 138 bytes */ { short collection; short vitality; unsigned long immunities; unsigned long weaknesses; unsigned long flags; long class; unsigned long friends; unsigned long enemies; short activation_sound; short conversation_sound; short flaming_sound; short random_sound; short random_sound_mask; short carrying_item_type; world_distance radius; world_distance height; world_distance preferred_hover_height; world_distance minimum_ledge_delta; world_distance maximum_ledge_delta; fixed external_velocity_scale; short impact_effect; short melee_impact_effect; short half_visual_arc; short half_vertical_visual_arc; world_distance visual_range; world_distance dark_visual_range; short intelligence; short speed; short gravity; short terminal_velocity; short door_retry_mask; short shrapnel_radius; /* no shapnel if NONE */ struct damage_struct shrapnel_damage; shape_descriptor hit_shapes; shape_descriptor hard_dying_shape; /* minus dead frame */ shape_descriptor soft_dying_shape; /* minus dead frame */ shape_descriptor hard_dead_shapes; /* NONE = vanishing */ shape_descriptor soft_dead_shapes; /* NONE = vanishing */ shape_descriptor stationary_shape; shape_descriptor moving_shape; short attack_frequency; struct attack_struct melee_attack; struct attack_struct ranged_attack; }; %collection: %vitality: How much damage the monter can sustain %immunities: mask of what the monster is immune to %weaknesses: mask of what the monster is susceptible to %flags: %class: bit of which class the monster belongs to %friends: mask of friend classes %enemies: mask of enemy classes %activation_sound: sound made when monster is generated %conversation_sound: sound made in conversation (?) %flaming_sound: sound made when the monster gets TOZT'ed %random_sound: randomly played sound (?) %random_sound_mask: mask of when to play sound (??) %carrying_item: something the monster will drop (ex: alien weapon) %radius: radius of monster %height: height of monster %preffered_hover_height: height at which the monsters 'likes' to fly %maximum_ledge_delta: the maximum a monster can 'climb' up %minimum_ledge_delta: the maximum a monster can 'climb' down %external_velocity_scale: No idea (?!?!?) %impact effect: effeect to play when monster hits person {kamikazee?} %melee_impact_effect: effect to play when monster whacks person %half_visual_arc: horizontal visual range {side-to-side vision} %half_vertical_visual_arc: vertical visual range {up-down vision} %visual_range: range at which the monster can 'see' something %dark_visual_range: range at which monster can see in the 'dark' (?) %intelligence: hmmm... (???) %speed: how fast the monster goes %gravity: acceleration on falling monster (?) %terminal_velocity: maximum fall rate (?) %door_retry_mask: something to do with doors - which they can open? (??) %shrapnel_radius: blast radius when self destructing %shrapnel_damage: damage structure for self destruction %hit_shapes: shapes of monster being hit by bullets %hard/soft_dying_shape: shape of monster dying %hard/soft_dead_shape: shape of dead monster on floor %stationary_shape: monster not moving {sitting down, etc} %moving_shape: normal monster in motion %attack_frequency: how many ticks between attacks - melee is twice as often as ranged %melee_attack: attack structure for melee attacks %ranged_attack: attack structure for ranged attacks ------------------------------------------------------------------------------ 'effe' chunk: ------------------------------------------------------------------------------ This is all guesswork I've got from playing with the effects a bit. I'm not certain what the hell the flags are, although they always seem to be either 0 or 4..? struct effect_entry /* 138 bytes */ { short collection; short shape; short flags; } %collection: Which collection the effect is from %animation: which animation it is %flags: unknown (???) ------------------------------------------------------------------------------ 'proj' chunk: ------------------------------------------------------------------------------ Projectiles are the bullets that everyone fires. No rocket science here. enum /* projectile flags */ { _projectileGuided = 0x0001, _projectileNoAnimation = 0x0002, _projectilePersistent = 0x0004, _projectileAlien = 0x0008, _projectileGravity = 0x0010, _projectileNoHErr = 0x0020, _projectileNoVErr = 0x0040, _projectileHitSwitch = 0x0080, _projectilePositiveVErr = 0x0100, _projectileMelee = 0x0200 }; %_projectileGuided: tracks targets apparently - useless for user weapons at the moment %_projectileNoAnimation: projectile stops when animation loops - ex flamethrower %_projectilePersistent: ??? %_projectileAlien: does less damage and moves slower on lower levels %_projectileGravity: projectile is affected by gravity %_projectileNoHErr: no horizontal error - spread is entirely vertical %_projectileNoVErr: no vertical error - spead is entirely horizontal %_projectileHitSwitch: projectile can toggle switches %_projectilePositiveVErr: positive vertical error - only shoots high? (??) %_projectileMelee: can use a monster's custom melee detonation (??) struct projectile_entry /* 36 bytes */ { short collection; short shape_index; short detonation_effect; short contrail_effect; short ticks_between_contrails; short maximum_contrails; world_distance radius; world_distance area_of_effect; short damage_type; short damage_flags; short damage_base, damage_random fixed damage_scale; word flags; world_distance speed; world_distance maximum_range; short flyby_sound; }; %collection: if -1 (NONE), then this is invisible %maximum_contrails: how many contrails will be left. if -1 (NONE), then this is treated as infinite %radius: proximity radius - can be zero and will still hit %area_of_effect: detonation radius - one target if = 0 ------------------------------------------------------------------------------ 'weap' chunk: ------------------------------------------------------------------------------ Lots of stuff to play with here. Unfortunately, it seems like a fair amount of stuff is hardcoded, like where ammo is displayed, ammo shapes on the screen, weapon names, etc. struct weapon_entry /* 120 bytes */ { short type; short class; unsigned short flags; short ammunition_type; short rounds_per_magazine; short secondary_ammunition_type; short secondary_rounds_per_magazine; fixed firing_light_intensity; short firing_intensity_decay_ticks; fixed idle_height; fixed bob_amplitude; fixed kick_height; fixed reload_height; fixed idle_width; fixed horizontal_amplitude; short collection; short idle_shape; short firing_shape; short reloading_shape; short shell_casing_shape; short charging_shape; short charged_shape; short primary_ticks_per_round; short secondary_ticks_per_round; short reload_ticks; short ready_ticks; short primary_recovery_ticks; short secondary_recovery_ticks; short primary_charging_ticks; short secondary_charging_ticks; world_distance primary_recoil_magnitude; world_distance secondary_recoil_magnitude; short primary_firing_sound; short secondary_firing_sound; short primary_click_sound; short secondary_click_sound; short reload_sound; short charging_sound; short primary_shell_casing_sound; short secondary_shell_casing_sound; short primary_sound_activation_range; short secondary_sound_activation_range; short primary_round_projectile_type; short secondary_round_projectile_type; short short primary_theta_error; short secondary_theta_error; short primary_dx; short primary_dz; short secondary_dx; short secondary_dz; short primary_burst_count; short secondary_burst_count; short instant_reload_tick; }; %type: unknown (???) %class: unknown (???) %ammunition_type: what type of ammo gets used up °rounds_per_magazine: how many roungs you get to fire before reloading °secondary_ammunition_type: ammo for the secondary weapon (if any) %short secondary_rounds_per_magazine: rounds/clip for the secondary weapon (if any) %fixed firing_light_intensity: how much the room lights up when firing (?) %short firing_intensity_decay_ticks: how long the light lasts %fixed idle_height: how high the weapon appears when being held %fixed bob_amplitude: how much the weapon bounces when moving %fixed kick_height: recoil height %fixed reload_height: how far it goes up when reloading (?) %fixed idle_width: width of weapon when idle (???) %fixed horizontal_amplitude: side to side sway (???) %short collection: collection of shapes for the weapon %short idle_shape: shape when idle %short firing_shape: shape when firing %short reloading_shape: shape when reloading %short shell_casing_shape: the casing shape, if any. $short charging_shape: Shape when a weapon is being charged %short charged_shape: Shape when a weapon is charged %short primary_ticks_per_round: How many ticks to fire a round (?) %short secondary_ticks_per_round: How many ticks to fire a round (?) %short reload_ticks: ticks to reload weapon %short ready_ticks: ticks to 'draw' weapon %short primary_recovery_ticks: time to recover from recoil for primary weapon %short secondary_recovery_ticks: time to recover from recoil for secondary weapon %short primary_charging_ticks: time to charge primary weapon %short secondary_charging_ticks: time to charge secondary weapon %world_distance primary_recoil_magnitude: how far the weapon recoils when firing primary %world_distance secondary_recoil_magnitude: how far the weapon recoils when firing secondary %short primary_firing_sound: sound when firing primary weapon %short secondary_firing_sound: sound when firing secondary weapon %short primary_click_sound: primary weapon is empty %short secondary_click_sound: secondary weapon is empty %short reload_sound: sound when reloading %short charging_sound: sound when charing %short primary_shell_casing_sound: sound of casing for primary hitting ground %short secondary_shell_casing_sound: sound of casing for secondary hitting ground %short primary_sound_activation_range: (???) %short secondary_sound_activation_range: (???) %short primary_round_projectile_type: type of projectile fired from primary %short secondary_round_projectile_type: type of projectile fire from secondary %short primary_theta_error: 'spread' of the weapon for firing primary %short secondary_theta_error: 'spread' of the weapon for firing secondary %short primary_dx: displacement for the primary weapon firing in the horizontal direction. %short primary_dz: displacement for the primary weapon firing in the vertical direction %short secondary_dx: displacement for the secondary weapon firing in the horizontal direction %short secondary_dz: displacement for the primary weapon firing in the vertical direction %short primary_burst_count: burst fire for primary weapon %short secondary_burst_count: burst fire for secondary weapon %short instant_reload_tick: no idea (?) ------------------------------------------------------------------------------ MAP INFORMATION ------------------------------------------------------------------------------ The Map file is by far the most complex of all the Marathon files. It contains all information about the structure and layout of the levels. Most Marathon Map files contain multiple levels, which are stored as follows: header (128 bytes) level 1 level 2 level 3... .... level n trailer (n * 8 bytes) Each level contains a number of chunks. Not all chunks must be present, and they may be in any order, but levels will not function properly without certain chunks. The exact format for the header is as follows: struct map_header /* 128 bytes */ { short type; unsigned short flags; char name[64]; long unknown; long map_size; short level_count; short unused[25]; //not quite.. }; %type: usually zero, as far as I can see. %flags: usually zero, as far as I can see. %name: ASCII string, zero terminated, up to 64 characters. Usually "Merged Map Files", but for saved games this is the name of the file. %map_size: total size of map file, excluding trailer but including header %level_count: number of levels The trailer contains one entry for each level: struct map_trailer_entry /* 8 bytes */ { long offset; long size; }; %offset: offset from start of file to this level %size: total size of all chunks in this level Each chunk starts with a header, followed by a number of entries (exact size and number of entries depends on the type of chunk). The format for the chunk header is as follows: struct map_chunk_header /* 12 bytes */ { long chunk_type; long offset; long size; //..rest of chunk data follows }; %chunk_type: 4 character ASCII string signifying chunk type %offset: offset from start of this level (not start of file) to next chunk %size: size of chunk Chunk types: 'iidx': exclusion zone chunk 'EPNT': vertex chunk (with extra info) 'PNTS': vertex chunk 'LINS': line chunk 'SIDS': side chunk 'POLY': polygon chunk 'NAME': name chunk (name of level) 'LITE': light source chunk 'NOTE': note chunk (text in automap) 'OBJS': object chunk 'p th': ??? 'Minf': map-info chunk (?) (physics and environment info) 'plac': placement chunk 'door': ??? not used? 'plat': platform chunk (elevators, doors..) 'plyr': player chunk 'dwol': ??? 'mobj': ??? 'alin': ??? 'apol': ??? 'mOns': monster chunk?? 'fx ': effects chunk?? 'bang': ??? 'PLAT': ??? #define MAXIMUM_VERTICES 1024 #define MAXIMUM_LINES 1024 #define MAXIMUM_SIDES 1024 #define MAXIMUM_POLYGONS 256 #define MAXIMUM_LIGHTSOURCES 32 #define MAXIMUM_OBJECTS 256 ------------------------------------------------------------------------------ 'EPNT' / 'PNTS' chunk: ------------------------------------------------------------------------------ Each 'PNTS' entry is of type world_point2d. Each 'EPNT' entry has the following structure: enum /* vertex flags */ { _vertexSolid = 0x0001, _vertexMultipleHeights = 0x0002 }; %_vertexSolid: ??? %_vertexMultipleHeights: adjacent polygons have different heights struct vertex_entry /* 16 bytes */ { unsigned short flags; world_distance highest_floor; world_distance lowest_ceiling; world_point2d vertex; world_point2d transformed; short polygon_index; }; %flags: see above %highest_adjacent_floor: highest adjacent floor height %lowest_adjacent_ceiling: lowest adjacent ceiling height %vertex: coordinates of vertex %transformed: ??? %polygon_index: ??? ------------------------------------------------------------------------------ 'LINS' chunk: ------------------------------------------------------------------------------ enum /* line flags */ { _lineSolid = 0x4000, _lineTransparent = 0x2000, _lineLandscaped = 0x1000, _lineElevated = 0x0800, _lineVariableElevation = 0x0400 }; %_lineSolid: %_lineTransparent: %_lineLandscaped: %_lineElevated: %_lineVariableElevation: struct line_entry /* 32 bytes */ { short vertex_indexes[2]; unsigned short flags; world_distance length; world_distance highest_floor; world_distance lowest_ceiling; short left_side_index; short right_side_index; short left_polygon_index; short right_polygon_index; short unused[6]; }; %vertex_indexes: endpoints of line %flags: see above %length: length of line %highest_floor: highest adjacent floor height %lowest_ceiling: lowest adjacent ceiling height %left_side_index: %right_side_index: %left_polygon_index: %right_polygon_index: ------------------------------------------------------------------------------ 'SIDS' chunk: ------------------------------------------------------------------------------ enum /* side flags */ { _sideControlPanelStatus = 0x0001, _sideControlPanel = 0x0002, _sideRepairSwitch = 0x0004 }; %_sideControlPanelStatus: %_sideControlPanel: %_sideRepairSwitch: enum /* side types */ { _sideFull, _sideHigh, _sideLow, _sideComposite, _sideSplit }; %_sideFull: primary texture is mapped from ceiling down to floor %_sideHigh: primary texture is mapped from ceiling downwards %_sideLow: primary texture is mapped from floor upwards %_sideComposite: primary texture is mapped from ceiling down to floor, secondary texture is mapped ??? %_sideSplit: primary texture is mapped from ceiling downards, and secondary texture is mapped from floor upwards enum /* control panel side types */ { _panelOxygen, _panelShield, _panelDoubleShield, _panelTripleShield, _panelLightSwitch _panelPlatformSwitch, _panelPatternBuffer, _panelUnused, _panelCommTerminal _panelSwitch, _alienPanelDoubleShield _alienPanelTripleShield, _alienPanelPlatformSwitch, _alienPanelPatternBuffer }; enum /* transfer modes (for sides and polygons) */ { tNormal, tFadeToBlack, tInvisible, tSubInvisible, tPulsate, /* polygons only */ tWobble, /* polygons only */ tFastWobble, /* polygons only */ tStatic, tSubStatic, tLandscape, tSmear, /* flat shading */ tFadeOutStatic, tPulsateStatic, tFoldIn, tFoldOut, tHorizSlide, tFastHorizSlide, tVertSlide, tFastVertSlide, tWander, tFastWander }; %tNormal: normal texture mapping %tFadeToBlack: %tInvisible: %tSubInvisible: %tPulsate: %tWobble: %tFastWobble: %tStatic: %tSubStatic: %tLandscape: direct copy (no texture mapping). This is typically used to draw the view outside of windows. %tSmear: fill polygon with pixel (0,0) %tFadeOutStatic: %tPulsateStatic: %tFoldIn: %tFoldOut: %tHorizSlide: %tFastHorizSlide: %tVertSlide: %tFastVertSlide: %tWander: %tFastWander: struct side_texture_struct /* 6 bytes */ { world_distance x0, y0; shape_descriptor texture; }; %x0,y0: texture offsets %texture: specifies texture set (first byte) and texture (second byte) struct side_exclusion_zone /* 16 bytes */ { world_point2d e0, e1, e2, e3; }; %e0,e1,e2,e3: struct side_entry /* 64 bytes */ { short type; unsigned short flags; struct side_texture_struct primary_texture; struct side_texture_struct secondary_texture; struct side_texture_struct transparent_texture; struct side_exclusion_zone exclusion_zone; short control_panel_type; short control_panel_permutation; short primary_transfer_mode; short secondary_transfer_mode; short transparent_transfer_mode; angle direction; short line_index; short unused[6]; }; ------------------------------------------------------------------------------ 'POLY' chunk: ------------------------------------------------------------------------------ enum /* polygon flags */ { _polygonDetached = 0x4000, _polygonPlatformInitiallyOff = 0x2000, _polygonPlatformInitiallyExtended = 0x1000 }; %_polygonDetached: ??? %_polygonPlatformInitiallyOff: platform is initially off %_polygonPlatformInitiallyExtended: platform is initially extended enum /* polygon types */ { _polygonNormal, _polygonItemImpassable, _polygonMonsterImpassable, _polygonMinorDamage, _polygonMajorDamage, _polygonPlatform, _polygonLightOnTrigger, _polygonPlatformOnTrigger, _polygonLightOffTrigger, _polygonPlatformOffTrigger, _polygonTeleporter, _polygonGlueTrigger, _polygonSuperglue, _polygonMustExplore, _polygonExit }; struct polygon_entry /* 128 bytes */ { short type; unsigned short flags; short permutation; short vertex_count; short vertex_index[8]; short line_index[8]; shape_descriptor floor_texture; shape_descriptor ceiling_texture; world_distance floor_height; world_distance ceiling_height; short floor_lightsource_index; short ceiling_lightsource_index; long area; short first_object; short first_exclusion_zone_index; short line_exclusion_zone_count; short point_exclusion_zone_count; short floor_transfer_mode; short ceiling_transfer_mode; short adjacent_polygon_index[8]; short first_neighbor_index; short neighbor_count; world_point2d center; short side_index[8]; short unused[10]; }; ------------------------------------------------------------------------------ 'NAME' chunk: ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ 'LITE' chunk: ------------------------------------------------------------------------------ enum /* light flags */ { _lightAutotriggered = 0x4000; }; enum /* light types */ { _lightNormal, _lightRheostat, _lightFlourescent, _lightStrobe, _lightFlicker, _lightPulsate, _lightAnnoying, _lightEnergyEfficient }; enum /* light modes */ { _lightTurningOn, _lightOn, _lightTurningOff, _lightOff, _lightToggle }; struct lightsource_entry /* 32 bytes */ { unsigned short flags; short type; short mode; short phase; fixed minimum_intensity; fixed maximum_intensity; short period; fixed intensity; short unused[5]; }; ------------------------------------------------------------------------------ 'NOTE' chunk: ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ 'OBJS' chunk: ------------------------------------------------------------------------------ enum /* map object types */ { _savedMonster, _savedObject, _savedItem, _savedPlayer, _savedGoal }; struct map_object_entry /* 16 bytes */ { short type; short index; short facing; short polygon_index; world_point2d location; short unused[2]; }; ------------------------------------------------------------------------------ 'p th' chunk: ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ 'Minf' chunk: ------------------------------------------------------------------------------ enum /* mission flags */ { _missionNone = 0x0000, _missionExtermination = 0x0001, _missionExploration = 0x0002, _missionRetrieval = 0x0004, _missionRepair = 0x0008, _missionRescue = 0x0010 }; enum /* environment flags */ { _environmentNormal = 0x0000, _environmentVacuum = 0x0001, _environmentMagnetic = 0x0002, _environmentRebellion = 0x0004, _environmentLowGravity = 0x0008 }; struct static_entry /* 86 bytes */ { short environment_code; short physics_model; short song_index; unsigned short mission_flags; unsigned short environment_flags; short unused[4]; char level_name[64]; long entry_point_flags; }; ------------------------------------------------------------------------------ 'plat' chunk: ------------------------------------------------------------------------------ enum /* platform types */ { _platformInitiallyActive = 0x00000001, _platformInitiallyExtended = 0x00000002, _platformStopsAtEachLevel = 0x00000004, _platformStopsAtInitialLevel = 0x00000008, _platformActivatesAdjacentUponDeactivating = 0x00000010, _platformExtendsFloorToCeiling = 0x00000020, _platformExtendsFloor = 0x00000040, _platformExtendsCeiling = 0x00000080, _platformCausesDamage = 0x00000100, _platformNoActivateParent = 0x00000200, _platformOneShot = 0x00000400, _platformActivatesLight = 0x00000800, _platformDeactivatesLight = 0x00001000, _platformPlayerControllable = 0x00002000, _platformMonsterControllable = 0x00004000, _platformSafety = 0x00008000, _platformNoExternalActivate = 0x00010000, _platformUsesNativeHeights = 0x00020000, _platformDelaysBeforeActivate = 0x00040000, _platformActivatesAdjacentUponActivating = 0x00080000, _platformDeactivatesAdjacentUponActivating = 0x00100000, _platformDeactivatesAdjacentUponDeactivating = 0x00200000, _platformContractsSlow = 0x00400000, _platformActivatesAdjacentOnEachLevel = 0x00800000, _platformFloods = 0x01000000 }; struct platform_entry /* 16 bytes */ { short type; short speed; short delay; short maximum_height; short minimum_height; unsigned long flags; short owner_polygon_index; short unused[8]; }; ----------------------------------------------------------------------------- ------------------------------------------------------------------------------ enum /* game options */ { _gameMultiplayer = 0x0001, _gameReplenishAmmo = 0x0002, _gameReplenishWeapons = 0x0004, _gameReplenishSpecials = 0x0008, _gameReplenishMonsters = 0x0010, _gameNoMotionSensor = 0x0020, _gameOmniscientMap = 0x0040, _gameLoseItemsOnDeath = 0x0080, _gameDebugMap = 0x0100, _gameKillLimit = 0x0200, _gameNoTeams = 0x0400, _gamePenalizeDying = 0x0800, _gamePenalizeSuicide = 0x1000, _gameMapShowsItems = 0x2000, _gameMapShowsMonsters = 0x4000, _gameMapShowsProjectiles = 0x8000 };