Format of Morrowind's ESM Plug-In File Provided As-Is by Dave Humphrey - uesp@sympatico.ca 10 May 2003 Basic Overall Format: The ESM/ESP/ESS files are composed entirely of records with the following format: Record 4 bytes: char Name[4] 4-byte record name string (not null-terminated) 4 bytes: long Size Size of the record not including the 16 bytes of header data. 4 bytes: long Header1 Unknown value, usually 0 (deleted/ignored flag?). 4 bytes: long Flags Record flags. 0x00002000 = Blocked 0x00000400 = Persistant ? bytes: SubRecords[] All records are composed of a variable number of sub-records. There is no sub-record count, just use the record Size value to determine when to stop reading a record. All records, as shown above, are again composed entirely of a variable number of sub-records with a similar format, as given below: Sub-Record 4 bytes: char Name[4] 4-byte sub-record name string (not null-terminated) 4 bytes: long Size Size of the sub-record not including the 8 bytes of header data. ? bytes: Sub-Record data. Format depends on the sub-record type (see below). 48228 total base records Number of unique main headers = 42 0: TES3 = 1 count Main Header Record, 308 Bytes HEDR (300 bytes) 4 bytes, float Version (1.2) 4 bytes, long Unknown (1) 32 Bytes, Company Name string 256 Bytes, ESM file description? 4 bytes, long NumRecords (48227) MAST = string, variable length Only found in ESP plugins and specifies a master file that the plugin requires. Can occur multiple times. Usually found just after the TES3 record. DATA = 8 Bytes long64 MasterSize Size of the previous master file in bytes (used for version tracking of plugin). The MAST and DATA records are always found together, the DATA following the MAST record that it refers to. 1: GMST = 1428 counts Game Setting Record, 19 to 261 bytes (43 average) NAME = Setting ID string STRV = String value INTV = Integer value (4 btes) FLTV = Float value (4 bytes) Each GMST has one of STRV, INTV, FLTV for the setting value. 2: GLOB = 73 counts Global Variable, 33 to 51 bytes (44 average) NAME = Global ID FNAM = Type of global (1 byte) 's' = short 'l' = long 'f' = float FLTV = Float data (4 bytes) 3: CLAS = 77 counts Class Definition, 96 to 352 bytes (185 average) NAME = Class ID string FNAM = Class name string CLDT = Class Data (60 bytes) long AttributeID1 long AttributeID2 long Specialization? 0 = Combat 1 = Magic 2 = Stealth long MinorID1 long MajorID1 long MinorID2 long MajorID2 long MinorID3 long MajorID3 long MinorID4 long MajorID4 long MinorID5 long MajorID5 long Flags 0x0001 = Playable long AutoCalcFlags 0x00001 = Weapon 0x00002 = Armor 0x00004 = Clothing 0x00008 = Books 0x00010 = Ingrediant 0x00020 = Picks 0x00040 = Probes 0x00080 = Lights 0x00100 = Apparatus 0x00200 = Repair 0x00400 = Misc 0x00800 = Spells 0x01000 = Magic Items 0x02000 = Potions 0x04000 = Training 0x08000 = Spellmaking 0x10000 = Enchanting 0x20000 = Repair Item DESC = Description string 4: FACT = 22 ( 286, 983.64, 1218) Faction Definition, 286 to 1218 bytes (984 average) NAME = Faction ID string FNAM = Faction name string RNAM = Rank Name (32 bytes) Occurs 10 times for each rank in order FADT = Faction data (240 bytes) long AttributeID1 long AttributeID2 RankData[10] long Attribute1 long Attribute2 long FirstSkill long SecondSkill long Faction long SkillID[6] long Unknown1 (-1)? long Flags 1 = Hidden from Player ANAM = Faction name string INTV = Faction reaction value (4 bytes, long) The ANAM/INTV occur in pairs for each faction with a reaction adjustment (usually -4 to +4) 5: RACE = 10 ( 693, 751.50, 881) Race Definition, 693 to 881 (752 average) NAME = Race ID string FNAM = Race name string RADT = Race data (140 bytes) SkillBonuses[7] long SkillID long Bonus long Strength[2] (Male/Female) long Intelligence[2] long Willpower[2] long Agility[2] long Speed[2] long Endurance[2] long Personality[2] long Luck[2] float Height[2] float Weight[2] long Flags 1 = Playable 2 = Beast Race NPCS = Special power/ability name string (32 bytes), multiple DESC = Race description 6: SOUN = 430 ( 44, 60.52, 80) Sound NAME = Sound ID FNAM = Sound Filename (relative to Sounds\) DATA = Sound Data (3 bytes) byte Volume (0=0.00, 255=1.00) byte MinRange byte MaxRange 7: SKIL = 27 ( 144, 247.44, 330) Skill INDX = Skill ID (4 bytes, long) The Skill ID (0 to 26) since skills are hardcoded in the game SKDT = Skill Data (24 bytes) long Attribute long Specialization 0 = Combat 1 = Magic 2 = Stealth float UseValue[4] The use types for each skill are hard-coded. DESC = Skill description string 8: MGEF = 137 ( 113, 432.65, 665) Magic Effect INDX = The Effect ID (0 to 137) (4 bytes, long) MEDT = Effect Data (36 bytes) long SpellSchool 0 = Alteration 1 = Conjuration 2 = Destruction 3 = Illusion 4 = Mysticism 5 = Restoration float BaseCost long Flags 0x0200 = Spellmaking 0x0400 = Enchanting 0x0800 = Negative long Red long Blue long Green float SpeedX float SizeX float SizeCap ITEX = Effect Icon string PTEX = Particle texture string CVFX = Casting visual string BVFX = Bolt visual string HVFX = Hit visual string AVFX = Area visual string DESC = Description text CSND = Cast sound (optional) BSND = Bolt sound (optional) HSND = Hit sound (optional) ASND = Area sound (optional) 9: SCPT = 631 ( 100, 1248.95, 9966) Script SCHD = Script Header (52 bytes) char Name[32] long NumShorts long NumLongs long NumFloats long ScriptDataSize long LocalVarSize SCVR = List of all the local script variables seperated by '\0' NULL characters. SCDT = The compiled script data SCTX = Script text 10: REGN = 9 ( 313, 682.44, 1219) Region NAME = Region ID string FNAM = Region name string WEAT = Weather Data (8 bytes) byte Clear byte Cloudy byte Foggy byte Overcast byte Rain byte Thunder byte Ash byte Blight BNAM = Sleep creature string CNAM = Map Color (4 bytes, COLORREF) byte Red byte Green byte Blue byte Null SNAM = Sound Record byte SoundName[32] (lots of extra junk beyond string?) byte Chance Multiple records with the order determining the sound priority 11: BSGN = 13 ( 158, 199.23, 272) Birth Sign NAME = Sign ID string FNAM = Sign name string TNAM = Texture filename DESC = Description string NPCS = Spell/ability (32 bytes), multiple 12: LTEX = 107 ( 48, 62.84, 76) Land Texture? 13: STAT = 2788 ( 39, 59.74, 79) Static NAME = ID string MODL = NIF model 14: DOOR = 140 ( 47, 134.68, 185) Door Definition NAME = door ID FNAM = door name MODL = NIF model filename SCIP = Script (optional) SNAM = Sound name open ANAM = Sound name close 15: MISC = 536 ( 99, 134.01, 176) Misc Items NAME = item ID, required MODL = model filename, required FNAM = item name MCDT = Weapon Data, 12 bytes binary, required float Weight long Value long Unknown ITEX = Iventory icon filename ENAM = Enchantment ID string??? SCRI = script ID string 16: WEAP = 485 ( 90, 162.62, 222) Weapons NAME = item ID, required MODL = model filename, required FNAM = item name WPDT = Weapon Data, 0x20 bytes binary, required float Weight long Value short Type? (0 to 13) 0 = ShortBladeOneHand 1 = LongBladeOneHand 2 = LongBladeTwoClose 3 = BluntOneHand 4 = BluntTwoClose 5 = BluntTwoWide 6 = SpearTwoWide 7 = AxeOneHand 8 = AxeTwoHand 9 = MarksmanBow 10 = MarksmanCrossbow 11 = MarksmanThrown 12 = Arrow 13 = Bolt short Health float Speed float Reach short EnchantPts byte ChopMin byte ChopMax byte SlashMin byte SlashMax byte ThrustMin byte ThrustMax long Flags (0 to 1) 0 = ? 1 = Ignore Normal Weapon Resistance? ITEX = Iventory icon filename ENAM = Enchantment ID string SCRI = script ID string 17: CONT = 890 ( 80, 284.19, 10371) Containers NAME = ID MODL = NIF Model FNAM = Container name CNDT = Container data (4 bytes) float Weight FLAG = Container flags (4 bytes, bit-field) 0x0001 = Organic 0x0002 = Respawns, organic only 0x0008 = Default, unknown NPCO = An item record (36 bytes, 0+ times) long Count Number of the item char Name[32] The ID of the item 18: SPEL = 982 ( 76, 109.80, 345) Spells NAME = Spell ID FNAM = Spell Name SPDT = Spell Data (12 bytes) long Type 0 = Spell 1 = Ability 2 = Blight 3 = Disease 4 = Curse 5 = Power long SpellCost long Flags 0x0001 = AutoCalc 0x0002 = PC Start 0x0004 = Always Succeeds ENAM = Enchantment data (24 bytes, 0 to 8) 19: CREA = 260 ( 213, 412.08, 780) Creatures NAME = ID MODL = NIF Model FNAM = Creature name NPDT = Creature data, 96 bytes long Type 0 = Creature 1 = Daedra 2 = Undead 3 = Humanoid long Level long Strength long Intelligence long Willpower long Agility long Speed long Endurance long Personality long Luck long Health long SpellPts long Fatigue long Soul long Combat long Magic long Stealth long AttackMin1 long AttackMax1 long AttackMin2 long AttackMax2 long AttackMin3 long AttackMax3 long Gold FLAG = Creature Flags (4 bytes, bit field) 0x0001 = Biped 0x0002 = Respawn 0x0004 = Weapon and shield 0x0008 = None 0x0010 = Swims 0x0020 = Flies 0x0040 = Walks 0x0048 = Default flags 0x0080 = Essential 0x0400 = Skeleton Blood 0x0800 = Metal Blood SCRI = Script NPCO = Item record (36 bytes, 0+ times) long Count Number of the item char Name[32] The ID of the item AIDT = AI data (12 bytes) AI_W = AI Wander (14 bytes) short Distance byte Duration byte TimeOfDay byte Idle[10] AI_T = AI Travel? AI_F = AI Follow? AI_E = AI Escort? AI_A = AI Activate? XSCL = Scale (4 bytes, float, optional) Only present if the scale is not 1.0 20: BODY = 1125 ( 75, 92.73, 103) Body Parts BYDT = Body part data (4 bytes) byte Part 0 = Head 1 = Hair 2 = Neck 3 = Chest 4 = Groin 5 = Hand 6 = Wrist 7 = Forearm 8 = Upperarm 9 = Foot 10 = Ankle 11 = Knee 12 = Upperleg 13 = Clavicle 14 = Tail byte Vampire byte Flags 1 = Female 2 = Playable byte PartType 0 = Skin 1 = Clothing 2 = Armor 21: LIGH = 574 ( 55, 105.77, 197) Lights NAME = ID string FNAM = Item name (optional) LHDT = Light data (24 bytes) float Weight long Value long Time long Radius byte Red } byte Green } byte Blue } long ColorRef? byte Null } long Flags 0x0001 = Dynamic 0x0002 = Can Carry 0x0004 = Negative 0x0008 = Flicker 0x0010 = Fire 0x0020 = Off Default 0x0040 = Flicker Slow 0x0080 = Pulse 0x0100 = Pulse Slow SCPT = Script name (optional) ITEX = Inventory icon (optional) MODL = NIF model name SNAM = Sound name 22: ENCH = 708 ( 57, 98.59, 311) Enchanting Effects NAME = ID string ENDT = Enchant Data (16 bytes) long Type 0 = Cast Once 1 = Cast Strikes 2 = Cast when Used 3 = Constant Effect long EnchantCost long Charge long AutoCalc ENAM = Single enchantment data (24 bytes) short EffectID byte SkillID (-1 if NA) byte AttributeID (-1 if NA) long RangeType 0 = Self 1 = Touch 2 = Target long Area long Duration long MagMin long MagMax 23: NPC_ = 2675 ( 233, 619.12, 6236) NPCs NAME = NPC ID string FNAM = NPC name MODL = Animation file RNAM = Race Name } ANAM = Faction name } Required, even if empty BNAM = Head model } CNAM = Class name KNAM = Hair model } NPDT = NPC Data (12 bytes or 52 bytes?) short Level byte Strength byte Intelligence byte Willpower byte Agility byte Speed byte Endurance byte Personality byte Luck byte Skills[27] } According to the skillID (0-26) byte Reputation short Health short SpellPts short Fatigue byte Disposition byte FactionID byte Rank byte Unknown1 long Gold 12 byte Version short Level byte Disposition byte FactionID? byte Rank byte Unknown1 byte Unknown2 byte Unknown3 long Gold? FLAG = NPC Flags (4 bytes, long) 0x0001 = Female 0x0002 = Essential 0x0004 = Respawn 0x0008 = None? 0x0010 = Autocalc 0x0400 = Blood Skel 0x0800 = Blood Metal NPCO = NPC item (36 bytes, occurs 0+ times) long Count Number of the item char Name[32] The ID of the item NPCS = NPC spell (32 bytes, occurs 0+ times) char Name[32] The ID of the item AIDT = AI data (12 bytes) byte Hello byte Unknown1 byte Fight byte Flee byte Alarm byte Unknown2 byte Unknown3 byte Unknown4 long Flags 0x00001 = Weapon 0x00002 = Armor 0x00004 = Clothing 0x00008 = Books 0x00010 = Ingrediant 0x00020 = Picks 0x00040 = Probes 0x00080 = Lights 0x00100 = Apparatus 0x00200 = Repair 0x00400 = Misc 0x00800 = Spells 0x01000 = Magic Items 0x02000 = Potions 0x04000 = Training 0x08000 = Spellmaking 0x10000 = Enchanting 0x20000 = Repair Item AI_W = AI bytes (14 bytes) short Distance short Duration byte TimeOfDay byte Idle[8] byte Unknown (1?) AI_T = AI Travel (16 bytes) float X float Y float Z long Unknown (1?) AI_F = AI Follow (48 bytes) float X float Y float Z short Duration char ID[32] short Unknown (0100?) AI_E = AI Escort (48 bytes) float X float Y float Z short Duration char ID[32] short Unknown (0100?) CNDT = Cell escort/follow to string (optional) AI_A = AI Activate (33 bytes) char Name[32] byte Unknown (1?) DODT = Cell Travel Destination float XPos float YPos float ZPos float XRot float YRot float ZRot DNAM = Cell name for previous DODT, if interior XSCL = Scale (4 bytes, float, optional) Only present if the scale is not 1.0 24: ARMO = 280 ( 155, 217.10, 346) Armour NAME = Item ID, required MODL = Model Filename, required FNAM = Item Name, required AODT = Armour Data, required (24 bytes) long Type 0 = Helmet 1 = Cuirass 2 = L. Pauldron 3 = R. Pauldron 4 = Greaves 5 = Boots 6 = L. Gauntlet 7 = R. Gauntlet 8 = Shield 9 = L. Bracer 10 = R. Bracer float Weight long Value long Health long EnchantPts long Armour ITEX = Icon Filename, required INDX = Body Part Index (1 byte) 0 = Head 1 = Hair 2 = Neck 3 = Cuirass 4 = Groin 5 = Skirt 6 = Right Hand 7 = Left Hand 8 = Right Wrist 9 = Left Wrist 10 = Shield 11 = Right Forearm 12 = Left Forearm 13 = Right Upper Arm 14 = Left Upper Arm 15 = Right Foot 16 = Left Foot 17 = Right Ankle 18 = Left Ankle 19 = Right Knee 20 = Left Knee 21 = Right Upper Leg 22 = Left Upper Leg 23 = Right Pauldron 24 = Left Pauldron 25 = Weapon 26 = Tail BNAM = Male Part Name CNAM = Female Body Part Name (0 occurences) INDX and BNAM/CNAM are grouped together. INDX first followed by an optional BNAM (no BNAM indicates a NULL field for that index). Up to 7 pairs allowed. SCRI = Script Name ENAM = Enchantment Name 25: CLOT = 510 ( 123, 203.98, 658) Clothing NAME = Item ID, required MODL = Model Name, required FNAM = Item Name, required CTDT = Clothing Data (12 bytes), required long Type 0 = Pants 1 = Shoes 2 = Shirt 3 = Belt 4 = Robe 5 = Right Glove 6 = Left Glove 7 = Skirt 8 = Ring 9 = Amulet float Weight short Value short EnchantPts ITEX = Inventory Icon INDX = Body Part Index (1 byte) BNAM = Male Body Part Name CNAM = Female Body Part Name INDX and BNAM/CNAM are grouped together. INDX first followed by an optional BNAM (no BNAM indicates a NULL field for that index). Up to 7 pairs allowed. ENAM = Enchantment Name SCRI = Script Name 26: REPA = 6 ( 124, 145.67, 158) Repair Items NAME = Item ID, required MODL = Model Name, required FNAM = Item Name, required RIDT = Repair Data (16 bytes), required float Weight long Value long Uses float Quality ITEX = Inventory Icon SCRI = Script Name 27: ACTI = 697 ( 52, 93.60, 138) Activator NAME = Item ID, required MODL = Model Name, required FNAM = Item Name, required SCRI = Script Name 28: APPA = 22 ( 139, 152.59, 167) Alchemy Apparatus NAME = Item ID, required MODL = Model Name, required FNAM = Item Name, required AADT = Alchemy Data (16 bytes), required long Type 0 = Mortar and Pestle 1 = Albemic 2 = Calcinator 3 = Retort float Quality float Weight long Value ITEX = Inventory Icon SCRI = Script Name 29: LOCK = 6 ( 126, 136.17, 145) Lockpicking Items NAME = Item ID, required MODL = Model Name, required FNAM = Item Name, required LKDT = Lock Data (16 bytes), required float Weight long Value float Quality long Uses ITEX = Inventory Icon SCRI = Script Name 30: PROB = 6 ( 124, 136.33, 145) Probe Items NAME = Item ID, required MODL = Model Name, required FNAM = Item Name, required PBDT = Probe Data (16 bytes), required float Weight long Value float Quality long Uses ITEX = Inventory Icon SCRI = Script Name 31: INGR = 95 ( 151, 181.66, 227) Ingrediants NAME = Item ID, required MODL = Model Name, required FNAM = Item Name, required IRDT = Ingrediant Data (56 bytes), required float Weight long Value long EffectID[4] 0 or -1 means no effect long SkillID[4] only for Skill related effects, 0 or -1 otherwise long AttributeID[4] only for Attribute related effects, 0 or -1 otherwise ITEX = Inventory Icon SCRI = Script Name 32: BOOK = 574 ( 131, 3306.91, 42120) Books NAME = Item ID, required MODL = Model Name, required FNAM = Item Name, required BKDT = Book Data (20 bytes), required float Weight long Value long Scroll (1 is scroll, 0 not) long SkillID (-1 is no skill) long EnchantPts ITEX = Inventory Icon SCRI = Script Name TEXT = Book text 33: ALCH = 258 ( 163, 188.15, 334) Alchemy? NAME = Item ID, required MODL = Model Name, required FNAM = Item Name, required ALDT = Alchemy Data (12 bytes), required float Weight long Value long AutoCalc ENAM = Enchantment (24 bytes) 1 to 8 per record short EffectID byte SkillID for skill related effects, -1/0 otherwise byte AttributeID for attribute related effects, -1/0 otherwise long Unknown1 long Unknown2 long Duration long Magnitude long Unknown4 TEXT = Inventory Icon SCRI = Script Name 34: LEVI = 227 ( 80, 486.23, 9201) Levelled Items Levelled Creatures NAME = ID of levelled list DATA = List data (4 bytes, long) 1 = Calc from all levels <= PC level 2 = Calc for each item NNAM = Chance None? (1 byte) INDX = Number of items in list (4 bytes, long) INAM = ID string of list item INTV = PC level for previous INAM (2 bytes, short) The INAM/INTV can occur many times in pairs 35: LEVC = 116 ( 97, 326.54, 1105) Levelled Creatures NAME = ID of levelled list DATA = List data (4 bytes, long) 1 = Calc from all levels <= PC level NNAM = Chance None? (1 byte) INDX = Number of items in list (4 bytes, long) CNAM = ID string of list item INTV = PC level for previous CNAM (2 bytes, short) The CNAM/INTV can occur many times in pairs 36: CELL = 2538 ( 29, 10151.12, 104488) Cell Definitions NAME = Cell ID string. Can be an empty string for exterior cells in which case the region name is used instead. DATA = Cell Data long Flags 0x01 = Interior? 0x02 = Has Water 0x04 = Illegal to Sleep here 0x80 = Behave like exterior (Tribunal) long GridX long GridY RGNN = Region name string NAM0 = Number of objects in cell in current file? (4 byte, long), Optional Exterior Cell Sub-Records NAM5 = Map Color (4 bytes, long, COLORREF) Interior Cell Sub-Records WHGT = Water Height (4 bytes, float) AMBI = Ambient Light Level (16 bytes) long AmbientColor long SunlightColor long FogColor float FogDensity Referenced Object Data Grouping FRMR = Object Index (starts at 1) (4 bytes, long) This is used to uniquely identify objects in the cell. For new files the index starts at 1 and is incremented for each new object added. For modified objects the index is kept the same. NAME = Object ID string XSCL = Scale (4 bytes, float) Static DELE = (4 byte long) Indicates that the reference is deleted. DODT = XYZ Pos, XYZ Rotation of exit (24 bytes, Door objects) float XPos float YPos float ZPos float XRotate float YRotate float ZRotate DNAM = Door exit name (Door objects) FLTV = Follows the DNAM optionally, lock level (long) KNAM = Door key TNAM = Trap name UNAM = Reference Blocked (1 byte, 00?), only occurs once in MORROWIND.ESM ANAM = Owner ID string BNAM = Global variable/rank ID string INTV = Number of uses ( 4 bytes, long, 1 default), occurs even for objects that don't use it NAM9 = ? (4 bytes, long, 0x00000001) XSOL = Soul Extra Data (ID string of creature) DATA = Ref Position Data (24 bytes) float XPos float YPos float ZPos float XRotate float YRotate float ZRotate 37: LAND = 1390 ( 28, 27374.14, 30243) Landscape INTV (8 bytes) long CellX long CellY The cell coordinates of the cell. DATA (4 bytes) long Unknown (default of 0x09) Changing this value makes the land 'disappear' in the editor. VNML (12675 bytes) struct { signed byte X signed byte Y signed byte Z } normals[65][65]; A RGB color map 65x65 pixels in size representing the land normal vectors. The signed value of the 'color' represents the vector's component. Blue is vertical (Z), Red the X direction and Green the Y direction. Note that the y-direction of the data is from the bottom up. VHGT (4232 bytes) float Unknown1 A height offset for the entire cell. Decreasing this value will shift the entire cell land down. byte Unknown2 (0x00) signed byte HeightData[65][65] Contains the height data for the cell in the form of a 65x65 pixel array. The height data is not absolute values but uses differences between adjacent pixels. Thus a pixel value of 0 means it has the same height as the last pixel. Note that the y-direction of the data is from the bottom up. short Unknown2 (0x0000) WNAM (81 bytes) byte Data[9][9] Unknown byte data. VCLR (12675 bytes) optional Vertex color array, looks like another RBG image 65x65 pixels in size. VTEX (512 bytes) optional A 16x16 array of short texture indices (from a LTEX record I think). 38: PGRD = 1194 ( 101, 996.60, 8261) Path Grid 39: SNDG = 168 ( 50, 75.86, 94) Sound Generator NAME = Name? (DEFAULT0001, ALIT0001, etc...) DATA = Sound Type Data (4 bytes, long) 0 = Left Foot 1 = Right Foot 2 = Swim Left 3 = Swim Right 4 = Moan 5 = Roar 6 = Scream 7 = Land SNAM = Sound ID string CNAM = Creature name (optional) 40: DIAL = 772 ( 24, 33.54, 54) Dialogue topic (including journals) NAME = Dialogue ID string DATA = Dialogue Type? (1 byte, 4 bytes for deleted?) 0 = Regular Topic 1 = Voice? 2 = Greeting? 3 = Persuasion? 4 = Journal What follows in the ESP/ESM are all the INFO records that belong to the DIAL record (one of the few cases where order is important). 41: INFO = 3408 ( 107, 299.86, 1063) Dialogue response record that belongs to previous DIAL record. INAM = Info name string (unique sequence of #'s), ID PNAM = Previous info ID NNAM = Next info ID (form a linked list of INFOs for the DIAL). First INFO has an empty PNAM, last has an empty NNAM. DATA = Info data (12 bytes) long Unknown1 long Disposition byte Rank (0-10) byte Gender 0xFF = None 0x00 = Male 0x01 = Female byte PCRank (0-10) byte Unknown2 ONAM = Actor string RNAM = Race string CNAM = Class string FNAM = Faction string ANAM = Cell string DNAM = PC Faction string NAME = The info response string (512 max) SNAM = Sound filename QSTN = Journal Name (1 byte, 0x01) QSTF = Journal Finished (1 byte, 0x01) QSTR = Journal Restart (1 byte, 0x01) SCVR = String for the function/variable choice (5+ bytes) byte Index '0' to '5' byte Type '0' = Nothing? '1' = Function '2' = Global '3' = Local '4' = Journal '5' = Item '6' = Dead '7' = Not ID '8' = Not Faction '9' = Not Class 'A' = Not Race 'B' = Not Cell 'C' = Not Local short Function (2-byte string, '00' to '71') 'sX' = Global/Local/Not Local types 'JX' = Journal type 'IX' = Item Type 'DX' = Dead Type 'XX' = Not ID Type 'FX' = Not Faction 'CX' = Not Class 'RX' = Not Race 'LX' = Not Cell byte CompareOp '0' = '=' '1' = '!=' '2' = '>' '3' = '>=' '4' = '<' '5' = '<=' byte Name[] Except for the function type, this is the ID for the global/local/etc... Is not nessecarily NULL terminated. The function type SCVR sub-record has no name string. INTV = FLTV = The function/variable result for the previous SCVR BNAM = Result text (not compiled) Size of master in bytes (64 bits) ESS Save Game Format Differences - Custom objects (alchemy, magic items, and spells) hatve a unique numeric ID, much like the dialogue infos. The characters class is held in the NEWCLASSID_CHARGEN class ID. GMDT (124 bytes) float Unknown[6] - Unknown values char CellName[64] - Current cell name of character? float Unknown char CharacterName[32] SCRD (20 bytes) unknown combination of short/longs? Related to SCRD? SCRS (65536 bytes) Looks like an array of byte data. Possible the save game screenshot. SCPT Contains local variable information for global scripts? SLCS SLCD QUES Quest dialogue/journal values? NAME - Quest name string DATA - INFO ID string? JOUR The character's journal NAME - The entire journal text (HTML) in one section KLST Kill stats? KNAM - Creature/NPC ID string CNAM - Occurs just after the KNAM sub-record long Value FMAP - Map data? MAPH - (8 bytes) Map header? long Size long Value MAPD - (786432 bytes) Map data? Size corresponds to an RGB 512x512 image. PCDT DNAM - Dialogue topic MNAM PNAM SNAM NAM9 Conversion from a biped to a bodypart types Armor Biped Type BodyPart Type 0 = Head 0 = Head 1 = Hair 1 = Hair 2 = Neck 2 = Neck 3 = Cuirass 3 = Chest 4 = Groin 4 = Groin 5 = Skirt 4 = Groin 6 = Right Hand 5 = Hand 7 = Left Hand 5 = Hand 8 = Right Wrist 6 = Wrist 9 = Left Wrist 6 = Wrist 10 = Shield 6 = Wrist 11 = Right Forearm 7 = Forearm 12 = Left Forearm 7 = Forearm 13 = Right Upper Arm 8 = Upperarm 14 = Left Upper Arm 8 = Upperarm 15 = Right Foot 9 = Foot 16 = Left Foot 9 = Foot 17 = Right Ankle 10 = Ankle 18 = Left Ankle 10 = Ankle 19 = Right Knee 11 = Knee 20 = Left Knee 11 = Knee 21 = Right Upper Leg 12 = Uppperleg 22 = Left Upper Leg 12 = Upperleg 23 = Right Pauldron 13 = Clavicle 24 = Left Pauldron 13 = Clavicle 25 = Weapon -1 = None? 26 = Tail 14 = Tail INFO Function Codes (2-byte character string) '00' = Rank Low '01' = Rank High '02' = Rank Requirement '03' = Reputation '04' = Health Percent '05' = PC Reputation '06' = PC Level '07' = PC Health Percent '08' = PC Magicka '09' = PC Fatigue '10' = PC Strength '11' = PC Block '12' = PC Armorer '13' = PC Medium Armor '14' = PC Heavy Armor '15' = PC Blunt Weapon '16' = PC Long Blade '17' = PC Axe '18' = PC Spear '19' = PC Athletics '20' = PC Enchant '21' = PC Destruction '22' = PC Alteration '23' = PC Illusion '24' = PC Conjuration '25' = PC Mysticism '26' = PC Restoration '27' = PC Alchemy '28' = PC Unarmored '29' = PC Security '30' = PC Sneak '31' = PC Acrobatics '32' = PC Light Armor '33' = PC Short Blade '34' = PC Marksman '35' = PC Mercantile '36' = PC Speechcraft '37' = PC Hand-to-Hand '38' = PC Gender '39' = PC Expelled '40' = PC Common Disease '41' = PC Blight Disease '42' = PC Clothing Modifier '43' = PC Crime Level '44' = Same Gender '45' = Same Race '46' = Same Faction '47' = Faction Rank Diff '48' = Detected '49' = Alarmed? '50' = Choice '51' = PC Intelligence '52' = PC Willpower '53' = PC Agility '54' = PC Speed '55' = PC Endurance '56' = PC Personality '57' = PC Luck '58' = PC Corprus '59' = Weather '60' = PC Vampire '61' = Level '62' = Attacked '63' = Talked to PC '64' = PC Health '65' = Creature Target '66' = Friend Hit '67' = Fight '69' = Hello '69' = Alarm '70' = Flee '71' = Should Attack Skill Action/Use Acrobatics: Jump, Fall Alchemy: Potion Use, Ingrediant Use Alteration: Successful Cast Armorer: Successful Repair Athletics: Second of Running, Second of Swimming Axe: Successful Attack Block: Successful Block Blunt Weapon: Successful Attack Conjuration: Successful Cast Destruction: Successful Cast Enchant: Recharge Item, Use Magic Item, Create Magic Item, Cast When Strikes Hand-To-Hand: Successful Attack Heavy Armor: Hit by Opponent Illusion: Successful Cast Light Armor: Hit by Opponent Long Blade: Successful Attack Marksman: Successful Attack Medium Armor: Hit by Opponent Mercantile: Successful Bargain, Successful Bribe Mysticism: Successful Cast Restoration: Successful Cast Security: Defeat Trap, Pick Lock Short Blade: Successful Attack Sneak: Avoid Notice, Successful Pick Pocket Spear: Successful Attack SpeechCraft: Successful Persuasion, Failed Persuasion Unarmored: Hit by Opponent SCDT Compiled script data For commands with ID short Code byte IDLength char ID[] IF Block short Code = 0x0601 byte Unknown (00?) byte CompareLength byte VarType 0x20 byte VarSize s/l/f/G local short VarIndex 1 based index of local variable by type global byte GlobalSize byte GlobalName[] Not NULL terminated byte CompareText[] Not NULL terminated SET Block short Code = 0x0501 short VarCode (0x2073, ... ) (var data) byte SetSize byte SetData[] Data in stack order: (6*3+1 => 6 3 * 1 +) Codes 0x2073 = Get short local var 0x206C = Get long local var 0x2066 = Get float local var 0x2047 = Get global var 0x010C = 0x1019 = 0x0501 = set 0x0601 = if 0x0101 = End 0x0901 = EndIf --------------------------------------------------------------------------- ------ Variables Vars are not defined in the SCDT. In SCVR the vars are listed as null terminated strings in the order shorts, longs, floats, this does not appear to be used by SCDT. The number of variables of each type is stored in SCHD, the format of which appears to be: SCHD (long) size, (cstr32) scriptname, (long) num shorts, (long) num longs, (long) num floats (long) 2, (long) size of SCVR seg SCDT uses the index of the variable by type, so the first float would be 'f 0001', it starts at 1 not 0 because its stupid. --------------------------------------------------------------------------- ------ Mnemonic HexOp Params -> 010C (bstr) objectname ; appears before the function which uses it ; lasts for 1 simple statement only else 0107 (byte) statement count elseif 0108 (byte) statement count, (ifexpr) condition end 0101 none endif 0109 none if 0106 (byte) statement count, (ifexpr) condition return 0124 none set 0105 (variable) target, (setexpr) newvalue ForceSneak 1163 none GetAlchemy 106B none GetDistance 1001 (ref) objectname GetPos 100A (byte) 'X' 'Y' or 'Z' Journal 10CC (bstr) topic, (sparam) index Lock 1136 (short) literal MessageBox 1000 (lstr) formatstr, (byte) num args, [ (variable) arg1 [, (variable) arg2 [...]]], (byte) num buttons, [ (bcstr) but1 [, (bcstr) but2 [...]]] Position 1004 (float) x, (float) y, (float) z, (float) zangle Random 1021 (short) limit SetAlchemy 106C (fparam) newalchemy SetSneak 1075 (fparam) newsneak StopScript 101C (bstr) scriptname --------------------------------------------------------------------------- ------ Definitions ; not there are no implicit separators, this is a binary stream = byte value = ' ' bstr = (byte) length, ascii lstr = (short) length, ascii cstr = ascii, <00> bcstr = (byte) length, cstr length1 = (byte) length varidx1 = (byte) var index varidx2 = (short) var index varidx = (short) var index mathop = ('+'|'-'|'*'|'/') mathcomp = ('=='|'!='|'<'|'<='|'>'|'>=') valascii = ['-']*(0-9)[.]*(0-9) vartype = ('s'|'f'|'l') local = ( vartype varidx ) global = ('G' bstr) variable = ( local | global ) ref = ('r' bstr) foreign = ( ref local ) fparam = ( float | local <00> ) ; 4 bytes either way see sparam = ( short | local <00> ) ; 4 bytes either way see rval = ( local | valascii ) setval = ( local | global | func | valascii ) ; The know issue of: set temp to ( myobj.val ); not working is a runtime problem ; the compiler generates a foreign reference exactly the same as for if func = ('X' opcode [ rval [ rval [ rval [ rval]]]]) ; How does the evaluator know how many params to grab? ; everything up to the end of the expression, can only have 1 function ; per set ; set temp to ( Position 1 2 3 4 ) okay ; set temp to ( Position 1 2 3 4 + 1 ) wont work ; set temp to ( 1 + Position 1 2 3 4 ) would work ; but this would not be backwards compatible ; up to the next space, funcs can only have 1 param, ; set temp to ( GetPos x + GetPos y ) okay ; this is backwards compatable, tested and works polish = Reverse polish calculator, uses space as 'push', mathop as operators, setval as values. If there is only 1 variable or 1 function then an additional <00> is appended which appears to do nothing, but is required by the runtime. setexpr = (byte) length, polish ifval = ( local | global | foreign | func | valascii ) ifexpr = (byte) length, ifval [mathcomp ifval] ; The if evaluator cannot handle calculations, the comparison operator is ; not implemented as part of the reverse polish calculator, the compiler ; will encode calculations in reverse polish but the comparisons are ; inserted in the wrong order to work. ; Like the calculator if there is only one term a <00> byte is appended