From 8e7dd48e06c1bbbf2daff68242dd79361a866d79 Mon Sep 17 00:00:00 2001 From: William Miles Date: Fri, 14 Oct 2022 16:23:24 +1100 Subject: [PATCH] Add project files. --- Navmesher.sln | 31 + Navmesher/Navmesher.vcxproj | 147 + Navmesher/Navmesher.vcxproj.filters | 33 + Navmesher/esx_reader.hpp | 142 + Navmesher/esx_reader_lut.cpp | 318 + Navmesher/main.cpp | 7 + Navmesher/utility.hpp | 46 + reference/flag_filter.py | 114 + reference/flags.json | 1391 +++ reference/record_filter.py | 95 + reference/record_types.csv | 137 + reference/wbDefinitionsTES5.pas | 13841 ++++++++++++++++++++++++++ 12 files changed, 16302 insertions(+) create mode 100644 Navmesher.sln create mode 100644 Navmesher/Navmesher.vcxproj create mode 100644 Navmesher/Navmesher.vcxproj.filters create mode 100644 Navmesher/esx_reader.hpp create mode 100644 Navmesher/esx_reader_lut.cpp create mode 100644 Navmesher/main.cpp create mode 100644 Navmesher/utility.hpp create mode 100644 reference/flag_filter.py create mode 100644 reference/flags.json create mode 100644 reference/record_filter.py create mode 100644 reference/record_types.csv create mode 100644 reference/wbDefinitionsTES5.pas diff --git a/Navmesher.sln b/Navmesher.sln new file mode 100644 index 0000000..f70921d --- /dev/null +++ b/Navmesher.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32922.545 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Navmesher", "Navmesher\Navmesher.vcxproj", "{FD707FEA-8D2F-45AB-93FE-CD31B92EFB1D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FD707FEA-8D2F-45AB-93FE-CD31B92EFB1D}.Debug|x64.ActiveCfg = Debug|x64 + {FD707FEA-8D2F-45AB-93FE-CD31B92EFB1D}.Debug|x64.Build.0 = Debug|x64 + {FD707FEA-8D2F-45AB-93FE-CD31B92EFB1D}.Debug|x86.ActiveCfg = Debug|Win32 + {FD707FEA-8D2F-45AB-93FE-CD31B92EFB1D}.Debug|x86.Build.0 = Debug|Win32 + {FD707FEA-8D2F-45AB-93FE-CD31B92EFB1D}.Release|x64.ActiveCfg = Release|x64 + {FD707FEA-8D2F-45AB-93FE-CD31B92EFB1D}.Release|x64.Build.0 = Release|x64 + {FD707FEA-8D2F-45AB-93FE-CD31B92EFB1D}.Release|x86.ActiveCfg = Release|Win32 + {FD707FEA-8D2F-45AB-93FE-CD31B92EFB1D}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {21B9C92D-FC98-4B4E-B3BD-BD6A441CAC1D} + EndGlobalSection +EndGlobal diff --git a/Navmesher/Navmesher.vcxproj b/Navmesher/Navmesher.vcxproj new file mode 100644 index 0000000..d46de5b --- /dev/null +++ b/Navmesher/Navmesher.vcxproj @@ -0,0 +1,147 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {fd707fea-8d2f-45ab-93fe-cd31b92efb1d} + Navmesher + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + true + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + EnableAllWarnings + true + _DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + stdcpp20 + false + Guard + true + true + + + Console + true + + + + + EnableAllWarnings + true + true + true + NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Navmesher/Navmesher.vcxproj.filters b/Navmesher/Navmesher.vcxproj.filters new file mode 100644 index 0000000..f460f1b --- /dev/null +++ b/Navmesher/Navmesher.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Navmesher/esx_reader.hpp b/Navmesher/esx_reader.hpp new file mode 100644 index 0000000..5db8e67 --- /dev/null +++ b/Navmesher/esx_reader.hpp @@ -0,0 +1,142 @@ +#ifndef ESX_READER_H +#define ESX_READER_H + +#include +#include +#include +#include +#include +#include + +#include "utility.hpp" + +namespace esxr { + +// +// Forward declarations +// + +class GroupNode; +class RecordNode; + +// +// Enumerations +// + +// This is defined by the file spec, do not change unless the file spec changes. +enum class GroupType : int32_t { + Top = 0, + WorldChildren = 1, + InteriorCellBlock = 2, + InteriorCellSubBlock = 3, + ExteriorCellBlock = 4, + ExteriorCellSubBlock = 5, + CellChildren = 6, + TopicChildren = 7, + CellPersistentChildren = 8, + CellTemporaryChildren = 9, +}; + +enum class RecordType { + None, + AACT, ACHR, ACTI, ADDN, ALCH, AMMO, ANIO, APPA, ARMA, ARMO, ARTO, ASPC, ASTP, AVIF, BOOK, BPTD, CAMS, CELL, CLAS, CLDC, CLFM, + CLMT, COBJ, COLL, CONT, CPTH, CSTY, DEBR, DIAL, DLBR, DLVW, DOBJ, DOOR, DUAL, ECZN, EFSH, ENCH, EQUP, EXPL, EYES, FACT, FLOR, + FLST, FSTP, FSTS, FURN, GLOB, GMST, GRAS, GRUP, HAIR, HAZD, HDPT, IDLE, IDLM, IMAD, IMGS, INFO, INGR, IPCT, IPDS, KEYM, KYWD, + LAND, LCRT, LCTN, LENS, LGTM, LIGH, LSCR, LTEX, LVLI, LVLN, LVSP, MATO, MATT, MESG, MGEF, MISC, MOVT, MSTT, MUSC, MUST, NAVI, + NAVM, NOTE, NPC_, OTFT, PACK, PARW, PBAR, PBEA, PCON, PERK, PFLA, PGRE, PHZD, PLYR, PMIS, PROJ, PWAT, QUST, RACE, REFR, REGN, + RELA, REVB, RFCT, RGDL, SCEN, SCOL, SCOL, SCPT, SCRL, SHOU, SLGM, SMBN, SMEN, SMQN, SNCT, SNDR, SOPM, SOUN, SPEL, SPGD, STAT, + TACT, TES4, TREE, TXST, VOLI, VTYP, WATR, WEAP, WOOP, WRLD, WTHR +}; + +// +// Type aliases +// + +using Node = std::variant; + +// +// Aggregate types +// + +struct FourCC : utility::Store> { + constexpr FourCC() noexcept = default; + explicit constexpr FourCC(const char (&str)[5]) noexcept : Store{ utility::literal_to_array(str) } { } +}; +static_assert(std::is_trivial_v); + +struct FormID : utility::Store { }; +struct Timestamp : utility::Store { }; +struct VCInfo : utility::Store { }; + +struct GroupHeader { + struct Coord { + int16_t y, x; + }; + + struct TopType : utility::Store { }; + struct ParentWorld : utility::Store { }; + struct BlockNumber : utility::Store { }; + struct SubBlockNumber : utility::Store { }; + struct BlockCoord : utility::Store { }; + struct SubBlockCoord : utility::Store { }; + struct ParentCell : utility::Store { }; + struct ParentDialogue : utility::Store { }; + + union GroupLabel { + TopType top_type; + ParentWorld parent_world; + BlockNumber block_number; + SubBlockNumber sub_block_number; + BlockCoord block_coord; + SubBlockCoord sub_block_coord; + ParentCell parent_cell; + ParentDialogue parent_dialogue; + }; + + RecordType grup; + uint32_t size; + GroupLabel label; + GroupType type; + Timestamp timestamp; + VCInfo version_control_information; + uint32_t unknown; +}; +static_assert(sizeof(GroupHeader) == 24); + +struct RecordHeader { + struct Flags : utility::Store { }; + struct Version : utility::Store { }; + + RecordType type; + uint32_t size; + Flags flags; + FormID formid; + Timestamp timestamp; + VCInfo version_control_information; + Version version; + uint16_t unknown; +}; +static_assert(sizeof(RecordHeader) == 24); + +// +// Classes +// + +class GroupNode { +private: + GroupHeader m_header; + std::vector m_children; +}; + +class RecordNode { +private: + RecordHeader m_header; + std::vector data; +}; + +// +// Free functions +// + +} +#endif diff --git a/Navmesher/esx_reader_lut.cpp b/Navmesher/esx_reader_lut.cpp new file mode 100644 index 0000000..ef78d85 --- /dev/null +++ b/Navmesher/esx_reader_lut.cpp @@ -0,0 +1,318 @@ +#include "esx_reader.hpp" + +using namespace esxr; + +namespace esxr_lut { + +static constexpr std::pair record_type_name_map[] = { + {RecordType::AACT, "Action"}, + {RecordType::ACHR, "Placed NPC"}, + {RecordType::ACTI, "Activator"}, + {RecordType::ADDN, "Addon Node"}, + {RecordType::ALCH, "Ingestible"}, + {RecordType::AMMO, "Ammunition"}, + {RecordType::ANIO, "Animated Object"}, + {RecordType::APPA, "Alchemical Apparatus"}, + {RecordType::ARMA, "Armor Addon"}, + {RecordType::ARMO, "Armor"}, + {RecordType::ARTO, "Art Object"}, + {RecordType::ASPC, "Acoustic Space"}, + {RecordType::ASTP, "Association Type"}, + {RecordType::AVIF, "Actor Value Information"}, + {RecordType::BOOK, "Book"}, + {RecordType::BPTD, "Body Part Data"}, + {RecordType::CAMS, "Camera Shot"}, + {RecordType::CELL, "Cell"}, + {RecordType::CLAS, "Class"}, + {RecordType::CLDC, "CLDC"}, + {RecordType::CLFM, "Color"}, + {RecordType::CLMT, "Climate"}, + {RecordType::COBJ, "Constructible Object"}, + {RecordType::COLL, "Collision Layer"}, + {RecordType::CONT, "Container"}, + {RecordType::CPTH, "Camera Path"}, + {RecordType::CSTY, "Combat Style"}, + {RecordType::DEBR, "Debris"}, + {RecordType::DIAL, "Dialog Topic"}, + {RecordType::DLBR, "Dialog Branch"}, + {RecordType::DLVW, "Dialog View"}, + {RecordType::DOBJ, "Default Object Manager"}, + {RecordType::DOOR, "Door"}, + {RecordType::DUAL, "Dual Cast Data"}, + {RecordType::ECZN, "Encounter Zone"}, + {RecordType::EFSH, "Effect Shader"}, + {RecordType::ENCH, "Object Effect"}, + {RecordType::EQUP, "Equip Type"}, + {RecordType::EXPL, "Explosion"}, + {RecordType::EYES, "Eyes"}, + {RecordType::FACT, "Faction"}, + {RecordType::FLOR, "Flora"}, + {RecordType::FLST, "FormID List"}, + {RecordType::FSTP, "Footstep"}, + {RecordType::FSTS, "Footstep Set"}, + {RecordType::FURN, "Furniture"}, + {RecordType::GLOB, "Global"}, + {RecordType::GMST, "Game Setting"}, + {RecordType::GRAS, "Grass"}, + {RecordType::GRUP, "Internal File Structure Group"}, + {RecordType::HAIR, "HAIR"}, + {RecordType::HAZD, "Hazard"}, + {RecordType::HDPT, "Head Part"}, + {RecordType::IDLE, "Idle Animation"}, + {RecordType::IDLM, "Idle Marker"}, + {RecordType::IMAD, "Image Space Adapter"}, + {RecordType::IMGS, "Image Space"}, + {RecordType::INFO, "Dialog response"}, + {RecordType::INGR, "Ingredient"}, + {RecordType::IPCT, "Impact"}, + {RecordType::IPDS, "Impact Data Set"}, + {RecordType::KEYM, "Key"}, + {RecordType::KYWD, "Keyword"}, + {RecordType::LAND, "Landscape"}, + {RecordType::LCRT, "Location Reference Type"}, + {RecordType::LCTN, "Location"}, + {RecordType::LENS, "Lens Flare"}, + {RecordType::LGTM, "Lighting Template"}, + {RecordType::LIGH, "Light"}, + {RecordType::LSCR, "Load Screen"}, + {RecordType::LTEX, "Landscape Texture"}, + {RecordType::LVLI, "Leveled Item"}, + {RecordType::LVLN, "Leveled NPC"}, + {RecordType::LVSP, "Leveled Spell"}, + {RecordType::MATO, "Material Object"}, + {RecordType::MATT, "Material Type"}, + {RecordType::MESG, "Message"}, + {RecordType::MGEF, "Magic Effect"}, + {RecordType::MISC, "Misc.Item"}, + {RecordType::MOVT, "Movement Type"}, + {RecordType::MSTT, "Moveable Static"}, + {RecordType::MUSC, "Music Type"}, + {RecordType::MUST, "Music Track"}, + {RecordType::NAVI, "Navigation Mesh Info Map"}, + {RecordType::NAVM, "Navigation Mesh"}, + {RecordType::NOTE, "NOTE"}, + {RecordType::NPC_, "Non - Player Character(Actor)"}, + {RecordType::OTFT, "Outfit"}, + {RecordType::PACK, "Package"}, + {RecordType::PARW, "Placed Arrow"}, + {RecordType::PBAR, "Placed Barrier"}, + {RecordType::PBEA, "Placed Beam"}, + {RecordType::PCON, "Placed Cone / Voice"}, + {RecordType::PERK, "Perk"}, + {RecordType::PFLA, "Placed Flame"}, + {RecordType::PGRE, "Placed Projectile"}, + {RecordType::PHZD, "Placed Hazard"}, + {RecordType::PLYR, "Player Reference"}, + {RecordType::PMIS, "Placed Missile"}, + {RecordType::PROJ, "Projectile"}, + {RecordType::PWAT, "PWAT"}, + {RecordType::QUST, "Quest"}, + {RecordType::RACE, "Race"}, + {RecordType::REFR, "Placed Object"}, + {RecordType::REGN, "Region"}, + {RecordType::RELA, "Relationship"}, + {RecordType::REVB, "Reverb Parameters"}, + {RecordType::RFCT, "Visual Effect"}, + {RecordType::RGDL, "RGDL"}, + {RecordType::SCEN, "Scene"}, + {RecordType::SCOL, "SCOL"}, + {RecordType::SCOL, "Static Collection"}, + {RecordType::SCPT, "SCPT"}, + {RecordType::SCRL, "Scroll"}, + {RecordType::SHOU, "Shout"}, + {RecordType::SLGM, "Soul Gem"}, + {RecordType::SMBN, "Story Manager Branch Node"}, + {RecordType::SMEN, "Story Manager Event Node"}, + {RecordType::SMQN, "Story Manager Quest Node"}, + {RecordType::SNCT, "Sound Category"}, + {RecordType::SNDR, "Sound Descriptor"}, + {RecordType::SOPM, "Sound Output Model"}, + {RecordType::SOUN, "Sound Marker"}, + {RecordType::SPEL, "Spell"}, + {RecordType::SPGD, "Shader Particle Geometry"}, + {RecordType::STAT, "Static"}, + {RecordType::TACT, "Talking Activator"}, + {RecordType::TES4, "Main File Header"}, + {RecordType::TREE, "Tree"}, + {RecordType::TXST, "Texture Set"}, + {RecordType::VOLI, "Volumetric Lighting"}, + {RecordType::VTYP, "Voice Type"}, + {RecordType::WATR, "Water"}, + {RecordType::WEAP, "Weapon"}, + {RecordType::WOOP, "Word of Power"}, + {RecordType::WRLD, "Worldspace"}, + {RecordType::WTHR, "Weather"} +}; + +static constexpr std::pair record_type_fourcc_map[] = { + {RecordType::AACT, FourCC("AACT")}, + {RecordType::ACHR, FourCC("ACHR")}, + {RecordType::ACTI, FourCC("ACTI")}, + {RecordType::ADDN, FourCC("ADDN")}, + {RecordType::ALCH, FourCC("ALCH")}, + {RecordType::AMMO, FourCC("AMMO")}, + {RecordType::ANIO, FourCC("ANIO")}, + {RecordType::APPA, FourCC("APPA")}, + {RecordType::ARMA, FourCC("ARMA")}, + {RecordType::ARMO, FourCC("ARMO")}, + {RecordType::ARTO, FourCC("ARTO")}, + {RecordType::ASPC, FourCC("ASPC")}, + {RecordType::ASTP, FourCC("ASTP")}, + {RecordType::AVIF, FourCC("AVIF")}, + {RecordType::BOOK, FourCC("BOOK")}, + {RecordType::BPTD, FourCC("BPTD")}, + {RecordType::CAMS, FourCC("CAMS")}, + {RecordType::CELL, FourCC("CELL")}, + {RecordType::CLAS, FourCC("CLAS")}, + {RecordType::CLDC, FourCC("CLDC")}, + {RecordType::CLFM, FourCC("CLFM")}, + {RecordType::CLMT, FourCC("CLMT")}, + {RecordType::COBJ, FourCC("COBJ")}, + {RecordType::COLL, FourCC("COLL")}, + {RecordType::CONT, FourCC("CONT")}, + {RecordType::CPTH, FourCC("CPTH")}, + {RecordType::CSTY, FourCC("CSTY")}, + {RecordType::DEBR, FourCC("DEBR")}, + {RecordType::DIAL, FourCC("DIAL")}, + {RecordType::DLBR, FourCC("DLBR")}, + {RecordType::DLVW, FourCC("DLVW")}, + {RecordType::DOBJ, FourCC("DOBJ")}, + {RecordType::DOOR, FourCC("DOOR")}, + {RecordType::DUAL, FourCC("DUAL")}, + {RecordType::ECZN, FourCC("ECZN")}, + {RecordType::EFSH, FourCC("EFSH")}, + {RecordType::ENCH, FourCC("ENCH")}, + {RecordType::EQUP, FourCC("EQUP")}, + {RecordType::EXPL, FourCC("EXPL")}, + {RecordType::EYES, FourCC("EYES")}, + {RecordType::FACT, FourCC("FACT")}, + {RecordType::FLOR, FourCC("FLOR")}, + {RecordType::FLST, FourCC("FLST")}, + {RecordType::FSTP, FourCC("FSTP")}, + {RecordType::FSTS, FourCC("FSTS")}, + {RecordType::FURN, FourCC("FURN")}, + {RecordType::GLOB, FourCC("GLOB")}, + {RecordType::GMST, FourCC("GMST")}, + {RecordType::GRAS, FourCC("GRAS")}, + {RecordType::GRUP, FourCC("GRUP")}, + {RecordType::HAIR, FourCC("HAIR")}, + {RecordType::HAZD, FourCC("HAZD")}, + {RecordType::HDPT, FourCC("HDPT")}, + {RecordType::IDLE, FourCC("IDLE")}, + {RecordType::IDLM, FourCC("IDLM")}, + {RecordType::IMAD, FourCC("IMAD")}, + {RecordType::IMGS, FourCC("IMGS")}, + {RecordType::INFO, FourCC("INFO")}, + {RecordType::INGR, FourCC("INGR")}, + {RecordType::IPCT, FourCC("IPCT")}, + {RecordType::IPDS, FourCC("IPDS")}, + {RecordType::KEYM, FourCC("KEYM")}, + {RecordType::KYWD, FourCC("KYWD")}, + {RecordType::LAND, FourCC("LAND")}, + {RecordType::LCRT, FourCC("LCRT")}, + {RecordType::LCTN, FourCC("LCTN")}, + {RecordType::LENS, FourCC("LENS")}, + {RecordType::LGTM, FourCC("LGTM")}, + {RecordType::LIGH, FourCC("LIGH")}, + {RecordType::LSCR, FourCC("LSCR")}, + {RecordType::LTEX, FourCC("LTEX")}, + {RecordType::LVLI, FourCC("LVLI")}, + {RecordType::LVLN, FourCC("LVLN")}, + {RecordType::LVSP, FourCC("LVSP")}, + {RecordType::MATO, FourCC("MATO")}, + {RecordType::MATT, FourCC("MATT")}, + {RecordType::MESG, FourCC("MESG")}, + {RecordType::MGEF, FourCC("MGEF")}, + {RecordType::MISC, FourCC("MISC")}, + {RecordType::MOVT, FourCC("MOVT")}, + {RecordType::MSTT, FourCC("MSTT")}, + {RecordType::MUSC, FourCC("MUSC")}, + {RecordType::MUST, FourCC("MUST")}, + {RecordType::NAVI, FourCC("NAVI")}, + {RecordType::NAVM, FourCC("NAVM")}, + {RecordType::NOTE, FourCC("NOTE")}, + {RecordType::NPC_, FourCC("NPC_")}, + {RecordType::OTFT, FourCC("OTFT")}, + {RecordType::PACK, FourCC("PACK")}, + {RecordType::PARW, FourCC("PARW")}, + {RecordType::PBAR, FourCC("PBAR")}, + {RecordType::PBEA, FourCC("PBEA")}, + {RecordType::PCON, FourCC("PCON")}, + {RecordType::PERK, FourCC("PERK")}, + {RecordType::PFLA, FourCC("PFLA")}, + {RecordType::PGRE, FourCC("PGRE")}, + {RecordType::PHZD, FourCC("PHZD")}, + {RecordType::PLYR, FourCC("PLYR")}, + {RecordType::PMIS, FourCC("PMIS")}, + {RecordType::PROJ, FourCC("PROJ")}, + {RecordType::PWAT, FourCC("PWAT")}, + {RecordType::QUST, FourCC("QUST")}, + {RecordType::RACE, FourCC("RACE")}, + {RecordType::REFR, FourCC("REFR")}, + {RecordType::REGN, FourCC("REGN")}, + {RecordType::RELA, FourCC("RELA")}, + {RecordType::REVB, FourCC("REVB")}, + {RecordType::RFCT, FourCC("RFCT")}, + {RecordType::RGDL, FourCC("RGDL")}, + {RecordType::SCEN, FourCC("SCEN")}, + {RecordType::SCOL, FourCC("SCOL")}, + {RecordType::SCOL, FourCC("SCOL")}, + {RecordType::SCPT, FourCC("SCPT")}, + {RecordType::SCRL, FourCC("SCRL")}, + {RecordType::SHOU, FourCC("SHOU")}, + {RecordType::SLGM, FourCC("SLGM")}, + {RecordType::SMBN, FourCC("SMBN")}, + {RecordType::SMEN, FourCC("SMEN")}, + {RecordType::SMQN, FourCC("SMQN")}, + {RecordType::SNCT, FourCC("SNCT")}, + {RecordType::SNDR, FourCC("SNDR")}, + {RecordType::SOPM, FourCC("SOPM")}, + {RecordType::SOUN, FourCC("SOUN")}, + {RecordType::SPEL, FourCC("SPEL")}, + {RecordType::SPGD, FourCC("SPGD")}, + {RecordType::STAT, FourCC("STAT")}, + {RecordType::TACT, FourCC("TACT")}, + {RecordType::TES4, FourCC("TES4")}, + {RecordType::TREE, FourCC("TREE")}, + {RecordType::TXST, FourCC("TXST")}, + {RecordType::VOLI, FourCC("VOLI")}, + {RecordType::VTYP, FourCC("VTYP")}, + {RecordType::WATR, FourCC("WATR")}, + {RecordType::WEAP, FourCC("WEAP")}, + {RecordType::WOOP, FourCC("WOOP")}, + {RecordType::WRLD, FourCC("WRLD")}, + {RecordType::WTHR, FourCC("WTHR")}, +}; + +static constexpr std::pair group_type_names_map[] = { + {GroupType::Top , "Top Type" }, + {GroupType::WorldChildren , "World Children" }, + {GroupType::InteriorCellBlock , "Interior Cell Block" }, + {GroupType::InteriorCellSubBlock , "Interior Cell Sub-Block" }, + {GroupType::ExteriorCellBlock , "Exterior Cell" }, + {GroupType::ExteriorCellSubBlock , "Exterior Cell Sub-Block" }, + {GroupType::CellChildren , "Cell Children" }, + {GroupType::TopicChildren , "Topic Children" }, + {GroupType::CellPersistentChildren, "Cell Persistent Children"}, + {GroupType::CellTemporaryChildren , "Cell Temporary Children" }, +}; + +struct flag { + RecordType type; + unsigned bit; +}; + +static constexpr std::pair flag_strings_map[]{ + {{RecordType::ACHR, 9}, "Starts Dead"}, +}; + +struct refr_flag { + RecordType refr_type; + unsigned bit; +}; + +static constexpr std::pair refr_flag_strings_map[]{ + {{RecordType::ACHR, 9}, "Hidden From Local Map"}, +}; + +} diff --git a/Navmesher/main.cpp b/Navmesher/main.cpp new file mode 100644 index 0000000..e630ae4 --- /dev/null +++ b/Navmesher/main.cpp @@ -0,0 +1,7 @@ +#include +#include "esx_reader.hpp" + +int main() +{ + std::cout << "Test" << std::endl; +} \ No newline at end of file diff --git a/Navmesher/utility.hpp b/Navmesher/utility.hpp new file mode 100644 index 0000000..7125f10 --- /dev/null +++ b/Navmesher/utility.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace utility { + +// Converts a string literal to a std::array, from https://stackoverflow.com/a/33484394 +template +constexpr std::array +literal_to_array(const char(&a)[N], std::index_sequence) +{ + return { {a[Is]...} }; +} + +template +constexpr std::array literal_to_array(const char(&a)[N]) +{ + return literal_to_array(a, std::make_index_sequence()); +} + + +// Used to inspect type sizes and values at compile time. Example: +// +// TS x = 0; +// +// or +// +// TD x = 0; +template +class TS; + +template +class TD; + + +// This is a base class for a generic store for some value that can be represented by +// type T but should not be type checked as type T, but rather some more constrained class. +template +struct Store { + static_assert(std::is_trivial_v); + T value; + friend constexpr auto operator<=>(const Store &, const Store &) noexcept = default; +}; + +} + diff --git a/reference/flag_filter.py b/reference/flag_filter.py new file mode 100644 index 0000000..8701c6c --- /dev/null +++ b/reference/flag_filter.py @@ -0,0 +1,114 @@ +import re +import os +import json +from dataclasses import dataclass + + +class Jsonify: + def encode(self, value=None): + if not value: + value = self.__dict__ + return value + +@dataclass +class Flag(Jsonify): + bit: int + description: str + +@dataclass +class Record(Jsonify): + fourcc: str + name: str + flags: list[Flag] + + +re_flags = re.compile(".*?(\d+?),.*?'(.*)'") + + +def find_records(data, re_record, re_first): + found_records = re_record.findall(data) + + seen = set() + records = [] + for record in found_records: + s = record.split('\n') + [first] = re_first.findall(s[0]) + assert len(first) == 2, "Could not parse first line of record:\n{}".format(record) + flags = [] + for line in s[2:-1]: + [f] = re_flags.findall(line) + assert len(f) == 2, "Could not parse flag definition: {}".format(line) + desc = f[1].replace("''", "'").replace("', '", "") + flags += [Flag(int(f[0]), desc)] + r = Record(first[0], first[1], flags) + if r.fourcc not in seen: + records += [r] + seen.add(r.fourcc) + + return records + + +def find_wbRecords(data): + re_wbRecord = re.compile("wbRecord\(.*?\n.*?wbFlagsList\(\[\n(?:.*?\n)*?.*?\]") + re_wbRecord_first = re.compile("wbRecord\((\w{4}).*?'(.+?)'.*?") + return find_records(data, re_wbRecord, re_wbRecord_first) + + +def find_stat(data): + re_stat = re.compile("wbRecord\(STAT,.*?\n.*?\n(?:.*?\n)+?.*?]") + lines = re_stat.findall(data)[0].split('\n') + + re_stat_first = re.compile("STAT, '(.*?)'") + [name] = re_stat_first.findall(lines[0]) + + re_stat_flag = re.compile("'(.*?)'") + flags = [] + for i, line in enumerate(lines[2:-1]): + [l] = re_stat_flag.findall(line) + if l: + flags += [Flag(i, l)] + + return Record("STAT", name, flags) + + +def find_concrete_wbRefRecords(data): + re_wbRefRecord = re.compile("wbRefRecord\(\w{4},.*?\n.*?wbFlagsList\(\[.*?\n(?:.*?\n)+?.*?\]") + re_wbRefRecord_first = re.compile("wbRefRecord\((\w{4}).*?'(.+?)'.*?") + return find_records(data, re_wbRefRecord, re_wbRefRecord_first) + + +def find_ReferenceRecords(data): + re_ReferenceRecordDef = re.compile("wbRefRecord\(aSignature, .*?\n(?:.*?\n)+?.*?]") + re_ReferenceRecordDef_first = re.compile("wbRefRecord\((\w+?), (\w+?),") + [d] = find_records(data, re_ReferenceRecordDef, re_ReferenceRecordDef_first) + + re_ReferenceRecord = re.compile("ReferenceRecord\((\w{4}), '(.*?)'\);") + rr = re_ReferenceRecord.findall(data) + + records = [Record(r[0], r[1], d.flags) for r in rr] + return records + + +def find_wbRefRecords(data): + records = find_concrete_wbRefRecords(data) + records = find_ReferenceRecords(data) + return records + + +fdir = os.path.dirname(__file__) +with open(os.path.join(fdir, "wbDefinitionsTES5.pas"), "r") as f: + inp = f.read() + +records = find_wbRecords(inp) + [find_stat(inp)] + find_wbRefRecords(inp) +records.sort(key = lambda x: x.fourcc) +print(len(records)) + +class Encoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, Jsonify): + return obj.encode() + else: + return json.JSONEncoder.default(self, obj) + +with open(os.path.join(fdir, "flags.json"), "w") as f: + json.dump(records, f, cls=Encoder, indent=4) diff --git a/reference/flags.json b/reference/flags.json new file mode 100644 index 0000000..ded0b29 --- /dev/null +++ b/reference/flags.json @@ -0,0 +1,1391 @@ +[ + { + "fourcc": "AACT", + "name": "Action", + "flags": [] + }, + { + "fourcc": "ACHR", + "name": "Placed NPC", + "flags": [ + { + "bit": "9", + "description": "Starts Dead" + }, + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "11", + "description": "Initially Disabled" + }, + { + "bit": "25", + "description": "No AI Acquire" + }, + { + "bit": "29", + "description": "Don''t Havok Settle" + } + ] + }, + { + "fourcc": "ACTI", + "name": "Activator", + "flags": [ + { + "bit": "6", + "description": "Has Tree LOD" + }, + { + "bit": "8", + "description": "Must Update Anims" + }, + { + "bit": "9", + "description": "Hidden From Local Map" + }, + { + "bit": "15", + "description": "Has Distant LOD" + }, + { + "bit": "16", + "description": "Random Anim Start" + }, + { + "bit": "17", + "description": "Dangerous" + }, + { + "bit": "20", + "description": "Ignore Object Interaction" + }, + { + "bit": "23", + "description": "Is Marker" + }, + { + "bit": "25", + "description": "Obstacle" + }, + { + "bit": "26", + "description": "NavMesh Generation - Filter" + }, + { + "bit": "27", + "description": "NavMesh Generation - Bounding Box" + }, + { + "bit": "29", + "description": "Child Can Use" + }, + { + "bit": "30", + "description": "NavMesh Generation - Ground" + } + ] + }, + { + "fourcc": "ADDN", + "name": "Addon Node", + "flags": [] + }, + { + "fourcc": "ALCH", + "name": "Ingestible", + "flags": [ + { + "bit": "29", + "description": "Medicine" + } + ] + }, + { + "fourcc": "AMMO", + "name": "Ammunition", + "flags": [ + { + "bit": "2", + "description": "Non-Playable" + } + ] + }, + { + "fourcc": "ANIO", + "name": "Animated Object", + "flags": [ + { + "bit": "9", + "description": "Unknown 9" + } + ] + }, + { + "fourcc": "APPA", + "name": "Alchemical Apparatus", + "flags": [] + }, + { + "fourcc": "ARMA", + "name": "Armor Addon", + "flags": [] + }, + { + "fourcc": "ARMO", + "name": "Armor", + "flags": [ + { + "bit": "2", + "description": "Non-Playable" + }, + { + "bit": "6", + "description": "Shield" + }, + { + "bit": "10", + "description": "Unknown 10" + }, + { + "bit": "15", + "description": "Unknown 15" + } + ] + }, + { + "fourcc": "ARTO", + "name": "Art Object", + "flags": [] + }, + { + "fourcc": "ASPC", + "name": "Acoustic Space", + "flags": [] + }, + { + "fourcc": "ASTP", + "name": "Association Type", + "flags": [] + }, + { + "fourcc": "AVIF", + "name": "Actor Value Information", + "flags": [] + }, + { + "fourcc": "BOOK", + "name": "Book", + "flags": [] + }, + { + "fourcc": "BPTD", + "name": "Body Part Data", + "flags": [] + }, + { + "fourcc": "CAMS", + "name": "Camera Shot", + "flags": [] + }, + { + "fourcc": "CELL", + "name": "Cell", + "flags": [ + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "17", + "description": "Off Limits" + }, + { + "bit": "18", + "description": "Compressed" + }, + { + "bit": "19", + "description": "Can''t Wait" + } + ] + }, + { + "fourcc": "CLAS", + "name": "Class", + "flags": [] + }, + { + "fourcc": "CLDC", + "name": "CLDC", + "flags": [] + }, + { + "fourcc": "CLFM", + "name": "Color", + "flags": [ + { + "bit": "2", + "description": "Non-Playable" + } + ] + }, + { + "fourcc": "CLMT", + "name": "Climate", + "flags": [] + }, + { + "fourcc": "COBJ", + "name": "Constructible Object", + "flags": [] + }, + { + "fourcc": "COLL", + "name": "Collision Layer", + "flags": [] + }, + { + "fourcc": "CONT", + "name": "Container", + "flags": [ + { + "bit": "15", + "description": "Has Distant LOD" + }, + { + "bit": "16", + "description": "Random Anim Start" + }, + { + "bit": "25", + "description": "Obstacle" + }, + { + "bit": "26", + "description": "NavMesh Generation - Filter" + }, + { + "bit": "27", + "description": "NavMesh Generation - Bounding Box" + }, + { + "bit": "30", + "description": "NavMesh Generation - Ground" + } + ] + }, + { + "fourcc": "CPTH", + "name": "Camera Path", + "flags": [] + }, + { + "fourcc": "CSTY", + "name": "Combat Style", + "flags": [ + { + "bit": "19", + "description": "Allow Dual Wielding" + } + ] + }, + { + "fourcc": "DEBR", + "name": "Debris", + "flags": [] + }, + { + "fourcc": "DIAL", + "name": "Dialog Topic", + "flags": [] + }, + { + "fourcc": "DLBR", + "name": "Dialog Branch", + "flags": [] + }, + { + "fourcc": "DLVW", + "name": "Dialog View", + "flags": [] + }, + { + "fourcc": "DOBJ", + "name": "Default Object Manager", + "flags": [] + }, + { + "fourcc": "DOOR", + "name": "Door", + "flags": [ + { + "bit": "15", + "description": "Has Distant LOD" + }, + { + "bit": "16", + "description": "Random Anim Start" + }, + { + "bit": "23", + "description": "Is Marker" + } + ] + }, + { + "fourcc": "DUAL", + "name": "Dual Cast Data", + "flags": [] + }, + { + "fourcc": "ECZN", + "name": "Encounter Zone", + "flags": [] + }, + { + "fourcc": "EFSH", + "name": "Effect Shader", + "flags": [] + }, + { + "fourcc": "ENCH", + "name": "Object Effect", + "flags": [] + }, + { + "fourcc": "EQUP", + "name": "Equip Type", + "flags": [] + }, + { + "fourcc": "EXPL", + "name": "Explosion", + "flags": [] + }, + { + "fourcc": "EYES", + "name": "Eyes", + "flags": [ + { + "bit": "2", + "description": "Non-Playable" + } + ] + }, + { + "fourcc": "FACT", + "name": "Faction", + "flags": [] + }, + { + "fourcc": "FLOR", + "name": "Flora", + "flags": [] + }, + { + "fourcc": "FLST", + "name": "FormID List", + "flags": [] + }, + { + "fourcc": "FSTP", + "name": "Footstep", + "flags": [] + }, + { + "fourcc": "FSTS", + "name": "Footstep Set", + "flags": [] + }, + { + "fourcc": "FURN", + "name": "Furniture", + "flags": [ + { + "bit": "7", + "description": "Is Perch" + }, + { + "bit": "15", + "description": "Has Distant LOD" + }, + { + "bit": "16", + "description": "Random Anim Start" + }, + { + "bit": "23", + "description": "Is Marker" + }, + { + "bit": "28", + "description": "Must Exit To Talk" + }, + { + "bit": "29", + "description": "Child Can Use" + } + ] + }, + { + "fourcc": "GLOB", + "name": "Global", + "flags": [ + { + "bit": "6", + "description": "Constant" + } + ] + }, + { + "fourcc": "GMST", + "name": "Game Setting", + "flags": [] + }, + { + "fourcc": "GRAS", + "name": "Grass", + "flags": [] + }, + { + "fourcc": "HAIR", + "name": "HAIR", + "flags": [] + }, + { + "fourcc": "HAZD", + "name": "Hazard", + "flags": [] + }, + { + "fourcc": "HDPT", + "name": "Head Part", + "flags": [ + { + "bit": "2", + "description": "Non-Playable" + } + ] + }, + { + "fourcc": "IDLE", + "name": "Idle Animation", + "flags": [] + }, + { + "fourcc": "IDLM", + "name": "Idle Marker", + "flags": [ + { + "bit": "29", + "description": "Child Can Use" + } + ] + }, + { + "fourcc": "IMAD", + "name": "Image Space Adapter", + "flags": [] + }, + { + "fourcc": "IMGS", + "name": "Image Space", + "flags": [] + }, + { + "fourcc": "INFO", + "name": "Dialog response", + "flags": [ + { + "bit": "13", + "description": "Actor Changed" + } + ] + }, + { + "fourcc": "INGR", + "name": "Ingredient", + "flags": [] + }, + { + "fourcc": "IPCT", + "name": "Impact", + "flags": [] + }, + { + "fourcc": "IPDS", + "name": "Impact Data Set", + "flags": [] + }, + { + "fourcc": "KEYM", + "name": "Key", + "flags": [ + { + "bit": "2", + "description": "Non-Playable" + } + ] + }, + { + "fourcc": "KYWD", + "name": "Keyword", + "flags": [] + }, + { + "fourcc": "LAND", + "name": "Landscape", + "flags": [ + { + "bit": "18", + "description": "Compressed" + } + ] + }, + { + "fourcc": "LCRT", + "name": "Location Reference Type", + "flags": [] + }, + { + "fourcc": "LCTN", + "name": "Location", + "flags": [] + }, + { + "fourcc": "LENS", + "name": "Lens Flare", + "flags": [] + }, + { + "fourcc": "LGTM", + "name": "Lighting Template", + "flags": [] + }, + { + "fourcc": "LIGH", + "name": "Light", + "flags": [ + { + "bit": "16", + "description": "Random Anim Start" + }, + { + "bit": "17", + "description": "Portal-strict" + }, + { + "bit": "25", + "description": "Obstacle" + } + ] + }, + { + "fourcc": "LSCR", + "name": "Load Screen", + "flags": [ + { + "bit": "10", + "description": "Displays In Main Menu" + } + ] + }, + { + "fourcc": "LTEX", + "name": "Landscape Texture", + "flags": [] + }, + { + "fourcc": "LVLI", + "name": "Leveled Item", + "flags": [] + }, + { + "fourcc": "LVLN", + "name": "Leveled NPC", + "flags": [] + }, + { + "fourcc": "LVSP", + "name": "Leveled Spell", + "flags": [] + }, + { + "fourcc": "MATO", + "name": "Material Object", + "flags": [] + }, + { + "fourcc": "MATT", + "name": "Material Type", + "flags": [] + }, + { + "fourcc": "MESG", + "name": "Message", + "flags": [] + }, + { + "fourcc": "MGEF", + "name": "Magic Effect", + "flags": [] + }, + { + "fourcc": "MISC", + "name": "Misc. Item", + "flags": [ + { + "bit": "2", + "description": "Non-Playable" + } + ] + }, + { + "fourcc": "MOVT", + "name": "Movement Type", + "flags": [] + }, + { + "fourcc": "MSTT", + "name": "Moveable Static", + "flags": [ + { + "bit": "8", + "description": "Must Update Anims" + }, + { + "bit": "9", + "description": "Hidden From Local Map" + }, + { + "bit": "15", + "description": "Has Distant LOD" + }, + { + "bit": "16", + "description": "Random Anim Start" + }, + { + "bit": "19", + "description": "Has Currents" + }, + { + "bit": "25", + "description": "Obstacle" + }, + { + "bit": "26", + "description": "NavMesh Generation - Filter" + }, + { + "bit": "27", + "description": "NavMesh Generation - Bounding Box" + }, + { + "bit": "30", + "description": "NavMesh Generation - Ground" + } + ] + }, + { + "fourcc": "MUSC", + "name": "Music Type", + "flags": [] + }, + { + "fourcc": "MUST", + "name": "Music Track", + "flags": [] + }, + { + "fourcc": "NAVI", + "name": "Navigation Mesh Info Map", + "flags": [] + }, + { + "fourcc": "NAVM", + "name": "Navigation Mesh", + "flags": [ + { + "bit": "18", + "description": "Compressed" + }, + { + "bit": "26", + "description": "AutoGen" + }, + { + "bit": "31", + "description": "NavmeshGenCell" + } + ] + }, + { + "fourcc": "NOTE", + "name": "Note", + "flags": [] + }, + { + "fourcc": "NPC_", + "name": "Non-Player Character (Actor)", + "flags": [ + { + "bit": "10", + "description": "Unknown 10" + }, + { + "bit": "18", + "description": "Compressed" + }, + { + "bit": "19", + "description": "Unknown 19" + }, + { + "bit": "29", + "description": "Bleedout Override" + } + ] + }, + { + "fourcc": "OTFT", + "name": "Outfit", + "flags": [] + }, + { + "fourcc": "PACK", + "name": "Package", + "flags": [] + }, + { + "fourcc": "PARW", + "name": "Placed Arrow", + "flags": [ + { + "bit": "7", + "description": "Turn Off Fire" + }, + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "11", + "description": "Initially Disabled" + }, + { + "bit": "28", + "description": "Reflected By Auto Water" + }, + { + "bit": "29", + "description": "Don''t Havok Settle" + }, + { + "bit": "30", + "description": "No Respawn" + } + ] + }, + { + "fourcc": "PBAR", + "name": "Placed Barrier", + "flags": [ + { + "bit": "7", + "description": "Turn Off Fire" + }, + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "11", + "description": "Initially Disabled" + }, + { + "bit": "28", + "description": "Reflected By Auto Water" + }, + { + "bit": "29", + "description": "Don''t Havok Settle" + }, + { + "bit": "30", + "description": "No Respawn" + } + ] + }, + { + "fourcc": "PBEA", + "name": "Placed Beam", + "flags": [ + { + "bit": "7", + "description": "Turn Off Fire" + }, + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "11", + "description": "Initially Disabled" + }, + { + "bit": "28", + "description": "Reflected By Auto Water" + }, + { + "bit": "29", + "description": "Don''t Havok Settle" + }, + { + "bit": "30", + "description": "No Respawn" + } + ] + }, + { + "fourcc": "PCON", + "name": "Placed Cone/Voice", + "flags": [ + { + "bit": "7", + "description": "Turn Off Fire" + }, + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "11", + "description": "Initially Disabled" + }, + { + "bit": "28", + "description": "Reflected By Auto Water" + }, + { + "bit": "29", + "description": "Don''t Havok Settle" + }, + { + "bit": "30", + "description": "No Respawn" + } + ] + }, + { + "fourcc": "PERK", + "name": "Perk", + "flags": [ + { + "bit": "2", + "description": "Non-Playable" + } + ] + }, + { + "fourcc": "PFLA", + "name": "Placed Flame", + "flags": [ + { + "bit": "7", + "description": "Turn Off Fire" + }, + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "11", + "description": "Initially Disabled" + }, + { + "bit": "28", + "description": "Reflected By Auto Water" + }, + { + "bit": "29", + "description": "Don''t Havok Settle" + }, + { + "bit": "30", + "description": "No Respawn" + } + ] + }, + { + "fourcc": "PGRE", + "name": "Placed Projectile", + "flags": [ + { + "bit": "7", + "description": "Turn Off Fire" + }, + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "11", + "description": "Initially Disabled" + }, + { + "bit": "28", + "description": "Reflected By Auto Water" + }, + { + "bit": "29", + "description": "Don''t Havok Settle" + }, + { + "bit": "30", + "description": "No Respawn" + } + ] + }, + { + "fourcc": "PHZD", + "name": "Placed Hazard", + "flags": [ + { + "bit": "7", + "description": "Turn Off Fire" + }, + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "11", + "description": "Initially Disabled" + }, + { + "bit": "28", + "description": "Reflected By Auto Water" + }, + { + "bit": "29", + "description": "Don''t Havok Settle" + }, + { + "bit": "30", + "description": "No Respawn" + } + ] + }, + { + "fourcc": "PLYR", + "name": "Player Reference", + "flags": [] + }, + { + "fourcc": "PMIS", + "name": "Placed Missile", + "flags": [ + { + "bit": "7", + "description": "Turn Off Fire" + }, + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "11", + "description": "Initially Disabled" + }, + { + "bit": "28", + "description": "Reflected By Auto Water" + }, + { + "bit": "29", + "description": "Don''t Havok Settle" + }, + { + "bit": "30", + "description": "No Respawn" + } + ] + }, + { + "fourcc": "PROJ", + "name": "Projectile", + "flags": [] + }, + { + "fourcc": "PWAT", + "name": "PWAT", + "flags": [] + }, + { + "fourcc": "QUST", + "name": "Quest", + "flags": [] + }, + { + "fourcc": "RACE", + "name": "Race", + "flags": [ + { + "bit": "19", + "description": "Critter?" + } + ] + }, + { + "fourcc": "REFR", + "name": "Placed Object", + "flags": [ + { + "bit": "10", + "description": "Persistent" + }, + { + "bit": "11", + "description": "Initially Disabled" + }, + { + "bit": "16", + "description": "Is Full LOD" + }, + { + "bit": "26", + "description": "Filter (Collision Geometry)" + }, + { + "bit": "27", + "description": "Bounding Box (Collision Geometry)" + }, + { + "bit": "28", + "description": "Reflected By Auto Water" + }, + { + "bit": "30", + "description": "Ground" + }, + { + "bit": "31", + "description": "Multibound" + } + ] + }, + { + "fourcc": "REGN", + "name": "Region", + "flags": [ + { + "bit": "6", + "description": "Border Region" + } + ] + }, + { + "fourcc": "RELA", + "name": "Relationship", + "flags": [ + { + "bit": "6", + "description": "Secret" + } + ] + }, + { + "fourcc": "REVB", + "name": "Reverb Parameters", + "flags": [] + }, + { + "fourcc": "RFCT", + "name": "Visual Effect", + "flags": [] + }, + { + "fourcc": "RGDL", + "name": "RGDL", + "flags": [] + }, + { + "fourcc": "SCEN", + "name": "Scene", + "flags": [] + }, + { + "fourcc": "SCOL", + "name": "Static Collection", + "flags": [] + }, + { + "fourcc": "SCPT", + "name": "SCPT", + "flags": [] + }, + { + "fourcc": "SCRL", + "name": "Scroll", + "flags": [] + }, + { + "fourcc": "SHOU", + "name": "Shout", + "flags": [ + { + "bit": "7", + "description": "Treat spells as powers" + } + ] + }, + { + "fourcc": "SLGM", + "name": "Soul Gem", + "flags": [ + { + "bit": "17", + "description": "Can Hold NPC Soul" + } + ] + }, + { + "fourcc": "SMBN", + "name": "Story Manager Branch Node", + "flags": [] + }, + { + "fourcc": "SMEN", + "name": "Story Manager Event Node", + "flags": [] + }, + { + "fourcc": "SMQN", + "name": "Story Manager Quest Node", + "flags": [] + }, + { + "fourcc": "SNCT", + "name": "Sound Category", + "flags": [] + }, + { + "fourcc": "SNDR", + "name": "Sound Descriptor", + "flags": [] + }, + { + "fourcc": "SOPM", + "name": "Sound Output Model", + "flags": [] + }, + { + "fourcc": "SOUN", + "name": "Sound Marker", + "flags": [] + }, + { + "fourcc": "SPEL", + "name": "Spell", + "flags": [] + }, + { + "fourcc": "SPGD", + "name": "Shader Particle Geometry", + "flags": [] + }, + { + "fourcc": "STAT", + "name": "Static", + "flags": [ + { + "bit": 2, + "description": "Never Fades" + }, + { + "bit": 5, + "description": "Deleted" + }, + { + "bit": 6, + "description": "Has Tree LOD" + }, + { + "bit": 7, + "description": "Add-On LOD Object" + }, + { + "bit": 9, + "description": "Hidden From Local Map" + }, + { + "bit": 11, + "description": "Unknown 11" + }, + { + "bit": 15, + "description": "Has Distant LOD" + }, + { + "bit": 16, + "description": "Unknown 16" + }, + { + "bit": 17, + "description": "Uses HD LOD Texture" + }, + { + "bit": 19, + "description": "Has Currents" + }, + { + "bit": 23, + "description": "Is Marker" + }, + { + "bit": 25, + "description": "Obstacle" + }, + { + "bit": 26, + "description": "NavMesh Generation - Filter" + }, + { + "bit": 27, + "description": "NavMesh Generation - Bounding Box" + }, + { + "bit": 28, + "description": "Show In World Map" + }, + { + "bit": 30, + "description": "NavMesh Generation - Ground" + } + ] + }, + { + "fourcc": "TACT", + "name": "Talking Activator", + "flags": [ + { + "bit": "9", + "description": "Hidden From Local Map" + }, + { + "bit": "16", + "description": "Random Anim Start" + }, + { + "bit": "17", + "description": "Radio Station" + } + ] + }, + { + "fourcc": "TES4", + "name": "Main File Header", + "flags": [ + { + "bit": "0", + "description": "ESM" + }, + { + "bit": "1", + "description": "Altered" + }, + { + "bit": "2", + "description": "Checked" + }, + { + "bit": "3", + "description": "Active" + }, + { + "bit": "4", + "description": "Optimized File" + }, + { + "bit": "5", + "description": "Temp ID Owner" + }, + { + "bit": "7", + "description": "Localized" + }, + { + "bit": "8", + "description": "Precalc Data Only" + }, + { + "bit": "9", + "description": "ESL', '" + } + ] + }, + { + "fourcc": "TREE", + "name": "Tree", + "flags": [ + { + "bit": "15", + "description": "Has Distant LOD" + } + ] + }, + { + "fourcc": "TXST", + "name": "Texture Set", + "flags": [] + }, + { + "fourcc": "VOLI", + "name": "Volumetric Lighting", + "flags": [] + }, + { + "fourcc": "VTYP", + "name": "Voice Type", + "flags": [] + }, + { + "fourcc": "WATR", + "name": "Water", + "flags": [] + }, + { + "fourcc": "WEAP", + "name": "Weapon", + "flags": [ + { + "bit": "2", + "description": "Non-Playable" + } + ] + }, + { + "fourcc": "WOOP", + "name": "Word of Power", + "flags": [] + }, + { + "fourcc": "WRLD", + "name": "Worldspace", + "flags": [ + { + "bit": "19", + "description": "Can''t Wait" + } + ] + }, + { + "fourcc": "WTHR", + "name": "Weather", + "flags": [] + } +] \ No newline at end of file diff --git a/reference/record_filter.py b/reference/record_filter.py new file mode 100644 index 0000000..6f50382 --- /dev/null +++ b/reference/record_filter.py @@ -0,0 +1,95 @@ +import os +import re +import json +from dataclasses import dataclass + +# helper used when dumping the records to JSON +class Jsonify: + def encode(self, value=None): + if not value: + value = self.__dict__ + return value + +# Record model +@dataclass +class Flag(Jsonify): + bit: int + description: str + +@dataclass +class Record(Jsonify): + fourcc: str + name: str + flags: list[Flag] + + +# open and read the records from xEdit source +fdir = os.path.dirname(__file__) +with open(os.path.join(fdir, "wbDefinitionsTES5.pas"), "r") as f: + inp = f.read() + +# find all wbRecord/wbRefRecord calls +re_record = re.compile("(?:wbRecord|wbRefRecord)\((.*?\n(?:.*?\n)*?.*?)\);") +all = re_record.findall(inp) + +# find all ReferenceRecord calls +re_ReferenceRecord = re.compile("ReferenceRecord\((\w{4}), '(.*?)'\);") +rr = re_ReferenceRecord.findall(inp) + +# partition all into true records and the ReferenceRecord template +[ref_template] = [x for x in all if x.startswith('aSignature')] +all = [x for x in all if not x.startswith('aSignature')] + +# generate and add ReferenceRecords to all +for sig, name in rr: + all += [ref_template.replace('aSignature', sig).replace('aName', "'" + name + "'")] + +# parse strings into Records +re_first = re.compile("(\w{4}), '(.*?)'") +re_flags = re.compile(".*?\n.*?wbFlagsList\(.*?\n(?:.*?\n)+?.*?\]") +re_flag_line = re.compile(".*?(\d+?),.*?'(.*)'") +re_stat_flag = re.compile(".*?'(.*?)'") +records = [] +for string in all: + # git sig and name from first line + sig, name = re_first.match(string).groups() + # check for a flag list, process if found + flags_string = re_flags.match(string) + flags = [] + if flags_string: + flag_lines = flags_string.group(0).split('\n')[2:-1] + assert len(flag_lines) > 0 + for line in flag_lines: + bit, desc = re_flag_line.match(line).groups() + flags += [Flag(bit, desc)] + # handle STAT special case + elif sig == "STAT": + flags_string = re.match(".*?\n.*?wbFlags\(.*?\n(?:.*?\n){32}.*?\]", string).group(0) + lines = flags_string.split('\n')[2:-1] + for bit, line in enumerate(lines): + desc = re_stat_flag.match(line).group(1) + if desc: + flags += [Flag(bit, desc)] + records += [Record(sig, name, flags)] + +# remove duplicates +rdict = {r.fourcc: r for r in records} +records = list(rdict.values()) + +# add in the apparently supported NOTE +records += [Record("NOTE", "Note", [])] + +# sort the records by signature +records = sorted(records, key=lambda x: x.fourcc) + +# write the records out to a JSON file +class Encoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, Jsonify): + return obj.encode() + else: + return json.JSONEncoder.default(self, obj) + +with open(os.path.join(fdir, "flags.json"), "w") as f: + json.dump(records, f, cls=Encoder, indent=4) + \ No newline at end of file diff --git a/reference/record_types.csv b/reference/record_types.csv new file mode 100644 index 0000000..d4accc1 --- /dev/null +++ b/reference/record_types.csv @@ -0,0 +1,137 @@ +AACT,Action +ACHR,Placed NPC +ACTI,Activator +ADDN,Addon Node +ALCH,Ingestible +AMMO,Ammunition +ANIO,Animated Object +APPA,Alchemical Apparatus +ARMA,Armor Addon +ARMO,Armor +ARTO,Art Object +ASPC,Acoustic Space +ASTP,Association Type +AVIF,Actor Value Information +BOOK,Book +BPTD,Body Part Data +CAMS,Camera Shot +CELL,Cell +CLAS,Class +CLDC,CLDC +CLFM,Color +CLMT,Climate +COBJ,Constructible Object +COLL,Collision Layer +CONT,Container +CPTH,Camera Path +CSTY,Combat Style +DEBR,Debris +DIAL,Dialog Topic +DLBR,Dialog Branch +DLVW,Dialog View +DOBJ,Default Object Manager +DOOR,Door +DUAL,Dual Cast Data +ECZN,Encounter Zone +EFSH,Effect Shader +ENCH,Object Effect +EQUP,Equip Type +EXPL,Explosion +EYES,Eyes +FACT,Faction +FLOR,Flora +FLST,FormID List +FSTP,Footstep +FSTS,Footstep Set +FURN,Furniture +GLOB,Global +GMST,Game Setting +GRAS,Grass +GRUP,Internal File Structure Group +HAIR,HAIR +HAZD,Hazard +HDPT,Head Part +IDLE,Idle Animation +IDLM,Idle Marker +IMAD,Image Space Adapter +IMGS,Image Space +INFO,Dialog response +INGR,Ingredient +IPCT,Impact +IPDS,Impact Data Set +KEYM,Key +KYWD,Keyword +LAND,Landscape +LCRT,Location Reference Type +LCTN,Location +LENS,Lens Flare +LGTM,Lighting Template +LIGH,Light +LSCR,Load Screen +LTEX,Landscape Texture +LVLI,Leveled Item +LVLN,Leveled NPC +LVSP,Leveled Spell +MATO,Material Object +MATT,Material Type +MESG,Message +MGEF,Magic Effect +MISC,Misc. Item +MOVT,Movement Type +MSTT,Moveable Static +MUSC,Music Type +MUST,Music Track +NAVI,Navigation Mesh Info Map +NAVM,Navigation Mesh +NOTE,NOTE +NPC_,Non-Player Character (Actor) +OTFT,Outfit +PACK,Package +PARW,Placed Arrow +PBAR,Placed Barrier +PBEA,Placed Beam +PCON,Placed Cone/Voice +PERK,Perk +PFLA,Placed Flame +PGRE,Placed Projectile +PHZD,Placed Hazard +PLYR,Player Reference +PMIS,Placed Missile +PROJ,Projectile +PWAT,PWAT +QUST,Quest +RACE,Race +REFR,Placed Object +REGN,Region +RELA,Relationship +REVB,Reverb Parameters +RFCT,Visual Effect +RGDL,RGDL +SCEN,Scene +SCOL,SCOL +SCOL,Static Collection +SCPT,SCPT +SCRL,Scroll +SHOU,Shout +SLGM,Soul Gem +SMBN,Story Manager Branch Node +SMEN,Story Manager Event Node +SMQN,Story Manager Quest Node +SNCT,Sound Category +SNDR,Sound Descriptor +SOPM,Sound Output Model +SOUN,Sound Marker +SPEL,Spell +SPGD,Shader Particle Geometry +STAT,Static +TACT,Talking Activator +TES4,Main File Header +TREE,Tree +TXST,Texture Set +VOLI,Volumetric Lighting +VTYP,Voice Type +WATR,Water +WEAP,Weapon +WOOP,Word of Power +WRLD,Worldspace +WTHR,Weather diff --git a/reference/wbDefinitionsTES5.pas b/reference/wbDefinitionsTES5.pas new file mode 100644 index 0000000..e50b2e4 --- /dev/null +++ b/reference/wbDefinitionsTES5.pas @@ -0,0 +1,13841 @@ +{****************************************************************************** + + This Source Code Form is subject to the terms of the Mozilla Public License, + v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain + one at https://mozilla.org/MPL/2.0/. + +*******************************************************************************} + +unit wbDefinitionsTES5; + +{$I wbDefines.inc} + +interface + +uses + wbInterface; + +var + wbBipedObjectFlags: IwbFlagsDef; + wbEquipType: IwbFlagsDef; + wbFurnitureEntryTypeFlags: IwbFlagsDef; + wbPKDTFlags: IwbFlagsDef; + wbPKDTInterruptFlags: IwbFlagsDef; + wbSMNodeFlags: IwbFlagsDef; + + wbAdvanceActionEnum: IwbEnumDef; + wbAlignmentEnum: IwbEnumDef; + wbArmorTypeEnum: IwbEnumDef; + wbAttackAnimationEnum: IwbEnumDef; + wbBipedObjectEnum: IwbEnumDef; + wbBlendModeEnum: IwbEnumDef; + wbBlendOpEnum: IwbEnumDef; + wbCastEnum: IwbEnumDef; + wbCastingSourceEnum: IwbEnumDef; + wbCrimeTypeEnum: IwbEnumDef; + wbCriticalStageEnum: IwbEnumDef; + wbEmotionTypeEnum: IwbEnumDef; + wbEntryPointsEnum: IwbEnumDef; + wbEventFunctionEnum: IwbEnumDef; + wbEventMemberEnum: IwbEnumDef; + wbFormTypeEnum: IwbEnumDef; + wbFunctionsEnum: IwbEnumDef; + wbFurnitureAnimTypeEnum: IwbEnumDef; + wbLocationEnum: IwbEnumDef; + wbMapMarkerEnum: IwbEnumDef; + wbMiscStatEnum: IwbEnumDef; + wbMusicEnum: IwbEnumDef; + wbObjectTypeEnum: IwbEnumDef; + wbPropTypeEnum: IwbEnumDef; + wbQuestTypeEnum: IwbEnumDef; + wbSkillEnum: IwbEnumDef; + wbSoulGemEnum: IwbEnumDef; + wbSoundLevelEnum: IwbEnumDef; + wbTargetEnum: IwbEnumDef; + wbTintMaskTypeEnum: IwbEnumDef; + wbVatsValueFunctionEnum: IwbEnumDef; + wbWardStateEnum: IwbEnumDef; + wbWeaponAnimTypeEnum: IwbEnumDef; + wbZTestFuncEnum: IwbEnumDef; + +procedure DefineTES5; + +implementation + +uses + Types, + Classes, + SysUtils, + Math, + Variants, + IOUtils, + wbHelpers, + wbDefinitionsCommon; + +const + _00_IAD: TwbSignature = #$00'IAD'; + _01_IAD: TwbSignature = #$01'IAD'; + _02_IAD: TwbSignature = #$02'IAD'; + _03_IAD: TwbSignature = #$03'IAD'; + _04_IAD: TwbSignature = #$04'IAD'; + _05_IAD: TwbSignature = #$05'IAD'; + _06_IAD: TwbSignature = #$06'IAD'; + _07_IAD: TwbSignature = #$07'IAD'; + _08_IAD: TwbSignature = #$08'IAD'; + _09_IAD: TwbSignature = #$09'IAD'; + _0A_IAD: TwbSignature = #$0A'IAD'; + _0B_IAD: TwbSignature = #$0B'IAD'; + _0C_IAD: TwbSignature = #$0C'IAD'; + _0D_IAD: TwbSignature = #$0D'IAD'; + _0E_IAD: TwbSignature = #$0E'IAD'; + _0F_IAD: TwbSignature = #$0F'IAD'; + _10_IAD: TwbSignature = #$10'IAD'; + _11_IAD: TwbSignature = #$11'IAD'; + _12_IAD: TwbSignature = #$12'IAD'; + _13_IAD: TwbSignature = #$13'IAD'; + _14_IAD: TwbSignature = #$14'IAD'; + _40_IAD: TwbSignature = #$40'IAD'; + _41_IAD: TwbSignature = #$41'IAD'; + _42_IAD: TwbSignature = #$42'IAD'; + _43_IAD: TwbSignature = #$43'IAD'; + _44_IAD: TwbSignature = #$44'IAD'; + _45_IAD: TwbSignature = #$45'IAD'; + _46_IAD: TwbSignature = #$46'IAD'; + _47_IAD: TwbSignature = #$47'IAD'; + _48_IAD: TwbSignature = #$48'IAD'; + _49_IAD: TwbSignature = #$49'IAD'; + _4A_IAD: TwbSignature = #$4A'IAD'; + _4B_IAD: TwbSignature = #$4B'IAD'; + _4C_IAD: TwbSignature = #$4C'IAD'; + _4D_IAD: TwbSignature = #$4D'IAD'; + _4E_IAD: TwbSignature = #$4E'IAD'; + _4F_IAD: TwbSignature = #$4F'IAD'; + _50_IAD: TwbSignature = #$50'IAD'; + _51_IAD: TwbSignature = #$51'IAD'; + _52_IAD: TwbSignature = #$52'IAD'; + _53_IAD: TwbSignature = #$53'IAD'; + _54_IAD: TwbSignature = #$54'IAD'; + +{00TX} _00_0TX: TwbSignature = #$30'0TX'; +{10TX} _10_0TX: TwbSignature = #$31'0TX'; +{20TX} _20_0TX: TwbSignature = #$32'0TX'; +{30TX} _30_0TX: TwbSignature = #$33'0TX'; +{40TX} _40_0TX: TwbSignature = #$34'0TX'; +{50TX} _50_0TX: TwbSignature = #$35'0TX'; +{60TX} _60_0TX: TwbSignature = #$36'0TX'; +{70TX} _70_0TX: TwbSignature = #$37'0TX'; +{80TX} _80_0TX: TwbSignature = #$38'0TX'; +{90TX} _90_0TX: TwbSignature = #$39'0TX'; +{:0TX} _3A_0TX: TwbSignature = #$3A'0TX'; +{;0TX} _3B_0TX: TwbSignature = #$3B'0TX'; +{<0TX} _3C_0TX: TwbSignature = #$3C'0TX'; +{=0TX} _3D_0TX: TwbSignature = #$3D'0TX'; +{>0TX} _3E_0TX: TwbSignature = #$3E'0TX'; +{?0TX} _3F_0TX: TwbSignature = #$3F'0TX'; +{@0TX} _40h_0TX: TwbSignature = #$40'0TX'; +{A0TX} A0TX: TwbSignature = 'A0TX'; +{B0TX} B0TX: TwbSignature = 'B0TX'; +{C0TX} C0TX: TwbSignature = 'C0TX'; +{D0TX} D0TX: TwbSignature = 'D0TX'; +{E0TX} E0TX: TwbSignature = 'E0TX'; +{F0TX} F0TX: TwbSignature = 'F0TX'; +{G0TX} G0TX: TwbSignature = 'G0TX'; +{H0TX} H0TX: TwbSignature = 'H0TX'; +{I0TX} I0TX: TwbSignature = 'I0TX'; +{J0TX} J0TX: TwbSignature = 'J0TX'; +{K0TX} K0TX: TwbSignature = 'K0TX'; +{L0TX} L0TX: TwbSignature = 'L0TX'; + + AACT : TwbSignature = 'AACT'; + ACBS : TwbSignature = 'ACBS'; + ACEC : TwbSignature = 'ACEC'; { New To Dawnguard } + ACEP : TwbSignature = 'ACEP'; { New To Dawnguard } + ACHR : TwbSignature = 'ACHR'; + ACID : TwbSignature = 'ACID'; { New To Dawnguard } + ACPR : TwbSignature = 'ACPR'; { New To Skyrim } + ACSR : TwbSignature = 'ACSR'; { New To Dawnguard } + ACTI : TwbSignature = 'ACTI'; + ACUN : TwbSignature = 'ACUN'; { New To Dawnguard } + ADDN : TwbSignature = 'ADDN'; + AHCF : TwbSignature = 'AHCF'; { New To Skyrim } + AHCM : TwbSignature = 'AHCM'; { New To Skyrim } + AIDT : TwbSignature = 'AIDT'; + ALCA : TwbSignature = 'ALCA'; { New To Skyrim } + ALCH : TwbSignature = 'ALCH'; + ALCL : TwbSignature = 'ALCL'; { New To Skyrim } + ALCO : TwbSignature = 'ALCO'; { New To Skyrim } + ALDN : TwbSignature = 'ALDN'; { New To Skyrim } + ALEA : TwbSignature = 'ALEA'; { New To Skyrim } + ALED : TwbSignature = 'ALED'; { New To Skyrim } + ALEQ : TwbSignature = 'ALEQ'; { New To Skyrim } + ALFA : TwbSignature = 'ALFA'; { New To Skyrim } + ALFC : TwbSignature = 'ALFC'; { New To Skyrim } + ALFD : TwbSignature = 'ALFD'; { New To Skyrim } + ALFE : TwbSignature = 'ALFE'; { New To Skyrim } + ALFI : TwbSignature = 'ALFI'; { New To Skyrim } + ALFL : TwbSignature = 'ALFL'; { New To Skyrim } + ALFR : TwbSignature = 'ALFR'; { New To Skyrim } + ALID : TwbSignature = 'ALID'; { New To Skyrim } + ALLS : TwbSignature = 'ALLS'; { New To Skyrim } + ALNA : TwbSignature = 'ALNA'; { New To Skyrim } + ALNT : TwbSignature = 'ALNT'; { New To Skyrim } + ALPC : TwbSignature = 'ALPC'; { New To Skyrim } + ALRT : TwbSignature = 'ALRT'; { New To Skyrim } + ALSP : TwbSignature = 'ALSP'; { New To Skyrim } + ALST : TwbSignature = 'ALST'; { New To Skyrim } + ALUA : TwbSignature = 'ALUA'; { New To Skyrim } + AMMO : TwbSignature = 'AMMO'; + ANAM : TwbSignature = 'ANAM'; + ANIO : TwbSignature = 'ANIO'; + APPA : TwbSignature = 'APPA'; + ARMA : TwbSignature = 'ARMA'; + ARMO : TwbSignature = 'ARMO'; + ARTO : TwbSignature = 'ARTO'; + ASPC : TwbSignature = 'ASPC'; + ASTP : TwbSignature = 'ASTP'; + ATKD : TwbSignature = 'ATKD'; { New to Skyrim } + ATKE : TwbSignature = 'ATKE'; { New to Skyrim } + ATKR : TwbSignature = 'ATKR'; { New to Skyrim } + ATXT : TwbSignature = 'ATXT'; + AVIF : TwbSignature = 'AVIF'; + AVSK : TwbSignature = 'AVSK'; { New to Skyrim } + BAMT : TwbSignature = 'BAMT'; { New to Skyrim } + BIDS : TwbSignature = 'BIDS'; { New to Skyrim } + BIPL : TwbSignature = 'BIPL'; + BMCT : TwbSignature = 'BMCT'; + BNAM : TwbSignature = 'BNAM'; + BOD2 : TwbSignature = 'BOD2'; { New to Skyrim 1.6.91 CK} + BODT : TwbSignature = 'BODT'; { New to Skyrim } + BOOK : TwbSignature = 'BOOK'; + BPND : TwbSignature = 'BPND'; + BPNI : TwbSignature = 'BPNI'; + BPNN : TwbSignature = 'BPNN'; + BPNT : TwbSignature = 'BPNT'; + BPTD : TwbSignature = 'BPTD'; + BPTN : TwbSignature = 'BPTN'; + BTXT : TwbSignature = 'BTXT'; + CAMS : TwbSignature = 'CAMS'; + CELL : TwbSignature = 'CELL'; + CIS1 : TwbSignature = 'CIS1'; { New to Skyrim } + CIS2 : TwbSignature = 'CIS2'; { New to Skyrim } + CITC : TwbSignature = 'CITC'; { New to Skyrim } + CLAS : TwbSignature = 'CLAS'; + CLDC : TwbSignature = 'CLDC'; { New to Skyrim, but unused } + CLFM : TwbSignature = 'CLFM'; + CLMT : TwbSignature = 'CLMT'; + CNAM : TwbSignature = 'CNAM'; + CNTO : TwbSignature = 'CNTO'; + COBJ : TwbSignature = 'COBJ'; + COCT : TwbSignature = 'COCT'; { New to Skyrim 'Count'} + COED : TwbSignature = 'COED'; + COLL : TwbSignature = 'COLL'; + CONT : TwbSignature = 'CONT'; + CPTH : TwbSignature = 'CPTH'; + CRDT : TwbSignature = 'CRDT'; + CRGR : TwbSignature = 'CRGR'; { New to Skyrim } + CRIF : TwbSignature = 'CRIF'; { New to Skyrim } + CRVA : TwbSignature = 'CRVA'; { New to Skyrim } + CSCR : TwbSignature = 'CSCR'; + CSDC : TwbSignature = 'CSDC'; + CSDI : TwbSignature = 'CSDI'; + CSDT : TwbSignature = 'CSDT'; + CSFL : TwbSignature = 'CSFL'; { New to Skyrim } + CSGD : TwbSignature = 'CSGD'; { New to Skyrim } + CSLR : TwbSignature = 'CSLR'; { New to Skyrim } + CSMD : TwbSignature = 'CSMD'; { New to Skyrim } + CSME : TwbSignature = 'CSME'; { New to Skyrim } + CSTY : TwbSignature = 'CSTY'; + CTDA : TwbSignature = 'CTDA'; + DALC : TwbSignature = 'DALC'; { New to Skyrim } + DATA : TwbSignature = 'DATA'; + DEBR : TwbSignature = 'DEBR'; + DELE : TwbSignature = 'DELE'; + DEMO : TwbSignature = 'DEMO'; { New to Skyrim } + DESC : TwbSignature = 'DESC'; + DEST : TwbSignature = 'DEST'; + DEVA : TwbSignature = 'DEVA'; { New to Skyrim } + DFTF : TwbSignature = 'DFTF'; { New To Skyrim } + DFTM : TwbSignature = 'DFTM'; { New To Skyrim } + DIAL : TwbSignature = 'DIAL'; + DLBR : TwbSignature = 'DLBR'; + DLVW : TwbSignature = 'DLVW'; + DMAX : TwbSignature = 'DMAX'; { New to Skyrim } + DMDL : TwbSignature = 'DMDL'; + DMDS : TwbSignature = 'DMDS'; { New to Skyrim } + DMIN : TwbSignature = 'DMIN'; { New to Skyrim } + DNAM : TwbSignature = 'DNAM'; + DOBJ : TwbSignature = 'DOBJ'; + DODT : TwbSignature = 'DODT'; + DOFT : TwbSignature = 'DOFT'; { New to Skyrim } + DOOR : TwbSignature = 'DOOR'; + DPLT : TwbSignature = 'DPLT'; { New to Skyrim } + DSTD : TwbSignature = 'DSTD'; + DSTF : TwbSignature = 'DSTF'; + DUAL : TwbSignature = 'DUAL'; + EAMT : TwbSignature = 'EAMT'; + ECOR : TwbSignature = 'ECOR'; { New to Skyrim } + ECZN : TwbSignature = 'ECZN'; + EDID : TwbSignature = 'EDID'; + EFID : TwbSignature = 'EFID'; + EFIT : TwbSignature = 'EFIT'; + EFSH : TwbSignature = 'EFSH'; + EITM : TwbSignature = 'EITM'; + ENAM : TwbSignature = 'ENAM'; + ENCH : TwbSignature = 'ENCH'; + ENIT : TwbSignature = 'ENIT'; + EPF2 : TwbSignature = 'EPF2'; + EPF3 : TwbSignature = 'EPF3'; + EPFD : TwbSignature = 'EPFD'; + EPFT : TwbSignature = 'EPFT'; + EQUP : TwbSignature = 'EQUP'; + ESCE : TwbSignature = 'ESCE'; + ETYP : TwbSignature = 'ETYP'; + EXPL : TwbSignature = 'EXPL'; + EYES : TwbSignature = 'EYES'; + FACT : TwbSignature = 'FACT'; + FCHT : TwbSignature = 'FCHT'; { New to Skyrim } + FLMV : TwbSignature = 'FLMV'; { New to Skyrim } + FLOR : TwbSignature = 'FLOR'; + FLST : TwbSignature = 'FLST'; + FLTR : TwbSignature = 'FLTR'; { New to Skyrim } + FLTV : TwbSignature = 'FLTV'; + FNAM : TwbSignature = 'FNAM'; + FNMK : TwbSignature = 'FNMK'; { New to Skyrim } + FNPR : TwbSignature = 'FNPR'; { New to Skyrim } + FPRT : TwbSignature = 'FPRT'; { New to Skyrim } + FSTP : TwbSignature = 'FSTP'; + FSTS : TwbSignature = 'FSTS'; + FTSF : TwbSignature = 'FTSF'; { New to Skyrim } + FTSM : TwbSignature = 'FTSM'; { New to Skyrim } + FTST : TwbSignature = 'FTST'; { New to Skyrim } + FULL : TwbSignature = 'FULL'; + FURN : TwbSignature = 'FURN'; + GLOB : TwbSignature = 'GLOB'; + GMST : TwbSignature = 'GMST'; + GNAM : TwbSignature = 'GNAM'; + GRAS : TwbSignature = 'GRAS'; + GWOR : TwbSignature = 'GWOR'; { New to Skyrim } + HAIR : TwbSignature = 'HAIR'; { Unused in Skyrim, but contained in Skyrim.esm } + HAZD : TwbSignature = 'HAZD'; + HCLF : TwbSignature = 'HCLF'; { New to Skyrim } + HDPT : TwbSignature = 'HDPT'; + HEAD : TwbSignature = 'HEAD'; { New to Skyrim } + HEDR : TwbSignature = 'HEDR'; + HNAM : TwbSignature = 'HNAM'; + HTID : TwbSignature = 'HTID'; { New to Skyrim } + ICO2 : TwbSignature = 'ICO2'; + ICON : TwbSignature = 'ICON'; + IDLA : TwbSignature = 'IDLA'; + IDLB : TwbSignature = 'IDLB'; + IDLC : TwbSignature = 'IDLC'; + IDLE : TwbSignature = 'IDLE'; + IDLF : TwbSignature = 'IDLF'; + IDLM : TwbSignature = 'IDLM'; + IDLT : TwbSignature = 'IDLT'; + IMAD : TwbSignature = 'IMAD'; + IMGS : TwbSignature = 'IMGS'; + IMSP : TwbSignature = 'IMSP'; { New to Skyrim } + INAM : TwbSignature = 'INAM'; + INCC : TwbSignature = 'INCC'; { New to Skyrim } + INDX : TwbSignature = 'INDX'; + INFO : TwbSignature = 'INFO'; + INGR : TwbSignature = 'INGR'; + INTV : TwbSignature = 'INTV'; + IPCT : TwbSignature = 'IPCT'; + IPDS : TwbSignature = 'IPDS'; + ITXT : TwbSignature = 'ITXT'; + JAIL : TwbSignature = 'JAIL'; { New To Skyrim } + JNAM : TwbSignature = 'JNAM'; + JOUT : TwbSignature = 'JOUT'; { New To Skyrim } + KEYM : TwbSignature = 'KEYM'; + KNAM : TwbSignature = 'KNAM'; + KSIZ : TwbSignature = 'KSIZ'; + KWDA : TwbSignature = 'KWDA'; + KYWD : TwbSignature = 'KYWD'; + LAND : TwbSignature = 'LAND'; + LCEC : TwbSignature = 'LCEC'; { New to Skyrim } + LCEP : TwbSignature = 'LCEP'; { New to Skyrim } + LCID : TwbSignature = 'LCID'; { New to Skyrim } + LCPR : TwbSignature = 'LCPR'; { New to Skyrim } + LCRT : TwbSignature = 'LCRT'; + LCSR : TwbSignature = 'LCSR'; { New to Skyrim } + LCTN : TwbSignature = 'LCTN'; + LCUN : TwbSignature = 'LCUN'; { New to Skyrim } + LENS : TwbSignature = 'LENS'; { New to SSE } + LFSD : TwbSignature = 'LFSD'; { New to SSE } + LFSP : TwbSignature = 'LFSP'; { New to SSE } + LGTM : TwbSignature = 'LGTM'; + LIGH : TwbSignature = 'LIGH'; + LLCT : TwbSignature = 'LLCT'; {New to Skyrim, part of LVLI 'Count'} + LNAM : TwbSignature = 'LNAM'; + LSCR : TwbSignature = 'LSCR'; + LTEX : TwbSignature = 'LTEX'; + MPCD : TwbSignature = 'MPCD'; + LTMP : TwbSignature = 'LTMP'; + LVLC : TwbSignature = 'LVLC'; + LVLD : TwbSignature = 'LVLD'; + LVLF : TwbSignature = 'LVLF'; + LVLG : TwbSignature = 'LVLG'; + LVLI : TwbSignature = 'LVLI'; + LVLN : TwbSignature = 'LVLN'; + LVLO : TwbSignature = 'LVLO'; + LVSP : TwbSignature = 'LVSP'; + MAST : TwbSignature = 'MAST'; + MATO : TwbSignature = 'MATO'; + MATT : TwbSignature = 'MATT'; + MCHT : TwbSignature = 'MCHT'; { New to Skyrim } + MDOB : TwbSignature = 'MDOB'; + MESG : TwbSignature = 'MESG'; + MGEF : TwbSignature = 'MGEF'; + MHDT : TwbSignature = 'MHDT'; { New to Skyrim } + MIC2 : TwbSignature = 'MIC2'; + MICO : TwbSignature = 'MICO'; + MISC : TwbSignature = 'MISC'; + MNAM : TwbSignature = 'MNAM'; + MO2S : TwbSignature = 'MO2S'; + MO2T : TwbSignature = 'MO2T'; + MO3S : TwbSignature = 'MO3S'; + MO3T : TwbSignature = 'MO3T'; + MO4S : TwbSignature = 'MO4S'; + MO4T : TwbSignature = 'MO4T'; + MO5S : TwbSignature = 'MO5S'; { New to Skyrim } + MO5T : TwbSignature = 'MO5T'; { New to Skyrim } + MOD2 : TwbSignature = 'MOD2'; + MOD3 : TwbSignature = 'MOD3'; + MOD4 : TwbSignature = 'MOD4'; + MOD5 : TwbSignature = 'MOD5'; { New to Skyrim } + MODD : TwbSignature = 'MODD'; + MODL : TwbSignature = 'MODL'; + MODS : TwbSignature = 'MODS'; + MOVT : TwbSignature = 'MOVT'; + MPAI : TwbSignature = 'MPAI'; { New To Skyrim } + MPAV : TwbSignature = 'MPAV'; { New To Skyrim } + MPRT : TwbSignature = 'MPRT'; { New to Skyrim } + MSTT : TwbSignature = 'MSTT'; + MTNM : TwbSignature = 'MTNM'; { New to Skyrim } + MTYP : TwbSignature = 'MTYP'; { New To Skyrim } + MUSC : TwbSignature = 'MUSC'; + MUST : TwbSignature = 'MUST'; + NAM0 : TwbSignature = 'NAM0'; + NAM1 : TwbSignature = 'NAM1'; + NAM2 : TwbSignature = 'NAM2'; + NAM3 : TwbSignature = 'NAM3'; + NAM4 : TwbSignature = 'NAM4'; + NAM5 : TwbSignature = 'NAM5'; + NAM6 : TwbSignature = 'NAM6'; + NAM7 : TwbSignature = 'NAM7'; + NAM8 : TwbSignature = 'NAM8'; + NAM9 : TwbSignature = 'NAM9'; + NAMA : TwbSignature = 'NAMA'; { New to Skyrim } + NAME : TwbSignature = 'NAME'; + NAVI : TwbSignature = 'NAVI'; + NAVM : TwbSignature = 'NAVM'; + NEXT : TwbSignature = 'NEXT'; + NNAM : TwbSignature = 'NNAM'; + NPC_ : TwbSignature = 'NPC_'; + NULL : TwbSignature = 'NULL'; + NVER : TwbSignature = 'NVER'; + NVMI : TwbSignature = 'NVMI'; + NVNM : TwbSignature = 'NVNM'; { New to Skyrim } + NVPP : TwbSignature = 'NVPP'; { New to Skyrim } + NVSI : TwbSignature = 'NVSI'; { New to Dawnguard } + OBND : TwbSignature = 'OBND'; + OCOR : TwbSignature = 'OCOR'; { New to Skyrim } + ONAM : TwbSignature = 'ONAM'; + OTFT : TwbSignature = 'OTFT'; + PACK : TwbSignature = 'PACK'; + PARW : TwbSignature = 'PARW'; { New to Skyrim } + PBAR : TwbSignature = 'PBAR'; { New to Skyrim } + PBEA : TwbSignature = 'PBEA'; { New to Skyrim } + PCON : TwbSignature = 'PCON'; { New to Skyrim } + PDTO : TwbSignature = 'PDTO'; { New to Skyrim } + PERK : TwbSignature = 'PERK'; + PFIG : TwbSignature = 'PFIG'; + PFLA : TwbSignature = 'PFLA'; { New to Skyrim } + PFO2 : TwbSignature = 'PFO2'; { New to Skyrim } + PFOR : TwbSignature = 'PFOR'; { New to Skyrim } + PFPC : TwbSignature = 'PFPC'; + PGRE : TwbSignature = 'PGRE'; + PHTN : TwbSignature = 'PHTN'; { New to Skyrim } + PHWT : TwbSignature = 'PHWT'; { New to Skyrim } + PHZD : TwbSignature = 'PHZD'; + PKC2 : TwbSignature = 'PKC2'; { New to Skyrim } + PKCU : TwbSignature = 'PKCU'; { New to Skyrim } + PKDT : TwbSignature = 'PKDT'; + PKID : TwbSignature = 'PKID'; + PLCN : TwbSignature = 'PLCN'; { New to Skyrim } + PLDT : TwbSignature = 'PLDT'; + PLVD : TwbSignature = 'PLVD'; { New to Skyrim } + PLYR : TwbSignature = 'PLYR'; + PMIS : TwbSignature = 'PMIS'; + PNAM : TwbSignature = 'PNAM'; + POBA : TwbSignature = 'POBA'; + POCA : TwbSignature = 'POCA'; + POEA : TwbSignature = 'POEA'; + PRCB : TwbSignature = 'PRCB'; { New to Skyrim } + PRKC : TwbSignature = 'PRKC'; + PRKE : TwbSignature = 'PRKE'; + PRKF : TwbSignature = 'PRKF'; + PRKR : TwbSignature = 'PRKR'; { New to Skyrim } + PRKZ : TwbSignature = 'PRKZ'; { New to Skyrim } + PROJ : TwbSignature = 'PROJ'; + PSDT : TwbSignature = 'PSDT'; + PTDA : TwbSignature = 'PTDA'; { New to Skyrim } + PWAT : TwbSignature = 'PWAT'; { Unused in Skyrim, but contained in Skyrim.esm } + QNAM : TwbSignature = 'QNAM'; + QOBJ : TwbSignature = 'QOBJ'; + QSDT : TwbSignature = 'QSDT'; + QSTA : TwbSignature = 'QSTA'; + QTGL : TwbSignature = 'QTGL'; { New To Skyrim } + QUAL : TwbSignature = 'QUAL'; { New To Skyrim } + QUST : TwbSignature = 'QUST'; + RACE : TwbSignature = 'RACE'; + RCEC : TwbSignature = 'RCEC'; { New To Skyrim } + RCLR : TwbSignature = 'RCLR'; + RCPR : TwbSignature = 'RCPR'; { New to Dawnguard } + RCSR : TwbSignature = 'RCSR'; { New To Skyrim } + RCUN : TwbSignature = 'RCUN'; { New To Skyrim } + RDAT : TwbSignature = 'RDAT'; + RDGS : TwbSignature = 'RDGS'; + RDMO : TwbSignature = 'RDMO'; + RDMP : TwbSignature = 'RDMP'; + RDOT : TwbSignature = 'RDOT'; + RDSA : TwbSignature = 'RDSA'; { New to Skyrim } + RDWT : TwbSignature = 'RDWT'; + REFR : TwbSignature = 'REFR'; + REGN : TwbSignature = 'REGN'; + RELA : TwbSignature = 'RELA'; + REPL : TwbSignature = 'REPL'; + RGDL : TwbSignature = 'RGDL';{ Unused in Skyrim, but contained in Skyrim.esm } + REVB : TwbSignature = 'REVB'; + RFCT : TwbSignature = 'RFCT'; + RNAM : TwbSignature = 'RNAM'; + RNMV : TwbSignature = 'RNMV'; { New to Skyrim } + RPLD : TwbSignature = 'RPLD'; + RPLI : TwbSignature = 'RPLI'; + RPRF : TwbSignature = 'RPRF'; { New To Skyrim } + RPRM : TwbSignature = 'RPRM'; { New To Skyrim } + SCDA : TwbSignature = 'SCDA'; + SCEN : TwbSignature = 'SCEN'; + SCHR : TwbSignature = 'SCHR'; + SCOL : TwbSignature = 'SCOL'; { Unused in Skyrim, but contained in Skyrim.esm } + SCPT : TwbSignature = 'SCPT'; { Unused in Skyrim, but contained in Skyrim.esm } + SCRL : TwbSignature = 'SCRL'; + SCRN : TwbSignature = 'SCRN'; + SCRO : TwbSignature = 'SCRO'; + SCTX : TwbSignature = 'SCTX'; + SDSC : TwbSignature = 'SDSC'; { New to Skyrim } + SHOU : TwbSignature = 'SHOU'; + SHRT : TwbSignature = 'SHRT'; { New to Skyrim } + SLCP : TwbSignature = 'SLCP'; + SLGM : TwbSignature = 'SLGM'; + SMBN : TwbSignature = 'SMBN'; + SMEN : TwbSignature = 'SMEN'; + SMQN : TwbSignature = 'SMQN'; + SNAM : TwbSignature = 'SNAM'; + SNCT : TwbSignature = 'SNCT'; + SNDD : TwbSignature = 'SNDD'; + SNDR : TwbSignature = 'SNDR'; + SNMV : TwbSignature = 'SNMV'; { New to Skyrim } + SOFT : TwbSignature = 'SOFT'; { New to Skyrim } + SOPM : TwbSignature = 'SOPM'; + SOUL : TwbSignature = 'SOUL'; + SOUN : TwbSignature = 'SOUN'; + SPCT : TwbSignature = 'SPCT'; { New to Skyrim } + SPED : TwbSignature = 'SPED'; { New To Skyrim } + SPEL : TwbSignature = 'SPEL'; + SPGD : TwbSignature = 'SPGD'; + SPIT : TwbSignature = 'SPIT'; + SPLO : TwbSignature = 'SPLO'; + SPMV : TwbSignature = 'SPMV'; { New To Skyrim } + SPOR : TwbSignature = 'SPOR'; { New to Skyrim } + STAT : TwbSignature = 'STAT'; + STOL : TwbSignature = 'STOL'; { New to Skyrim } + SWMV : TwbSignature = 'SWMV'; { New to Skyrim } + TACT : TwbSignature = 'TACT'; + TCLT : TwbSignature = 'TCLT'; + TES4 : TwbSignature = 'TES4'; + TIAS : TwbSignature = 'TIAS'; { New to Skyrim } + TIFC : TwbSignature = 'TIFC'; { New To Skyrim } + TINC : TwbSignature = 'TINC'; { New to Skyrim } + TIND : TwbSignature = 'TIND'; { New to Skyrim } + TINI : TwbSignature = 'TINI'; { New to Skyrim } + TINL : TwbSignature = 'TINL'; { New to Skyrim } + TINP : TwbSignature = 'TINP'; { New to Skyrim } + TINT : TwbSignature = 'TINT'; { New to Skyrim } + TINV : TwbSignature = 'TINV'; { New to Skyrim } + TIRS : TwbSignature = 'TIRS'; { New to Skyrim } + TNAM : TwbSignature = 'TNAM'; + TPIC : TwbSignature = 'TPIC'; + TPLT : TwbSignature = 'TPLT'; + TRDT : TwbSignature = 'TRDT'; + TREE : TwbSignature = 'TREE'; + TVDT : TwbSignature = 'TVDT'; { New To Skyrim } + TWAT : TwbSignature = 'TWAT'; { New To Skyrim } + TX00 : TwbSignature = 'TX00'; + TX01 : TwbSignature = 'TX01'; + TX02 : TwbSignature = 'TX02'; + TX03 : TwbSignature = 'TX03'; + TX04 : TwbSignature = 'TX04'; + TX05 : TwbSignature = 'TX05'; + TX06 : TwbSignature = 'TX06'; { New To Skyrim } + TX07 : TwbSignature = 'TX07'; { New To Skyrim } + TXST : TwbSignature = 'TXST'; + UNAM : TwbSignature = 'UNAM'; + UNES : TwbSignature = 'UNES'; { New To Skyrim } + VATS : TwbSignature = 'VATS'; + VCLR : TwbSignature = 'VCLR'; + VENC : TwbSignature = 'VENC'; { New To Skyrim } + VEND : TwbSignature = 'VEND'; { New To Skyrim } + VENV : TwbSignature = 'VENV'; { New To Skyrim } + VHGT : TwbSignature = 'VHGT'; + VMAD : TwbSignature = 'VMAD'; + VNAM : TwbSignature = 'VNAM'; + VNML : TwbSignature = 'VNML'; + VOLI : TwbSignature = 'VOLI'; { New To SSE } + VTCK : TwbSignature = 'VTCK'; + VTEX : TwbSignature = 'VTEX'; + VTXT : TwbSignature = 'VTXT'; + VTYP : TwbSignature = 'VTYP'; + WAIT : TwbSignature = 'WAIT'; { New To Skyrim } + WATR : TwbSignature = 'WATR'; + WBDT : TwbSignature = 'WBDT'; { New to Skyrim } + WCTR : TwbSignature = 'WCTR'; { New To Skyrim } + WEAP : TwbSignature = 'WEAP'; + WKMV : TwbSignature = 'WKMV'; { New to Skyrim } + WLST : TwbSignature = 'WLST'; + WNAM : TwbSignature = 'WNAM'; + WOOP : TwbSignature = 'WOOP'; + WRLD : TwbSignature = 'WRLD'; + WTHR : TwbSignature = 'WTHR'; + XACT : TwbSignature = 'XACT'; + XALP : TwbSignature = 'XALP'; { New To Skyrim } + XAPD : TwbSignature = 'XAPD'; + XAPR : TwbSignature = 'XAPR'; + XATR : TwbSignature = 'XATR'; { New To Dawnguard } + XCAS : TwbSignature = 'XCAS'; + XCCM : TwbSignature = 'XCCM'; + XCHG : TwbSignature = 'XCHG'; + XCIM : TwbSignature = 'XCIM'; + XCLC : TwbSignature = 'XCLC'; + XCLL : TwbSignature = 'XCLL'; + XCLP : TwbSignature = 'XCLP'; + XCLR : TwbSignature = 'XCLR'; + XCLW : TwbSignature = 'XCLW'; + XCMO : TwbSignature = 'XCMO'; + XCNT : TwbSignature = 'XCNT'; + XCVL : TwbSignature = 'XCVL'; { New To Skyrim } + XCWT : TwbSignature = 'XCWT'; + XCZA : TwbSignature = 'XCZA'; { New To Skyrim } + XCZC : TwbSignature = 'XCZC'; { New To Skyrim } + XCZR : TwbSignature = 'XCZR'; { New To Skyrim } + XDCR : TwbSignature = 'XDCR'; + XEMI : TwbSignature = 'XEMI'; + XESP : TwbSignature = 'XESP'; + XEZN : TwbSignature = 'XEZN'; + XFVC : TwbSignature = 'XFVC'; { New To Skyrim } + XGLB : TwbSignature = 'XGLB'; + XHLP : TwbSignature = 'XHLP'; + XHOR : TwbSignature = 'XHOR'; { New To Skyrim } + XHTW : TwbSignature = 'XHTW'; { New To Skyrim } + XIBS : TwbSignature = 'XIBS'; + XILL : TwbSignature = 'XILL'; { New To Skyrim } + XIS2 : TwbSignature = 'XIS2'; { New To Skyrim } + XLCM : TwbSignature = 'XLCM'; + XLCN : TwbSignature = 'XLCN'; { New To Skyrim } + XLIB : TwbSignature = 'XLIB'; { New To Skyrim } + XLIG : TwbSignature = 'XLIG'; { New To Skyrim } + XLKR : TwbSignature = 'XLKR'; + XLOC : TwbSignature = 'XLOC'; + XLOD : TwbSignature = 'XLOD'; + XLRL : TwbSignature = 'XLRL'; { New To Skyrim } + XLRM : TwbSignature = 'XLRM'; + XLRT : TwbSignature = 'XLRT'; { New To Skyrim } + XLTW : TwbSignature = 'XLTW'; + XMBO : TwbSignature = 'XMBO'; + XMBP : TwbSignature = 'XMBP'; + XMBR : TwbSignature = 'XMBR'; + XMRC : TwbSignature = 'XMRC'; + XMRK : TwbSignature = 'XMRK'; + XNAM : TwbSignature = 'XNAM'; + XNDP : TwbSignature = 'XNDP'; + XOCP : TwbSignature = 'XOCP'; + XORD : TwbSignature = 'XORD'; + XOWN : TwbSignature = 'XOWN'; + XPOD : TwbSignature = 'XPOD'; + XPPA : TwbSignature = 'XPPA'; + XPRD : TwbSignature = 'XPRD'; + XPRM : TwbSignature = 'XPRM'; + XPTL : TwbSignature = 'XPTL'; + XPWR : TwbSignature = 'XPWR'; + XRDS : TwbSignature = 'XRDS'; + XRGB : TwbSignature = 'XRGB'; + XRGD : TwbSignature = 'XRGD'; + XRMR : TwbSignature = 'XRMR'; + XRNK : TwbSignature = 'XRNK'; + XSCL : TwbSignature = 'XSCL'; + XSPC : TwbSignature = 'XSPC'; { New To Skyrim } + XTEL : TwbSignature = 'XTEL'; + XTNM : TwbSignature = 'XTNM'; { New To Skyrim } + XTRI : TwbSignature = 'XTRI'; + XWEM : TwbSignature = 'XWEM'; { New To Skyrim } + XWCN : TwbSignature = 'XWCN'; { New To Skyrim } + XWCS : TwbSignature = 'XWCS'; { New To Skyrim } + XWCU : TwbSignature = 'XWCU'; { New To Skyrim } + XXXX : TwbSignature = 'XXXX'; + YNAM : TwbSignature = 'YNAM'; + ZNAM : TwbSignature = 'ZNAM'; + +var + wbPKDTSpecificFlagsUnused : Boolean; + wbEDID: IwbSubRecordDef; + wbCOED: IwbSubRecordDef; + wbXLCM: IwbSubRecordDef; + wbEITM: IwbSubRecordDef; + wbDEST: IwbSubRecordStructDef; + wbDESTActor: IwbSubRecordStructDef; + wbDODT: IwbSubRecordDef; + wbXRGD: IwbSubRecordDef; + wbXRGB: IwbSubRecordDef; + wbSPLO: IwbSubRecordDef; + wbSPLOs: IwbSubRecordArrayDef; + wbCNTO: IwbRecordMemberDef; + wbCNTOs: IwbSubRecordArrayDef; + wbCNTONoReach: IwbRecordMemberDef; + wbCNTOsNoReach: IwbSubRecordArrayDef; + wbAIDT: IwbSubRecordDef; + wbCSDT: IwbSubRecordStructDef; + wbCSDTs: IwbSubRecordArrayDef; + wbFULL: IwbSubRecordDef; + wbFULLActor: IwbSubRecordDef; + wbFULLReq: IwbSubRecordDef; + wbDESC: IwbSubRecordDef; + wbDESCReq: IwbSubRecordDef; + wbXSCL: IwbSubRecordDef; + wbMODD: IwbSubRecordDef; + wbMODS: IwbSubRecordDef; + wbMO2S: IwbSubRecordDef; + wbMO3S: IwbSubRecordDef; + wbMO4S: IwbSubRecordDef; + wbMaleWorldModel: IwbRecordMemberDef; + wbARMOFemaleWorldModel: IwbRecordMemberDef; + wbARMAFemaleWorldModel: IwbRecordMemberDef; + wbARMAMale1stPersonModel: IwbRecordMemberDef; + wbARMAFemale1stPersonModel: IwbRecordMemberDef; + wbCTDA: IwbRecordMemberDef; + wbCTDAs: IwbSubRecordArrayDef; + wbCTDAsReq: IwbSubRecordArrayDef; + wbCTDAsCount: IwbSubRecordArrayDef; + wbXESP: IwbSubRecordDef; + wbICON: IwbSubRecordStructDef; + wbICONReq: IwbSubRecordStructDef; + wbICO2: IwbSubRecordStructDef; + wbActorValue: IwbIntegerDef; + wbETYP: IwbSubRecordDef; + wbETYPReq: IwbSubRecordDef; + wbEFID: IwbSubRecordDef; + wbEFIT: IwbSubRecordDef; + wbEffectsReq: IwbSubRecordArrayDef; + wbFirstPersonFlagsU32: IwbIntegerDef; + wbBODT: IwbSubRecordDef; + wbBOD2: IwbSubRecordDef; + wbBODTBOD2: IwbRecordMemberDef; + wbScriptEntry: IwbValueDef; + wbScriptFlags: IwbIntegerDef; + wbScriptPropertyObject: IwbUnionDef; + wbScriptProperty: IwbValueDef; + wbScriptProperties: IwbArrayDef; + wbScriptFragments: IwbValueDef; + wbScriptFragmentsQuest: IwbValueDef; + wbScriptFragmentsInfo: IwbValueDef; + wbScriptFragmentsPack: IwbValueDef; + wbScriptFragmentsScen: IwbValueDef; + wbPLDT: IwbSubRecordDef; + wbPLVD: IwbSubRecordDef; + wbTargetData: IwbStructDef; + wbAttackData: IwbSubRecordStructDef; + wbLLCT: IwbSubRecordDef; + wbLVLD: IwbSubRecordDef; + wbVMAD: IwbSubRecordDef; + wbVMADFragmentedPERK: IwbSubRecordDef; + wbVMADFragmentedPACK: IwbSubRecordDef; + wbVMADFragmentedQUST: IwbSubRecordDef; + wbVMADFragmentedSCEN: IwbSubRecordDef; + wbVMADFragmentedINFO: IwbSubRecordDef; + wbCOCT: IwbSubRecordDef; + wbKSIZ: IwbSubRecordDef; + wbKWDAs: IwbSubRecordDef; + wbReqKWDAs: IwbSubRecordDef; + wbKeywords: IwbSubRecordStructDef; + wbCITC: IwbSubRecordDef; + wbCITCReq: IwbSubRecordDef; + wbMGEFData: IwbSubRecordStructDef; + wbMGEFType: IwbIntegerDef; + wbSPIT: IwbSubRecordDef; + wbDMDSs: IwbSubRecordDef; + wbMO5S: IwbSubRecordDef; + wbSPCT: IwbSubRecordDef; + wbTints: IwbSubRecordArrayDef; + wbRACE_DATAFlags01: IwbIntegerDef; + wbPhonemeTargets: IwbSubRecordDef; + wbNoseMorphFlags: IwbIntegerDef; + wbBrowMorphFlags: IwbIntegerDef; + wbEyesMorphFlags01: IwbIntegerDef; + wbEyesMorphFlags02: IwbIntegerDef; + wbLipMorphFlags: IwbIntegerDef; + wbPHWT: IwbSubRecordStructDef; + wbMorphs: IwbSubRecordStructDef; + wbQUSTAliasFlags: IwbSubRecordDef; + wbPDTO: IwbSubRecordDef; + wbPDTOs: IwbSubRecordArrayDef; + wbUNAMs: IwbSubRecordArrayDef; + wbNull: IwbValueDef; + wbYNAM: IwbSubRecordDef; + wbZNAM: IwbSubRecordDef; + wbMaxHeightDataCELL: IwbSubRecordDef; + wbMaxHeightDataWRLD: IwbSubRecordDef; + wbTVDT: IwbSubRecordDef; + wbNVNM: IwbSubRecordDef; + wbNAVIslandData: IwbStructDef; + wbXOWN: IwbSubRecordDef; + + +function wbGenericModel(aRequired: Boolean = False; aDontShow: TwbDontShowCallback = nil): IwbRecordMemberDef; +begin + Result := + wbRStructSK([0], 'Model', [ + wbString(MODL, 'Model FileName', 0, cpNormal, True), + wbMODT, + wbMODS + ], [], cpNormal, aRequired, aDontShow, True) + .SetSummaryKey([0]) + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfSummaryNoSortKey) + .IncludeFlag(dfCollapsed, wbCollapseModels); +end; + +function wbTexturedModel(aSubRecordName: string; aSignatures: TwbSignatures; aTextureSubRecord: IwbSubRecordDef): IwbRecordMemberDef; +begin + Result := + wbRStruct(aSubRecordName, [ + wbString(aSignatures[0], 'Model FileName'), + wbModelInfo(aSignatures[1]), + aTextureSubRecord + ], []) + .SetSummaryKey([0, 2]) + .SetSummaryMemberPrefixSuffix(2, '', '') + .SetSummaryDelimiter(' ') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfSummaryNoSortKey) + .IncludeFlag(dfCollapsed, wbCollapseModels); +end; + +function IsSSE: Boolean; inline; overload; +begin + Result := wbGameMode in [gmSSE, gmTES5VR, gmEnderalSE]; +end; + +function IsSSE(const aDef1, aDef2: String): String; inline; overload; +begin + if IsSSE then + Result := aDef1 + else + Result := aDef2; +end; + +function IsSSE(const aDef1, aDef2: IwbSubRecordDef): IwbSubRecordDef; inline; overload; +begin + if IsSSE then + Result := aDef1 + else + Result := aDef2; +end; + +function wbEPFDActorValueToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + AsCardinal : Cardinal; + AsFloat : Single; +begin + AsCardinal := aInt; + AsFloat := PSingle(@AsCardinal)^; + aInt := Round(AsFloat); + case aType of + ctToStr, ctToSummary: Result := wbActorValueEnum.ToString(aInt, aElement, aType = ctToSummary); + ctToSortKey: Result := wbActorValueEnum.ToSortKey(aInt, aElement); + ctCheck: Result := wbActorValueEnum.Check(aInt, aElement); + ctToEditValue: Result := wbActorValueEnum.ToEditValue(aInt, aElement); + ctEditType: Result := 'ComboBox'; + ctEditInfo: Result := wbActorValueEnum.EditInfo[aInt, aElement].ToCommaText; + end; +end; + +function wbEPFDActorValueToInt(const aString: string; const aElement: IwbElement): Int64; +var + AsCardinal : Cardinal; + AsFloat : Single; +begin + AsFloat := wbActorValueEnum.FromEditValue(aString, aElement); + PSingle(@AsCardinal)^ := AsFloat; + Result := AsCardinal; +end; + +function wbGetQuestStageAsStr(aInt: Int64; aParam1: IwbElement; aType: TwbCallbackType; var aResult: string): Boolean; +var + MainRecord: IwbMainRecord; + EditInfos: TStringList; + Stage, Stages: IwbContainerElementRef; +begin + Result := False; + if not Assigned(aParam1) then + Exit; + + if not Supports(aParam1.LinksTo, IwbMainRecord, MainRecord) then + Exit; + + MainRecord := MainRecord.WinningOverride; + + if MainRecord.Signature <> QUST then + begin + case aType of + ctToStr, ctToSummary: + begin + aResult := aInt.ToString; + if aType = ctToStr then + aResult := aResult + ' '; + end; + ctCheck: + aResult := ''; + end; + Exit; + end; + + case aType of + ctEditType: + begin + aResult := 'ComboBox'; + Exit(True); + end; + + ctEditInfo: + EditInfos := TStringList.Create; + else + EditInfos := nil; + end; + + try + if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then + begin + for var i := 0 to Pred(Stages.ElementCount) do + begin + if not Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then + Continue; + + var j: Integer := Stage.ElementNativeValues['INDX\Stage Index']; + var s: string := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); + + var t: string := IntToStr(j); + while Length(t) < 3 do + t := '0' + t; + + if s <> '' then + t := t + ' ' + s; + + if Assigned(EditInfos) then + begin + EditInfos.AddObject(t, TObject(j)); + Continue; + end; + + if j = aInt then + begin + case aType of + ctToStr, ctToSummary, ctToEditValue: + aResult := t; + ctCheck: + aResult := ''; + end; + + Result := True; + Exit; + end; + end; + end; + + case aType of + ctToStr, ctToSummary: + begin + aResult := aInt.ToString; + if aType = ctToStr then + aResult := aResult + ' '; + end; + + ctCheck: + aResult := ''; + + ctEditInfo: + begin + EditInfos.Sort; + aResult := EditInfos.CommaText; + end; + end; + finally + FreeAndNil(EditInfos); + end; + + Result := True; +end; + +function wbCTDAParam2QuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Container : IwbContainerElementRef; + Param1 : IwbElement; +begin + case aType of + ctToStr, ctToSummary: begin + Result := aInt.ToString; + if aType = ctToStr then + Result := Result + ' '; + end; + + ctToEditValue: Result := aInt.ToString; + + ctToSortKey: begin + Result := IntToHex64(aInt, 8); + Exit; + end; + + ctCheck: Result := ''; + ctEditType: Result := ''; + ctEditInfo: Result := ''; + end; + + if not wbTryGetContainerRefFromUnionOrValue(aElement, Container) then + Exit; + + Param1 := Container.ElementByName['Parameter #1']; + + if not wbGetQuestStageAsStr(aInt, Param1, aType, Result) then + Exit; +end; + +function wbPerkDATAQuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Container : IwbContainerElementRef; + Param1 : IwbElement; +begin + case aType of + ctToStr, ctToSummary: begin + Result := aInt.ToString; + if aType = ctToStr then + Result := Result + ' '; + end; + + ctToEditValue: Result := aInt.ToString; + + ctToSortKey: begin + Result := IntToHex64(aInt, 8); + Exit; + end; + + ctCheck: Result := ''; + ctEditType: Result := ''; + ctEditInfo: Result := ''; + end; + + if not wbTryGetContainerRefFromUnionOrValue(aElement, Container) then + Exit; + + Param1 := Container.ElementByName['Quest']; + + if not wbGetQuestStageAsStr(aInt, Param1, aType, Result) then + Exit; +end; + +function wbREFRNavmeshTriangleToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Container : IwbContainerElementRef; + Navmesh : IwbElement; + MainRecord : IwbMainRecord; + Triangles : IwbContainerElementRef; +begin + case aType of + ctToStr, ctToSummary: Result := aInt.ToString; + ctToEditValue: Result := aInt.ToString; + ctToSortKey: begin + Result := IntToHex64(aInt, 8); + Exit; + end; + ctCheck: Result := ''; + ctEditType: Result := ''; + ctEditInfo: Result := ''; + end; + + if not wbTryGetContainerRefFromUnionOrValue(aElement, Container) then + Exit; + + Navmesh := Container.Elements[0]; + if not wbTryGetMainRecord(Navmesh, MainRecord) then + Exit; + + MainRecord := MainRecord.WinningOverride; + + if MainRecord.Signature <> NAVM then begin + case aType of + ctToStr, ctToSummary: begin + Result := aInt.ToString; + if aType = ctToStr then + Result := Result + ' '; + end; + ctCheck: Result := ''; + end; + Exit; + end; + + if Supports(MainRecord.ElementByPath['NVNM\Triangles'], IwbContainerElementRef, Triangles) and (aType = ctCheck) then + if aInt >= Triangles.ElementCount then + Result := ''; +end; + +function wbStringToInt(const aString: string; const aElement: IwbElement): Int64; +begin + Result := StrToIntDef(aString, 0); +end; + +function wbEdgeToStr(aEdge: Integer; aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Triangle : IwbContainerElementRef; + Flags : Int64; + MainRecord : IwbMainRecord; + EdgeLinks : IwbContainerElementRef; + EdgeLink : IwbContainerElementRef; + FormID : TwbFormID; +begin + case aType of + ctToStr, ctToSummary: begin + if aInt < 0 then + Exit('None'); + + Result := aInt.ToString; + + if not Assigned(aElement) then + Exit; + + Triangle := aElement.Container as IwbContainerElementRef; + if not Assigned(Triangle) then + Exit; + + MainRecord := aElement.ContainingMainRecord; + if not Assigned(MainRecord) then + Exit; + + Flags := Triangle.ElementNativeValues['Flags']; + if Flags and (1 shl aEdge) <> 0 then begin + if not Supports(MainRecord.ElementByPath['NVNM\Edge Links'], IwbContainerElementRef, EdgeLinks) then + Exit; + + if aInt >= EdgeLinks.ElementCount then + Exit; + + if aInt < 0 then + Exit; + + EdgeLink := EdgeLinks.Elements[aInt] as IwbContainerElementRef; + if not Assigned(EdgeLink) then + Exit; + + MainRecord := nil; + if not Supports(EdgeLink.ElementLinksTo['Mesh'], IwbMainRecord, MainRecord) then + Exit; + + aInt := EdgeLink.ElementNativeValues['Triangle']; + + Result := Result + ' (#' + aInt.ToString + ' in ' + MainRecord.Name + ')'; + end; + end; + ctToSortKey: begin + Result := '00000000' + IntToHex(aInt, 4); + if not Assigned(aElement) then + Exit; + + Triangle := aElement.Container as IwbContainerElementRef; + if not Assigned(Triangle) then + Exit; + + MainRecord := aElement.ContainingMainRecord; + if not Assigned(MainRecord) then + Exit; + + FormID := MainRecord.LoadOrderFormID; + + Flags := Triangle.ElementNativeValues['Flags']; + if Flags and (1 shl aEdge) <> 0 then begin + if not Supports(MainRecord.ElementByPath['NVNM\Edge Links'], IwbContainerElementRef, EdgeLinks) then + Exit; + + if aInt >= EdgeLinks.ElementCount then + Exit; + + EdgeLink := EdgeLinks.Elements[aInt] as IwbContainerElementRef; + + MainRecord := nil; + if not Supports(EdgeLink.ElementLinksTo['Mesh'], IwbMainRecord, MainRecord) then + Exit; + + if Assigned(MainRecord) then + FormID := MainRecord.LoadOrderFormID + else + FormID := TwbFormID.Null; + + aInt := EdgeLink.ElementNativeValues['Triangle']; + end; + + Result := FormID.ToString + IntToHex(aInt, 4); + end; + ctCheck: Result := ''; + ctToEditValue: if aInt < 0 then + Result := '' + else + Result := aInt.ToString; + ctEditType: Result := ''; + ctEditInfo: Result := ''; + end; +end; + +function wbEdgeLinksTo(aEdge: Integer; const aElement: IwbElement): IwbElement; +var + aInt : Int64; + Triangle : IwbContainerElementRef; + Triangles : IwbContainerElementRef; + Flags : Int64; + MainRecord : IwbMainRecord; + EdgeLinks : IwbContainerElementRef; + EdgeLink : IwbContainerElementRef; +begin + Result := nil; + if not Assigned(aElement) then + Exit; + + Triangle := aElement.Container as IwbContainerElementRef; + if not Assigned(Triangle) then + Exit; + + MainRecord := aElement.ContainingMainRecord; + if not Assigned(MainRecord) then + Exit; + + aInt := aElement.NativeValue; + + Flags := Triangle.ElementNativeValues['Flags']; + if Flags and (1 shl aEdge) <> 0 then begin + if not Supports(MainRecord.ElementByPath['NVNM\Edge Links'], IwbContainerElementRef, EdgeLinks) then + Exit; + + if aInt >= EdgeLinks.ElementCount then + Exit; + + if aInt < 0 then + Exit; + + EdgeLink := EdgeLinks.Elements[aInt] as IwbContainerElementRef; + + MainRecord := nil; + if not Supports(EdgeLink.ElementLinksTo['Mesh'], IwbMainRecord, MainRecord) then + Exit; + + aInt := EdgeLink.ElementNativeValues['Triangle']; + end; + + if not Supports(MainRecord.ElementByPath['NVNM\Triangles'], IwbContainerElementRef, Triangles) then + Exit; + + if aInt >= Triangles.ElementCount then + Exit; + + if aInt < 0 then + Exit; + + Triangle := Triangles.Elements[aInt] as IwbContainerElementRef; + + Result := Triangle; +end; + +function wbEdgeLinksTo0(const aElement: IwbElement): IwbElement; +begin + Result := wbEdgeLinksTo(0, aElement); +end; + +function wbEdgeLinksTo1(const aElement: IwbElement): IwbElement; +begin + Result := wbEdgeLinksTo(1, aElement); +end; + +function wbEdgeLinksTo2(const aElement: IwbElement): IwbElement; +begin + Result := wbEdgeLinksTo(2, aElement); +end; + +function wbTriangleLinksTo(const aElement: IwbElement): IwbElement; +var + aInt : Int64; + Triangle : IwbContainerElementRef; + Triangles : IwbContainerElementRef; + MainRecord : IwbMainRecord; +begin + Result := nil; + if not Assigned(aElement) then + Exit; + + Triangle := aElement.Container as IwbContainerElementRef; + if not Assigned(Triangle) then + Exit; + + MainRecord := aElement.ContainingMainRecord; + if not Assigned(MainRecord) then + Exit; + + aInt := aElement.NativeValue; + + if not Supports(MainRecord.ElementByPath['NVNM\Triangles'], IwbContainerElementRef, Triangles) then + Exit; + + if aInt >= Triangles.ElementCount then + Exit; + + if aInt < 0 then + Exit; + + Triangle := Triangles.Elements[aInt] as IwbContainerElementRef; + + Result := Triangle; +end; + +function wbVertexToStr(aVertex: Integer; aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Triangle : IwbContainerElementRef; + MainRecord : IwbMainRecord; + Vertices : IwbContainerElementRef; + Vertex : IwbContainerElementRef; +begin + case aType of + ctToStr, ctToSummary: begin + Result := aInt.ToString; + if not Assigned(aElement) then + Exit; + + Triangle := aElement.Container as IwbContainerElementRef; + if not Assigned(Triangle) then + Exit; + + MainRecord := aElement.ContainingMainRecord; + if not Assigned(MainRecord) then + Exit; + + if not Supports(MainRecord.ElementByPath['NVNM\Vertices'], IwbContainerElementRef, Vertices) then + Exit; + + if aInt >= Vertices.ElementCount then + Exit; + + if aInt < 0 then + Exit; + + Vertex := Vertices.Elements[aInt] as IwbContainerElementRef; + + with Vertex do try + Result := Result + Format(' (%s, %s, %s)', [ElementEditValues['X'], ElementEditValues['Y'], ElementEditValues['Z']]); + except + // TODO: yikes, suppressing exceptions? + end; + end; + ctToSortKey: begin + Result := IntToHex(aInt, 4); + if not Assigned(aElement) then + Exit; + + Triangle := aElement.Container as IwbContainerElementRef; + if not Assigned(Triangle) then + Exit; + + MainRecord := aElement.ContainingMainRecord; + if not Assigned(MainRecord) then + Exit; + + if not Supports(MainRecord.ElementByPath['NVNM\Vertices'], IwbContainerElementRef, Vertices) then + Exit; + + if aInt >= Vertices.ElementCount then + Exit; + + if aInt < 0 then + Exit; + + Vertex := Vertices.Elements[aInt] as IwbContainerElementRef; + + with Vertex do try + Result := SortKey[False]; + except + // TODO: yikes, suppressing exceptions? + end; + end; + ctCheck: Result := ''; + ctToEditValue: Result := aInt.ToString; + ctEditType: Result := ''; + ctEditInfo: Result := ''; + end; +end; + + +function wbVertexLinksTo(const aElement: IwbElement): IwbElement; +var + aInt : Int64; + Triangle : IwbContainerElementRef; + MainRecord : IwbMainRecord; + Vertices : IwbContainerElementRef; + Vertex : IwbContainerElementRef; +begin + Result := nil; + if not Assigned(aElement) then + Exit; + + Triangle := aElement.Container as IwbContainerElementRef; + if not Assigned(Triangle) then + Exit; + + MainRecord := aElement.ContainingMainRecord; + if not Assigned(MainRecord) then + Exit; + + if not Supports(MainRecord.ElementByPath['NVNM\Vertices'], IwbContainerElementRef, Vertices) then + Exit; + + aInt := aElement.NativeValue; + + if aInt >= Vertices.ElementCount then + Exit; + if aInt < 0 then + Exit; + + Vertex := Vertices.Elements[aInt] as IwbContainerElementRef; + + Result := Vertex; +end; + +function wbVertexToInt(aVertex: Integer; const aString: string; const aElement: IwbElement): Int64; +begin + Result := StrToIntDef(aString, 0); +end; + +function wbVertexToStr0(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +begin + Result := wbVertexToStr(0, aInt, aElement, aType); +end; + +function wbVertexToInt0(const aString: string; const aElement: IwbElement): Int64; +begin + Result := wbVertexToInt(0, aString, aElement); +end; + +function wbVertexToStr1(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +begin + Result := wbVertexToStr(1, aInt, aElement, aType); +end; + +function wbVertexToInt1(const aString: string; const aElement: IwbElement): Int64; +begin + Result := wbVertexToInt(1, aString, aElement); +end; + +function wbVertexToStr2(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +begin + Result := wbVertexToStr(2, aInt, aElement, aType); +end; + +function wbVertexToInt2(const aString: string; const aElement: IwbElement): Int64; +begin + Result := wbVertexToInt(2, aString, aElement); +end; + + +function wbEdgeToInt(aEdge: Integer; const aString: string; const aElement: IwbElement): Int64; +var + s: string; +begin + s := Trim(aString); + if (s = '') or SameText(s, 'None') then + Result := -1 + else + Result := StrToIntDef(aString, 0); +end; + +function wbEdgeToStr0(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +begin + Result := wbEdgeToStr(0, aInt, aElement, aType); +end; + +function wbEdgeToInt0(const aString: string; const aElement: IwbElement): Int64; +begin + Result := wbEdgeToInt(0, aString, aElement); +end; + +function wbEdgeToStr1(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +begin + Result := wbEdgeToStr(1, aInt, aElement, aType); +end; + +function wbEdgeToInt1(const aString: string; const aElement: IwbElement): Int64; +begin + Result := wbEdgeToInt(1, aString, aElement); +end; + +function wbEdgeToStr2(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +begin + Result := wbEdgeToStr(2, aInt, aElement, aType); +end; + +function wbEdgeToInt2(const aString: string; const aElement: IwbElement): Int64; +begin + Result := wbEdgeToInt(2, aString, aElement); +end; + + + +{ Alias to string conversion, requires quest reference or quest record specific to record that references alias } +function wbAliasToStr(aInt: Int64; const aQuestRef: IwbElement; aType: TwbCallbackType): string; +var + MainRecord : IwbMainRecord; + EditInfos : TStringList; + Aliases : IwbContainerElementRef; + Alias : IwbContainerElementRef; + i, j : Integer; + s, t : string; +begin + case aType of + ctToStr, ctToSummary: + if aInt = -1 then begin + if aType = ctToStr then + Result := 'None' + else + Result := ''; + end else begin + Result := aInt.ToString; + if aType = ctToStr then + Result := Result + ' '; + end; + ctToEditValue: if aInt = -1 then Result := 'None' else + Result := aInt.ToString; + ctToSortKey: begin + Result := IntToHex64(aInt, 8); + Exit; + end; + ctCheck: if aInt = -1 then Result := '' else + Result := ''; + ctEditType: Result := ''; + ctEditInfo: Result := ''; + end; + + if (aInt = -1) and (aType <> ctEditType) and (aType <> ctEditInfo) then + Exit; + + if not Assigned(aQuestRef) then + Exit; + + // aQuestRef can be a QUST record or reference to QUST record + if not Supports(aQuestRef, IwbMainRecord, MainRecord) then + if not Supports(aQuestRef.LinksTo, IwbMainRecord, MainRecord) then + Exit; + + MainRecord := MainRecord.WinningOverride; + + if MainRecord.Signature <> QUST then begin + case aType of + ctToStr, ctToSummary: begin + Result := aInt.ToString; + if aType = ctToStr then + Result := Result + ' '; + end; + ctCheck: Result := ''; + end; + Exit; + end; + + case aType of + ctEditType: begin + Result := 'ComboBox'; + Exit; + end; + ctEditInfo: + EditInfos := TStringList.Create; + else + EditInfos := nil; + end; + + try + if Supports(MainRecord.ElementByName['Aliases'], IwbContainerElementRef, Aliases) then begin + for i := 0 to Pred(Aliases.ElementCount) do + if Supports(Aliases.Elements[i], IwbContainerElementRef, Alias) then begin + j := Alias.Elements[0].NativeValue; + s := Alias.ElementEditValues['ALID']; + if (aType <> ctToSummary) or not wbNoIndexInAliasSummary then begin + t := IntToStr(j); + while Length(t) < 3 do + t := '0' + t; + if s <> '' then + t := t + ' ' + s; + end else + t := s; + if Assigned(EditInfos) then + EditInfos.Add(t) + else if j = aInt then begin + case aType of + ctToStr, ctToSummary, ctToEditValue: Result := t; + ctCheck: Result := ''; + end; + Exit; + end; + end; + end; + + case aType of + ctToStr, ctToSummary: begin + Result := aInt.ToString; + if aType = ctToStr then + Result := Result + ' '; + end; + ctCheck: Result := ''; + ctEditInfo: begin + EditInfos.Add('None'); + EditInfos.Sort; + Result := EditInfos.CommaText; + end; + end; + finally + FreeAndNil(EditInfos); + end; +end; + +function wbStrToAlias(const aString: string; const aElement: IwbElement): Int64; +var + i : Integer; + s : string; +begin + Result := -1; + + if aString = 'None' then + Exit; + + i := 1; + s := Trim(aString); + while (i <= Length(s)) and (s[i] in ['-', '0'..'9']) do + Inc(i); + s := Copy(s, 1, Pred(i)); + + Result := StrToIntDef(s, -1); +end; + +function wbScriptObjectAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Container : IwbContainerElementRef; +begin + if not wbResolveAlias then begin + case aType of + ctToStr, ctToSummary, ctToEditValue: Result := aInt.ToString; + ctToSortKey: Result := IntToHex64(aInt, 8); + else + Result := ''; + end; + Exit; + end; + + if not wbTryGetContainerRefFromUnionOrValue(aElement, Container) then + Exit; + + Result := wbAliasToStr(aInt, Container.ElementByName['FormID'], aType); +end; + +function wbPackageLocationAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Container : IwbContainer; +begin + if not wbResolveAlias then begin + case aType of + ctToStr, ctToSummary, ctToEditValue: Result := aInt.ToString; + ctToSortKey: Result := IntToHex64(aInt, 8); + else + Result := ''; + end; + Exit; + end; + + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + while Assigned(Container) and (Container.ElementType <> etMainRecord) do + Container := Container.Container; + + if not Assigned(Container) then + Exit; + + Result := wbAliasToStr(aInt, Container.ElementBySignature['QNAM'], aType); +end; + +function wbQuestAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Container : IwbContainer; +begin + if not wbResolveAlias then begin + case aType of + ctToStr, ctToSummary, ctToEditValue: Result := aInt.ToString; + ctToSortKey: Result := IntToHex64(aInt, 8); + else + Result := ''; + end; + Exit; + end; + + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + while Assigned(Container) and (Container.ElementType <> etMainRecord) do + Container := Container.Container; + + if not Assigned(Container) then + Exit; + + Result := wbAliasToStr(aInt, Container, aType); +end; + +function wbQuestExternalAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Container : IwbContainer; +begin + if not wbResolveAlias then begin + case aType of + ctToStr, ctToSummary, ctToEditValue: Result := aInt.ToString; + ctToSortKey: Result := IntToHex64(aInt, 8); + else + Result := ''; + end; + Exit; + end; + + if not Assigned(aElement) then + Exit; + + Container := aElement.Container; + if not Assigned(Container) then + Exit; + + Result := wbAliasToStr(aInt, Container.ElementBySignature['ALEQ'] , aType); +end; + +function wbConditionAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Container : IwbContainer; + MainRecord : IwbMainRecord; + GroupRecord : IwbGroupRecord; +begin + if not wbResolveAlias then begin + case aType of + ctToStr, ctToSummary, ctToEditValue: Result := aInt.ToString; + ctToSortKey: Result := IntToHex64(aInt, 8); + else + Result := ''; + end; + Exit; + end; + + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + while Assigned(Container) and (Container.ElementType <> etMainRecord) do + Container := Container.Container; + + if not Assigned(Container) then + Exit; + + if not Supports(Container, IwbMainRecord, MainRecord) then + Exit; + + if MainRecord.Signature = QUST then + Result := wbAliasToStr(aInt, Container, aType) + else if MainRecord.Signature = SCEN then + Result := wbAliasToStr(aInt, Container.ElementBySignature['PNAM'], aType) + else if MainRecord.Signature = PACK then + Result := wbAliasToStr(aInt, Container.ElementBySignature['QNAM'], aType) + else if MainRecord.Signature = INFO then begin + // get DIAL for INFO + if Supports(MainRecord.Container, IwbGroupRecord, GroupRecord) then + if Supports(GroupRecord.ChildrenOf, IwbMainRecord, MainRecord) then + Result := wbAliasToStr(aInt, MainRecord.ElementBySignature['QNAM'], aType); + end else + // this should never be called since aliases in conditions can be in the forms above only + // but just in case + case aType of + ctToStr, ctToSummary, ctToEditValue: Result := aInt.ToString; + ctToSortKey: Result := IntToHex64(aInt, 8); + else + Result := ''; + end; +end; + +function wbClmtMoonsPhaseLength(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + PhaseLength : Byte; + Masser : Boolean; + Secunda : Boolean; +begin + Result := ''; + if aType = ctToSortKey then begin + Result := IntToHex64(aInt, 2); + Exit; + end; + + if aType in [ctToStr, ctToSummary] then begin + PhaseLength := aInt mod 64; + Masser := (aInt and 64) <> 0; + Secunda := (aInt and 128) <> 0; + if Masser then + if Secunda then + Result := 'Masser, Secunda / ' + else + Result := 'Masser / ' + else + if Secunda then + Result := 'Secunda / ' + else + Result := 'No Moon / '; + Result := Result + IntToStr(PhaseLength); + end; +end; + +function wbClmtTime(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +begin + if aType = ctToSortKey then + Result := IntToHex64(aInt, 4) + else if aType in [ctToStr, ctToSummary] then + try + Result := TimeToStr( EncodeTime(aInt div 6, (aInt mod 6) * 10, 0, 0) ) + except + Result := aInt.ToString + end + else + Result := ''; +end; + + +var + wbCtdaTypeFlags : IwbFlagsDef; + +function wbCtdaTypeToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + s: string; +begin + Result := ''; + + if not Assigned(wbCtdaTypeFlags) then + wbCtdaTypeFlags := wbFlags([ + {0x01} 'Or', + {0x02} 'Use aliases', + {0x04} 'Use global', + {0x08} 'Use packdata', + {0x10} 'Swap Subject and Target' + ]); +{ + Compare operator (upper 3 bits) + LGE + 000 0=Equal to + 001 1=Not equal to + 010 2=Greater than + 011 3=Greater than or equal to + 100 4=Less than + 101 5=Less than or equal to + + Flags (lower 5 bits) + 0x01=OR (default is to AND conditions together) + 0x02=Parameters (use aliases) : Force function parameters to use quest alias data (exclusive with "use pack data") + 0x04=Use global + 0x08=Use Pack Data : Force function parameters to use pack data (exclusive with "use aliases") + 0x10=Swap Subject and Target +} + case aType of + ctEditType: + Result := 'CheckComboBox'; + ctEditInfo: + Result := 'Equal,Greater,Lesser,Or,"Use Aliases","Use Global","Use Packdata","Swap Subject and Target"'; + ctToEditValue: begin + Result := '00000000'; + case aInt and $E0 of + $00 : Result[1] := '1'; + $40 : Result[2] := '1'; + $60 : begin + Result[1] := '1'; + Result[2] := '1'; + end; + $80 : Result[3] := '1'; + $A0 : begin + Result[1] := '1'; + Result[3] := '1'; + end; + end; + if (aInt and $01) <> 0 then // Or + Result[4] := '1'; + if (aInt and $02) <> 0 then // Use aliases + Result[5] := '1'; + if (aInt and $04) <> 0 then // Use global + Result[6] := '1'; + if (aInt and $08) <> 0 then // Use packdata + Result[7] := '1'; + if (aInt and $10) <> 0 then // Swap Subject and Target + Result[8] := '1'; + end; + ctToStr, ctToSummary: begin + case aInt and $E0 of + $00 : Result := 'Equal to'; + $20 : Result := 'Not equal to'; + $40 : Result := 'Greater than'; + $60 : Result := 'Greater than or equal to'; + $80 : Result := 'Less than'; + $A0 : Result := 'Less than or equal to'; + else + Result := '' + end; + s := wbCtdaTypeFlags.ToString(aInt and $1F, aElement, aType = ctToSummary); + if s <> '' then + Result := Result + ' / ' + s; + end; + ctToSortKey: begin + Result := IntToHex64(aInt, 2); + Exit; + end; + ctCheck: begin + case aInt and $E0 of + $00, $20, $40, $60, $80, $A0 : Result := ''; + else + Result := '' + end; + s := wbCtdaTypeFlags.Check(aInt and $1F, aElement); + if s <> '' then + Result := Result + ' / ' + s; + end; + end; +end; + +function wbCtdaTypeToInt(const aString: string; const aElement: IwbElement): Int64; +var + s: string; +begin + s := aString + '00000000'; + if s[1] = '1' then begin + if s[2] = '1' then begin + if s[3] = '1' then begin + Result := $00; + end else begin + Result := $60; + end; + end else begin + if s[3] = '1' then begin + Result := $A0; + end else begin + Result := $00; + end; + end; + end else begin + if s[2] = '1' then begin + if s[3] = '1' then begin + Result := $20; + end else begin + Result := $40; + end; + end else begin + if s[3] = '1' then begin + Result := $80; + end else begin + Result := $20; + end; + end; + end; + // Or + if s[4] = '1' then + Result := Result or $01; + // Use aliases + if s[5] = '1' then + Result := Result or $02; + // Use global + if s[6] = '1' then + Result := Result or $04; + // Use packdata + if s[7] = '1' then + Result := Result or $08; + // Swap Subject and Target + if s[8] = '1' then + Result := Result or $10; +end; + +var + wbEventFunctionAndMemberEditInfo: string; + +function wbEventFunctionAndMemberToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + EventFunction, EventMember: Integer; + i, j: Integer; + s1, s2: string; + slMember: TStringList; +begin + Result := ''; + EventFunction := aInt and $FFFF; + EventMember := aInt shr 16; + case aType of + ctToStr, ctToSummary, ctToEditValue: begin + Result := wbEventFunctionEnum.ToEditValue(EventFunction, nil); + Result := Result + ':' + wbEventMemberEnum.ToEditValue(EventMember, nil); + end; + ctToSortKey: Result := IntToHex(aInt, 8); + ctCheck: begin + s1 := wbEventFunctionEnum.Check(EventFunction, nil); + if s1 <> '' then + s1 := 'EventFunction' + s1; + s2 := wbEventMemberEnum.Check(EventMember, nil); + if s2 <> '' then + s2 := 'EventMember' + s2; + if (s1 <> '') or (s2 <> '') then + Result := s1 + ':' + s2; + end; + ctEditType: + Result := 'ComboBox'; + ctEditInfo: begin + Result := wbEventFunctionAndMemberEditInfo; + if Result = '' then try + slMember := TStringList.Create; + slMember.AddStrings(wbEventMemberEnum.EditInfo[0, nil]); + with TStringList.Create do try + for i := 0 to Pred(wbEventFunctionEnum.NameCount) do + for j := 0 to Pred(slMember.Count) do + Add(wbEventFunctionEnum.Names[i] + ':' + slMember[j]); + Sort; + Result := CommaText; + finally + Free; + end; + wbEventFunctionAndMemberEditInfo := Result; + finally + FreeAndNil(slMember); + end + end; + end; +end; + +function wbEventFunctionAndMemberToInt(const aString: string; const aElement: IwbElement): Int64; +var + EventFunction, EventMember, i: Integer; +begin + i := Pos(':', aString); + if i > 0 then begin + EventFunction := wbEventFunctionEnum.FromEditValue(Copy(aString, 1, i-1), nil); + EventMember := wbEventMemberEnum.FromEditValue(Copy(aString, i+1, Length(aString)), nil); + end + else begin + EventFunction := 0; + EventMember := 0; + end; + Result := EventMember shl 16 + EventFunction; +end; + +procedure wbINFOPNAMAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + Container : IwbContainer; + Group : IwbGroupRecord; +begin + if not wbSortINFO then + Exit; + + if VarSameValue(aOldValue, aNewValue) then + Exit; + + if not Assigned(aElement) then + Exit; + + Container := aElement.Container; + while Assigned(Container) do begin + if Supports(Container, IwbGroupRecord, Group) then begin + Group.Sort(True); + Exit; + end; + Container := Container.Container; + end; + +end; + +procedure wbMESGDNAMAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + OldValue, NewValue : Integer; + Container : IwbContainerElementRef; +begin + if VarSameValue(aOldValue, aNewValue) then + Exit; + + if not Supports(aElement.Container, IwbContainerElementRef, Container) then + Exit; + + OldValue := Integer(aOldValue) and 1; + NewValue := Integer(aNewValue) and 1; + + if NewValue = OldValue then + Exit; + + if NewValue = 1 then + Container.RemoveElement('TNAM') + else + Container.Add('TNAM', True); +end; + +procedure wbGMSTEDIDAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + OldValue, NewValue : string; + Container : IwbContainerElementRef; +begin + if VarSameValue(aOldValue, aNewValue) then + Exit; + + if not Supports(aElement.Container, IwbContainerElementRef, Container) then + Exit; + + OldValue := aOldValue; + NewValue := aNewValue; + + if (Length(OldValue) < 1) or (Length(OldValue) < 1) or (OldValue[1] <> NewValue[1]) then begin + Container.RemoveElement('DATA'); + Container.Add('DATA', True); + end; +end; + +procedure wbFLSTEDIDAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + OldValue, NewValue : string; + OldOrdered, NewOrdered : Boolean; + Container : IwbContainerElementRef; +const + OrderedList = 'OrderedList'; +begin + if VarSameValue(aOldValue, aNewValue) then + Exit; + + if not Supports(aElement.Container, IwbContainerElementRef, Container) then + Exit; + + OldValue := aOldValue; + NewValue := aNewValue; + + if Length(OldValue) > Length(OrderedList) then + Delete(OldValue, 1, Length(OldValue)-Length(OrderedList)); + + if Length(NewValue) > Length(OrderedList) then + Delete(NewValue, 1, Length(NewValue)-Length(OrderedList)); + + OldOrdered := SameText(OldValue, OrderedList); + NewOrdered := SameText(NewValue, OrderedList); + + if OldOrdered <> NewOrdered then + Container.RemoveElement('FormIDs'); +end; + +procedure wbCtdaTypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + OldValue, NewValue: Integer; + Container: IwbContainerElementRef; +begin + if VarSameValue(aOldValue, aNewValue) then + Exit; + + if not Supports(aElement, IwbContainerElementRef, Container) then + Exit; + + // reset value if "use global" has changed + OldValue := aOldValue and $04; + NewValue := aNewValue and $04; + + if OldValue <> NewValue then + Container.ElementNativeValues['..\Comparison Value'] := 0; + + {>>> "run on target", no such flag in Skyrim <<<} +// if aNewValue and $02 then begin +// Container.ElementNativeValues['..\Run On'] := 1; +// if Integer(Container.ElementNativeValues['..\Run On']) = 1 then +// aElement.NativeValue := Byte(aNewValue) and not $02; +// end; +end; + +procedure wbAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +begin + Exit; +end; + +{>>> Needs revision for Skyrim <<<} +//function wbIdleAnam(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +//begin +// Result := ''; +// case aType of +// ctToStr, ctToSummary: begin +// case aInt and not $C0 of +// 0: Result := 'Idle'; +// 1: Result := 'Movement'; +// 2: Result := 'Left Arm'; +// 3: Result := 'Left Hand'; +// 4: Result := 'Weapon'; +// 5: Result := 'Weapon Up'; +// 6: Result := 'Weapon Down'; +// 7: Result := 'Special Idle'; +// 20: Result := 'Whole Body'; +// 21: Result := 'Upper Body'; +// else +// Result := ''; +// end; +// +// if (aInt and $80) = 0 then +// Result := Result + ', Must return a file'; +// if (aInt and $40) = 1 then +// Result := Result + ', Unknown Flag'; +// end; +// ctToSortKey: begin +// Result := IntToHex64(aInt, 2); +// end; +// ctCheck: begin +// case aInt and not $C0 of +// 0..7, 20, 21: Result := ''; +// else +// Result := ''; +// end; +// end; +// end; +//end; + +function wbCloudSpeedToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +begin + Result := ''; + case aType of + ctToStr, ctToSummary, ctToEditValue: Result := FloatToStrF((aInt - 127)/127/10, ffFixed, 99, 4); + ctCheck: Result := ''; + end; +end; + +function wbCloudSpeedToInt(const aString: string; const aElement: IwbElement): Int64; +var + f: Extended; +begin + f := StrToFloat(aString); + f := f*10*127 + 127; + Result := Min(Round(f), 254); +end; + +function wbShortXYtoStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + x, y: SmallInt; +begin + y := aInt and $FFFF; + x := aInt shr 16 and $FFFF; + Result := ''; + case aType of + ctToStr, ctToSummary, ctToEditValue: Result := Format('%d, %d', [x, y]); + ctCheck: Result := ''; + end; +end; + +function wbStrToShortXY(const aString: string; const aElement: IwbElement): Int64; +var + x, y: SmallInt; + Value: Cardinal; +begin + y := StrToIntDef(Copy(aString, 1, Pred(Pos(', ', aString))), 0); + x := StrToIntDef(Copy(aString, Pos(', ', aString) + 2, Length(aString)), 0); + PWord(@Value)^ := x; + PWord(Cardinal(@Value) + SizeOf(SmallInt))^ := y; + Result := Value; +end; + +function wbGLOBFNAM(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +begin + Result := ''; + case aType of + ctToStr, ctToSummary: begin + case aInt of + Ord('s'): Result := 'Short'; + Ord('l'): Result := 'Long'; + Ord('f'): Result := 'Float'; + Ord('b'): Result := 'Boolean'; + else + Result := ''; + end; + end; + ctToSortKey: Result := Chr(aInt); + ctCheck: begin + case aInt of + Ord('s'), Ord('l'), Ord('f'), Ord('b'): Result := ''; + else + Result := ''; + end; + end; + end; +end; + +function wbPlacedAddInfo(const aMainRecord: IwbMainRecord): string; +var + Rec: IwbRecord; + Container: IwbContainer; + s: string; + Cell: IwbMainRecord; + Position: TwbVector; + Grid: TwbGridCell; +begin + Result := ''; + + Rec := aMainRecord.RecordBySignature['NAME']; + if Assigned(Rec) then begin + s := Trim(Rec.Value); + if s <> '' then + Result := 'places ' + s; + end; + + Container := aMainRecord.Container; + while Assigned(Container) and (Container.ElementType <> etGroupRecord) do + Container := Container.Container; + + if not Assigned(Container) then + Exit; + + s := Trim(Container.Name); + if s <> '' then begin + if Result <> '' then + Result := Result + ' '; + + Result := Result + 'in ' + s; + + // grid position of persistent reference in exterior persistent cell (interior cells are not persistent) + if Supports(aMainRecord.Container, IwbGroupRecord, Container) then + Cell := IwbGroupRecord(Container).ChildrenOf; + + if Assigned(Cell) and Cell.IsPersistent and (Cell.Signature = 'CELL') then + if aMainRecord.GetPosition(Position) then begin + Grid := wbPositionToGridCell(Position); + Result := Result + ' at ' + IntToStr(Grid.x) + ',' + IntToStr(Grid.y); + end; + end; +end; + +function wbINFOAddInfo(const aMainRecord: IwbMainRecord): string; +var + Container: IwbContainer; + s: string; + i: Integer; +begin + Result := Trim(aMainRecord.ElementValues['Responses\Response\NAM1']); + if Result <> '' then + Result := '''' + Result + ''''; + + s := ''; + i := aMainRecord.ElementNativeValues['ENAM\Flags']; + if (i and $0001) <> 0 then + s := s + '[G]'; + if (i and $0002) <> 0 then + s := s + '[R]'; + if (i and $0020) <> 0 then + s := s + '[RE]'; + if (i and $0004) <> 0 then + s := s + '[SO]'; + + Result := s + Result; + + Container := aMainRecord.Container; + while Assigned(Container) and (Container.ElementType <> etGroupRecord) do + Container := Container.Container; + + if Assigned(Container) then begin + s := Trim(Container.Name); + if s <> '' then begin + if Result <> '' then + Result := Result + ' '; + Result := Result + 'in ' + s; + end; + end; + + s := Trim(aMainRecord.ElementValues['QNAM']); + if s <> '' then begin + if Result <> '' then + Result := Result + ' '; + Result := Result + 'for ' + s; + end; +end; + +function wbNAVMAddInfo(const aMainRecord: IwbMainRecord): string; +var + Container: IwbContainer; + s: string; +begin + Result := ''; + + Container := aMainRecord.Container; + while Assigned(Container) and (Container.ElementType <> etGroupRecord) do + Container := Container.Container; + + if not Assigned(Container) then + Exit; + + s := Trim(Container.Name); + if s <> '' then begin + if Result <> '' then + Result := Result + ' '; + Result := Result + 'in ' + s; + end; +end; + +function wbNPCLevelDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container: IwbContainer; + i: Int64; +begin + Result := 0; + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + i := Container.ElementByName['Flags'].NativeValue; + if i and $00000080 <> 0 then + Result := 1; +end; + +function wbMGEFAssocItemDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container : IwbContainer; + Archtype : Variant; + DataContainer : IwbDataContainer; + Element : IwbElement; +const + OffsetArchtype = 56; + +begin + Result := 0; + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + VarClear(ArchType); + Element := Container.ElementByName['Archtype']; + + if Assigned(Element) then + ArchType := Element.NativeValue + else if Supports(Container, IwbDataContainer, DataContainer) and + DataContainer.IsValidOffset(aBasePtr, aEndPtr, OffsetArchtype) then begin // we are part a proper structure + aBasePtr := PByte(aBasePtr) + OffsetArchtype; + ArchType := PCardinal(aBasePtr)^; + end; + + if VarIsEmpty(ArchType) then + Exit; + + case Integer(ArchType) of + 12: Result := 1; // Light + 17: Result := 2; // Bound Item + 18: Result := 3; // Summon Creature + 25: Result := 4; // Guide + 34: Result := 8; // Peak Mod + 35: Result := 5; // Cloak + 36: Result := 6; // Werewolf + 39: Result := 7; // Enhance Weapon + 40: Result := 4; // Spawn Hazard + 46: Result := 6; // Vampire Lord + end; +end; + +procedure wbMGEFAssocItemAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + Container : IwbContainer; + Element : IwbElement; +begin + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + if not (aNewValue <> 0) then + Exit; + + Element := Container.ElementByName['Archtype']; + if Assigned(Element) and (Element.NativeValue = 0) then + Element.NativeValue := $FF; // Signals ArchType that it should not mess with us on the next change! + // I assume this will alo protect Second AV Weight (The two actor values are after ArchType) +end; + +procedure wbMGEFAV2WeightAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + Container : IwbContainer; + Element : IwbElement; +begin + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + if not (aNewValue <> 0.0) then + Exit; + + Element := Container.ElementByName['Archtype']; + if Assigned(Element) and (Element.NativeValue = 0) then + Element.NativeValue := $FF; // Signals ArchType that it should not mess with us on the next change! +end; + +procedure wbMGEFArchtypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + Container: IwbContainerElementRef; +begin + if VarSameValue(aOldValue, aNewValue) then + Exit; + + if not Supports(aElement, IwbContainerElementRef, Container) then + Exit; + + if (aNewValue < $FF) and (aOldValue < $FF) then begin + Container.ElementNativeValues['..\Assoc. Item'] := 0; + case Integer(aNewValue) of + 06: Container.ElementNativeValues['..\Actor Value'] := 00;//Agression + 07: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence + 08: Container.ElementNativeValues['..\Actor Value'] := 00;//Agression + 11: Container.ElementNativeValues['..\Actor Value'] := 54;//Invisibility + 21: Container.ElementNativeValues['..\Actor Value'] := 53;//Paralysis + 24: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence + 38: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence + 42: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence + else + Container.ElementNativeValues['..\Actor Value'] := -1; + end; + Container.ElementNativeValues['..\Second Actor Value'] := -1; + Container.ElementNativeValues['..\Second AV Weight'] := 0.0; + end; +end; + +function wbNAVIIslandDataDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container : IwbContainer; + SubRecord : IwbMainRecord; + Element : IwbElement; +begin + Result := 0; + + Container := aElement.Container; + while Assigned(Container) and (Container.ElementType <> etsubRecord) do + Container := Container.Container; + + if not Supports(Container, IwbSubRecord, SubRecord) then + Exit; + + Element := SubRecord.ElementByName['Is Island']; + if not Assigned(Element) then + Exit; + + Result := Element.NativeValue; +end; + +function wbNAVIParentDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container : IwbContainer; + SubRecord : IwbMainRecord; + Element : IwbElement; +begin + Result := 0; + + Container := aElement.Container; + while Assigned(Container) and (Container.ElementType <> etsubRecord) do + Container := Container.Container; + + if not Supports(Container, IwbSubRecord, SubRecord) then + Exit; + + Element := SubRecord.ElementByName['Parent Worldspace']; + if not Assigned(Element) then + Exit; + + if (Element.NativeValue = 0) then + Result := 1; +end; + +function wbNVNMParentDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container : IwbContainer; + Current : IwbContainer; + Parent : IwbContainer; + GroupRecord : IwbGroupRecord; + MainRecord : IwbMainRecord; + rData : IwbRecord; + i : integer; +begin + Result := 0; + + Container := aElement.Container; + while Assigned(Container) and (Container.ElementType <> etGroupRecord) do + Container := Container.Container; + + if not Supports(Container, IwbGroupRecord, GroupRecord) then + Exit; + + MainRecord := GroupRecord.ChildrenOf; // This does NOT work while adding master! + + if not Assigned(MainRecord) then begin // we expect: + // plugin \ CELL group \ Block \ Sub Block \ CELL + // \ CELL Children group \ Permanent children group + // \ Temporary children group = GroupRecord = Container + if Assigned(Container) and (Container.ElementType = etGroupRecord) then + Container := Container.Container; + if Assigned(Container) and (Container.ElementType = etGroupRecord) then + Parent := Container.Container; + i := 0; + while (i < Parent.ElementCount) and Supports(Parent.Elements[i], IwbContainer, Current) and (Current <> Container) do + Inc(i); + if (i = 0) or (i = Parent.ElementCount) or not Supports(Parent.Elements[i-1], IwbMainRecord,MainRecord) then begin + wbProgressCallback('Parent of a NVNM is not a MainRecord'); +// Assert(Assigned(MainRecord)); // Better an exception than to destroy the plugin. + Exit; + end; + end; + + if (MainRecord.Signature<>CELL) then begin + wbProgressCallback('Parent of a NVNM is not identified as a CELL'); + Assert(MainRecord.Signature=CELL); // Better an exception than to destroy the plugin. + Exit; + end; + + rDATA := MainRecord.RecordBySignature['DATA']; + + if not Assigned(rData) then + Exit; + + i := rData.NativeValue; + + // is interior cell? + if i and 1 <> 0 then + Result := 1; +end; + +function wbCOEDOwnerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container : IwbContainer; + LinksTo : IwbElement; + MainRecord : IwbMainRecord; +begin + Result := 0; + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + LinksTo := Container.ElementLinksTo['Owner']; + + if Supports(LinksTo, IwbMainRecord, MainRecord) then + if MainRecord.Signature = 'NPC_' then + Result := 1 + else if MainRecord.Signature = 'FACT' then + Result := 2; +end; + +function wbGMSTUnionDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + rEDID: IwbRecord; + s: string; +begin + Result := 1; + rEDID := aElement.Container.RecordBySignature[EDID]; + if not Assigned(rEDID) then + Exit; + + s := rEDID.Value; + if Length(s) > 0 then + case s[1] of + 's': Result := 0; {String} {>>> Localization Strings <<<} + 'i': Result := 1; {intS32} + 'f': Result := 2; {Float} + 'b': Result := 3; {Boolean} + end; +end; + +function wbFLSTLNAMIsSorted(const aContainer: IwbContainer): Boolean; +var + rEDID : IwbRecord; + s : string; +const + OrderedList = 'OrderedList'; +begin + Result := False; {>>> Should not be sorted according to Arthmoor and JustinOther <<<} + rEDID := aContainer.RecordBySignature[EDID]; + if not Assigned(rEDID) then + Exit; + + s := rEDID.Value; + if Length(s) > Length(OrderedList) then + Delete(s, 1, Length(s)-Length(OrderedList)); + + if SameText(s, OrderedList) then + Result := False; +end; + +function wbPerkDATADecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + rPRKE: IwbRecord; + eType: IwbElement; +begin + Result := 0; + rPRKE := aElement.Container.RecordBySignature[PRKE]; + if not Assigned(rPRKE) then + Exit; + + eType := rPRKE.ElementByName['Type']; + if not Assigned(eType) then + Exit; + + Result := eType.NativeValue; +end; + +function wbEPFDDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container: IwbContainerElementRef; +begin + Result := 0; + if not Assigned(aElement) then + Exit; + + if not Supports(aElement.Container, IwbContainerElementRef, Container) then + Exit; + + Result := Container.ElementNativeValues['EPFT']; + + if Result = 2 then + case Integer(Container.ElementNativeValues['..\DATA\Entry Point\Function']) of + 5, 12, 13, 14: Result := 8; + end; +end; + + +{>>> For VMAD <<<} +function wbScriptPropertyDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container : IwbContainer; +begin + Result := 0; + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + case Integer(Container.ElementNativeValues['Type']) of + 1: Result := 1; + 2: Result := 2; + 3: Result := 3; + 4: Result := 4; + 5: Result := 5; + 11: Result := 6; + 12: Result := 7; + 13: Result := 8; + 14: Result := 9; + 15: Result := 10; + end; +end; + +procedure wbScriptPropertyTypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + Container : IwbContainerElementRef; +begin + if aOldValue <> aNewValue then + if Supports(aElement.Container, IwbContainerElementRef, Container) then + Container.ElementByName['Value'].SetToDefault; +end; + +{>>> For VMAD <<<} +function wbScriptFragmentExistsDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container : IwbContainer; + MainRecord : IwbMainRecord; +begin + Result := 0; + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + while Assigned(Container) and (Container.ElementType <> etMainRecord) do + Container := Container.Container; + + if not Assigned(Container) then Exit; + + // TODO: should this assume there's a MainRecord? + Supports(Container, IwbMainRecord, MainRecord); + + if MainRecord.Signature = INFO then + Result := 1 + else if MainRecord.Signature = PACK then + Result := 2 + else if MainRecord.Signature = PERK then + Result := 3 + else if MainRecord.Signature = QUST then + Result := 4 + else if MainRecord.Signature = SCEN then + Result := 5; +end; + +{>>> For VMAD <<<} +function wbScriptFragmentsQuestCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; +var + Container : IwbContainer; +begin + Result := 0; + if aElement.ElementType = etValue then + Container := aElement.Container + else + Container := aElement as IwbContainer; + if not Assigned(Container) then Exit; + while Assigned(Container) and (Container.Name <> 'Script Fragments') do + Container := Container.Container; + if not Assigned(Container) then Exit; + + Result := Integer(Container.ElementNativeValues['FragmentCount']); +end; + +procedure wbScriptFragmentsQuestAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +begin + wbCounterContainerAfterSet('FragmentCount', 'Fragments', aElement); +end; + +procedure wbScriptFragmentsQuestFragmentsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +begin + wbCounterAfterSet('FragmentCount', aElement); +end; + +{>>> For VMAD <<<} +function wbScriptFragmentsInfoCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; +var + Container : IwbContainer; + F : Integer; + i : Integer; +begin + Result := 0; + if aElement.ElementType = etValue then + Container := aElement.Container + else + Container := aElement as IwbContainer; + if not Assigned(Container) then Exit; + while Assigned(Container) and (Container.Name <> 'Script Fragments') do + Container := Container.Container; + if not Assigned(Container) then Exit; + + F := Container.ElementByName['Flags'].NativeValue; + for i := 0 to 2 do begin + if (F and 1) = 1 then + Inc(Result); + F := F shr 1; + end; + + for i := 3 to 7 do begin + if (F and 1) = 1 then begin + Inc(Result); + if wbHasProgressCallback then + wbProgressCallback('==='+aElement.Name+' ['+Container.Name+':'+Container.Path+'] = unknown info VMAD flag bit '+IntToStr(i)); + end; + F := F shr 1; + end; +end; + +{>>> For VMAD <<<} +function wbScriptFragmentsSceneCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; +var + Container : IwbContainer; + F : Integer; + i : Integer; +begin + Result := 0; + if aElement.ElementType = etValue then + Container := aElement.Container + else + Container := aElement as IwbContainer; + if not Assigned(Container) then Exit; + while Assigned(Container) and (Container.Name <> 'Script Fragments') do + Container := Container.Container; + if not Assigned(Container) then Exit; + + F := Container.ElementByName['Flags'].NativeValue; + for i := 0 to 2 do begin + if (F and 1) = 1 then + Inc(Result); + F := F shr 1; + end; + + for i := 3 to 7 do begin + if (F and 1) = 1 then begin + Inc(Result); + if wbHasProgressCallback then + wbProgressCallback('==='+aElement.Name+' ['+Container.Name+':'+Container.Path+'] = unknown scene VMAD flag bit '+IntToStr(i)); + end; + F := F shr 1; + end; +end; + +{>>> For VMAD <<<} +function wbScriptFragmentsPackCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; +var + Container : IwbContainer; + F : Integer; + i : Integer; +begin + Result := 0; + if aElement.ElementType = etValue then + Container := aElement.Container + else + Container := aElement as IwbContainer; + if not Assigned(Container) then Exit; + while Assigned(Container) and (Container.Name <> 'Script Fragments') do + Container := Container.Container; + if not Assigned(Container) then Exit; + + F := Container.ElementByName['Flags'].NativeValue; + for i := 0 to 7 do begin + if (F and 1) = 1 then + Inc(Result); + F := F shr 1; + end; +end; + +function wbBOOKTeachesDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container: IwbContainer; + i: Int64; +begin + Result := 0; + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + i := Container.ElementByName['Flags'].NativeValue; + if i and $00000004 <> 0 then Result := 1; +end; + +type + TCTDAFunctionParamType = ( + ptNone, + ptInteger, + ptFloat, + ptVariableName, //Integer + ptSex, //Enum: Male, Female + ptActorValue, //Enum: wbActorValue + ptCrimeType, //?? Enum + ptAxis, //?? Char + ptQuestStage, //?? Integer + ptMiscStat, //?? Enum + ptAlignment, //?? Enum + ptEquipType, //?? Enum + ptFormType, //?? Enum + ptCriticalStage, //?? Enum + ptObjectReference, //REFR, ACHR + ptInventoryObject, //ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, ARMA, LIGH, LVLI, COBJ + ptActor, //ACHR + ptVoiceType, //VTYP + ptIdleForm, //IDLE + ptFormList, //FLST + ptQuest, //QUST + ptFaction, //FACT + ptCell, //CELL + ptClass, //CLAS + ptRace, //RACE + ptActorBase, //NPC_ + ptGlobal, //GLOB + ptWeather, //WTHR + ptPackage, //PACK + ptEncounterZone, //ECZN + ptPerk, //PERK + ptOwner, //FACT, NPC_ + ptFurniture, //FURN + ptMagicItem, //SPEL + ptMagicEffect, //MGEF + ptWorldspace, //WRLD + ptVATSValueFunction, + ptVATSValueParam, + ptReferencableObject, + ptRegion, //REGN + ptKeyword, //KYWD + ptAdvanceAction, // ?? Enum + ptCastingSource, // ?? Enum + ptShout, //SHOU + ptLocation, //LCTN + ptRefType, //LCRT + ptAlias, // index into QUST quest aliases + ptPackdata, // index into PACK package data inputs + ptAssociationType, // ASTP + ptFurnitureAnim, // enum + ptFurnitureEntry, // flags + ptScene, // SCEN + ptWardState, // enum + ptEvent, // Struct + ptEventData, // LCTN, KYWD or FLST + ptKnowable // MGEF, WOOP, ENCH + ); + + PCTDAFunction = ^TCTDAFunction; + TCTDAFunction = record + Index: Integer; + Name: string; + ParamType1: TCTDAFunctionParamType; + ParamType2: TCTDAFunctionParamType; + ParamType3: TCTDAFunctionParamType; + end; + +const + {>> N means New, V means verified that the name has not changed <<<} + wbCTDAFunctions : array[0..401] of TCTDAFunction = ( +{N} (Index: 0; Name: 'GetWantBlocking'), +{V} (Index: 1; Name: 'GetDistance'; ParamType1: ptObjectReference), +{V} (Index: 5; Name: 'GetLocked'), +{V} (Index: 6; Name: 'GetPos'; ParamType1: ptAxis), +{V} (Index: 8; Name: 'GetAngle'; ParamType1: ptAxis), +{V} (Index: 10; Name: 'GetStartingPos'; ParamType1: ptAxis), +{V} (Index: 11; Name: 'GetStartingAngle'; ParamType1: ptAxis), +{V} (Index: 12; Name: 'GetSecondsPassed'), +{V} (Index: 14; Name: 'GetActorValue'; ParamType1: ptActorValue), +{V} (Index: 18; Name: 'GetCurrentTime'), +{V} (Index: 24; Name: 'GetScale'), +{V} (Index: 25; Name: 'IsMoving'), +{V} (Index: 26; Name: 'IsTurning'), +{V} (Index: 27; Name: 'GetLineOfSight'; ParamType1: ptObjectReference), +{V} (Index: 32; Name: 'GetInSameCell'; ParamType1: ptObjectReference), +{V} (Index: 35; Name: 'GetDisabled'), +{V} (Index: 36; Name: 'MenuMode'; ParamType1: ptInteger), // was ptMenuMode +{V} (Index: 39; Name: 'GetDisease'), +{V} (Index: 41; Name: 'GetClothingValue'), +{V} (Index: 42; Name: 'SameFaction'; ParamType1: ptActor), +{V} (Index: 43; Name: 'SameRace'; ParamType1: ptActor), +{V} (Index: 44; Name: 'SameSex'; ParamType1: ptActor), +{V} (Index: 45; Name: 'GetDetected'; ParamType1: ptActor), +{V} (Index: 46; Name: 'GetDead'), +{V} (Index: 47; Name: 'GetItemCount'; ParamType1: ptInventoryObject), +{V} (Index: 48; Name: 'GetGold'), +{V} (Index: 49; Name: 'GetSleeping'), +{V} (Index: 50; Name: 'GetTalkedToPC'), +{V} (Index: 53; Name: 'GetScriptVariable'; ParamType1: ptObjectReference; ParamType2: ptVariableName), +{V} (Index: 56; Name: 'GetQuestRunning'; ParamType1: ptQuest), +{V} (Index: 58; Name: 'GetStage'; ParamType1: ptQuest), +{V} (Index: 59; Name: 'GetStageDone'; ParamType1: ptQuest; ParamType2: ptQuestStage), +{V} (Index: 60; Name: 'GetFactionRankDifference'; ParamType1: ptFaction; ParamType2: ptActor), +{V} (Index: 61; Name: 'GetAlarmed'), +{V} (Index: 62; Name: 'IsRaining'), +{V} (Index: 63; Name: 'GetAttacked'), +{V} (Index: 64; Name: 'GetIsCreature'), +{V} (Index: 65; Name: 'GetLockLevel'), +{V} (Index: 66; Name: 'GetShouldAttack'; ParamType1: ptActor), +{V} (Index: 67; Name: 'GetInCell'; ParamType1: ptCell), +{V} (Index: 68; Name: 'GetIsClass'; ParamType1: ptClass), +{V} (Index: 69; Name: 'GetIsRace'; ParamType1: ptRace), +{V} (Index: 70; Name: 'GetIsSex'; ParamType1: ptSex), +{V} (Index: 71; Name: 'GetInFaction'; ParamType1: ptFaction), +{V} (Index: 72; Name: 'GetIsID'; ParamType1: ptReferencableObject), +{V} (Index: 73; Name: 'GetFactionRank'; ParamType1: ptFaction), +{V} (Index: 74; Name: 'GetGlobalValue'; ParamType1: ptGlobal), +{V} (Index: 75; Name: 'IsSnowing'), +{V} (Index: 77; Name: 'GetRandomPercent'), +{V} (Index: 79; Name: 'GetQuestVariable'; ParamType1: ptQuest; ParamType2: ptVariableName), +{V} (Index: 80; Name: 'GetLevel'), +{N} (Index: 81; Name: 'IsRotating'), +{V} (Index: 84; Name: 'GetDeadCount'; ParamType1: ptActorBase), +{V} (Index: 91; Name: 'GetIsAlerted'), +{V} (Index: 98; Name: 'GetPlayerControlsDisabled'; ParamType1: ptInteger; ParamType2: ptInteger), +{V} (Index: 99; Name: 'GetHeadingAngle'; ParamType1: ptObjectReference), +{N} (Index: 101; Name: 'IsWeaponMagicOut'), +{V} (Index: 102; Name: 'IsTorchOut'), +{V} (Index: 103; Name: 'IsShieldOut'), +{V} (Index: 106; Name: 'IsFacingUp'), +{V} (Index: 107; Name: 'GetKnockedState'), +{V} (Index: 108; Name: 'GetWeaponAnimType'), +{V} (Index: 109; Name: 'IsWeaponSkillType'; ParamType1: ptActorValue), +{V} (Index: 110; Name: 'GetCurrentAIPackage'), +{V} (Index: 111; Name: 'IsWaiting'), +{V} (Index: 112; Name: 'IsIdlePlaying'), +{N} (Index: 116; Name: 'IsIntimidatedbyPlayer'), +{N} (Index: 117; Name: 'IsPlayerInRegion'; ParamType1: ptRegion), +{V} (Index: 118; Name: 'GetActorAggroRadiusViolated'), +{V} (Index: 122; Name: 'GetCrime'; ParamType1: ptActor; ParamType2: ptCrimeType), +{V} (Index: 123; Name: 'IsGreetingPlayer'), +{V} (Index: 125; Name: 'IsGuard'), +{V} (Index: 127; Name: 'HasBeenEaten'), +{V} (Index: 128; Name: 'GetStaminaPercentage'), +{V} (Index: 129; Name: 'GetPCIsClass'; ParamType1: ptClass), +{V} (Index: 130; Name: 'GetPCIsRace'; ParamType1: ptRace), +{V} (Index: 131; Name: 'GetPCIsSex'; ParamType1: ptSex), +{V} (Index: 132; Name: 'GetPCInFaction'; ParamType1: ptFaction), +{V} (Index: 133; Name: 'SameFactionAsPC'), +{V} (Index: 134; Name: 'SameRaceAsPC'), +{V} (Index: 135; Name: 'SameSexAsPC'), +{V} (Index: 136; Name: 'GetIsReference'; ParamType1: ptObjectReference), +{V} (Index: 141; Name: 'IsTalking'), +{V} (Index: 142; Name: 'GetWalkSpeed'), +{V} (Index: 143; Name: 'GetCurrentAIProcedure'), +{V} (Index: 144; Name: 'GetTrespassWarningLevel'), +{V} (Index: 145; Name: 'IsTrespassing'), +{V} (Index: 146; Name: 'IsInMyOwnedCell'), +{V} (Index: 147; Name: 'GetWindSpeed'), +{V} (Index: 148; Name: 'GetCurrentWeatherPercent'), +{V} (Index: 149; Name: 'GetIsCurrentWeather'; ParamType1: ptWeather), +{V} (Index: 150; Name: 'IsContinuingPackagePCNear'), +{N} (Index: 152; Name: 'GetIsCrimeFaction'; ParamType1: ptFaction), +{V} (Index: 153; Name: 'CanHaveFlames'), +{V} (Index: 154; Name: 'HasFlames'), +{V} (Index: 157; Name: 'GetOpenState'), +{V} (Index: 159; Name: 'GetSitting'), +{V} (Index: 161; Name: 'GetIsCurrentPackage'; ParamType1: ptPackage), +{V} (Index: 162; Name: 'IsCurrentFurnitureRef'; ParamType1: ptObjectReference), +{V} (Index: 163; Name: 'IsCurrentFurnitureObj'; ParamType1: ptFurniture), +{V} (Index: 170; Name: 'GetDayOfWeek'), +{V} (Index: 172; Name: 'GetTalkedToPCParam'; ParamType1: ptActor), +{V} (Index: 175; Name: 'IsPCSleeping'), +{V} (Index: 176; Name: 'IsPCAMurderer'), +{N} (Index: 180; Name: 'HasSameEditorLocAsRef'; ParamType1: ptObjectReference; ParamType2: ptKeyword), +{N} (Index: 181; Name: 'HasSameEditorLocAsRefAlias'; ParamType1: ptAlias; ParamType2: ptKeyword), +{V} (Index: 182; Name: 'GetEquipped'; ParamType1: ptInventoryObject), +{V} (Index: 185; Name: 'IsSwimming'), +{V} (Index: 190; Name: 'GetAmountSoldStolen'), +{V} (Index: 192; Name: 'GetIgnoreCrime'), +{V} (Index: 193; Name: 'GetPCExpelled'; ParamType1: ptFaction), +{V} (Index: 195; Name: 'GetPCFactionMurder'; ParamType1: ptFaction), +{V} (Index: 197; Name: 'GetPCEnemyofFaction'; ParamType1: ptFaction), +{V} (Index: 199; Name: 'GetPCFactionAttack'; ParamType1: ptFaction), +{V} (Index: 203; Name: 'GetDestroyed'), +{V} (Index: 214; Name: 'HasMagicEffect'; ParamType1: ptMagicEffect), +{V} (Index: 215; Name: 'GetDefaultOpen'), +{V} (Index: 219; Name: 'GetAnimAction'), +{V} (Index: 223; Name: 'IsSpellTarget'; ParamType1: ptMagicItem), +{V} (Index: 224; Name: 'GetVATSMode'), +{V} (Index: 225; Name: 'GetPersuasionNumber'), +{V} (Index: 226; Name: 'GetVampireFeed'), +{V} (Index: 227; Name: 'GetCannibal'), +{V} (Index: 228; Name: 'GetIsClassDefault'; ParamType1: ptClass), +{V} (Index: 229; Name: 'GetClassDefaultMatch'), +{V} (Index: 230; Name: 'GetInCellParam'; ParamType1: ptCell; ParamType2: ptObjectReference), +{V} (Index: 235; Name: 'GetVatsTargetHeight'), +{V} (Index: 237; Name: 'GetIsGhost'), +{V} (Index: 242; Name: 'GetUnconscious'), +{V} (Index: 244; Name: 'GetRestrained'), +{V} (Index: 246; Name: 'GetIsUsedItem'; ParamType1: ptReferencableObject), +{V} (Index: 247; Name: 'GetIsUsedItemType'; ParamType1: ptFormType), +{N} (Index: 248; Name: 'IsScenePlaying'; ParamType1: ptScene), +{N} (Index: 249; Name: 'IsInDialogueWithPlayer'), +{N} (Index: 250; Name: 'GetLocationCleared'; ParamType1: ptLocation), +{V} (Index: 254; Name: 'GetIsPlayableRace'), +{V} (Index: 255; Name: 'GetOffersServicesNow'), +{N} (Index: 258; Name: 'HasAssociationType'; ParamType1: ptActor; ParamType2: ptAssociationType), +{N} (Index: 259; Name: 'HasFamilyRelationship'; ParamType1: ptActor), +{N} (Index: 261; Name: 'HasParentRelationship'; ParamType1: ptActor), +{N} (Index: 262; Name: 'IsWarningAbout'; ParamType1: ptFormList), +{V} (Index: 263; Name: 'IsWeaponOut'), +{N} (Index: 264; Name: 'HasSpell'; ParamType1: ptMagicItem), +{V} (Index: 265; Name: 'IsTimePassing'), +{V} (Index: 266; Name: 'IsPleasant'), +{V} (Index: 267; Name: 'IsCloudy'), +{N} (Index: 274; Name: 'IsSmallBump'), +{V} (Index: 277; Name: 'GetBaseActorValue'; ParamType1: ptActorValue), +{V} (Index: 278; Name: 'IsOwner'; ParamType1: ptOwner), +{V} (Index: 280; Name: 'IsCellOwner'; ParamType1: ptCell; ParamType2: ptOwner), +{V} (Index: 282; Name: 'IsHorseStolen'), +{V} (Index: 285; Name: 'IsLeftUp'), +{V} (Index: 286; Name: 'IsSneaking'), +{V} (Index: 287; Name: 'IsRunning'), +{V} (Index: 288; Name: 'GetFriendHit'), +{V} (Index: 289; Name: 'IsInCombat'; ParamType1: ptInteger), +{V} (Index: 300; Name: 'IsInInterior'), +{V} (Index: 304; Name: 'IsWaterObject'), +{N} (Index: 305; Name: 'GetPlayerAction'), +{V} (Index: 306; Name: 'IsActorUsingATorch'), +{V} (Index: 309; Name: 'IsXBox'), +{V} (Index: 310; Name: 'GetInWorldspace'; ParamType1: ptWorldSpace), +{V} (Index: 312; Name: 'GetPCMiscStat'; ParamType1: ptMiscStat), +{N} (Index: 313; Name: 'GetPairedAnimation'), +{V} (Index: 314; Name: 'IsActorAVictim'), +{V} (Index: 315; Name: 'GetTotalPersuasionNumber'), +{V} (Index: 318; Name: 'GetIdleDoneOnce'), +{V} (Index: 320; Name: 'GetNoRumors'), +{N} (Index: 323; Name: 'GetCombatState'), +{N} (Index: 325; Name: 'GetWithinPackageLocation'; ParamType1: ptPackdata), +{V} (Index: 327; Name: 'IsRidingMount'), +{N} (Index: 329; Name: 'IsFleeing'), +{V} (Index: 332; Name: 'IsInDangerousWater'), +{V} (Index: 338; Name: 'GetIgnoreFriendlyHits'), +{V} (Index: 339; Name: 'IsPlayersLastRiddenMount'), +{V} (Index: 353; Name: 'IsActor'), +{V} (Index: 354; Name: 'IsEssential'), +{V} (Index: 358; Name: 'IsPlayerMovingIntoNewSpace'), +{N} (Index: 359; Name: 'GetInCurrentLoc'; ParamType1: ptLocation), +{N} (Index: 360; Name: 'GetInCurrentLocAlias'; ParamType1: ptAlias), +{V} (Index: 361; Name: 'GetTimeDead'), +{N} (Index: 362; Name: 'HasLinkedRef'; ParamType1: ptKeyword), +{V} (Index: 365; Name: 'IsChild'), +{N} (Index: 366; Name: 'GetStolenItemValueNoCrime'; ParamType1: ptFaction), +{V} (Index: 367; Name: 'GetLastPlayerAction'), +{V} (Index: 368; Name: 'IsPlayerActionActive'; ParamType1: ptInteger), // was ptPlayerAction +{V} (Index: 370; Name: 'IsTalkingActivatorActor'; ParamType1: ptActor), +{V} (Index: 372; Name: 'IsInList'; ParamType1: ptFormList), +{N} (Index: 373; Name: 'GetStolenItemValue'; ParamType1: ptFaction), +{N} (Index: 375; Name: 'GetCrimeGoldViolent'; ParamType1: ptFaction), +{N} (Index: 376; Name: 'GetCrimeGoldNonviolent'; ParamType1: ptFaction), +{N} (Index: 378; Name: 'HasShout'; ParamType1: ptShout), +{V} (Index: 381; Name: 'GetHasNote'; ParamType1: ptInteger), // was ptNote +{V} (Index: 390; Name: 'GetHitLocation'), +{V} (Index: 391; Name: 'IsPC1stPerson'), +{V} (Index: 396; Name: 'GetCauseofDeath'), +{V} (Index: 397; Name: 'IsLimbGone'; ParamType1: ptInteger), // was ptBodyLocation +{V} (Index: 398; Name: 'IsWeaponInList'; ParamType1: ptFormList), +{N} (Index: 402; Name: 'IsBribedbyPlayer'), +{V} (Index: 403; Name: 'GetRelationshipRank'; ParamType1: ptObjectReference), +{V} (Index: 407; Name: 'GetVATSValue'; ParamType1: ptVATSValueFunction; ParamType2: ptVATSValueParam), +{V} (Index: 408; Name: 'IsKiller'; ParamType1: ptActor), +{V} (Index: 409; Name: 'IsKillerObject'; ParamType1: ptFormList), +{V} (Index: 410; Name: 'GetFactionCombatReaction'; ParamType1: ptFaction; ParamType2: ptFaction), +{V} (Index: 414; Name: 'Exists'; ParamType1: ptObjectReference), +{V} (Index: 415; Name: 'GetGroupMemberCount'), +{V} (Index: 416; Name: 'GetGroupTargetCount'), +{V} (Index: 426; Name: 'GetIsVoiceType'; ParamType1: ptVoiceType), +{V} (Index: 427; Name: 'GetPlantedExplosive'), +{N} (Index: 429; Name: 'IsScenePackageRunning'), +{V} (Index: 430; Name: 'GetHealthPercentage'), +{V} (Index: 432; Name: 'GetIsObjectType'; ParamType1: ptFormType), +{V} (Index: 434; Name: 'GetDialogueEmotion'), +{V} (Index: 435; Name: 'GetDialogueEmotionValue'), +{V} (Index: 437; Name: 'GetIsCreatureType'; ParamType1: ptInteger), +{N} (Index: 444; Name: 'GetInCurrentLocFormList'; ParamType1: ptFormList), +{V} (Index: 445; Name: 'GetInZone'; ParamType1: ptEncounterZone), +{N} (Index: 446; Name: 'GetVelocity'; ParamType1: ptAxis), +{N} (Index: 447; Name: 'GetGraphVariableFloat'; ParamType1: ptVariableName), +{V} (Index: 448; Name: 'HasPerk'; ParamType1: ptPerk; ParamType2: ptInteger{Alt?}), +{V} (Index: 449; Name: 'GetFactionRelation'; ParamType1: ptActor), +{V} (Index: 450; Name: 'IsLastIdlePlayed'; ParamType1: ptIdleForm), +{V} (Index: 453; Name: 'GetPlayerTeammate'), +{V} (Index: 454; Name: 'GetPlayerTeammateCount'), +{V} (Index: 458; Name: 'GetActorCrimePlayerEnemy'), +{V} (Index: 459; Name: 'GetCrimeGold'; ParamType1: ptFaction), +{V} (Index: 463; Name: 'IsPlayerGrabbedRef'; ParamType1: ptObjectReference), +{N} (Index: 465; Name: 'GetKeywordItemCount'; ParamType1: ptKeyword), +{V} (Index: 470; Name: 'GetDestructionStage'), +{V} (Index: 473; Name: 'GetIsAlignment'; ParamType1: ptAlignment), +{N} (Index: 476; Name: 'IsProtected'), +{V} (Index: 477; Name: 'GetThreatRatio'; ParamType1: ptActor), +{V} (Index: 479; Name: 'GetIsUsedItemEquipType'; ParamType1: ptEquipType), +{N} (Index: 487; Name: 'IsCarryable'), +{V} (Index: 488; Name: 'GetConcussed'), +{V} (Index: 491; Name: 'GetMapMarkerVisible'), +{N} (Index: 493; Name: 'PlayerKnows'; ParamType1: ptKnowable), +{V} (Index: 494; Name: 'GetPermanentActorValue'; ParamType1: ptActorValue), +{V} (Index: 495; Name: 'GetKillingBlowLimb'), +{N} (Index: 497; Name: 'CanPayCrimeGold'), +{N} (Index: 499; Name: 'GetDaysInJail'), +{N} (Index: 500; Name: 'EPAlchemyGetMakingPoison'), +{N} (Index: 501; Name: 'EPAlchemyEffectHasKeyword'; ParamType1: ptKeyword), +{N} (Index: 503; Name: 'GetAllowWorldInteractions'), +{V} (Index: 508; Name: 'GetLastHitCritical'), +{N} (Index: 513; Name: 'IsCombatTarget'; ParamType1: ptActor), +{V} (Index: 515; Name: 'GetVATSRightAreaFree'; ParamType1: ptObjectReference), +{V} (Index: 516; Name: 'GetVATSLeftAreaFree'; ParamType1: ptObjectReference), +{V} (Index: 517; Name: 'GetVATSBackAreaFree'; ParamType1: ptObjectReference), +{V} (Index: 518; Name: 'GetVATSFrontAreaFree'; ParamType1: ptObjectReference), +{N} (Index: 519; Name: 'GetLockIsBroken'), +{N} (Index: 520; Name: 'IsPS3'), +{N} (Index: 521; Name: 'IsWin32'), +{V} (Index: 522; Name: 'GetVATSRightTargetVisible'; ParamType1: ptObjectReference), +{V} (Index: 523; Name: 'GetVATSLeftTargetVisible'; ParamType1: ptObjectReference), +{V} (Index: 524; Name: 'GetVATSBackTargetVisible'; ParamType1: ptObjectReference), +{V} (Index: 525; Name: 'GetVATSFrontTargetVisible'; ParamType1: ptObjectReference), +{V} (Index: 528; Name: 'IsInCriticalStage'; ParamType1: ptCriticalStage), +{N} (Index: 530; Name: 'GetXPForNextLevel'), +{N} (Index: 533; Name: 'GetInfamy'; ParamType1: ptFaction), +{N} (Index: 534; Name: 'GetInfamyViolent'; ParamType1: ptFaction), +{N} (Index: 535; Name: 'GetInfamyNonViolent'; ParamType1: ptFaction), +{V} (Index: 543; Name: 'GetQuestCompleted'; ParamType1: ptQuest), +{V} (Index: 547; Name: 'IsGoreDisabled'), +{N} (Index: 550; Name: 'IsSceneActionComplete'; ParamType1: ptScene; ParamType2: ptInteger), +{V} (Index: 552; Name: 'GetSpellUsageNum'; ParamType1: ptMagicItem), +{N} (Index: 554; Name: 'GetActorsInHigh'), +{V} (Index: 555; Name: 'HasLoaded3D'), +{N} (Index: 560; Name: 'HasKeyword'; ParamType1: ptKeyword), +{N} (Index: 561; Name: 'HasRefType'; ParamType1: ptRefType), +{N} (Index: 562; Name: 'LocationHasKeyword'; ParamType1: ptKeyword), +{N} (Index: 563; Name: 'LocationHasRefType'; ParamType1: ptRefType), +{N} (Index: 565; Name: 'GetIsEditorLocation'; ParamType1: ptLocation), +{N} (Index: 566; Name: 'GetIsAliasRef'; ParamType1: ptAlias), +{N} (Index: 567; Name: 'GetIsEditorLocAlias'; ParamType1: ptAlias), +{N} (Index: 568; Name: 'IsSprinting'), +{N} (Index: 569; Name: 'IsBlocking'), +{N} (Index: 570; Name: 'HasEquippedSpell'; ParamType1: ptCastingSource), +{N} (Index: 571; Name: 'GetCurrentCastingType'; ParamType1: ptCastingSource), +{N} (Index: 572; Name: 'GetCurrentDeliveryType'; ParamType1: ptCastingSource), +{N} (Index: 574; Name: 'GetAttackState'), +{N} (Index: 576; Name: 'GetEventData'; ParamType1: ptEvent; ParamType2: ptEventData; ParamType3: ptNone), +{N} (Index: 577; Name: 'IsCloserToAThanB'; ParamType1: ptObjectReference; ParamType2: ptObjectReference), +{N} (Index: 579; Name: 'GetEquippedShout'; ParamType1: ptShout), +{N} (Index: 580; Name: 'IsBleedingOut'), +{N} (Index: 584; Name: 'GetRelativeAngle'; ParamType1: ptObjectReference; ParamType2: ptAxis), +{N} (Index: 589; Name: 'GetMovementDirection'), +{N} (Index: 590; Name: 'IsInScene'), +{N} (Index: 591; Name: 'GetRefTypeDeadCount'; ParamType1: ptLocation; ParamType2: ptRefType), +{N} (Index: 592; Name: 'GetRefTypeAliveCount'; ParamType1: ptLocation; ParamType2: ptRefType), +{N} (Index: 594; Name: 'GetIsFlying'), +{N} (Index: 595; Name: 'IsCurrentSpell'; ParamType1: ptMagicItem; ParamType2: ptCastingSource), +{N} (Index: 596; Name: 'SpellHasKeyword'; ParamType1: ptCastingSource; ParamType2: ptKeyword), +{N} (Index: 597; Name: 'GetEquippedItemType'; ParamType1: ptCastingSource), +{N} (Index: 598; Name: 'GetLocationAliasCleared'; ParamType1: ptAlias), +{N} (Index: 600; Name: 'GetLocAliasRefTypeDeadCount'; ParamType1: ptAlias; ParamType2: ptRefType), +{N} (Index: 601; Name: 'GetLocAliasRefTypeAliveCount'; ParamType1: ptAlias; ParamType2: ptRefType), +{N} (Index: 602; Name: 'IsWardState'; ParamType1: ptWardState), +{N} (Index: 603; Name: 'IsInSameCurrentLocAsRef'; ParamType1: ptObjectReference; ParamType2: ptKeyword), +{N} (Index: 604; Name: 'IsInSameCurrentLocAsRefAlias'; ParamType1: ptAlias; ParamType2: ptKeyword), +{N} (Index: 605; Name: 'LocAliasIsLocation'; ParamType1: ptAlias; ParamType2: ptLocation), +{N} (Index: 606; Name: 'GetKeywordDataForLocation'; ParamType1: ptLocation; ParamType2: ptKeyword), +{N} (Index: 608; Name: 'GetKeywordDataForAlias'; ParamType1: ptAlias; ParamType2: ptKeyword), +{N} (Index: 610; Name: 'LocAliasHasKeyword'; ParamType1: ptAlias; ParamType2: ptKeyword), +{N} (Index: 611; Name: 'IsNullPackageData'; ParamType1: ptPackdata), +{N} (Index: 612; Name: 'GetNumericPackageData'; ParamType1: ptInteger), +{N} (Index: 613; Name: 'IsFurnitureAnimType'; ParamType1: ptFurnitureAnim), +{N} (Index: 614; Name: 'IsFurnitureEntryType'; ParamType1: ptFurnitureEntry), +{N} (Index: 615; Name: 'GetHighestRelationshipRank'), +{N} (Index: 616; Name: 'GetLowestRelationshipRank'), +{N} (Index: 617; Name: 'HasAssociationTypeAny'; ParamType1: ptAssociationType), +{N} (Index: 618; Name: 'HasFamilyRelationshipAny'), +{N} (Index: 619; Name: 'GetPathingTargetOffset'; ParamType1: ptAxis), +{N} (Index: 620; Name: 'GetPathingTargetAngleOffset'; ParamType1: ptAxis), +{N} (Index: 621; Name: 'GetPathingTargetSpeed'), +{N} (Index: 622; Name: 'GetPathingTargetSpeedAngle'; ParamType1: ptAxis), +{N} (Index: 623; Name: 'GetMovementSpeed'), +{N} (Index: 624; Name: 'GetInContainer'; ParamType1: ptObjectReference), +{N} (Index: 625; Name: 'IsLocationLoaded'; ParamType1: ptLocation), +{N} (Index: 626; Name: 'IsLocAliasLoaded'; ParamType1: ptAlias), +{N} (Index: 627; Name: 'IsDualCasting'), +{N} (Index: 629; Name: 'GetVMQuestVariable'; ParamType1: ptQuest; ParamType2: ptVariableName), +{N} (Index: 630; Name: 'GetVMScriptVariable'; ParamType1: ptObjectReference; ParamType2: ptVariableName), +{N} (Index: 631; Name: 'IsEnteringInteractionQuick'), +{N} (Index: 632; Name: 'IsCasting'), +{N} (Index: 633; Name: 'GetFlyingState'), +{N} (Index: 635; Name: 'IsInFavorState'), +{N} (Index: 636; Name: 'HasTwoHandedWeaponEquipped'), +{N} (Index: 637; Name: 'IsExitingInstant'), +{N} (Index: 638; Name: 'IsInFriendStateWithPlayer'), +{N} (Index: 639; Name: 'GetWithinDistance'; ParamType1: ptObjectReference; ParamType2: ptFloat), +{N} (Index: 640; Name: 'GetActorValuePercent'; ParamType1: ptActorValue), +{N} (Index: 641; Name: 'IsUnique'), +{N} (Index: 642; Name: 'GetLastBumpDirection'), +{N} (Index: 644; Name: 'IsInFurnitureState'; ParamType1: ptFurnitureAnim), +{N} (Index: 645; Name: 'GetIsInjured'), +{N} (Index: 646; Name: 'GetIsCrashLandRequest'), +{N} (Index: 647; Name: 'GetIsHastyLandRequest'), +{N} (Index: 650; Name: 'IsLinkedTo'; ParamType1: ptObjectReference; ParamType2: ptKeyword), +{N} (Index: 651; Name: 'GetKeywordDataForCurrentLocation'; ParamType1: ptKeyword), +{N} (Index: 652; Name: 'GetInSharedCrimeFaction'; ParamType1: ptObjectReference), +{N} (Index: 654; Name: 'GetBribeSuccess'), +{N} (Index: 655; Name: 'GetIntimidateSuccess'), +{N} (Index: 656; Name: 'GetArrestedState'), +{N} (Index: 657; Name: 'GetArrestingActor'), +{N} (Index: 659; Name: 'EPTemperingItemIsEnchanted'), +{N} (Index: 660; Name: 'EPTemperingItemHasKeyword'; ParamType1: ptKeyword), +{N} (Index: 664; Name: 'GetReplacedItemType'; ParamType1: ptCastingSource), +{N} (Index: 672; Name: 'IsAttacking'), +{N} (Index: 673; Name: 'IsPowerAttacking'), +{N} (Index: 674; Name: 'IsLastHostileActor'), +{N} (Index: 675; Name: 'GetGraphVariableInt'; ParamType1: ptVariableName), +{N} (Index: 676; Name: 'GetCurrentShoutVariation'), +{N} (Index: 678; Name: 'ShouldAttackKill'; ParamType1: ptActor), +{N} (Index: 680; Name: 'GetActivatorHeight'), +{N} (Index: 681; Name: 'EPMagic_IsAdvanceSkill'; ParamType1: ptActorValue), +{N} (Index: 682; Name: 'WornHasKeyword'; ParamType1: ptKeyword), +{N} (Index: 683; Name: 'GetPathingCurrentSpeed'), +{N} (Index: 684; Name: 'GetPathingCurrentSpeedAngle'; ParamType1: ptAxis), +{N} (Index: 691; Name: 'EPModSkillUsage_AdvanceObjectHasKeyword'; ParamType1: ptKeyword), +{N} (Index: 692; Name: 'EPModSkillUsage_IsAdvanceAction'; ParamType1: ptAdvanceAction), +{N} (Index: 693; Name: 'EPMagic_SpellHasKeyword'; ParamType1: ptKeyword), +{N} (Index: 694; Name: 'GetNoBleedoutRecovery'), +{N} (Index: 696; Name: 'EPMagic_SpellHasSkill'; ParamType1: ptActorValue), +{N} (Index: 697; Name: 'IsAttackType'; ParamType1: ptKeyword), +{N} (Index: 698; Name: 'IsAllowedToFly'), +{N} (Index: 699; Name: 'HasMagicEffectKeyword'; ParamType1: ptKeyword), +{N} (Index: 700; Name: 'IsCommandedActor'), +{N} (Index: 701; Name: 'IsStaggered'), +{N} (Index: 702; Name: 'IsRecoiling'), +{N} (Index: 703; Name: 'IsExitingInteractionQuick'), +{N} (Index: 704; Name: 'IsPathing'), +{N} (Index: 705; Name: 'GetShouldHelp'; ParamType1: ptActor), +{N} (Index: 706; Name: 'HasBoundWeaponEquipped'; ParamType1: ptCastingSource), +{N} (Index: 707; Name: 'GetCombatTargetHasKeyword'; ParamType1: ptKeyword), +{N} (Index: 709; Name: 'GetCombatGroupMemberCount'), +{N} (Index: 710; Name: 'IsIgnoringCombat'), +{N} (Index: 711; Name: 'GetLightLevel'), +{N} (Index: 713; Name: 'SpellHasCastingPerk'; ParamType1: ptPerk), +{N} (Index: 714; Name: 'IsBeingRidden'), +{N} (Index: 715; Name: 'IsUndead'), +{N} (Index: 716; Name: 'GetRealHoursPassed'), +{N} (Index: 718; Name: 'IsUnlockedDoor'), +{N} (Index: 719; Name: 'IsHostileToActor'; ParamType1: ptActor), +{N} (Index: 720; Name: 'GetTargetHeight'; ParamType1: ptObjectReference), +{N} (Index: 721; Name: 'IsPoison'), +{N} (Index: 722; Name: 'WornApparelHasKeywordCount'; ParamType1: ptKeyword), +{N} (Index: 723; Name: 'GetItemHealthPercent'), +{N} (Index: 724; Name: 'EffectWasDualCast'), +{N} (Index: 725; Name: 'GetKnockedStateEnum'), +{N} (Index: 726; Name: 'DoesNotExist'), +{N} (Index: 730; Name: 'IsOnFlyingMount'), +{N} (Index: 731; Name: 'CanFlyHere'), +{N} (Index: 732; Name: 'IsFlyingMountPatrolQueud'), +{N} (Index: 733; Name: 'IsFlyingMountFastTravelling'), +{N} (Index: 734; Name: 'IsOverEncumbered'), +{N} (Index: 735; Name: 'GetActorWarmth'), + + // Added by SKSE + (Index: 1024; Name: 'GetSKSEVersion'; ), + (Index: 1025; Name: 'GetSKSEVersionMinor'; ), + (Index: 1026; Name: 'GetSKSEVersionBeta'; ), + (Index: 1027; Name: 'GetSKSERelease'; ), + (Index: 1028; Name: 'ClearInvalidRegistrations'; ) + ); + +var + wbCTDAFunctionEditInfo: string; + +function wbCTDAParamDescFromIndex(aIndex: Integer): PCTDAFunction; +var + L, H, I, C: Integer; +begin + Result := nil; + + L := Low(wbCTDAFunctions); + H := High(wbCTDAFunctions); + while L <= H do begin + I := (L + H) shr 1; + C := CmpW32(wbCTDAFunctions[I].Index, aIndex); + if C < 0 then + L := I + 1 + else begin + H := I - 1; + if C = 0 then begin + L := I; + Result := @wbCTDAFunctions[L]; + end; + end; + end; +end; + +function wbCTDACompValueDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container: IwbContainer; +begin + Result := 0; + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + // "use global" flag + if Integer(Container.ElementByName['Type'].NativeValue) and $04 <> 0 then + Result := 1; +end; + +function wbCTDAParam1Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Desc: PCTDAFunction; + Container: IwbContainer; + ParamFlag: Byte; + ParamType: TCTDAFunctionParamType; +begin + Result := 0; + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); + + if Assigned(Desc) then begin + ParamType := Desc.ParamType1; + ParamFlag := Container.ElementByName['Type'].NativeValue; + if ParamType in [ptObjectReference, ptActor, ptPackage] then begin + if ParamFlag and $02 > 0 then ParamType := ptAlias else {>>> 'use aliases' is set <<<} + if ParamFlag and $08 > 0 then ParamType := ptPackdata; {>>> 'use packdata' is set <<<} + end; + Result := Succ(Integer(ParamType)); + end; +end; + +function wbCTDAParam2Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Desc: PCTDAFunction; + Container: IwbContainer; + ParamFlag: Byte; + ParamType: TCTDAFunctionParamType; +begin + Result := 0; + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); + + if Assigned(Desc) then begin + ParamType := Desc.ParamType2; + ParamFlag := Container.ElementByName['Type'].NativeValue; + + if ParamType in [ptObjectReference, ptActor, ptPackage] then begin + if ParamFlag and $02 > 0 then ParamType := ptAlias else {>>> 'use aliases' is set <<<} + if ParamFlag and $08 > 0 then ParamType := ptPackdata; {>>> 'use packdata' is set <<<} + end; + + Result := Succ(Integer(ParamType)); + end; +end; + +function wbCTDAParam2VATSValueParamDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container : IwbContainer; +begin + Result := 0; + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + Result := Container.ElementByName['Parameter #1'].NativeValue; +end; + +function wbCTDAFunctionToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Desc : PCTDAFunction; + i : Integer; +begin + Result := ''; + case aType of + ctToStr, ctToSummary, ctToEditValue: begin + Desc := wbCTDAParamDescFromIndex(aInt); + if Assigned(Desc) then + Result := Desc.Name + else if aType in [ctToSummary, ctToEditValue] then + Result := aInt.ToString + else + Result := ''; + end; + ctToSortKey: Result := IntToHex(aInt, 8); + ctCheck: begin + Desc := wbCTDAParamDescFromIndex(aInt); + if Assigned(Desc) then + Result := '' + else + Result := ''; + end; + ctEditType: + Result := 'ComboBox'; + ctEditInfo: begin + Result := wbCTDAFunctionEditInfo; + if Result = '' then begin + with TStringList.Create do try + for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do + Add(wbCTDAFunctions[i].Name); + Sort; + Result := CommaText; + finally + Free; + end; + wbCTDAFunctionEditInfo := Result; + end; + end; + end; +end; + +function wbCTDAFunctionToInt(const aString: string; const aElement: IwbElement): Int64; +var + i: Integer; +begin + for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do + with wbCTDAFunctions[i] do + if SameText(Name, aString) then begin + Result := Index; + Exit; + end; + + Result := StrToInt64(aString); +end; + +function wbCTDAParam1StringToInt(const aString: string; const aElement: IwbElement): Int64; +var + Container : IwbContainerElementRef; +begin + Result := 0; + + if not Assigned(aElement) then + Exit; + + Container := GetContainerFromUnion(aElement) as IwbContainerElementRef; + if not Assigned(Container) then + Exit; + + Container.ElementEditValues['..\CIS1'] := aString +end; + +function wbCTDAParam1StringToString(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Container : IwbContainerElementRef; +begin + case aType of + ctToStr, ctToSummary, ctToSortKey, ctToEditValue, ctToNativeValue: begin + Result := ''; + + if not Assigned(aElement) then + Exit; + + Container := GetContainerFromUnion(aElement) as IwbContainerElementRef; + if not Assigned(Container) then + Exit; + + case aType of + ctToSummary: + Result := Container.ElementSummaries['..\CIS1']; + ctToEditValue, ctToNativeValue: + Result := Container.ElementEditValues['..\CIS1']; + else + Result := Container.ElementValues['..\CIS1']; + end; + end; + ctCheck, ctEditType, ctEditInfo, ctLinksTo: + Result := ''; + else + Result := aInt.ToString; + end; +end; + +function wbCTDAParam2StringToInt(const aString: string; const aElement: IwbElement): Int64; +var + Container : IwbContainerElementRef; +begin + Result := 0; + + if not Assigned(aElement) then + Exit; + + Container := GetContainerFromUnion(aElement) as IwbContainerElementRef; + if not Assigned(Container) then + Exit; + + Container.ElementEditValues['..\CIS2'] := aString +end; + +function wbCTDAParam2StringToString(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; +var + Container : IwbContainerElementRef; +begin + case aType of + ctToStr, ctToSummary, ctToSortKey, ctToEditValue, ctToNativeValue: begin + Result := ''; + + if not Assigned(aElement) then + Exit; + + Container := GetContainerFromUnion(aElement) as IwbContainerElementRef; + if not Assigned(Container) then + Exit; + + case aType of + ctToSummary: + Result := Container.ElementSummaries['..\CIS2']; + ctToEditValue, ctToNativeValue: + Result := Container.ElementEditValues['..\CIS2']; + else + Result := Container.ElementValues['..\CIS2']; + end; + end; + ctCheck, ctEditType, ctEditInfo, ctLinksTo: + Result := ''; + else + Result := aInt.ToString; + end; +end; + +function wbMESGTNAMDontShow(const aElement: IwbElement): Boolean; +var + Container : IwbContainerElementRef; + MainRecord : IwbMainRecord; +begin + Result := False; + if not Supports(aElement, IwbMainRecord, MainRecord) then + Exit; + + if not Supports(aElement, IwbContainerElementRef, Container) then + Exit; + + if Integer(Container.ElementNativeValues['DNAM']) and 1 <> 0 then + Result := True; +end; + +function wbEPFDDontShow(const aElement: IwbElement): Boolean; +var + Container: IwbContainerElementRef; +begin + Result := False; + if aElement.Name <> 'Entry Point Function Parameters' then + Exit; + + if not Supports(aElement, IwbContainerElementRef, Container) then + Exit; + + if not (Integer(Container.ElementNativeValues['EPFT']) in [1..3]) then + Result := True; +end; + +function wbTES4ONAMDontShow(const aElement: IwbElement): Boolean; +var + MainRecord : IwbMainRecord; +begin + Result := False; + if not Assigned(aElement) then + Exit; + + MainRecord := aElement.ContainingMainRecord; + if not Assigned(MainRecord) then + Exit; + + if not MainRecord.IsESM then + Result := True; +end; + +function wbEPF2DontShow(const aElement: IwbElement): Boolean; +var + Container: IwbContainerElementRef; +begin + Result := False; + if aElement.Name <> 'Entry Point Function Parameters' then + Exit; + + if not Supports(aElement, IwbContainerElementRef, Container) then + Exit; + + if not (Integer(Container.ElementNativeValues['EPFT']) in [4]) then + Result := True; +end; + +procedure wbRemoveOFST(const aElement: IwbElement); +var + Container: IwbContainer; + rOFST: IwbRecord; +begin + if not wbRemoveOffsetData then + Exit; + + if not Supports(aElement, IwbContainer, Container) then + Exit; + + if wbBeginInternalEdit then try + Container.RemoveElement(OFST); + finally + wbEndInternalEdit; + end else begin + rOFST := Container.RecordBySignature[OFST]; + if Assigned(rOFST) then + Container.RemoveElement(rOFST); + end; +end; + +procedure wbWRLDAfterLoad(const aElement: IwbElement); + function OutOfRange(aValue: Integer; aRange: Integer = 256): Boolean; + begin + Result := (aValue < -aRange) or (aValue > aRange); + end; +var + MainRecord: IwbMainRecord; + Container: IwbContainer; +begin + if wbBeginInternalEdit then try + + if not Supports(aElement, IwbMainRecord, MainRecord) then + Exit; + + // not used in Skyrim + if MainRecord.ElementExists['Unused RNAM'] then + MainRecord.RemoveElement('Unused RNAM'); + + // used in SSE but remove from the game master to speed up worldspace browsing since it is huge + // and the game master is never saved anyway + if IsSSE and (MainRecord._File.LoadOrder = 0) then + MainRecord.RemoveElement('Large References'); + + // large values in object bounds cause stutter and performance issues in game (reported by Arthmoor) + // CK can occasionally set them wrong, so make a warning + if Supports(MainRecord.ElementByName['Object Bounds'], IwbContainer, Container) then + if OutOfRange(StrToIntDef(Container.ElementEditValues['NAM0\X'], 0)) or + OutOfRange(StrToIntDef(Container.ElementEditValues['NAM0\Y'], 0)) or + OutOfRange(StrToIntDef(Container.ElementEditValues['NAM9\X'], 0)) or + OutOfRange(StrToIntDef(Container.ElementEditValues['NAM9\Y'], 0)) + then + wbProgressCallback(''); + finally + wbEndInternalEdit; + end; +end; + +procedure wbDOBJObjectsAfterLoad(const aElement: IwbElement); +var + ObjectsContainer : IwbContainerElementRef; + i : Integer; + ObjectContainer : IwbContainerElementRef; +begin + wbRemoveOFST(aElement); + + if wbBeginInternalEdit then try + + if not Supports(aElement, IwbContainerElementRef, ObjectsContainer) then + Exit; + + for i := Pred(ObjectsContainer.ElementCount) downto 0 do + if Supports(ObjectsContainer.Elements[i], IwbContainerElementRef, ObjectContainer) then + if ObjectContainer.ElementNativeValues['Use'] = 0 then + ObjectsContainer.RemoveElement(i, True); + finally + wbEndInternalEdit; + end; +end; + +function wbActorTemplateUseTraits(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Template Flags']; + Result := (i and $00000001) <> 0; +end; + +function wbActorTemplateUseStats(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Template Flags']; + Result := (i and $00000002) <> 0; +end; + +function wbActorAutoCalcDontShow(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Flags']; + Result := (i and $00000010) <> 0; +end; + +function wbActorTemplateUseStatsAutoCalc(const aElement: IwbElement): Boolean; +begin + Result := wbActorTemplateUseStats(aElement) or wbActorAutoCalcDontShow(aElement); +end; + +function wbActorTemplateUseFactions(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Template Flags']; + Result := (i and $00000004) <> 0; +end; + +function wbActorTemplateUseActorEffectList(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Template Flags']; + Result := (i and $00000008) <> 0; +end; + +function wbActorTemplateUseAIData(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Template Flags']; + Result := (i and $00000010) <> 0; +end; + +function wbActorTemplateUseAIPackages(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Template Flags']; + Result := (i and $00000020) <> 0; +end; + +function wbActorTemplateUseModelAnimation(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Template Flags']; + Result := (i and $00000040) <> 0; +end; + +function wbActorTemplateUseBaseData(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Template Flags']; + Result := (i and $00000080) <> 0; +end; + +function wbActorTemplateUseInventory(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Template Flags']; + Result := (i and $00000100) <> 0; +end; + +function wbActorTemplateUseScript(const aElement: IwbElement): Boolean; +var + Element : IwbElement; + MainRecord : IwbMainRecord; + i : Int64; +begin + Result := False; + Element := aElement; + MainRecord := nil; + + while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do + Element := Element.Container; + + if not Assigned(MainRecord) then + Exit; + + i := MainRecord.ElementNativeValues['ACBS\Template Flags']; + Result := (i and $00000200) <> 0; +end; + +procedure wbRemoveEmptyKWDA(const aElement: IwbElement); +var + Container : IwbContainerElementRef; + MainRecord : IwbMainRecord; +begin + if wbBeginInternalEdit then try + if not wbTryGetContainerWithValidMainRecord(aElement, Container, MainRecord) then + Exit; + + if Assigned(Container.ElementBySignature['KSIZ']) then + Exit; + + if Assigned(Container.ElementBySignature['KWDA']) then + Container.ElementBySignature['KWDA'].Remove; + finally + wbEndInternalEdit; + end; +end; + +procedure wbReplaceBODTwithBOD2(const aElement: IwbElement); +var + MainRecord : IwbMainRecord; + ContainerBOD2 : IwbContainerElementRef; + ContainerBODT : IwbContainerElementRef; +begin + Exit; {>>> Looks like causes problems with Dawnguard.esm <<<} + + if wbBeginInternalEdit then try + if not Supports(aElement, IwbMainRecord, MainRecord) then + Exit; + + if not Supports(MainRecord.ElementBySignature[BODT], IwbContainerElementRef, ContainerBODT) then + Exit; + + if not Supports(MainRecord.Add('BOD2', True), IwbContainerElementRef, ContainerBOD2) then + Exit; + + ContainerBOD2.ElementNativeValues['First Person Flags'] := ContainerBODT.ElementNativeValues['First Person Flags']; + ContainerBOD2.ElementNativeValues['Armor Type'] := ContainerBODT.ElementNativeValues['Armor Type']; + MainRecord.RemoveElement(BODT); + finally + wbEndInternalEdit; + end; +end; + +procedure wbARMOAfterLoad(const aElement: IwbElement); +begin + wbRemoveEmptyKWDA(aElement); + wbReplaceBODTwithBOD2(aElement); +end; + +procedure wbARMAAfterLoad(const aElement: IwbElement); +{var + MainRecord : IwbMainRecord;} +begin + wbReplaceBODTwithBOD2(aElement); + {if wbBeginInternalEdit then try + if not Supports(aElement, IwbMainRecord, MainRecord) then + Exit; + if MainRecord.ElementNativeValues['DNAM\Weight slider - Male'] = 0 then + MainRecord.ElementNativeValues['DNAM\Weight slider - Male'] := 2; + if MainRecord.ElementNativeValues['DNAM\Weight slider - Female'] = 0 then + MainRecord.ElementNativeValues['DNAM\Weight slider - Female'] := 2; + finally + wbEndInternalEdit; + end;} +end; + +procedure wbNPCAfterLoad(const aElement: IwbElement); +begin + wbRemoveEmptyKWDA(aElement); +end; + +procedure wbREFRAfterLoad(const aElement: IwbElement); +var + Container : IwbContainerElementRef; + MainRecord : IwbMainRecord; +begin + if wbBeginInternalEdit then try + if not wbTryGetContainerWithValidMainRecord(aElement, Container, MainRecord) then + Exit; + + if not Container.ElementExists['XLOC'] then + Exit; + + if Container.ElementNativeValues['XLOC - Lock Data\Level'] = 0 then + Container.ElementNativeValues['XLOC - Lock Data\Level'] := 1; + + Container.RemoveElement('XPTL'); + finally + wbEndInternalEdit; + end; +end; + +procedure wbRACEAfterLoad(const aElement: IwbElement); +begin + wbReplaceBODTwithBOD2(aElement); +end; + +procedure wbWEAPAfterLoad(const aElement: IwbElement); +var + Container : IwbContainerElementRef; + MainRecord : IwbMainRecord; + Flags : Cardinal; +begin + wbRemoveEmptyKWDA(aElement); + + if wbBeginInternalEdit then try + if not Supports(aElement, IwbContainerElementRef, Container) then + Exit; + + if Container.ElementCount < 1 then + Exit; + + if not Supports(aElement, IwbMainRecord, MainRecord) then + Exit; + + if MainRecord.IsDeleted then + Exit; + + // clear IronSights flags which are randomly assigned in CK + if not Container.ElementExists['DNAM'] then + Exit; + + Flags := Container.ElementNativeValues['DNAM - Data\Flags']; + Flags := Flags and ($FFFF xor $0040); + Container.ElementNativeValues['DNAM - Data\Flags'] := Flags; + + Flags := Container.ElementNativeValues['DNAM - Data\Flags2']; + Flags := Flags and ($FFFFFFFF xor $0100); + Container.ElementNativeValues['DNAM - Data\Flags2'] := Flags; + + finally + wbEndInternalEdit; + end; +end; + +procedure wbCELLXCLWGetConflictPriority(const aElement: IwbElement; var aCP: TwbConflictPriority); +var + Container : IwbContainerElementRef; + MainRecord : IwbMainRecord; + DataRec : IwbElement; + Flags : Cardinal; +begin + if not Assigned(aElement) then + Exit; + + if not Supports(aElement.Container, IwbContainerElementRef, Container) then + Exit; + + if Container.ElementCount < 1 then + Exit; + + if not Supports(Container, IwbMainRecord, MainRecord) then + Exit; + + if MainRecord.IsDeleted then + Exit; + + DataRec := MainRecord.ElementBySignature[DATA]; + + if not Assigned(DataRec) then + Exit; + + Flags := DataRec.NativeValue; + + {0x0001 Is Interior Cell} + if (Flags and 1) = 1 then + {Interior cells don't use water level in Skyrim at all} + aCP := cpIgnore; +end; + +procedure wbCELLDATAAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + Container : IwbContainer; +begin + if not Assigned(aElement) then + Exit; + + Container := aElement.Container; + + while Assigned(Container) and not (Container.Def.DefType = dtRecord) do + Container := Container.Container; + + if Assigned(Container) then + Container.ResetConflict; +end; + +procedure wbCELLAfterLoad(const aElement: IwbElement); +var + Container : IwbContainerElementRef; +// Container2 : IwbContainerElementRef; + MainRecord : IwbMainRecord; + DataSubRec : IwbSubrecord; + Flags : Byte; +begin + if wbBeginInternalEdit then try + if not wbTryGetContainerWithValidMainRecord(aElement, Container, MainRecord) then + Exit; + + if Supports(Container.ElementBySignature['DATA'] , IwbSubRecord, DataSubRec) then begin + // expand legacy itU8 flags to itU16 + if DataSubRec.SubRecordHeaderSize = 1 then begin + Flags := PByte(DataSubRec.DataBasePtr)^; + DataSubRec.SetToDefault; + DataSubRec.NativeValue := Flags; + end; + // 'Default' water height for exterior cells if not set (so water height will be taken from WRLD by game) + if (not Container.ElementExists['XCLW']) and ((Integer(DataSubRec.NativeValue) and $02) <> 0) then begin + Container.Add('XCLW', True); + Container.ElementEditValues['XCLW'] := 'Default'; + end; + end; + + // Min (-0 as in CK) water height is set to 0 when saving in CK + if Container.ElementEditValues['XCLW'] = 'Min' then + Container.ElementEditValues['XCLW'] := '0.0'; + +// if Supports(Container.ElementBySignature[XCLR], IwbContainerElementRef, Container2) then begin +// for i := Pred(Container2.ElementCount) downto 0 do +// if not Supports(Container2.Elements[i].LinksTo, IwbMainRecord, MainRecord) or (MainRecord.Signature <> 'REGN') then +// Container2.RemoveElement(i); +// if Container2.ElementCount < 1 then +// Container2.Remove; +// end; + finally + wbEndInternalEdit; + end; +end; + +procedure wbMESGAfterLoad(const aElement: IwbElement); +var + Container : IwbContainerElementRef; + MainRecord : IwbMainRecord; + IsMessageBox : Boolean; + HasTimeDelay : Boolean; +begin + if wbBeginInternalEdit then try + if not wbTryGetContainerWithValidMainRecord(aElement, Container, MainRecord) then + Exit; + + IsMessageBox := (Integer(Container.ElementNativeValues['DNAM']) and 1) = 1; + HasTimeDelay := Container.ElementExists['TNAM']; + + if not (IsMessageBox = HasTimeDelay) then + Exit; + + if IsMessageBox then + Container.RemoveElement('TNAM') + else begin + if not Container.ElementExists['DNAM'] then + Container.Add('DNAM', True); + Container.ElementNativeValues['DNAM'] := Integer(Container.ElementNativeValues['DNAM']) or 1; + end; + finally + wbEndInternalEdit; + end; +end; + + +{>>> + Updated, but not called for Skyrim + Why is it required to fix particle counts? Because 1 pass = 79 particles? +>>>} +//procedure wbEFSHAfterLoad(const aElement: IwbElement); +//var +// Container: IwbContainerElementRef; +// MainRecord : IwbMainRecord; +// FullParticleBirthRatio : Extended; +// PersistantParticleCount : Extended; +//begin +// if wbBeginInternalEdit then try +// if not Supports(aElement, IwbContainerElementRef, Container) then +// Exit; +// +// if Container.ElementCount < 1 then +// Exit; +// +// if not Supports(aElement, IwbMainRecord, MainRecord) then +// Exit; +// +// if MainRecord.IsDeleted then +// Exit; +// +// if not Container.ElementExists['DATA'] then +// Exit; +// +// FullParticleBirthRatio := Container.ElementNativeValues['DATA\Particle Shader - Full Particle Birth Ratio']; +// PersistantParticleCount := Container.ElementNativeValues['DATA\Particle Shader - Persistant Particle Count']; +// +// if ((FullParticleBirthRatio <> 0) and (FullParticleBirthRatio <= 1)) then begin +// FullParticleBirthRatio := FullParticleBirthRatio * 78.0; +// Container.ElementNativeValues['DATA\Particle Shader - Full Particle Birth Ratio'] := FullParticleBirthRatio; +// end; +// +// if ((PersistantParticleCount <> 0) and (PersistantParticleCount <= 1)) then begin +// PersistantParticleCount := PersistantParticleCount * 78.0; +// Container.ElementNativeValues['DATA\Particle Shader - Persistant Particle Count'] := PersistantParticleCount; +// end; +// +// finally +// wbEndInternalEdit; +// end; +//end; + +procedure wbLIGHAfterLoad(const aElement: IwbElement); +var + Container: IwbContainerElementRef; + MainRecord: IwbMainRecord; +begin + if wbBeginInternalEdit then try + if not wbTryGetContainerWithValidMainRecord(aElement, Container, MainRecord) then + Exit; + + if not Container.ElementExists['FNAM'] then begin + Container.Add('FNAM', True); + Container.ElementNativeValues['FNAM'] := 1.0; + end; + + if not Container.ElementExists['DATA'] then + Exit; + + if SameValue(Container.ElementNativeValues['DATA\Falloff Exponent'], 0.0) then + Container.ElementNativeValues['DATA\Falloff Exponent'] := 1.0; + + if SameValue(Container.ElementNativeValues['DATA\FOV'], 0.0) then + Container.ElementNativeValues['DATA\FOV'] := 90.0; + finally + wbEndInternalEdit; + end; +end; + +procedure wbEFITAfterLoad(const aElement: IwbElement); +var + Container : IwbContainerElementRef; + Element : IwbElement; + ActorValue: Variant; + MainRecord: IwbMainRecord; +begin + if wbBeginInternalEdit then try + if not Supports(aElement, IwbContainerElementRef, Container) then + Exit; + + if Container.ElementCount < 1 then + Exit; + + MainRecord := Container.ContainingMainRecord; + if not Assigned(MainRecord) or MainRecord.IsDeleted then + Exit; + + Element := Container.ElementByPath['..\EFID']; + if not wbTryGetMainRecord(Element, MainRecord, 'MGEF') then + Exit; + + ActorValue := MainRecord.ElementNativeValues['DATA - Data\Actor Value']; + if VarIsNull(ActorValue) or VarIsClear(ActorValue) then + Exit; + + if VarCompareValue(ActorValue, Container.ElementNativeValues['Actor Value']) <> vrEqual then + Container.ElementNativeValues['Actor Value'] := ActorValue; + finally + wbEndInternalEdit; + end; +end; + +procedure wbRPLDAfterLoad(const aElement: IwbElement); +var + Container: IwbContainer; + a, b: Single; + NeedsFlip: Boolean; +begin + if wbBeginInternalEdit then try + if not Supports(aElement, IwbContainer, Container) then + Exit; + + NeedsFlip := False; + + if Container.ElementCount > 1 then begin + a := StrToFloat((Container.Elements[0] as IwbContainer).Elements[0].Value); + b := StrToFloat((Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[0].Value); + + case CompareValue(a, b) of + EqualsValue: begin + a := StrToFloat((Container.Elements[0] as IwbContainer).Elements[1].Value); + b := StrToFloat((Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[1].Value); + NeedsFlip := CompareValue(a, b) = GreaterThanValue; + end; + GreaterThanValue: + NeedsFlip := True; + end; + end; + + if NeedsFlip then + Container.ReverseElements; + finally + wbEndInternalEdit; + end; +end; + +function wbPubPackCNAMDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + rANAM: IwbRecord; + ctype: string; +begin + Result := 0; + + rANAM := aElement.Container.RecordBySignature[ANAM]; + if not Assigned(rANAM) then + Exit; + + ctype := rANAM.NativeValue; + if ctype = 'Bool' then Result := 1 else + if ctype = 'Int' then Result := 2 else + if ctype = 'Float' then Result := 3 else + if ctype = 'ObjectList' then Result := 3; +end; + +function wbTypeDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; +var + Container : IwbContainer; + Element : IwbElement; +begin + Result := 0; + + if not wbTryGetContainerFromUnion(aElement, Container) then + Exit; + + Element := Container.ElementByName['Type']; + + if Assigned(Element) then + Result := Element.NativeValue + else if wbMoreInfoForDecider then + wbProgressCallback('"'+Container.Name+'" does not contain an element named Type'); +end; + +procedure wbIDLAsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + Element : IwbElement; + Container : IwbContainer; + SelfAsContainer : IwbContainer; +begin + if wbBeginInternalEdit(True) then try + if wbCounterAfterSet('IDLC - Animation Count', aElement) then + Exit; + + if not Supports(aElement.Container, IwbContainer, Container) then + Exit; + + Element := Container.ElementByPath['IDLC\Animation Count']; + if Assigned(Element) and Supports(aElement, IwbContainer, SelfAsContainer) and + (Element.GetNativeValue<>SelfAsContainer.GetElementCount) then + Element.SetNativeValue(SelfAsContainer.GetElementCount); + finally + wbEndInternalEdit; + end; +end; + +procedure wbAnimationsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + Element : IwbElement; + Elems : IwbElement; + Container : IwbContainer; +begin + if wbBeginInternalEdit(True) then try + if wbCounterContainerAfterSet('IDLC - Animation Count', 'IDLA - Animations', aElement) then + Exit; + + if not Supports(aElement, IwbContainer, Container) then + Exit; + + Element := Container.ElementByPath['IDLC\Animation Count']; + Elems := Container.ElementByName['IDLA - Animations']; + + if Assigned(Element) and not Assigned(Elems) then + if Element.GetNativeValue <> 0 then + Element.SetNativeValue(0); + finally + wbEndInternalEdit; + end; +end; + +procedure wbPackageDataInputValueTypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); +var + Container : IwbContainerElementRef; + Value : IwbElement; +begin + if aOldValue <> aNewValue then + if Supports(aElement.Container, IwbContainerElementRef, Container) then begin + Value := Container.ElementByPath['CNAM']; + if Assigned(Value) then + if (aNewValue = 'Bool') or (aNewValue = 'Int') or (aNewValue = 'Float') or (aNewValue = 'ObjectList') then + Value.SetToDefault + else + Value.Remove + else + if (aNewValue = 'Bool') or (aNewValue = 'Int') or (aNewValue = 'Float') or (aNewValue = 'ObjectList') then + Container.Add('CNAM'); + end; +end; + +function wbREFRRecordFlagsDecider(const aElement: IwbElement): Integer; +var + MainRecord : IwbMainRecord; + NameRec : IwbElement; +begin + Result := 0; + + if not wbTryGetContainingMainRecord(aElement, MainRecord) then + Exit; + + NameRec := MainRecord.ElementBySignature[NAME]; + if not wbTryGetMainRecord(NameRec, MainRecord) then + Exit; + + if (MainRecord.Signature = ACTI) or + (MainRecord.Signature = STAT) or + (MainRecord.Signature = TREE) or + (MainRecord.Signature = FLOR) + then + Result := 1 + else if MainRecord.Signature = CONT then + Result := 2 + else if MainRecord.Signature = DOOR then + Result := 3 + else if MainRecord.Signature = LIGH then + Result := 4 + else if MainRecord.Signature = MSTT then + Result := 5 + else if MainRecord.Signature = ADDN then + Result := 6 + else if + (MainRecord.Signature = SCRL) or + (MainRecord.Signature = AMMO) or + (MainRecord.Signature = ARMO) or + (MainRecord.Signature = BOOK) or + (MainRecord.Signature = INGR) or + (MainRecord.Signature = KEYM) or + (MainRecord.Signature = MISC) or + (MainRecord.Signature = SLGM) or + (MainRecord.Signature = WEAP) or + (MainRecord.Signature = ALCH) + then + Result := 7; +end; + +function wbByteColors(const aName: string = 'Color'): IwbValueDef; +begin + Result := wbStruct(aName, [ + wbInteger('Red', itU8), + wbInteger('Green', itU8), + wbInteger('Blue', itU8), + wbByteArray('Unused', 1) + ]).SetToStr(wbRGBAToStr).IncludeFlag(dfCollapsed, wbCollapseRGBA); +end; + +function wbFloatColors(const aName: string = 'Color'): IwbValueDef; +begin + Result := wbStruct(aName, [ + wbFloat('Red', cpNormal, True, 255, 0), + wbFloat('Green', cpNormal, True, 255, 0), + wbFloat('Blue', cpNormal, True, 255, 0) + ]).SetToStr(wbRGBAToStr).IncludeFlag(dfCollapsed, wbCollapseRGBA); +end; + +function wbWeatherColors(const aName: string): IwbStructDef; +begin + Result := wbStruct(aName, [ + wbByteColors('Sunrise'), + wbByteColors('Day'), + wbByteColors('Sunset'), + wbByteColors('Night') + ], cpNormal, True); +end; + +function wbAmbientColors(const aSignature: TwbSignature; const aName: string = 'Directional Ambient Lighting Colors'): IwbSubRecordDef; overload; +begin + Result := wbStruct(aSignature, aName, [ + wbStruct('Directional', [ + wbByteColors('X+'), + wbByteColors('X-'), + wbByteColors('Y+'), + wbByteColors('Y-'), + wbByteColors('Z+'), + wbByteColors('Z-') + ]), + wbByteColors('Specular'), + wbFloat('Scale') + ], cpNormal, False, nil, 1) +end; + +function wbAmbientColors(const aName: string = 'Directional Ambient Lighting Colors'): IwbStructDef; overload; +begin + Result := wbStruct(aName, [ + wbStruct('Directional', [ + wbByteColors('X+'), + wbByteColors('X-'), + wbByteColors('Y+'), + wbByteColors('Y-'), + wbByteColors('Z+'), + wbByteColors('Z-') + ]), + wbByteColors('Specular'), + wbFloat('Scale', cpIgnore) + ], cpNormal, False, nil, 1); +end; + +type + TFaceGenFeature = record + RaceID : String; + Female : Boolean; + Entries : array of record + Index: Cardinal; + Name : String; + end; + end; + PFaceGenFeature = ^TFaceGenFeature; + +var + // cache of race specific tint layers + TintLayers: array of TFaceGenFeature; + +function wbTintLayerToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; + + function GetCached(const aRaceID: string; aFemale: boolean): PFaceGenFeature; + var + i: integer; + begin + Result := nil; + if Length(TintLayers) <> 0 then + for i := Low(TintLayers) to High(TintLayers) do + if (TintLayers[i].Female = aFemale) and (TintLayers[i].RaceID = aRaceID) then begin + Result := @TintLayers[i]; + Break; + end; + end; + +var + Actor, Race : IwbMainRecord; + Element : IwbElement; + Container, Entry : IwbContainerElementRef; + Female, Female2 : Boolean; + RaceID, EntryName : string; + s : string; + Cache : PFaceGenFeature; + Index : Cardinal; + i, j : integer; +begin + // defaults + case aType of + ctToStr, ctToSummary, ctToEditValue: Result := aInt.ToString; + ctToSortKey: begin + Result := IntToHex64(aInt, 8); + Exit; + end; + ctCheck: Result := ''; + ctEditType: Result := ''; + ctEditInfo: Result := ''; + end; + + Actor := aElement.ContainingMainRecord; + if not Assigned(Actor) then + Exit; + + Female := Actor.ElementEditValues['ACBS\Flags\Female'] = '1'; + + Element := Actor.ElementBySignature['RNAM']; + if not Assigned(Element) then + Exit; + + Element := Element.LinksTo; + if not Supports(Element, IwbMainRecord, Race) then + Exit; + + Race := Race.WinningOverride; + RaceID := Race.EditorID; + + Cache := GetCached(RaceID, Female); + + // cache not found, fill with data from RACE + if not Assigned(Cache) then begin + + for i := 0 to 1 do begin + + Female2 := i = 1; + SetLength(TintLayers, Succ(Length(TintLayers))); + Cache := @TintLayers[Pred(Length(TintLayers))]; + Cache.RaceID := RaceID; + Cache.Female := Female2; + + if not Female2 then + Element := Race.ElementByPath['Head Data\Male Head Data\Tint Masks'] + else + Element := Race.ElementByPath['Head Data\Female Head Data\Tint Masks']; + + if not Supports(Element, IwbContainerElementRef, Container) then + Continue; + + SetLength(Cache.Entries, Container.ElementCount); + + for j := 0 to Pred(Container.ElementCount) do begin + // should never be false + if not Supports(Container.Elements[j], IwbContainerElementRef, Entry) then + Continue; + Cache.Entries[j].Index := Entry.ElementNativeValues['Tint Layer\Texture\TINI']; + s := Entry.ElementEditValues['Tint Layer\Texture\TINP']; + // add texture name + if s <> '' then + s := '[' + s + '] '; + s := s + ChangeFileExt(ExtractFileName(Entry.ElementEditValues['Tint Layer\Texture\TINT']), ''); + Cache.Entries[j].Name := s; + end; + end; + + Cache := GetCached(RaceID, Female); + end; + + if not Assigned(Cache) then + Exit; + + EntryName := ''; + Index := Cardinal(aInt); + if Length(Cache.Entries) <> 0 then + for i := Low(Cache.Entries) to High(Cache.Entries) do + if Cache.Entries[i].Index = Index then begin + EntryName := Cache.Entries[i].Name; + Break; + end; + + case aType of + ctToStr, ctToSummary: begin + if EntryName <> '' then + Result := aInt.ToString + ' ' + EntryName + else begin + Result := aInt.ToString; + if aType = ctToStr then + Result := Result + ' '; + end; + end; + ctCheck: begin + if EntryName = '' then + Result := '' + else + Result := ''; + end; + ctEditType: Result := 'ComboBox'; + ctEditInfo: begin + Result := ''; + if Length(Cache.Entries) <> 0 then + for i := Low(Cache.Entries) to High(Cache.Entries) do begin + if Result <> '' then Result := Result + ','; + Result := Result + '"' + IntToStr(Cache.Entries[i].Index) + ' ' + Cache.Entries[i].Name + '"'; + end; + end; + end; +end; + + +var + wbRecordFlagsFlags, wbEmptyBaseFlags : IwbFlagsDef; + +procedure DefineTES5a; + +begin + wbNull := wbByteArray('Unused', -255); + wbLLCT := wbInteger(LLCT, 'Count', itU8, nil, cpBenign); + wbCITC := wbInteger(CITC, 'Condition Count', itU32, nil, cpBenign); + wbCITCReq := wbInteger( CITC, 'Condition Count', itU32, nil, cpBenign, True); + wbLVLD := wbInteger(LVLD, 'Chance None', itU8, nil, cpNormal, True); + + wbSPCT := wbInteger(SPCT, 'Count', itU32, nil, cpBenign); + wbSPLO := wbFormIDCk(SPLO, 'Actor Effect', [SPEL, SHOU, LVSP]); + wbSPLOs := wbRArrayS('Actor Effects', wbSPLO, cpNormal, False, nil, wbSPLOsAfterSet, nil{wbActorTemplateUseActorEffectList}); + + wbKSIZ := wbInteger(KSIZ, 'Keyword Count', itU32, nil, cpBenign); + wbKWDAs := wbArrayS(KWDA, 'Keywords', wbFormIDCk('Keyword', [KYWD, NULL]), 0, cpNormal, False, nil, wbKWDAsAfterSet); + wbReqKWDAs := wbArrayS(KWDA, 'Keywords', wbFormIDCk('Keyword', [KYWD, NULL]), 0, cpNormal, True, nil, wbKWDAsAfterSet); + + wbKeywords := wbRStruct('Keywords', [ + wbKSIZ, + wbReqKWDAs + ], []); + + wbCOED := wbStructExSK(COED, [2], [0, 1], 'Extra Data', [ + {00} wbFormIDCkNoReach('Owner', [NPC_, FACT, NULL]), + {04} wbUnion('Global Variable / Required Rank', wbCOEDOwnerDecider, [ + wbByteArray('Unused', 4, cpIgnore), + wbFormIDCk('Global Variable', [GLOB, NULL]), + wbInteger('Required Rank', itS32) + ]), + {08} wbFloat('Item Condition') + ]); + + wbCNTO := + wbRStructExSK([0], [1], 'Item', [ + wbStructExSK(CNTO, [0], [1], 'Item', [ + wbFormIDCk('Item', [ARMO, AMMO, APPA, MISC, WEAP, BOOK, LVLI, KEYM, ALCH, INGR, LIGH, SLGM, SCRL]), + wbInteger('Count', itS32) + ]), + wbCOED + ], []).SetToStr(wbItemToStr).IncludeFlag(dfCollapsed, wbCollapseItems); + wbCOCT := wbInteger(COCT, 'Count', itU32, nil, cpBenign); + wbCNTOs := wbRArrayS('Items', wbCNTO, cpNormal, False, nil, wbCNTOsAfterSet); + + wbCNTONoReach := + wbRStructExSK([0], [1], 'Item', [ + wbStructExSK(CNTO, [0], [1], 'Item', [ + wbFormIDCkNoReach('Item', [ARMO, AMMO, APPA, MISC, WEAP, BOOK, LVLI, KEYM, ALCH, INGR, LIGH, SLGM, SCRL]), + wbInteger('Count', itS32) + ]), + wbCOED + ], []).SetToStr(wbItemToStr).IncludeFlag(dfCollapsed, wbCollapseItems); + wbCNTOsNoReach := wbRArrayS('Items', wbCNTONoReach, cpNormal, False, nil, wbCNTOsAfterSet); + + wbArmorTypeEnum := wbEnum([ + 'Light Armor', + 'Heavy Armor', + 'Clothing' + ]); + + {>>> When NAME is user defined these will be incorrect <<<} + wbBipedObjectEnum := wbEnum([ + '30 - Head', + '31 - Hair', + '32 - Body', + '33 - Hands', + '34 - Forearms', + '35 - Amulet', + '36 - Ring', + '37 - Feet', + '38 - Calves', + '39 - Shield', + '40 - Tail', + '41 - LongHair', + '42 - Circlet', + '43 - Ears', + '44 - Unnamed', + '45 - Unnamed', + '46 - Unnamed', + '47 - Unnamed', + '48 - Unnamed', + '49 - Unnamed', + '50 - DecapitateHead', + '51 - Decapitate', + '52 - Unnamed', + '53 - Unnamed', + '54 - Unnamed', + '55 - Unnamed', + '56 - Unnamed', + '57 - Unnamed', + '58 - Unnamed', + '59 - Unnamed', + '60 - Unnamed', + '61 - FX01' + ], [ + -1, 'None' + ]); + + wbBipedObjectFlags := wbFlags([ + {0x00000001} '30 - Head', + {0x00000002} '31 - Hair', + {0x00000004} '32 - Body', + {0x00000008} '33 - Hands', + {0x00000010} '34 - Forearms', + {0x00000020} '35 - Amulet', + {0x00000040} '36 - Ring', + {0x00000080} '37 - Feet', + {0x00000100} '38 - Calves', + {0x00000200} '39 - Shield', + {0x00000400} '40 - Tail', + {0x00000800} '41 - LongHair', + {0x00001000} '42 - Circlet', + {0x00002000} '43 - Ears', + {0x00004000} '44 - Unnamed', + {0x00008000} '45 - Unnamed', + {0x00010000} '46 - Unnamed', + {0x00020000} '47 - Unnamed', + {0x00040000} '48 - Unnamed', + {0x00080000} '49 - Unnamed', + {0x00100000} '50 - DecapitateHead', + {0x00200000} '51 - Decapitate', + {0x00400000} '52 - Unnamed', + {0x00800000} '53 - Unnamed', + {0x01000000} '54 - Unnamed', + {0x02000000} '55 - Unnamed', + {0x04000000} '56 - Unnamed', + {0x08000000} '57 - Unnamed', + {0x10000000} '58 - Unnamed', + {0x20000000} '59 - Unnamed', + {0x40000000} '60 - Unnamed', + {0x80000000} '61 - FX01' + ], True); + + wbFirstPersonFlagsU32 := wbInteger('First Person Flags', itU32, wbBipedObjectFlags); + + wbBODT := wbStruct(BODT, 'Body Template', [ + wbFirstPersonFlagsU32, + wbInteger('General Flags', itU8, wbFlags([ + {0x00000001}'(ARMA)Modulates Voice', {>>> From ARMA <<<} + {0x00000002}'Unknown 2', + {0x00000004}'Unknown 3', + {0x00000008}'Unknown 4', + {0x00000010}'(ARMO)Non-Playable', {>>> From ARMO <<<} + {0x00000020}'Unknown 6', + {0x00000040}'Unknown 7', + {0x00000080}'Unknown 8' + ], True)), + wbByteArray('Unused', 3, cpIgnore), + wbInteger('Armor Type', itU32, wbArmorTypeEnum) + ], cpNormal, False, nil, 3); + + wbBOD2 := wbStruct(BOD2, 'Biped Body Template', [ + wbFirstPersonFlagsU32, + wbInteger('Armor Type', itU32, wbArmorTypeEnum) + ], cpNormal, False) + .SetSummaryKeyOnValue([1, 0]) + .SetSummaryPrefixSuffixOnValue(0, '(', ')') + .IncludeFlagOnValue(dfSummaryMembersNoName); + + wbBODTBOD2 := + wbRUnion('Biped Body Template', [ + wbStruct(BOD2, 'Biped Body Template', [ + wbFirstPersonFlagsU32, + wbInteger('General Flags', it0, wbFlags([ + {0x00000001}'(ARMA)Modulates Voice', {>>> From ARMA <<<} + {0x00000002}'Unknown 2', + {0x00000004}'Unknown 3', + {0x00000008}'Unknown 4', + {0x00000010}'(ARMO)Non-Playable', {>>> From ARMO <<<} + {0x00000020}'Unknown 6', + {0x00000040}'Unknown 7', + {0x00000080}'Unknown 8' + ], True)), + wbUnused, + wbInteger('Armor Type', itU32, wbArmorTypeEnum) + ], cpNormal, True) + .SetSummaryKeyOnValue([3, 0]) + .SetSummaryPrefixSuffixOnValue(0, '(', ')') + .IncludeFlagOnValue(dfSummaryMembersNoName), + wbStruct(BODT, 'Body Template', [ + wbFirstPersonFlagsU32, + wbInteger('General Flags', itU8, wbFlags([ + {0x00000001}'(ARMA)Modulates Voice', {>>> From ARMA <<<} + {0x00000002}'Unknown 2', + {0x00000004}'Unknown 3', + {0x00000008}'Unknown 4', + {0x00000010}'(ARMO)Non-Playable', {>>> From ARMO <<<} + {0x00000020}'Unknown 6', + {0x00000040}'Unknown 7', + {0x00000080}'Unknown 8' + ], True)), + wbByteArray('Unused', 3, cpIgnore), + wbInteger('Armor Type', itU32, wbArmorTypeEnum) + ], cpNormal, True, nil, 3) + .SetSummaryKeyOnValue([3, 0]) + .SetSummaryPrefixSuffixOnValue(0, '(', ')') + .IncludeFlagOnValue(dfSummaryMembersNoName) + ], []).SetRequired; + + wbDODT := wbStruct(DODT, 'Decal Data', [ + wbFloat('Min Width'), + wbFloat('Max Width'), + wbFloat('Min Height'), + wbFloat('Max Height'), + wbFloat('Depth'), + wbFloat('Shininess'), + wbStruct('Parallax', [ + wbFloat('Scale'), + wbInteger('Passes', itU8) {>>> This can't be higher than 30 <<<} + ]), + wbInteger('Flags', itU8, wbFlags([ + {0x01}'Parallax', + {0x02}'Alpha - Blending', + {0x04}'Alpha - Testing', + {0x08}'No Subtextures' + ], True)), + wbByteArray('Unknown', 2), + wbByteColors('Color') + ]); + +// wbRecordFlagsFlags := wbFlags([ +// {>>> 0x00000000 ACTI: Collision Geometry (default) <<<} +// {0x00000001}'ESM', +// {0x00000002}'Unknown 2', +// {>>> 0x00000004 ARMO: Not playable <<<} +// {0x00000004}'NotPlayable', +// {0x00000008}'Unknown 4', +// {0x00000010}'Unknown 5', +// {0x00000020}'Deleted', +// {>>> 0x00000040 ACTI: Has Tree LOD <<<} +// {>>> 0x00000040 REGN: Border Region <<<} +// {>>> 0x00000040 STAT: Has Tree LOD <<<} +// {>>> 0x00000040 REFR: Hidden From Local Map <<<} +// {0x00000040}'Constant HiddenFromLocalMap BorderRegion HasTreeLOD', +// {>>> 0x00000080 TES4: Localized <<<} +// {>>> 0x00000080 PHZD: Turn Off Fire <<<} +// {>>> 0x00000080 SHOU: Treat Spells as Powers <<<} +// {>>> 0x00000080 STAT: Add-on LOD Object <<<} +// {0x00000080}'Localized IsPerch AddOnLODObject TurnOffFire TreatSpellsAsPowers', +// {>>> 0x00000100 ACTI: Must Update Anims <<<} +// {>>> 0x00000100 REFR: Inaccessible <<<} +// {>>> 0x00000100 REFR for LIGH: Doesn't light water <<<} +// {0x00000100}'MustUpdateAnims Inaccessible DoesntLightWater', +// {>>> 0x00000200 ACTI: Local Map - Turns Flag Off, therefore it is Hidden <<<} +// {>>> 0x00000200 REFR: MotionBlurCastsShadows <<<} +// {0x00000200}'HiddenFromLocalMap StartsDead MotionBlurCastsShadows', +// {>>> 0x00000400 LSCR: Displays in Main Menu <<<} +// {0x00000400}'PersistentReference QuestItem DisplaysInMainMenu', +// {0x00000800}'InitiallyDisabled', +// {0x00001000}'Ignored', +// {0x00002000}'ActorChanged', +// {0x00004000}'Unknown 15', +// {>>> 0x00008000 STAT: Has Distant LOD <<<} +// {0x00008000}'VWD', +// {>>> 0x00010000 ACTI: Random Animation Start <<<} +// {>>> 0x00010000 REFR light: Never fades <<<} +// {0x00010000}'RandomAnimationStart NeverFades', +// {>>> 0x00020000 ACTI: Dangerous <<<} +// {>>> 0x00020000 REFR light: Doesn't light landscape <<<} +// {>>> 0x00020000 SLGM: Can hold NPC's soul <<<} +// {>>> 0x00020000 STAT: Use High-Detail LOD Texture <<<} +// {0x00020000}'Dangerous OffLimits DoesntLightLandscape HighDetailLOD CanHoldNPC', +// {0x00040000}'Compressed', +// {>>> 0x00080000 STAT: Has Currents <<<} +// {0x00080000}'CantWait HasCurrents', +// {>>> 0x00100000 ACTI: Ignore Object Interaction <<<} +// {0x00100000}'IgnoreObjectInteraction', +// {0x00200000}'(Used in Memory Changed Form)', +// {0x00400000}'Unknown 23', +// {>>> 0x00800000 ACTI: Is Marker <<<} +// {0x00800000}'IsMarker', +// {0x01000000}'Unknown 25', +// {>>> 0x02000000 ACTI: Obstacle <<<} +// {>>> 0x02000000 REFR: No AI Acquire <<<} +// {0x02000000}'Obstacle NoAIAcquire', +// {>>> 0x04000000 ACTI: Filter <<<} +// {0x04000000}'NavMeshFilter', +// {>>> 0x08000000 ACTI: Bounding Box <<<} +// {0x08000000}'NavMeshBoundingBox', +// {>>> 0x10000000 STAT: Show in World Map <<<} +// {0x10000000}'MustExitToTalk ShowInWorldMap', +// {>>> 0x20000000 ACTI: Child Can Use <<<} +// {>>> 0x20000000 REFR: Don't Havok Settle <<<} +// {0x20000000}'ChildCanUse DontHavokSettle', +// {>>> 0x40000000 ACTI: GROUND <<<} +// {>>> 0x40000000 REFR: NoRespawn <<<} +// {0x40000000}'NavMeshGround NoRespawn', +// {>>> 0x80000000 REFR: MultiBound <<<} +// {0x80000000}'MultiBound' +// ], [18]); + + wbRecordFlagsFlags := wbFlags(wbRecordFlagsFlags, [ + {0x00000001} { 0} 'Unknown 0', + {0x00000002} { 1} 'Unknown 1', + {0x00000004} { 2} 'Unknown 2', + {0x00000008} { 3} 'Unknown 3', + {0x00000010} { 4} 'Unknown 4', + {0x00000020} { 4} 'Unknown 5', + {0x00000040} { 6} 'Unknown 6', + {0x00000080} { 7} 'Unknown 7', + {0x00000100} { 8} 'Unknown 8', + {0x00000200} { 9} 'Unknown 9', + {0x00000400} {10} 'Unknown 10', + {0x00000800} {11} 'Unknown 11', + {0x00001000} {12} 'Unknown 12', + {0x00002000} {13} 'Unknown 13', + {0x00004000} {14} 'Unknown 14', + {0x00008000} {15} 'Unknown 15', + {0x00010000} {16} 'Unknown 16', + {0x00020000} {17} 'Unknown 17', + {0x00040000} {18} 'Unknown 18', + {0x00080000} {19} 'Unknown 19', + {0x00100000} {20} 'Unknown 20', + {0x00200000} {21} 'Unknown 21', + {0x00400000} {22} 'Unknown 22', + {0x00800000} {23} 'Unknown 23', + {0x01000000} {24} 'Unknown 24', + {0x02000000} {25} 'Unknown 25', + {0x04000000} {26} 'Unknown 26', + {0x08000000} {27} 'Unknown 27', + {0x10000000} {28} 'Unknown 28', + {0x20000000} {29} 'Unknown 29', + {0x40000000} {30} 'Unknown 30', + {0x80000000} {31} 'Unknown 31' + ]); + + wbEmptyBaseFlags := wbFlags(wbEmptyBaseFlags, [ + {0x00000001} { 0} 'Unknown 0', + {0x00000002} { 1} 'Unknown 1', + {0x00000004} { 2} 'Unknown 2', + {0x00000008} { 3} 'Unknown 3', + {0x00000010} { 4} 'Unknown 4', + {0x00000020} { 4} 'Unknown 5', + {0x00000040} { 6} 'Unknown 6', + {0x00000080} { 7} 'Unknown 7', + {0x00000100} { 8} 'Unknown 8', + {0x00000200} { 9} 'Unknown 9', + {0x00000400} {10} 'Unknown 10', + {0x00000800} {11} 'Unknown 11', + {0x00001000} {12} 'Unknown 12', + {0x00002000} {13} 'Unknown 13', + {0x00004000} {14} 'Unknown 14', + {0x00008000} {15} 'Unknown 15', + {0x00010000} {16} 'Unknown 16', + {0x00020000} {17} 'Unknown 17', + {0x00040000} {18} 'Unknown 18', + {0x00080000} {19} 'Unknown 19', + {0x00100000} {20} 'Unknown 20', + {0x00200000} {21} 'Unknown 21', + {0x00400000} {22} 'Unknown 22', + {0x00800000} {23} 'Unknown 23', + {0x01000000} {24} 'Unknown 24', + {0x02000000} {25} 'Unknown 25', + {0x04000000} {26} 'Unknown 26', + {0x08000000} {27} 'Unknown 27', + {0x10000000} {28} 'Unknown 28', + {0x20000000} {29} 'Unknown 29', + {0x40000000} {30} 'Unknown 30', + {0x80000000} {31} 'Unknown 31' + ]); + + wbRecordFlags := wbInteger('Record Flags', itU32, wbFlags(wbRecordFlagsFlags, wbFlagsList([]))); + + wbMainRecordHeader := wbRecordHeader(wbRecordFlags); + + wbSizeOfMainRecordStruct := 24; + + wbIgnoreRecords.Add(XXXX); + + wbXRGD := wbByteArray(XRGD, 'Ragdoll Data'); + wbXRGB := wbByteArray(XRGB, 'Ragdoll Biped Data'); + + wbMusicEnum := wbEnum(['Default', 'Public', 'Dungeon']); + wbSoundLevelEnum := wbEnum([ + 'Loud', + 'Normal', + 'Silent', + 'Very Loud' + ]); + + wbEntryPointsEnum := wbEnum([ + { 0} 'Calculate Weapon Damage', + { 1} 'Calculate My Critical Hit Chance', + { 2} 'Calculate My Critical Hit Damage', + { 3} 'Calculate Mine Explode Chance', + { 4} 'Adjust Limb Damage', + { 5} 'Adjust Book Skill Points', + { 6} 'Mod Recovered Health', + { 7} 'Get Should Attack', + { 8} 'Mod Buy Prices', + { 9} 'Add Leveled List On Death', + {10} 'Get Max Carry Weight', + {11} 'Mod Addiction Chance', + {12} 'Mod Addiction Duration', + {13} 'Mod Positive Chem Duration', + {14} 'Activate', + {15} 'Ignore Running During Detection', + {16} 'Ignore Broken Lock', + {17} 'Mod Enemy Critical Hit Chance', + {18} 'Mod Sneak Attack Mult', + {19} 'Mod Max Placeable Mines', + {20} 'Mod Bow Zoom', + {21} 'Mod Recover Arrow Chance', + {22} 'Mod Skill Use', + {23} 'Mod Telekinesis Distance', + {24} 'Mod Telekinesis Damage Mult', + {25} 'Mod Telekinesis Damage', + {26} 'Mod Bashing Damage', + {27} 'Mod Power Attack Stamina', + {28} 'Mod Power Attack Damage', + {29} 'Mod Spell Magnitude', + {30} 'Mod Spell Duration', + {31} 'Mod Secondary Value Weight', + {32} 'Mod Armor Weight', + {33} 'Mod Incoming Stagger', + {34} 'Mod Target Stagger', + {35} 'Mod Attack Damage', + {36} 'Mod Incoming Damage', + {37} 'Mod Target Damage Resistance', + {38} 'Mod Spell Cost', + {39} 'Mod Percent Blocked', + {40} 'Mod Shield Deflect Arrow Chance', + {41} 'Mod Incoming Spell Magnitude', + {42} 'Mod Incoming Spell Duration', + {43} 'Mod Player Intimidation', + {44} 'Mod Player Reputation', + {45} 'Mod Favor Points', + {46} 'Mod Bribe Amount', + {47} 'Mod Detection Light', + {48} 'Mod Detection Movement', + {49} 'Mod Soul Gem Recharge', + {50} 'Set Sweep Attack', + {51} 'Apply Combat Hit Spell', + {52} 'Apply Bashing Spell', + {53} 'Apply Reanimate Spell', + {54} 'Set Boolean Graph Variable', + {55} 'Mod Spell Casting Sound Event', + {56} 'Mod Pickpocket Chance', + {57} 'Mod Detection Sneak Skill', + {58} 'Mod Falling Damage', + {59} 'Mod Lockpick Sweet Spot', + {60} 'Mod Sell Prices', + {61} 'Can Pickpocket Equipped Item', + {62} 'Mod Lockpick Level Allowed', + {63} 'Set Lockpick Starting Arc', + {64} 'Set Progression Picking', + {65} 'Make Lockpicks Unbreakable', + {66} 'Mod Alchemy Effectiveness', + {67} 'Apply Weapon Swing Spell', + {68} 'Mod Commanded Actor Limit', + {69} 'Apply Sneaking Spell', + {70} 'Mod Player Magic Slowdown', + {71} 'Mod Ward Magicka Absorption Pct', + {72} 'Mod Initial Ingredient Effects Learned', + {73} 'Purify Alchemy Ingredients', + {74} 'Filter Activation', + {75} 'Can Dual Cast Spell', + {76} 'Mod Tempering Health', + {77} 'Mod Enchantment Power', + {78} 'Mod Soul Pct Captured to Weapon', + {79} 'Mod Soul Gem Enchanting', + {80} 'Mod # Applied Enchantments Allowed', + {81} 'Set Activate Label', + {82} 'Mod Shout OK', + {83} 'Mod Poison Dose Count', + {84} 'Should Apply Placed Item', + {85} 'Mod Armor Rating', + {86} 'Mod Lockpicking Crime Chance', + {87} 'Mod Ingredients Harvested', + {88} 'Mod Spell Range (Target Loc.)', + {89} 'Mod Potions Created', + {90} 'Mod Lockpicking Key Reward Chance', + {91} 'Allow Mount Actor' + ]); + + wbLocationEnum := wbEnum([ + {0} 'Near reference', + {1} 'In cell', + {2} 'Near package start location', + {3} 'Near editor location', + {4} 'Object ID', + {5} 'Object Type', + {6} 'Near linked reference', + {7} 'At package location', + {8} 'Alias (reference)', + {9} 'Alias (location)', + {10} 'Unknown 10', + {11} 'Unknown 11', + {12} 'Near self' + ]); + + wbEquipType := wbFlags([ + {0x00000001}'Hand To Hand Melee', + {0x00000002}'One Hand Sword', + {0x00000004}'One Hand Dagger', + {0x00000008}'One Hand Axe', + {0x00000010}'One Hand Mace', + {0x00000020}'Two Hand Sword', + {0x00000040}'Two Hand Axe', + {0x00000080}'Bow', + {0x00000100}'Staff', + {0x00000200}'Spell', + {0x00000400}'Shield', + {0x00000800}'Torch', + {0x00001000}'Crossbow' + ], True); + + wbEmotionTypeEnum := wbEnum([ + {0} 'Neutral', + {1} 'Anger', + {2} 'Disgust', + {3} 'Fear', + {4} 'Sad', + {5} 'Happy', + {6} 'Surprise', + {7} 'Puzzled' + ]); + + wbFurnitureAnimTypeEnum := wbEnum([ + {0} '', + {1} 'Sit', + {2} 'Lay', + {3} '', + {4} 'Lean' + ]); + + wbFurnitureEntryTypeFlags := wbFlags([ + {0x01} 'Front', + {0x02} 'Behind', + {0x04} 'Right', + {0x08} 'Left', + {0x10} 'Up' + ]); + + wbWardStateEnum := wbEnum([ + 'None', + 'Absorb', + 'Break' + ]); + + wbEventFunctionEnum := wbEnum([ + 'GetIsID', + 'IsInList', + 'GetValue', + 'HasKeyword', + 'GetItemValue' + ]); + + // Event member names and availability are different depending on event type + // Using generic names for the last 3 of them: Form, Value1, Value2 + wbEventMemberEnum := wbEnum([], [ + $0000, 'None', + $314F, 'CreatedObject', + $314C, '(Old)Location', + $324C, '(New)Location', + $314B, 'Keyword', + $3146, 'Form', + $3156, 'Value1', + $3256, 'Value2' + ]); + + wbWeaponAnimTypeEnum := wbEnum([ + {0} 'HandToHandMelee', + {1} 'OneHandSword', + {2} 'OneHandDagger', + {3} 'OneHandAxe', + {4} 'OneHandMace', + {5} 'TwoHandSword', + {6} 'TwoHandAxe', + {7} 'Bow', + {8} 'Staff', + {9} 'Crossbow' + ]); + + wbEDID := wbStringKC(EDID, 'Editor ID', 0, cpOverride); + wbFULL := wbLStringKC(FULL, 'Name', 0, cpTranslate); + wbFULLActor := wbLStringKC(FULL, 'Name', 0, cpTranslate, False, nil{wbActorTemplateUseBaseData}); + wbFULLReq := wbLStringKC(FULL, 'Name', 0, cpTranslate, True); + wbDESC := wbLStringKC(DESC, 'Description', 0, cpTranslate); + wbDESCReq := wbLStringKC(DESC, 'Description', 0, cpTranslate, True); + wbXSCL := wbFloat(XSCL, 'Scale'); + + wbPropTypeEnum := wbEnumSummary([ + {00} 'None', '', + {01} 'Object', '', + {02} 'String', '', + {03} 'Int32', '', + {04} 'Float', '', + {05} 'Bool', '', + {06} '', '', + {07} '', '', + {08} '', '', + {09} '', '', + {10} '', '', + {11} 'Array of Object', 'Object[]', + {12} 'Array of String', 'String[]', + {13} 'Array of Int32', 'Int32[]', + {14} 'Array of Float', 'Float[]', + {15} 'Array of Bool', 'Bool[]' + ]); + + wbScriptFlags := wbInteger('Flags', itU8, wbEnum([ + {0x00} 'Local', + {0x01} 'Inherited', + {0x02} 'Removed', + {0x03} 'Inherited and Removed' + ])); + + wbScriptPropertyObject := wbUnion('Object Union', wbScriptObjFormatDecider, [ + wbStructSK([2], 'Object v2', [ + wbInteger('Unused', itU16, nil, cpIgnore), + wbInteger('Alias', itS16, wbScriptObjectAliasToStr, wbStrToAlias).SetDefaultEditValue('None'), + wbFormID('FormID') + ], [2, 1, 0]) + .SetSummaryKey([2, 1]) + .SetSummaryMemberPrefixSuffix(2, '', '') + .SetSummaryMemberPrefixSuffix(1, ', Alias[', ']') + .SetSummaryDelimiter('') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfSummaryNoSortKey), + wbStructSK([0], 'Object v1', [ + wbFormID('FormID'), + wbInteger('Alias', itS16, wbScriptObjectAliasToStr, wbStrToAlias), + wbInteger('Unused', itU16, nil, cpIgnore) + ]) + .SetSummaryKey([0, 1]) + .SetSummaryMemberPrefixSuffix(0, '', '') + .SetSummaryMemberPrefixSuffix(1, ', Alias[', ']') + .SetSummaryDelimiter('') + .IncludeFlag(dfSummaryMembersNoName) + ]); + + wbScriptProperty := + wbStructSK([0], 'Property', [ + wbLenString('propertyName', 2), + wbInteger('Type', itU8, wbPropTypeEnum, cpNormal, False, nil, wbScriptPropertyTypeAfterSet), + wbInteger('Flags', itU8, wbEnum([ + {0x00} '', + {0x01} 'Edited', + {0x02} '', + {0x03} 'Removed' + ])).SetDefaultEditValue('Edited'), + wbUnion('Value', wbScriptPropertyDecider, [ + {00} wbNull, + {01} wbScriptPropertyObject, + {02} wbLenString('String', 2).OverrideEncoding(wbEncodingVMAD), + {03} wbInteger('Int32', itS32), + {04} wbFloat('Float'), + {05} wbInteger('Bool', itU8, wbEnum(['False', 'True'])), + {11} wbArray('Array of Object', wbScriptPropertyObject, -1), + {12} wbArray('Array of String', wbLenString('Element', 2).OverrideEncoding(wbEncodingVMAD), -1), + {13} wbArray('Array of Int32', wbInteger('Element', itS32), -1), + {14} wbArray('Array of Float', wbFloat('Element'), -1), + {15} wbArray('Array of Bool', wbInteger('Element', itU8, wbEnum(['False', 'True'])), -1) + ]) + ]) + .SetSummaryKey([1, 3]) + .SetSummaryMemberPrefixSuffix(0, '', ':') + .SetSummaryMemberPrefixSuffix(3, '= ', '') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfCollapsed, wbCollapseScriptProperties); + + wbScriptProperties := + wbArrayS('Properties', wbScriptProperty, -2, cpNormal, False, nil, nil, nil, wbCanAddScriptProperties) + .SetSummaryPassthroughMaxLength(80) + .SetSummaryPassthroughMaxDepth(1); + + wbScriptEntry := wbStructSK([0], 'Script', [ + wbLenString('ScriptName', 2), + wbScriptFlags, + wbScriptProperties + ]) + .SetSummaryKey([2]) + .SetSummaryMemberPrefixSuffix(2, '(', ')') + .SetSummaryDelimiter('') + .IncludeFlag(dfSummaryMembersNoName); + + wbScriptFragmentsInfo := wbStruct('Script Fragments', [ + wbInteger('Extra bind data version', itS8).SetDefaultNativeValue(2), + wbInteger('Flags', itU8, wbFlags([ + {1} 'OnBegin', + {2} 'OnEnd' + ])), + wbLenString('FileName', 2), + wbArray('Fragments', // Do NOT sort, ordered OnBegin, OnEnd + wbStruct('Fragment', [ + wbInteger('Unknown', itS8), + wbLenString('ScriptName', 2), + wbLenString('FragmentName', 2) + ]) + .SetSummaryKey([1, 2]) + .SetSummaryMemberPrefixSuffix(1, '', ':') + .SetSummaryDelimiter('') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfCollapsed, wbCollapseFragments) + , [], wbScriptFragmentsInfoCounter) + ]) + .SetSummaryKey([1, 2, 3]) + .IncludeFlag(dfSummaryMembersNoName); + + wbScriptFragmentsPack := wbStruct('Script Fragments', [ + wbInteger('Extra bind data version', itS8).SetDefaultNativeValue(2), + wbInteger('Flags', itU8, wbFlags([ + {1} 'OnBegin', + {2} 'OnEnd', + {4} 'OnChange' + ])), + wbLenString('FileName', 2), + wbArray('Fragments', // Do NOT sort, ordered OnBegin, OnEnd, OnChange + wbStruct('Fragment', [ + wbInteger('Unknown', itS8), + wbLenString('ScriptName', 2), + wbLenString('FragmentName', 2) + ]) + .SetSummaryKey([1, 2]) + .SetSummaryMemberPrefixSuffix(1, '', ':') + .SetSummaryDelimiter('') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfCollapsed, wbCollapseFragments) + , [], wbScriptFragmentsPackCounter) + ]) + .SetSummaryKey([1, 2, 3]) + .IncludeFlag(dfSummaryMembersNoName); + + wbScriptFragmentsQuest := wbStruct('Script Fragments', [ + wbInteger('Extra bind data version', itS8).SetDefaultNativeValue(2), + wbInteger('FragmentCount', itU16, nil, cpBenign), + wbLenString('FileName', 2), + wbArrayS('Fragments', + wbStructSK([0, 2], 'Fragment', [ + wbInteger('Quest Stage', itU16), + wbInteger('Unknown', itS16), + wbInteger('Quest Stage Index', itS32), + wbInteger('Unknown', itS8), + wbLenString('ScriptName', 2), + wbLenString('FragmentName', 2) + ]) + .SetSummaryKey([4, 5]) + .SetSummaryMemberPrefixSuffix(0, '[', '/') + .SetSummaryMemberPrefixSuffix(2, '', ']') + .SetSummaryMemberPrefixSuffix(4, ' ', ':') + .SetSummaryDelimiter('') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfCollapsed, wbCollapseFragments) + , wbScriptFragmentsQuestCounter).SetAfterSet(wbScriptFragmentsQuestFragmentsAfterSet) + ]) + .SetSummaryKey([2, 3]) + .IncludeFlag(dfSummaryMembersNoName) + .SetAfterSet(wbScriptFragmentsQuestAfterSet); + + wbScriptFragmentsScen := wbStruct('Script Fragments', [ + wbInteger('Extra bind data version', itS8).SetDefaultNativeValue(2), + wbInteger('Flags', itU8, wbFlags([ + {1} 'OnBegin', + {2} 'OnEnd' + ])), + wbLenString('FileName', 2), + wbArray('Fragments', // Do NOT sort, ordered OnBegin, OnEnd + wbStruct('Fragment', [ + wbInteger('Unknown', itS8), + wbLenString('ScriptName', 2), + wbLenString('FragmentName', 2) + ]) + .SetSummaryKey([1, 2]) + .SetSummaryMemberPrefixSuffix(1, '', ':') + .SetSummaryDelimiter('') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfCollapsed, wbCollapseFragments) + , [], wbScriptFragmentsSceneCounter), + wbArray('Phase Fragments', + wbStructSK([0, 1], 'Phase Fragment', [ + wbInteger('Phase Flag', itU8, wbFlags([ + {1} 'OnStart', + {2} 'OnCompletion' + ])), + wbInteger('Phase Index', itU8), + wbInteger('Unknown', itS16), + wbInteger('Unknown', itS8), + wbInteger('Unknown', itS8), + wbLenString('ScriptName', 2), + wbLenString('FragmentName', 2) + ]) + .SetSummaryKey([5, 6]) + .SetSummaryMemberPrefixSuffix(0, '[', ':') + .SetSummaryMemberPrefixSuffix(1, '', ']') + .SetSummaryMemberPrefixSuffix(5, ' ', ':') + .SetSummaryDelimiter('') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfCollapsed, wbCollapseFragments) + , -2) + ]) + .SetSummaryKey([1, 2, 3, 4]) + .IncludeFlag(dfSummaryMembersNoName); + + wbScriptFragments := wbStruct('Script Fragments', [ + wbInteger('Extra bind data version', itS8).SetDefaultNativeValue(2), + wbLenString('FileName', 2), + wbArrayS('Fragments', + wbStructSK([0], 'Fragment', [ + wbInteger('Fragment Index', itU16), + wbInteger('Unknown', itS16), + wbInteger('Unknown', itS8), + wbLenString('ScriptName', 2), + wbLenString('FragmentName', 2) + ]) + .SetSummaryKey([3, 4]) + .SetSummaryMemberPrefixSuffix(0, '[', ']') + .SetSummaryMemberPrefixSuffix(3, ' ', ':') + .SetSummaryDelimiter('') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfCollapsed, wbCollapseFragments) + , -2) + ]) + .SetSummaryKey([1, 2]) + .IncludeFlag(dfSummaryMembersNoName); + + {>>> http://www.uesp.net/wiki/Tes5Mod:Mod_File_Format/VMAD_Field <<<} + var wbVMADScripts := + wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, wbCanAddScripts) + .SetSummaryPassthroughMaxLength(100); + + var wbVMADVersion := + wbInteger('Version', itS16, nil, cpIgnore).SetDefaultNativeValue(5); + var wbVMADObjectFormat := + wbInteger('Object Format', itS16, nil, cpIgnore).SetDefaultNativeValue(2); + + wbVMAD := wbStruct(VMAD, 'Virtual Machine Adapter', [ + wbVMADVersion, + wbVMADObjectFormat, + wbVMADScripts + ]) + .SetSummaryKeyOnValue([2]); + + wbVMADFragmentedPERK := wbStruct(VMAD, 'Virtual Machine Adapter', [ + wbVMADVersion, + wbVMADObjectFormat, + wbVMADScripts, + wbScriptFragments + ], cpNormal, False, nil, 3) + .SetSummaryKeyOnValue([2, 3]); + + wbVMADFragmentedPACK := wbStruct(VMAD, 'Virtual Machine Adapter', [ + wbVMADVersion, + wbVMADObjectFormat, + wbVMADScripts, + wbScriptFragmentsPack + ], cpNormal, False, nil, 3) + .SetSummaryKeyOnValue([2, 3]); + + wbVMADFragmentedQUST := wbStruct(VMAD, 'Virtual Machine Adapter', [ + wbVMADVersion, + wbVMADObjectFormat, + wbVMADScripts, + wbScriptFragmentsQuest, + wbArrayS('Aliases', wbStructSK([0], 'Alias', [ + wbScriptPropertyObject, + wbVMADVersion, + wbVMADObjectFormat, + wbArrayS('Alias Scripts', wbScriptEntry, -2) + ]), -2) + ], cpNormal, False, nil, 3) + .SetSummaryKeyOnValue([2, 3, 4]); + + wbVMADFragmentedSCEN := wbStruct(VMAD, 'Virtual Machine Adapter', [ + wbVMADVersion, + wbVMADObjectFormat, + wbVMADScripts, + wbScriptFragmentsScen + ], cpNormal, False, nil, 3) + .SetSummaryKeyOnValue([2, 3]); + + wbVMADFragmentedINFO := wbStruct(VMAD, 'Virtual Machine Adapter', [ + wbVMADVersion, + wbVMADObjectFormat, + wbVMADScripts, + wbScriptFragmentsInfo + ], cpNormal, False, nil, 3) + .SetSummaryKeyOnValue([2, 3]); + + wbAttackData := wbRStructSK([1], 'Attack', [ + wbStruct(ATKD, 'Attack Data', [ + wbFloat('Damage Mult'), + wbFloat('Attack Chance'), + wbFormIDCk('Attack Spell', [SPEL, SHOU, NULL]), + wbInteger('Attack Flags', itU32, wbFlags([ + {0x00000001} 'Ignore Weapon', + {0x00000002} 'Bash Attack', + {0x00000004} 'Power Attack', + {0x00000008} 'Left Attack', + {0x00000010} 'Rotating Attack', + {0x00000020} 'Unknown 5', + {0x00000040} 'Unknown 6', + {0x00000080} 'Unknown 7', + {0x00000100} 'Unknown 8', + {0x00000200} 'Unknown 9', + {0x00000400} 'Unknown 10', + {0x00000800} 'Unknown 11', + {0x00001000} 'Unknown 12', + {0x00002000} 'Unknown 13', + {0x00004000} 'Unknown 14', + {0x00008000} 'Unknown 15', + {0x00010000} 'Unknown 16', + {0x00020000} 'Unknown 17', + {0x00040000} 'Unknown 18', + {0x00080000} 'Unknown 19', + {0x00100000} 'Unknown 20', + {0x00200000} 'Unknown 21', + {0x00400000} 'Unknown 22', + {0x00800000} 'Unknown 23', + {0x01000000} 'Unknown 24', + {0x02000000} 'Unknown 25', + {0x04000000} 'Unknown 26', + {0x08000000} 'Unknown 27', + {0x10000000} 'Unknown 28', + {0x20000000} 'Unknown 29', + {0x40000000} 'Unknown 30', + {0x80000000} 'Override Data' + ])), + wbFloat('Attack Angle'), + wbFloat('Strike Angle'), + wbFloat('Stagger'), + wbFormIDCk('Attack Type', [KYWD, NULL]), + wbFloat('Knockdown'), + wbFloat('Recovery Time'), + wbFloat('Stamina Mult') + ]), + wbString(ATKE, 'Attack Event') + ], []); + + wbPLDT := wbStruct(PLDT, 'Location', [ + wbInteger('Type', itS32, wbLocationEnum), + wbUnion('Location Value', wbTypeDecider, [ + {0} wbFormIDCkNoReach('Reference', [NULL, DOOR, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + {1} wbFormIDCkNoReach('Cell', [NULL, CELL]), + {2} wbByteArray('Near Package Start Location', 4, cpIgnore), + {3} wbByteArray('Near Editor Location', 4, cpIgnore), + {4} wbFormIDCkNoReach('Object ID', [NULL, ACTI, DOOR, STAT, MSTT, FURN, SPEL, SCRL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, FACT, FLST, IDLM, SHOU]), + {5} wbInteger('Object Type', itU32, wbObjectTypeEnum), + {6} wbFormIDCk('Keyword', [NULL, KYWD]), + {7} wbByteArray('Unused', 4, cpIgnore), + {8} wbInteger('Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), + {9} wbInteger('Reference', itS32, wbPackageLocationAliasToStr, wbStrToAlias), + {10} wbByteArray('Unknown', 4, cpIgnore), + {11} wbByteArray('Unknown', 4, cpIgnore), + {12} wbByteArray('Unknown', 4, cpIgnore) + ]), + wbInteger('Radius', itS32) + ]); + + wbPLVD := wbStruct(PLVD, 'Location', [ + wbInteger('Type', itS32, wbLocationEnum), + wbUnion('Location Value', wbTypeDecider, [ + {0} wbFormIDCkNoReach('Reference', [NULL, DOOR, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + {1} wbFormIDCkNoReach('Cell', [NULL, CELL]), + {2} wbByteArray('Near Package Start Location', 4, cpIgnore), + {3} wbByteArray('Near Editor Location', 4, cpIgnore), + {4} wbFormIDCkNoReach('Object ID', [NULL, ACTI, DOOR, STAT, MSTT, FURN, SPEL, SCRL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, INGR, LIGH, FACT, FLST, IDLM, SHOU]), + {5} wbInteger('Object Type', itU32, wbObjectTypeEnum), + {6} wbFormIDCk('Keyword', [NULL, KYWD]), + {7} wbByteArray('Unused', 4, cpIgnore), + {8} wbInteger('Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), + {9} wbInteger('Reference', itS32, wbPackageLocationAliasToStr, wbStrToAlias), + {10} wbByteArray('Unknown', 4, cpIgnore), + {11} wbByteArray('Unknown', 4, cpIgnore), + {12} wbByteArray('Unknown', 4, cpIgnore) + ]), + wbInteger('Radius', itS32) + ]); + + wbTargetData := wbStruct('Target Data', [ + wbInteger('Type', itS32, wbEnum([ + {0} 'Specific Reference', + {1} 'Object ID', + {2} 'Object Type', + {3} 'Linked Reference', + {4} 'Ref Alias', + {5} 'Unknown 5', + {6} 'Self' + ]), cpNormal, False, nil, nil, 2), + wbUnion('Target', wbTypeDecider, [ + {0} wbFormIDCkNoReach('Reference', [NULL, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], True), + {1} wbFormIDCkNoReach('Object ID', [NULL, ACTI, DOOR, STAT, MSTT, FURN, SPEL, SCRL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, INGR, LIGH, FACT, FLST, IDLM, SHOU, SOUN, TXST, PROJ, FLOR, SLGM]), + {2} wbInteger('Object Type', itU32, wbObjectTypeEnum), + {3} wbFormID('Reference'), + {4} wbInteger('Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), + {5} wbByteArray('Unknown', 4, cpIgnore), + {6} wbByteArray('Unknown', 4, cpIgnore) + ]), + wbInteger('Count / Distance', itS32) + ]); + + wbEITM := wbFormIDCk(EITM, 'Object Effect', [ENCH, SPEL]); + + wbMO2S := wbArrayS(MO2S, 'Alternate Textures', wbAlternateTexture, -1); + wbMO3S := wbArrayS(MO3S, 'Alternate Textures', wbAlternateTexture, -1); + wbMO4S := wbArrayS(MO4S, 'Alternate Textures', wbAlternateTexture, -1); + wbMO5S := wbArrayS(MO5S, 'Alternate Textures', wbAlternateTexture, -1); + wbMODS := wbArrayS(MODS, 'Alternate Textures', wbAlternateTexture, -1); + + wbMODD := + wbInteger(MODD, 'FaceGen Model Flags', itU8, wbFlags([ + 'Head', + 'Torso', + 'Right Hand', + 'Left Hand' + ])); + + wbDMDSs := wbArrayS(DMDS, 'Alternate Textures', wbAlternateTexture, -1); + + wbDEST := wbRStruct('Destructible', [ + wbStruct(DEST, 'Header', [ + wbInteger('Health', itS32), + wbInteger('DEST Count', itU8), + wbInteger('VATS Targetable', itU8, wbEnum(['False', 'True'])), + wbByteArray('Unknown', 2) + ]), + wbRArray('Stages', + wbRStruct('Stage', [ + wbStruct(DSTD, 'Destruction Stage Data', [ + wbInteger('Health %', itU8), + wbInteger('Index', itU8), + wbInteger('Model Damage Stage', itU8), + wbInteger('Flags', itU8, wbFlags([ + 'Cap Damage', + 'Disable', + 'Destroy', + 'Ignore External Dmg' + ])), + wbInteger('Self Damage per Second', itS32), + wbFormIDCk('Explosion', [EXPL, NULL]), + wbFormIDCk('Debris', [DEBR, NULL]), + wbInteger('Debris Count', itS32) + ], cpNormal, True), + wbRStructSK([0], 'Model', [ + wbString(DMDL, 'Model FileName'), + wbDMDT, + wbDMDSs + ], [], cpNormal, False, nil), + wbEmpty(DSTF, 'End Marker', cpNormal, True) + ], [], cpNormal, False, nil) + ) + ], [], cpNormal, False, nil); + + wbDESTActor := wbRStruct('Destructible', [ + wbStruct(DEST, 'Header', [ + wbInteger('Health', itS32), + wbInteger('Count', itU8), + wbInteger('VATS Targetable', itU8, wbEnum(['False', 'True'])), + wbByteArray('Unknown', 2) + ]), + wbRArray('Stages', // Begin Stage Array + wbRStruct('Stage', [ // Begin Stage RStruct + wbStruct(DSTD, 'Destruction Stage Data', [ // Begin DSTD + wbInteger('Health %', itU8), + wbInteger('Index', itU8), + wbInteger('Damage Stage', itU8), + wbInteger('Flags', itU8, wbFlags([ + 'Cap Damage', + 'Disable', + 'Destroy' + ])), + wbInteger('Self Damage per Second', itS32), + wbFormIDCk('Explosion', [EXPL, NULL]), + wbFormIDCk('Debris', [DEBR, NULL]), + wbInteger('Debris Count', itS32) + ], cpNormal, True), // End DSTD + wbRStructSK([0], 'Model', [ // Begin DMDL + wbString(DMDL, 'Model FileName') + ], []), // End DMDL + wbDMDT, + wbDMDSs, + wbEmpty(DSTF, 'End Marker', cpNormal, True) + ], []) // Begin Stage RStruct + ) // End Stage Array + ], [], cpNormal, False, nil{wbActorTemplateUseModelAnimation}); + + wbXESP := wbStruct(XESP, 'Enable Parent', [ + wbFormIDCk('Reference', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + wbInteger('Flags', itU8, wbFlags([ + 'Set Enable State to Opposite of Parent', + 'Pop In' + ])), + wbByteArray('Unused', 3, cpIgnore) + ]); + + wbPDTO := + wbStruct(PDTO, 'Topic Data', [ + wbInteger('Type', itU32, wbEnum([ + 'Topic Ref', + 'Topic Subtype' + ])), + wbUnion('Data', wbTypeDecider, [ + wbFormIDCk('Topic', [DIAL, NULL]), + wbString('Subtype', 4) + ]) + ]); + + wbPDTOs := wbRArray('Topic', wbPDTO, cpNormal, False, nil); + + wbXLCM := wbInteger(XLCM, 'Level Modifier', itS32, wbEnum([ + 'Easy', + 'Medium', + 'Hard', + 'Very Hard' + ])); + + wbTVDT := wbByteArray(TVDT, 'Occlusion Data', 0, cpNormal); +// wbTVDT := wbArray(TVDT, 'Occlusion Data', wbInteger('Unknown', itS32)), + + if wbSimpleRecords then begin + wbMaxHeightDataCELL := wbByteArray(MHDT, 'Max Height Data', 0, cpNormal); + wbMaxHeightDataWRLD := wbByteArray(MHDT, 'Max Height Data', 0, wbWorldMHDTConflictPriority[wbIgnoreWorldMHDT]); + end + else begin + wbMaxHeightDataCELL := wbStruct(MHDT, 'Max Height Data', [ + wbFloat('Offset'), + wbArray('Rows', + wbByteArray('Columns', 32) + // way too verbose for no practical use + //wbStruct('Row', [ wbArray('Columns', wbInteger('Column', itU8), 32) ]) + , 32) + ]); + wbMaxHeightDataWRLD := wbStruct(MHDT, 'Max Height Data', [ + wbStruct('Min', [ + wbInteger('X', itS16, nil, nil, wbWorldMHDTConflictPriority[wbIgnoreWorldMHDT]), + wbInteger('Y', itS16, nil, nil, wbWorldMHDTConflictPriority[wbIgnoreWorldMHDT]) + ]), + wbStruct('Max', [ + wbInteger('X', itS16, nil, nil, wbWorldMHDTConflictPriority[wbIgnoreWorldMHDT]), + wbInteger('Y', itS16, nil, nil, wbWorldMHDTConflictPriority[wbIgnoreWorldMHDT]) + ]), + wbByteArray('Cell Data', 0, wbWorldMHDTConflictPriority[wbIgnoreWorldMHDT]) + // way too verbose for no practical use + {wbArray('Cell Data', wbStruct('Quad Height', [ + wbInteger('Bottom Left', itU8), + wbInteger('Bottom Right', itU8), + wbInteger('Top Left', itU8), + wbInteger('Top Right', itU8) + ]))} + ], wbWorldMHDTConflictPriority[wbIgnoreWorldMHDT]); + end; + + wbXOWN := wbFormIDCkNoReach(XOWN, 'Owner', [FACT, ACHR, NPC_]); +end; + +procedure DefineTES5b; +begin + wbRefRecord(ACHR, 'Placed NPC', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000200} 9, 'Starts Dead', + {0x00000400} 10, 'Persistent', + {0x00000800} 11, 'Initially Disabled', + {0x02000000} 25, 'No AI Acquire', + {0x20000000} 29, 'Don''t Havok Settle' + ], True, True)), [ + wbEDID, + wbVMAD, + wbFormIDCk(NAME, 'Base', [NPC_], False, cpNormal, True), + wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), + + {--- Ragdoll ---} + wbXRGD, + wbXRGB, + + {--- Patrol Data ---} + wbRStruct('Patrol Data', [ + wbFloat(XPRD, 'Idle Time', cpNormal, True), + wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), + wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), + {>>> BEGIN leftover from earlier CK versions <<<} + wbRStruct('Unused', [ + wbUnknown(SCHR), + wbUnknown(SCDA), + wbUnknown(SCTX), + wbUnknown(QNAM), + wbUnknown(SCRO) + ], [], cpIgnore, false, wbNeverShow), + {>>> END leftover from earlier CK versions <<<} + wbPDTOs, + wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal) + ], []), + + {--- Leveled Actor ----} + wbXLCM, + + {--- Merchant Container ----} + wbFormIDCk(XMRC, 'Merchant Container', [REFR], True), + + {--- Extra ---} + wbInteger(XCNT, 'Count', itS32), + wbFloat(XRDS, 'Radius'), + wbFloat(XHLP, 'Health'), + + wbRArrayS('Linked References', wbStructSK(XLKR, [0], 'Linked Reference', [ + wbFormIDCk('Keyword/Ref', [KYWD, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), + wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]) + ], cpNormal, False, nil, 1)), + + {--- Activate Parents ---} + wbRStruct('Activate Parents', [ + wbInteger(XAPD, 'Flags', itU8, wbFlags([ + 'Parent Activate Only' + ], True)), + wbRArrayS('Activate Parent Refs', + wbStructSK(XAPR, [0], 'Activate Parent Ref', [ + wbFormIDCk('Reference', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + wbFloat('Delay') + ]) + ) + ], []), + + {--- Linked Ref ---} + wbStruct(XCLP, 'Linked Reference Color', [ + wbByteColors('Link Start Color'), + wbByteColors('Link End Color') + ]), + + wbFormIDCk(XLCN, 'Persistent Location', [LCTN]), + wbFormIDCk(XLRL, 'Location Reference', [LCRT, LCTN, NULL], False, cpBenignIfAdded), + wbEmpty(XIS2, 'Ignored by Sandbox'), + wbArray(XLRT, 'Location Ref Type', wbFormIDCk('Ref', [LCRT, NULL])), + wbFormIDCk(XHOR, 'Horse', [ACHR]), + wbFloat(XHTW, 'Head-Tracking Weight'), + wbFloat(XFVC, 'Favor Cost'), + + {--- Enable Parent ---} + wbXESP, + + {--- Ownership ---} + wbOwnership(wbXOWN, [XRGD]), + + {--- Emittance ---} + wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), + + {--- MultiBound ---} + wbFormIDCk(XMBR, 'MultiBound Reference', [REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + + {--- Flags ---} + wbEmpty(XIBS, 'Ignored By Sandbox'), + + {--- 3D Data ---} + wbXSCL, + wbDATAPosRot + ], True, wbPlacedAddInfo); + + wbRecord(ACTI, 'Activator', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000040} 6, 'Has Tree LOD', + {0x00000100} 8, 'Must Update Anims', + {0x00000200} 9, 'Hidden From Local Map', + {0x00008000} 15, 'Has Distant LOD', + {0x00010000} 16, 'Random Anim Start', + {0x00020000} 17, 'Dangerous', + {0x00100000} 20, 'Ignore Object Interaction', + {0x00800000} 23, 'Is Marker', + {0x02000000} 25, 'Obstacle', + {0x04000000} 26, 'NavMesh Generation - Filter', + {0x08000000} 27, 'NavMesh Generation - Bounding Box', + {0x20000000} 29, 'Child Can Use', + {0x40000000} 30, 'NavMesh Generation - Ground' + ])), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbGenericModel, + wbDEST, + wbKSIZ, + wbKWDAs, + wbStruct(PNAM, 'Marker Color', [ + wbInteger('Red', itU8), + wbInteger('Green', itU8), + wbInteger('Blue', itU8), + wbInteger('Unused', itU8) + ]).SetToStr(wbRGBAToStr).IncludeFlag(dfCollapsed, wbCollapseRGBA), + wbFormIDCk(SNAM, 'Sound - Looping', [SNDR]), + wbFormIDCk(VNAM, 'Sound - Activation', [SNDR]), + wbFormIDCk(WNAM, 'Water Type', [WATR]), + wbLString(RNAM, 'Activate Text Override', 0, cpTranslate), + wbInteger(FNAM, 'Flags', itU16, wbFlags([ + 'No Displacement', + 'Ignored by Sandbox' + ])), + wbFormIDCk(KNAM, 'Interaction Keyword', [KYWD]) + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); + + wbRecord(TACT, 'Talking Activator', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000200} 9, 'Hidden From Local Map', + {0x00010000} 16, 'Random Anim Start', + {0x00020000} 17, 'Radio Station' + ]), [17]), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbGenericModel, + wbDEST, + wbKSIZ, + wbKWDAs, + wbUnknown(PNAM, cpIgnore, True), + wbFormIDCk(SNAM, 'Looping Sound', [SNDR]), + wbUnknown(FNAM, cpIgnore, True), + wbFormIDCk(VNAM, 'Voice Type', [VTYP]) + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); + + wbICON := wbRStruct('Icon', [ + wbString(ICON, 'Large Icon FileName', 0, cpNormal, True), + wbString(MICO, 'Small Icon FileName') + ], [], cpNormal, False, nil, True); + + wbICONReq := wbRStruct('Icon', [ + wbString(ICON, 'Large Icon FileName', 0, cpNormal, True), + wbString(MICO, 'Small Icon FileName') + ], [], cpNormal, True, nil, True); + + wbICO2 := wbRStruct('Icon 2 (female)', [ + wbString(ICO2, 'Large Icon FileName', 0, cpNormal, True), + wbString(MIC2, 'Small Icon FileName') + ], [], cpNormal, False, nil, True); + + wbVatsValueFunctionEnum := + wbEnum([ + { 0} 'Weapon Is', + { 1} 'Weapon In List', + { 2} 'Target Is', + { 3} 'Target In List', + { 4} 'Target Distance', + { 5} 'Target Part', + { 6} 'VATS Action', + { 7} 'Is Success', + { 8} 'Is Critical', + { 9} 'Critical Effect Is', + {10} 'Critical Effect In List', + {11} 'Is Fatal', + {12} 'Explode Part', + {13} 'Dismember Part', + {14} 'Cripple Part', + {15} 'Weapon Type Is', + {16} 'Is Stranger', + {17} 'Is Paralyzing Palm', + {18} 'Projectile Type Is', + {19} 'Delivery Type Is', + {20} 'Casting Type Is' + ]); + + wbActorValueEnum := + wbEnum([ + {00} 'Aggression', + {01} 'Confidence', + {02} 'Energy', + {03} 'Morality', + {04} 'Mood', + {05} 'Assistance', + {06} 'One-Handed', + {07} 'Two-Handed', + {08} 'Archery', + {09} 'Block', + {10} 'Smithing', + {11} 'Heavy Armor', + {12} 'Light Armor', + {13} 'Pickpocket', + {14} 'Lockpicking', + {15} 'Sneak', + {16} 'Alchemy', + {17} 'Speech', + {18} 'Alteration', + {19} 'Conjuration', + {20} 'Destruction', + {21} 'Illusion', + {22} 'Restoration', + {23} 'Enchanting', + {24} 'Health', + {25} 'Magicka', + {26} 'Stamina', + {27} 'Heal Rate', + {28} 'Magicka Rate', + {29} 'Stamina Rate', + {30} 'Speed Mult', + {31} 'Inventory Weight', + {32} 'Carry Weight', + {33} 'Critical Chance', + {34} 'Melee Damage', + {35} 'Unarmed Damage', + {36} 'Mass', + {37} 'Voice Points', + {38} 'Voice Rate', + {39} 'Damage Resist', + {40} 'Poison Resist', + {41} 'Resist Fire', + {42} 'Resist Shock', + {43} 'Resist Frost', + {44} 'Resist Magic', + {45} 'Resist Disease', + {46} 'Unknown 46', + {47} 'Unknown 47', + {48} 'Unknown 48', + {49} 'Unknown 49', + {50} 'Unknown 50', + {51} 'Unknown 51', + {52} 'Unknown 52', + {53} 'Paralysis', + {54} 'Invisibility', + {55} 'Night Eye', + {56} 'Detect Life Range', + {57} 'Water Breathing', + {58} 'Water Walking', + {59} 'Unknown 59', + {60} 'Fame', + {61} 'Infamy', + {62} 'Jumping Bonus', + {63} 'Ward Power', + {64} 'Right Item Charge', + {65} 'Armor Perks', + {66} 'Shield Perks', + {67} 'Ward Deflection', + {68} 'Variable01', + {69} 'Variable02', + {70} 'Variable03', + {71} 'Variable04', + {72} 'Variable05', + {73} 'Variable06', + {74} 'Variable07', + {75} 'Variable08', + {76} 'Variable09', + {77} 'Variable10', + {78} 'Bow Speed Bonus', + {79} 'Favor Active', + {80} 'Favors Per Day', + {81} 'Favors Per Day Timer', + {82} 'Left Item Charge', + {83} 'Absorb Chance', + {84} 'Blindness', + {85} 'Weapon Speed Mult', + {86} 'Shout Recovery Mult', + {87} 'Bow Stagger Bonus', + {88} 'Telekinesis', + {89} 'Favor Points Bonus', + {90} 'Last Bribed Intimidated', + {91} 'Last Flattered', + {92} 'Movement Noise Mult', + {93} 'Bypass Vendor Stolen Check', + {94} 'Bypass Vendor Keyword Check', + {95} 'Waiting For Player', + {96} 'One-Handed Modifier', + {97} 'Two-Handed Modifier', + {98} 'Marksman Modifier', + {99} 'Block Modifier', + {100} 'Smithing Modifier', + {101} 'Heavy Armor Modifier', + {102} 'Light Armor Modifier', + {103} 'Pickpocket Modifier', + {104} 'Lockpicking Modifier', + {105} 'Sneaking Modifier', + {106} 'Alchemy Modifier', + {107} 'Speechcraft Modifier', + {108} 'Alteration Modifier', + {109} 'Conjuration Modifier', + {110} 'Destruction Modifier', + {111} 'Illusion Modifier', + {112} 'Restoration Modifier', + {113} 'Enchanting Modifier', + {114} 'One-Handed Skill Advance', + {115} 'Two-Handed Skill Advance', + {116} 'Marksman Skill Advance', + {117} 'Block Skill Advance', + {118} 'Smithing Skill Advance', + {119} 'Heavy Armor Skill Advance', + {120} 'Light Armor Skill Advance', + {121} 'Pickpocket Skill Advance', + {122} 'Lockpicking Skill Advance', + {123} 'Sneaking Skill Advance', + {124} 'Alchemy Skill Advance', + {125} 'Speechcraft Skill Advance', + {126} 'Alteration Skill Advance', + {127} 'Conjuration Skill Advance', + {128} 'Destruction Skill Advance', + {129} 'Illusion Skill Advance', + {130} 'Restoration Skill Advance', + {131} 'Enchanting Skill Advance', + {132} 'Left Weapon Speed Multiply', + {133} 'Dragon Souls', + {134} 'Combat Health Regen Multiply', + {135} 'One-Handed Power Modifier', + {136} 'Two-Handed Power Modifier', + {137} 'Marksman Power Modifier', + {138} 'Block Power Modifier', + {139} 'Smithing Power Modifier', + {140} 'Heavy Armor Power Modifier', + {141} 'Light Armor Power Modifier', + {142} 'Pickpocket Power Modifier', + {143} 'Lockpicking Power Modifier', + {144} 'Sneaking Power Modifier', + {145} 'Alchemy Power Modifier', + {146} 'Speechcraft Power Modifier', + {147} 'Alteration Power Modifier', + {148} 'Conjuration Power Modifier', + {149} 'Destruction Power Modifier', + {150} 'Illusion Power Modifier', + {151} 'Restoration Power Modifier', + {152} 'Enchanting Power Modifier', + {153} 'Dragon Rend', + {154} 'Attack Damage Mult', + {155} 'Heal Rate Mult', + {156} 'Magicka Rate Mult', + {157} 'Stamina Rate Mult', + {158} 'Werewolf Perks', + {159} 'Vampire Perks', + {160} 'Grab Actor Offset', + {161} 'Grabbed', + {162} 'Unknown 162', + {163} 'Reflect Damage' + ], [ + -1, 'None' + ]); + + wbSkillEnum := + wbEnum([ + 'Unknown 1', + 'Unknown 2', + 'Unknown 3', + 'Unknown 4', + 'Unknown 5', + 'Unknown 6', + 'One Handed', + 'Two Handed', + 'Archery', + 'Block', + 'Smithing', + 'Heavy Armor', + 'Light Armor', + 'Pickpocket', + 'Lockpicking', + 'Sneak', + 'Alchemy', + 'Speech', + 'Alteration', + 'Conjuration', + 'Destruction', + 'Illusion', + 'Restoration', + 'Enchanting' + ], [ + -1, 'None' + ]); + + wbCastEnum := wbEnum([ + {0} 'Constant Effect', + {1} 'Fire and Forget', + {2} 'Concentration', + {3} 'Scroll' + ]); + + wbTargetEnum := wbEnum([ + {0} 'Self', + {1} 'Touch', + {2} 'Aimed', + {3} 'Target Actor', + {4} 'Target Location' + ]); + + wbCastingSourceEnum := wbEnum([ + 'Left', + 'Right', + 'Voice', + 'Instant' + ]); + + wbCrimeTypeEnum := + wbEnum([ + 'Steal', + 'Pickpocket', + 'Trespass', + 'Attack', + 'Murder', + 'Escape Jail', + 'Werewolf Transformation' + ], [ + -1, 'None' + ]); + + wbActorValue := wbInteger('Actor Value', itS32, wbActorValueEnum); + + wbETYP := wbFormIDCk(ETYP, 'Equipment Type', [EQUP, NULL]); + wbETYPReq := wbFormIDCk(ETYP, 'Equipment Type', [EQUP, NULL], False, cpNormal, True); + + wbFormTypeEnum := wbEnum([], [ + 0, 'Activator', + 1, 'Armor', + 2, 'Book', + 3, 'Container', + 4, 'Door', + 5, 'Ingredient', + 6, 'Light', + 7, 'MiscItem', + 8, 'Static', + 9, 'Grass', + 10, 'Tree', + 12, 'Weapon', + 13, 'Actor', + 14, 'LeveledCharacter', + 15, 'Spell', + 16, 'Enchantment', + 17, 'Potion', + 18, 'LeveledItem', + 19, 'Key', + 20, 'Ammo', + 21, 'Flora', + 22, 'Furniture', + 23, 'Sound Marker', + 24, 'LandTexture', + 25, 'CombatStyle', + 26, 'LoadScreen', + 27, 'LeveledSpell', + 28, 'AnimObject', + 29, 'WaterType', + 30, 'IdleMarker', + 31, 'EffectShader', + 32, 'Projectile', + 33, 'TalkingActivator', + 34, 'Explosion', + 35, 'TextureSet', + 36, 'Debris', + 37, 'MenuIcon', + 38, 'FormList', + 39, 'Perk', + 40, 'BodyPartData', + 41, 'AddOnNode', + 42, 'MovableStatic', + 43, 'CameraShot', + 44, 'ImpactData', + 45, 'ImpactDataSet', + 46, 'Quest', + 47, 'Package', + 48, 'VoiceType', + 49, 'Class', + 50, 'Race', + 51, 'Eyes', + 52, 'HeadPart', + 53, 'Faction', + 54, 'Note', + 55, 'Weather', + 56, 'Climate', + 57, 'ArmorAddon', + 58, 'Global', + 59, 'Imagespace', + 60, 'Imagespace Modifier', + 61, 'Encounter Zone', + 62, 'Message', + 63, 'Constructible Object', + 64, 'Acoustic Space', + 65, 'Ragdoll', + 66, 'Script', + 67, 'Magic Effect', + 68, 'Music Type', + 69, 'Static Collection', + 70, 'Keyword', + 71, 'Location', + 72, 'Location Ref Type', + 73, 'Footstep', + 74, 'Footstep Set', + 75, 'Material Type', + 76, 'Actor Action', + 77, 'Music Track', + 78, 'Word of Power', + 79, 'Shout', + 80, 'Relationship', + 81, 'Equip Slot', + 82, 'Association Type', + 83, 'Outfit', + 84, 'Art Object', + 85, 'Material Object', + 87, 'Lighting Template', + 88, 'Shader Particle Geometry', + 89, 'Visual Effect', + 90, 'Apparatus', + 91, 'Movement Type', + 92, 'Hazard', + 93, 'SM Event Node', + 94, 'Sound Descriptor', + 95, 'Dual Cast Data', + 96, 'Sound Category', + 97, 'Soul Gem', + 98, 'Sound Output Model', + 99, 'Collision Layer', + 100, 'Scroll', + 101, 'ColorForm', + 102, 'Reverb Parameters' + ]); + + wbMiscStatEnum := wbEnum([], [ + Int64($FCDD5011), 'Animals Killed', + Int64($366D84CF), 'Armor Improved', + Int64($023497E6), 'Armor Made', + Int64($8E20D7C9), 'Assaults', + Int64($579FFA75), 'Automations Killed', + Int64($B9B50725), 'Backstabs', + Int64($ED6A0EF2), 'Barters', + Int64($CCB952CE), 'Books Read', + Int64($317E8B4C), 'Brawls Won', + Int64($1D79006B), 'Bribes', + Int64($3602DE8F), 'Bunnies Slaughtered', + Int64($53D9E9B5), 'Chests Looted', + Int64($683C1980), 'Civil War Quests Completed', + Int64($66CCC50A), 'College of Winterhold Quests Completed', + Int64($40B11EFE), 'Creatures Killed', + Int64($22D5BA38), 'Critical Strikes', + Int64($A930980F), 'Daedra Killed', + Int64($3558374B), 'Daedric Quests Completed', + Int64($37A76425), 'Dawnguard Quests Completed', + Int64($2BDAC36F), 'Days as a Vampire', + Int64($6E684590), 'Days as a Werewolf', + Int64($B6F118DB), 'Days Jailed', + Int64($3C626A90), 'Days Passed', + Int64($8556AD88), 'Diseases Contracted', + Int64($46D6FBBC), 'Dragon Souls Collected', + Int64($AA444695), 'Dungeons Cleared', + Int64($1A37F336), 'Eastmarch Bounty', + Int64($5AC3A8ED), 'Falkreath Bounty', + Int64($87B12ECC), 'Favorite School', + Int64($518BBC4E), 'Favorite Shout', + Int64($41DD77A6), 'Favorite Spell', + Int64($171C5391), 'Favorite Weapon', + Int64($4F041AA2), 'Fines Paid', + Int64($9311B22B), 'Food Eaten', + Int64($57C089F7), 'Gold Found', + Int64($D20EDA4F), 'Haafingar Bounty', + Int64($516C486D), 'Hjaalmarch Bounty', + Int64($B0A1E32E), 'Horses Owned', + Int64($EBAE35E8), 'Horses Stolen', + Int64($FA024018), 'Hours Slept', + Int64($CAD2ECA1), 'Hours Waiting', + Int64($527DF857), 'Houses Owned', + Int64($47B4A015), 'Ingredients Eaten', + Int64($CE842356), 'Ingredients Harvested', + Int64($7D2E57C0), 'Intimidations', + Int64($C21702B5), 'Items Pickpocketed', + Int64($82F190C2), 'Items Stolen', + Int64($6627464B), 'Jail Escapes', + Int64($3520E710), 'Largest Bounty', + Int64($8A24FDE2), 'Locations Discovered', + Int64($5829CC2E), 'Locks Picked', + Int64($88089979), 'Magic Items Made', + Int64($7EA26C2D), 'Main Quests Completed', + Int64($7187A208), 'Mauls', + Int64($98EE55DC), 'Misc Objectives Completed', + Int64($FA06230B), 'Most Gold Carried', + Int64($D37C6909), 'Murders', + Int64($22C2CBD0), 'Necks Bitten', + Int64($BEEBCC87), 'Nirnroots Found', + Int64($56CCFC54), 'NumVampirePerks', + Int64($76A1A5C0), 'NumWerewolfPerks', + Int64($F22A8133), 'People Killed', + Int64($47A78467), 'Persuasions', + Int64($F2BAC234), 'Pockets Picked', + Int64($17C64668), 'Poisons Mixed', + Int64($7D8F2EA6), 'Poisons Used', + Int64($4228DE85), 'Potions Mixed', + Int64($9631EC11), 'Potions Used', + Int64($DE6C73FE), 'Questlines Completed', + Int64($0D7B8B16), 'Quests Completed', + Int64($BB39399E), 'Shouts Learned', + Int64($731B5333), 'Shouts Mastered', + Int64($F921D8BA), 'Shouts Unlocked', + Int64($B1AE4792), 'Side Quests Completed', + Int64($ACE470D7), 'Skill Books Read', + Int64($F33130CE), 'Skill Increases', + Int64($B556CC52), 'Sneak Attacks', + Int64($A74CBE83), 'Soul Gems Used', + Int64($C2C9E233), 'Souls Trapped', + Int64($5EC89F1A), 'Spells Learned', + Int64($B251A346), 'Standing Stones Found', + Int64($05D45702), 'Stores Invested In', + Int64($D0FE7031), 'The Companions Quests Completed', + Int64($52BA68CB), 'The Dark Brotherhood Quests Completed', + Int64($3E267D77), 'The Pale Bounty', + Int64($69B48177), 'The Reach Bounty', + Int64($50A23F69), 'The Rift Bounty', + Int64($62B2E95D), 'Thieves'' Guild Quests Completed', + Int64($944CEA93), 'Times Jailed', + Int64($50AAB633), 'Times Shouted', + Int64($99BB86D8), 'Total Lifetime Bounty', + Int64($4C252391), 'Training Sessions', + Int64($7AEA9C2B), 'Trespasses', + Int64($A67626F4), 'Tribal Orcs Bounty', + Int64($41D4BC0F), 'Undead Killed', + Int64($F39260A1), 'Vampirism Cures', + Int64($61A5C5A9), 'Weapons Disarmed', + Int64($1D3BA844), 'Weapons Improved', + Int64($25F1EA25), 'Weapons Made', + Int64($38A2DD66), 'Werewolf Transformations', + Int64($4231FA4F), 'Whiterun Bounty', + Int64($92565767), 'Wings Plucked', + Int64($C7FC518D), 'Winterhold Bounty', + Int64($949FA7BC), 'Words of Power Learned', + Int64($2C6E3FC0), 'Words of Power Unlocked' + ]); + + wbAdvanceActionEnum := wbEnum([ + 'Normal Usage', + 'Power Attack', + 'Bash', + 'Lockpick Success', + 'Lockpick Broken' + ]); + + wbAlignmentEnum := + wbEnum([ + 'Good', + 'Neutral', + 'Evil', + 'Very Good', + 'Very Evil' + ]); + + wbCriticalStageEnum := + wbEnum([ + 'None', + 'Goo Start', + 'Goo End', + 'Disintegrate Start', + 'Disintegrate End' + ]); + + wbEFID := wbFormIDCk(EFID, 'Base Effect', [MGEF]); + + wbEFIT := + wbStructSK(EFIT, [3, 4], '', [ + wbFloat('Magnitude', cpNormal, True), + wbInteger('Area', itU32), + wbInteger('Duration', itU32) + ], cpNormal, True, nil, -1, wbEFITAfterLoad); + + wbCTDA := + wbRStructSK([0], 'Condition', [ + wbStructSK(CTDA, [3, 5, 6], '', [ + {0}wbInteger('Type', itU8, wbCtdaTypeToStr, wbCtdaTypeToInt, cpNormal, False, nil, wbCtdaTypeAfterSet), + {1}wbByteArray('Unused', 3, cpIgnore, False, wbNeverShow), + {2}wbUnion('Comparison Value', wbCTDACompValueDecider, [ + wbFloat('Comparison Value - Float'), + wbFormIDCk('Comparison Value - Global', [GLOB]) + ]), + {3}wbInteger('Function', itU16, wbCTDAFunctionToStr, wbCTDAFunctionToInt), + {4}wbByteArray('Unused', 2, cpIgnore, False, wbNeverShow), + {5}wbUnion('Parameter #1', wbCTDAParam1Decider, [ + wbByteArray('Unknown', 4), + wbByteArray('None', 4, cpIgnore).IncludeFlag(dfZeroSortKey), + wbInteger('Integer', itS32), + wbFloat('Float'), + wbInteger('Variable Name', itU32, wbCTDAParam1StringToString, wbCTDAParam1StringToInt), + wbInteger('Sex', itU32, wbSexEnum), + wbInteger('Actor Value', itS32, wbActorValueEnum), + wbInteger('Crime Type', itU32, wbCrimeTypeEnum), + wbInteger('Axis', itU32, wbAxisEnum), + wbInteger('Quest Stage (unused)', itS32).IncludeFlag(dfZeroSortKey), + wbInteger('Misc Stat', itU32, wbMiscStatEnum), + wbInteger('Alignment', itU32, wbAlignmentEnum), + wbFormIDCkNoReach('Equip Type', [EQUP]), + wbInteger('Form Type', itU32, wbFormTypeEnum), + wbInteger('Critical Stage', itU32, wbCriticalStageEnum), + wbFormIDCkNoReach('Object Reference', [NULL, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + wbFormIDCkNoReach('Inventory Object', [ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, SCRL, SLGM, INGR, FLST, LIGH, LVLI, COBJ]), + wbFormIDCkNoReach('Actor', [NULL, PLYR, ACHR, REFR]), + wbFormIDCkNoReach('Voice Type', [VTYP, FLST]), + wbFormIDCkNoReach('Idle', [IDLE]), + wbFormIDCkNoReach('Form List', [FLST]), + wbFormIDCkNoReach('Quest', [QUST]), + wbFormIDCkNoReach('Faction', [FACT]), + wbFormIDCkNoReach('Cell', [CELL]), + wbFormIDCkNoReach('Class', [CLAS]), + wbFormIDCkNoReach('Race', [RACE]), + wbFormIDCkNoReach('Actor Base', [NPC_]), + wbFormIDCkNoReach('Global', [GLOB]), + wbFormIDCkNoReach('Weather', [WTHR]), + wbFormIDCkNoReach('Package', [PACK]), + wbFormIDCkNoReach('Encounter Zone', [ECZN]), + wbFormIDCkNoReach('Perk', [PERK]), + wbFormIDCkNoReach('Owner', [NULL, FACT, NPC_]), + wbFormIDCkNoReach('Furniture', [FURN, FLST]), + wbFormIDCkNoReach('Effect Item', [SPEL, ENCH, ALCH, INGR, SCRL]), + wbFormIDCkNoReach('Base Effect', [MGEF]), + wbFormIDCkNoReach('Worldspace', [WRLD, FLST]), + wbInteger('VATS Value Function', itU32, wbVATSValueFunctionEnum), + wbInteger('VATS Value Param (INVALID)', itU32).IncludeFlag(dfZeroSortKey), + wbFormIDCkNoReach('Referenceable Object', [NULL, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, TACT, LVLI, LVSP, SPEL, SCRL, SHOU, SLGM, ENCH, FLOR, HAZD, FLST], + [NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, TACT, LVLI, LVSP, SPEL, SCRL, SHOU, SLGM, ENCH, FLOR, HAZD]), + wbFormIDCkNoReach('Region', [REGN]), + wbFormIDCkNoReach('Keyword', [KYWD, NULL]), + wbInteger('Player Action', itU32, wbAdvanceActionEnum), + wbInteger('Casting Type', itU32, wbCastingSourceEnum), + wbFormIDCkNoReach('Shout', [SHOU]), + wbFormIDCkNoReach('Location', [LCTN]), + wbFormIDCkNoReach('Location Ref Type', [LCRT]), + wbInteger('Alias', itS32, wbConditionAliasToStr, wbStrToAlias), + wbInteger('Packdata ID', itU32), + wbFormIDCk('Association Type', [ASTP]), + wbInteger('Furniture Anim', itU32, wbFurnitureAnimTypeEnum), + wbInteger('Furniture Entry', itU32, wbEnum([], [$010000, 'Front', $020000, 'Behind', $040000, 'Right', $80000, 'Left', $100000, 'Up'])), + wbFormIDCk('Scene', [NULL, SCEN]), + wbInteger('Ward State', itU32, wbWardStateEnum), + wbInteger('Event', itU32, wbEventFunctionAndMemberToStr, wbEventFunctionAndMemberToInt), + wbFormID('Event Data'), + wbFormIDCk('Knowable', [MGEF, WOOP, ENCH]) + ]), + {6}wbUnion('Parameter #2', wbCTDAParam2Decider, [ + wbByteArray('Unknown', 4), + wbByteArray('None', 4, cpIgnore).IncludeFlag(dfZeroSortKey), + wbInteger('Integer', itS32), + wbFloat('Float'), + wbInteger('Variable Name', itU32, wbCTDAParam2StringToString, wbCTDAParam2StringToInt), + wbInteger('Sex', itU32, wbSexEnum), + wbInteger('Actor Value', itS32, wbActorValueEnum), + wbInteger('Crime Type', itU32, wbCrimeTypeEnum), + wbInteger('Axis', itU32, wbAxisEnum), + wbInteger('Quest Stage', itS32, wbCTDAParam2QuestStageToStr, wbCTDAParam2QuestStageToInt), + wbInteger('Misc Stat', itU32, wbMiscStatEnum), + wbInteger('Alignment', itU32, wbAlignmentEnum), + wbFormIDCkNoReach('Equip Type', [EQUP]), + wbInteger('Form Type', itU32, wbFormTypeEnum), + wbInteger('Critical Stage', itU32, wbCriticalStageEnum), + wbFormIDCkNoReach('Object Reference', [NULL, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + wbFormIDCkNoReach('Inventory Object', [ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, SCRL, SLGM, INGR, FLST, LIGH, LVLI, COBJ]), + wbFormIDCkNoReach('Actor', [NULL, PLYR, ACHR, REFR]), + wbFormIDCkNoReach('Voice Type', [VTYP, FLST]), + wbFormIDCkNoReach('Idle', [IDLE]), + wbFormIDCkNoReach('Form List', [FLST]), + wbFormIDCkNoReach('Quest', [QUST]), + wbFormIDCkNoReach('Faction', [FACT]), + wbFormIDCkNoReach('Cell', [CELL]), + wbFormIDCkNoReach('Class', [CLAS]), + wbFormIDCkNoReach('Race', [RACE]), + wbFormIDCkNoReach('Actor Base', [NPC_]), + wbFormIDCkNoReach('Global', [GLOB]), + wbFormIDCkNoReach('Weather', [WTHR]), + wbFormIDCkNoReach('Package', [PACK]), + wbFormIDCkNoReach('Encounter Zone', [ECZN]), + wbFormIDCkNoReach('Perk', [PERK]), + wbFormIDCkNoReach('Owner', [NULL, FACT, NPC_]), + wbFormIDCkNoReach('Furniture', [FURN, FLST]), + wbFormIDCkNoReach('Effect Item', [SPEL, ENCH, ALCH, INGR, SCRL]), + wbFormIDCkNoReach('Base Effect', [MGEF]), + wbFormIDCkNoReach('Worldspace', [WRLD, FLST]), + wbInteger('VATS Value Function', itU32, wbVATSValueFunctionEnum), + wbUnion('VATS Value Param', wbCTDAParam2VATSValueParamDecider, [ + { 0} wbFormIDCkNoReach('Weapon', [WEAP]), + { 1} wbFormIDCkNoReach('Weapon List', [FLST], [WEAP]), + { 2} wbFormIDCkNoReach('Target', [NPC_]), + { 3} wbFormIDCkNoReach('Target List', [FLST], [NPC_]), + { 4} wbByteArray('Unknown', 4, cpIgnore), + { 5} wbInteger('Target Part', itS32, wbActorValueEnum), + { 6} wbInteger('VATS Action', itU32, wbEnum([ + 'Unarmed Attack', + 'One Hand Melee Attack', + 'Two Hand Melee Attack', + 'Magic Attack', + 'Ranged Attack', + 'Reload', + 'Crouch', + 'Stand', + 'Switch Weapon', + 'Toggle Weapon Drawn', + 'Heal', + 'Player Death' + ])), + { 7} wbByteArray('Unknown', 4, cpIgnore).IncludeFlag(dfZeroSortKey), + { 8} wbByteArray('Unknown', 4, cpIgnore).IncludeFlag(dfZeroSortKey), + { 9} wbFormIDCkNoReach('Critical Effect', [SPEL]), + {10} wbFormIDCkNoReach('Critical Effect List', [FLST], [SPEL]), + {11} wbByteArray('Unknown', 4, cpIgnore).IncludeFlag(dfZeroSortKey), + {12} wbByteArray('Unknown', 4, cpIgnore).IncludeFlag(dfZeroSortKey), + {13} wbByteArray('Unknown', 4, cpIgnore).IncludeFlag(dfZeroSortKey), + {14} wbByteArray('Unknown', 4, cpIgnore).IncludeFlag(dfZeroSortKey), + {15} wbInteger('Weapon Type', itU32, wbWeaponAnimTypeEnum), + {16} wbByteArray('Unknown', 4, cpIgnore).IncludeFlag(dfZeroSortKey), + {17} wbByteArray('Unknown', 4, cpIgnore).IncludeFlag(dfZeroSortKey), + {18} wbInteger('Projectile Type', itU32, wbEnum([ + 'Missile', + 'Lobber', + 'Beam', + 'Flame', + 'Cone', + 'Barrier', + 'Arrow' + ])), + {19} wbInteger('Delivery Type', itU32, wbTargetEnum), + {20} wbInteger('Casting Type', itU32, wbCastEnum) + ]), + wbFormIDCkNoReach('Referenceable Object', [NULL, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, TACT, FLST, LVLI, LVSP, SPEL, SCRL, SHOU, SLGM, ENCH], [NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, TACT, LVLI, LVSP, SPEL, SCRL, SHOU, SLGM, ENCH]), + wbFormIDCkNoReach('Region', [REGN]), + wbFormIDCkNoReach('Keyword', [KYWD, NULL]), + wbInteger('Player Action', itU32, wbAdvanceActionEnum), + wbInteger('Casting Type', itU32, wbCastingSourceEnum), + wbFormIDCkNoReach('Shout', [SHOU]), + wbFormIDCkNoReach('Location', [LCTN]), + wbFormIDCkNoReach('Location Ref Type', [LCRT]), + wbInteger('Alias', itS32, wbConditionAliasToStr, wbStrToAlias), + wbInteger('Packdata ID', itU32), + wbFormIDCk('Association Type', [ASTP]), + wbInteger('Furniture Anim', itU32, wbFurnitureAnimTypeEnum), + wbInteger('Furniture Entry', itU32, wbEnum([], [$010000, 'Front', $020000, 'Behind', $040000, 'Right', $80000, 'Left', $100000, 'Up'])), + wbFormIDCk('Scene', [NULL, SCEN]), + wbInteger('Ward State', itU32, wbWardStateEnum), + wbInteger('Event', itU32, wbEventFunctionAndMemberToStr, wbEventFunctionAndMemberToInt), + wbFormID('Event Data'), + wbFormIDCk('Knowable', [MGEF, WOOP, ENCH]) + ]), + {7}wbInteger('Run On', itU32, wbEnum([ + {0} 'Subject', + {1} 'Target', + {2} 'Reference', + {3} 'Combat Target', + {4} 'Linked Reference', + {5} 'Quest Alias', + {6} 'Package Data', + {7} 'Event Data' + ]), cpNormal, False, nil, wbCTDARunOnAfterSet), + {8}wbUnion('Reference', wbCTDAReferenceDecider, [ + wbInteger('Unused', itU32, nil, cpIgnore), + wbFormIDCkNoReach('Reference', [NULL, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False) + ]), + {9}wbInteger('Parameter #3', itS32, nil, cpNormal, False, nil, nil, -1) + ], cpNormal, False{, nil, 0, wbCTDAAfterLoad}), + wbString(CIS1, 'Parameter #1'), + wbString(CIS2, 'Parameter #2') + ], [], cpNormal).SetToStr(wbConditionToStr).IncludeFlag(dfCollapsed, wbCollapseConditions); + + wbCTDAs := wbRArray('Conditions', wbCTDA, cpNormal, False); + wbCTDAsCount := wbRArray('Conditions', wbCTDA, cpNormal, False, nil, wbCTDAsAfterSet); + wbCTDAsReq := wbRArray('Conditions', wbCTDA, cpNormal, True); + wbYNAM := wbFormIDCk(YNAM, 'Sound - Pick Up', [SNDR]); + wbZNAM := wbFormIDCk(ZNAM, 'Sound - Put Down', [SNDR]); + + var wbEffect := + wbRStruct('Effect', [ + wbEFID, + wbEFIT, + wbCTDAs + ], [], cpNormal, True); + + wbEffectsReq := + wbRArray('Effects', wbEffect, cpNormal, True); + + wbRecord(ALCH, 'Ingestible', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x20000000} 29, 'Medicine' + ])), [ + wbEDID, + wbOBND(True), + wbFULL, + wbKSIZ, + wbKWDAs, + wbDESC, + wbGenericModel, + wbDEST, + wbICON, + wbYNAM, + wbZNAM, + wbETYP, + wbFloat(DATA, 'Weight', cpNormal, True), + wbStruct(ENIT, 'Effect Data', [ + wbInteger('Value', itS32), + wbInteger('Flags', itU32, wbFlags([ + {0x00000001} 'No Auto-Calc', + {0x00000002} 'Food Item', + {0x00000004} 'Unknown 3', + {0x00000008} 'Unknown 4', + {0x00000010} 'Unknown 5', + {0x00000020} 'Unknown 6', + {0x00000040} 'Unknown 7', + {0x00000080} 'Unknown 8', + {0x00000100} 'Unknown 9', + {0x00000200} 'Unknown 10', + {0x00000400} 'Unknown 11', + {0x00000800} 'Unknown 12', + {0x00001000} 'Unknown 13', + {0x00002000} 'Unknown 14', + {0x00004000} 'Unknown 15', + {0x00008000} 'Unknown 16', + {0x00010000} 'Medicine', + {0x00020000} 'Poison' + ])), + wbFormID('Addiction'), + wbFloat('Addiction Chance'), + wbFormIDCk('Sound - Consume', [SNDR, NULL]) + ], cpNormal, True), + wbEffectsReq + ], False, nil, cpNormal, False, wbRemoveEmptyKWDA, wbKeywordsAfterSet); + + wbRecord(AMMO, 'Ammunition', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000004} 2, 'Non-Playable' + ])), [ + wbEDID, + wbOBND(True), + wbFULL, + wbGenericModel, + wbICON, + wbDEST, + wbYNAM, + wbZNAM, + wbDESC, + wbKSIZ, + wbKWDAs, + IsSSE( + wbStruct(DATA, 'Data', [ + wbFormIDCk('Projectile', [PROJ, NULL]), + wbInteger('Flags', itU32, wbFlags([ + 'Ignores Normal Weapon Resistance', + 'Non-Playable', + 'Non-Bolt' + ])), + wbFloat('Damage'), + wbInteger('Value', itU32), + wbFloat('Weight') + ], cpNormal, True, nil, 4), + wbStruct(DATA, 'Data', [ + wbFormIDCk('Projectile', [PROJ, NULL]), + wbInteger('Flags', itU32, wbFlags([ + 'Ignores Normal Weapon Resistance', + 'Non-Playable', + 'Non-Bolt' + ])), + wbFloat('Damage'), + wbInteger('Value', itU32) + ], cpNormal, True) + ), + wbString(ONAM, 'Short Name') + ], False, nil, cpNormal, False, wbRemoveEmptyKWDA, wbKeywordsAfterSet); + + wbRecord(ANIO, 'Animated Object', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000200} 9, 'Unknown 9' // always present in updated records, not in Skyrim.esm + ]), [9]), [ + wbEDID, + wbGenericModel, + wbString(BNAM, 'Unload Event') + ]).SetSummaryKey([1]); + + wbRecord(ARMO, 'Armor', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000004} 2, 'Non-Playable', + {0x00000040} 6, 'Shield', + {0x00000400} 10, 'Unknown 10', + {0x00008000} 15, 'Unknown 15' + ])), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbEITM, + wbInteger(EAMT, 'Enchantment Amount', itU16), + wbTexturedModel('Male world model', [MOD2, MO2T], wbMO2S), + wbICON, + wbTexturedModel('Female world model', [MOD4, MO4T], wbMO4S), + wbICO2, + wbBODTBOD2, + wbDEST, + wbYNAM, + wbZNAM, + wbString(BMCT, 'Ragdoll Constraint Template'), + wbETYP, + wbFormIDCk(BIDS, 'Bash Impact Data Set', [IPDS]), + wbFormIDCk(BAMT, 'Alternate Block Material', [MATT]), + wbFormIDCk(RNAM, 'Race', [RACE]), + wbKSIZ, + wbKWDAs, + wbDESC, + wbRArray('Armature', wbFormIDCK(MODL, 'Model FileName', [ARMA, NULL])), + wbStruct(DATA, 'Data', [ + wbInteger('Value', itS32), + wbFloat('Weight') + ], cpNormal, True), + wbInteger(DNAM, 'Armor Rating', itS32, wbDiv(100), cpNormal, True), + wbFormIDCk(TNAM, 'Template Armor', [ARMO]) + ], False, nil, cpNormal, False, wbARMOAfterLoad, wbKeywordsAfterSet); + + wbRecord(ARMA, 'Armor Addon', [ + wbEDID, + wbBODTBOD2, + wbFormIDCk(RNAM, 'Race', [RACE]), + wbStruct(DNAM, 'Data', [ + wbInteger('Male Priority', itU8), + wbInteger('Female Priority', itU8), + // essentialy a number of world models for different weights (Enabled = 2 models _0.nif and _1.nif) + wbInteger('Weight slider - Male', itU8, wbFlags([ + {0x01} 'Unknown 0', + {0x02} 'Enabled' + ])), + wbInteger('Weight slider - Female', itU8, wbFlags([ + {0x01} 'Unknown 0', + {0x02} 'Enabled' + ])), + wbByteArray('Unknown', 2), + wbInteger('Detection Sound Value', itU8), + wbByteArray('Unknown', 1), + wbFloat('Weapon Adjust') + ], cpNormal, True), + wbTexturedModel('Male world model', [MOD2, MO2T], wbMO2S), + wbTexturedModel('Female world model', [MOD3, MO3T], wbMO3S), + wbTexturedModel('Male 1st Person', [MOD4, MO4T], wbMO4S), + wbTexturedModel('Female 1st Person', [MOD5, MO5T], wbMO5S), + wbFormIDCK(NAM0, 'Male Skin Texture', [TXST, NULL]), + wbFormIDCK(NAM1, 'Female Skin texture', [TXST, NULL]), + wbFormIDCK(NAM2, 'Male Skin Texture Swap List', [FLST, NULL]), + wbFormIDCK(NAM3, 'Female Skin Texture Swap List', [FLST, NULL]), + wbRArrayS('Additional Races', wbFormIDCK(MODL, 'Race', [RACE, NULL])), + wbFormIDCk(SNDD, 'Footstep Sound', [FSTS, NULL]), + wbFormIDCk(ONAM, 'Art Object', [ARTO]) + ], False, nil, cpNormal, False, wbARMAAfterLoad).SetSummaryKey([4]); + + wbRecord(BOOK, 'Book', [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbGenericModel, + wbICON, + wbLStringKC(DESC, 'Book Text', 0, cpTranslate, True), + wbDEST, + wbYNAM, + wbZNAM, + wbKSIZ, + wbKWDAs, + wbStruct(DATA, 'Data', [ + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'Teaches Skill', + {0x02} 'Can''t be Taken', + {0x04} 'Teaches Spell', + {0x08} 'Unknown 4', + {0x10} 'Unknown 5', + {0x20} 'Unknown 6', + {0x40} 'Unknown 7', + {0x80} 'Unknown 8' + ])), + wbInteger('Type', itU8, wbEnum([], [ + 0, 'Book/Tome', 255, 'Note/Scroll' + ])), + wbByteArray('Unused', 2), + wbUnion('Teaches', wbBOOKTeachesDecider, [ + wbInteger('Skill', itS32, wbSkillEnum), + wbFormIDCk('Spell', [SPEL]) + ]), + wbInteger('Value', itU32), + wbFloat('Weight') + ], cpNormal, True), + wbFormIDCk(INAM, 'Inventory Art', [STAT]), + wbLString(CNAM, 'Description', 0, cpTranslate) + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); +end; + +procedure DefineTES5c; + + procedure ReferenceRecord(aSignature: TwbSignature; const aName: string); + begin + wbRefRecord(aSignature, aName, + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000080} 7, 'Turn Off Fire', + {0x00000400} 10, 'Persistent', + {0x00000800} 11, 'Initially Disabled', + {0x10000000} 28, 'Reflected By Auto Water', + {0x20000000} 29, 'Don''t Havok Settle', + {0x40000000} 30, 'No Respawn' + ], True, True)), [ + wbEDID, + wbVMAD, + wbFormIDCk(NAME, 'Projectile', [PROJ, HAZD]), + wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), + wbOwnership(wbXOWN, [XRGD]), + wbFloat(XHTW, 'Head-Tracking Weight'), + wbFloat(XFVC, 'Favor Cost'), + wbRArrayS('Reflected/Refracted By', + wbStructSK(XPWR, [0], 'Water', [ + wbFormIDCk('Reference', [REFR]), + wbInteger('Type', itU32, wbFlags([ + 'Reflection', + 'Refraction' + ])) + ], cpNormal, False, nil, 1) + ), + wbRArrayS('Linked References', wbStructSK(XLKR, [0], 'Linked Reference', [ + wbFormIDCk('Keyword/Ref', [KYWD, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), + wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]) + ], cpNormal, False, nil, 1)), + wbRStruct('Activate Parents', [ + wbInteger(XAPD, 'Flags', itU8, wbFlags([ + 'Parent Activate Only' + ], True)), + wbRArrayS('Activate Parent Refs', + wbStructSK(XAPR, [0], 'Activate Parent Ref', [ + wbFormIDCk('Reference', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + wbFloat('Delay') + ]) + ) + ], []), + wbXESP, + wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), + wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), + wbEmpty(XIS2, 'Ignored by Sandbox'), + wbArray(XLRT, 'Location Ref Type', wbFormIDCk('Ref', [LCRT, NULL])), + wbFormIDCk(XLRL, 'Location Reference', [LCRT, LCTN, NULL], False, cpBenignIfAdded), + wbXLOD, + wbXSCL, + wbDataPosRot + ], True, wbPlacedAddInfo); + end; + +begin +{>>> + Skrim has its own ref record for every projectile type + PARW 'Arrow' + PBEA 'Beam' + PFLA 'Flame' + PCON 'Cone' (voice) + PBAR 'Barrier' + PGRE 'Traps' + PHZD 'Hazards' + I guess all of them have the same structure +<<<} + ReferenceRecord(PARW, 'Placed Arrow'); + ReferenceRecord(PBAR, 'Placed Barrier'); + ReferenceRecord(PBEA, 'Placed Beam'); + ReferenceRecord(PCON, 'Placed Cone/Voice'); + ReferenceRecord(PFLA, 'Placed Flame'); + ReferenceRecord(PGRE, 'Placed Projectile'); + ReferenceRecord(PHZD, 'Placed Hazard'); + ReferenceRecord(PMIS, 'Placed Missile'); + + wbRecord(CELL, 'Cell', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000400} 10, 'Persistent', + {0x00020000} 17, 'Off Limits', + {0x00040000} 18, 'Compressed', + {0x00080000} 19, 'Can''t Wait' + ]), [18]), [ + wbEDID, + wbFULL, + {>>> + Flags can be itU8, but CELL\DATA has a critical role in various wbImplementation.pas routines + and replacing it with wbUnion generates error when setting for example persistent flag in REFR. + So let it always be an integer + <<<} + wbInteger(DATA, 'Flags', itU16, wbFlags([ + {0x0001} 'Is Interior Cell', + {0x0002} 'Has Water', + {0x0004} 'Can Travel From Here', + {0x0008} 'No LOD Water', + {0x0010} 'Unknown 5', + {0x0020} 'Public Area', + {0x0040} 'Hand Changed', + {0x0080} 'Show Sky', + {0x0100} 'Use Sky Lighting' + ]), cpNormal, True, False, nil, wbCELLDATAAfterSet), + wbCellGrid, + wbStruct(XCLL, 'Lighting', [ + wbByteColors('Ambient Color'), + wbByteColors('Directional Color'), + wbByteColors('Fog Color Near'), + wbFloat('Fog Near'), + wbFloat('Fog Far'), + wbInteger('Directional Rotation XY', itS32), + wbInteger('Directional Rotation Z', itS32), + wbFloat('Directional Fade'), + wbFloat('Fog Clip Distance'), + wbFloat('Fog Power'), + wbAmbientColors('Ambient Colors'), + wbByteColors('Fog Color Far'), + wbFloat('Fog Max'), + wbFloat('Light Fade Begin'), + wbFloat('Light Fade End'), + wbInteger('Inherits', itU32, wbFlags([ + {0x00000001}'Ambient Color', + {0x00000002}'Directional Color', + {0x00000004}'Fog Color', + {0x00000008}'Fog Near', + {0x00000010}'Fog Far', + {0x00000020}'Directional Rotation', + {0x00000040}'Directional Fade', + {0x00000080}'Clip Distance', + {0x00000100}'Fog Power', + {0x00000200}'Fog Max', + {0x00000400}'Light Fade Distances' + ])) + ], cpNormal, False, nil, 11), + + wbTVDT, + wbMaxHeightDataCELL, + wbFormIDCk(LTMP, 'Lighting Template', [LGTM, NULL], False, cpNormal, True), + wbByteArray(LNAM, 'Unknown', 0, cpIgnore), // leftover flags, they are now in XCLC + + {>>> XCLW sometimes has $FF7FFFFF and causes invalid floation point <<<} + wbFloat(XCLW, 'Water Height', cpNormal, False, 1, -1, nil, nil, 0, wbCELLXCLWGetConflictPriority), + //wbByteArray(XCLW, 'Water Height', 4), + wbString(XNAM, 'Water Noise Texture'), + wbArrayS(XCLR, 'Regions', wbFormIDCk('Region', [REGN])), + wbFormIDCk(XLCN, 'Location', [LCTN]), + wbByteArray(XWCN, 'Unknown', 0, cpIgnore), // leftover + wbByteArray(XWCS, 'Unknown', 0, cpIgnore), // leftover + wbStruct(XWCU, 'Water Velocity', [ + wbFloat('X Offset'), + wbFloat('Y Offset'), + wbFloat('Z Offset'), + wbByteArray('Unknown', 4), + wbFloat('X Angle'), + wbFloat('Y Angle'), + wbFloat('Z Angle'), + wbByteArray('Unknown', 0) + ]), + wbFormIDCk(XCWT, 'Water', [WATR]), + wbOwnership(wbXOWN, [XRGD]), + wbFormIDCk(XILL, 'Lock List', [FLST, NPC_]), + wbString(XWEM, 'Water Environment Map'), + wbFormIDCk(XCCM, 'Sky/Weather from Region', [REGN]), + wbFormIDCk(XCAS, 'Acoustic Space', [ASPC]), + wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), + wbFormIDCk(XCMO, 'Music Type', [MUSC]), + wbFormIDCk(XCIM, 'Image Space', [IMGS]) + ], True, wbCellAddInfo, cpNormal, False, wbCELLAfterLoad); + + + wbRecord(CLAS, 'Class', [ + wbEDID, + wbFULLReq, + wbDESCReq, + wbICON, + wbStruct(DATA, '', [ + wbByteArray('Unknown', 4), + wbInteger('Teaches', itS8, wbEnum([ + 'One Handed', + 'Two Handed', + 'Archery', + 'Block', + 'Smithing', + 'Heavy Armor', + 'Light Armor', + 'Pickpocket', + 'Lockpicking', + 'Sneak', + 'Alchemy', + 'Speech', + 'Alteration', + 'Conjuration', + 'Destruction', + 'Illusion', + 'Restoration', + 'Enchanting' + ])), + wbInteger('Maximum training level', itU8), + wbArray('Skill Weights', wbInteger('Weight', itU8), [ + 'One Handed', + 'Two Handed', + 'Archery', + 'Block', + 'Smithing', + 'Heavy Armor', + 'Light Armor', + 'Pickpocket', + 'Lockpicking', + 'Sneak', + 'Alchemy', + 'Speech', + 'Alteration', + 'Conjuration', + 'Destruction', + 'Illusion', + 'Restoration', + 'Enchanting' + ]), + wbFloat('Bleedout Default'), + wbInteger('Voice Points', itU32), + wbArray('Attribute Weights', wbInteger('Weight', itU8), [ + 'Health', + 'Magicka', + 'Stamina', + 'Unknown' + ]) + ], cpNormal, True) + ]); + + wbRecord(CLMT, 'Climate', [ + wbEDID, + wbArrayS(WLST, 'Weather Types', wbStructSK([0], 'Weather Type', [ + wbFormIDCk('Weather', [WTHR, NULL]), + wbInteger('Chance', itS32), + wbFormIDCk('Global', [GLOB, NULL]) + ])), + wbString(FNAM, 'Sun Texture'), + wbString(GNAM, 'Sun Glare Texture'), + wbGenericModel, + wbClimateTiming(wbClmtTime, wbClmtMoonsPhaseLength) + ]); + + wbRecord(SPGD, 'Shader Particle Geometry', [ + wbEDID, + wbStruct(DATA, 'Data', [ + wbFloat('Gravity Velocity'), + wbFloat('Rotation Velocity'), + wbFloat('Particle Size X'), + wbFloat('Particle Size Y'), + wbFloat('Center Offset Min'), + wbFloat('Center Offset Max'), + wbFloat('Initial Rotation Range'), + wbInteger('# of Subtextures X', itU32), + wbInteger('# of Subtextures Y', itU32), + wbInteger('Type', itU32, wbEnum([ + 'Rain', + 'Snow' + ])), + wbInteger('Box Size', itU32), + wbFloat('Particle Density') + ], cpNormal, True, nil, 10), + wbString(ICON, 'Particle Texture') + ]); + + wbRecord(RFCT, 'Visual Effect', [ + wbEDID, + wbStruct(DATA, 'Effect Data', [ + wbFormIDCK('Effect Art', [ARTO, NULL]), + wbFormIDCK('Shader', [EFSH, NULL]), + wbInteger('Flags', itU32, wbFlags([ + {0x00000001}'Rotate to Face Target', + {0x00000002}'Attach to Camera', + {0x00000004}'Inherit Rotation' + ])) + ], cpNormal, True) + ]); + + wbRecord(CONT, 'Container', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00008000} 15, 'Has Distant LOD', + {0x00010000} 16, 'Random Anim Start', + {0x02000000} 25, 'Obstacle', + {0x04000000} 26, 'NavMesh Generation - Filter', + {0x08000000} 27, 'NavMesh Generation - Bounding Box', + {0x40000000} 30, 'NavMesh Generation - Ground' + ])), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbGenericModel, + wbCOCT, + wbCNTOs, + wbDEST, + wbStruct(DATA, '', [ + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'Allow Sounds When Animation', + {0x02} 'Respawns', + {0x04} 'Show Owner' + ])), + wbFloat('Weight') + ], cpNormal, True), + wbFormIDCk(SNAM, 'Sound - Open', [SNDR]), + wbFormIDCk(QNAM, 'Sound - Close', [SNDR]) + ], True, nil, cpNormal, False, nil, wbContainerAfterSet); + + wbCSDT := wbRStructSK([0], 'Sound Type', [ + wbInteger(CSDT, 'Type', itU32,wbEnum([ + {00} 'Left Foot', + {01} 'Right Foot', + {02} 'Left Back Foot', + {03} 'Right Back Foot', + {04} 'Idle', + {05} 'Aware', + {06} 'Attack', + {07} 'Hit', + {08} 'Death', + {09} 'Weapon', + {10} 'Movement Loop', + {11} 'Conscious Loop', + {12} 'Auxiliary 1', + {13} 'Auxiliary 2', + {14} 'Auxiliary 3', + {15} 'Auxiliary 4', + {16} 'Auxiliary 5', + {17} 'Auxiliary 6', + {18} 'Auxiliary 7', + {19} 'Auxiliary 8', + {19} 'Auxiliary 8', + {20} 'Jump', + {21} 'PlayRandom/Loop' + ])), + wbSoundTypeSounds + ], []); + + wbCSDTs := wbRArrayS('Sound Types', wbCSDT, cpNormal, False, nil, nil, nil{wbActorTemplateUseModelAnimation}); + + wbAIDT := + wbStruct(AIDT, 'AI Data', [ + {00} wbInteger('Aggression', itU8, wbEnum([ + 'Unaggressive', + 'Aggressive', + 'Very Aggressive', + 'Frenzied' + ])), + {01} wbInteger('Confidence', itU8, wbEnum([ + 'Cowardly', + 'Cautious', + 'Average', + 'Brave', + 'Foolhardy' + ])), + {02} wbInteger('Energy Level', itU8), + {03} wbInteger('Responsibility', itU8, wbEnum([ + 'Any crime', + 'Violence against enemies', + 'Property crime only', + 'No crime' + ])), + {04} wbInteger('Mood', itU8, wbEnum([ + 'Neutral', + 'Angry', + 'Fear', + 'Happy', + 'Sad', + 'Surprised', + 'Puzzled', + 'Disgusted' + ])), + wbInteger('Assistance', itU8, wbEnum([ + 'Helps Nobody', + 'Helps Allies', + 'Helps Friends and Allies' + ])), + wbStruct('Aggro', [ + wbInteger('Aggro Radius Behavior', itU8, wbEnum(['False', 'True'])), + wbInteger('Unused', itU8, nil, nil, cpIgnore), + wbInteger('Warn', itU32), + wbInteger('Warn/Attack', itU32), + wbInteger('Attack', itU32) + ]) + ], cpNormal, True, nil{wbActorTemplateUseAIData}); + + wbAttackAnimationEnum := wbEnum([], [ + 26, 'AttackLeft', + 32, 'AttackRight', + 38, 'Attack3', + 44, 'Attack4', + 50, 'Attack5', + 56, 'Attack6', + 62, 'Attack7', + 68, 'Attack8', + 74, 'AttackLoop', + 80, 'AttackSpin', + 86, 'AttackSpin2', + 97, 'PlaceMine', + 103, 'PlaceMine2', + 109, 'AttackThrow', + 115, 'AttackThrow2', + 121, 'AttackThrow3', + 127, 'AttackThrow4', + 133, 'AttackThrow5', + 255, ' DEFAULT' + ]); + + wbRecord(CSTY, 'Combat Style', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00080000} 19, 'Allow Dual Wielding' + ])), [ + wbEDID, + wbStruct(CSGD, 'General', [ + wbFloat('Offensive Mult'), + wbFloat('Defensive Mult'), + wbFloat('Group Offensive Mult'), + // keep as separate floats, some elements can be omitted + wbFloat('Equipment Score Mult - Melee'), + wbFloat('Equipment Score Mult - Magic'), + wbFloat('Equipment Score Mult - Ranged'), + wbFloat('Equipment Score Mult - Shout'), + wbFloat('Equipment Score Mult - Unarmed'), + wbFloat('Equipment Score Mult - Staff'), + wbFloat('Avoid Threat Chance') + ], cpNormal, True, nil, 0), + wbUnknown(CSMD, cpIgnore), + wbStruct(CSME, 'Melee', [ + wbFloat('Attack Staggered Mult'), + wbFloat('Power Attack Staggered Mult'), + wbFloat('Power Attack Blocking Mult'), + wbFloat('Bash Mult'), + wbFloat('Bash Recoil Mult'), + wbFloat('Bash Attack Mult'), + wbFloat('Bash Power Attack Mult'), + wbFloat('Special Attack Mult') + ], cpNormal, False, nil, 0), + wbStruct(CSCR, 'Close Range', [ + wbFloat('Circle Mult'), + wbFloat('Fallback Mult'), + wbFloat('Flank Distance'), + wbFloat('Stalk Time') + ], cpNormal, False, nil, 0), + wbStruct(CSLR, 'Long Range', [ + wbFloat('Strafe Mult') + ], cpNormal, False), + wbStruct(CSFL, 'Flight', [ + wbFloat('Hover Chance'), + wbFloat('Dive Bomb Chance'), + wbFloat('Ground Attack Chance'), + wbFloat('Hover Time'), + wbFloat('Ground Attack Time'), + wbFloat('Perch Attack Chance'), + wbFloat('Perch Attack Time'), + wbFloat('Flying Attack Chance') + ], cpNormal, False, nil, 0), + wbInteger(DATA, 'Flags', itU32, wbFlags([ + {0x01} 'Dueling', + {0x02} 'Flanking', + {0x04} 'Allow Dual Wielding' + ]), cpNormal, False) + ]); +end; + +procedure DefineTES5d; +var + wbFactionRank: IwbRecordMemberDef; +begin + wbRecord(DIAL, 'Dialog Topic', [ + wbEDID, + wbFULL, + wbFloat(PNAM, 'Priority', cpNormal, True, 1, -1, nil, nil, 50.0), + wbFormIDCkNoReach(BNAM, 'Branch', [DLBR, NULL]), + wbFormIDCkNoReach(QNAM, 'Quest', [QUST, NULL], False, cpNormal, False), + wbStruct(DATA, 'Data', [ + // this should not be named Flags since TwbFile.BuildReachable + // expects Top-Level flag here from FNV + wbInteger('Topic Flags', itU8, wbFlags([ + 'Do All Before Repeating' + ]), cpNormal, True), + wbInteger('Category', itU8, wbEnum([ + {0} 'Topic', + {1} 'Favor', // only in DA14 quest topics + {2} 'Scene', + {3} 'Combat', + {4} 'Favors', + {5} 'Detection', + {6} 'Service', + {7} 'Miscellaneous' + ])), + wbInteger('Subtype', itU16, wbEnum([], [ + 0, 'Custom', + 1, 'ForceGreet', + 2, 'Rumors', + 3, 'Custom?', + 4, 'Intimidate', + 5, 'Flatter', + 6, 'Bribe', + 7, 'Ask Gift', + 8, 'Gift', + 9, 'Ask Favor', + 10, 'Favor', + 11, 'Show Relationships', + 12, 'Folow', + 13, 'Reject', + 14, 'Scene', + 15, 'Show', + 16, 'Agree', + 17, 'Refuse', + 18, 'ExitFavorState', + 19, 'MoralRefusal', + 20, 'FlyingMountLand', + 21, 'FlyingMountCancelLand', + 22, 'FlyingMountAcceptTarget', + 23, 'FlyingMountRejectTarget', + 24, 'FlyingMountNoTarget', + 25, 'FlyingMountDestinationReached', + 26, 'Attack', + 27, 'PowerAttack', + 28, 'Bash', + 29, 'Hit', + 30, 'Flee', + 31, 'Bleedout', + 32, 'AvoidThreat', + 33, 'Death', + 34, 'GroupStrategy', + 35, 'Block', + 36, 'Taunt', + 37, 'AllyKilled', + 38, 'Steal', + 39, 'Yield', + 40, 'AcceptYield', + 41, 'PickpocketCombat', + 42, 'Assault', + 43, 'Murder', + 44, 'AssaultNC', + 45, 'MurderNC', + 46, 'PickpocketNC', + 47, 'StealFromNC', + 48, 'TrespassAgainstNC', + 49, 'Trespass', + 50, 'WereTransformCrime', + 51, 'VoicePowerStartShort', + 52, 'VoicePowerStartLong', + 53, 'VoicePowerEndShort', + 54, 'VoicePowerEndLong', + 55, 'AlertIdle', + 56, 'LostIdle', + 57, 'NormalToAlert', + 58, 'AlertToCombat', + 59, 'NormalToCombat', + 60, 'AlertToNormal', + 61, 'CombatToNormal', + 62, 'CombatToLost', + 63, 'LostToNormal', + 64, 'LostToCombat', + 65, 'DetectFriendDie', + 66, 'ServiceRefusal', + 67, 'Repair', + 68, 'Travel', + 69, 'Training', + 70, 'BarterExit', + 71, 'RepairExit', + 72, 'Recharge', + 73, 'RechargeExit', + 74, 'TrainingExit', + 75, 'ObserveCombat', + 76, 'NoticeCorpse', + 77, 'TimeToGo', + 78, 'GoodBye', + 79, 'Hello', + 80, 'SwingMeleeWeapon', + 81, 'ShootBow', + 82, 'ZKeyObject', + 83, 'Jump', + 84, 'KnockOverObject', + 85, 'DestroyObject', + 86, 'StandonFurniture', + 87, 'LockedObject', + 88, 'PickpocketTopic', + 89, 'PursueIdleTopic', + 90, 'SharedInfo', + 91, 'PlayerCastProjectileSpell', + 92, 'PlayerCastSelfSpell', + 93, 'PlayerShout', + 94, 'Idle', + 95, 'EnterSprintBreath', + 96, 'EnterBowZoomBreath', + 97, 'ExitBowZoomBreath', + 98, 'ActorCollidewithActor', + 99, 'PlayerinIronSights', + 100, 'OutofBreath', + 101, 'CombatGrunt', + 102, 'LeaveWaterBreath' + ])) + ]), + wbString(SNAM, 'Subtype Name', 4), + wbInteger(TIFC, 'Info Count', itU32, nil, cpBenign), + wbArray(INOM, 'INFO Order (Masters only)', wbFormIDCk('INFO', [INFO], False, cpBenign).IncludeFlag(dfUseLoadOrder), 0, nil, nil, cpBenign).IncludeFlag(dfInternalEditOnly).IncludeFlag(dfDontSave).IncludeFlag(dfDontAssign), + wbArray(INOA, 'INFO Order (All previous modules)', wbFormIDCk('INFO', [INFO], False, cpBenign).IncludeFlag(dfUseLoadOrder), 0, nil, nil, cpBenign).IncludeFlag(dfInternalEditOnly).IncludeFlag(dfDontSave).IncludeFlag(dfDontAssign) + ]); + + wbRecord(DOOR, 'Door', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00008000} 15, 'Has Distant LOD', + {0x00010000} 16, 'Random Anim Start', + {0x00800000} 23, 'Is Marker' + ])), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbGenericModel, + wbDEST, + wbFormIDCk(SNAM, 'Sound - Open', [SNDR]), + wbFormIDCk(ANAM, 'Sound - Close', [SNDR]), + wbFormIDCk(BNAM, 'Sound - Loop', [SNDR]), + wbInteger(FNAM, 'Flags', itU8, wbFlags([ + '', + 'Automatic', + 'Hidden', + 'Minimal Use', + 'Sliding', + 'Do Not Open in Combat Search' + ]), cpNormal, True), + wbRArrayS('Random teleport destinations', wbFormIDCk(TNAM, 'Destination', [CELL, WRLD])) + ]); + + wbBlendModeEnum := wbEnum([ + '', + 'Zero', + 'One', + 'Source Color', + 'Source Inverse Color', + 'Source Alpha', + 'Source Inverted Alpha', + 'Dest Alpha', + 'Dest Inverted Alpha', + 'Dest Color', + 'Dest Inverse Color', + 'Source Alpha SAT' + ]); + + wbBlendOpEnum := wbEnum([ + '', + 'Add', + 'Subtract', + 'Reverse Subtract', + 'Minimum', + 'Maximum' + ]); + + wbZTestFuncEnum := wbEnum([ + '', + '', + '', + 'Equal To', + 'Normal', + 'Greater Than', + '', + 'Greater Than or Equal To', + 'Always Show' + ]); + + wbRecord(EFSH, 'Effect Shader', [ + wbEDID, + wbString(ICON, 'Fill Texture'), + wbString(ICO2, 'Particle Shader Texture'), + wbString(NAM7, 'Holes Texture'), + wbString(NAM8, 'Membrane Palette Texture'), + wbString(NAM9, 'Particle Palette Texture'), + wbStruct(DATA, '', [ + wbByteArray('Unknown', 4), + wbInteger('Membrane Shader - Source Blend Mode', itU32, wbBlendModeEnum), + wbInteger('Membrane Shader - Blend Operation', itU32, wbBlendOpEnum), + wbInteger('Membrane Shader - Z Test Function', itU32, wbZTestFuncEnum), + wbByteColors('Fill/Texture Effect - Color Key 1'), + wbFloat('Fill/Texture Effect - Alpha Fade In Time'), + wbFloat('Fill/Texture Effect - Full Alpha Time'), + wbFloat('Fill/Texture Effect - Alpha Fade Out Time'), + wbFloat('Fill/Texture Effect - Presistent Alpha Ratio'), + wbFloat('Fill/Texture Effect - Alpha Pulse Amplitude'), + wbFloat('Fill/Texture Effect - Alpha Pulse Frequency'), + wbFloat('Fill/Texture Effect - Texture Animation Speed (U)'), + wbFloat('Fill/Texture Effect - Texture Animation Speed (V)'), + wbFloat('Edge Effect - Fall Off'), + wbByteColors('Edge Effect - Color'), + wbFloat('Edge Effect - Alpha Fade In Time'), + wbFloat('Edge Effect - Full Alpha Time'), + wbFloat('Edge Effect - Alpha Fade Out Time'), + wbFloat('Edge Effect - Persistent Alpha Ratio'), + wbFloat('Edge Effect - Alpha Pulse Amplitude'), + wbFloat('Edge Effect - Alpha Pulse Frequency'), + wbFloat('Fill/Texture Effect - Full Alpha Ratio'), + wbFloat('Edge Effect - Full Alpha Ratio'), + wbInteger('Membrane Shader - Dest Blend Mode', itU32, wbBlendModeEnum), + wbInteger('Particle Shader - Source Blend Mode', itU32, wbBlendModeEnum), + wbInteger('Particle Shader - Blend Operation', itU32, wbBlendOpEnum), + wbInteger('Particle Shader - Z Test Function', itU32, wbZTestFuncEnum), + wbInteger('Particle Shader - Dest Blend Mode', itU32, wbBlendModeEnum), + wbFloat('Particle Shader - Particle Birth Ramp Up Time'), + wbFloat('Particle Shader - Full Particle Birth Time'), + wbFloat('Particle Shader - Particle Birth Ramp Down Time'), + wbFloat('Particle Shader - Full Particle Birth Ratio'), + wbFloat('Particle Shader - Persistant Particle Count'), + wbFloat('Particle Shader - Particle Lifetime'), + wbFloat('Particle Shader - Particle Lifetime +/-'), + wbFloat('Particle Shader - Initial Speed Along Normal'), + wbFloat('Particle Shader - Acceleration Along Normal'), + wbFloat('Particle Shader - Initial Velocity #1'), + wbFloat('Particle Shader - Initial Velocity #2'), + wbFloat('Particle Shader - Initial Velocity #3'), + wbFloat('Particle Shader - Acceleration #1'), + wbFloat('Particle Shader - Acceleration #2'), + wbFloat('Particle Shader - Acceleration #3'), + wbFloat('Particle Shader - Scale Key 1'), + wbFloat('Particle Shader - Scale Key 2'), + wbFloat('Particle Shader - Scale Key 1 Time'), + wbFloat('Particle Shader - Scale Key 2 Time'), + wbByteColors('Color Key 1 - Color'), + wbByteColors('Color Key 2 - Color'), + wbByteColors('Color Key 3 - Color'), + wbFloat('Color Key 1 - Color Alpha'), + wbFloat('Color Key 2 - Color Alpha'), + wbFloat('Color Key 3 - Color Alpha'), + wbFloat('Color Key 1 - Color Key Time'), + wbFloat('Color Key 2 - Color Key Time'), + wbFloat('Color Key 3 - Color Key Time'), + wbFloat('Particle Shader - Initial Speed Along Normal +/-'), + wbFloat('Particle Shader - Initial Rotation (deg)'), + wbFloat('Particle Shader - Initial Rotation (deg) +/-'), + wbFloat('Particle Shader - Rotation Speed (deg/sec)'), + wbFloat('Particle Shader - Rotation Speed (deg/sec) +/-'), + wbFormIDCk('Addon Models', [DEBR, NULL]), + wbFloat('Holes - Start Time'), + wbFloat('Holes - End Time'), + wbFloat('Holes - Start Val'), + wbFloat('Holes - End Val'), + wbFloat('Edge Width (alpha units)'), + wbByteColors('Edge Color'), + wbFloat('Explosion Wind Speed'), + wbInteger('Texture Count U', itU32), + wbInteger('Texture Count V', itU32), + wbFloat('Addon Models - Fade In Time'), + wbFloat('Addon Models - Fade Out Time'), + wbFloat('Addon Models - Scale Start'), + wbFloat('Addon Models - Scale End'), + wbFloat('Addon Models - Scale In Time'), + wbFloat('Addon Models - Scale Out Time'), + wbFormIDCk('Ambient Sound', [SNDR, SOUN, NULL]), + wbByteColors('Fill/Texture Effect - Color Key 2'), + wbByteColors('Fill/Texture Effect - Color Key 3'), + wbStruct('Fill/Texture Effect - Color Key Scale/Time', [ + wbFloat('Color Key 1 - Scale'), + wbFloat('Color Key 2 - Scale'), + wbFloat('Color Key 3 - Scale'), + wbFloat('Color Key 1 - Time'), + wbFloat('Color Key 2 - Time'), + wbFloat('Color Key 3 - Time') + ]), + wbFloat('Color Scale'), + wbFloat('Birth Position Offset'), + wbFloat('Birth Position Offset Range +/-'), + wbStruct('Particle Shader Animated', [ + wbInteger('Start Frame', itU32), + wbInteger('Start Frame Variation', itU32), + wbInteger('End Frame', itU32), + wbInteger('Loop Start Frame', itU32), + wbInteger('Loop Start Variation', itU32), + wbInteger('Frame Count', itU32), + wbInteger('Frame Count Variation', itU32) + ]), + wbInteger('Flags', itU32, wbFlags([ + 'No Membrane Shader', + 'Membrane Grayscale Color', + 'Membrane Grayscale Alpha', + 'No Particle Shader', + 'Edge Effect Inverse', + 'Affect Skin Only', + 'Ignore Alpha', + 'Project UVs', + 'Ignore Base Geometry Alpha', + 'Lighting', + 'No Weapons', + 'Unknown 11', + 'Unknown 12', + 'Unknown 13', + 'Unknown 14', + 'Particle Animated', + 'Particle Grayscale Color', + 'Particle Grayscale Alpha', + 'Unknown 18', + 'Unknown 19', + 'Unknown 20', + 'Unknown 21', + 'Unknown 22', + 'Unknown 23', + 'Use Blood Geometry' + ])), + wbFloat('Fill/Texture Effect - Texture Scale (U)'), + wbFloat('Fill/Texture Effect - Texture Scale (V)'), + wbInteger('Scene Graph Emit Depth Limit (unused)', itU32) + ], cpNormal, True, nil, 0) + ], False, nil, cpNormal, False, nil {wbEFSHAfterLoad}); + + wbRecord(ENCH, 'Object Effect', [ + wbEDID, + wbOBND(True), + wbFULL, + wbStruct(ENIT, 'Effect Data', [ + wbInteger('Enchantment Cost', itS32), + wbInteger('Flags', itU32, wbFlags([ + 'No Auto-Calc', + '', + 'Extend Duration On Recast' + ])), + wbInteger('Cast Type', itU32, wbCastEnum), + wbInteger('Enchantment Amount', itS32), + wbInteger('Target Type', itU32, wbTargetEnum), + wbInteger('Enchant Type', itU32, wbEnum([], [ + $06, 'Enchantment', + $0C, 'Staff Enchantment' + ])), + wbFloat('Charge Time'), + wbFormIDCk('Base Enchantment', [ENCH, NULL]), + wbFormIDCk('Worn Restrictions', [FLST, NULL]) + ], cpNormal, True, nil, 8), + wbEffectsReq + ]); + + wbRecord(EYES, 'Eyes', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000004} 2, 'Non-Playable' + ])), [ + wbEDID, + wbFULLReq, + wbString(ICON, 'Texture', 0, cpNormal, True), + wbInteger(DATA, 'Flags', itU8, wbFlags([ + {0x01}'Playable', + {0x02}'Not Male', + {0x04}'Not Female', + {0x08}'Unknown 4', + {0x10}'Unknown 5', + {0x20}'Unknown 6', + {0x40}'Unknown 7', + {0x80}'Unknown 8' + ]), cpNormal, True) + ]); + + wbFactionRank := + wbRStructSK([0], 'Rank', [ + wbInteger(RNAM, 'Rank#', itU32), + wbLString(MNAM, 'Male Title', 0, cpTranslate), + wbLString(FNAM, 'Female Title', 0, cpTranslate), + wbString(INAM, 'Insignia Unused') + ], []); + + wbRecord(FACT, 'Faction', [ + wbEDID, + wbFULL, + wbFactionRelations, + wbStruct(DATA, 'Flags', [ + wbInteger('Flags', itU32, wbFlags([ + {0x00000001}'Hidden From NPC', + {0x00000002}'Special Combat', + {0x00000004}'Unknown 3', + {0x00000008}'Unknown 4', + {0x00000010}'Unknown 5', + {0x00000020}'Unknown 6', + {0x00000040}'Track Crime', + {0x00000080}'Ignore Crimes: Murder', + {0x00000100}'Ignore Crimes: Assault', + {0x00000200}'Ignore Crimes: Stealing', + {0x00000400}'Ignore Crimes: Trespass', + {0x00000800}'Do Not Report Crimes Against Members', + {0x00001000}'Crime Gold - Use Defaults', + {0x00002000}'Ignore Crimes: Pickpocket', + {0x00004000}'Vendor', + {0x00008000}'Can Be Owner', + {0x00010000}'Ignore Crimes: Werewolf', + {0x00020000}'Unknown 18', + {0x00040000}'Unknown 19', + {0x00080000}'Unknown 20', + {0x00100000}'Unknown 21', + {0x00200000}'Unknown 22', + {0x00400000}'Unknown 23', + {0x00800000}'Unknown 24', + {0x01000000}'Unknown 25', + {0x02000000}'Unknown 26', + {0x04000000}'Unknown 27', + {0x08000000}'Unknown 28', + {0x10000000}'Unknown 29', + {0x20000000}'Unknown 30', + {0x40000000}'Unknown 31', + {0x80000000}'Unknown 32' + ])) + ], cpNormal, True, nil, 1), + wbFormIDCk(JAIL, 'Exterior Jail Marker', [REFR]), + wbFormIDCk(WAIT, 'Follower Wait Marker', [REFR]), + wbFormIDCk(STOL, 'Stolen Goods Container', [REFR]), + wbFormIDCk(PLCN, 'Player Inventory Container', [REFR]), + wbFormIDCk(CRGR, 'Shared Crime Faction List', [FLST]), + wbFormIDCk(JOUT, 'Jail Outfit', [OTFT]), + wbStruct(CRVA, 'Crime Values', [ + {01} wbInteger('Arrest', itU8, wbEnum(['False', 'True'])), + {02} wbInteger('Attack On Sight', itU8, wbEnum(['False', 'True'])), + {02} wbInteger('Murder', itU16), + {02} wbInteger('Assault', itU16), + {02} wbInteger('Trespass', itU16), + {02} wbInteger('Pickpocket', itU16), + {02} wbInteger('Unknown', itU16), + {02} wbFloat('Steal Multiplier'), + {02} wbInteger('Escape', itU16), + {02} wbInteger('Werewolf', itU16) + ], cpNormal, False, nil, 7), + wbRArrayS('Ranks', wbFactionRank), + wbFormIDCk(VEND, 'Vendor Buy/Sell List', [FLST]), + wbFormIDCk(VENC, 'Merchant Container', [REFR]), + wbStruct(VENV, 'Vendor Values', [ + {01} wbInteger('Start Hour', itU16), + {02} wbInteger('End Hour', itU16), + {02} wbInteger('Radius', itU16), + {02} wbByteArray('Unknown 1', 2), + wbInteger('Only Buys Stolen Items', itU8, wbEnum(['False', 'True'])), + wbInteger('Not/Sell Buy', itU8, wbEnum(['False', 'True'])), + {02} wbByteArray('Unknown 2', 2) + ]), + wbPLVD, + wbCITC, + wbCTDAsCount + ], False, nil, cpNormal, False, nil {wbFACTAfterLoad}, wbConditionsAfterSet); + + wbRecord(FURN, 'Furniture', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000080} 7, 'Is Perch', + {0x00008000} 15, 'Has Distant LOD', + {0x00010000} 16, 'Random Anim Start', + {0x00800000} 23, 'Is Marker', + {0x10000000} 28, 'Must Exit To Talk', + {0x20000000} 29, 'Child Can Use' + ])), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbGenericModel, + wbDEST, + wbKSIZ, + wbKWDAs, + wbUnknown(PNAM), + wbInteger(FNAM, 'Flags', itU16, wbFlags([ + {0x0001} 'Unknown 0', + {0x0002} 'Ignored By Sandbox' + ])), + wbFormIDCk(KNAM, 'Interaction Keyword', [KYWD, NULL]), + wbInteger(MNAM, 'Active Markers / Flags', itU32, wbFlags([ + {0x00000001} 'Sit 0', + {0x00000002} 'Sit 1', + {0x00000004} 'Sit 2', + {0x00000008} 'Sit 3', + {0x00000010} 'Sit 4', + {0x00000020} 'Sit 5', + {0x00000040} 'Sit 6', + {0x00000080} 'Sit 7', + {0x00000100} 'Sit 8', + {0x00000200} 'Sit 9', + {0x00000400} 'Sit 10', + {0x00000800} 'Sit 11', + {0x00001000} 'Sit 12', + {0x00002000} 'Sit 13', + {0x00004000} 'Sit 14', + {0x00008000} 'Sit 15', + {0x00010000} 'Sit 16', + {0x00020000} 'Sit 17', + {0x00040000} 'Sit 18', + {0x00080000} 'Sit 19', + {0x00100000} 'Sit 20', + {0x00200000} 'Sit 21', + {0x00400000} 'Sit 22', + {0x00800000} 'Sit 23', + {0x01000000} 'Unknown 25', + {0x02000000} 'Disables Activation', + {0x04000000} 'Is Perch', + {0x08000000} 'Must Exit to Talk', + {0x10000000} 'Unknown 29', + {0x20000000} 'Unknown 30', + {0x40000000} 'Unknown 31', + {0x80000000} 'Unknown 32' + ])), + wbStruct(WBDT, 'Workbench Data', [ + wbInteger('Bench Type', itU8, wbEnum([ + {0} 'None', + {1} 'Create object', + {2} 'Smithing Weapon', + {3} 'Enchanting', + {4} 'Enchanting Experiment', + {5} 'Alchemy', + {6} 'Alchemy Experiment', + {7} 'Smithing Armor' + ])), + wbInteger('Uses Skill', itS8, wbSkillEnum) + ]), + wbFormIDCk(NAM1, 'Associated Spell', [SPEL]), + wbRArray('Markers', wbRStruct('Marker', [ + wbInteger(ENAM, 'Marker Index', itU32), + wbStruct(NAM0, 'Disabled Entry Points', [ + wbByteArray('Unknown', 2), + wbInteger('Disabled Points', itU16, wbFurnitureEntryTypeFlags) + ]), + wbFormIDCk(FNMK, 'Marker Keyword', [KYWD, NULL]) + ], [])), + wbRArray('Marker Entry Points', wbStruct(FNPR, 'Marker', [ + wbInteger('Type', itU16, wbFurnitureAnimTypeEnum), + wbInteger('Entry Points', itU16, wbFurnitureEntryTypeFlags) + ])), + wbString(XMRK, 'Model FileName') + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); + +//---------------------------------------------------------------------------- +// For expansion to use wbGLOBUnionDecider to display Short, Long, Float +// correctly without making a signed float by default +//---------------------------------------------------------------------------- + wbRecord(GLOB, 'Global', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000040} 6, 'Constant' + ])), [ + wbEDID, + wbInteger(FNAM, 'Type', itU8, wbEnum([], [ + Ord('s'), 'Short', + Ord('l'), 'Long', + Ord('f'), 'Float' + ]), cpNormal, True).SetDefaultEditValue('Float'), + wbFloat(FLTV, 'Value', cpNormal, True) + ]); + + wbRecord(GMST, 'Game Setting', [ + wbString(EDID, 'Editor ID', 0, cpCritical, True, nil, wbGMSTEDIDAfterSet), + wbUnion(DATA, 'Value', wbGMSTUnionDecider, [ + wbLString('Name', 0, cpTranslate), + wbInteger('Int', itS32), + wbFloat('Float'), + wbInteger('Bool', itU32, wbEnum(['False', 'True'])) + ], cpNormal, True) + ]); + + wbRecord(KYWD, 'Keyword', [ + wbEDID, + wbCNAM + ]); +end; + +procedure DefineTES5e; +begin + wbRecord(LCRT, 'Location Reference Type', [ + wbEDID, + wbCNAM + ]); + + wbRecord(AACT, 'Action', [ + wbEDID, + wbCNAM + ]); + + wbRecord(TXST, 'Texture Set', [ + wbEDID, + wbOBND(True), + wbRStruct('Textures (RGB/A)', [ + wbString(TX00,'Diffuse'), + wbString(TX01,'Normal/Gloss'), + wbString(TX02,'Environment Mask/Subsurface Tint'), + wbString(TX03,'Glow/Detail Map'), + wbString(TX04,'Height'), + wbString(TX05,'Environment'), + wbString(TX06,'Multilayer'), + wbString(TX07,'Backlight Mask/Specular') + ], []).SetSummaryKey([0]), + wbDODT, + wbInteger(DNAM, 'Flags', itU16, wbFlags([ + {0x0001}'No Specular Map', + {0x0002}'Facegen Textures', + {0x0004}'Has Model Space Normal Map' + ]), cpNormal, False) + ]).SetSummaryKey([2, 3]); + + wbRecord(HDPT, 'Head Part', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000004} 2, 'Non-Playable' + ])), [ + wbEDID, + wbFULL, + wbGenericModel, + wbInteger(DATA, 'Flags', itU8, wbFlags([ + {0x01} 'Playable', + {0x02} 'Male', + {0x04} 'Female', + {0x10} 'Is Extra Part', + {0x20} 'Use Solid Tint' + ]), cpNormal, True), + wbInteger(PNAM, 'Type', itU32, wbEnum([ + 'Misc', + 'Face', + 'Eyes', + 'Hair', + 'Facial Hair', + 'Scar', + 'Eyebrows' + ])), + wbRArrayS('Extra Parts', + wbFormIDCk(HNAM, 'Part', [HDPT]) + ), + wbRArray('Parts', wbRStruct('Part', [ + wbInteger(NAM0, 'Part Type', itU32, wbEnum([ + 'Race Morph', + 'Tri', + 'Chargen Morph' + ])), + wbString(NAM1, 'FileName', 0, cpTranslate, True) + ], [])), + wbFormIDCk(TNAM, 'Texture Set', [TXST, NULL]), + wbFormIDCk(CNAM, 'Color', [CLFM, NULL]), + wbFormIDCk(RNAM, 'Valid Races', [FLST, NULL]) + ]); + + wbRecord(ASPC, 'Acoustic Space', [ + wbEDID, + wbOBND(True), + wbFormIDCk(SNAM, 'Ambient Sound', [SNDR]), + wbFormIDCk(RDAT, 'Use Sound from Region (Interiors Only)', [REGN]), + wbFormIDCk(BNAM, 'Environment Type (reverb)', [REVB]) + ]); + + wbRecord(MSTT, 'Moveable Static', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000100} 8, 'Must Update Anims', + {0x00000200} 9, 'Hidden From Local Map', + {0x00008000} 15, 'Has Distant LOD', + {0x00010000} 16, 'Random Anim Start', + {0x00080000} 19, 'Has Currents', + {0x02000000} 25, 'Obstacle', + {0x04000000} 26, 'NavMesh Generation - Filter', + {0x08000000} 27, 'NavMesh Generation - Bounding Box', + {0x40000000} 30, 'NavMesh Generation - Ground' + ])), [ + wbEDID, + wbOBND(True), + wbFULL, + wbGenericModel, + wbDEST, + wbInteger(DATA, 'Flags', itU8, wbFlags([ + 'On Local Map', + 'Unknown 1', + 'Unknown 2' + ]), cpNormal, True), + wbFormIDCk(SNAM, 'Looping Sound', [SNDR]) + ]); +end; + +procedure DefineTES5f; +begin + wbRecord(IDLM, 'Idle Marker', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x20000000} 29, 'Child Can Use' + ])), [ + wbEDID, + wbOBND(True), + wbInteger(IDLF, 'Flags', itU8, wbFlags([ + 'Run in Sequence', + 'Unknown 1', + 'Do Once', + 'Unknown 3', + 'Ignored by Sandbox' + ]), cpNormal, False), + wbInteger(IDLC, 'Animation Count', itU8, nil, cpBenign), + wbFloat(IDLT, 'Idle Timer Setting', cpNormal, False), + wbArray(IDLA, 'Animations', wbFormIDCk('Animation', [IDLE]), 0, nil, wbIDLAsAfterSet, cpNormal, False), + wbGenericModel + ], False, nil, cpNormal, False, nil, wbAnimationsAfterSet); + + wbRecord(PROJ, 'Projectile', [ + wbEDID, + wbOBND(True), + wbFULL, + wbGenericModel, + wbDEST, + wbStruct(DATA, 'Data', [ + {00} wbInteger('Flags', itU16, wbFlags([ + 'Hitscan', + 'Explosion', + 'Alt. Trigger', + 'Muzzle Flash', + '', + 'Can Be Disabled', + 'Can Be Picked Up', + 'Supersonic', + 'Pins Limbs', + 'Pass Through Small Transparent', + 'Disable Combat Aim Correction', + 'Rotation' + ])), + {02} wbInteger('Type', itU16, wbEnum([], [ + $01, 'Missile', + $02, 'Lobber', + $04, 'Beam', + $08, 'Flame', + $10, 'Cone', + $20, 'Barrier', + $40, 'Arrow' + ])), + {04} wbFloat('Gravity'), + {08} wbFloat('Speed'), + {12} wbFloat('Range'), + {16} wbFormIDCk('Light', [LIGH, NULL]), + {20} wbFormIDCk('Muzzle Flash - Light', [LIGH, NULL]), + {24} wbFloat('Tracer Chance'), + {28} wbFloat('Explosion - Alt. Trigger - Proximity'), + {32} wbFloat('Explosion - Alt. Trigger - Timer'), + {36} wbFormIDCk('Explosion', [EXPL, NULL]), + {40} wbFormIDCk('Sound', [SNDR, NULL]), + {44} wbFloat('Muzzle Flash - Duration'), + {48} wbFloat('Fade Duration'), + {52} wbFloat('Impact Force'), + {56} wbFormIDCk('Sound - Countdown', [SNDR, NULL]), + {60} wbFormIDCk('Sound - Disable', [SNDR, NULL]), + {64} wbFormIDCk('Default Weapon Source', [WEAP, NULL]), + {68} wbFloat('Cone Spread'), + {72} wbFloat('Collision Radius'), + {76} wbFloat('Lifetime'), + {80} wbFloat('Relaunch Interval'), + wbFormIDCk('Decal Data', [TXST, NULL]), + wbFormIDCk('Collision Layer', [COLL, NULL]) + ], cpNormal, True, nil, 22), + wbRStructSK([0], 'Muzzle Flash Model', [ + wbString(NAM1, 'Model FileName'), + wbModelInfo(NAM2) + ], [], cpNormal, True), + wbInteger(VNAM, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) + ]); + + wbRecord(HAZD, 'Hazard', [ + wbEDID, + wbOBND(True), + wbFULL, + wbGenericModel, + wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD, NULL]), + wbStruct(DATA, 'Data', [ + wbInteger('Limit', itU32), + wbFloat('Radius'), + wbFloat('Lifetime'), + wbFloat('Image Space Radius'), + wbFloat('Target Interval'), + wbInteger('Flags', itU32, wbFlags([ + {0x01} 'Affects Player Only', + {0x02} 'Inherit Duration from Spawn Spell', + {0x04} 'Align to Impact Normal', + {0x08} 'Inherit Radius from Spawn Spell', + {0x10} 'Drop to Ground' + ])), + wbFormIDCk('Spell', [SPEL, ENCH, NULL]), + wbFormIDCk('Light', [LIGH, NULL]), + wbFormIDCk('Impact Data Set', [IPDS, NULL]), + wbFormIDCk('Sound', [SNDR, NULL]) + ]) + ]); + + wbSoulGemEnum := wbEnum([ + {0} 'None', + {1} 'Petty', + {2} 'Lesser', + {3} 'Common', + {4} 'Greater', + {5} 'Grand' + ]); + + wbRecord(SLGM, 'Soul Gem', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00020000} 17, 'Can Hold NPC Soul' + ])), [ + wbEDID, + wbOBND, + wbFULL, + wbGenericModel, + wbICON, + wbDEST, + wbYNAM, + wbZNAM, + wbKSIZ, + wbKWDAs, + wbStruct(DATA, '', [ + wbInteger('Value', itU32), + wbFloat('Weight') + ], cpNormal, True), + wbInteger(SOUL, 'Contained Soul', itU8, wbSoulGemEnum, cpNormal, True), + wbInteger(SLCP, 'Maximum Capacity', itU8, wbSoulGemEnum, cpNormal, True), + wbFormIDCk(NAM0, 'Linked To', [SLGM]) + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); + + + if wbSimpleRecords then + wbNVNM := + wbStruct(NVNM, 'Geometry', [ + wbInteger('Version', itU32).SetDefaultNativeValue(12), + wbByteArray('Magic', 4).SetDefaultEditValue('3C A0 E9 A5'), + wbFormIDCk('Parent Worldspace', [WRLD, NULL]), + wbUnion('Parent', wbNVNMParentDecider, [ + wbStruct('Coordinates', [ + wbInteger('Grid Y', itS16), + wbInteger('Grid X', itS16) + ]), + wbFormIDCk('Parent Cell', [CELL]) + ]), + wbArray('Vertices', wbByteArray('Vertex', 12), -1).IncludeFlag(dfNotAlignable), + wbArray('Triangles', wbByteArray('Triangle', 16), -1).IncludeFlag(dfNotAlignable), + wbArray('Edge Links', + wbStruct('Edge Link', [ + wbByteArray('Unknown', 4), + wbFormIDCk('Mesh', [NAVM]), + wbInteger('Triangle', itS16) + ]) + , -1).IncludeFlag(dfNotAlignable), + wbArrayS('Door Triangles', + wbStructSK([0, 2], 'Door Triangle', [ + wbInteger('Triangle before door', itS16), + wbByteArray('Unknown', 4), + wbFormIDCk('Door', [REFR]) + ]) + , -1), + wbByteArray('NavMeshGrid') + ]) + else + wbNVNM := + wbStruct(NVNM, 'Geometry', [ + wbInteger('Version', itU32).SetDefaultNativeValue(12), + wbByteArray('Magic', 4).SetDefaultEditValue('3C A0 E9 A5'), + wbFormIDCk('Parent Worldspace', [WRLD, NULL]), + wbUnion('Parent', wbNVNMParentDecider, [ + wbStruct('Coordinates', [ + wbInteger('Grid Y', itS16), + wbInteger('Grid X', itS16) + ]), + wbFormIDCk('Parent Cell', [CELL]) + ]), + wbArray('Vertices', wbStructSK([0, 1, 2], 'Vertex', [ + wbFloat('X'), + wbFloat('Y'), + wbFloat('Z') + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), -1).IncludeFlag(dfNotAlignable), + wbArray('Triangles', + wbStruct('Triangle', [ + wbInteger('Vertex 0', itS16, wbVertexToStr0, wbVertexToInt0).SetLinksToCallback(wbVertexLinksTo), + wbInteger('Vertex 1', itS16, wbVertexToStr1, wbVertexToInt1).SetLinksToCallback(wbVertexLinksTo), + wbInteger('Vertex 2', itS16, wbVertexToStr2, wbVertexToInt2).SetLinksToCallback(wbVertexLinksTo), + wbInteger('Edge 0-1', itS16, wbEdgeToStr0, wbEdgeToInt0).SetLinksToCallback(wbEdgeLinksTo0), + wbInteger('Edge 1-2', itS16, wbEdgeToStr1, wbEdgeToInt1).SetLinksToCallback(wbEdgeLinksTo1), + wbInteger('Edge 2-0', itS16, wbEdgeToStr2, wbEdgeToInt1).SetLinksToCallback(wbEdgeLinksTo2), + wbInteger('Flags', itU16, wbFlags([ + 'Edge 0-1 link', // 0 $0001 1 + 'Edge 1-2 link', // 1 $0002 2 + 'Edge 2-0 link', // 2 $0004 4 + 'Deleted', // 3 $0008 8 added by CK Fixes to mark pseudo-deleted triangles + 'No Large Creatures', // 4 $0010 16 used in CK source according to Nukem + 'Overlapping', // 5 $0020 32 + 'Preferred', // 6 $0040 64 + '', // 7 $0080 128 + 'Unknown 9', // 8 $0100 256 used in CK source according to Nukem + 'Water', // 9 $0200 512 + 'Door', //10 $0400 1024 + 'Found', //11 $0800 2048 + 'Unknown 13', //12 $1000 4096 used in CK source according to Nukem + '', //13 $2000 \ + '', //14 $4000 |-- used as 3 bit counter inside CK, probably stripped before save + '' //15 $8000 / + ])), +{ Flags below are wrong. The first 4 bit are an enum as follows: +0000 = Open Edge No Cover +1000 = wall no cover +0100 = ledge cover +1100 = UNUSED +0010 = cover 64 +1010 = cover 80 +0110 = cover 96 +1110 = cover 112 +0001 = cover 128 +1001 = cover 144 +0101 = cover 160 +1101 = cover 176 +0011 = cover 192 +1011 = cover 208 +0111 = cover 224 +1111 = max cover +then 2 bit flags, then another such enum, and the rest is probably flags. +Can't properly represent that with current record definition methods. +} + wbInteger('Cover Flags', itU16, wbFlags([ + 'Edge 0-1 Cover Value 1/4', + 'Edge 0-1 Cover Value 2/4', + 'Edge 0-1 Cover Value 3/4', + 'Edge 0-1 Cover Value 4/4', + 'Edge 0-1 Left', + 'Edge 0-1 Right', + 'Edge 1-2 Cover Value 1/4', + 'Edge 1-2 Cover Value 2/4', + 'Edge 1-2 Cover Value 3/4', + 'Edge 1-2 Cover Value 4/4', + 'Edge 1-2 Left', + 'Edge 1-2 Right', + 'Unknown 13', + 'Unknown 14', + 'Unknown 15', + 'Unknown 16' + ])) + ]) + , -1).IncludeFlag(dfNotAlignable), + wbArray('Edge Links', + wbStruct('Edge Link', [ + wbByteArray('Unknown', 4, cpIgnore), + wbFormIDCk('Mesh', [NAVM], False, cpIgnore), + wbInteger('Triangle', itS16, nil, cpIgnore) + ], cpIgnore) + , -1, cpIgnore).IncludeFlag(dfNotAlignable), + wbArrayS('Door Triangles', + wbStructSK([0, 2], 'Door Triangle', [ + wbInteger('Triangle before door', itS16).SetLinksToCallback(wbTriangleLinksTo), + wbByteArray('Unknown', 4), + wbFormIDCk('Door', [REFR]) + ]) + , -1), + wbArray('Cover Triangles', + wbInteger('Triangle', itS16).SetLinksToCallback(wbTriangleLinksTo) + , -1).IncludeFlag(dfNotAlignable), + wbInteger('NavMeshGrid Divisor', itU32), + wbFloat('Max X Distance'), + wbFloat('Max Y Distance'), + wbFloat('Min X'), + wbFloat('Min Y'), + wbFloat('Min Z'), + wbFloat('Max X'), + wbFloat('Max Y'), + wbFloat('Max Z'), + wbArray('NavMeshGrid', + wbArray('NavMeshGridCell', + wbInteger('Triangle', itS16).SetLinksToCallback(wbTriangleLinksTo) + , -1).IncludeFlag(dfNotAlignable) + ).IncludeFlag(dfNotAlignable) // There are NavMeshGridSize^2 arrays to load + ]); + + wbRecord(NAVM, 'Navigation Mesh', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00040000} 18, 'Compressed', + {0x04000000} 26, 'AutoGen', + {0x80000000} 31, 'NavmeshGenCell' + ]), [18]), [ + wbEDID, + wbNVNM, + wbUnknown(ONAM), + wbUnknown(PNAM), + wbUnknown(NNAM) + ], False, wbNAVMAddInfo); + + + if wbSimpleRecords then + wbNAVIslandData := + wbStruct('Island Data', [ + wbByteArray('Unknown', 24), + wbArray('Triangles', wbByteArray('Triangle', 6), -1), + wbArray('Vertices', wbByteArray('Vertex', 12), -1) + ]) + else + wbNAVIslandData := + wbStruct('Island Data', [ + wbFloat('Min X'), + wbFloat('Min Y'), + wbFloat('Min Z'), + wbFloat('Max X'), + wbFloat('Max Y'), + wbFloat('Max Z'), + wbArray('Triangles', + wbStruct('Triangle', [ + wbArray('Vertices', wbInteger('Vertex', itS16), 3).IncludeFlag(dfNotAlignable) + ]) + , -1).IncludeFlag(dfNotAlignable), + wbArray('Vertices', wbStruct('Vertex', [ + wbFloat('X'), + wbFloat('Y'), + wbFloat('Z') + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), -1).IncludeFlag(dfNotAlignable) + ]); + + wbRecord(NAVI, 'Navigation Mesh Info Map', [ + wbEDID, + wbInteger(NVER, 'Version', itU32), + wbRArray('Navigation Map Infos', + wbStruct(NVMI, 'Navigation Map Info', [ + wbFormIDCk('Navigation Mesh', [NAVM]), + wbByteArray('Unknown', 4), + wbFloat('X'), + wbFloat('Y'), + wbFloat('Z'), + wbInteger('Preferred Merges Flag', itU32), + wbArray('Merged To', wbFormIDCk('Mesh', [NAVM]), -1), + wbArray('Preferred Merges', wbFormIDCk('Mesh', [NAVM]), -1), + wbArray('Linked Doors', wbStruct('Door', [ + wbByteArray('Unknown', 4), + wbFormIDCk('Door Ref', [REFR]) + ]), -1), + wbInteger('Is Island', itU8, wbEnum(['False', 'True'])), + wbUnion('Island', wbNAVIIslandDataDecider, [ + wbNull, + wbNAVIslandData + ]), + wbByteArray('Unknown', 4), + wbFormIDCk('Parent Worldspace', [WRLD, NULL]), + wbUnion('Parent', wbNAVIParentDecider, [ + wbStruct('Coordinates', [ + wbInteger('Grid Y', itS16), + wbInteger('Grid X', itS16) + ]), + wbFormIDCk('Parent Cell', [CELL]) + ]) + ]) + ), + wbStruct(NVPP, 'Preferred Pathing', [ + wbArray('NavMeshes', wbArray('Set', wbFormIDCk('', [NAVM]), -1), -1), + wbArray('NavMesh Tree?', wbStruct('', [ + wbFormIDCk('NavMesh', [NAVM]), + wbInteger('Index/Node', itU32) + ]), -1) + ]), + wbArray(NVSI, 'Unknown', wbFormIDCk('Navigation Mesh', [NAVM])) + ]); + +end; + +procedure DefineTES5g; +begin + wbRecord(EXPL, 'Explosion', [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbGenericModel, + wbEITM, + wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD]), + wbStruct(DATA, 'Data', [ // Contradicted by FireStormExplosion02 [EXPL:000877F9] + wbFormIDCk('Light', [LIGH, NULL]), + wbFormIDCk('Sound 1', [SNDR, NULL]), + wbFormIDCk('Sound 2', [SNDR, NULL]), + wbFormIDCk('Impact Data Set', [IPDS, NULL]), + wbFormID('Placed Object'), + wbFormIDCk('Spawn Projectile', [PROJ, NULL]), + wbFloat('Force'), + wbFloat('Damage'), + wbFloat('Radius'), + wbFloat('IS Radius'), + wbFloat('Vertical Offset Mult'), + wbInteger('Flags', itU32, wbFlags([ + 'Unknown 0', + 'Always Uses World Orientation', + 'Knock Down - Always', + 'Knock Down - By Formula', + 'Ignore LOS Check', + 'Push Explosion Source Ref Only', + 'Ignore Image Space Swap', + 'Chain', + 'No Controller Vibration' + ])), + wbInteger('Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) + ], cpNormal, True, nil, 10) + ]); + + wbRecord(DEBR, 'Debris', [ + wbEDID, + wbRArray('Models', wbDebrisModel(wbMODT), cpNormal, True) + ]); + + wbRecord(IMGS, 'Image Space', [ + wbEDID, + wbUnknown(ENAM, cpIgnore), + wbStruct(HNAM, 'HDR', [ + wbFloat('Eye Adapt Speed'), + wbFloat('Bloom Blur Radius'), + wbFloat('Bloom Threshold'), + wbFloat('Bloom Scale'), + wbFloat('Receive Bloom Threshold'), + wbFloat('White'), + wbFloat('Sunlight Scale'), + wbFloat('Sky Scale'), + wbFloat('Eye Adapt Strength') + ]), + wbStruct(CNAM, 'Cinematic', [ + wbFloat('Saturation'), + wbFloat('Brightness'), + wbFloat('Contrast') + ]), + wbStruct(TNAM, 'Tint', [ + wbFloat('Amount'), + wbFloatColors('Color') + ]), + wbStruct(DNAM, 'Depth of Field', [ + wbFloat('Strength'), + wbFloat('Distance'), + wbFloat('Range'), + wbByteArray('Unknown', 2), + wbInteger('Sky / Blur Radius', itU16, wbEnum([], [ + 16384, 'Radius 0', + 16672, 'Radius 1', + 16784, 'Radius 2', + 16848, 'Radius 3', + 16904, 'Radius 4', + 16936, 'Radius 5', + 16968, 'Radius 6', + 17000, 'Radius 7', + 16576, 'No Sky, Radius 0', + 16736, 'No Sky, Radius 1', + 16816, 'No Sky, Radius 2', + 16880, 'No Sky, Radius 3', + 16920, 'No Sky, Radius 4', + 16952, 'No Sky, Radius 5', + 16984, 'No Sky, Radius 6', + 17016, 'No Sky, Radius 7' + ])) + ], cpNormal, False, nil, 3) + ]); + + wbRecord(IMAD, 'Image Space Adapter', [ + wbEDID, + wbStruct(DNAM, 'Data Count', [ + wbInteger('Animatable', itU32, wbEnum(['False', 'True'])), + wbFloat('Duration'), + wbStruct('HDR', [ + wbInteger('Eye Adapt Speed Mult', itU32), + wbInteger('Eye Adapt Speed Add', itU32), + wbInteger('Bloom Blur Radius Mult', itU32), + wbInteger('Bloom Blur Radius Add', itU32), + wbInteger('Bloom Threshold Mult', itU32), + wbInteger('Bloom Threshold Add', itU32), + wbInteger('Bloom Scale Mult', itU32), + wbInteger('Bloom Scale Add', itU32), + wbInteger('Target Lum Min Mult', itU32), + wbInteger('Target Lum Min Add', itU32), + wbInteger('Target Lum Max Mult', itU32), + wbInteger('Target Lum Max Add', itU32), + wbInteger('Sunlight Scale Mult', itU32), + wbInteger('Sunlight Scale Add', itU32), + wbInteger('Sky Scale Mult', itU32), + wbInteger('Sky Scale Add', itU32) + ]), + wbInteger('Unknown08 Mult', itU32), + wbInteger('Unknown48 Add', itU32), + wbInteger('Unknown09 Mult', itU32), + wbInteger('Unknown49 Add', itU32), + wbInteger('Unknown0A Mult', itU32), + wbInteger('Unknown4A Add', itU32), + wbInteger('Unknown0B Mult', itU32), + wbInteger('Unknown4B Add', itU32), + wbInteger('Unknown0C Mult', itU32), + wbInteger('Unknown4C Add', itU32), + wbInteger('Unknown0D Mult', itU32), + wbInteger('Unknown4D Add', itU32), + wbInteger('Unknown0E Mult', itU32), + wbInteger('Unknown4E Add', itU32), + wbInteger('Unknown0F Mult', itU32), + wbInteger('Unknown4F Add', itU32), + wbInteger('Unknown10 Mult', itU32), + wbInteger('Unknown50 Add', itU32), + wbStruct('Cinematic', [ + wbInteger('Saturation Mult', itU32), + wbInteger('Saturation Add', itU32), + wbInteger('Brightness Mult', itU32), + wbInteger('Brightness Add', itU32), + wbInteger('Contrast Mult', itU32), + wbInteger('Contrast Add', itU32) + ]), + wbInteger('Unknown14 Mult', itU32), + wbInteger('Unknown54 Add', itU32), + wbInteger('Tint Color', itU32), + wbInteger('Blur Radius', itU32), + wbInteger('Double Vision Strength', itU32), + wbInteger('Radial Blur Strength', itU32), + wbInteger('Radial Blur Ramp Up', itU32), + wbInteger('Radial Blur Start', itU32), + wbInteger('Radial Blur Flags', itU32, wbFlags(['Use Target'])), + wbFloat('Radial Blur Center X'), + wbFloat('Radial Blur Center Y'), + wbInteger('DoF Strength', itU32), + wbInteger('DoF Distance', itU32), + wbInteger('DoF Range', itU32), + wbInteger('DoF Use Target', itU8, wbBoolEnum), + wbInteger('DoF Flags', itU8, wbFlags([ + {0x00000001} 'Mode - Front', + {0x00000002} 'Mode - Back', + {0x00000004} 'No Sky', + {0x00000008} 'Blur Radius Bit 2', + {0x00000010} 'Blur Radius Bit 1', + {0x00000020} 'Blur Radius Bit 0' + ])), + wbInteger('Unused', itU16), + wbInteger('Radial Blur Ramp Down', itU32), + wbInteger('Radial Blur Down Start', itU32), + wbInteger('Fade Color', itU32), + wbInteger('Motion Blur Strength', itU32) + ]), + wbTimeInterpolators(BNAM, 'Blur Radius'), + wbTimeInterpolators(VNAM, 'Double Vision Strength'), + wbArray(TNAM, 'Tint Color', wbColorInterpolator), + wbArray(NAM3, 'Fade Color', wbColorInterpolator), + wbRStruct('Radial Blur', [ + wbTimeInterpolators(RNAM, 'Strength'), + wbTimeInterpolators(SNAM, 'Ramp Up'), + wbTimeInterpolators(UNAM, 'Start'), + wbTimeInterpolators(NAM1, 'Ramp Down'), + wbTimeInterpolators(NAM2, 'Down Start') + ], []), + wbRStruct('Depht of Field', [ + wbTimeInterpolators(WNAM, 'Strength'), + wbTimeInterpolators(XNAM, 'Distance'), + wbTimeInterpolators(YNAM, 'Range') + ], []), + wbTimeInterpolators(NAM4, 'Motion Blur Strength'), + wbRStruct('HDR', [ + wbTimeInterpolatorsMultAdd(_00_IAD, _40_IAD, 'Eye Adapt Speed'), + wbTimeInterpolatorsMultAdd(_01_IAD, _41_IAD, 'Bloom Blur Radius'), + wbTimeInterpolatorsMultAdd(_02_IAD, _42_IAD, 'Bloom Threshold'), + wbTimeInterpolatorsMultAdd(_03_IAD, _43_IAD, 'Bloom Scale'), + wbTimeInterpolatorsMultAdd(_04_IAD, _44_IAD, 'Target Lum Min'), + wbTimeInterpolatorsMultAdd(_05_IAD, _45_IAD, 'Target Lum Max'), + wbTimeInterpolatorsMultAdd(_06_IAD, _46_IAD, 'Sunlight Scale'), + wbTimeInterpolatorsMultAdd(_07_IAD, _47_IAD, 'Sky Scale') + ], []), + wbTimeInterpolators(_08_IAD, 'Unused'), + wbTimeInterpolators(_48_IAD, 'Unused'), + wbTimeInterpolators(_09_IAD, 'Unused'), + wbTimeInterpolators(_49_IAD, 'Unused'), + wbTimeInterpolators(_0A_IAD, 'Unused'), + wbTimeInterpolators(_4A_IAD, 'Unused'), + wbTimeInterpolators(_0B_IAD, 'Unused'), + wbTimeInterpolators(_4B_IAD, 'Unused'), + wbTimeInterpolators(_0C_IAD, 'Unused'), + wbTimeInterpolators(_4C_IAD, 'Unused'), + wbTimeInterpolators(_0D_IAD, 'Unused'), + wbTimeInterpolators(_4D_IAD, 'Unused'), + wbTimeInterpolators(_0E_IAD, 'Unused'), + wbTimeInterpolators(_4E_IAD, 'Unused'), + wbTimeInterpolators(_0F_IAD, 'Unused'), + wbTimeInterpolators(_4F_IAD, 'Unused'), + wbTimeInterpolators(_10_IAD, 'Unused'), + wbTimeInterpolators(_50_IAD, 'Unused'), + wbCinematicIMAD + ]); + + wbRecord(FLST, 'FormID List', [ + wbString(EDID, 'Editor ID', 0, cpBenign, True, nil, wbFLSTEDIDAfterSet), + wbRArrayS('FormIDs', wbFormID(LNAM, 'FormID'), cpNormal, False, nil, nil, nil, wbFLSTLNAMIsSorted) + ]); + + var wbPerkConditions := + wbRStructSK([0], 'Perk Condition', [ + wbInteger(PRKC, 'Run On (Tab Index)', itS8{, wbPRKCToStr, wbPRKCToInt}), + wbCTDAsReq + ], [], cpNormal, False{, nil, nil, wbPERKPRKCDontShow}); + + var wbPerkEffect := + wbRStructSK([0, 1], 'Effect', [ + wbStructSK(PRKE, [1, 2, 0], 'Header', [ + wbPerkEffectType(wbPERKPRKETypeAfterSet), + wbInteger('Rank', itU8), + wbInteger('Priority', itU8) + ]), + wbUnion(DATA, 'Effect Data', wbPerkDATADecider, [ + wbStructSK([0, 1], 'Quest + Stage', [ + wbFormIDCk('Quest', [QUST]), + wbInteger('Quest Stage', itU8, wbPerkDATAQuestStageToStr, wbCTDAParam2QuestStageToInt), + wbByteArray('Unused', 3) + ]), + wbFormIDCk('Ability', [SPEL]), + wbStructSK([0, 1], 'Entry Point', [ + wbInteger('Entry Point', itU8, wbEntryPointsEnum, cpNormal, True, nil{, wbPERKEntryPointAfterSet}), + wbInteger('Function', itU8, wbEnum([ + {0} 'Unknown 0', + {1} 'Set Value', // EPFT=1 + {2} 'Add Value', // EPFT=1 + {3} 'Multiply Value', // EPFT=1 + {4} 'Add Range To Value', // EPFT=2 + {5} 'Add Actor Value Mult', // EPFT=2 + {6} 'Absolute Value', // no params + {7} 'Negative Absolute Value', // no params + {8} 'Add Leveled List', // EPFT=3 + {9} 'Add Activate Choice', // EPFT=4 + {10} 'Select Spell', // EPFT=5 + {11} 'Select Text', // EPFT=6 + {12} 'Set to Actor Value Mult', // EPFT=2 + {13} 'Multiply Actor Value Mult', // EPFT=2 + {14} 'Multiply 1 + Actor Value Mult', // EPFT=2 + {15} 'Set Text' // EPFT=7 + ])), + wbInteger('Perk Condition Tab Count', itU8, nil, cpIgnore) + ]) + ], cpNormal, True), + + wbRArrayS('Perk Conditions', wbPerkConditions), + + wbRStruct('Function Parameters', [ + wbInteger(EPFT, 'Type', itU8, wbEnum([ + {0} 'None', + {1} 'Float', + {2} 'Float/AV,Float', + {3} 'LVLI', + {4} 'SPEL,lstring,flags', + {5} 'SPEL', + {6} 'string', + {7} 'lstring' + ])), + // case(EPFT) of + // 1: EPFD=float + // 2: EPFD=float,float + // 3: EPFD=LVLI + // 4: EPFD=SPEL, EPF2=lstring, EPF3=int32 flags + // 5: EPFD=SPEL + // 6: EPFD=string + // 7: EPFD=lstring + wbLString(EPF2, 'Button Label', 0, cpTranslate), + wbStruct(EPF3, 'Script Flags', [ + wbInteger('Script Flags', itU16, wbFlags([ + 'Run Immediately', + 'Replace Default' + ])), + wbInteger('Fragment Index', itU16) + ]), + wbUnion(EPFD, 'Data', wbEPFDDecider, [ + {0} wbByteArray('Unknown'), + {1} wbFloat('Float'), + {2} wbStruct('Float, Float', [ + wbFloat('Float 1'), + wbFloat('Float 2') + ]), + {3} wbFormIDCk('Leveled Item', [LVLI]), + {4} wbFormIDCk('Spell', [SPEL]), + {5} wbFormIDCk('Spell', [SPEL]), + {6} wbString('Text', 0, cpTranslate), + {7} wbLString('Text', 0, cpTranslate), + {8} wbStruct('Actor Value, Float', [ + wbInteger('Actor Value', itU32, wbEPFDActorValueToStr, wbEPFDActorValueToInt), + wbFloat('Float') + ]) + ], cpNormal, False{, wbEPFDDontShow}) + ], [], cpNormal, False{, wbPERKPRKCDontShow}), + wbEmpty(PRKF, 'End Marker', cpIgnore, True) + ], []); + + wbRecord(PERK, 'Perk', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000004} 2, 'Non-Playable' + ])), [ + wbEDID, + wbVMADFragmentedPERK, + wbFULL, + wbDESCReq, + wbICON, + wbCTDAs, + wbStruct(DATA, 'Data', [ + wbInteger('Trait', itU8, wbEnum(['False', 'True'])), + wbInteger('Level', itU8), + wbInteger('Num Ranks', itU8), + wbInteger('Playable', itU8, wbEnum(['False', 'True'])), + wbInteger('Hidden', itU8, wbEnum(['False', 'True'])) + ], cpNormal, True), + wbFormIDCK(NNAM, 'Next Perk', [PERK, NULL]), + wbRArrayS('Effects', wbPerkEffect) + ]); + + var wbBodyPartPart := + wbRStructSK([2], 'Body Part', [ + wbLString(BPTN, 'Part Name', 0, cpTranslate, True), + wbString(PNAM, 'Pose Matching', 0, cpNormal, False), + wbString(BPNN, 'Part Node', 0, cpNormal, True), + wbString(BPNT, 'VATS Target', 0, cpNormal, True), + wbString(BPNI, 'IK Data - Start Node', 0, cpNormal, True), + wbStruct(BPND, '', [ + {00} wbFloat('Damage Mult'), + {04} wbInteger('Flags', itU8, wbFlags([ + 'Severable', + 'IK Data', + 'IK Data - Biped Data', + 'Explodable', + 'IK Data - Is Head', + 'IK Data - Headtracking', + 'To Hit Chance - Absolute' + ])), + {05} wbInteger('Part Type', itU8, wbEnum([ + 'Torso', + 'Head', + 'Eye', + 'LookAt', + 'Fly Grab', + 'Saddle' + ])), + {06} wbInteger('Health Percent', itU8), + {07} wbInteger('Actor Value', itS8, wbActorValueEnum), + {08} wbInteger('To Hit Chance', itU8), + {09} wbInteger('Explodable - Explosion Chance %', itU8), + {10} wbInteger('Explodable - Debris Count', itU16), + {12} wbFormIDCk('Explodable - Debris', [DEBR, NULL]), + {16} wbFormIDCk('Explodable - Explosion', [EXPL, NULL]), + {20} wbFloat('Tracking Max Angle'), + {24} wbFloat('Explodable - Debris Scale'), + {28} wbInteger('Severable - Debris Count', itS32), + {32} wbFormIDCk('Severable - Debris', [DEBR, NULL]), + {36} wbFormIDCk('Severable - Explosion', [EXPL, NULL]), + {40} wbFloat('Severable - Debris Scale'), + wbStruct('Gore Effects Positioning', [ + wbStruct('Translate', [ + {44} wbFloat('X'), + {48} wbFloat('Y'), + {52} wbFloat('Z') + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + wbStruct('Rotation', [ + {56} wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), + {60} wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), + {64} wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3) + ]), + {68} wbFormIDCk('Severable - Impact DataSet', [IPDS, NULL]), + {72} wbFormIDCk('Explodable - Impact DataSet', [IPDS, NULL]), + {28} wbInteger('Severable - Decal Count', itU8), + {28} wbInteger('Explodable - Decal Count', itU8), + {76} wbByteArray('Unknown', 2), + {80} wbFloat('Limb Replacement Scale') + ], cpNormal, True), + wbString(NAM1, 'Limb Replacement Model', 0, cpNormal, True), + wbString(NAM4, 'Gore Effects - Target Bone', 0, cpNormal, True), + wbModelInfo(NAM5) + ], [], cpNormal, True + ).SetSummaryKey([1, 2]).IncludeFlag(dfSummaryMembersNoName); + + wbRecord(BPTD, 'Body Part Data', [ + wbEDID, + wbGenericModel, + wbRArrayS('Body Parts', wbBodyPartPart) + ]).SetSummaryKey([1, 2]).IncludeFlag(dfSummaryNoName); + + wbRecord(ADDN, 'Addon Node', [ + wbEDID, + wbOBND(True), + wbGenericModel, + wbInteger(DATA, 'Node Index', itS32, nil, cpNormal, True), + wbFormIDCk(SNAM, 'Sound', [SNDR, NULL]), + wbStruct(DNAM, 'Data', [ + wbInteger('Master Particle System Cap', itU16), + wbInteger('Flags', itU16, wbEnum([], [ + {>>> Value Must be 1 or 3 <<<} + 1, 'Unknown 1', // {0x0001}'Unknown 0', : The Check-Box is Unchecked in the CK + 3, 'Always Loaded' // {0x0002}'Always Loaded' : The Check-Box is Unchecked in the CK + ])) + ], cpNormal, True) + ]).SetSummaryKey([2]); +end; + +procedure DefineTES5h; +begin + wbRecord(AVIF, 'Actor Value Information', [ + wbEDID, + wbFULL, + wbDESCReq, + wbString(ANAM, 'Abbreviation'), + wbUnknown(CNAM), + wbStruct(AVSK, 'Skill', [ + wbFloat('Skill Use Mult'), + wbFloat('Skill Offset Mult'), + wbFloat('Skill Improve Mult'), + wbFloat('Skill Improve Offset') + ]), + wbRArray('Perk Tree', + wbRStruct('Node', [ + wbFormIDCk(PNAM, 'Perk', [PERK, NULL]), + wbUnknown(FNAM), + wbInteger(XNAM, 'Perk-Grid X', itU32), + wbInteger(YNAM, 'Perk-Grid Y', itU32), + wbFloat(HNAM, 'Horizontal Position'), + wbFloat(VNAM, 'Vertical Position'), + wbFormIDCk(SNAM, 'Associated Skill', [AVIF, NULL]), + wbRArray('Connections', wbInteger(CNAM, 'Line to Index', itU32)), + wbInteger(INAM, 'Index', itU32) + ], []) + ) + ]); + + wbRecord(CAMS, 'Camera Shot', [ + wbEDID, + wbGenericModel, + wbStruct(DATA, 'Data', [ + {00} wbInteger('Action', itU32, wbEnum([ + 'Shoot', + 'Fly', + 'Hit', + 'Zoom' + ])), + {04} wbInteger('Location', itU32, wbEnum([ + 'Attacker', + 'Projectile', + 'Target', + 'Lead Actor' + ])), + {08} wbInteger('Target', itU32, wbEnum([ + 'Attacker', + 'Projectile', + 'Target', + 'Lead Actor' + ])), + {12} wbInteger('Flags', itU32, wbFlags([ + 'Position Follows Location', + 'Rotation Follows Target', + 'Don''t Follow Bone', + 'First Person Camera', + 'No Tracer', + 'Start At Time Zero' + ])), + wbStruct('Time Multipliers', [ + {16} wbFloat('Player'), + {20} wbFloat('Target'), + {24} wbFloat('Global') + ]), + {28} wbFloat('Max Time'), + {32} wbFloat('Min Time'), + {36} wbFloat('Target % Between Actors'), + {40} wbFloat('Near Target Distance') + ], cpNormal, True, nil, 8) + .SetSummaryKeyOnValue([0, 1, 2]) + .SetSummaryPrefixSuffixOnValue(0, '', ',') + .SetSummaryPrefixSuffixOnValue(1, '', ' ->') + .IncludeFlagOnValue(dfSummaryMembersNoName), + wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD]) + ]) + .SetSummaryKey([1, 2]) + .SetSummaryMemberPrefixSuffix(2, '[', ']') + .IncludeFlag(dfSummaryMembersNoName); + + wbRecord(CPTH, 'Camera Path', [ + wbEDID, + wbCTDAs, + wbArray(ANAM, 'Related Camera Paths', wbFormIDCk('Related Camera Path', [CPTH, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True), + wbInteger(DATA, 'Camera Zoom', itU8, wbEnum([], [ + 0, 'Default, Must Have Camera Shots', + 1, 'Disable, Must Have Camera Shots', + 2, 'Shot List, Must Have Camera Shots', + 128, 'Default', + 129, 'Disable', + 130, 'Shot List' + ]), cpNormal, True), + wbRArray('Camera Shots', wbFormIDCk(SNAM, 'Camera Shot', [CAMS])) + ]).SetSummaryKey([1, 4]).IncludeFlag(dfSummaryMembersNoName); + + wbRecord(VTYP, 'Voice Type', [ + wbEDID, + wbInteger(DNAM, 'Flags', itU8, wbFlags([ + 'Allow Default Dialog', + 'Female' + ]), cpNormal, True) + ]); + + wbRecord(MATT, 'Material Type', [ + wbEDID, + wbFormIDCk(PNAM, 'Material Parent', [MATT, NULL]), + wbString(MNAM, 'Material Name'), + wbStruct(CNAM, 'Havok Display Color', [ + wbFloat('Red', cpNormal, True, 255, 0), + wbFloat('Green', cpNormal, True, 255, 0), + wbFloat('Blue', cpNormal, True, 255, 0) + ]).SetToStr(wbRGBAToStr).IncludeFlag(dfCollapsed, wbCollapseRGBA), + wbFloat(BNAM, 'Buoyancy'), + wbInteger(FNAM, 'Flags', itU32, wbFlags([ + 'Stair Material', + 'Arrows Stick' + ], False)), + wbFormIDCk(HNAM, 'Havok Impact Data Set', [IPDS, NULL]) + ]); + + wbRecord(IPCT, 'Impact', [ + wbEDID, + wbGenericModel, + wbStruct(DATA, '', [ + wbFloat('Effect - Duration'), + wbInteger('Effect - Orientation', itU32, wbEnum([ + 'Surface Normal', + 'Projectile Vector', + 'Projectile Reflection' + ])), + wbFloat('Angle Threshold'), + wbFloat('Placement Radius'), + wbInteger('Sound Level', itU32, wbSoundLevelEnum), + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'No Decal Data' + ])), + wbInteger('Impact Result', itU8, wbEnum([ + {0} 'Default', + {1} 'Destroy', + {2} 'Bounce', + {3} 'Impale', + {4} 'Stick' + ])), + wbByteArray('Unknown', 2) + ], cpNormal, True, nil, 4), + wbDODT, + wbFormIDCk(DNAM, 'Texture Set', [TXST]), + wbFormIDCk(ENAM, 'Secondary Texture Set', [TXST]), + wbFormIDCk(SNAM, 'Sound 1', [SNDR, SOUN, NULL]), + wbFormIDCk(NAM1, 'Sound 2', [SNDR, SOUN, NULL]), + wbFormIDCk(NAM2, 'Hazard', [HAZD, NULL]) + ]); + + wbRecord(IPDS, 'Impact Data Set', [ + wbEDID, + wbRArrayS('Data', wbStructSK(PNAM, [0], '', [ + wbFormIDCk('Material', [MATT]), + wbFormIDCk('Impact', [IPCT]) + ])) + ]); + + wbRecord(ECZN, 'Encounter Zone', [ + wbEDID, + wbStruct(DATA, '', [ + wbFormIDCkNoReach('Owner', [NPC_, FACT, NULL]), + wbFormIDCk('Location', [LCTN, NULL]), + wbInteger('Rank', itS8), + wbInteger('Min Level', itS8), + wbInteger('Flags', itU8, wbFlags([ + 'Never Resets', + 'Match PC Below Minimum Level', + 'Disable Combat Boundary' + ])), + wbInteger('Max Level', itS8) + ], cpNormal, True, nil, 2) + ]); + + wbRecord(LCTN, 'Location', [ + wbEDID, + + wbArray(ACPR, 'Actor Cell Persistent Reference', wbStruct('', [ + wbFormIDCk('Actor', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), + wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), + wbInteger('Grid Y', itS16, nil, cpBenign), + wbInteger('Grid X', itS16, nil, cpBenign) + ], cpBenign), 0, nil, nil, cpBenign), + wbArray(LCPR, 'Location Cell Persistent Reference', wbStruct('', [ + wbFormIDCk('Actor', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), + wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), + wbInteger('Grid Y', itS16, nil, cpBenign), + wbInteger('Grid X', itS16, nil, cpBenign) + ], cpBenign), 0, nil, nil, cpBenign), + {>>> From Danwguard.esm, Does not follow similar previous patterns <<<} + wbArray(RCPR, 'Reference Cell Persistent Reference', wbFormIDCk('Ref', [ACHR, REFR], False, cpBenign)), + + wbArray(ACUN, 'Actor Cell Unique', wbStruct('', [ + wbFormIDCk('Actor', [NPC_], False, cpBenign), + wbFormIDCk('Ref', [ACHR], False, cpBenign), + wbFormIDCk('Location', [LCTN, NULL], False, cpBenign) + ], cpBenign), 0, nil, nil, cpBenign), + wbArray(LCUN, 'Location Cell Unique', wbStruct('', [ + wbFormIDCk('Actor', [NPC_], False, cpBenign), + wbFormIDCk('Ref', [ACHR], False, cpBenign), + wbFormIDCk('Location', [LCTN, NULL], False, cpBenign) + ], cpBenign), 0, nil, nil, cpBenign), + {>>> in Unofficial Skyrim patch <<<} + wbArray(RCUN, 'Reference Cell Unique', wbFormIDCk('Actor', [NPC_], False, cpBenign)), + + wbArray(ACSR, 'Actor Cell Static Reference', wbStruct('', [ + wbFormIDCk('Loc Ref Type', [LCRT], False, cpBenign), + wbFormIDCk('Marker', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), + wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), + wbInteger('Grid Y', itS16, nil, cpBenign), + wbInteger('Grid X', itS16, nil, cpBenign) + ], cpBenign), 0, nil, nil, cpBenign), + wbArray(LCSR, 'Location Cell Static Reference', wbStruct('', [ + wbFormIDCk('Loc Ref Type', [LCRT], False, cpBenign), + wbFormIDCk('Marker', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), + wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), + wbInteger('Grid Y', itS16, nil, cpBenign), + wbInteger('Grid X', itS16, nil, cpBenign) + ], cpBenign), 0, nil, nil, cpBenign), + {>>> Seen in Open Cities <<<} + wbArray(RCSR, 'Reference Cell Static Reference', wbFormIDCk('Ref', [ACHR, REFR], False, cpBenign), 0, nil, nil, cpBenign), + + wbRArray('Actor Cell Encounter Cell', + wbStruct(ACEC, 'Unknown', [ + wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), + wbArray('Coordinates', wbStruct('', [ + wbInteger('Grid Y', itS16, nil, cpBenign), + wbInteger('Grid X', itS16, nil, cpBenign) + ])) + ], cpBenign) + , cpBenign), + wbRArray('Location Cell Encounter Cell', + wbStruct(LCEC, 'Unknown', [ + wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), + wbArray('Coordinates', wbStruct('', [ + wbInteger('Grid Y', itS16, nil, cpBenign), + wbInteger('Grid X', itS16, nil, cpBenign) + ])) + ]) + , cpBenign), + {>>> Seen in Open Cities <<<} + wbRArray('Reference Cell Encounter Cell', + wbStruct(RCEC, 'Unknown', [ + wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), + wbArray('Coordinates', wbStruct('', [ + wbInteger('Grid Y', itS16, nil, cpBenign), + wbInteger('Grid X', itS16, nil, cpBenign) + ])) + ]) + , cpBenign), + + wbArray(ACID, 'Actor Cell Marker Reference', wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), 0, nil, nil, cpBenign), + wbArray(LCID, 'Location Cell Marker Reference', wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), 0, nil, nil, cpBenign), + + wbArray(ACEP, 'Actor Cell Enable Point', wbStruct('', [ + wbFormIDCk('Actor', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), + wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), + wbInteger('Grid Y', itS16, nil, cpBenign), + wbInteger('Grid X', itS16, nil, cpBenign) + ]), 0, nil, nil, cpBenign), + wbArray(LCEP, 'Location Cell Enable Point', wbStruct('', [ + wbFormIDCk('Actor', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), + wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), + wbInteger('Grid Y', itS16, nil, cpBenign), + wbInteger('Grid X', itS16, nil, cpBenign) + ]), 0, nil, nil, cpBenign), + + wbFULL, + wbKSIZ, + wbKWDAs, + wbFormIDCk(PNAM, 'Parent Location', [LCTN, NULL]), + wbFormIDCk(NAM1, 'Music', [MUSC, NULL]), + wbFormIDCk(FNAM, 'Unreported Crime Faction', [FACT]), + wbFormIDCk(MNAM, 'World Location Marker Ref', [REFR, ACHR]), + wbFloat(RNAM, 'World Location Radius'), + wbFormIDCk(NAM0, 'Horse Marker Ref', [REFR]), + wbCNAM + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); + +end; + +{this is required to prevent XE6 compiler error} +type + TVarRecs = array of TVarRec; + +function CombineVarRecs(const a, b : array of const) + : TVarRecs; +begin + SetLength(Result, Length(a) + Length(b)); + if Length(a) > 0 then + Move(a[0], Result[0], SizeOf(TVarRec) * Length(a)); + if Length(b) > 0 then + Move(b[0], Result[Length(a)], SizeOf(TVarRec) * Length(b)); +end; + +function MakeVarRecs(const a : array of const) + : TVarRecs; +begin + SetLength(Result, Length(a)); + if Length(a) > 0 then + Move(a[0], Result[0], SizeOf(TVarRec) * Length(a)); +end; + + +procedure DefineTES5i; +var + a, b, c : TVarRecs; + s: string; + wbMenuButton: IwbRecordMemberDef; +begin + // load map markes list from external file if present + s := ExtractFilePath(ParamStr(0)) + wbAppName + 'MapMarkers.txt'; + if FileExists(s) then try + wbMapMarkerEnum := wbEnum(TFile.ReadAllLines(s)); + except end; + + if not Assigned(wbMapMarkerEnum) then + wbMapMarkerEnum := wbEnum([ + { 0} 'None', + { 1} 'City', + { 2} 'Town', + { 3} 'Settlement', + { 4} 'Cave', + { 5} 'Camp', + { 6} 'Fort', + { 7} 'Nordic Ruins', + { 8} 'Dwemer Ruin', + { 9} 'Shipwreck', + {10} 'Grove', + {11} 'Landmark', + {12} 'Dragon Lair', + {13} 'Farm', + {14} 'Wood Mill', + {15} 'Mine', + {16} 'Imperial Camp', + {17} 'Stormcloak Camp', + {18} 'Doomstone', + {19} 'Wheat Mill', + {20} 'Smelter', + {21} 'Stable', + {22} 'Imperial Tower', + {23} 'Clearing', + {24} 'Pass', + {25} 'Altar', + {26} 'Rock', + {27} 'Lighthouse', + {28} 'Orc Stronghold', + {29} 'Giant Camp', + {30} 'Shack', + {31} 'Nordic Tower', + {32} 'Nordic Dwelling', + {33} 'Docks', + {34} 'Shrine', + {35} 'Riften Castle', + {36} 'Riften Capitol', + {37} 'Windhelm Castle', + {38} 'Windhelm Capitol', + {39} 'Whiterun Castle', + {40} 'Whiterun Capitol', + {41} 'Solitude Castle', + {42} 'Solitude Capitol', + {43} 'Markarth Castle', + {44} 'Markarth Capitol', + {45} 'Winterhold Castle', + {46} 'Winterhold Capitol', + {47} 'Morthal Castle', + {48} 'Morthal Capitol', + {49} 'Falkreath Castle', + {50} 'Falkreath Capitol', + {51} 'Dawnstar Castle', + {52} 'Dawnstar Capitol', + {53} 'DLC02 - Temple of Miraak', + {54} 'DLC02 - Raven Rock', + {55} 'DLC02 - Beast Stone', + {56} 'DLC02 - Tel Mithryn', + {57} 'DLC02 - To Skyrim', + {58} 'DLC02 - To Solstheim', + {59} 'DLC02 - Castle Karstaag' + ]); + + // load quest types list from external file if present + s := ExtractFilePath(ParamStr(0)) + wbAppName + 'QuestTypes.txt'; + if FileExists(s) then try + wbQuestTypeEnum := wbEnum(TFile.ReadAllLines(s)); + except end; + + if not Assigned(wbQuestTypeEnum) then + wbQuestTypeEnum := wbEnum([ + {0} 'None', + {1} 'Main Quest', + {2} 'Mages'' Guild', + {3} 'Thieves'' Guild', + {4} 'Dark Brotherhood', + {5} 'Companion Quests', + {6} 'Miscellaneous', + {7} 'Daedric', + {8} 'Side Quest', + {9} 'Civil War', + {10} 'DLC01 - Vampire', + {11} 'DLC02 - Dragonborn' + ]); + + wbMenuButton := + wbRStruct('Menu Button', [ + wbLString(ITXT, 'Button Text', 0, cpTranslate), + wbCTDAs + ], []); + + wbRecord(MESG, 'Message', [ + wbEDID, + wbDESCReq, + wbFULL, + wbFormIDCk(INAM, 'Icon (unused)', [NULL], False, cpIgnore, True), // leftover + wbFormIDCk(QNAM, 'Owner Quest', [QUST]), + wbInteger(DNAM, 'Flags', itU32, wbFlags([ + 'Message Box', + 'Auto Display' + ]), cpNormal, True, False, nil, wbMESGDNAMAfterSet), + wbInteger(TNAM, 'Display Time', itU32, nil, cpNormal, False, False, wbMESGTNAMDontShow), + wbRArray('Menu Buttons', wbMenuButton) + ], False, nil, cpNormal, False, wbMESGAfterLoad); + + a := MakeVarRecs([ + 0, 'None', + Sig2Int('RADA'), 'RADA (Unused)', + Sig2Int('MORP'), 'MORP (Unused)', + Sig2Int('PPAR'), 'PPAR (Unused)', + Sig2Int('MYSN'), 'MYSN (Unused)', + Sig2Int('MYSF'), 'MYSF (Unused)', + Sig2Int('WWSP'), 'Werewolf Spell', + Sig2Int('SALT'), 'Sitting Angle Limit', + Sig2Int('APSH'), 'Allow Player Shout', + Sig2Int('GOLD'), 'Gold', + Sig2Int('LKPK'), 'Lockpick', + Sig2Int('SKLK'), 'SkeletonKey', + Sig2Int('PFAC'), 'Player Faction', + Sig2Int('GFAC'), 'Guard Faction', + Sig2Int('DFMS'), 'Default Music', + Sig2Int('BTMS'), 'Battle Music', + Sig2Int('DTMS'), 'Death Music', + Sig2Int('SCMS'), 'Success Music', + Sig2Int('LUMS'), 'Level Up Music', + Sig2Int('DCMS'), 'Dungeon Cleared Music', + Sig2Int('PVMA'), 'Player Voice (Male)', + Sig2Int('PVMC'), 'Player Voice (Male Child)', + Sig2Int('PVFA'), 'Player Voice (Female)', + Sig2Int('PVFC'), 'Player Voice (Female Child)', + Sig2Int('EPDF'), 'Eat Package Default Food', + Sig2Int('LHEQ'), 'LeftHand Equip', + Sig2Int('RHEQ'), 'RightHand Equip', + Sig2Int('EHEQ'), 'EitherHand Equip', + Sig2Int('VOEQ'), 'Voice Equip', + Sig2Int('POEQ'), 'Potion Equip', + Sig2Int('EACA'), 'Every Actor Ability', + Sig2Int('CACA'), 'Commanded Actor Ability', + Sig2Int('DEIS'), 'Drug Wears Off Image Space', + Sig2Int('DFTS'), 'Footstep Set', + Sig2Int('DLMT'), 'Landscape Material', + Sig2Int('DLZM'), 'Dragon Land Zone Marker', + Sig2Int('DCZM'), 'Dragon Crash Zone Marker', + Sig2Int('CSTY'), 'Combat Style', + Sig2Int('PLST'), 'Default Pack List', + Sig2Int('PWFD'), 'Wait-For-Dialogue Package', + Sig2Int('LRTB'), 'LocRefType Boss', + Sig2Int('VLOC'), 'Virtual Location', + Sig2Int('PLOC'), 'PersistAll Location', + Sig2Int('INVP'), 'Inventory Player', + Sig2Int('PTNP'), 'Pathing Test NPC', + Sig2Int('FPCS'), 'Favor Cost Small', + Sig2Int('FPCM'), 'Favor Cost Medium', + Sig2Int('FPCL'), 'Favor Cost Large', + Sig2Int('FGPD'), 'Favor Gifts Per Day', + Sig2Int('AASW'), 'Action Swim State Change', + Sig2Int('AALK'), 'Action Look', + Sig2Int('AALA'), 'Action LeftAttack', + Sig2Int('AALD'), 'Action LeftReady', + Sig2Int('AALR'), 'Action LeftRelease', + Sig2Int('AALI'), 'Action LeftInterrupt', + Sig2Int('AARA'), 'Action RightAttack', + Sig2Int('AARD'), 'Action RightReady', + Sig2Int('AARR'), 'Action RightRelease', + Sig2Int('AARI'), 'Action RightInterrupt', + Sig2Int('AADA'), 'Action DualAttack', + Sig2Int('AADL'), 'Action DualRelease', + Sig2Int('AAAC'), 'Action Activate', + Sig2Int('AAJP'), 'Action Jump', + Sig2Int('AAFA'), 'Action Fall', + Sig2Int('AALN'), 'Action Land', + Sig2Int('AASN'), 'Action Sneak', + Sig2Int('AAVC'), 'Action Voice', + Sig2Int('AAVD'), 'Action VoiceReady', + Sig2Int('AAVR'), 'Action VoiceRelease', + Sig2Int('AAVI'), 'Action VoiceInterrupt', + Sig2Int('AAID'), 'Action Idle', + Sig2Int('AAST'), 'Action Sprint Start', + Sig2Int('AASP'), 'Action Sprint Stop', + Sig2Int('AADR'), 'Action Draw', + Sig2Int('AASH'), 'Action Sheath', + Sig2Int('ALPA'), 'Action Left Power Attack', + Sig2Int('AAPA'), 'Action Right Power Attack', + Sig2Int('ADPA'), 'Action Dual Power Attack', + Sig2Int('AAS1'), 'Action Stagger Start', + Sig2Int('AABH'), 'Action Block Hit', + Sig2Int('AABA'), 'Action Block Anticipate', + Sig2Int('AARC'), 'Action Recoil', + Sig2Int('AAR2'), 'Action Large Recoil', + Sig2Int('AAB1'), 'Action Bleedout Start', + Sig2Int('AAB2'), 'Action Bleedout Stop', + Sig2Int('AAIS'), 'Action Idle Stop', + Sig2Int('AAWH'), 'Action Ward Hit', + Sig2Int('AAFQ'), 'Action Force Equip', + Sig2Int('AASC'), 'Action Shield Change', + Sig2Int('AAPS'), 'Action Path Start', + Sig2Int('AAPE'), 'Action Path End', + Sig2Int('AALM'), 'Action Large Movement Delta', + Sig2Int('AAF1'), 'Action Fly Start', + Sig2Int('AAF2'), 'Action Fly Stop', + Sig2Int('AAH1'), 'Action Hover Start', + Sig2Int('AAH2'), 'Action Hover Stop', + Sig2Int('AABI'), 'Action Bumped Into', + Sig2Int('AASS'), 'Action Summoned Start', + Sig2Int('ATKI'), 'Action Talking Idle', + Sig2Int('ALTI'), 'Action Listen Idle', + Sig2Int('AADE'), 'Action Death', + Sig2Int('AADW'), 'Action Death Wait', + Sig2Int('AIDW'), 'Action Idle Warn', + Sig2Int('AMST'), 'Action Move Start', + Sig2Int('AMSP'), 'Action Move Stop', + Sig2Int('ATRI'), 'Action Turn Right', + Sig2Int('ATLE'), 'Action Turn Left', + Sig2Int('ATSP'), 'Action Turn Stop', + Sig2Int('AMFD'), 'Action Move Forward', + Sig2Int('AMBK'), 'Action Move Backward', + Sig2Int('AMLT'), 'Action Move Left', + Sig2Int('AMRT'), 'Action Move Right', + Sig2Int('ARAG'), 'Action Reset Animation Graph', + Sig2Int('AKDN'), 'Action Knockdown', + Sig2Int('AAGU'), 'Action Get Up', + Sig2Int('ASID'), 'Action Idle Stop Instant', + Sig2Int('ARGI'), 'Action Ragdoll Instant', + Sig2Int('AWWS'), 'Action Waterwalk Start', + Sig2Int('AREL'), 'Action Reload', + Sig2Int('PUSG'), 'Pickup Sound Generic', + Sig2Int('PDSG'), 'Putdown Sound Generic', + Sig2Int('PUSW'), 'Pickup Sound Weapon', + Sig2Int('PDSW'), 'Putdown Sound Weapon', + Sig2Int('PUSA'), 'Pickup Sound Armor', + Sig2Int('PDSA'), 'Putdown Sound Armor', + Sig2Int('PUSB'), 'Pickup Sound Book', + Sig2Int('PDSB'), 'Putdown Sound Book', + Sig2Int('PUSI'), 'Pickup Sound Ingredient', + Sig2Int('PDSI'), 'Putdown Sound Ingredient', + Sig2Int('HVSS'), 'Harvest Sound', + Sig2Int('HVFS'), 'Harvest Failed Sound', + Sig2Int('WBSN'), 'Ward Break Sound', + Sig2Int('WASN'), 'Ward Absorb Sound', + Sig2Int('WDSN'), 'Ward Deflect Sound', + Sig2Int('MFSN'), 'Magic Fail Sound', + Sig2Int('SFSN'), 'Shout Fail Sound', + Sig2Int('HFSD'), 'Heartbeat Sound Fast', + Sig2Int('HSSD'), 'Heartbeat Sound Slow', + Sig2Int('IMLH'), 'Imagespace: Low Health', + Sig2Int('SCSD'), 'Soul Captured Sound', + Sig2Int('NASD'), 'No-Activation Sound', + Sig2Int('MMSD'), 'Map Menu Looping Sound', + Sig2Int('DDSC'), 'Dialogue Voice Category', + Sig2Int('NDSC'), 'Non-Dialogue Voice Category', + Sig2Int('SFDC'), 'SFX To Fade In Dialogue Category', + Sig2Int('PDMC'), 'Pause During Menu Category (Fade)', + Sig2Int('PIMC'), 'Pause During Menu Category (Immediate)', + Sig2Int('PDLC'), 'Pause During Loading Menu Category', + Sig2Int('MDSC'), 'Music Sound Category', + Sig2Int('SMSC'), 'Stats Mute Category', + Sig2Int('SSSC'), 'Stats Music', + Sig2Int('MTSC'), 'Master Sound Category', + Sig2Int('TSSC'), 'Time Sensitive Sound Category', + Sig2Int('DOP2'), 'Dialogue Output Model (3D)', + Sig2Int('DOP3'), 'Dialogue Output Model (2D)', + Sig2Int('POPM'), 'Player''s Output Model (1st Person)', + Sig2Int('P3OM'), 'Player''s Output Model (3rd Person)', + Sig2Int('IOPM'), 'Interface Output Model', + Sig2Int('RVBT'), 'Reverb Type', + Sig2Int('UWLS'), 'Underwater Loop Sound', + Sig2Int('URVT'), 'Underwater Reverb Type', + Sig2Int('HRSK'), 'Keyword - Horse', + Sig2Int('UNDK'), 'Keyword - Undead', + Sig2Int('NPCK'), 'Keyword - NPC', + Sig2Int('KWBR'), 'Keyword - BeastRace', + Sig2Int('KWDM'), 'Keyword - DummyObject', + Sig2Int('KWGE'), 'Keyword - UseGeometryEmitter', + Sig2Int('KWMS'), 'Keyword - MustStop', + Sig2Int('KWUA'), 'Keyword - UpdateDuringArchery', + Sig2Int('KWOT'), 'Keyword - Skip Outfit Items', + Sig2Int('FTHD'), 'Male Face Texture Set: Head', + Sig2Int('FTMO'), 'Male Face Texture Set: Mouth', + Sig2Int('FTEL'), 'Male Face Texture Set: Eyes', + Sig2Int('FTHF'), 'Female Face Texture Set: Head', + Sig2Int('FTMF'), 'Female Face Texture Set: Mouth', + Sig2Int('FTRF'), 'Female Face Texture Set: Eyes', + Sig2Int('IMID'), 'ImageSpaceModifier for inventory menu.', + Sig2Int('PTEM'), 'Package template', + Sig2Int('MMCL'), 'Main Menu Cell', + Sig2Int('DMWL'), 'Default MovementType: Walk', + Sig2Int('DMRN'), 'Default MovementType: Run', + Sig2Int('DMSW'), 'Default MovementType: Swim', + Sig2Int('DMFL'), 'Default MovementType: Fly', + Sig2Int('DMSN'), 'Default MovementType: Sneak', + Sig2Int('DMSP'), 'Default MovementType: Sprint', + Sig2Int('SPFK'), 'Keyword - Special Furniture', + Sig2Int('FFFP'), 'Keyword - Furniture Forces 1st Person', + Sig2Int('FFTP'), 'Keyword - Furniture Forces 3rd Person', + Sig2Int('AFNP'), 'Keyword - Activator Furniture No Player', + Sig2Int('TKGS'), 'Telekinesis Grab Sound', + Sig2Int('TKTS'), 'Telekinesis Throw Sound', + Sig2Int('WMWE'), 'World Map Weather', + Sig2Int('HMPC'), 'Help Manual PC', + Sig2Int('HMXB'), 'Help Manual XBox', + Sig2Int('TKAM'), 'Keyword - Type Ammo', + Sig2Int('TKAR'), 'Keyword - Type Armor', + Sig2Int('TKBK'), 'Keyword - Type Book', + Sig2Int('TKIG'), 'Keyword - Type Ingredient', + Sig2Int('TKKY'), 'Keyword - Type Key', + Sig2Int('TKMS'), 'Keyword - Type Misc', + Sig2Int('TKSG'), 'Keyword - Type SoulGem', + Sig2Int('TKWP'), 'Keyword - Type Weapon', + Sig2Int('TKPT'), 'Keyword - Type Potion', + Sig2Int('BENW'), 'Base Weapon Enchantment', + Sig2Int('BENA'), 'Base Armor Enchantment', + Sig2Int('BAPO'), 'Base Potion', + Sig2Int('BAPS'), 'Base Poison', + Sig2Int('DRAK'), 'Keyword - Dragon', + Sig2Int('MVBL'), 'Keyword - Movable', + Sig2Int('ABSE'), 'Art Object - Absorb Effect', + Sig2Int('WEML'), 'Weapon Material List', + Sig2Int('ARTL'), 'Armor Material List', + Sig2Int('DIEN'), 'Keyword - Disallow Enchanting', + Sig2Int('FTML'), 'Favor travel marker location', + Sig2Int('LKHO'), 'Keyword - Hold Location', + Sig2Int('CWOK'), 'Keyword - Civil War Owner', + Sig2Int('CWNE'), 'Keyword - Civil War Neutral', + Sig2Int('LRSO'), 'LocRefType - Civil War Soldier', + Sig2Int('KWDO'), 'Keyword - ClearableLocation', + Sig2Int('LRRD'), 'LocRefType - Resource Destructible', + Sig2Int('HCLL'), 'FormList - Hair Color List', + Sig2Int('CMPX'), 'Complex Scene Object', + Sig2Int('RUSG'), 'Keyword - Reusable SoulGem', + Sig2Int('ANML'), 'Keyword - Animal', + Sig2Int('DAED'), 'Keyword - Daedra' + ]); + + b := MakeVarRecs([ + Sig2Int('BEEP'), 'Keyword - Robot', + Sig2Int('NRNT'), 'Keyword - Nirnroot', + Sig2Int('FTGF'), 'Fighters'' Guild Faction', + Sig2Int('MGGF'), 'Mages'' Guild Faction', + Sig2Int('TVGF'), 'Thieves'' Guild Faction', + Sig2Int('DBHF'), 'Dark Brotherhood Faction', + Sig2Int('JRLF'), 'Jarl Faction', + Sig2Int('AWWW'), 'Bunny Faction', + Sig2Int('PIVV'), 'Player Is Vampire Variable', + Sig2Int('PIWV'), 'Player Is Werewolf Variable', + Sig2Int('NMRD'), 'Road Marker', + Sig2Int('SAT1'), 'Keyword: Scale Actor To 1.0', + Sig2Int('VAMP'), 'Keyword: Vampire', + Sig2Int('FORG'), 'Keyword: Forge', + Sig2Int('COOK'), 'Keyword: Cooking Pot', + Sig2Int('SMLT'), 'Keyword: Smelter', + Sig2Int('TANN'), 'Keyword: Tanning Rack', + Sig2Int('HBLK'), 'Help - Basic Lockpicking (PC)', + Sig2Int('HBLX'), 'Help - Basic Lockpicking (Console)', + Sig2Int('HBFG'), 'Help - Basic Forging', + Sig2Int('HBCO'), 'Help - Basic Cooking', + Sig2Int('HBML'), 'Help - Basic Smelting', + Sig2Int('HBTA'), 'Help - Basic Tanning', + Sig2Int('HBOC'), 'Help - Basic Object Creation', + Sig2Int('HBEC'), 'Help - Basic Enchanting', + Sig2Int('HBSM'), 'Help - Basic Smithing Weapon', + Sig2Int('HBSA'), 'Help - Basic Smithing Armor', + Sig2Int('HBAL'), 'Help - Basic Alchemy', + Sig2Int('HBBR'), 'Help - Barter', + Sig2Int('HBLU'), 'Help - Leveling up', + Sig2Int('HBSK'), 'Help - Skills Menu', + Sig2Int('HBMM'), 'Help - Map Menu', + Sig2Int('HBJL'), 'Help - Journal', + Sig2Int('HBLH'), 'Help - Low Health', + Sig2Int('HBLM'), 'Help - Low Magicka', + Sig2Int('HBLS'), 'Help - Low Stamina', + Sig2Int('HBHJ'), 'Help - Jail', + Sig2Int('HBFT'), 'Help - Teammate Favor', + Sig2Int('HBWC'), 'Help - Weapon Charge', + Sig2Int('HBFS'), 'Help - Favorites', + Sig2Int('KHFL'), 'Kinect Help FormList', + Sig2Int('HBFM'), 'Help - Flying Mount', + Sig2Int('HBTL'), 'Help - Target Lock', + Sig2Int('HBAT'), 'Help - Attack Target', + Sig2Int('MHFL'), 'Help - Mods', + Sig2Int('LSIS'), 'Imagespace: Load screen', + Sig2Int('WMDA'), 'Keyword - Weapon Material Daedric', + Sig2Int('WMDR'), 'Keyword - Weapon Material Draugr', + Sig2Int('WMDH'), 'Keyword - Weapon Material DraugrHoned', + Sig2Int('WMDW'), 'Keyword - Weapon Material Dwarven', + Sig2Int('WMEB'), 'Keyword - Weapon Material Ebony', + Sig2Int('WMEL'), 'Keyword - Weapon Material Elven', + Sig2Int('WMFA'), 'Keyword - Weapon Material Falmer', + Sig2Int('WMFH'), 'Keyword - Weapon Material FalmerHoned', + Sig2Int('WMGL'), 'Keyword - Weapon Material Glass', + Sig2Int('WMIM'), 'Keyword - Weapon Material Imperial', + Sig2Int('WMIR'), 'Keyword - Weapon Material Iron', + Sig2Int('WMOR'), 'Keyword - Weapon Material Orcish', + Sig2Int('WMST'), 'Keyword - Weapon Material Steel', + Sig2Int('WMWO'), 'Keyword - Weapon Material Wood', + Sig2Int('WTBA'), 'Keyword - WeaponTypeBoundArrow', + Sig2Int('AODA'), 'Keyword - Armor Material Daedric', + Sig2Int('AODP'), 'Keyword - Armor Material Dragonplate', + Sig2Int('AODS'), 'Keyword - Armor Material Dragonscale', + Sig2Int('AODB'), 'Keyword - Armor Material Dragonbone', + Sig2Int('AODW'), 'Keyword - Armor Material Dwarven', + Sig2Int('AOEB'), 'Keyword - Armor Material Ebony', + Sig2Int('AOEL'), 'Keyword - Armor Material Elven', + Sig2Int('AOES'), 'Keyword - Armor Material ElvenSplinted', + Sig2Int('AOFL'), 'Keyword - Armor Material FullLeather', + Sig2Int('AOGL'), 'Keyword - Armor Material Glass', + Sig2Int('AOHI'), 'Keyword - Armor Material Hide', + Sig2Int('AOIM'), 'Keyword - Armor Material Imperial', + Sig2Int('AOIH'), 'Keyword - Armor Material ImperialHeavy', + Sig2Int('AOIR'), 'Keyword - Armor Material ImperialReinforced', + Sig2Int('AOFE'), 'Keyword - Armor Material Iron', + Sig2Int('AOIB'), 'Keyword - Armor Material IronBanded', + Sig2Int('AOOR'), 'Keyword - Armor Material Orcish', + Sig2Int('AOSC'), 'Keyword - Armor Material Scaled', + Sig2Int('AOST'), 'Keyword - Armor Material Steel', + Sig2Int('AOSP'), 'Keyword - Armor Material SteelPlate', + Sig2Int('AOSK'), 'Keyword - Armor Material Stormcloak', + Sig2Int('AOSD'), 'Keyword - Armor Material Studded', + Sig2Int('GCK1'), 'Keyword - Generic Craftable Keyword 01', + Sig2Int('GCK2'), 'Keyword - Generic Craftable Keyword 02', + Sig2Int('GCK3'), 'Keyword - Generic Craftable Keyword 03', + Sig2Int('GCK4'), 'Keyword - Generic Craftable Keyword 04', + Sig2Int('GCK5'), 'Keyword - Generic Craftable Keyword 05', + Sig2Int('GCK6'), 'Keyword - Generic Craftable Keyword 06', + Sig2Int('GCK7'), 'Keyword - Generic Craftable Keyword 07', + Sig2Int('GCK8'), 'Keyword - Generic Craftable Keyword 08', + Sig2Int('GCK9'), 'Keyword - Generic Craftable Keyword 09', + Sig2Int('GCKX'), 'Keyword - Generic Craftable Keyword 10', + Sig2Int('JWLR'), 'Keyword - Jewelry', + Sig2Int('KWCU'), 'Keyword - Cuirass', + Sig2Int('MNTK'), 'Keyword - Mount', + Sig2Int('LMHP'), 'Local Map Hide Plane', + Sig2Int('SLDM'), 'Snow LOD Material', + Sig2Int('SLHD'), 'Snow LOD Material (HD)', + Sig2Int('ALDM'), 'Ash LOD Material', + Sig2Int('ALHD'), 'Ash LOD Material (HD)', + Sig2Int('DGFL'), 'DialogueFollower Quest', + Sig2Int('PTFR'), 'PotentialFollower Faction', + Sig2Int('AVWP'), 'Werewolf Available Perks', + Sig2Int('AVVP'), 'Vampire Available Perks', + Sig2Int('RIWR'), 'Werewolf Race', + Sig2Int('RIVR'), 'Vampire Race', + Sig2Int('RIVS'), 'Vampire Spells', + Sig2Int('DMXL'), 'Dragon Mount No Land List', + Sig2Int('PCMD'), 'Player Can Mount Dragon Here List', + Sig2Int('FMYS'), 'Flying Mount - Allowed Spells', + Sig2Int('FMNS'), 'Flying Mount - Disallowed Spells', + Sig2Int('MNT2'), 'Keyword - Mount', + Sig2Int('AIVC'), 'Verlet Cape', + Sig2Int('FTNP'), 'Furniture Test NPC', + Sig2Int('COEX'), 'Keyword - Conditional Explosion', + Sig2Int('VFNC'), 'Vampire Feed No Crime Faction', + Sig2Int('KWSP'), 'Skyrim - Worldspace', + Sig2Int('ALBM'), 'Keyword - Armor Material Light Bonemold', + Sig2Int('ALCH'), 'Keyword - Armor Material Light Chitin', + Sig2Int('ALNC'), 'Keyword - Armor Material Light Nordic', + Sig2Int('ALSM'), 'Keyword - Armor Material Light Stalhrim', + Sig2Int('FMFF'), 'Flying Mount - Fly Fast Worldspaces', + Sig2Int('AHBM'), 'Keyword - Armor Material Heavy Bonemold', + Sig2Int('AHCH'), 'Keyword - Armor Material Heavy Chitin', + Sig2Int('AHNC'), 'Keyword - Armor Material Heavy Nordic', + Sig2Int('AHSM'), 'Keyword - Armor Material Heavy Stalhrim', + Sig2Int('WPNC'), 'Keyword - Weapon Material Nordic', + Sig2Int('WPSM'), 'Keyword - Weapon Material Stalhrim', + Sig2Int('SKAB'), 'Survival - Keyword Armor Body', + Sig2Int('SKAF'), 'Survival - Keyword Armor Feet', + Sig2Int('SKAH'), 'Survival - Keyword Armor Hands', + Sig2Int('SKAO'), 'Survival - Keyword Armor Head', + Sig2Int('SKCB'), 'Survival - Keyword Clothing Body', + Sig2Int('SKCD'), 'Survival - Keyword Cold', + Sig2Int('SKCF'), 'Survival - Keyword Clothing Feet', + Sig2Int('SKCH'), 'Survival - Keyword Clothing Hands', + Sig2Int('SKCO'), 'Survival - Keyword Clothing Head', + Sig2Int('SKWM'), 'Survival - Keyword Warm', + Sig2Int('SRCP'), 'Survival - Cold Penalty', + Sig2Int('SRHP'), 'Survival - Hunger Penalty', + Sig2Int('SRSP'), 'Survival - Sleep Penalty', + Sig2Int('SRTP'), 'Survival - Temperature', + Sig2Int('SRVE'), 'Survival Mode Enabled', + Sig2Int('SRVS'), 'Survival Mode - Show Option', + Sig2Int('SRVT'), 'Survival Mode - Toggle' + ]); + + c := CombineVarRecs(a, b); + + if wbGameMode = gmTES5VR then begin + b := MakeVarRecs([ + Sig2Int('FIJC'), 'FIJC', + Sig2Int('HMMC'), 'HMMC', + Sig2Int('FISC'), 'FISC', + Sig2Int('FASF'), 'FASF', + Sig2Int('HBVM'), 'HBVM', + Sig2Int('HSVM'), 'HSVM', + Sig2Int('VRPR'), 'VRPR', + Sig2Int('VRRR'), 'VRRR', + Sig2Int('CBTR'), 'CBTR', + Sig2Int('PSIS'), 'PSIS', + Sig2Int('VRWS'), 'VRWS', + Sig2Int('CBIT'), 'CBIT', + Sig2Int('FSIT'), 'FSIT', + Sig2Int('CBLT'), 'CBLT', + Sig2Int('CBST'), 'CBST', + Sig2Int('CBTT'), 'CBTT', + Sig2Int('HTLV'), 'HTLV', + Sig2Int('HFMV'), 'HFMV', + Sig2Int('HMOV'), 'HMOV', + Sig2Int('HATV'), 'HATV' + ]); + + c := CombineVarRecs(c, b); + end; + + + wbRecord(DOBJ, 'Default Object Manager', [ + wbEDID, + wbArrayS(DNAM, 'Objects', + wbStructSK([0], 'Object', [ + wbInteger('Use', itU32, wbEnum([], c), cpNormalIgnoreEmpty), + wbFormID('Object ID', cpNormalIgnoreEmpty) + ]), 0, cpNormalIgnoreEmpty, True, wbDOBJObjectsAfterLoad + ) + ]); + + wbRecord(LGTM, 'Lighting Template', [ + wbEDID, + wbStruct(DATA, 'Lighting', [ + wbByteColors('Ambient Color'), + wbByteColors('Directional Color'), + wbByteColors('Fog Color Near'), + wbFloat('Fog Near'), + wbFloat('Fog Far'), + wbInteger('Directional Rotation XY', itS32), + wbInteger('Directional Rotation Z', itS32), + wbFloat('Directional Fade'), + wbFloat('Fog Clip Dist'), + wbFloat('Fog Power'), + wbAmbientColors('Ambient Colors'), // WindhelmLightingTemplate [LGTM:0007BA87] only find 24 ! + wbByteColors('Fog Color Far'), + wbFloat('Fog Max'), + wbStruct('Light Fade Distances', [ + wbFloat('Start'), + wbFloat('End') + ]), + wbByteArray('Unknown', 4) + ], cpNormal, True, nil, 11), + wbAmbientColors(DALC) + ]); + + wbRecord(MUSC, 'Music Type', [ + wbEDID, + wbInteger(FNAM, 'Flags', itU32, wbFlags([ + {0x01} 'Plays One Selection', + {0x02} 'Abrupt Transition', + {0x04} 'Cycle Tracks', + {0x08} 'Maintain Track Order', + {0x10} 'Unknown 4', + {0x20} 'Ducks Current Track', + {0x40} IsSSE('Doesn''t Queue', 'Unknown 6') + ]), cpNormal, True), + wbStruct(PNAM, 'Data', [ + wbInteger('Priority', itU16), + wbInteger('Ducking (dB)', itU16, wbDiv(100)) + ]), + wbFloat(WNAM, 'Fade Duration'), + wbArray(TNAM, 'Music Tracks', wbFormIDCk('Track', [MUST, NULL])) + ]); + + wbRecord(FSTP, 'Footstep', [ + wbEDID, + wbFormIDCk(DATA, 'Impact Data Set', [IPDS, NULL], False, cpNormal, True), + wbString(ANAM, 'Tag', 0, cpNormal, True) + ]); + + wbRecord(FSTS, 'Footstep Set', [ + wbEDID, + wbStruct(XCNT, 'Count', [ + wbInteger('Walk Forward Sets', itU32), + wbInteger('Run Forward Sets', itU32), + wbInteger('Walk Forward Alternate Sets', itU32), + wbInteger('Run Forward Alternate Sets', itU32), + wbInteger('Walk Forward Alternate 2 Sets', itU32) + ], cpNormal, True), + wbArray(DATA, 'Footstep Sets', wbFormIDCk('Footstep', [FSTP]), 0, nil, nil, cpNormal, True) + ]); + + wbSMNodeFlags := wbFlags([ + 'Random', + 'Warn if no child quest started' + ]); + + wbRecord(SMBN, 'Story Manager Branch Node', [ + wbEDID, + wbFormIDCkNoReach(PNAM, 'Parent ', [SMQN, SMBN, SMEN, NULL]), + wbFormIDCkNoReach(SNAM, 'Previous Sibling ', [SMQN, SMBN, SMEN, NULL], False, cpBenign), + wbCITCReq, + wbCTDAsCount, + wbInteger(DNAM, 'Flags', itU32, wbSMNodeFlags), + wbInteger(XNAM, 'Max concurrent quests', itU32) + ], False, nil, cpNormal, False, nil, wbConditionsAfterSet); + + wbRecord(SMQN, 'Story Manager Quest Node', [ + wbEDID, + wbFormIDCkNoReach(PNAM, 'Parent ', [SMQN, SMBN, SMEN, NULL]), + wbFormIDCkNoReach(SNAM, 'Previous Sibling ', [SMQN, SMBN, SMEN, NULL], False, cpBenign), + wbCITCReq, + wbCTDAsCount, + wbStruct(DNAM, 'Flags', [ + wbInteger('Node Flags', itU16, wbSMNodeFlags), + wbInteger('Quest Flags', itU16, wbFlags([ + 'Do all before repeating', + 'Shares event', + 'Num quests to run' + ])) + ]), + wbInteger(XNAM, 'Max concurrent quests', itU32), + wbInteger(MNAM, 'Num quests to run', itU32), + wbInteger(QNAM, 'Quest Count', itU32, nil, cpBenign, True), + wbRArray('Quests', wbRStructSK([0], 'Quest', [ + wbFormIDCk(NNAM, 'Quest', [QUST], False, cpBenign), + wbInteger(FNAM, 'Flags', itU32, wbEmptyBaseFlags, cpBenign), + wbFloat(RNAM, 'Hours until reset', cpBenign, False, 1/24) + ], []), cpBenign, False, nil, wbSMQNQuestsAfterSet) + ], False, nil, cpNormal, False, nil, wbConditionsAfterSet); + + wbRecord(SMEN, 'Story Manager Event Node', [ + wbEDID, + wbFormIDCkNoReach(PNAM, 'Parent ', [SMQN, SMBN, SMEN, NULL]), + wbFormIDCkNoReach(SNAM, 'Previous Sibling ', [SMQN, SMBN, SMEN, NULL], False, cpBenign), + wbCITCReq, + wbCTDAsCount, + wbInteger(DNAM, 'Flags', itU32, wbSMNodeFlags), + wbInteger(XNAM, 'Max concurrent quests', itU32), + wbInteger(ENAM, 'Type', itU32, wbQuestEventEnum) + ], False, nil, cpNormal, False, nil, wbConditionsAfterSet) + .SetSummaryKey([7]); +end; + +procedure DefineTES5j; +begin + wbRecord(DLBR, 'Dialog Branch', [ + wbEDID, + wbFormIDCkNoReach(QNAM, 'Quest', [QUST], False, cpNormal, True), + wbInteger(TNAM, 'Category', itU32, wbEnum([ + {0} 'Player', + {1} 'Command' + ])), + wbInteger(DNAM, 'Flags', itU32, wbFlags([ + {0x01} 'Top-Level', + {0x02} 'Blocking', + {0x04} 'Exclusive' + ])), + wbFormIDCk(SNAM, 'Starting Topic', [DIAL], False, cpNormal, True) + ]); + + wbRecord(MUST, 'Music Track', [ + wbEDID, + wbInteger(CNAM, 'Track Type', itU32, wbEnum([], [ + Int64($23F678C3), 'Palette', + Int64($6ED7E048), 'Single Track', + Int64($A1A9C4D5), 'Silent Track' + ]), cpNormal, True), + wbFloat(FLTV, 'Duration'), + wbFloat(DNAM, 'Fade-Out'), + wbString(ANAM, 'Track FileName'), + wbString(BNAM, 'Finale FileName'), + wbStruct(LNAM, 'Loop Data', [ + wbFloat('Loop Begins'), + wbFloat('Loop Ends'), + wbInteger('Loop Count', itU32) + ]), + wbArray(FNAM, 'Cue Points', wbFloat('Point')).IncludeFlag(dfNotAlignable), + wbCITC, + wbCTDAsCount, + wbArray(SNAM, 'Tracks', wbFormIDCk('Track', [MUST, NULL])) + ], True, nil, cpNormal, False, nil, wbConditionsAfterSet); + + wbRecord(DLVW, 'Dialog View', [ + wbEDID, + wbFormIDCk(QNAM, 'Quest', [QUST], False, cpNormal, True), + wbRArray('Branches', wbFormIDCk(BNAM, 'Branch', [DLBR])), + wbRArray('Unknown TNAM', wbRStruct('Unknown', [ + wbUnknown(TNAM) + ], [])), + wbUnknown(ENAM), + wbUnknown(DNAM) + ]); + + wbRecord(WOOP, 'Word of Power', [ + wbEDID, + wbFULL, + wbLString(TNAM, 'Translation', 0, cpTranslate, True) + ]); + + wbRecord(SHOU, 'Shout', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000080} 7, 'Treat spells as powers' + ])), [ + wbEDID, + wbFULL, + wbMDOB, + wbDESC, + {>>> Don't sort <<<} + wbRArray('Words of Power', + wbStruct(SNAM, '', [ + wbFormIDCk('Word', [WOOP, NULL]), + wbFormIDCk('Spell', [SPEL, NULL]), + wbFloat('Recovery Time') + ]) + ).IncludeFlag(dfNotAlignable) + ]); + + wbRecord(EQUP, 'Equip Type', [ + wbEDID, + wbArray(PNAM, 'Slot Parents', wbFormID('Can Be Equipped'), 0, nil, nil, cpNormal, False), + wbInteger(DATA, 'Use All Parents', itU32, wbEnum(['False', 'True'])) + ]); + + wbRecord(RELA, 'Relationship', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000040} 6, 'Secret' + ])), [ + wbEDID, + wbStruct(DATA, 'Data', [ + wbFormIDCkNoReach('Parent', [NPC_, NULL]), + wbFormIDCkNoReach('Child', [NPC_, NULL]), + wbInteger('Rank', itU16, wbEnum([ + 'Lover', + 'Ally', + 'Confidant', + 'Friend', + 'Acquaintance', + 'Rival', + 'Foe', + 'Enemy', + 'Archnemesis' + ])), + wbByteArray('Unknown', 1), + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'Unknown 1', + {0x02} 'Unknown 2', + {0x04} 'Unknown 3', + {0x08} 'Unknown 4', + {0x10} 'Unknown 5', + {0x20} 'Unknown 6', + {0x40} 'Unknown 7', + {0x80} 'Secret' + ])), + wbFormIDCk('Association Type', [ASTP, NULL]) + ]) + ]); + + wbRecord(SCEN, 'Scene', [ + wbEDID, + wbVMADFragmentedSCEN, + wbInteger(FNAM, 'Flags', itU32, wbFlags([ + 'Begin on Quest Start', + 'Stop on Quest End', + 'Show All Text', + 'Repeat Conditions While True', + 'Interruptible' + ])), + wbRArray('Phases', + wbRStruct('Phase', [ + wbEmpty(HNAM, 'Marker Phase Start', cpNormal, True), + wbString(NAM0, 'Name', 0, cpNormal, True), + // CTDA before or after next + //wbEmpty(NEXT, 'Marker'), + wbRStruct('Start Conditions', [wbCTDAs], []), + wbEmpty(NEXT, 'Marker', cpNormal, True), + wbRStruct('Completion Conditions', [wbCTDAs], []), + {>>> BEGIN leftover from earlier CK versions <<<} + wbRStruct('Unused', [ + wbUnknown(SCHR), + wbUnknown(SCDA), + wbUnknown(SCTX), + wbUnknown(QNAM), + wbUnknown(SCRO) + ], [], cpIgnore, false, wbNeverShow), + wbEmpty(NEXT, 'Marker', cpNormal, True), + wbRStruct('Unused', [ + wbUnknown(SCHR), + wbUnknown(SCDA), + wbUnknown(SCTX), + wbUnknown(QNAM), + wbUnknown(SCRO) + ], [], cpIgnore, false, wbNeverShow), + {>>> END leftover from earlier CK versions begin <<<} + wbInteger(WNAM, 'Editor Width', itU32, nil, cpNormal, True, false, nil, nil, 200), + wbEmpty(HNAM, 'Marker Phase End', cpNormal, True) + ], []) + ), + wbRArray('Actors', wbRStruct('Actor', [ + wbInteger(ALID, 'Actor ID', itU32, nil, cpNormal, True), + wbInteger(LNAM, 'Flags', itU32, wbFlags([ + 'No Player Activation', + 'Optional' + ]), cpNormal, True), + wbInteger(DNAM, 'Behaviour Flags', itU32, wbFlags([ + 'Death Pause (unsused)', + 'Death End', + 'Combat Pause', + 'Combat End', + 'Dialogue Pause', + 'Dialogue End', + 'OBS_COM Pause', + 'OBS_COM End' + ]), cpNormal, True, false, nil, nil, 26) + ], [])), + wbRArray('Actions', wbRStruct('Action', [ + wbInteger(ANAM, 'Type', itU16, wbEnum([ + 'Dialogue', + 'Package', + 'Timer' + ]), cpNormal, True), + wbString(NAM0, 'Name'), + wbInteger(ALID, 'Actor ID', itS32), + wbUnknown(LNAM), + wbInteger(INAM, 'Index', itU32), + wbInteger(FNAM, 'Flags', itU32, wbFlags([ + {0x00000001} 'Unknown 1', + {0x00000002} 'Unknown 2', + {0x00000004} 'Unknown 3', + {0x00000008} 'Unknown 4', + {0x00000010} 'Unknown 5', + {0x00000020} 'Unknown 6', + {0x00000040} 'Unknown 7', + {0x00000080} 'Unknown 8', + {0x00000100} 'Unknown 9', + {0x00000200} 'Unknown 10', + {0x00000400} 'Unknown 11', + {0x00000800} 'Unknown 12', + {0x00001000} 'Unknown 13', + {0x00002000} 'Unknown 14', + {0x00004000} 'Unknown 15', + {0x00008000} 'Face Target', + {0x00010000} 'Looping', + {0x00020000} 'Headtrack Player' + ])), + wbInteger(SNAM, 'Start Phase', itU32), + wbInteger(ENAM, 'End Phase', itU32), + wbFloat(SNAM, 'Timer Seconds'), + wbRArray('Packages', wbFormIDCk(PNAM, 'Package', [PACK])), + wbFormIDCk(DATA, 'Topic', [DIAL, NULL]), + wbInteger(HTID, 'Headtrack Actor ID', itS32), + wbFloat(DMAX, 'Looping - Max'), + wbFloat(DMIN, 'Looping - Min'), + wbInteger(DEMO, 'Emotion Type', itU32, wbEmotionTypeEnum), + wbInteger(DEVA, 'Emotion Value', itU32), + {>>> BEGIN leftover from earlier CK versions <<<} + wbRStruct('Unused', [ + wbUnknown(SCHR), + wbUnknown(SCDA), + wbUnknown(SCTX), + wbUnknown(QNAM), + wbUnknown(SCRO) + ], [], cpIgnore, false, wbNeverShow), + {>>> END leftover from earlier CK versions <<<} + wbEmpty(ANAM, 'End Marker', cpNormal, True) + ], [])), + {>>> BEGIN leftover from earlier CK versions <<<} + wbRStruct('Unused', [ + wbUnknown(SCHR), + wbUnknown(SCDA), + wbUnknown(SCTX), + wbUnknown(QNAM), + wbUnknown(SCRO) + ], [], cpIgnore, false, wbNeverShow), + wbEmpty(NEXT, 'Marker', cpNormal, True), + wbRStruct('Unused', [ + wbUnknown(SCHR), + wbUnknown(SCDA), + wbUnknown(SCTX), + wbUnknown(QNAM), + wbUnknown(SCRO) + ], [], cpIgnore, false, wbNeverShow), + {>>> END leftover from earlier CK versions <<<} + wbFormIDCk(PNAM, 'Quest', [QUST]), + wbInteger(INAM, 'Last Action Index', itU32), + wbUnknown(VNAM), + wbCTDAs + ]); + + wbRecord(ASTP, 'Association Type', [ + wbEDID, + wbString(MPRT, 'Male Parent Title'), + wbString(FPRT, 'Female Parent Title'), + wbString(MCHT, 'Male Child Title'), + wbString(FCHT, 'Female Child Title'), + wbInteger(DATA, 'Flags', itU32, wbFlags([ + 'Family Association' + ])) + ]); +end; + +procedure DefineTES5k; +begin + + wbRecord(OTFT, 'Outfit', [ + wbEDID, + wbArrayS(INAM, 'Items', wbFormIDCk('Item', [ARMO, LVLI])) + ]); + + wbRecord(ARTO, 'Art Object', [ + wbEDID, + wbOBND(True), + wbGenericModel, + wbInteger(DNAM, 'Art Type', itU32, wbEnum([ + 'Magic Casting', + 'Magic Hit Effect', + 'Enchantment Effect' + ])) + ]).SetSummaryKey([2]); + + wbRecord(MATO, 'Material Object', [ + wbEDID, + wbGenericModel, + wbRArray('Property Data', + wbByteArray(DNAM, 'Data', 0, cpIgnore, False, False, wbNeverShow) + ), + IsSSE( + wbStruct(DATA, 'Directional Material Data', [ + wbFloat('Falloff Scale'), + wbFloat('Falloff Bias'), + wbFloat('Noise UV Scale'), + wbFloat('Material UV Scale'), + wbStruct('Projection Vector', [ + wbFloat('X'), + wbFloat('Y'), + wbFloat('Z') + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + wbFloat('Normal Dampener'), + wbFloatColors('Single Pass Color'), + wbInteger('Flags', itU32, wbFlags(['Single Pass'])), + // SSE + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'Snow' + ])), + wbByteArray('Unused', 3, cpIgnore) + ], cpNormal, True, nil, 5), + wbStruct(DATA, 'Directional Material Data', [ + wbFloat('Falloff Scale'), + wbFloat('Falloff Bias'), + wbFloat('Noise UV Scale'), + wbFloat('Material UV Scale'), + wbStruct('Projection Vector', [ + wbFloat('X'), + wbFloat('Y'), + wbFloat('Z') + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + wbFloat('Normal Dampener'), + wbFloatColors('Single Pass Color'), + wbInteger('Flags', itU32, wbFlags(['Single Pass'])) + ], cpNormal, True, nil, 5) + ) + ]); + + wbRecord(MOVT, 'Movement Type', [ + wbEDID, + wbString(MNAM, 'Name'), + wbStruct(SPED, 'Default Data', [ + wbFloat('Left Walk'), + wbFloat('Left Run'), + wbFloat('Right Walk'), + wbFloat('Right Run'), + wbFloat('Forward Walk'), + wbFloat('Forward Run'), + wbFloat('Back Walk'), + wbFloat('Back Run'), + wbFloat('Rotate in Place Walk', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), + wbFloat('Rotate in Place Run', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), + wbFloat('Rotate while Moving Run', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) + ], cpNormal, True, nil, 10), + wbStruct(INAM, 'Anim Change Thresholds', [ + wbFloat('Directional', cpNormal, True, 180/Pi), + wbFloat('Movement Speed'), + wbFloat('Rotation Speed', cpNormal, True, 180/Pi) + ]) + ]); + + wbRecord(SNDR, 'Sound Descriptor', [ + wbEDID, + wbInteger(CNAM, 'Descriptor Type', itU32, wbEnum([], [ + Int64($1EEF540A), 'Standard' + ])), + wbFormID(GNAM, 'Category'), + wbFormIDCk(SNAM, 'Alternate Sound For', [SNDR, NULL]), + wbSoundDescriptorSounds, + wbFormIDCk(ONAM, 'Output Model', [SOPM, NULL]), + wbLString(FNAM, 'String', 0, cpIgnore), + wbCTDAs, + wbStruct(LNAM, 'Values', [ + wbByteArray('Unknown', 1), + wbInteger('Looping', itU8, wbEnum([], [ + $00 , 'None', + $08 , 'Loop', + $10 , 'Envelope Fast', + $20 , 'Envelope Slow' + ])), + wbByteArray('Unknown', 1), + wbInteger('Rumble Send Value = (Small / 7) + ((Big / 7) * 16)', itU8) + ]), + wbStruct(BNAM, 'Values', [ + wbInteger('% Frequency Shift', itS8), + wbInteger('% Frequency Variance', itS8), + wbInteger('Priority', itU8), + wbInteger('db Variance', itU8), + wbInteger('Static Attenuation (db)', itU16, wbDiv(100)) + ]) + ]); + + wbRecord(DUAL, 'Dual Cast Data', [ + wbEDID, + wbOBND(True), + wbStruct(DATA, 'Data', [ + wbFormIDCk('Projectile', [PROJ, NULL]), + wbFormIDCk('Explosion', [EXPL, NULL]), + wbFormIDCk('Effect Shader', [EFSH, NULL]), + wbFormIDCk('Hit Effect Art', [ARTO, NULL]), + wbFormIDCk('Impact Data Set', [IPDS, NULL]), + wbInteger('Inherit Scale', itU32, wbFlags([ + 'Hit Effect Art', + 'Projectile', + 'Explosion' + ])) + ], cpNormal, True) + ]); + + wbRecord(SNCT, 'Sound Category', [ + wbEDID, + wbFULL, + wbInteger(FNAM, 'Flags', itU32, wbFlags([ + 'Mute When Submerged', + 'Should Appear on Menu' + ]), cpNormal, True), + wbFormIDCk(PNAM, 'Parent', [SNCT]), + wbInteger(VNAM, 'Static Volume Multiplier', itU16, wbDiv(65535)), + wbInteger(UNAM, 'Default Menu Value', itU16, wbDiv(65535)) + ]); + + wbRecord(SOPM, 'Sound Output Model', [ + wbEDID, + wbStruct(NAM1, 'Data', [ + wbInteger('Flags', itU8, wbFlags([ + 'Attenuates With Distance', + 'Allows Rumble' + ])), + wbByteArray('Unknown', 2), + wbInteger('Reverb Send %', itU8) + ]), + wbUnknown(FNAM), // leftover, unused + wbInteger(MNAM, 'Type', itU32, wbEnum([ + 'Uses HRTF', + 'Defined Speaker Output' + ])), + wbUnknown(CNAM), // leftover, unused + wbUnknown(SNAM), // leftover, unused + wbStruct(ONAM, 'Output Values', [ + wbArray('Channels', wbStruct('', [ + wbInteger('L', itU8), + wbInteger('R', itU8), + wbInteger('C', itU8), + wbInteger('LFE', itU8), + wbInteger('RL', itU8), + wbInteger('RR', itU8), + wbInteger('BL', itU8), + wbInteger('BR', itU8) + ]), [ + 'Channel 0', + 'Channel 1', + 'Channel 2? (unused)' + ]) + ]), + wbStruct(ANAM, 'Attenuation Values', [ + wbByteArray('Unknown', 4), + wbFloat('Min Distance'), + wbFloat('Max Distance'), + wbArray('Curve', wbInteger('Value', itU8), 5), + wbByteArray('Unknown', 3) + ]) + ]); + + wbRecord(COLL, 'Collision Layer', [ + wbEDID, + wbDESCReq, + wbInteger(BNAM, 'Index', itU32, nil, cpNormal, True), + wbStruct(FNAM, 'Debug Color', [ + wbInteger('Red', itU8), + wbInteger('Green', itU8), + wbInteger('Blue', itU8), + wbInteger('Unused', itU8) + ], cpNormal, True).SetToStr(wbRGBAToStr).IncludeFlag(dfCollapsed, wbCollapseRGBA), + wbInteger(GNAM, 'Flags', itU32, wbFlags([ + {0x00000001} 'Trigger Volume', + {0x00000002} 'Sensor', + {0x00000004} 'Navmesh Obstacle' + ]), cpNormal, True), + wbString(MNAM, 'Name', 0, cpNormal, True), + wbInteger(INTV, 'Interactables Count', itU32, nil, cpNormal, True), + wbArrayS(CNAM, 'Collides With', wbFormIDCk('Forms', [COLL]), 0, cpNormal, False) + ]); + + wbRecord(CLFM, 'Color', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000004} 2, 'Non-Playable' + ])), [ + wbEDID, + wbFULL, + wbCNAM(True), + wbInteger(FNAM, 'Playable', itU32, wbEnum(['False', 'True']), cpNormal, True) + ]); +end; + +procedure DefineTES5l; +begin + wbRecord(REVB, 'Reverb Parameters', [ + wbEDID, + wbStruct(DATA, 'Data', [ + wbInteger('Decay Time (ms)', itU16), + wbInteger('HF Reference (Hz)', itU16), + wbInteger('Room Filter', itS8), + wbInteger('Room HF Filter', itS8), + wbInteger('Reflections', itS8), + wbInteger('Reverb Amp', itS8), + wbInteger('Decay HF Ratio', itU8, wbDiv(100)), + wbInteger('Reflect Delay (ms), scaled', itU8), + wbInteger('Reverb Delay (ms)', itU8), + wbInteger('Diffusion %', itU8), + wbInteger('Density %', itU8), + wbInteger('Unknown', itU8) + ], cpNormal, True) + ]); + + wbRecord(GRAS, 'Grass', [ + wbEDID, + wbOBND(True), + wbGenericModel, + wbStruct(DATA, '', [ + wbInteger('Density', itU8), + wbInteger('Min Slope', itU8), + wbInteger('Max Slope', itU8), + wbByteArray('Unknown', 1), + wbInteger('Units From Water', itU16), + wbByteArray('Unknown', 2), + wbInteger('Units From Water Type', itU32, wbEnum([ + 'Above - At Least', + 'Above - At Most', + 'Below - At Least', + 'Below - At Most', + 'Either - At Least', + 'Either - At Most', + 'Either - At Most Above', + 'Either - At Most Below' + ])), + wbFloat('Position Range'), + wbFloat('Height Range'), + wbFloat('Color Range'), + wbFloat('Wave Period'), + wbInteger('Flags', itU8, wbFlags([ + 'Vertex Lighting', + 'Uniform Scaling', + 'Fit to Slope' + ])), + wbByteArray('Unknown', 3) + ], cpNormal, True) + ]); + + wbRecord(IDLE, 'Idle Animation', [ + wbEDID, + wbCTDAs, + wbString(DNAM, 'FileName'), + wbString(ENAM, 'Animation Event'), + wbArray(ANAM, 'Related Idle Animations', wbFormIDCk('Related Idle Animation', [AACT, IDLE, NULL]), + ['Parent', 'Previous Sibling'], cpNormal, True), + wbStruct(DATA, 'Data (unused)', [ + wbStruct('Looping seconds (both 255 forever)', [ + wbInteger('Min', itU8), + wbInteger('Max', itU8) + ]), + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'Parent', + {0x02} 'Sequence', + {0x04} 'No Attacking', + {0x04} 'Blocking' + ], True)), + wbInteger('Animation Group Section', itU8{, wbIdleAnam}), + wbInteger('Replay Delay', itU16) + ], cpIgnore, True) + ]); + + wbRecord(INFO, 'Dialog response', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00002000} 13, 'Actor Changed' + ])), [ + wbEDID, + wbVMADFragmentedINFO, + wbUnknown(DATA), + wbStruct(ENAM, 'Response flags', [ + wbInteger('Flags', itU16, wbFlags([ + {0x0001} 'Goodbye', + {0x0002} 'Random', + {0x0004} 'Say once', + {0x0008} 'Requires Player Activation', + {0x0010} 'Info Refusal', + {0x0020} 'Random end', + {0x0040} 'Invisible continue', + {0x0080} 'Walk Away', + {0x0100} 'Walk Away Invisible in Menu', + {0x0200} 'Force subtitle', + {0x0400} 'Can move while greeting', + {0x0800} 'No LIP File', + {0x1000} 'Requires post-processing', + {0x2000} 'Audio Output Override', + {0x4000} 'Spends favor points', + {0x8000} 'Unknown 16' + ])), + wbInteger('Reset Hours', itU16, wbDiv(2730)) + ]), + wbFormIDCk(TPIC, 'Topic', [DIAL]), + wbFormIDCkNoReach(PNAM, 'Previous INFO', [INFO, NULL], False, cpBenign).SetAfterSet(wbINFOPNAMAfterSet), + wbInteger(CNAM, 'Favor Level', itU8, wbEnum([ + 'None', + 'Small', + 'Medium', + 'Large' + ])), + + wbRArray('Link To', wbFormIDCk(TCLT, 'Response', [DIAL, INFO, NULL])), + wbFormID(DNAM, 'Response Data'), + + wbRArray('Responses', wbRStruct('Response', [ + wbStruct(TRDT, 'Response Data', [ + wbInteger('Emotion Type', itU32, wbEmotionTypeEnum), + wbInteger('Emotion Value', itU32), + wbByteArray('Unused', 4), + wbInteger('Response number', itU8), + wbByteArray('Unused', 3), + wbFormIDCk('Sound', [SNDR, NULL]), + wbInteger('Flags', itU8, wbFlags([ + 'Use Emotion Animation' + ])), + wbByteArray('Unused', 3) + ]), + wbLStringKC(NAM1, 'Response Text', 0, cpTranslate), + wbString(NAM2, 'Script Notes'), + wbString(NAM3, 'Edits'), + wbFormIDCk(SNAM, 'Idle Animations: Speaker', [IDLE]), + wbFormIDCk(LNAM, 'Idle Animations: Listener', [IDLE]) + ], [])), + + wbCTDAs, + + {>>> BEGIN leftover from earlier CK versions <<<} + wbRArray('Unknown', + wbRStruct('Unknown', [ + wbUnknown(SCHR), + wbFormID(QNAM, 'Unknown'), + wbEmpty(NEXT, 'Marker', cpNormal, True) + ], []), cpIgnore, false, nil, nil, wbNeverShow + ), + {>>> END leftover from earlier CK versions <<<} + + wbLStringKC(RNAM, 'Prompt', 0, cpTranslate), + wbFormIDCkNoReach(ANAM, 'Speaker', [NPC_]), + wbFormIDCk(TWAT, 'Walk Away Topic', [DIAL]), + wbFormIDCk(ONAM, 'Audio Output Override', [SOPM]) + ], False, wbINFOAddInfo, cpNormal, False, nil{wbINFOAfterLoad}); + + wbRecord(INGR, 'Ingredient', [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbKSIZ, + wbKWDAs, + wbGenericModel, + wbICON, + wbDEST, + wbETYP, + wbYNAM, + wbZNAM, + wbStruct(DATA, '', [ + wbInteger('Value', itS32), + wbFloat('Weight') + ], cpNormal, True), + wbStruct(ENIT, 'Effect Data', [ + wbInteger('Ingredient Value', itS32), + wbInteger('Flags', itU32, wbFlags([ + {0x00000001} 'No auto-calculation', + {0x00000002} 'Food item', + {0x00000004} 'Unknown 3', + {0x00000008} 'Unknown 4', + {0x00000010} 'Unknown 5', + {0x00000020} 'Unknown 6', + {0x00000040} 'Unknown 7', + {0x00000080} 'Unknown 8', + {0x00000100} 'References Persist' + ])) + ], cpNormal, True), + wbEffectsReq + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); + + wbRecord(KEYM, 'Key', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000004} 2, 'Non-Playable' + ])), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULLReq, + wbGenericModel, + wbICON, + wbDEST, + wbYNAM, + wbZNAM, + wbKSIZ, + wbKWDAs, + wbStruct(DATA, '', [ + wbInteger('Value', itS32), + wbFloat('Weight') + ], cpNormal, True) + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); + + if wbSimpleRecords then begin + + wbRecord(LAND, 'Landscape', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00040000} 18, 'Compressed' + ]), [18]), [ + wbByteArray(DATA, 'Unknown'), + wbByteArray(VNML, 'Vertex Normals'), + wbByteArray(VHGT, 'Vertex Height Map'), + wbByteArray(VCLR, 'Vertex Colours'), + wbLandscapeLayers(wbSimpleRecords), + wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) + ]); + + end else begin + + wbRecord(LAND, 'Landscape', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00040000} 18, 'Compressed' + ]), [18]), [ + wbInteger(DATA, 'Flags', itU32, wbFlags([ + 'Vertex Normals / Height Map', + 'Vertex Colours', + 'Layers', + 'Unknown 4', + 'Unknown 5', + '', + '', + '', + '', + '', + 'MPCD' + ])), + wbVertexColumns(VNML, 'Vertex Normals'), + wbVertexHeightMap, + wbVertexColumns(VCLR, 'Vertex Colours'), + wbLandscapeLayers(wbSimpleRecords), + wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])), + wbRArray('Unknown', wbUnknown(MPCD)) + ]); + + end; + + wbRecord(LIGH, 'Light', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00010000} 16, 'Random Anim Start', + {0x00020000} 17, 'Portal-strict', + {0x02000000} 25, 'Obstacle' + ])), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbGenericModel, + wbDEST, + wbFULL, + wbICON, + wbStruct(DATA, '', [ + wbInteger('Time', itS32), + wbInteger('Radius', itU32), + wbByteColors, + wbInteger('Flags', itU32, wbFlags([ + {0x00000001} 'Dynamic', + {0x00000002} 'Can be Carried', + {0x00000004} 'Negative', + {0x00000008} 'Flicker', + {0x00000010} 'Unknown', + {0x00000020} 'Off By Default', + {0x00000040} 'Flicker Slow', + {0x00000080} 'Pulse', + {0x00000100} 'Pulse Slow', + {0x00000200} 'Spot Light', + {0x00000400} 'Shadow Spotlight', + {0x00000800} 'Shadow Hemisphere', + {0x00001000} 'Shadow Omnidirectional', + {0x00002000} 'Portal-strict' + ])), + wbFloat('Falloff Exponent'), + wbFloat('FOV'), + wbFloat('Near Clip'), + wbStruct('Flicker Effect', [ + wbFloat('Period', cpNormal, False, 0.01), + wbFloat('Intensity Amplitude'), + wbFloat('Movement Amplitude') + ]), + wbInteger('Value', itU32), + wbFloat('Weight') + ], cpNormal, True), + wbFloat(FNAM, 'Fade value', cpNormal, True), + wbFormIDCk(SNAM, 'Sound', [SNDR]) + ], False, nil, cpNormal, False, wbLIGHAfterLoad); +end; + +procedure DefineTES5m; +var + wbLeveledListEntryItem: IwbRecordMemberDef; + wbLeveledListEntryNPC: IwbRecordMemberDef; + wbLeveledListEntrySpell: IwbRecordMemberDef; +begin + + wbRecord(LSCR, 'Load Screen', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000400} 10, 'Displays In Main Menu' + ])), [ + wbEDID, + wbICON, + wbDESCReq, + wbCTDAs, + wbFormIDCk(NNAM, 'Loading Screen NIF', [STAT, NULL], False, cpNormal, True), + wbFloat(SNAM, 'Initial Scale'), + wbStruct(RNAM, 'Initial Rotation', [ + wbInteger('X', itS16), + wbInteger('Y', itS16), + wbInteger('Z', itS16) + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + wbStruct(ONAM, 'Rotation Offset Constraints', [ + wbInteger('Min', itS16), + wbInteger('Max', itS16) + ]), + wbStruct(XNAM, 'Initial Translation Offset', [ + wbFloat('X'), + wbFloat('Y'), + wbFloat('Z') + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + wbString(MOD2, 'Camera Path', 0, cpNormal, False) + ]); + + wbRecord(LTEX, 'Landscape Texture', [ + wbEDID, + wbFormIDCk(TNAM, 'Texture Set', [TXST], False, cpNormal, False), + wbFormIDCk(MNAM, 'Material Type', [MATT, NULL], False, cpNormal, True), + wbStruct(HNAM, 'Havok Data', [ + wbInteger('Friction', itU8), + wbInteger('Restitution', itU8) + ], cpNormal, True), + wbInteger(SNAM, 'Texture Specular Exponent', itU8, nil, cpNormal, True), + wbRArrayS('Grasses', wbFormIDCk(GNAM, 'Grass', [GRAS])), + // SSE + wbInteger(INAM, IsSSE('Flags', 'Unused'), itU32, wbFlags([ + {0x01} 'Is Snow' + ])) + ]); + + wbLeveledListEntryItem := + wbRStructExSK([0], [1], 'Leveled List Entry', [ + wbStructExSK(LVLO, [0, 2], [3], 'Base Data', [ + wbInteger('Level', itU16), + wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow), + wbFormIDCk('Reference', [ARMO, AMMO, APPA, MISC, WEAP, BOOK, LVLI, KEYM, ALCH, LIGH, INGR, SLGM, SCRL]), + wbInteger('Count', itU16), + wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow) + ]) + .SetSummaryKeyOnValue([0, 3, 2]) + .SetSummaryPrefixSuffixOnValue(0, '[Lv', ']') + .SetSummaryPrefixSuffixOnValue(3, '', 'x') + .SetSummaryDelimiterOnValue(' ') + .IncludeFlagOnValue(dfSummaryMembersNoName) + .IncludeFlagOnValue(dfSummaryNoSortKey) + , wbCOED + ], []) + .SetSummaryMemberMaxDepth(0, 1) + .IncludeFlag(dfCollapsed, wbCollapseLeveledItems); + + wbLeveledListEntryNPC := + wbRStructExSK([0], [1], 'Leveled List Entry', [ + wbStructExSK(LVLO, [0, 2], [3], 'Base Data', [ + wbInteger('Level', itS16), + wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow), + wbFormIDCk('Reference', [NPC_, LVLN]), + wbInteger('Count', itS16), + wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow) + ]) + .SetSummaryKeyOnValue([0, 3, 2]) + .SetSummaryPrefixSuffixOnValue(0, '[Lv', ']') + .SetSummaryPrefixSuffixOnValue(3, '', 'x') + .SetSummaryDelimiterOnValue(' ') + .IncludeFlagOnValue(dfSummaryMembersNoName) + .IncludeFlagOnValue(dfSummaryNoSortKey) + , wbCOED + ], []) + .SetSummaryMemberMaxDepth(0, 1) + .IncludeFlag(dfCollapsed, wbCollapseLeveledItems); + + wbLeveledListEntrySpell := + wbRStructSK([0], 'Leveled List Entry', [ + wbStructExSK(LVLO, [0, 2], [3], 'Base Data', [ + wbInteger('Level', itU16), + wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow), + wbFormIDCk('Reference', [SPEL, LVSP]), + wbInteger('Count', itU16), + wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow) + ]) + .SetSummaryKeyOnValue([0, 3, 2]) + .SetSummaryPrefixSuffixOnValue(0, '[Lv', ']') + .SetSummaryPrefixSuffixOnValue(3, '', 'x') + .SetSummaryDelimiterOnValue(' ') + .IncludeFlagOnValue(dfSummaryMembersNoName) + .IncludeFlagOnValue(dfSummaryNoSortKey) + ], []) + .SetSummaryMemberMaxDepth(0, 1) + .IncludeFlag(dfCollapsed, wbCollapseLeveledItems); + + wbRecord(LVLN, 'Leveled NPC', [ + wbEDID, + wbOBND(True), + wbLVLD, + wbInteger(LVLF, 'Flags', itU8, wbFlags([ + {0x01} 'Calculate from all levels <= player''s level', + {0x02} 'Calculate for each item in count' + ]), cpNormal, True), + wbFormIDCk(LVLG, 'Global', [GLOB]), + wbLLCT, + wbRArrayS('Leveled List Entries', wbLeveledListEntryNPC, cpNormal, False, nil, wbLVLOsAfterSet), + wbGenericModel + ], False, nil, cpNormal, False, nil, wbLLEAfterSet); + + wbRecord(LVLI, 'Leveled Item', [ + wbEDID, + wbOBND(True), + wbLVLD, + wbInteger(LVLF, 'Flags', itU8, wbFlags([ + {0x01} 'Calculate from all levels <= player''s level', + {0x02} 'Calculate for each item in count', + {0x04} 'Use All', + {0x08} 'Special Loot' + ]), cpNormal, True), + wbFormIDCk(LVLG, 'Global', [GLOB]), + wbLLCT, + wbRArrayS('Leveled List Entries', wbLeveledListEntryItem, cpNormal, False, nil, wbLVLOsAfterSet) + ], False, nil, cpNormal, False, nil, wbLLEAfterSet); + + wbRecord(LVSP, 'Leveled Spell', [ + wbEDID, + wbOBND(True), + wbLVLD, + wbInteger(LVLF, 'Flags', itU8, wbFlags([ + {0x01} 'Calculate from all levels <= player''s level', + {0x02} 'Calculate for each item in count', + {0x04} 'Use All Spells' + ]), cpNormal, True), + wbLLCT, + wbRArrayS('Leveled List Entries', wbLeveledListEntrySpell, cpNormal, False, nil, wbLVLOsAfterSet) + ], False, nil, cpNormal, False, nil, wbLLEAfterSet); + + wbMGEFType := wbInteger('Archtype', itU32, wbEnum([ + {00} 'Value Modifier', + {01} 'Script', + {02} 'Dispel', + {03} 'Cure Disease', + {04} 'Absorb', + {05} 'Dual Value Modifier', + {06} 'Calm', + {07} 'Demoralize', + {08} 'Frenzy', + {09} 'Disarm', + {10} 'Command Summoned', + {11} 'Invisibility', + {12} 'Light', + {13} 'Unknown 13', + {14} 'Unknown 14', + {15} 'Lock', + {16} 'Open', + {17} 'Bound Weapon', + {18} 'Summon Creature', + {19} 'Detect Life', + {20} 'Telekinesis', + {21} 'Paralysis', + {22} 'Reanimate', + {23} 'Soul Trap', + {24} 'Turn Undead', + {25} 'Guide', + {26} 'Werewolf Feed', + {27} 'Cure Paralysis', + {28} 'Cure Addiction', + {29} 'Cure Poison', + {30} 'Concussion', + {31} 'Value and Parts', + {32} 'Accumulate Magnitude', + {33} 'Stagger', + {34} 'Peak Value Modifier', + {35} 'Cloak', + {36} 'Werewolf', + {37} 'Slow Time', + {38} 'Rally', + {39} 'Enhance Weapon', + {40} 'Spawn Hazard', + {41} 'Etherealize', + {42} 'Banish', + {43} 'Spawn Scripted Ref', + {44} 'Disguise', + {45} 'Grab Actor', + {46} 'Vampire Lord' + ]), cpNormal, False, nil, wbMGEFArchtypeAfterSet); + + wbMGEFData := wbRStruct('Magic Effect Data', [ + wbStruct(DATA, 'Data', [ + wbInteger('Flags', itU32, wbFlags([ + {0x00000001} 'Hostile', + {0x00000002} 'Recover', + {0x00000004} 'Detrimental', + {0x00000008} 'Snap to Navmesh', + {0x00000010} 'No Hit Event', + {0x00000020} 'Unknown 6', + {0x00000040} 'Unknown 7', + {0x00000080} 'Unknown 8', + {0x00000100} 'Dispel with Keywords', + {0x00000200} 'No Duration', + {0x00000400} 'No Magnitude', + {0x00000800} 'No Area', + {0x00001000} 'FX Persist', + {0x00002000} 'Unknown 14', + {0x00004000} 'Gory Visuals', + {0x00008000} 'Hide in UI', + {0x00010000} 'Unknown 17', + {0x00020000} 'No Recast', + {0x00040000} 'Unknown 19', + {0x00080000} 'Unknown 20', + {0x00100000} 'Unknown 21', + {0x00200000} 'Power Affects Magnitude', + {0x00400000} 'Power Affects Duration', + {0x00800000} 'Unknown 24', + {0x01000000} 'Unknown 25', + {0x02000000} 'Unknown 26', + {0x04000000} 'Painless', + {0x08000000} 'No Hit Effect', + {0x10000000} 'No Death Dispel', + {0x20000000} 'Unknown 30', + {0x40000000} 'Unknown 31', + {0x80000000} 'Unknown 32' + ])), + wbFloat('Base Cost'), + wbUnion('Assoc. Item', wbMGEFAssocItemDecider, [ + wbFormID('Unused', cpIgnore), + wbFormIDCk('Assoc. Item', [LIGH, NULL]), + wbFormIDCk('Assoc. Item', [WEAP, ARMO, NULL]), + wbFormIDCk('Assoc. Item', [NPC_, NULL]), + wbFormIDCk('Assoc. Item', [HAZD, NULL]), + wbFormIDCk('Assoc. Item', [SPEL, NULL]), + wbFormIDCk('Assoc. Item', [RACE, NULL]), + wbFormIDCk('Assoc. Item', [ENCH, NULL]), + wbFormIDCk('Assoc. Item', [KYWD, NULL]) + ], cpNormal, False, nil, wbMGEFAssocItemAfterSet), + wbInteger('Magic Skill', itS32, wbActorValueEnum), + wbInteger('Resist Value', itS32, wbActorValueEnum), + wbInteger('Counter Effect count', itU16), + wbByteArray('Unused', 2), + wbFormIDCk('Casting Light', [LIGH, NULL]), + wbFloat('Taper Weight'), + wbFormIDCk('Hit Shader', [EFSH, NULL]), + wbFormIDCk('Enchant Shader', [EFSH, NULL]), + wbInteger('Minimum Skill Level', itU32), + wbStruct('Spellmaking', [ + wbInteger('Area', itU32), + wbFloat('Casting Time') + ]), + wbFloat('Taper Curve'), + wbFloat('Taper Duration'), + wbFloat('Second AV Weight', cpNormal, False, nil, wbMGEFAV2WeightAfterSet), + wbMGEFType, + wbActorValue, + wbFormIDCk('Projectile', [PROJ, NULL]), + wbFormIDCk('Explosion', [EXPL, NULL]), + wbInteger('Casting Type', itU32, wbCastEnum), + wbInteger('Delivery', itU32, wbTargetEnum), + wbInteger('Second Actor Value', itS32, wbActorValueEnum), + wbFormIDCk('Casting Art', [ARTO, NULL]), + wbFormIDCk('Hit Effect Art', [ARTO, NULL]), + wbFormIDCk('Impact Data', [IPDS, NULL]), + wbFloat('Skill Usage Multiplier'), + wbStruct('Dual Casting', [ + wbFormIDCk('Art', [DUAL, NULL]), + wbFloat('Scale') + ]), + wbFormIDCk('Enchant Art', [ARTO, NULL]), + wbFormIDCk('Hit Visuals', [RFCT, NULL]), + wbFormIDCk('Enchant Visuals', [RFCT, NULL]), + wbFormIDCk('Equip Ability', [SPEL, NULL]), + wbFormIDCk('Image Space Modifier', [IMAD, NULL]), + wbFormIDCk('Perk to Apply', [PERK, NULL]), + wbInteger('Casting Sound Level', itU32, wbSoundLevelEnum), + wbStruct('Script Effect AI', [ + wbFloat('Score'), + wbFloat('Delay Time') + ]) + ], cpNormal, True) + ], []); + + wbRecord(MGEF, 'Magic Effect', [ + wbEDID, + wbVMAD, + wbFULL, + wbMDOB, + wbKSIZ, + wbKWDAs, + wbMGEFData, + wbRArrayS('Counter Effects', wbFormIDCk(ESCE, 'Effect', [MGEF]), cpNormal, False, nil, wbCounterEffectsAfterSet), + wbMagicEffectSounds, + wbLStringKC(DNAM, 'Magic Item Description', 0, cpTranslate), + wbCTDAs + ], False, nil, cpNormal, False, nil {wbMGEFAfterLoad}, wbMGEFAfterSet); + + wbRecord(MISC, 'Misc. Item', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000004} 2, 'Non-Playable' + ])), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbGenericModel, + wbICON, + wbDEST, + wbYNAM, + wbZNAM, + wbKSIZ, + wbKWDAs, + wbStruct(DATA, 'Data', [ + wbInteger('Value', itS32), + wbFloat('Weight') + ], cpNormal, True) + ], False, nil, cpNormal, False, wbRemoveEmptyKWDA, wbKeywordsAfterSet); + + wbRecord(APPA, 'Alchemical Apparatus', [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbGenericModel, + wbICON, + wbDEST, + wbYNAM, + wbZNAM, + wbInteger(QUAL, 'Quality', itS32, wbEnum([], [ + 0, 'Novice', + 1, 'Apprentice', + 2, 'Journeyman', + 3, 'Expert', + 4, 'Master' + ])), + wbDESC, + wbStruct(DATA, 'Data', [ + wbInteger('Value', itU32), + wbFloat('Weight') + ]) + ]); + + wbRecord(COBJ, 'Constructible Object', [ + wbEDID, + wbCOCT, + wbCNTOsNoReach, + wbCTDAs, + wbFormID(CNAM, 'Created Object'), + wbFormIDCkNoReach(BNAM, 'Workbench Keyword', [KYWD]), + wbInteger(NAM1, 'Created Object Count', itU16) + ], False, nil, cpNormal, False, nil, wbContainerAfterSet) + .SetSummaryKey([6, 4, 2, 3, 5]) + .SetSummaryMemberPrefixSuffix(6, '(', 'x') + .SetSummaryMemberPrefixSuffix(4, '', ')') + .SetSummaryMemberPrefixSuffix(2, 'from (', ')') + .SetSummaryMemberPrefixSuffix(3, 'when (', ')') + .SetSummaryMemberPrefixSuffix(5, 'at (', ')'); + + wbRecord(NPC_, 'Non-Player Character (Actor)', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000400} 10, 'Unknown 10', + {0x00040000} 18, 'Compressed', + {0x00080000} 19, 'Unknown 19', + {0x20000000} 29, 'Bleedout Override' + ]), [18]), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbStruct(ACBS, 'Configuration', [ + wbInteger('Flags', itU32, wbFlags([ + {0x00000001} 'Female', + {0x00000002} 'Essential', + {0x00000004} 'Is CharGen Face Preset', + {0x00000008} 'Respawn', + {0x00000010} 'Auto-calc stats', + {0x00000020} 'Unique', + {0x00000040} 'Doesn''t affect stealth meter', + {0x00000080} 'PC Level Mult', + {0x00000100} 'Use Template?', + {0x00000200} 'Unknown 9', + {0x00000400} 'Unknown 10', + {0x00000800} 'Protected', + {0x00001000} 'Unknown 12', + {0x00002000} 'Unknown 13', + {0x00004000} 'Summonable', + {0x00008000} 'Unknown 15', + {0x00010000} 'Doesn''t bleed', + {0x00020000} 'Unknown 17', + {0x00040000} 'Bleedout Override', + {0x00080000} 'Opposite Gender Anims', + {0x00100000} 'Simple Actor', + {0x00200000} 'looped script?', + {0x00400000} 'Unknown 22', + {0x00800000} 'Unknown 23', + {0x01000000} 'Unknown 24', + {0x02000000} 'Unknown 25', + {0x04000000} 'Unknown 26', + {0x08000000} 'Unknown 27', + {0x10000000} 'looped audio?', + {0x20000000} 'Is Ghost', + {0x40000000} 'Unknown 30', + {0x80000000} 'Invulnerable' + ])), + wbInteger('Magicka Offset', itS16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), + wbInteger('Stamina Offset', itS16, nil, cpNormal, False, nil{wbActorTemplateUseAIData}), + wbUnion('Level', wbNPCLevelDecider, [ + wbInteger('Level', itS16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), + wbInteger('Level Mult', itS16, wbDiv(1000), cpNormal, True, nil{wbActorTemplateUseStats}) + ], cpNormal, True, nil{wbActorTemplateUseStats}), + wbInteger('Calc min level', itU16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), + wbInteger('Calc max level', itU16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), + wbInteger('Speed Multiplier', itU16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), + wbInteger('Disposition Base (unused)', itS16, nil, cpIgnore, True, nil{wbActorTemplateUseTraits}), + wbInteger('Template Flags', itU16, wbFlags([ + {0x0001} 'Use Traits', + {0x0002} 'Use Stats', + {0x0004} 'Use Factions', + {0x0008} 'Use Spell List', + {0x0010} 'Use AI Data', + {0x0020} 'Use AI Packages', + {0x0040} 'Use Model/Animation?', + {0x0080} 'Use Base Data', + {0x0100} 'Use Inventory', + {0x0200} 'Use Script', + {0x0400} 'Use Def Pack List', + {0x0800} 'Use Attack Data', + {0x1000} 'Use Keywords' + ])), + wbInteger('Health Offset', itS16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), + wbInteger('Bleedout Override', itU16, nil, cpNormal, True, nil{wbActorTemplateUseStats}) + ], cpNormal, True), + wbRArrayS('Factions', wbFaction, cpNormal, False, nil, nil, nil{wbActorTemplateUseFactions}), + wbFormIDCk(INAM, 'Death item', [LVLI], False, cpNormal, False, nil{wbActorTemplateUseTraits}), + wbFormIDCk(VTCK, 'Voice', [VTYP], False, cpNormal, False, nil{wbActorTemplateUseTraits}), + wbFormIDCk(TPLT, 'Template', [LVLN, NPC_]), + wbFormIDCk(RNAM, 'Race', [RACE], False, cpNormal, True, nil{wbActorTemplateUseTraits}), + wbSPCT, + wbSPLOs, + wbDEST, + wbFormIDCk(WNAM, 'Worn Armor', [ARMO], False, cpNormal, False), + wbFormIDCk(ANAM, 'Far away model', [ARMO], False, cpNormal, False, nil{wbActorTemplateUseTraits}), + wbFormIDCk(ATKR, 'Attack Race', [RACE], False, cpNormal, False), + wbRArrayS('Attacks', wbAttackData), + wbFormIDCk(SPOR, 'Spectator override package list', [FLST], False, cpNormal, False), + wbFormIDCk(OCOR, 'Observe dead body override package list', [FLST], False, cpNormal, False), + wbFormIDCk(GWOR, 'Guard warn override package list', [FLST], False, cpNormal, False), + wbFormIDCk(ECOR, 'Combat override package list', [FLST], False, cpNormal, False), + wbInteger(PRKZ, 'Perk Count', itU32, nil, cpBenign), + wbRArrayS('Perks', + wbStructSK(PRKR, [0], 'Perk', [ + wbFormIDCk('Perk', [PERK]), + wbInteger('Rank', itU8), + wbByteArray('Unused', 3, cpIgnore) + ]), cpNormal, False, nil, wbPRKRsAfterSet + ), + wbCOCT, + wbCNTOs, + wbAIDT, + wbRArray('Packages', wbFormIDCk(PKID, 'Package', [PACK]), cpNormal, False, nil{wbActorTemplateUseAIPackages}), + wbKSIZ, + wbKWDAs, + wbFormIDCk(CNAM, 'Class', [CLAS], False, cpNormal, True), + wbFULL, + wbLString(SHRT, 'Short Name', 0, cpTranslate), + wbEmpty(DATA, 'Marker', cpNormal, True), + wbStruct(DNAM, 'Player Skills', [ + wbArray('Skill Values', wbInteger('Skill', itU8), [ + 'OneHanded', + 'TwoHanded', + 'Marksman', + 'Block', + 'Smithing', + 'HeavyArmor', + 'LightArmor', + 'Pickpocket', + 'Lockpicking', + 'Sneak', + 'Alchemy', + 'Speechcraft', + 'Alteration', + 'Conjuration', + 'Destruction', + 'Illusion', + 'Restoration', + 'Enchanting' + ]), + wbArray('Skill Offsets', wbInteger('Skill', itU8), [ + 'OneHanded', + 'TwoHanded', + 'Marksman', + 'Block', + 'Smithing', + 'HeavyArmor', + 'LightArmor', + 'Pickpocket', + 'Lockpicking', + 'Sneak', + 'Alchemy', + 'Speechcraft', + 'Alteration', + 'Conjuration', + 'Destruction', + 'Illusion', + 'Restoration', + 'Enchanting' + ]), + //wbByteArray('Unknown', 4), + wbInteger('Health', itU16), + wbInteger('Magicka', itU16), + wbInteger('Stamina', itU16), + wbByteArray('Unused', 2, cpIgnore), + wbFloat('Far away model distance'), + wbInteger('Geared up weapons', itU8), + wbByteArray('Unused', 3, cpIgnore) + ], cpNormal, False, nil{wbActorTemplateUseStatsAutoCalc}), + wbRArrayS('Head Parts', wbFormIDCk(PNAM, 'Head Part', [HDPT]), cpNormal, False, nil, nil, nil{wbActorTemplateUseModelAnimation}), + wbFormIDCk(HCLF, 'Hair Color', [CLFM], False, cpNormal, False), + wbFormIDCk(ZNAM, 'Combat Style', [CSTY], False, cpNormal, False), + wbFormIDCk(GNAM, 'Gift Filter', [FLST], False, cpNormal, False), + wbUnknown(NAM5, cpNormal, True), + wbFloat(NAM6, 'Height', cpNormal, True), + wbFloat(NAM7, 'Weight', cpNormal, True), + wbInteger(NAM8, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True), + wbCSDTs, + // When CSCR exists CSDT, CSDI, CSDC are not present + wbFormIDCk(CSCR, 'Inherits Sounds From', [NPC_], False, cpNormal, False), + wbFormIDCk(DOFT, 'Default outfit', [OTFT], False, cpNormal, False), + wbFormIDCk(SOFT, 'Sleeping outfit', [OTFT], False, cpNormal, False), + wbFormIDCk(DPLT, 'Default Package List', [FLST], False, cpNormal, False), + wbFormIDCk(CRIF, 'Crime faction', [FACT], False, cpNormal, False), + wbFormIDCk(FTST, 'Head texture', [TXST], False, cpNormal, False), + wbStruct(QNAM, 'Texture lighting', [ + wbFloat('Red', cpNormal, True, 255, 0), + wbFloat('Green', cpNormal, True, 255, 0), + wbFloat('Blue', cpNormal, True, 255, 0) + ]).SetToStr(wbRGBAToStr).IncludeFlag(dfCollapsed, wbCollapseRGBA), + wbStruct(NAM9, 'Face morph', [ + wbFloat('Nose Long/Short'), + wbFloat('Nose Up/Down'), + wbFloat('Jaw Up/Down'), + wbFloat('Jaw Narrow/Wide'), + wbFloat('Jaw Farward/Back'), + wbFloat('Cheeks Up/Down'), + wbFloat('Cheeks Farward/Back'), + wbFloat('Eyes Up/Down'), + wbFloat('Eyes In/Out'), + wbFloat('Brows Up/Down'), + wbFloat('Brows In/Out'), + wbFloat('Brows Farward/Back'), + wbFloat('Lips Up/Down'), + wbFloat('Lips In/Out'), + wbFloat('Chin Narrow/Wide'), + wbFloat('Chin Up/Down'), + wbFloat('Chin Underbite/Overbite'), + wbFloat('Eyes Farward/Back'), + wbFloat('Unknown') + ], cpNormal, False), + wbStruct(NAMA, 'Face parts', [ + wbInteger('Nose', itU32), + wbInteger('Unknown', itS32), + wbInteger('Eyes', itU32), + wbInteger('Mouth', itU32) + ]), + wbRArrayS('Tint Layers', + wbRStructSK([0], 'Layer', [ + wbInteger(TINI, 'Tint Index', itU16, wbTintLayerToStr, wbStrToInt), + wbStruct(TINC, 'Tint Color', [ + wbInteger('Red', itU8), + wbInteger('Green', itU8), + wbInteger('Blue', itU8), + wbInteger('Alpha', itU8) + ]).SetToStr(wbRGBAToStr).IncludeFlag(dfCollapsed, wbCollapseRGBA), + wbInteger(TINV, 'Interpolation Value', itU32, wbDiv(100)), + wbInteger(TIAS, 'Preset', itS16) + ], [])) + ], False, nil, cpNormal, False, wbNPCAfterLoad, wbNPCAfterSet); + + wbObjectTypeEnum := wbEnum([ + ' NONE', + 'Activators', + 'Armor', + 'Books', + 'Clothing', + 'Containers', + 'Doors', + 'Ingredients', + 'Lights', + 'Misc', + 'Flora', + 'Furniture', + 'Weapons: Any', + 'Ammo', + 'NPCs', + 'Creatures', + 'Keys', + 'Alchemy', + 'Food', + ' All: Combat Wearable', + ' All: Wearable', + 'Weapons: Ranged', + 'Weapons: Melee', + 'Weapons: NONE', + 'Actor Effects: Any', + 'Actor Effects: Range Target', + 'Actor Effects: Range Touch', + 'Actor Effects: Range Self', + 'Actors: Any' + ]); + + wbPKDTSpecificFlagsUnused := False; + + wbPKDTFlags := wbFlags([ + {0x00000001} 'Offers Services', + {0x00000002} 'Unknown 2', + {0x00000004} 'Must complete', + {0x00000008} 'Maintain Speed at Goal', + {0x00000010} 'Unknown 5', + {0x00000020} 'Unknown 6', + {0x00000040} 'Unlock doors at package start', + {0x00000080} 'Unlock doors at package end', + {0x00000100} 'Unknown 9', + {0x00000200} 'Continue if PC Near', + {0x00000400} 'Once per day', + {0x00000800} 'Unknown 12', + {0x00001000} 'Unknown 13', + {0x00002000} 'Preferred Speed', + {0x00004000} 'Unknown 15', + {0x00008000} 'Unknown 16', + {0x00010000} 'Unknown 17', + {0x00020000} 'Always Sneak', + {0x00040000} 'Allow Swimming', + {0x00080000} 'Unknown 20', + {0x00100000} 'Ignore Combat', + {0x00200000} 'Weapons Unequipped', + {0x00400000} 'Unknown 23', + {0x00800000} 'Weapon Drawn', + {0x01000000} 'Unknown 25', + {0x02000000} 'Unknown 26', + {0x04000000} 'Unknown 27', + {0x08000000} 'No Combat Alert', + {0x10000000} 'Unknown 29', + {0x20000000} 'Wear Sleep Outfit (unused)', + {0x40000000} 'Unknown 31', + {0x80000000} 'Unknown 32' + ], [29]); + + wbPKDTInterruptFlags := wbFlags([ + {0x0001}'Hellos to player', + {0x0002}'Random conversations', + {0x0004}'Observe combat behavior', + {0x0008}'Greet corpse behavior', + {0x0010}'Reaction to player actions', + {0x0020}'Friendly fire comments', + {0x0040}'Aggro Radius Behavior', + {0x0080}'Allow Idle Chatter', + {0x0100}'Unknown 9', + {0x0200}'World Interactions', + {0x0400}'Unknown 11', + {0x0800}'Unknown 12', + {0x1000}'Unknown 13', + {0x2000}'Unknown 14', + {0x4000}'Unknown 15', + {0x8000}'Unknown 16' + ]); +end; + +procedure DefineTES5n; +begin + + wbUNAMs:= wbRArray('Data Inputs', wbRStruct('Data Input', [ + wbInteger(UNAM, 'Index', itS8), + wbString(BNAM, 'Name'), + wbInteger(PNAM, 'Flags', itU32, wbFlags([ + 'Public' + ])) + ], [])); + + wbRecord(PACK, 'Package', [ + wbEDID, + wbVMADFragmentedPACK, + + wbStruct(PKDT, 'Pack Data', [ + wbInteger('General Flags', itU32, wbPKDTFlags), + wbInteger('Type', itU8, wbEnum ([], [ + 18, 'Package', + 19, 'Package Template' + ])).SetDefaultEditValue('Package'), + wbInteger('Interrupt Override', itU8, wbEnum([ + 'None', + 'Spectator', + 'ObserveDead', + 'GuardWarn', + 'Combat' + ])), + wbInteger('Preferred Speed', itU8, wbEnum([ + 'Walk', + 'Jog', + 'Run', + 'Fast Walk' + ])), + wbByteArray('Unknown', 1), + wbInteger('Interrupt Flags', itU16, wbPKDTInterruptFlags), + wbByteArray('Unknown', 2) + ], cpNormal, True), + + wbStruct(PSDT, 'Schedule', [ + wbInteger('Month', itS8), + wbInteger('Day of week', itS8, wbEnum([ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + 'Weekdays', + 'Weekends', + 'Monday, Wednesday, Friday', + 'Tuesday, Thursday' + ], [ + -1, 'Any' + ])), + wbInteger('Date', itU8), + wbInteger('Hour', itS8), + wbInteger('Minute', itS8), + wbByteArray('Unused', 3, cpIgnore), + wbInteger('Duration (minutes)', itS32) + ], cpNormal, True), + wbCTDAs, + + wbRStruct('Idle Animations', [ + wbInteger(IDLF, 'Flags', itU8, wbEnum([], [ + 0, 'Unknown', + 8, 'Random', + 9, 'Run in Sequence', + 12, 'Random, Do Once', + 13, 'Run in Sequence, Do Once' + ]), cpNormal, True), + wbStruct(IDLC, '', [ + wbInteger('Animation Count', itU8, nil, cpBenign), + wbByteArray('Unknown', 3) + ], cpNormal, True, nil, 1), + wbFloat(IDLT, 'Idle Timer Setting', cpNormal, True), + wbArray(IDLA, 'Animations', wbFormIDCk('Animation', [IDLE]), 0, nil, wbIDLAsAfterSet, cpNormal, True), + wbByteArray(IDLB, 'Unknown', 4, cpIgnore) + ], [], cpNormal, False, nil, False, nil {cannot be totally removed , wbAnimationsAfterSet}), + + wbFormIDCk(CNAM, 'Combat Style', [CSTY]), + wbFormIDCk(QNAM, 'Owner Quest', [QUST]), + wbStruct(PKCU, 'Counter', [ + wbInteger('Data Input Count', itU32), + wbFormIDCk('Package Template', [PACK, NULL]), + wbInteger('Version Counter (autoincremented)', itU32) + ], cpNormal, True), + + wbRStruct('Package Data', [ + wbRArray('Data Input Values', wbRStruct('Value', [ + wbString(ANAM, 'Type').SetAfterSet(wbPackageDataInputValueTypeAfterSet), + wbUnion(CNAM, 'Value', wbPubPackCNAMDecider, [ + {0} wbByteArray('Unknown'), + {1} wbInteger('Bool', itU8, wbEnum(['False', 'True'])), + {2} wbInteger('Integer', itU32), + {3} wbFloat('Float') + ]), + wbUnknown(BNAM), + wbPDTOs, + wbPLDT, + wbStruct(PTDA, 'Target', [wbTargetData]), + wbUnknown(TPIC) + ], [], cpNormal, False)), + wbUNAMs + ], []), + wbByteArray(XNAM, 'Marker', 0, cpNormal, True), + + wbRStruct('Procedure Tree', [ + wbRArray('Branches', wbRStruct('Branch', [ + wbString(ANAM, 'Branch Type'), + wbCITCReq, + wbCTDAsCount, + wbStruct(PRCB, 'Root', [ + wbInteger('Branch Count', itU32), + wbInteger('Flags', itU32, wbFlags([ + 'Repeat when Complete', + 'Unknown 1' + ])) + ]), + wbString(PNAM, 'Procedure Type'), + wbInteger(FNAM, 'Flags', itU32, wbFlags(['Success Completes Package'])), + wbRArray('Data Input Indexes', wbInteger(PKC2, 'Index', itU8)), + {>>> PFO2 should be single, there is only 1 PACK [00095F46] in Skyrim.esm with 2xPFO2 <<<} + wbRArray('Flags Override', + wbStruct(PFO2, 'Data', [ + wbInteger('Set General Flags', itU32, wbPKDTFlags), + wbInteger('Clear General Flags', itU32, wbPKDTFlags), + wbInteger('Set Interrupt Flags', itU16, wbPKDTInterruptFlags), + wbInteger('Clear Interrupt Flags', itU16, wbPKDTInterruptFlags), + wbInteger('Preferred Speed Override', itU8, wbEnum([ + 'Walk', + 'Jog', + 'Run', + 'Fast Walk' + ])), + wbByteArray('Unknown', 3) + ]) + ), + wbRArray('Unknown', wbUnknown(PFOR), cpIgnore) + ], [], cpNormal, False, nil, False, nil, wbConditionsAfterSet)) + ], []), + wbUNAMs, + wbRStruct('OnBegin', [ + wbEmpty(POBA, 'OnBegin Marker', cpNormal, True), + wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), + {>>> BEGIN leftover from earlier CK versions <<<} + wbByteArray(SCHR, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(SCTX, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(QNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(TNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + {>>> END leftover from earlier CK versions <<<} + wbPDTOs + ], [], cpNormal, True), + wbRStruct('OnEnd', [ + wbEmpty(POEA, 'OnEnd Marker', cpNormal, True), + wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), + {>>> BEGIN leftover from earlier CK versions <<<} + wbByteArray(SCHR, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(SCTX, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(QNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(TNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + {>>> END leftover from earlier CK versions <<<} + wbPDTOs + ], [], cpNormal, True), + wbRStruct('OnChange', [ + wbEmpty(POCA, 'OnChange Marker', cpNormal, True), + wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), + {>>> BEGIN leftover from earlier CK versions <<<} + wbByteArray(SCHR, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(SCDA, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(SCTX, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(QNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(TNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + {>>> END leftover from earlier CK versions <<<} + wbPDTOs + ], [], cpNormal, True) + ], False, nil, cpNormal, False, nil {wbPACKAfterLoad}); + + wbQUSTAliasFlags := + wbStruct(FNAM, 'Alias Flags', [ + wbInteger('Flags', itU16, wbFlags([ + {0x0001}'Reserves Location/Reference', + {0x0002}'Optional', + {0x0004}'Quest Object', + {0x0008}'Allow Reuse in Quest', + {0x0010}'Allow Dead', + {0x0020}'Matching Ref - In Loaded Area', + {0x0040}'Essential', + {0x0080}'Allow Disabled', + {0x0100}'Stores Text', + {0x0200}'Allow Reserved', + {0x0400}'Protected', + {0x0800}'Forced by Aliases?', + {0x1000}'Allow Destroyed', + {0x2000}'Matching Ref - Closest', + {0x4000}'Uses Stored Text', + {0x8000}'Initially Disabled' + ])), + wbInteger('Additional Flags', itU16, wbFlags([ + {0x0001}'Allow Cleared', + {0x0002}'Clear Names When Removed' + ])) + ], cpNormal, True, nil, 1) + .SetSummaryKeyOnValue([0, 1]) + .SetSummaryDelimiterOnValue(', ') + .IncludeFlagOnValue(dfSummaryMembersNoName); + + wbRecord(QUST, 'Quest', [ + wbEDID, + wbVMADFragmentedQUST, + wbFULL, + wbStruct(DNAM, 'General', [ + wbInteger('Flags', itU16, wbFlags([ + {0x0001} 'Start Game Enabled', + {0x0002} 'Completed', + {0x0004} 'Add Idle topic to Hello', + {0x0008} 'Allow repeated stages', + {0x0010} 'Starts Enabled', + {0x0020} 'Displayed In HUD', + {0x0040} 'Failed', + {0x0080} 'Stage Wait', + {0x0100} 'Run Once', + {0x0200} 'Exclude from dialogue export', + {0x0400} 'Warn on alias fill failure', + {0x0800} 'Active', + {0x1000} 'Repeats Conditions', + {0x2000} 'Keep Instance', + {0x4000} 'Want Dormant', + {0x8000} 'Has Dialogue Data' + ])), + wbInteger('Priority', itU8), + wbInteger('Form Version', itU8, nil, cpIgnore), + wbByteArray('Unknown', 4), + wbInteger('Type', itU32, wbQuestTypeEnum) + ], cpNormal, True), + wbString(ENAM, 'Event', 4), + wbRArray('Text Display Globals', wbFormIDCk(QTGL, 'Global', [GLOB])), + wbString(FLTR, 'Object Window Filter', 0, cpTranslate), + wbRStruct('Quest Dialogue Conditions', [wbCTDAs], [], cpNormal, False), + wbEmpty(NEXT, 'Marker', cpNormal, True), + wbCTDAs, {>>> Unknown, doesn't show up in CK <<<} + wbRArrayS('Stages', wbRStructSK([0], 'Stage', [ + wbStructSK(INDX, [0], 'Stage Index', [ + wbInteger('Stage Index', itU16), + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'Unknown 1', + {0x02} 'Start Up Stage', + {0x04} 'Shut Down Stage', + {0x08} 'Keep Instance Data From Here On' + ])), + wbInteger('Unknown', itU8) + ]), + wbRArray('Log Entries', wbRStruct('Log Entry', [ + wbInteger(QSDT, 'Stage Flags', itU8, wbFlags([ + {0x01} 'Complete Quest', + {0x02} 'Fail Quest' + ])), + wbCTDAs, + wbLStringKC(CNAM, 'Log Entry', 0, cpTranslate), + wbFormIDCk(NAM0, 'Next Quest', [QUST]), + {>>> BEGIN leftover from earlier CK versions <<<} + wbByteArray(SCHR, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(SCTX, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(QNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow) + {>>> END leftover from earlier CK versions <<<} + ], [])) + ], [])), + wbRArray('Objectives', wbRStruct('Objective', [ + wbInteger(QOBJ, 'Objective Index', itU16), + wbInteger(FNAM, 'Flags', itU32, wbFlags(['ORed With Previous'])), + wbLStringKC(NNAM, 'Display Text', 0, cpTranslate, True), + wbRArray('Targets', wbRStruct('Target', [ + wbStruct(QSTA, 'Target', [ + wbInteger('Alias', itS32, wbQuestAliasToStr, wbStrToAlias), + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'Compass Marker Ignores Locks' + ])), + wbByteArray('Unused', 3) + ]), + wbCTDAs + ], [])) + ], [])), + wbInteger(ANAM, 'Next Alias ID', itU32, nil, cpNormal, True), + wbRArray('Aliases', + wbRUnion('Alias', [ + + // Reference Alias + wbRStructSK([0], 'Alias', [ + wbInteger(ALST, 'Reference Alias ID', itU32, nil, cpNormal, True), + wbString(ALID, 'Alias Name', 0, cpNormal, True), + wbQUSTAliasFlags, + wbInteger(ALFI, 'Force Into Alias When Filled', itS32, wbQuestAliasToStr, wbStrToAlias), + wbFormIDCk(ALFL, 'Specific Location', [LCTN]), + wbFormID(ALFR, 'Forced Reference'), + wbFormIDCk(ALUA, 'Unique Actor', [NPC_]), + wbRStruct('Location Alias Reference', [ + wbInteger(ALFA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), + wbFormIDCk(KNAM, 'Keyword', [KYWD]), + wbFormIDCk(ALRT, 'Ref Type', [LCRT]) + ], []), + wbRStruct('External Alias Reference', [ + wbFormIDCk(ALEQ, 'Quest', [QUST]), + wbInteger(ALEA, 'Alias', itS32, wbQuestExternalAliasToStr, wbStrToAlias) + ], []), + wbRStruct('Create Reference to Object', [ + wbFormID(ALCO, 'Object'), + wbStruct(ALCA, 'Alias', [ + wbInteger('Alias', itS16, wbQuestAliasToStr, wbStrToAlias), + wbInteger('Create', itU16, wbEnum([] ,[ + $0000, 'At', + $8000, 'In' + ])) + ]), + wbInteger(ALCL, 'Level', itU32, wbEnum([ + 'Easy', + 'Medium', + 'Hard', + 'Very Hard', + 'None' + ])) + ], []), + wbRStruct('Find Matching Reference Near Alias', [ + wbInteger(ALNA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), + wbInteger(ALNT, 'Type', itU32, wbEnum([ + 'Linked Ref Child' + ])) + ], []), + wbRStruct('Find Matching Reference From Event', [ + wbString(ALFE, 'From Event', 4), + wbByteArray(ALFD, 'Event Data') + ], []), + wbCTDAs, + wbKSIZ, + wbKWDAs, + wbCOCT, + wbCNTOs, + wbFormIDCk(SPOR, 'Spectator override package list', [FLST], False, cpNormal, False), + wbFormIDCk(OCOR, 'Observe dead body override package list', [FLST], False, cpNormal, False), + wbFormIDCk(GWOR, 'Guard warn override package list', [FLST], False, cpNormal, False), + wbFormIDCk(ECOR, 'Combat override package list', [FLST], False, cpNormal, False), + wbFormIDCk(ALDN, 'Display Name', [MESG]), + wbRArray('Alias Spells', wbFormIDCk(ALSP, 'Spell', [SPEL])), + wbRArray('Alias Factions', wbFormIDCk(ALFC, 'Faction', [FACT])), + wbRArray('Alias Package Data', wbFormIDCk(ALPC, 'Package', [PACK])), + wbFormIDCk(VTCK, 'Voice Types', [NPC_, FLST, NULL]), + wbEmpty(ALED, 'Alias End', cpNormal, True) + ], [], cpNormal, False, nil, False, nil, wbContainerAfterSet) + .SetSummaryKey([1, 2]) + .SetSummaryDelimiter(' ') + .SetSummaryMemberPrefixSuffix(0, 'Ref [', ']') + .SetSummaryMemberPrefixSuffix(1, '', '') + .SetSummaryMemberPrefixSuffix(2, '{', '}') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfCollapsed), + + // Location Alias + wbRStructSK([0], 'Alias', [ + wbInteger(ALLS, 'Location Alias ID', itU32), + wbString(ALID, 'Alias Name'), + wbQUSTAliasFlags, + wbInteger(ALFI, 'Force Into Alias When Filled', itS32, wbQuestAliasToStr, wbStrToAlias), + wbFormIDCk(ALFL, 'Specific Location', [LCTN]), + wbFormID(ALFR, 'Forced Reference'), + wbFormIDCk(ALUA, 'Unique Actor', [NPC_]), + wbRStruct('Location Alias Reference', [ + wbInteger(ALFA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), + wbFormIDCk(KNAM, 'Keyword', [KYWD]), + wbFormIDCk(ALRT, 'Ref Type', [LCRT]) + ], []), + wbRStruct('External Alias Reference', [ + wbFormIDCk(ALEQ, 'Quest', [QUST]), + wbInteger(ALEA, 'Alias', itS32, wbQuestExternalAliasToStr, wbStrToAlias) + ], []), + wbRStruct('Create Reference to Object', [ + wbFormID(ALCO, 'Object'), + wbStruct(ALCA, 'Alias', [ + wbInteger('Alias', itS16, wbQuestAliasToStr, wbStrToAlias), + wbInteger('Create', itU16, wbEnum([] ,[ + $0000, 'At', + $8000, 'In' + ])) + ]), + wbInteger(ALCL, 'Level', itU32, wbEnum([ + 'Easy', + 'Medium', + 'Hard', + 'Very Hard', + 'None' + ])) + ], []), + wbRStruct('Find Matching Reference Near Alias', [ + wbInteger(ALNA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), + wbInteger(ALNT, 'Type', itU32, wbEnum([ + 'Linked Ref Child' + ])) + ], []), + wbRStruct('Find Matching Reference From Event', [ + wbString(ALFE, 'From Event', 4), + wbByteArray(ALFD, 'Event Data') + ], []), + wbCTDAs, + wbKSIZ, + wbKWDAs, + wbCOCT, + wbCNTOs, + wbFormIDCk(SPOR, 'Spectator override package list', [FLST], False, cpNormal, False), + wbFormIDCk(OCOR, 'Observe dead body override package list', [FLST], False, cpNormal, False), + wbFormIDCk(GWOR, 'Guard warn override package list', [FLST], False, cpNormal, False), + wbFormIDCk(ECOR, 'Combat override package list', [FLST], False, cpNormal, False), + wbFormIDCk(ALDN, 'Display Name', [MESG]), + wbRArray('Alias Spells', wbFormIDCk(ALSP, 'Spell', [SPEL])), + wbRArray('Alias Factions', wbFormIDCk(ALFC, 'Faction', [FACT])), + wbRArray('Alias Package Data', wbFormIDCk(ALPC, 'Package', [PACK])), + wbFormIDCk(VTCK, 'Voice Types', [NPC_, FLST, NULL]), + wbEmpty(ALED, 'Alias End', cpNormal, True) + ], [], cpNormal, False, nil, False, nil, wbContainerAfterSet) + .SetSummaryKey([1, 2]) + .SetSummaryDelimiter(' ') + .SetSummaryMemberPrefixSuffix(0, 'Loc [', ']') + .SetSummaryMemberPrefixSuffix(1, '', '') + .SetSummaryMemberPrefixSuffix(2, '{', '}') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfCollapsed) + ], []) + ), + wbString(NNAM, 'Description', 0, cpNormal, False), + wbRArray('Targets', wbRStruct('Target', [ + wbStruct(QSTA, 'Target', [ + wbFormIDCkNoReach('Target', [ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], True), + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'Compass Marker Ignores Locks' + ])), + wbByteArray('Unknown', 3) + ]), + wbCTDAs + ], [])) + ]); + + var wbBodyPartIndexEnum := wbEnum([ + 'Body Texture' + ]); + + wbNoseMorphFlags := wbInteger('Nose Morph Flags', itU32, wbFlags([ + {0x00000001}'NoseType0', + {0x00000002}'NoseType1', + {0x00000004}'NoseType2', + {0x00000008}'NoseType3', + {0x00000010}'NoseType4', + {0x00000020}'NoseType5', + {0x00000040}'NoseType6', + {0x00000080}'NoseType7', + {0x00000100}'NoseType8', + {0x00000200}'NoseType9', + {0x00000400}'NoseType10', + {0x00000800}'NoseType11', + {0x00001000}'NoseType12', + {0x00002000}'NoseType13', + {0x00004000}'NoseType14', + {0x00008000}'NoseType15', + {0x00010000}'NoseType16', + {0x00020000}'NoseType17', + {0x00040000}'NoseType18', + {0x00080000}'NoseType19', + {0x00100000}'NoseType20', + {0x00200000}'NoseType21', + {0x00400000}'NoseType22', + {0x00800000}'NoseType23', + {0x01000000}'NoseType24', + {0x02000000}'NoseType25', + {0x04000000}'NoseType26', + {0x08000000}'NoseType27', + {0x10000000}'NoseType28', + {0x20000000}'NoseType29', + {0x40000000}'NoseType30', + {0x80000000}'NoseType31' + ])); + + wbBrowMorphFlags := wbInteger('Brow Morph Flags', itU32, wbFlags([ + {0x00000001}'BrowType0', + {0x00000002}'BrowType1', + {0x00000004}'BrowType2', + {0x00000008}'BrowType3', + {0x00000010}'BrowType4', + {0x00000020}'BrowType5', + {0x00000040}'BrowType6', + {0x00000080}'BrowType7', + {0x00000100}'BrowType8', + {0x00000200}'BrowType9', + {0x00000400}'BrowType10', + {0x00000800}'BrowType11', + {0x00001000}'BrowType12', + {0x00002000}'BrowType13', + {0x00004000}'BrowType14', + {0x00008000}'BrowType15', + {0x00010000}'BrowType16', + {0x00020000}'BrowType17', + {0x00040000}'BrowType18', + {0x00080000}'BrowType19', + {0x00100000}'BrowType20' + ], True)); + + wbEyesMorphFlags01 := wbInteger('Eye Morph Flags 1', itU32, wbFlags([ + {0x00000001}'EyesType0', + {0x00000002}'EyesType1', + {0x00000004}'EyesType2', + {0x00000008}'EyesType3', + {0x00000010}'EyesType4', + {0x00000020}'EyesType5', + {0x00000040}'EyesType6', + {0x00000080}'EyesType7', + {0x00000100}'EyesType8', + {0x00000200}'EyesType9', + {0x00000400}'EyesType10', + {0x00000800}'EyesType11', + {0x00001000}'EyesType12', + {0x00002000}'EyesType13', + {0x00004000}'EyesType14', + {0x00008000}'EyesType15', + {0x00010000}'EyesType16', + {0x00020000}'EyesType17', + {0x00040000}'EyesType18', + {0x00080000}'EyesType19', + {0x00100000}'EyesType20', + {0x00200000}'EyesType21', + {0x00400000}'EyesType22', + {0x00800000}'EyesType23', + {0x01000000}'EyesType24', + {0x02000000}'EyesType25', + {0x04000000}'EyesType26', + {0x08000000}'EyesType27', + {0x10000000}'EyesType28', + {0x20000000}'EyesType29', + {0x40000000}'EyesType30', + {0x80000000}'EyesType31' + ])); + + wbEyesMorphFlags02 := wbInteger('Eye Morph Flags 2', itU8, wbFlags([ + {0x00000001}'EyesType32', + {0x00000002}'EyesType33', + {0x00000004}'EyesType34', + {0x00000008}'EyesType35', + {0x00000010}'EyesType36', + {0x00000020}'EyesType37', + {0x00000040}'EyesType38' + ], True)); + + wbLipMorphFlags := wbInteger('Lip Morph Flags', itU32, wbFlags([ + {0x00000001}'LipType0', + {0x00000002}'LipType1', + {0x00000004}'LipType2', + {0x00000008}'LipType3', + {0x00000010}'LipType4', + {0x00000020}'LipType5', + {0x00000040}'LipType6', + {0x00000080}'LipType7', + {0x00000100}'LipType8', + {0x00000200}'LipType9', + {0x00000400}'LipType10', + {0x00000800}'LipType11', + {0x00001000}'LipType12', + {0x00002000}'LipType13', + {0x00004000}'LipType14', + {0x00008000}'LipType15', + {0x00010000}'LipType16', + {0x00020000}'LipType17', + {0x00040000}'LipType18', + {0x00080000}'LipType19', + {0x00100000}'LipType20', + {0x00200000}'LipType21', + {0x00400000}'LipType22', + {0x00800000}'LipType23', + {0x01000000}'LipType24', + {0x02000000}'LipType25', + {0x04000000}'LipType26', + {0x08000000}'LipType27', + {0x10000000}'LipType28', + {0x20000000}'LipType29', + {0x40000000}'LipType30', + {0x80000000}'LipType31' + ])); + + wbTintMaskTypeEnum := wbEnum([ + 'None', + 'Lip Color', + 'Cheek Color', + 'Eyeliner', + 'EyeSocket Upper', + 'EyeSocket Lower', + 'Skin Tone', + 'Paint', + 'Laugh Lines', + 'Cheek Color Lower', + 'Nose', + 'Chin', + 'Neck', + 'Forehead', + 'Dirt', + 'Unknown 16' + ]); + + wbTints := wbRArray('Tint Masks', wbRStruct('Tint Assets', [ + wbRArray('Tint Layer', wbRStruct('Texture', [ + wbInteger(TINI, 'Index', itU16), + wbString(TINT, 'File Name'), + {>>> When set to None TINP does not exist Needs routine to add when + changing the Mask Type <<<} + wbInteger(TINP, 'Mask Type', itU16, wbTintMaskTypeEnum), + wbFormIDCk(TIND, 'Preset Default', [CLFM, NULL]) + ], [])), + wbRArray('Presets', wbRStruct('Preset', [ + wbFormIDCk(TINC, 'Color', [CLFM, NULL]), + wbFloat(TINV, 'Default Value'), + wbInteger(TIRS, 'Index', itU16) + ], [])) + ], [])); + + wbRACE_DATAFlags01 := wbInteger('Flags', itU32, wbFlags([ + {0x00000001}'Playable', + {0x00000002}'FaceGen Head', + {0x00000004}'Child', + {0x00000008}'Tilt Front/Back', + {0x00000010}'Tilt Left/Right', + {0x00000020}'No Shadow', + {0x00000040}'Swims', + {0x00000080}'Flies', + {0x00000100}'Walks', + {0x00000200}'Immobile', + {0x00000400}'Not Pushable', + {0x00000800}'No Combat In Water', + {0x00001000}'No Rotating to Head-Track', + {0x00002000}'Don''t Show Blood Spray', + {0x00004000}'Don''t Show Blood Decal', + {0x00008000}'Uses Head Track Anims', + {0x00010000}'Spells Align w/Magic Node', + {0x00020000}'Use World Raycasts For FootIK', + {0x00040000}'Allow Ragdoll Collision', + {0x00080000}'Regen HP In Combat', + {0x00100000}'Can''t Open Doors', + {0x00200000}'Allow PC Dialogue', + {0x00400000}'No Knockdowns', + {0x00800000}'Allow Pickpocket', + {0x01000000}'Always Use Proxy Controller', + {0x02000000}'Don''t Show Weapon Blood', + {0x04000000}'Overlay Head Part List', {>>>Only one can be active<<<} + {0x08000000}'Override Head Part List', {>>>Only one can be active<<<} + {0x10000000}'Can Pickup Items', + {0x20000000}'Allow Multiple Membrane Shaders', + {0x40000000}'Can Dual Wield', + {0x80000000}'Avoids Roads' + ])); + + wbPhonemeTargets := wbStruct(PHWT, 'Phoneme Target Weight', [ + wbFloat('Aah / LipBigAah'), + wbFloat('BigAah / LipDST'), + wbFloat('BMP / LipEee'), + wbFloat('ChJsh / LipFV'), + wbFloat('DST / LipK'), + wbFloat('Eee / LipL'), + wbFloat('Eh / LipR'), + wbFloat('FV / LipTh'), + wbFloat('I'), + wbFloat('K'), + wbFloat('N'), + wbFloat('Oh'), + wbFloat('OohQ'), + wbFloat('R'), + wbFloat('TH'), + wbFloat('W') + ], cpNormal, False, nil, 8); + + wbPHWT := wbRStruct('FaceFX Phonemes', [ + wbRStruct('IY', [wbPhonemeTargets], []), + wbRStruct('IH', [wbPhonemeTargets], []), + wbRStruct('EH', [wbPhonemeTargets], []), + wbRStruct('EY', [wbPhonemeTargets], []), + wbRStruct('AE', [wbPhonemeTargets], []), + wbRStruct('AA', [wbPhonemeTargets], []), + wbRStruct('AW', [wbPhonemeTargets], []), + wbRStruct('AY', [wbPhonemeTargets], []), + wbRStruct('AH', [wbPhonemeTargets], []), + wbRStruct('AO', [wbPhonemeTargets], []), + wbRStruct('OY', [wbPhonemeTargets], []), + wbRStruct('OW', [wbPhonemeTargets], []), + wbRStruct('UH', [wbPhonemeTargets], []), + wbRStruct('UW', [wbPhonemeTargets], []), + wbRStruct('ER', [wbPhonemeTargets], []), + wbRStruct('AX', [wbPhonemeTargets], []), + wbRStruct('S', [wbPhonemeTargets], []), + wbRStruct('SH', [wbPhonemeTargets], []), + wbRStruct('Z', [wbPhonemeTargets], []), + wbRStruct('ZH', [wbPhonemeTargets], []), + wbRStruct('F', [wbPhonemeTargets], []), + wbRStruct('TH', [wbPhonemeTargets], []), + wbRStruct('V', [wbPhonemeTargets], []), + wbRStruct('DH', [wbPhonemeTargets], []), + wbRStruct('M', [wbPhonemeTargets], []), + wbRStruct('N', [wbPhonemeTargets], []), + wbRStruct('NG', [wbPhonemeTargets], []), + wbRStruct('L', [wbPhonemeTargets], []), + wbRStruct('R', [wbPhonemeTargets], []), + wbRStruct('W', [wbPhonemeTargets], []), + wbRStruct('Y', [wbPhonemeTargets], []), + wbRStruct('HH', [wbPhonemeTargets], []), + wbRStruct('B', [wbPhonemeTargets], []), + wbRStruct('D', [wbPhonemeTargets], []), + wbRStruct('JH', [wbPhonemeTargets], []), + wbRStruct('G', [wbPhonemeTargets], []), + wbRStruct('P', [wbPhonemeTargets], []), + wbRStruct('T', [wbPhonemeTargets], []), + wbRStruct('K', [wbPhonemeTargets], []), + wbRStruct('CH', [wbPhonemeTargets], []), + wbRStruct('SIL', [wbPhonemeTargets], []), + wbRStruct('SHOTSIL', [wbPhonemeTargets], []), + wbRStruct('FLAP', [wbPhonemeTargets], []) + ], []); + + wbMorphs := wbRStruct('Available Morphs', [ + wbByteArray(MPAI, 'Unknown', 0), + wbStruct(MPAV, 'Nose Variants', [ + wbNoseMorphFlags, + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4) + ]), + wbByteArray(MPAI, 'Unknown', 0), + wbStruct(MPAV, 'Brow Variants', [ + wbBrowMorphFlags, + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4) + ]), + wbByteArray(MPAI, 'Unknown', 0), + wbStruct(MPAV, 'Eye Variants', [ + wbEyesMorphFlags01, + wbEyesMorphFlags02, + wbByteArray('Unknown', 3), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4) + ]), + wbByteArray(MPAI, 'Unknown', 0), + wbStruct(MPAV, 'Lip Variants', [ + wbLipMorphFlags, + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4), + wbByteArray('Unknown', 4) + ]) + ], []); + + var wbHeadParts := + wbRArrayS('Head Parts', wbHeadPart, cpNormal); + + var wbBodyParts := + wbRArrayS('Parts', + wbRStructSK([0], 'Part', [ + wbInteger(INDX, 'Index', itU32, wbBodyPartIndexEnum), + wbGenericModel + ], []) + .SetSummaryKey([0, 1]) + .SetSummaryMemberPrefixSuffix(0, '[', ']') + .SetSummaryDelimiter(' ') + .IncludeFlag(dfSummaryMembersNoName) + .IncludeFlag(dfSummaryNoSortKey) + .IncludeFlag(dfCollapsed, wbCollapseBodyParts) + , cpNormal, True); + + wbRecord(RACE, 'Race', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00080000} 19, 'Critter?' + ])), [ + wbEDID, + wbFULL, + wbDESCReq, + wbSPCT, + wbSPLOs, + wbFormIDCk(WNAM, 'Skin', [ARMO, NULL]), + wbBODTBOD2, + wbKSIZ, + wbKWDAs, + wbStruct(DATA, '', [ + wbArrayS('Skill Boosts', wbStructSK([0], 'Skill Boost', [ + wbInteger('Skill', itS8, wbActorValueEnum), + wbInteger('Boost', itS8) + ]).SetSummaryKey([1, 0]) + .SetSummaryMemberPrefixSuffix(1, '+', '') + .SetSummaryMemberPrefixSuffix(0, '', '') + .SetSummaryDelimiter(' ') + .IncludeFlag(dfSummaryNoSortKey) + .IncludeFlag(dfSummaryMembersNoName).IncludeFlag(dfCollapsed), 7), + wbByteArray('Unknown', 2), + wbFloat('Male Height'), + wbFloat('Female Height'), + wbFloat('Male Weight'), + wbFloat('Female Weight'), + wbRACE_DATAFlags01, + wbFloat('Starting Health'), + wbFloat('Starting Magicka'), + wbFloat('Starting Stamina'), + wbFloat('Base Carry Weight'), + wbFloat('Base Mass'), + wbFloat('Acceleration rate'), + wbFloat('Deceleration rate'), + wbInteger('Size', itU32, wbEnum([ + 'Small', + 'Medium', + 'Large', + 'Extra Large' + ])), + wbInteger('Head Biped Object', itS32, wbBipedObjectEnum), + wbInteger('Hair Biped Object', itS32, wbBipedObjectEnum), + wbFloat('Injured Health Pct'), + wbInteger('Shield Biped Object', itS32, wbBipedObjectEnum), + wbFloat('Health Regen'), + wbFloat('Magicka Regen'), + wbFloat('Stamina Regen'), + wbFloat('Unarmed Damage'), + wbFloat('Unarmed Reach'), + wbInteger('Body Biped Object', itS32, wbBipedObjectEnum), + wbFloat('Aim Angle Tolerance'), + wbFloat('Flight Radius'), + wbFloat('Angular Acceleration Rate'), + wbFloat('Angular Tolerance'), + wbInteger('Flags 2', itU32, wbFlags([ + {0x00000001} 'Use Advanced Avoidance', + {0x00000002} 'Non-Hostile', + {0x00000004} 'Unknown 2', + {0x00000008} 'Unknown 3', + {0x00000010} 'Allow Mounted Combat' + ])), + wbStruct('Mount Data', [ + wbFloat('Mount Offset X', cpNormal, False, 1, -1, nil, nil, -63.479000), + wbFloat('Mount Offset Y'), + wbFloat('Mount Offset Z'), + wbFloat('Dismount Offset X', cpNormal, False, 1, -1, nil, nil, -50.0), + wbFloat('Dismount Offset Y'), + wbFloat('Dismount Offset Z', cpNormal, False, 1, -1, nil, nil, 65.0), + wbFloat('Mount Camera Offset X'), + wbFloat('Mount Camera Offset Y', cpNormal, False, 1, -1, nil, nil, -300.0), + wbFloat('Mount Camera Offset Z') + ]) + //wbByteArray('Unknown', 4*7) + ], cpNormal, True, nil, 29), + wbEmpty(MNAM, 'Male Marker').SetRequired, + wbString(ANAM, 'Male Skeletal Model'), + wbMODT, + wbEmpty(FNAM, 'Female Marker').SetRequired, + wbString(ANAM, 'Female Skeletal Model'), + wbMODT, + wbEmpty(NAM2, 'Marker NAM2 #1'), + wbRArrayS('Movement Type Names', wbString(MTNM, 'Name', 4)).SetDefaultEditValues(['BLDO', 'RUN1', 'SNEK', 'SWIM', 'WALK']).SetRequired, + wbArray(VTCK, 'Voices', wbFormIDCk('Voice', [VTYP]), ['Male', 'Female'], cpNormal, True).SetDefaultEditValues(['MaleUniqueMolagBal [VTYP:0000002D]', 'FemaleUniqueAzura [VTYP:0000002E]']), + wbArray(DNAM, 'Decapitate Armors', wbFormIDCk('Decapitate Armor', [NULL, ARMO]), ['Male', 'Female'], cpNormal, False), + wbArray(HCLF, 'Default Hair Colors', wbFormIDCk('Default Hair Color', [NULL, CLFM]), ['Male', 'Female'], cpNormal, False), + wbInteger(TINL, 'Total Number of Tints in List', itU16, nil, nil, cpNormal, False), {>>> Needs Count Updated <<<} + wbFloat(PNAM, 'FaceGen - Main clamp', cpNormal, True).SetDefaultNativeValue(5.0), + wbFloat(UNAM, 'FaceGen - Face clamp', cpNormal, True).SetDefaultNativeValue(5.0), + wbFormIDCk(ATKR, 'Attack Race', [RACE], False, cpNormal, False), + wbRArrayS('Attacks', wbAttackData), + wbRStruct('Body Data', [ + wbEmpty(NAM1, 'Body Data Marker', cpNormal, True), + wbRStruct('Male Body Data', [ + wbEmpty(MNAM, 'Male Data Marker'), + wbBodyParts + ], [], cpNormal, True), + wbRStruct('Female Body Data', [ + wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), + wbBodyParts + ], [], cpNormal, True) + ], [], cpNormal, True), + wbArrayS(HNAM, 'Hairs', wbFormIDCk('Hair', [HDPT, NULL]), 0, cpNormal), + wbArrayS(ENAM, 'Eyes', wbFormIDCk('Eye', [EYES, NULL]), 0, cpNormal), + wbFormIDCk(GNAM, 'Body Part Data', [BPTD, NULL]).SetDefaultEditValue('DefaultBodyPartData [BPTD:0000001D]').SetRequired, + wbEmpty(NAM2, 'Marker NAM2 #2', cpNormal), + wbEmpty(NAM3, 'Marker NAM3 #3', cpNormal, True), + wbRStruct('Male Behavior Graph', [ + wbEmpty(MNAM, 'Male Data Marker'), + wbGenericModel + ], [], cpNormal, True) + .SetSummaryKey([1]) + .IncludeFlag(dfCollapsed, wbCollapseModels), + wbRStruct('Female Behavior Graph', [ + wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), + wbGenericModel + ], [], cpNormal, True) + .SetSummaryKey([1]) + .IncludeFlag(dfCollapsed, wbCollapseModels), + wbFormIDCk(NAM4, 'Material Type', [MATT, NULL]), + wbFormIDCk(NAM5, 'Impact Data Set', [IPDS, NULL]), + wbFormIDCk(NAM7, 'Decapitation FX', [ARTO, NULL]), + wbFormIDCk(ONAM, 'Open Loot Sound', [SNDR, NULL]), + wbFormIDCk(LNAM, 'Close Loot Sound', [SNDR, NULL]), + {>>> When NAME is user defined wbBipedObjectEnum will be incorrect <<<} + wbRArray('Biped Object Names', wbString(NAME, 'Name'), 32).IncludeFlag(dfNotAlignable).SetRequired, + wbRArrayS('Movement Types', wbRStructSK([0], 'Movement Types', [ + wbFormIDCk(MTYP, 'Movement Type', [MOVT, NULL]), + wbStruct(SPED, 'Override Values', [ + wbFloat('Left - Walk'), + wbFloat('Left - Run'), + wbFloat('Right - Walk'), + wbFloat('Right - Run'), + wbFloat('Forward - Walk'), + wbFloat('Forward - Run'), + wbFloat('Back - Walk'), + wbFloat('Back - Run'), + wbFloat('Rotate - Walk'), + wbFloat('Rotate - Walk'), + wbFloat('Unknown') + ]) + ], [])), + wbInteger(VNAM, 'Equipment Flags', itU32, wbEquipType).SetRequired, + wbRArrayS('Equip Slots', wbFormIDCk(QNAM, 'Equip Slot', [EQUP, NULL])), + wbFormIDCk(UNES, 'Unarmed Equip Slot', [EQUP, NULL]), + wbRArray('Phoneme Target Names', wbString(PHTN, 'Name')), + wbPHWT, + wbFormIDCk(WKMV, 'Base Movement Default - Walk', [MOVT, NULL]), + wbFormIDCk(RNMV, 'Base Movement Default - Run', [MOVT, NULL]), + wbFormIDCk(SWMV, 'Base Movement Default - Swim', [MOVT, NULL]), + wbFormIDCk(FLMV, 'Base Movement Default - Fly', [MOVT, NULL]), + wbFormIDCk(SNMV, 'Base Movement Default - Sneak', [MOVT, NULL]), + wbFormIDCk(SPMV, 'Base Movement Default - Sprint', [MOVT, NULL]), + // Start Head Data + wbRStruct('Head Data', [ + wbEmpty(NAM0, 'Head Data Marker', cpNormal, True), + wbRStruct('Male Head Data', [ + wbEmpty(MNAM, 'Male Data Marker', cpNormal, True), + wbHeadParts, + wbMorphs, + wbRArrayS('Race Presets Male', wbFormIDCk(RPRM, 'Preset NPC', [NPC_, NULL])), + wbRArrayS('Available Hair Colors Male', wbFormIDCk(AHCM, 'Hair Color', [CLFM, NULL])), + wbRArrayS('Face Details Texture Set List Male', wbFormIDCk(FTSM, 'Texture Set', [TXST, NULL])), + wbFormIDCk(DFTM, 'Default Face Texture Male', [TXST, NULL]), + wbTints, + wbGenericModel + ], [], cpNormal, True), + wbRStruct('Female Head Data', [ + wbEmpty(NAM0, 'Head Data Marker', cpNormal, True), + wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), + wbHeadParts, + wbMorphs, + wbRArrayS('Race Presets Female', wbFormIDCk(RPRF, 'Preset NPC', [NPC_, NULL])), + wbRArrayS('Available Hair Colors Female', wbFormIDCk(AHCF, 'Hair Color', [CLFM, NULL])), + wbRArrayS('Face Details Texture Set List Female', wbFormIDCk(FTSF, 'Texture Set', [TXST, NULL])), + wbFormIDCk(DFTF, 'Default Face Texture Female', [TXST, NULL]), + wbTints, + wbGenericModel + ], [], cpNormal, True) + ], [], cpNormal, False), + // End Head Data + wbFormIDCk(NAM8, 'Morph race', [RACE, NULL]), + wbFormIDCk(RNAM, 'Armor race', [RACE, NULL]) + ], False, nil, cpNormal, False, wbRACEAfterLoad, wbRACEAfterSet); + + wbRefRecord(REFR, 'Placed Object', wbFormaterUnion(wbREFRRecordFlagsDecider, [ + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000400} 10, 'Persistent', + {0x00000800} 11, 'Initially Disabled', + {0x00010000} 16, 'Is Full LOD', + {0x04000000} 26, 'Filter (Collision Geometry)', + {0x08000000} 27, 'Bounding Box (Collision Geometry)', + {0x10000000} 28, 'Reflected By Auto Water', + {0x40000000} 30, 'Ground', + {0x80000000} 31, 'Multibound' + ], True, True)), + {ACTI STAT TREE FLOR} wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000200} 9, 'Hidden From Local Map', + {0x00000400} 10, 'Persistent', + {0x00000800} 11, 'Initially Disabled', + {0x00002000} 13, 'Sky Marker', + {0x00008000} 15, 'Visible when distant', + {0x00010000} 16, 'Is Full LOD', + {0x04000000} 26, 'Filter (Collision Geometry)', + {0x08000000} 27, 'Bounding Box (Collision Geometry)', + {0x10000000} 28, 'Reflected By Auto Water', + {0x20000000} 29, 'Don''t Havok Settle', + {0x40000000} 30, 'No Respawn', + {0x80000000} 31, 'Multibound' + ], True, True)), + {CONT} wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000400} 10, 'Persistent', + {0x00000800} 11, 'Initially Disabled', + {0x00010000} 16, 'Is Full LOD', + {0x02000000} 25, 'No AI Acquire', + {0x04000000} 26, 'Filter (Collision Geometry)', + {0x08000000} 27, 'Bounding Box (Collision Geometry)', + {0x10000000} 28, 'Reflected By Auto Water', + {0x20000000} 29, 'Don''t Havok Settle', + {0x40000000} 30, 'Ground', + {0x80000000} 31, 'Multibound' + ], True, True)), + {DOOR} wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000040} 6, 'Hidden From Local Map', + {0x00000100} 8, 'Inaccessible', + {0x00000400} 10, 'Persistent', + {0x00000800} 11, 'Initially Disabled', + {0x00010000} 16, 'Is Full LOD', + {0x04000000} 26, 'Filter (Collision Geometry)', + {0x08000000} 27, 'Bounding Box (Collision Geometry)', + {0x10000000} 28, 'Reflected By Auto Water', + {0x20000000} 29, 'Don''t Havok Settle', + {0x40000000} 30, 'No Respawn', + {0x80000000} 31, 'Multibound' + ], True, True)), + {LIGH} wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000100} 8, 'Doesn''t Light Water', + {0x00000200} 9, 'Casts Shadows', + {0x00000400} 10, 'Persistent', + {0x00000800} 11, 'Initially Disabled', + {0x00010000} 16, 'Never Fades', + {0x00020000} 17, 'Doesn''t Light Landscape', + {0x02000000} 25, 'No AI Acquire', + {0x10000000} 28, 'Reflected By Auto Water', + {0x20000000} 29, 'Don''t Havok Settle', + {0x40000000} 30, 'No Respawn', + {0x80000000} 31, 'Multibound' + ], True, True)), + {MSTT} wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000200} 9, 'Motion Blur', + {0x00000400} 10, 'Persistent', + {0x00000800} 11, 'Initially Disabled', + {0x00010000} 16, 'Is Full LOD', + {0x04000000} 26, 'Filter (Collision Geometry)', + {0x08000000} 27, 'Bounding Box (Collision Geometry)', + {0x10000000} 28, 'Reflected By Auto Water', + {0x20000000} 29, 'Don''t Havok Settle', + {0x40000000} 30, 'No Respawn', + {0x80000000} 31, 'Multibound' + ], True, True)), + {ADDN} wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000400} 10, 'Persistent', + {0x00000800} 11, 'Initially Disabled', + {0x00010000} 16, 'Is Full LOD', + {0x10000000} 28, 'Reflected By Auto Water', + {0x20000000} 29, 'Don''t Havok Settle', + {0x40000000} 30, 'No Respawn', + {0x80000000} 31, 'Multibound' + ], True, True)), + {ALCH SCRL AMMO ARMO INGR KEYM MISC SLGM WEAP} + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000400} 10, 'Persistent', + {0x00000800} 11, 'Initially Disabled', + {0x00010000} 16, 'Is Full LOD', + {0x02000000} 25, 'No AI Acquire', + {0x10000000} 28, 'Reflected By Auto Water', + {0x20000000} 29, 'Don''t Havok Settle', + {0x40000000} 30, 'No Respawn', + {0x80000000} 31, 'Multibound' + ], True, True)) + ]), [ + wbEDID, + wbVMAD, + wbFormIDCk(NAME, 'Base', [ + TREE, SNDR, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, LVLN, LVLC, + MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, INGR, + MSTT, TACT, TXST, FLOR, SLGM, SCRL, SOUN, APPA, SPEL, ARTO, ADDN + ], False, cpNormal, True), + + {--- Bound Contents ---} + {--- Bound Data ---} + wbStruct(XMBO, 'Bound Half Extents', [ + wbFloat('X'), + wbFloat('Y'), + wbFloat('Z') + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + + {--- Primitive ---} + wbStruct(XPRM, 'Primitive', [ + wbStruct('Bounds', [ + wbFloat('X', cpNormal, True, 2, 4), + wbFloat('Y', cpNormal, True, 2, 4), + wbFloat('Z', cpNormal, True, 2, 4) + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + wbStruct('Color', [ + {84} wbFloat('Red', cpNormal, False, 255, 0), + {88} wbFloat('Green', cpNormal, False, 255, 0), + {92} wbFloat('Blue', cpNormal, False, 255, 0) + ]).SetToStr(wbRGBAToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + wbFloat('Unknown'), + wbInteger('Type', itU32, wbEnum([ + 'None', + 'Box', + 'Sphere', + 'Portal Box', + 'Unknown 4' + ])) + ]), + wbUnknown(XORD), + wbSizePosRot(XOCP, 'Occlusion Plane Data'), + + wbArray(XPOD, 'Portal Data', wbStruct('References', [ + wbFormIDCk('Origin', [REFR, NULL]), + wbFormIDCk('Destination', [REFR, NULL]) + ])), + wbSizePosRot(XPTL, 'Room Portal (unused)', cpIgnore), // removed by CK + + wbRStruct('Bound Data', [ + wbStruct(XRMR, 'Header', [ + wbInteger('Linked Rooms Count', itU8), + wbInteger('Flags', itU8, wbFlags([ + 'Unknown 1', + 'Unknown 2', + 'Unknown 3', + 'Unknown 4', + 'Unknown 5', + 'Unknown 6', + 'Has Image Space', + 'Has Lighting Template' + ])), + wbByteArray('Unknown', 2) + ]), + wbFormIDCk(LNAM, 'Lighting Template', [LGTM]), + wbFormIDCk(INAM, 'Image Space', [IMGS]), + wbRArrayS('Linked Rooms', + wbFormIDCk(XLRM, 'Linked Room', [REFR]) + ).SetCountPath('XRMR\Linked Rooms Count') + ], []), + wbEmpty(XMBP, 'MultiBound Primitive Marker', cpIgnore), + + wbXRGD, + wbXRGB, + wbFloat(XRDS, 'Radius'), + + {--- Reflected By / Refracted By ---} + wbRArrayS('Reflected/Refracted By', + wbStructSK(XPWR, [0], 'Water', [ + wbFormIDCk('Reference', [REFR]), + wbInteger('Type', itU32, wbFlags([ + 'Reflection', + 'Refraction' + ])) + ], cpNormal, False, nil, 1) + ), + + {--- Lit Water ---} + wbRArrayS('Lit Water', + wbFormIDCk(XLTW, 'Water', [REFR]) + ), + + {--- Emittance ---} + wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), + wbStruct(XLIG, 'Light Data', [ + wbFloat('FOV 90+/-'), + wbFloat('Fade 1.35+/-'), + wbFloat('End Distance Cap'), + wbFloat('Shadow Depth Bias'), + wbByteArray('Unknown', 4) // optional + ], cpNormal, False, nil, 4), + wbStruct(XALP, 'Alpha', [ + wbInteger('Cutoff', itU8), + wbInteger('Base', itU8) + ]), + + {--- Teleport ---} + wbStruct(XTEL, 'Teleport Destination', [ + wbFormIDCk('Door', [REFR], True), + wbPosRot, + wbInteger('Flags', itU32, wbFlags([ + 'No Alarm' + ])) + ]), + wbFormIDCk(XTNM, 'Teleport Message Box', [MESG]), + + {--- MultiBound ---} + wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), + + wbByteArray(XWCN, 'Unknown', 0, cpIgnore), // leftover + wbByteArray(XWCS, 'Unknown', 0, cpIgnore), // leftover + wbStruct(XWCU, 'Water Velocity', [ + wbFloat('X Offset'), + wbFloat('Y Offset'), + wbFloat('Z Offset'), + wbByteArray('Unknown', 4), + wbFloat('X Angle'), + wbFloat('Y Angle'), + wbFloat('Z Angle'), + wbByteArray('Unknown', 0) + ]), + + wbStruct(XCVL, 'Unknown', [ + wbByteArray('Unknown', 4), + wbFloat('X Angle'), + wbByteArray('Unknown', 4) + ]), + wbFormIDCk(XCZR, 'Unknown', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), + wbUnknown(XCZA), + wbFormIDCk(XCZC, 'Unknown', [CELL, NULL]), + wbXSCL, + wbFormIDCk(XSPC, 'Spawn Container', [REFR]), + + {--- Activate Parents ---} + wbRStruct('Activate Parents', [ + wbInteger(XAPD, 'Flags', itU8, wbFlags([ + 'Parent Activate Only' + ], True)), + wbRArrayS('Activate Parent Refs', + wbStructSK(XAPR, [0], 'Activate Parent Ref', [ + wbFormIDCk('Reference', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + wbFloat('Delay') + ]) + ) + ], []), + + wbFormIDCk(XLIB, 'Leveled Item Base Object', [LVLI]), + wbXLCM, + wbFormIDCk(XLCN, 'Persistent Location', [LCTN]), + + {>>> COLL form Index value <<<} + wbInteger(XTRI, 'Collision Layer', itU32), + + {--- Lock ---} + {>>Lock Tab for REFR when 'Locked' is Unchecked this record is not present <<<} + wbStruct(XLOC, 'Lock Data', [ + wbInteger('Level', itU8, wbEnum([], [ + 1, 'Novice', + 25, 'Apprentice', + 50, 'Adept', + 75, 'Expert', + 100, 'Master', + 255, 'Requires Key' + ])), + wbByteArray('Unused', 3, cpIgnore), + wbFormIDCkNoReach('Key', [KEYM, NULL]), + wbInteger('Flags', itU8, wbFlags(['', '', 'Leveled Lock'])), + wbByteArray('Unused', 3, cpIgnore), + wbByteArray('Unused', 8, cpIgnore) + ], cpNormal, False, nil, 4), + + wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), + + {--- Generated Data ---} + wbStruct(XNDP, 'Navigation Door Link', [ + wbFormIDCk('Navigation Mesh', [NAVM]), + wbInteger('Teleport Marker Triangle', itS16, wbREFRNavmeshTriangleToStr, wbStringToInt), + wbByteArray('Unused', 2, cpIgnore) + ]), + + wbArray(XLRT, 'Location Ref Type', wbFormIDCk('Ref', [LCRT, NULL])), + wbEmpty(XIS2, 'Ignored by Sandbox'), + + {--- Ownership ---} + wbOwnership(wbXOWN, [XRGD]), + + wbInteger(XCNT, 'Item Count', itS32), + wbFloat(XCHG, 'Charge'), + wbFormIDCk(XLRL, 'Location Reference', [LCRT, LCTN, NULL], False, cpBenignIfAdded), + + wbXESP, + wbRArray('Linked References', wbStruct(XLKR, 'Linked Reference', [ + wbFormIDCk('Keyword/Ref', [KYWD, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), + wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]) + ], cpNormal, False, nil, 1)), + + wbRArray('Patrol', wbRStruct('Data', [ + wbFloat(XPRD, 'Idle Time', cpNormal, True), + wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), + wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), + wbByteArray(SCHR, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbByteArray(SCTX, 'Unused', 0, cpIgnore, false, false, wbNeverShow), + wbPDTOs + ], [])), + + {--- Flags ---} + wbActionFlag, + + wbFloat(XHTW, 'Head-Tracking Weight'), + wbFloat(XFVC, 'Favor Cost'), + + wbEmpty(ONAM, 'Open by Default'), + + {--- Map Data ---} + wbRStruct('Map Marker', [ + wbEmpty(XMRK, 'Map Marker Data'), + wbInteger(FNAM, 'Map Flags', itU8, wbFlags([ + {0x01} 'Visible', + {0x02} 'Can Travel To', + {0x04} '"Show All" Hidden' + ]), cpNormal, True), + wbFULLReq, + wbStruct(TNAM, '', [ + wbInteger('Type', itU8, wbMapMarkerEnum), + wbByteArray('Unused', 1) + ], cpNormal, True) + ], []), + {--- Attach reference ---} + wbFormIDCk(XATR, 'Attach Ref', [REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + wbXLOD, + wbDataPosRot + ], True, wbPlacedAddInfo, cpNormal, False, wbREFRAfterLoad); + + wbRecord(REGN, 'Region', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000040} 6, 'Border Region' + ])), [ + wbEDID, + wbStruct(RCLR, 'Map Color', [ + wbInteger('Red', itU8), + wbInteger('Green', itU8), + wbInteger('Blue', itU8), + wbByteArray('Unknown', 1) + ], cpNormal, True).SetToStr(wbRGBAToStr).IncludeFlag(dfCollapsed, wbCollapseRGBA), + {>>> Skyrim.esm has some incorrect FormIDs here, probably leftover <<<} + wbFormIDCkNoReach(WNAM, 'Worldspace', [WRLD]), + wbRArray('Region Areas', wbRStruct('Region Area', [ + wbInteger(RPLI, 'Edge Fall-off', itU32), + wbArray(RPLD, 'Region Point List Data', wbStruct('Point', [ + wbFloat('X'), + wbFloat('Y') + ]), 0, wbRPLDAfterLoad) + ], [])), + wbRArrayS('Region Data Entries', wbRStructSK([0], 'Region Data Entry', [ + {always starts with an RDAT} + wbStructSK(RDAT, [0], 'Data Header', [ + wbInteger('Type', itU32, wbEnum([ + {0} 'Unknown 0', + {1} 'Unknown 1', + {2} 'Objects', + {3} 'Weather', + {4} 'Map', + {5} 'Land', + {6} 'Grass', + {7} 'Sound', + {8} 'Imposter', + {9} 'Unknown 10', + {10}'Unknown 11', + {11}'Unknown 12', + {12}'Unknown 13', + {13}'Unknown 14', + {14}'Unknown 15', + {15}'Unknown 16' + ])), + wbInteger('Flags', itU8, wbFlags([ + 'Override' + ])), + wbInteger('Priority', itU8), + wbByteArray('Unknown') + ], cpNormal, True), + + {--- Icon ---} + wbICON, + + {--- Sound ---} + wbFormIDCk(RDMO, 'Music', [MUSC], False, cpNormal, False, wbREGNSoundDontShow), + wbRegionSounds, + + {--- Map ---} + wbLString(RDMP, 'Map Name', 0, cpTranslate, False, wbREGNMapDontShow), + + {followed by one of these: } + + {--- Objects ---} + wbArray(RDOT, 'Objects', wbStruct('Object', [ + wbFormIDCk('Object', [TREE, FLOR, STAT, LTEX, MSTT]), + wbInteger('Parent Index', itU16, wbHideFFFF), + wbByteArray('Unknown', 2), + wbFloat('Density'), + wbInteger('Clustering', itU8), + wbInteger('Min Slope', itU8), + wbInteger('Max Slope', itU8), + wbInteger('Flags', itU8, wbFlags([ + {0}'Conform to slope', + {1}'Paint Vertices', + {2}'Size Variance +/-', + {3}'X +/-', + {4}'Y +/-', + {5}'Z +/-', + {6}'Tree', + {7}'Huge Rock' + ])), + wbInteger('Radius wrt Parent', itU16), + wbInteger('Radius', itU16), + wbFloat('Min Height'), + wbFloat('Max Height'), + wbFloat('Sink'), + wbFloat('Sink Variance'), + wbFloat('Size Variance'), + wbStruct('Angle Variance', [ + wbInteger('X', itU16), + wbInteger('Y', itU16), + wbInteger('Z', itU16) + ]).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + wbByteArray('Unknown', 2), + wbByteArray('Unknown', 4) + ]), 0, nil, nil, cpNormal, False, wbREGNObjectsDontShow), + + {--- Grass ---} + wbArrayS(RDGS, 'Grasses', wbStructSK([0], 'Grass', [ + wbFormIDCk('Grass', [GRAS]), + wbByteArray('Unknown',4) + ]), 0, cpNormal, False, nil, nil, wbREGNGrassDontShow), + + {--- Weather ---} + wbArrayS(RDWT, 'Weather Types', wbStructSK([0], 'Weather Type', [ + wbFormIDCk('Weather', [WTHR]), + wbInteger('Chance', itU32), + wbFormIDCk('Global', [GLOB, NULL]) + ]), 0, cpNormal, False, nil, nil, wbREGNWeatherDontShow) + + ], [])) + ], True); + + wbRecord(SOUN, 'Sound Marker', [ + wbEDID, + wbOBND(True), + wbUnknown(FNAM, cpIgnore), // leftover, unused + wbUnknown(SNDD, cpIgnore), // leftover, unused + wbFormIDCk(SDSC, 'Sound Descriptor', [SNDR, NULL]) + ]); + + wbSPIT := wbStruct(SPIT, 'Data', [ + wbInteger('Base Cost', itU32), + wbInteger('Flags', itU32, wbFlags([ + {0x00000001} 'Manual Cost Calc', + {0x00000002} 'Unknown 2', + {0x00000004} 'Unknown 3', + {0x00000008} 'Unknown 4', + {0x00000010} 'Unknown 5', + {0x00000020} 'Unknown 6', + {0x00000040} 'Unknown 7', + {0x00000080} 'Unknown 8', + {0x00000100} 'Unknown 9', + {0x00000200} 'Unknown 10', + {0x00000400} 'Unknown 11', + {0x00000800} 'Unknown 12', + {0x00001000} 'Unknown 13', + {0x00002000} 'Unknown 14', + {0x00004000} 'Unknown 15', + {0x00008000} 'Unknown 16', + {0x00010000} 'Unknown 17', + {0x00020000} 'PC Start Spell', + {0x00040000} 'Unknown 19', + {0x00080000} 'Area Effect Ignores LOS', + {0x00100000} 'Ignore Resistance', + {0x00200000} 'No Absorb/Reflect', + {0x00400000} 'Unknown 23', + {0x00800000} 'No Dual Cast Modification', + {0x01000000} 'Unknown 25', + {0x02000000} 'Unknown 26', + {0x04000000} 'Unknown 27', + {0x08000000} 'Unknown 28', + {0x10000000} 'Unknown 29', + {0x20000000} 'Unknown 30', + {0x40000000} 'Unknown 31', + {0x80000000} 'Unknown 32' + ])), + wbInteger('Type', itU32, wbEnum([ + {0} 'Spell', + {1} 'Disease', + {2} 'Power', + {3} 'Lesser Power', + {4} 'Ability', + {5} 'Poison', + {6} 'Unknown 6', + {7} 'Unknown 7', + {8} 'Unknown 8', + {9} 'Unknown 9', + {10} 'Addiction', + {11} 'Voice' + ])), + wbFloat('Charge Time'), + wbInteger('Cast Type', itU32, wbCastEnum), + wbInteger('Target Type', itU32, wbTargetEnum), + wbFloat('Cast Duration'), + wbFloat('Range'), + wbFormIDCk('Half-cost Perk', [NULL, PERK]) + ], cpNormal, True); + + wbRecord(SPEL, 'Spell', [ + wbEDID, + wbOBND(True), + wbFULL, + wbKSIZ, + wbKWDAs, + wbMDOB, + wbETYP, + wbDESCReq, + wbSPIT, + wbEffectsReq + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); + + wbRecord(SCRL, 'Scroll', [ + wbEDID, + wbOBND(True), + wbFULL, + wbKSIZ, + wbKWDAs, + wbMDOB, + wbETYP, + wbDESC, + wbGenericModel, + wbDEST, + wbYNAM, + wbZNAM, + wbStruct(DATA, 'Item', [ + wbInteger('Value', itU32), + wbFloat('Weight') + ], cpNormal, True), + wbSPIT, + wbEffectsReq + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); + + wbRecord(STAT, 'Static', + wbFlags(wbRecordFlagsFlags, [ + {0x00000001} { 0} '', + {0x00000002} { 1} '', + {0x00000004} { 2} 'Never Fades', + {0x00000008} { 3} '', + {0x00000010} { 4} '', + {0x00000020} { 5} 'Deleted', + {0x00000040} { 6} 'Has Tree LOD', + {0x00000080} { 7} 'Add-On LOD Object', + {0x00000100} { 8} '', + {0x00000200} { 9} 'Hidden From Local Map', + {0x00000400} {10} '', + {0x00000800} {11} 'Unknown 11', // present in Skyrim.esm but can't be set + {0x00001000} {12} '', + {0x00002000} {13} '', + {0x00004000} {14} '', + {0x00008000} {15} 'Has Distant LOD', + {0x00010000} {16} 'Unknown 16', // present in Skyrim.esm but can't be set + {0x00020000} {17} 'Uses HD LOD Texture', + {0x00040000} {18} '', + {0x00080000} {19} 'Has Currents', + {0x00100000} {20} '', + {0x00200000} {21} '', + {0x00400000} {22} '', + {0x00800000} {23} 'Is Marker', + {0x01000000} {24} '', + {0x02000000} {25} 'Obstacle', + {0x04000000} {26} 'NavMesh Generation - Filter', + {0x08000000} {27} 'NavMesh Generation - Bounding Box', + {0x10000000} {28} 'Show In World Map', + {0x20000000} {29} '', + {0x40000000} {30} 'NavMesh Generation - Ground', + {0x80000000} {31} '' + ], [11, 16]), [ + wbEDID, + wbOBND(True), + wbGenericModel, + IsSSE( + wbStruct(DNAM, 'Direction Material', [ + wbFloat('Max Angle (30-120)'), + wbFormIDCk('Material', [MATO, NULL]), + // SSE + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'Considered Snow' + ])), + wbByteArray('Unused', 3, cpIgnore) + ], cpNormal, True, nil, 2), + wbStruct(DNAM, 'Direction Material', [ + wbFloat('Max Angle (30-120)'), + wbFormIDCk('Material', [MATO, NULL]) + ], cpNormal, True) + ), + wbArray(MNAM, 'Distant LOD', + wbStruct('LOD', [ + {>>> Contains null-terminated mesh FileName followed by random data up to 260 bytes <<<} + wbString(True, 'Mesh', 260) + //wbByteArray('Mesh', 260, cpIgnore) + ]), [ + 'Level 0', + 'Level 1', + 'Level 2', + 'Level 3' + ], + cpNormal, False + ), + wbUnknown(ENAM) + ]); + + wbRecord(TES4, 'Main File Header', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000001} 0, 'ESM', + {0x00000002} 1, 'Altered', + {0x00000004} 2, 'Checked', + {0x00000008} 3, 'Active', + {0x00000010} 4, 'Optimized File', + {0x00000020} 5, 'Temp ID Owner', + {0x00000080} 7, 'Localized', + {0x00000100} 8, 'Precalc Data Only', + {0x00000200} 9, IsSSE('ESL', '') + ], False), True), [ + wbHEDR, + wbByteArray(OFST, 'Unknown', 0, cpIgnore), + wbByteArray(DELE, 'Unknown', 0, cpIgnore), + wbString(CNAM, 'Author', 0, cpTranslate, True), + wbString(SNAM, 'Description', 0, cpTranslate), + wbRArray('Master Files', wbRStruct('Master File', [ + wbStringForward(MAST, 'FileName', 0, cpNormal, True), + wbByteArray(DATA, 'Unknown', 8, cpIgnore, True) + ], [ONAM])).IncludeFlag(dfInternalEditOnly, not wbAllowMasterFilesEdit), + wbArray(ONAM, 'Overridden Forms', + wbFormIDCk('Form', [ACHR, LAND, NAVM, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), + 0, nil, nil, cpNormal, False{, wbTES4ONAMDontShow}), + wbByteArray(SCRN, 'Screenshot'), + wbUnknown(INTV), + wbUnknown(INCC) + ], True, nil, cpNormal, True, wbRemoveOFST); + + wbRecord(PLYR, 'Player Reference', [ + wbEDID, + wbFormID(PLYR, 'Player', cpNormal, True).SetDefaultNativeValue($7) + ]).IncludeFlag(dfInternalEditOnly); +end; + +procedure DefineTES5o; +begin + + wbRecord(TREE, 'Tree', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00008000} 15, 'Has Distant LOD' + ])), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbGenericModel, + wbFormIDCK(PFIG, 'Ingredient', [INGR, ALCH, MISC, LVLI, NULL]), + wbFormIDCK(SNAM, 'Harvest Sound', [SNDR, NULL]), + wbStruct(PFPC, 'Ingredient Production', [ + wbInteger('Spring', itU8), + wbInteger('Summer', itU8), + wbInteger('Fall', itU8), + wbInteger('Winter', itU8) + ]), + wbFULL, + wbStruct(CNAM, 'Tree Data', [ + wbFloat('Trunk Flexibility'), + wbFloat('Branch Flexibility'), + wbFloat('Trunk Amplitude'), + wbFloat('Front Amplitude'), + wbFloat('Back Amplitude'), + wbFloat('Side Amplitude'), + wbFloat('Front Frequency'), + wbFloat('Back Frequency'), + wbFloat('Side Frequency'), + wbFloat('Leaf Flexibility'), + wbFloat('Leaf Amplitude'), + wbFloat('Leaf Frequency') + ], cpNormal, True) + ]); + + wbRecord(FLOR, 'Flora', [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULLReq, + wbGenericModel, + wbDEST, + wbKSIZ, + wbKWDAs, + wbUnknown(PNAM), + wbLString(RNAM, 'Activate Text Override', 0, cpTranslate), + wbUnknown(FNAM), + wbFormIDCk(PFIG, 'Ingredient', [INGR, ALCH, LVLI, MISC, NULL]), + wbFormIDCK(SNAM, 'Sound', [SNDR, NULL]), + wbSeasons + ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); + + wbRecord(WATR, 'Water', [ + wbEDID, + wbFULL, + wbRArray('Unused', wbString(NNAM, 'Noise Map', 0, cpIgnore, False)), // leftover + wbInteger(ANAM, 'Opacity', itU8, nil, cpNormal, True), + wbInteger(FNAM, 'Flags', itU8, wbFlags([ + {0x01} 'Causes Damage', + {0x02} 'Unknown 1', + {0x04} 'Unknown 2', + {0x08} IsSSE('Enable Flowmap', 'Unknown 3'), + {0x10} IsSSE('Blend Normals', 'Unknown 4'), + {0x20} 'Unknown 5', + {0x40} 'Unknown 6', + {0x80} 'Unknown 7' + ]), cpNormal, True), + wbByteArray(MNAM, 'Unused', 0, cpIgnore, False), // leftover + wbFormIDCk(TNAM, 'Material', [MATT]), + wbFormIDCk(SNAM, 'Open Sound', [SNDR, NULL]), + wbFormIDCk(XNAM, 'Spell', [SPEL]), + wbFormIDCk(INAM, 'Image Space', [IMGS]), + IsSSE( + wbInteger(DATA, 'Unused', itU16, nil, cpIgnore, True, True), + wbInteger(DATA, 'Damage Per Second', itU16, nil, cpNormal, True, True) + ), + IsSSE( + wbStruct(DNAM, 'Visual Data', [ + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Specular Properties - Sun Specular Power'), + wbFloat('Water Properties - Reflectivity Amount'), + wbFloat('Water Properties - Fresnel Amount'), + wbByteArray('Unknown', 4), + wbFloat('Fog Properties - Above Water - Fog Distance - Near Plane'), + wbFloat('Fog Properties - Above Water - Fog Distance - Far Plane'), + wbByteColors('Shallow Color'), + wbByteColors('Deep Color'), + wbByteColors('Reflection Color'), + wbByteArray('Unknown', 4), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Displacement Simulator - Starting Size'), + wbFloat('Displacement Simulator - Force'), + wbFloat('Displacement Simulator - Velocity'), + wbFloat('Displacement Simulator - Falloff'), + wbFloat('Displacement Simulator - Dampner'), + wbFloat('Unknown'), + wbFloat('Noise Properties - Noise Falloff'), + wbFloat('Noise Properties - Layer One - Wind Direction'), + wbFloat('Noise Properties - Layer Two - Wind Direction'), + wbFloat('Noise Properties - Layer Three - Wind Direction'), + wbFloat('Noise Properties - Layer One - Wind Speed'), + wbFloat('Noise Properties - Layer Two - Wind Speed'), + wbFloat('Noise Properties - Layer Three - Wind Speed'), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Fog Properties - Above Water - Fog Amount'), + wbFloat('Unknown'), + wbFloat('Fog Properties - Under Water - Fog Amount'), + wbFloat('Fog Properties - Under Water - Fog Distance - Near Plane'), + wbFloat('Fog Properties - Under Water - Fog Distance - Far Plane'), + wbFloat('Water Properties - Refraction Magnitude'), + wbFloat('Specular Properties - Specular Power'), + wbFloat('Unknown'), + wbFloat('Specular Properties - Specular Radius'), + wbFloat('Specular Properties - Specular Brightness'), + wbFloat('Noise Properties - Layer One - UV Scale'), + wbFloat('Noise Properties - Layer Two - UV Scale'), + wbFloat('Noise Properties - Layer Three - UV Scale'), + wbFloat('Noise Properties - Layer One - Amplitude Scale'), + wbFloat('Noise Properties - Layer Two - Amplitude Scale'), + wbFloat('Noise Properties - Layer Three - Amplitude Scale'), + wbFloat('Water Properties - Reflection Magnitude'), + wbFloat('Specular Properties - Sun Sparkle Magnitude'), + wbFloat('Specular Properties - Sun Specular Magnitude'), + wbFloat('Depth Properties - Reflections'), + wbFloat('Depth Properties - Refraction'), + wbFloat('Depth Properties - Normals'), + wbFloat('Depth Properties - Specular Lighting'), + wbFloat('Specular Properties - Sun Sparkle Power'), + // SSE + wbFloat('Noise Properties - Flowmap Scale') + ], cpNormal, True, nil, 57), + wbStruct(DNAM, 'Visual Data', [ + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Specular Properties - Sun Specular Power'), + wbFloat('Water Properties - Reflectivity Amount'), + wbFloat('Water Properties - Fresnel Amount'), + wbByteArray('Unknown', 4), + wbFloat('Fog Properties - Above Water - Fog Distance - Near Plane'), + wbFloat('Fog Properties - Above Water - Fog Distance - Far Plane'), + wbByteColors('Shallow Color'), + wbByteColors('Deep Color'), + wbByteColors('Reflection Color'), + wbByteArray('Unknown', 4), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Displacement Simulator - Starting Size'), + wbFloat('Displacement Simulator - Force'), + wbFloat('Displacement Simulator - Velocity'), + wbFloat('Displacement Simulator - Falloff'), + wbFloat('Displacement Simulator - Dampner'), + wbFloat('Unknown'), + wbFloat('Noise Properties - Noise Falloff'), + wbFloat('Noise Properties - Layer One - Wind Direction'), + wbFloat('Noise Properties - Layer Two - Wind Direction'), + wbFloat('Noise Properties - Layer Three - Wind Direction'), + wbFloat('Noise Properties - Layer One - Wind Speed'), + wbFloat('Noise Properties - Layer Two - Wind Speed'), + wbFloat('Noise Properties - Layer Three - Wind Speed'), + wbFloat('Unknown'), + wbFloat('Unknown'), + wbFloat('Fog Properties - Above Water - Fog Amount'), + wbFloat('Unknown'), + wbFloat('Fog Properties - Under Water - Fog Amount'), + wbFloat('Fog Properties - Under Water - Fog Distance - Near Plane'), + wbFloat('Fog Properties - Under Water - Fog Distance - Far Plane'), + wbFloat('Water Properties - Refraction Magnitude'), + wbFloat('Specular Properties - Specular Power'), + wbFloat('Unknown'), + wbFloat('Specular Properties - Specular Radius'), + wbFloat('Specular Properties - Specular Brightness'), + wbFloat('Noise Properties - Layer One - UV Scale'), + wbFloat('Noise Properties - Layer Two - UV Scale'), + wbFloat('Noise Properties - Layer Three - UV Scale'), + wbFloat('Noise Properties - Layer One - Amplitude Scale'), + wbFloat('Noise Properties - Layer Two - Amplitude Scale'), + wbFloat('Noise Properties - Layer Three - Amplitude Scale'), + wbFloat('Water Properties - Reflection Magnitude'), + wbFloat('Specular Properties - Sun Sparkle Magnitude'), + wbFloat('Specular Properties - Sun Specular Magnitude'), + wbFloat('Depth Properties - Reflections'), + wbFloat('Depth Properties - Refraction'), + wbFloat('Depth Properties - Normals'), + wbFloat('Depth Properties - Specular Lighting'), + wbFloat('Specular Properties - Sun Sparkle Power') + ]) + ), + wbByteArray(GNAM, 'Unused', 0, cpNormal, True), // leftover + wbStruct(NAM0, 'Linear Velocity', [ + wbFloat('X'), + wbFloat('Y'), + wbFloat('Z') + ], cpNormal, False).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + wbStruct(NAM1, 'Angular Velocity', [ + wbFloat('X'), + wbFloat('Y'), + wbFloat('Z') + ], cpNormal, False).SetToStr(wbVec3ToStr).IncludeFlag(dfCollapsed, wbCollapseVec3), + wbString(NAM2, 'Noise Layer One - Noise Texture', 0, cpNormal, False), + wbString(NAM3, 'Noise Layer Two - Noise Texture', 0, cpNormal, False), + wbString(NAM4, 'Noise Layer Three - Noise Texture', 0, cpNormal, False), + // SSE + wbString(NAM5, 'Flow Normals - Noise Texture', 0, cpNormal, False) + ], False, nil, cpNormal, False); + + wbRecord(WEAP, 'Weapon', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00000004} 2, 'Non-Playable' + ])), [ + wbEDID, + wbVMAD, + wbOBND(True), + wbFULL, + wbGenericModel, + wbICON, + wbEITM, + wbInteger(EAMT, 'Enchantment Amount', itU16), + wbDEST, + wbETYP, + wbFormIDCk(BIDS, 'Block Bash Impact Data Set', [IPDS, NULL]), + wbFormIDCk(BAMT, 'Alternate Block Material', [MATT, NULL]), + wbYNAM, + wbZNAM, + wbKSIZ, + wbKWDAs, + wbDESC, + wbTexturedModel('Has Scope', [MOD3, MO3T], wbMO3S), + wbByteArray(NNAM, 'Unused', 0, cpIgnore, False), // leftover + wbFormIDCk(INAM, 'Impact Data Set', [IPDS, NULL]), + wbFormIDCk(WNAM, '1st Person Model Object', [STAT, NULL]), + wbFormIDCk(SNAM, 'Attack Sound', [SNDR]), + wbFormIDCk(XNAM, 'Attack Sound 2D', [SNDR]), + wbFormIDCk(NAM7, 'Attack Loop Sound', [SNDR]), + wbFormIDCk(TNAM, 'Attack Fail Sound', [SNDR]), + wbFormIDCk(UNAM, 'Idle Sound', [SNDR]), + wbFormIDCk(NAM9, 'Equip Sound', [SNDR]), + wbFormIDCk(NAM8, 'Unequip Sound', [SNDR]), + wbStruct(DATA, 'Game Data', [ + wbInteger('Value', itU32), + wbFloat('Weight'), + wbInteger('Damage', itU16) + ]), + wbStruct(DNAM, 'Data', [ + wbInteger('Animation Type', itU8, wbWeaponAnimTypeEnum), + wbByteArray('Unused', 3, cpIgnore), + wbFloat('Speed'), + wbFloat('Reach'), + wbInteger('Flags', itU16, wbFlags([ + {0x0001}'Ignores Normal Weapon Resistance', + {0x0002}'Automatic (unused)', + {0x0004}'Has Scope (unused)', + {0x0008}'Can''t Drop', + {0x0010}'Hide Backpack (unused)', + {0x0020}'Embedded Weapon (unused)', + {0x0040}'Don''t Use 1st Person IS Anim (unused)', + {0x0080}'Non-playable' + ], [1, 2, 4, 5, 6])), + wbByteArray('Unused', 2, cpIgnore), + wbFloat('Sight FOV'), + wbByteArray('Unknown', 4), + wbInteger('Base VATS To-Hit Chance', itU8), + wbInteger('Attack Animation', itU8, wbAttackAnimationEnum), + wbInteger('# Projectiles', itU8), + wbInteger('Embedded Weapon AV (unused)', itU8), + wbFloat('Range Min'), + wbFloat('Range Max'), + wbInteger('On Hit', itU32, wbEnum([ + 'No formula behaviour', + 'Dismember only', + 'Explode only', + 'No dismember/explode' + ])), + wbInteger('Flags2', itU32, wbFlags([ + {0x00000001} 'Player Only', + {0x00000002} 'NPCs Use Ammo', + {0x00000004} 'No Jam After Reload (unused)', + {0x00000008} 'Unknown 4', + {0x00000010} 'Minor Crime', + {0x00000020} 'Range Fixed', + {0x00000040} 'Not Used in Normal Combat', + {0x00000080} 'Unknown 8', + {0x00000100} 'Don''t Use 3rd Person IS Anim (unused)', + {0x00000200} 'Burst Shot', + {0x00000400} 'Rumble - Alternate', + {0x00000800} 'Long Bursts', + {0x00001000} 'Non-hostile', + {0x00002000} 'Bound Weapon' + ], [2, 8])), + wbFloat('Animation Attack Mult'), + wbFloat('Unknown'), + wbFloat('Rumble - Left Motor Strength'), + wbFloat('Rumble - Right Motor Strength'), + wbFloat('Rumble - Duration'), + wbByteArray('Unknown', 12), + wbInteger('Skill', itS32, wbSkillEnum), + wbByteArray('Unknown', 8), + wbInteger('Resist', itS32, wbActorValueEnum), + wbByteArray('Unknown', 4), + wbFloat('Stagger') + ]), + IsSSE( + wbStruct(CRDT, 'Critical Data', [ + wbInteger('Damage', itU16), + wbByteArray('Unused', 2, cpIgnore), + wbFloat('% Mult'), + wbInteger('Flags', itU8, wbFlags([ + 'On Death' + ])), + wbByteArray('Unused', 7, cpIgnore), + wbFormIDCk('Effect', [SPEL, NULL]), + wbByteArray('Unused', 4, cpIgnore) + ]), + wbStruct(CRDT, 'Critical Data', [ + wbInteger('Damage', itU16), + wbByteArray('Unused', 2, cpIgnore), + wbFloat('% Mult'), + wbInteger('Flags', itU8, wbFlags([ + 'On Death' + ])), + wbByteArray('Unused', 3, cpIgnore), + wbFormIDCk('Effect', [SPEL, NULL]) + ]) + ), + wbInteger(VNAM, 'Detection Sound Level', itU32, wbSoundlevelEnum), + wbFormIDCk(CNAM, 'Template', [WEAP]) + ], False, nil, cpNormal, False, wbWEAPAfterLoad, wbKeywordsAfterSet); + + wbRecord(WRLD, 'Worldspace', + wbFlags(wbRecordFlagsFlags, wbFlagsList([ + {0x00080000} 19, 'Can''t Wait' + ])), [ + wbEDID, + wbRArray(IsSSE('Large References', 'Unused RNAM'), + wbStruct(RNAM, 'Grid', [ + wbInteger('Y', itS16, nil, cpIgnore), + wbInteger('X', itS16, nil, cpIgnore), + wbArray('References', wbStruct('Reference', [ + wbFormIDCk('Ref', [REFR], False, cpIgnore), + wbInteger('Y', itS16, nil, cpIgnore), + wbInteger('X', itS16, nil, cpIgnore) + ]), -1).IncludeFlag(dfNotAlignable) + ]), + cpIgnore, False, nil, nil, wbNeverShow + ).IncludeFlag(dfNotAlignable), + wbMaxHeightDataWRLD, + wbFULL, + wbStruct(WCTR, 'Fixed Dimensions Center Cell', [ + wbInteger('X', itS16), + wbInteger('Y', itS16) + ]), + wbFormIDCk(LTMP, 'Interior Lighting', [LGTM]), + wbFormIDCk(XEZN, 'Encounter Zone', [ECZN, NULL]), + wbFormIDCk(XLCN, 'Location', [LCTN, NULL]), + wbRStruct('Parent', [ + wbFormIDCk(WNAM, 'Worldspace', [WRLD]), + wbStruct(PNAM, '', [ + wbInteger('Flags', itU8, wbFlags([ + {0x0001}'Use Land Data', + {0x0002}'Use LOD Data', + {0x0004}'Use Map Data', + {0x0008}'Use Water Data', + {0x0010}'Use Climate Data', + {0x0020}'Use Image Space Data (unused)', + {0x0040}'Use Sky Cell' + ], [5])), + wbByteArray('Unknown', 1) + ], cpNormal, True) + ], []), + wbFormIDCk(CNAM, 'Climate', [CLMT]), + wbFormIDCk(NAM2, 'Water', [WATR]), + wbFormIDCk(NAM3, 'LOD Water Type', [WATR]), + wbFloat(NAM4, 'LOD Water Height'), + wbStruct(DNAM, 'Land Data', [ + wbFloat('Default Land Height'), + wbFloat('Default Water Height') + ]), + wbString(ICON, 'Map Image'), + wbRStruct('Cloud Model', [wbGenericModel], []), + wbStruct(MNAM, 'Map Data', [ + wbStruct('Usable Dimensions', [ + wbInteger('X', itS32), + wbInteger('Y', itS32) + ]), + wbStruct('Cell Coordinates', [ + wbStruct('NW Cell', [ + wbInteger('X', itS16), + wbInteger('Y', itS16) + ]), + wbStruct('SE Cell', [ + wbInteger('X', itS16), + wbInteger('Y', itS16) + ]) + ]), + wbStruct('Camera Data', [ + wbFloat('Min Height'), + wbFloat('Max Height'), + wbFloat('Initial Pitch') + ]) + ], cpNormal, False, nil, 2), + wbStruct(ONAM, 'World Map Offset Data', [ + wbFloat('World Map Scale'), + wbFloat('Cell X Offset'), + wbFloat('Cell Y Offset'), + wbFloat('Cell Z Offset') + ], cpNormal, True), + wbFloat(NAMA, 'Distant LOD Multiplier'), + wbInteger(DATA, 'Flags', itU8, wbFlags([ + {0x01} 'Small World', + {0x02} 'Can''t Fast Travel', + {0x04} 'Unknown 3', + {0x08} 'No LOD Water', + {0x10} 'No Landscape', + {0x20} 'No Sky', + {0x40} 'Fixed Dimensions', + {0x80} 'No Grass' + ]), cpNormal, True), + {>>> Object Bounds doesn't show up in CK <<<} + wbWorldspaceOBND, + wbFormIDCk(ZNAM, 'Music', [MUSC]), + wbString(NNAM, 'Canopy Shadow (unused)', 0, cpIgnore), + wbString(XNAM, 'Water Noise Texture'), + wbString(TNAM, 'HD LOD Diffuse Texture'), + wbString(UNAM, 'HD LOD Normal Texture'), + wbString(XWEM, 'Water Environment Map (unused)', 0, cpIgnore), + wbOFST + ], False, nil, cpNormal, False, wbWRLDAfterLoad); + + + wbRecord(WTHR, 'Weather', [ + wbEDID, + wbString(_00_0TX, 'Cloud Texture Layer #0'), + wbString(_10_0TX, 'Cloud Texture Layer #1'), + wbString(_20_0TX, 'Cloud Texture Layer #2'), + wbString(_30_0TX, 'Cloud Texture Layer #3'), + wbString(_40_0TX, 'Cloud Texture Layer #4'), + wbString(_50_0TX, 'Cloud Texture Layer #5'), + wbString(_60_0TX, 'Cloud Texture Layer #6'), + wbString(_70_0TX, 'Cloud Texture Layer #7'), + wbString(_80_0TX, 'Cloud Texture Layer #8'), + wbString(_90_0TX, 'Cloud Texture Layer #9'), + wbString(_3A_0TX, 'Cloud Texture Layer #10'), + wbString(_3B_0TX, 'Cloud Texture Layer #11'), + wbString(_3C_0TX, 'Cloud Texture Layer #12'), + wbString(_3D_0TX, 'Cloud Texture Layer #13'), + wbString(_3E_0TX, 'Cloud Texture Layer #14'), + wbString(_3F_0TX, 'Cloud Texture Layer #15'), + wbString(_40h_0TX, 'Cloud Texture Layer #16'), + wbString(A0TX, 'Cloud Texture Layer #17'), + wbString(B0TX, 'Cloud Texture Layer #18'), + wbString(C0TX, 'Cloud Texture Layer #19'), + wbString(D0TX, 'Cloud Texture Layer #20'), + wbString(E0TX, 'Cloud Texture Layer #21'), + wbString(F0TX, 'Cloud Texture Layer #22'), + wbString(G0TX, 'Cloud Texture Layer #23'), + wbString(H0TX, 'Cloud Texture Layer #24'), + wbString(I0TX, 'Cloud Texture Layer #25'), + wbString(J0TX, 'Cloud Texture Layer #26'), + wbString(K0TX, 'Cloud Texture Layer #27'), + wbString(L0TX, 'Cloud Texture Layer #28'), + wbByteArray(DNAM, 'Unused', 0, cpIgnore), + wbByteArray(CNAM, 'Unused', 0, cpIgnore), + wbByteArray(ANAM, 'Unused', 0, cpIgnore), + wbByteArray(BNAM, 'Unused', 0, cpIgnore), + wbUnknown(LNAM), + wbFormIDCK(MNAM, 'Precipitation Type', [SPGD, NULL]), + wbFormIDCK(NNAM, 'Visual Effect', [RFCT, NULL], False, cpNormal, True), + wbByteArray(ONAM, 'Unused', 0, cpIgnore), + wbRStruct('Cloud Speed', [ + wbArray(RNAM, 'Y Speed', wbInteger('Layer', itU8, wbCloudSpeedToStr, wbCloudSpeedToInt)).IncludeFlag(dfNotAlignable), + wbArray(QNAM, 'X Speed', wbInteger('Layer', itU8, wbCloudSpeedToStr, wbCloudSpeedToInt)).IncludeFlag(dfNotAlignable) + ], []), + wbArray(PNAM, 'Cloud Colors', wbWeatherColors('Layer')).IncludeFlag(dfNotAlignable), + wbArray(JNAM, 'Cloud Alphas', wbStruct('Layer', [ + wbFloat('Sunrise'), + wbFloat('Day'), + wbFloat('Sunset'), + wbFloat('Night') + ])).IncludeFlag(dfNotAlignable), + {>>> not as an array since last entries are omitted in skyrim.esm <<<} + wbStruct(NAM0, 'Weather Colors', [ + wbWeatherColors('Sky-Upper'), + wbWeatherColors('Fog Near'), + wbWeatherColors('Unknown'), + wbWeatherColors('Ambient'), + wbWeatherColors('Sunlight'), + wbWeatherColors('Sun'), + wbWeatherColors('Stars'), + wbWeatherColors('Sky-Lower'), + wbWeatherColors('Horizon'), + wbWeatherColors('Effect Lighting'), + wbWeatherColors('Cloud LOD Diffuse'), + wbWeatherColors('Cloud LOD Ambient'), + wbWeatherColors('Fog Far'), + wbWeatherColors('Sky Statics'), + wbWeatherColors('Water Multiplier'), + wbWeatherColors('Sun Glare'), + wbWeatherColors('Moon Glare') + ], cpNormal, True, nil, 13), + wbStruct(FNAM, 'Fog Distance', [ + wbFloat('Day - Near'), + wbFloat('Day - Far'), + wbFloat('Night - Near'), + wbFloat('Night - Far'), + wbFloat('Day - Power'), + wbFloat('Night - Power'), + wbFloat('Day - Max'), + wbFloat('Night - Max') + ], cpNormal, True), + wbStruct(DATA, 'Data', [ + wbInteger('Wind Speed', itU8), // scaled 0..1 + wbByteArray('Unknown', 2), + wbInteger('Trans Delta', itU8), // scaled 0..0,25 + wbInteger('Sun Glare', itU8), // scaled 0..1 + wbInteger('Sun Damage', itU8), // scaled 0..1 + wbInteger('Precipitation - Begin Fade In', itU8), // scaled 0..1 + wbInteger('Precipitation - End Fade Out', itU8), // scaled 0..1 + wbInteger('Thunder/Lightning - Begin Fade In', itU8), + wbInteger('Thunder/Lightning - End Fade Out', itU8), + wbInteger('Thunder/Lightning - Frequency', itU8), + wbInteger('Flags', itU8, wbFlags([ + {0x01} 'Weather - Pleasant', + {0x02} 'Weather - Cloudy', + {0x04} 'Weather - Rainy', + {0x08} 'Weather - Snow', + {0x10} 'Sky Statics - Always Visible', + {0x20} 'Sky Statics - Follows Sun Position' + ])), + wbStruct('Lightning Color', [ + wbInteger('Red', itU8), + wbInteger('Green', itU8), + wbInteger('Blue', itU8) + ]).SetToStr(wbRGBAToStr).IncludeFlag(dfCollapsed, wbCollapseRGBA), + wbInteger('Visual Effect - Begin', itU8), // scaled 0..1 + wbInteger('Visual Effect - End', itU8), // scaled 0..1 + wbInteger('Wind Direction', itU8), // scaled 0..360 + wbInteger('Wind Direction Range', itU8) // scaled 0..180 + ], cpNormal, True), + wbInteger(NAM1, 'Disabled Cloud Layers', itU32, wbFlags(['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31'])), + wbWeatherSounds, + wbRArrayS('Sky Statics', wbFormIDCk(TNAM, 'Static', [STAT, NULL])), + wbStruct(IMSP, 'Image Spaces', [ + wbFormIDCK('Sunrise', [IMGS, NULL]), + wbFormIDCK('Day', [IMGS, NULL]), + wbFormIDCK('Sunset', [IMGS, NULL]), + wbFormIDCK('Night', [IMGS, NULL]) + ]), + // SSE + wbStruct(HNAM, 'Volumetric Lighting', [ + wbFormIDCK('Sunrise', [VOLI, NULL]), + wbFormIDCK('Day', [VOLI, NULL]), + wbFormIDCK('Sunset', [VOLI, NULL]), + wbFormIDCK('Night', [VOLI, NULL]) + ]), + wbRStruct('Directional Ambient Lighting Colors', [ + wbAmbientColors(DALC, 'Sunrise'), + wbAmbientColors(DALC, 'Day'), + wbAmbientColors(DALC, 'Sunset'), + wbAmbientColors(DALC, 'Night') + ], [], cpNormal, True), + wbByteArray(NAM2, 'Unused', 0, cpIgnore), + wbByteArray(NAM3, 'Unused', 0, cpIgnore), + wbRStruct('Aurora', [wbGenericModel], []), + wbFormIDCk(GNAM, 'Sun Glare Lens Flare', [LENS]) + ]); + + if IsSSE then begin + wbRecord(VOLI, 'Volumetric Lighting', [ + wbEDID, + wbFloat(CNAM, 'Intensity'), + wbFloat(DNAM, 'Custom Color - Contribution'), + wbFloat(ENAM, 'Red', cpNormal, False, 255, 0), + wbFloat(FNAM, 'Green', cpNormal, False, 255, 0), + wbFloat(GNAM, 'Blue', cpNormal, False, 255, 0), + wbFloat(HNAM, 'Density - Contribution'), + wbFloat(INAM, 'Density - Size'), + wbFloat(JNAM, 'Density - Wind Speed'), + wbFloat(KNAM, 'Density - Falling Speed'), + wbFloat(LNAM, 'Phase Function - Contribution'), + wbFloat(MNAM, 'Phase Function - Scattering'), + wbFloat(NNAM, 'Sampling Repartition - Range Factor') { max 1.0 } + ]); + + wbRecord(LENS, 'Lens Flare', [ + wbEDID, + wbFloat(CNAM, 'Color Influence'), + wbFloat(DNAM, 'Fade Distance Radius Scale'), + wbInteger(LFSP, 'Count', itU32, nil, cpBenign), + wbRArray('Lens Flare Sprites', + wbRStruct('Flare', [ + wbString(DNAM, 'Lens Flare Sprite ID'), + wbString(FNAM, 'Texture'), + wbStruct(LFSD, 'Lens Flare Data', [ + wbFloatColors('Tint'), + wbFloat('Width'), + wbFloat('Height'), + wbFloat('Position'), + wbFloat('Angular Fade'), + wbFloat('Opacity'), + wbInteger('Flags', itU32, wbFlags([ + {0x01} 'Rotates', + {0x02} 'Shrinks When Occluded' + ])) + ]) + ], []), + cpNormal, False, nil, wbLENSAfterSet + ) + ]); + + end; +end; + +{>>> Unused records, they have empty GRUP in skyrim.esm <<<} +procedure DefineTES5p; +var + wbStaticPart: IwbRecordMemberDef; +begin + wbRecord(CLDC, 'CLDC', [ + wbEDID + ]); + wbRecord(HAIR, 'HAIR', [ + wbEDID + ]); + wbRecord(PWAT, 'PWAT', [ + wbEDID + ]); + wbRecord(RGDL, 'RGDL', [ + wbEDID + ]); + { + wbRecord(SCOL, 'SCOL', [ + wbEDID + ]); + } + + wbStaticPart := + wbRStruct('Part', [ + wbFormIDCk(ONAM, 'Static', [STAT]), + wbArrayS(DATA, 'Placements', wbStruct('Placement', [ + wbStruct('Position', [ + wbFloat('X'), + wbFloat('Y'), + wbFloat('Z') + ]), + wbStruct('Rotation', [ + wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), + wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), + wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) + ]), + wbFloat('Scale') + ]), 0, cpNormal, True) + ], [], cpNormal, True); + + wbRecord(SCOL, 'Static Collection', [ + wbEDID, + wbOBND(True), + wbGenericModel(True), + wbRArray('Parts', wbStaticPart) + ]); + + wbRecord(SCPT, 'SCPT', [ + wbEDID + ]); +end; + +procedure DefineTES5q; +begin + wbAddGroupOrder(GMST); + wbAddGroupOrder(KYWD); + wbAddGroupOrder(LCRT); + wbAddGroupOrder(AACT); + wbAddGroupOrder(TXST); + wbAddGroupOrder(GLOB); + wbAddGroupOrder(CLAS); + wbAddGroupOrder(FACT); + wbAddGroupOrder(HDPT); + wbAddGroupOrder(HAIR);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} + wbAddGroupOrder(EYES); + wbAddGroupOrder(RACE); + wbAddGroupOrder(SOUN); + wbAddGroupOrder(ASPC); + wbAddGroupOrder(MGEF); + wbAddGroupOrder(SCPT);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} + wbAddGroupOrder(LTEX); + wbAddGroupOrder(ENCH); + wbAddGroupOrder(SPEL); + wbAddGroupOrder(SCRL); + wbAddGroupOrder(ACTI); + wbAddGroupOrder(TACT); + wbAddGroupOrder(ARMO); + wbAddGroupOrder(BOOK); + wbAddGroupOrder(CONT); + wbAddGroupOrder(DOOR); + wbAddGroupOrder(INGR); + wbAddGroupOrder(LIGH); + wbAddGroupOrder(MISC); + wbAddGroupOrder(APPA); + wbAddGroupOrder(STAT); + wbAddGroupOrder(SCOL);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} + wbAddGroupOrder(MSTT); + wbAddGroupOrder(PWAT);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} + wbAddGroupOrder(GRAS); + wbAddGroupOrder(TREE); + wbAddGroupOrder(CLDC);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} + wbAddGroupOrder(FLOR); + wbAddGroupOrder(FURN); + wbAddGroupOrder(WEAP); + wbAddGroupOrder(AMMO); + wbAddGroupOrder(NPC_); + wbAddGroupOrder(PLYR); + wbAddGroupOrder(LVLN); + wbAddGroupOrder(KEYM); + wbAddGroupOrder(ALCH); + wbAddGroupOrder(IDLM); + wbAddGroupOrder(COBJ); + wbAddGroupOrder(PROJ); + wbAddGroupOrder(HAZD); + wbAddGroupOrder(SLGM); + wbAddGroupOrder(LVLI); + wbAddGroupOrder(WTHR); + wbAddGroupOrder(CLMT); + wbAddGroupOrder(SPGD); + wbAddGroupOrder(RFCT); + wbAddGroupOrder(REGN); + wbAddGroupOrder(NAVI); + wbAddGroupOrder(CELL); + wbAddGroupOrder(WRLD); + wbAddGroupOrder(DIAL); + wbAddGroupOrder(QUST); + wbAddGroupOrder(IDLE); + wbAddGroupOrder(PACK); + wbAddGroupOrder(CSTY); + wbAddGroupOrder(LSCR); + wbAddGroupOrder(LVSP); + wbAddGroupOrder(ANIO); + wbAddGroupOrder(WATR); + wbAddGroupOrder(EFSH); + wbAddGroupOrder(EXPL); + wbAddGroupOrder(DEBR); + wbAddGroupOrder(IMGS); + wbAddGroupOrder(IMAD); + wbAddGroupOrder(FLST); + wbAddGroupOrder(PERK); + wbAddGroupOrder(BPTD); + wbAddGroupOrder(ADDN); + wbAddGroupOrder(AVIF); + wbAddGroupOrder(CAMS); + wbAddGroupOrder(CPTH); + wbAddGroupOrder(VTYP); + wbAddGroupOrder(MATT); + wbAddGroupOrder(IPCT); + wbAddGroupOrder(IPDS); + wbAddGroupOrder(ARMA); + wbAddGroupOrder(ECZN); + wbAddGroupOrder(LCTN); + wbAddGroupOrder(MESG); + wbAddGroupOrder(RGDL);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} + wbAddGroupOrder(DOBJ); + wbAddGroupOrder(LGTM); + wbAddGroupOrder(MUSC); + wbAddGroupOrder(FSTP); + wbAddGroupOrder(FSTS); + wbAddGroupOrder(SMBN); + wbAddGroupOrder(SMQN); + wbAddGroupOrder(SMEN); + wbAddGroupOrder(DLBR); + wbAddGroupOrder(MUST); + wbAddGroupOrder(DLVW); + wbAddGroupOrder(WOOP); + wbAddGroupOrder(SHOU); + wbAddGroupOrder(EQUP); + wbAddGroupOrder(RELA); + wbAddGroupOrder(SCEN); + wbAddGroupOrder(ASTP); + wbAddGroupOrder(OTFT); + wbAddGroupOrder(ARTO); + wbAddGroupOrder(MATO); + if IsSSE then wbAddGroupOrder(VOLI); {New to SSE} + wbAddGroupOrder(MOVT); + wbAddGroupOrder(SNDR); + wbAddGroupOrder(DUAL); + wbAddGroupOrder(SNCT); + wbAddGroupOrder(SOPM); + wbAddGroupOrder(COLL); + wbAddGroupOrder(CLFM); + wbAddGroupOrder(REVB); + if IsSSE then wbAddGroupOrder(LENS); {New to SSE} +end; + +procedure DefineTES5; +begin + if IsSSE then begin + wbNexusModsUrl := 'https://www.nexusmods.com/skyrimspecialedition/mods/164'; + if wbToolMode = tmLODgen then + wbNexusModsUrl := 'https://www.nexusmods.com/skyrimspecialedition/mods/6642'; + end else begin + wbNexusModsUrl := 'https://www.nexusmods.com/skyrim/mods/25859'; + if wbToolMode = tmLODgen then + wbNexusModsUrl := 'https://www.nexusmods.com/skyrim/mods/62698'; + end; + + case wbGameMode of + gmEnderal: wbNexusModsUrl := 'https://www.nexusmods.com/enderal/mods/23'; + gmEnderalSE: wbNexusModsUrl := 'https://www.nexusmods.com/enderalspecialedition/mods/78'; + end; + + DefineTES5a; + DefineTES5b; + DefineTES5c; + DefineTES5d; + DefineTES5e; + DefineTES5f; + DefineTES5g; + DefineTES5h; + DefineTES5i; + DefineTES5j; + DefineTES5k; + DefineTES5l; + DefineTES5m; + DefineTES5n; + DefineTES5o; + DefineTES5p; + DefineTES5q; + + if IsSSE then begin + SetLength(wbOfficialDLC, 3); + wbOfficialDLC[0] := 'Dawnguard.esm'; + wbOfficialDLC[1] := 'HearthFires.esm'; + wbOfficialDLC[2] := 'Dragonborn.esm'; + + if wbGameMode = gmTES5VR then begin + // new VR esm is loaded after DLCs + SetLength(wbOfficialDLC, Succ(Length(wbOfficialDLC))); + wbOfficialDLC[Pred(Length(wbOfficialDLC))] := 'SkyrimVR.esm'; + end else + wbCreationClubContentFileName := 'Skyrim.ccc'; + + end; + + wbHEDRVersion := 1.7; +end; + +initialization +end.