Merge branch 'esm4' into 'master'

ESM4 Support

See merge request OpenMW/openmw!1610
C++20
psi29a 3 years ago
commit 3af037d2ae

@ -76,7 +76,7 @@ add_component_dir (to_utf8
to_utf8
)
add_component_dir(esm attr defs esmcommon records util luascripts)
add_component_dir(esm attr common defs esmcommon reader records util luascripts)
add_component_dir (esm3
esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell
@ -94,6 +94,16 @@ add_component_dir (esm3terrain
storage
)
add_component_dir (esm4
loadachr loadacre loadacti loadalch loadaloc loadammo loadanio loadappa loadarma loadarmo loadaspc loadbook
loadbptd loadcell loadclas loadclfm loadclot common loadcont loadcrea loaddial loaddobj loaddoor loadeyes
loadflor loadflst formid loadfurn loadglob loadgras loadhair loadhdpt loadidle loadidlm loadimod loadinfo
loadingr loadkeym loadland loadlgtm loadligh loadltex loadlvlc loadlvli loadlvln loadmato loadmisc loadmset
loadmstt loadmusc loadnavi loadnavm loadnote loadnpc loadotft loadpack loadpgrd loadpgre loadpwat loadqust
loadrace loadrefr loadregn loadroad loadsbsp loadscol loadscpt loadscrl loadsgst loadslgm loadsndr
loadsoun loadstat loadtact loadterm loadtes4 loadtree loadtxst loadweap loadwrld reader
)
add_component_dir (misc
constants utf8stream stringops resourcehelpers rng messageformatparser weakcache thread
compression osguservalues errorMarker color

@ -0,0 +1,15 @@
#include "sstream"
namespace ESM
{
std::string printName(const std::uint32_t typeId)
{
unsigned char typeName[4];
typeName[0] = typeId & 0xff;
typeName[1] = (typeId >> 8) & 0xff;
typeName[2] = (typeId >> 16) & 0xff;
typeName[3] = (typeId >> 24) & 0xff;
return std::string((char*)typeName, 4);
}
}

@ -0,0 +1,57 @@
#ifndef COMPONENT_ESM_COMMON_H
#define COMPONENT_ESM_COMMON_H
#include <cstdint>
#include <string>
namespace ESM
{
#pragma pack(push, 1)
union ESMVersion
{
float f;
std::uint32_t ui;
};
union TypeId
{
std::uint32_t value;
char name[4]; // record type in ascii
};
#pragma pack(pop)
enum ESMVersions
{
VER_120 = 0x3f99999a, // TES3
VER_130 = 0x3fa66666, // TES3
VER_080 = 0x3f4ccccd, // TES4
VER_100 = 0x3f800000, // TES4
VER_132 = 0x3fa8f5c3, // FONV Courier's Stash, DeadMoney
VER_133 = 0x3faa3d71, // FONV HonestHearts
VER_134 = 0x3fab851f, // FONV, GunRunnersArsenal, LonesomeRoad, OldWorldBlues
VER_094 = 0x3f70a3d7, // TES5/FO3
VER_170 = 0x3fd9999a // TES5
};
// Defines another files (esm or esp) that this file depends upon.
struct MasterData
{
std::string name;
std::uint64_t size;
};
enum VarType
{
VT_Unknown = 0,
VT_None,
VT_Short, // stored as a float, kinda
VT_Int,
VT_Long, // stored as a float
VT_Float,
VT_String
};
std::string printName(const std::uint32_t typeId);
}
#endif // COMPONENT_ESM_COMMON_H

@ -0,0 +1,86 @@
#include "reader.hpp"
//#ifdef NDEBUG
//#undef NDEBUG
//#endif
#include <cassert>
#include <stdexcept>
#include <components/files/constrainedfilestream.hpp>
#include "components/esm3/esmreader.hpp"
#include "components/esm4/reader.hpp"
namespace ESM
{
Reader* Reader::getReader(const std::string &filename)
{
Files::IStreamPtr esmStream(Files::openConstrainedFileStream (filename.c_str ()));
std::uint32_t modVer = 0; // get the first 4 bytes of the record header only
esmStream->read((char*)&modVer, sizeof(modVer));
if (esmStream->gcount() == sizeof(modVer))
{
esmStream->seekg(0);
if (modVer == ESM4::REC_TES4)
{
return new ESM4::Reader(esmStream, filename);
}
else
{
//return new ESM3::ESMReader(esmStream, filename);
}
}
throw std::runtime_error("Unknown file format");
}
bool Reader::getStringImpl(std::string& str, std::size_t size,
Files::IStreamPtr filestream, ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull)
{
std::size_t newSize = size;
if (encoder)
{
std::string input(size, '\0');
filestream->read(input.data(), size);
if (filestream->gcount() == static_cast<std::streamsize>(size))
{
encoder->getUtf8(input, ToUTF8::BufferAllocationPolicy::FitToRequiredSize, str);
return true;
}
}
else
{
if (hasNull)
newSize -= 1; // don't read the null terminator yet
str.resize(newSize); // assumed C++11
filestream->read(&str[0], newSize);
if ((std::size_t)filestream->gcount() == newSize)
{
if (hasNull)
{
char ch;
filestream->read(&ch, 1); // read the null terminator
assert (ch == '\0'
&& "ESM4::Reader::getString string is not terminated with a null");
}
#if 0
else
{
// NOTE: normal ESMs don't but omwsave has locals or spells with null terminator
assert (str[newSize - 1] != '\0'
&& "ESM4::Reader::getString string is unexpectedly terminated with a null");
}
#endif
return true;
}
}
str.clear();
return false; // FIXME: throw instead?
}
}

@ -0,0 +1,60 @@
#ifndef COMPONENT_ESM_READER_H
#define COMPONENT_ESM_READER_H
#include <vector>
#include <components/files/constrainedfilestream.hpp>
#include <components/to_utf8/to_utf8.hpp>
#include "common.hpp" // MasterData
namespace ToUTF8
{
class Utf8Encoder;
}
namespace ESM
{
class Reader
{
std::vector<Reader*>* mGlobalReaderList;
public:
virtual ~Reader() {}
static Reader* getReader(const std::string& filename);
void setGlobalReaderList(std::vector<Reader*> *list) {mGlobalReaderList = list;}
std::vector<Reader*> *getGlobalReaderList() {return mGlobalReaderList;}
virtual inline bool isEsm4() const = 0;
virtual inline bool hasMoreRecs() const = 0;
virtual inline void setEncoder(ToUTF8::StatelessUtf8Encoder* encoder) = 0;
// used to check for dependencies e.g. CS::Editor::run()
virtual inline const std::vector<ESM::MasterData>& getGameFiles() const = 0;
// used by ContentSelector::ContentModel::addFiles()
virtual inline const std::string getAuthor() const = 0;
virtual inline const std::string getDesc() const = 0;
virtual inline int getFormat() const = 0;
virtual inline std::string getFileName() const = 0;
// used by CSMWorld::Data::startLoading() and getTotalRecords() for loading progress bar
virtual inline int getRecordCount() const = 0;
virtual void setModIndex(std::uint32_t index) = 0;
// used by CSMWorld::Data::getTotalRecords()
virtual void close() = 0;
protected:
bool getStringImpl(std::string& str, std::size_t size,
Files::IStreamPtr filestream, ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull = false);
};
}
#endif // COMPONENT_ESM_READER_H

@ -0,0 +1,70 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_ACTI_H
#define ESM4_ACTI_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Activator
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
FormId mScriptId;
FormId mLoopingSound; // SOUN
FormId mActivationSound; // SOUN
float mBoundRadius;
FormId mRadioTemplate; // SOUN
FormId mRadioStation; // TACT
std::string mActivationPrompt;
Activator();
virtual ~Activator();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_ACTI_H

@ -0,0 +1,163 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_ACTOR_H
#define ESM4_ACTOR_H
#include <cstdint>
#include "formid.hpp"
namespace ESM4
{
#pragma pack(push, 1)
struct AIData // NPC_, CREA
{
std::uint8_t aggression;
std::uint8_t confidence;
std::uint8_t energyLevel;
std::uint8_t responsibility;
std::uint32_t aiFlags;
std::uint8_t trainSkill;
std::uint8_t trainLevel;
std::uint16_t unknown;
};
struct AttributeValues
{
std::uint8_t strength;
std::uint8_t intelligence;
std::uint8_t willpower;
std::uint8_t agility;
std::uint8_t speed;
std::uint8_t endurance;
std::uint8_t personality;
std::uint8_t luck;
};
struct ACBS_TES4
{
std::uint32_t flags;
std::uint16_t baseSpell;
std::uint16_t fatigue;
std::uint16_t barterGold;
std::int16_t levelOrOffset;
std::uint16_t calcMin;
std::uint16_t calcMax;
std::uint32_t padding1;
std::uint32_t padding2;
};
struct ACBS_FO3
{
std::uint32_t flags;
std::uint16_t fatigue;
std::uint16_t barterGold;
std::int16_t levelOrMult;
std::uint16_t calcMinlevel;
std::uint16_t calcMaxlevel;
std::uint16_t speedMultiplier;
float karma;
std::int16_t dispositionBase;
std::uint16_t templateFlags;
};
struct ACBS_TES5
{
std::uint32_t flags;
std::uint16_t magickaOffset;
std::uint16_t staminaOffset;
std::uint16_t levelOrMult; // TODO: check if int16_t
std::uint16_t calcMinlevel;
std::uint16_t calcMaxlevel;
std::uint16_t speedMultiplier;
std::uint16_t dispositionBase; // TODO: check if int16_t
std::uint16_t templateFlags;
std::uint16_t healthOffset;
std::uint16_t bleedoutOverride;
};
union ActorBaseConfig
{
ACBS_TES4 tes4;
ACBS_FO3 fo3;
ACBS_TES5 tes5;
};
struct ActorFaction
{
FormId faction;
std::int8_t rank;
std::uint8_t unknown1;
std::uint8_t unknown2;
std::uint8_t unknown3;
};
#pragma pack(pop)
struct BodyTemplate // TES5
{
// 0x00000001 - Head
// 0x00000002 - Hair
// 0x00000004 - Body
// 0x00000008 - Hands
// 0x00000010 - Forearms
// 0x00000020 - Amulet
// 0x00000040 - Ring
// 0x00000080 - Feet
// 0x00000100 - Calves
// 0x00000200 - Shield
// 0x00000400 - Tail
// 0x00000800 - Long Hair
// 0x00001000 - Circlet
// 0x00002000 - Ears
// 0x00004000 - Body AddOn 3
// 0x00008000 - Body AddOn 4
// 0x00010000 - Body AddOn 5
// 0x00020000 - Body AddOn 6
// 0x00040000 - Body AddOn 7
// 0x00080000 - Body AddOn 8
// 0x00100000 - Decapitate Head
// 0x00200000 - Decapitate
// 0x00400000 - Body AddOn 9
// 0x00800000 - Body AddOn 10
// 0x01000000 - Body AddOn 11
// 0x02000000 - Body AddOn 12
// 0x04000000 - Body AddOn 13
// 0x08000000 - Body AddOn 14
// 0x10000000 - Body AddOn 15
// 0x20000000 - Body AddOn 16
// 0x40000000 - Body AddOn 17
// 0x80000000 - FX01
std::uint32_t bodyPart;
std::uint8_t flags;
std::uint8_t unknown1; // probably padding
std::uint8_t unknown2; // probably padding
std::uint8_t unknown3; // probably padding
std::uint32_t type; // 0 = light, 1 = heavy, 2 = none (cloth?)
};
}
#endif // ESM4_ACTOR_H

@ -0,0 +1,100 @@
/*
Copyright (C) 2015-2016, 2018, 2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "common.hpp"
#include <sstream>
#include <algorithm>
#include <stdexcept>
#include <string>
#include "formid.hpp"
namespace ESM4
{
const char *sGroupType[] =
{
"Record Type", "World Child", "Interior Cell", "Interior Sub Cell", "Exterior Cell",
"Exterior Sub Cell", "Cell Child", "Topic Child", "Cell Persistent Child",
"Cell Temporary Child", "Cell Visible Dist Child", "Unknown"
};
std::string printLabel(const GroupLabel& label, const std::uint32_t type)
{
std::ostringstream ss;
ss << std::string(sGroupType[std::min(type, (uint32_t)11)]); // avoid out of range
switch (type)
{
case ESM4::Grp_RecordType:
{
ss << ": " << std::string((char*)label.recordType, 4);
break;
}
case ESM4::Grp_ExteriorCell:
case ESM4::Grp_ExteriorSubCell:
{
//short x, y;
//y = label & 0xff;
//x = (label >> 16) & 0xff;
ss << ": grid (x, y) " << std::dec << label.grid[1] << ", " << label.grid[0];
break;
}
case ESM4::Grp_InteriorCell:
case ESM4::Grp_InteriorSubCell:
{
ss << ": block 0x" << std::hex << label.value;
break;
}
case ESM4::Grp_WorldChild:
case ESM4::Grp_CellChild:
case ESM4::Grp_TopicChild:
case ESM4::Grp_CellPersistentChild:
case ESM4::Grp_CellTemporaryChild:
case ESM4::Grp_CellVisibleDistChild:
{
ss << ": FormId 0x" << formIdToString(label.value);
break;
}
default:
break;
}
return ss.str();
}
void gridToString(std::int16_t x, std::int16_t y, std::string& str)
{
char buf[6+6+2+1]; // longest signed 16 bit number is 6 characters (-32768)
int res = snprintf(buf, 6+6+2+1, "#%d %d", x, y);
if (res > 0 && res < 6+6+2+1)
str.assign(buf);
else
throw std::runtime_error("possible buffer overflow while converting grid");
}
}

@ -0,0 +1,939 @@
/*
Copyright (C) 2015-2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
MKTAG macro was adapated from ScummVM.
*/
#ifndef ESM4_COMMON_H
#define ESM4_COMMON_H
#include <cstdint>
#include <string>
#include "formid.hpp"
// From ScummVM's endianness.h but for little endian
#ifndef MKTAG
#define MKTAG(a0,a1,a2,a3) ((std::uint32_t)((a0) | ((a1) << 8) | ((a2) << 16) | ((a3) << 24)))
#endif
namespace ESM4
{
// Based on http://www.uesp.net/wiki/Tes5Mod:Mod_File_Format
enum RecordTypes
{
REC_AACT = MKTAG('A','A','C','T'), // Action
REC_ACHR = MKTAG('A','C','H','R'), // Actor Reference
REC_ACTI = MKTAG('A','C','T','I'), // Activator
REC_ADDN = MKTAG('A','D','D','N'), // Addon Node
REC_ALCH = MKTAG('A','L','C','H'), // Potion
REC_AMMO = MKTAG('A','M','M','O'), // Ammo
REC_ANIO = MKTAG('A','N','I','O'), // Animated Object
REC_APPA = MKTAG('A','P','P','A'), // Apparatus (probably unused)
REC_ARMA = MKTAG('A','R','M','A'), // Armature (Model)
REC_ARMO = MKTAG('A','R','M','O'), // Armor
REC_ARTO = MKTAG('A','R','T','O'), // Art Object
REC_ASPC = MKTAG('A','S','P','C'), // Acoustic Space
REC_ASTP = MKTAG('A','S','T','P'), // Association Type
REC_AVIF = MKTAG('A','V','I','F'), // Actor Values/Perk Tree Graphics
REC_BOOK = MKTAG('B','O','O','K'), // Book
REC_BPTD = MKTAG('B','P','T','D'), // Body Part Data
REC_CAMS = MKTAG('C','A','M','S'), // Camera Shot
REC_CELL = MKTAG('C','E','L','L'), // Cell
REC_CLAS = MKTAG('C','L','A','S'), // Class
REC_CLFM = MKTAG('C','L','F','M'), // Color
REC_CLMT = MKTAG('C','L','M','T'), // Climate
REC_CLOT = MKTAG('C','L','O','T'), // Clothing
REC_COBJ = MKTAG('C','O','B','J'), // Constructible Object (recipes)
REC_COLL = MKTAG('C','O','L','L'), // Collision Layer
REC_CONT = MKTAG('C','O','N','T'), // Container
REC_CPTH = MKTAG('C','P','T','H'), // Camera Path
REC_CREA = MKTAG('C','R','E','A'), // Creature
REC_CSTY = MKTAG('C','S','T','Y'), // Combat Style
REC_DEBR = MKTAG('D','E','B','R'), // Debris
REC_DIAL = MKTAG('D','I','A','L'), // Dialog Topic
REC_DLBR = MKTAG('D','L','B','R'), // Dialog Branch
REC_DLVW = MKTAG('D','L','V','W'), // Dialog View
REC_DOBJ = MKTAG('D','O','B','J'), // Default Object Manager
REC_DOOR = MKTAG('D','O','O','R'), // Door
REC_DUAL = MKTAG('D','U','A','L'), // Dual Cast Data (possibly unused)
//REC_ECZN = MKTAG('E','C','Z','N'), // Encounter Zone
REC_EFSH = MKTAG('E','F','S','H'), // Effect Shader
REC_ENCH = MKTAG('E','N','C','H'), // Enchantment
REC_EQUP = MKTAG('E','Q','U','P'), // Equip Slot (flag-type values)
REC_EXPL = MKTAG('E','X','P','L'), // Explosion
REC_EYES = MKTAG('E','Y','E','S'), // Eyes
REC_FACT = MKTAG('F','A','C','T'), // Faction
REC_FLOR = MKTAG('F','L','O','R'), // Flora
REC_FLST = MKTAG('F','L','S','T'), // Form List (non-levelled list)
REC_FSTP = MKTAG('F','S','T','P'), // Footstep
REC_FSTS = MKTAG('F','S','T','S'), // Footstep Set
REC_FURN = MKTAG('F','U','R','N'), // Furniture
REC_GLOB = MKTAG('G','L','O','B'), // Global Variable
REC_GMST = MKTAG('G','M','S','T'), // Game Setting
REC_GRAS = MKTAG('G','R','A','S'), // Grass
REC_GRUP = MKTAG('G','R','U','P'), // Form Group
REC_HAIR = MKTAG('H','A','I','R'), // Hair
//REC_HAZD = MKTAG('H','A','Z','D'), // Hazard
REC_HDPT = MKTAG('H','D','P','T'), // Head Part
REC_IDLE = MKTAG('I','D','L','E'), // Idle Animation
REC_IDLM = MKTAG('I','D','L','M'), // Idle Marker
REC_IMAD = MKTAG('I','M','A','D'), // Image Space Modifier
REC_IMGS = MKTAG('I','M','G','S'), // Image Space
REC_INFO = MKTAG('I','N','F','O'), // Dialog Topic Info
REC_INGR = MKTAG('I','N','G','R'), // Ingredient
REC_IPCT = MKTAG('I','P','C','T'), // Impact Data
REC_IPDS = MKTAG('I','P','D','S'), // Impact Data Set
REC_KEYM = MKTAG('K','E','Y','M'), // Key
REC_KYWD = MKTAG('K','Y','W','D'), // Keyword
REC_LAND = MKTAG('L','A','N','D'), // Land
REC_LCRT = MKTAG('L','C','R','T'), // Location Reference Type
REC_LCTN = MKTAG('L','C','T','N'), // Location
REC_LGTM = MKTAG('L','G','T','M'), // Lighting Template
REC_LIGH = MKTAG('L','I','G','H'), // Light
REC_LSCR = MKTAG('L','S','C','R'), // Load Screen
REC_LTEX = MKTAG('L','T','E','X'), // Land Texture
REC_LVLC = MKTAG('L','V','L','C'), // Leveled Creature
REC_LVLI = MKTAG('L','V','L','I'), // Leveled Item
REC_LVLN = MKTAG('L','V','L','N'), // Leveled Actor
REC_LVSP = MKTAG('L','V','S','P'), // Leveled Spell
REC_MATO = MKTAG('M','A','T','O'), // Material Object
REC_MATT = MKTAG('M','A','T','T'), // Material Type
REC_MESG = MKTAG('M','E','S','G'), // Message
REC_MGEF = MKTAG('M','G','E','F'), // Magic Effect
REC_MISC = MKTAG('M','I','S','C'), // Misc. Object
REC_MOVT = MKTAG('M','O','V','T'), // Movement Type
REC_MSTT = MKTAG('M','S','T','T'), // Movable Static
REC_MUSC = MKTAG('M','U','S','C'), // Music Type
REC_MUST = MKTAG('M','U','S','T'), // Music Track
REC_NAVI = MKTAG('N','A','V','I'), // Navigation (master data)
REC_NAVM = MKTAG('N','A','V','M'), // Nav Mesh
REC_NOTE = MKTAG('N','O','T','E'), // Note
REC_NPC_ = MKTAG('N','P','C','_'), // Actor (NPC, Creature)
REC_OTFT = MKTAG('O','T','F','T'), // Outfit
REC_PACK = MKTAG('P','A','C','K'), // AI Package
REC_PERK = MKTAG('P','E','R','K'), // Perk
REC_PGRE = MKTAG('P','G','R','E'), // Placed grenade
REC_PHZD = MKTAG('P','H','Z','D'), // Placed hazard
REC_PROJ = MKTAG('P','R','O','J'), // Projectile
REC_QUST = MKTAG('Q','U','S','T'), // Quest
REC_RACE = MKTAG('R','A','C','E'), // Race / Creature type
REC_REFR = MKTAG('R','E','F','R'), // Object Reference
REC_REGN = MKTAG('R','E','G','N'), // Region (Audio/Weather)
REC_RELA = MKTAG('R','E','L','A'), // Relationship
REC_REVB = MKTAG('R','E','V','B'), // Reverb Parameters
REC_RFCT = MKTAG('R','F','C','T'), // Visual Effect
REC_SBSP = MKTAG('S','B','S','P'), // Subspace (TES4 only?)
REC_SCEN = MKTAG('S','C','E','N'), // Scene
REC_SCPT = MKTAG('S','C','P','T'), // Script
REC_SCRL = MKTAG('S','C','R','L'), // Scroll
REC_SGST = MKTAG('S','G','S','T'), // Sigil Stone
REC_SHOU = MKTAG('S','H','O','U'), // Shout
REC_SLGM = MKTAG('S','L','G','M'), // Soul Gem
REC_SMBN = MKTAG('S','M','B','N'), // Story Manager Branch Node
REC_SMEN = MKTAG('S','M','E','N'), // Story Manager Event Node
REC_SMQN = MKTAG('S','M','Q','N'), // Story Manager Quest Node
REC_SNCT = MKTAG('S','N','C','T'), // Sound Category
REC_SNDR = MKTAG('S','N','D','R'), // Sound Reference
REC_SOPM = MKTAG('S','O','P','M'), // Sound Output Model
REC_SOUN = MKTAG('S','O','U','N'), // Sound
REC_SPEL = MKTAG('S','P','E','L'), // Spell
REC_SPGD = MKTAG('S','P','G','D'), // Shader Particle Geometry
REC_STAT = MKTAG('S','T','A','T'), // Static
REC_TACT = MKTAG('T','A','C','T'), // Talking Activator
REC_TERM = MKTAG('T','E','R','M'), // Terminal
REC_TES4 = MKTAG('T','E','S','4'), // Plugin info
REC_TREE = MKTAG('T','R','E','E'), // Tree
REC_TXST = MKTAG('T','X','S','T'), // Texture Set
REC_VTYP = MKTAG('V','T','Y','P'), // Voice Type
REC_WATR = MKTAG('W','A','T','R'), // Water Type
REC_WEAP = MKTAG('W','E','A','P'), // Weapon
REC_WOOP = MKTAG('W','O','O','P'), // Word Of Power
REC_WRLD = MKTAG('W','R','L','D'), // World Space
REC_WTHR = MKTAG('W','T','H','R'), // Weather
REC_ACRE = MKTAG('A','C','R','E'), // Placed Creature (TES4 only?)
REC_PGRD = MKTAG('P','G','R','D'), // Pathgrid (TES4 only?)
REC_ROAD = MKTAG('R','O','A','D'), // Road (TES4 only?)
REC_IMOD = MKTAG('I','M','O','D'), // Item Mod
REC_PWAT = MKTAG('P','W','A','T'), // Placeable Water
REC_SCOL = MKTAG('S','C','O','L'), // Static Collection
REC_CCRD = MKTAG('C','C','R','D'), // Caravan Card
REC_CMNY = MKTAG('C','M','N','Y'), // Caravan Money
REC_ALOC = MKTAG('A','L','O','C'), // Audio Location Controller
REC_MSET = MKTAG('M','S','E','T') // Media Set
};
enum SubRecordTypes
{
SUB_HEDR = MKTAG('H','E','D','R'),
SUB_CNAM = MKTAG('C','N','A','M'),
SUB_SNAM = MKTAG('S','N','A','M'), // TES4 only?
SUB_MAST = MKTAG('M','A','S','T'),
SUB_DATA = MKTAG('D','A','T','A'),
SUB_ONAM = MKTAG('O','N','A','M'),
SUB_INTV = MKTAG('I','N','T','V'),
SUB_INCC = MKTAG('I','N','C','C'),
SUB_OFST = MKTAG('O','F','S','T'), // TES4 only?
SUB_DELE = MKTAG('D','E','L','E'), // TES4 only?
SUB_DNAM = MKTAG('D','N','A','M'),
SUB_EDID = MKTAG('E','D','I','D'),
SUB_FULL = MKTAG('F','U','L','L'),
SUB_LTMP = MKTAG('L','T','M','P'),
SUB_MHDT = MKTAG('M','H','D','T'),
SUB_MNAM = MKTAG('M','N','A','M'),
SUB_MODL = MKTAG('M','O','D','L'),
SUB_NAM0 = MKTAG('N','A','M','0'),
SUB_NAM2 = MKTAG('N','A','M','2'),
SUB_NAM3 = MKTAG('N','A','M','3'),
SUB_NAM4 = MKTAG('N','A','M','4'),
SUB_NAM9 = MKTAG('N','A','M','9'),
SUB_NAMA = MKTAG('N','A','M','A'),
SUB_PNAM = MKTAG('P','N','A','M'),
SUB_RNAM = MKTAG('R','N','A','M'),
SUB_TNAM = MKTAG('T','N','A','M'),
SUB_UNAM = MKTAG('U','N','A','M'),
SUB_WCTR = MKTAG('W','C','T','R'),
SUB_WNAM = MKTAG('W','N','A','M'),
SUB_XEZN = MKTAG('X','E','Z','N'),
SUB_XLCN = MKTAG('X','L','C','N'),
SUB_XXXX = MKTAG('X','X','X','X'),
SUB_ZNAM = MKTAG('Z','N','A','M'),
SUB_MODT = MKTAG('M','O','D','T'),
SUB_ICON = MKTAG('I','C','O','N'), // TES4 only?
SUB_NVER = MKTAG('N','V','E','R'),
SUB_NVMI = MKTAG('N','V','M','I'),
SUB_NVPP = MKTAG('N','V','P','P'),
SUB_NVSI = MKTAG('N','V','S','I'),
SUB_NVNM = MKTAG('N','V','N','M'),
SUB_NNAM = MKTAG('N','N','A','M'),
SUB_XCLC = MKTAG('X','C','L','C'),
SUB_XCLL = MKTAG('X','C','L','L'),
SUB_TVDT = MKTAG('T','V','D','T'),
SUB_XCGD = MKTAG('X','C','G','D'),
SUB_LNAM = MKTAG('L','N','A','M'),
SUB_XCLW = MKTAG('X','C','L','W'),
SUB_XNAM = MKTAG('X','N','A','M'),
SUB_XCLR = MKTAG('X','C','L','R'),
SUB_XWCS = MKTAG('X','W','C','S'),
SUB_XWCN = MKTAG('X','W','C','N'),
SUB_XWCU = MKTAG('X','W','C','U'),
SUB_XCWT = MKTAG('X','C','W','T'),
SUB_XOWN = MKTAG('X','O','W','N'),
SUB_XILL = MKTAG('X','I','L','L'),
SUB_XWEM = MKTAG('X','W','E','M'),
SUB_XCCM = MKTAG('X','C','C','M'),
SUB_XCAS = MKTAG('X','C','A','S'),
SUB_XCMO = MKTAG('X','C','M','O'),
SUB_XCIM = MKTAG('X','C','I','M'),
SUB_XCMT = MKTAG('X','C','M','T'), // TES4 only?
SUB_XRNK = MKTAG('X','R','N','K'), // TES4 only?
SUB_XGLB = MKTAG('X','G','L','B'), // TES4 only?
SUB_VNML = MKTAG('V','N','M','L'),
SUB_VHGT = MKTAG('V','H','G','T'),
SUB_VCLR = MKTAG('V','C','L','R'),
SUA_BTXT = MKTAG('B','T','X','T'),
SUB_ATXT = MKTAG('A','T','X','T'),
SUB_VTXT = MKTAG('V','T','X','T'),
SUB_VTEX = MKTAG('V','T','E','X'),
SUB_HNAM = MKTAG('H','N','A','M'),
SUB_GNAM = MKTAG('G','N','A','M'),
SUB_RCLR = MKTAG('R','C','L','R'),
SUB_RPLI = MKTAG('R','P','L','I'),
SUB_RPLD = MKTAG('R','P','L','D'),
SUB_RDAT = MKTAG('R','D','A','T'),
SUB_RDMD = MKTAG('R','D','M','D'), // TES4 only?
SUB_RDSD = MKTAG('R','D','S','D'), // TES4 only?
SUB_RDGS = MKTAG('R','D','G','S'), // TES4 only?
SUB_RDMO = MKTAG('R','D','M','O'),
SUB_RDSA = MKTAG('R','D','S','A'),
SUB_RDWT = MKTAG('R','D','W','T'),
SUB_RDOT = MKTAG('R','D','O','T'),
SUB_RDMP = MKTAG('R','D','M','P'),
SUB_MODB = MKTAG('M','O','D','B'),
SUB_OBND = MKTAG('O','B','N','D'),
SUB_MODS = MKTAG('M','O','D','S'),
SUB_NAME = MKTAG('N','A','M','E'),
SUB_XMRK = MKTAG('X','M','R','K'),
SUB_FNAM = MKTAG('F','N','A','M'),
SUB_XSCL = MKTAG('X','S','C','L'),
SUB_XTEL = MKTAG('X','T','E','L'),
SUB_XTRG = MKTAG('X','T','R','G'),
SUB_XSED = MKTAG('X','S','E','D'),
SUB_XLOD = MKTAG('X','L','O','D'),
SUB_XPCI = MKTAG('X','P','C','I'),
SUB_XLOC = MKTAG('X','L','O','C'),
SUB_XESP = MKTAG('X','E','S','P'),
SUB_XLCM = MKTAG('X','L','C','M'),
SUB_XRTM = MKTAG('X','R','T','M'),
SUB_XACT = MKTAG('X','A','C','T'),
SUB_XCNT = MKTAG('X','C','N','T'),
SUB_VMAD = MKTAG('V','M','A','D'),
SUB_XPRM = MKTAG('X','P','R','M'),
SUB_XMBO = MKTAG('X','M','B','O'),
SUB_XPOD = MKTAG('X','P','O','D'),
SUB_XRMR = MKTAG('X','R','M','R'),
SUB_INAM = MKTAG('I','N','A','M'),
SUB_SCHR = MKTAG('S','C','H','R'),
SUB_XLRM = MKTAG('X','L','R','M'),
SUB_XRGD = MKTAG('X','R','G','D'),
SUB_XRDS = MKTAG('X','R','D','S'),
SUB_XEMI = MKTAG('X','E','M','I'),
SUB_XLIG = MKTAG('X','L','I','G'),
SUB_XALP = MKTAG('X','A','L','P'),
SUB_XNDP = MKTAG('X','N','D','P'),
SUB_XAPD = MKTAG('X','A','P','D'),
SUB_XAPR = MKTAG('X','A','P','R'),
SUB_XLIB = MKTAG('X','L','I','B'),
SUB_XLKR = MKTAG('X','L','K','R'),
SUB_XLRT = MKTAG('X','L','R','T'),
SUB_XCVL = MKTAG('X','C','V','L'),
SUB_XCVR = MKTAG('X','C','V','R'),
SUB_XCZA = MKTAG('X','C','Z','A'),
SUB_XCZC = MKTAG('X','C','Z','C'),
SUB_XFVC = MKTAG('X','F','V','C'),
SUB_XHTW = MKTAG('X','H','T','W'),
SUB_XIS2 = MKTAG('X','I','S','2'),
SUB_XMBR = MKTAG('X','M','B','R'),
SUB_XCCP = MKTAG('X','C','C','P'),
SUB_XPWR = MKTAG('X','P','W','R'),
SUB_XTRI = MKTAG('X','T','R','I'),
SUB_XATR = MKTAG('X','A','T','R'),
SUB_XPRD = MKTAG('X','P','R','D'),
SUB_XPPA = MKTAG('X','P','P','A'),
SUB_PDTO = MKTAG('P','D','T','O'),
SUB_XLRL = MKTAG('X','L','R','L'),
SUB_QNAM = MKTAG('Q','N','A','M'),
SUB_COCT = MKTAG('C','O','C','T'),
SUB_COED = MKTAG('C','O','E','D'),
SUB_CNTO = MKTAG('C','N','T','O'),
SUB_SCRI = MKTAG('S','C','R','I'),
SUB_BNAM = MKTAG('B','N','A','M'),
SUB_BMDT = MKTAG('B','M','D','T'),
SUB_MOD2 = MKTAG('M','O','D','2'),
SUB_MOD3 = MKTAG('M','O','D','3'),
SUB_MOD4 = MKTAG('M','O','D','4'),
SUB_MO2B = MKTAG('M','O','2','B'),
SUB_MO3B = MKTAG('M','O','3','B'),
SUB_MO4B = MKTAG('M','O','4','B'),
SUB_MO2T = MKTAG('M','O','2','T'),
SUB_MO3T = MKTAG('M','O','3','T'),
SUB_MO4T = MKTAG('M','O','4','T'),
SUB_ANAM = MKTAG('A','N','A','M'),
SUB_ENAM = MKTAG('E','N','A','M'),
SUB_ICO2 = MKTAG('I','C','O','2'),
SUB_ACBS = MKTAG('A','C','B','S'),
SUB_SPLO = MKTAG('S','P','L','O'),
SUB_AIDT = MKTAG('A','I','D','T'),
SUB_PKID = MKTAG('P','K','I','D'),
SUB_HCLR = MKTAG('H','C','L','R'),
SUB_FGGS = MKTAG('F','G','G','S'),
SUB_FGGA = MKTAG('F','G','G','A'),
SUB_FGTS = MKTAG('F','G','T','S'),
SUB_KFFZ = MKTAG('K','F','F','Z'),
SUB_PFIG = MKTAG('P','F','I','G'),
SUB_PFPC = MKTAG('P','F','P','C'),
SUB_XHRS = MKTAG('X','H','R','S'),
SUB_XMRC = MKTAG('X','M','R','C'),
SUB_SNDD = MKTAG('S','N','D','D'),
SUB_SNDX = MKTAG('S','N','D','X'),
SUB_DESC = MKTAG('D','E','S','C'),
SUB_ENIT = MKTAG('E','N','I','T'),
SUB_EFID = MKTAG('E','F','I','D'),
SUB_EFIT = MKTAG('E','F','I','T'),
SUB_SCIT = MKTAG('S','C','I','T'),
SUB_SOUL = MKTAG('S','O','U','L'),
SUB_SLCP = MKTAG('S','L','C','P'),
SUB_CSCR = MKTAG('C','S','C','R'),
SUB_CSDI = MKTAG('C','S','D','I'),
SUB_CSDC = MKTAG('C','S','D','C'),
SUB_NIFZ = MKTAG('N','I','F','Z'),
SUB_CSDT = MKTAG('C','S','D','T'),
SUB_NAM1 = MKTAG('N','A','M','1'),
SUB_NIFT = MKTAG('N','I','F','T'),
SUB_LVLD = MKTAG('L','V','L','D'),
SUB_LVLF = MKTAG('L','V','L','F'),
SUB_LVLO = MKTAG('L','V','L','O'),
SUB_BODT = MKTAG('B','O','D','T'),
SUB_YNAM = MKTAG('Y','N','A','M'),
SUB_DEST = MKTAG('D','E','S','T'),
SUB_DMDL = MKTAG('D','M','D','L'),
SUB_DMDS = MKTAG('D','M','D','S'),
SUB_DMDT = MKTAG('D','M','D','T'),
SUB_DSTD = MKTAG('D','S','T','D'),
SUB_DSTF = MKTAG('D','S','T','F'),
SUB_KNAM = MKTAG('K','N','A','M'),
SUB_KSIZ = MKTAG('K','S','I','Z'),
SUB_KWDA = MKTAG('K','W','D','A'),
SUB_VNAM = MKTAG('V','N','A','M'),
SUB_SDSC = MKTAG('S','D','S','C'),
SUB_MO2S = MKTAG('M','O','2','S'),
SUB_MO4S = MKTAG('M','O','4','S'),
SUB_BOD2 = MKTAG('B','O','D','2'),
SUB_BAMT = MKTAG('B','A','M','T'),
SUB_BIDS = MKTAG('B','I','D','S'),
SUB_ETYP = MKTAG('E','T','Y','P'),
SUB_BMCT = MKTAG('B','M','C','T'),
SUB_MICO = MKTAG('M','I','C','O'),
SUB_MIC2 = MKTAG('M','I','C','2'),
SUB_EAMT = MKTAG('E','A','M','T'),
SUB_EITM = MKTAG('E','I','T','M'),
SUB_SCTX = MKTAG('S','C','T','X'),
SUB_XLTW = MKTAG('X','L','T','W'),
SUB_XMBP = MKTAG('X','M','B','P'),
SUB_XOCP = MKTAG('X','O','C','P'),
SUB_XRGB = MKTAG('X','R','G','B'),
SUB_XSPC = MKTAG('X','S','P','C'),
SUB_XTNM = MKTAG('X','T','N','M'),
SUB_ATKR = MKTAG('A','T','K','R'),
SUB_CRIF = MKTAG('C','R','I','F'),
SUB_DOFT = MKTAG('D','O','F','T'),
SUB_DPLT = MKTAG('D','P','L','T'),
SUB_ECOR = MKTAG('E','C','O','R'),
SUB_ATKD = MKTAG('A','T','K','D'),
SUB_ATKE = MKTAG('A','T','K','E'),
SUB_FTST = MKTAG('F','T','S','T'),
SUB_HCLF = MKTAG('H','C','L','F'),
SUB_NAM5 = MKTAG('N','A','M','5'),
SUB_NAM6 = MKTAG('N','A','M','6'),
SUB_NAM7 = MKTAG('N','A','M','7'),
SUB_NAM8 = MKTAG('N','A','M','8'),
SUB_PRKR = MKTAG('P','R','K','R'),
SUB_PRKZ = MKTAG('P','R','K','Z'),
SUB_SOFT = MKTAG('S','O','F','T'),
SUB_SPCT = MKTAG('S','P','C','T'),
SUB_TINC = MKTAG('T','I','N','C'),
SUB_TIAS = MKTAG('T','I','A','S'),
SUB_TINI = MKTAG('T','I','N','I'),
SUB_TINV = MKTAG('T','I','N','V'),
SUB_TPLT = MKTAG('T','P','L','T'),
SUB_VTCK = MKTAG('V','T','C','K'),
SUB_SHRT = MKTAG('S','H','R','T'),
SUB_SPOR = MKTAG('S','P','O','R'),
SUB_XHOR = MKTAG('X','H','O','R'),
SUB_CTDA = MKTAG('C','T','D','A'),
SUB_CRDT = MKTAG('C','R','D','T'),
SUB_FNMK = MKTAG('F','N','M','K'),
SUB_FNPR = MKTAG('F','N','P','R'),
SUB_WBDT = MKTAG('W','B','D','T'),
SUB_QUAL = MKTAG('Q','U','A','L'),
SUB_INDX = MKTAG('I','N','D','X'),
SUB_ATTR = MKTAG('A','T','T','R'),
SUB_MTNM = MKTAG('M','T','N','M'),
SUB_UNES = MKTAG('U','N','E','S'),
SUB_TIND = MKTAG('T','I','N','D'),
SUB_TINL = MKTAG('T','I','N','L'),
SUB_TINP = MKTAG('T','I','N','P'),
SUB_TINT = MKTAG('T','I','N','T'),
SUB_TIRS = MKTAG('T','I','R','S'),
SUB_PHWT = MKTAG('P','H','W','T'),
SUB_AHCF = MKTAG('A','H','C','F'),
SUB_AHCM = MKTAG('A','H','C','M'),
SUB_HEAD = MKTAG('H','E','A','D'),
SUB_MPAI = MKTAG('M','P','A','I'),
SUB_MPAV = MKTAG('M','P','A','V'),
SUB_DFTF = MKTAG('D','F','T','F'),
SUB_DFTM = MKTAG('D','F','T','M'),
SUB_FLMV = MKTAG('F','L','M','V'),
SUB_FTSF = MKTAG('F','T','S','F'),
SUB_FTSM = MKTAG('F','T','S','M'),
SUB_MTYP = MKTAG('M','T','Y','P'),
SUB_PHTN = MKTAG('P','H','T','N'),
SUB_RNMV = MKTAG('R','N','M','V'),
SUB_RPRF = MKTAG('R','P','R','F'),
SUB_RPRM = MKTAG('R','P','R','M'),
SUB_SNMV = MKTAG('S','N','M','V'),
SUB_SPED = MKTAG('S','P','E','D'),
SUB_SWMV = MKTAG('S','W','M','V'),
SUB_WKMV = MKTAG('W','K','M','V'),
SUB_LLCT = MKTAG('L','L','C','T'),
SUB_IDLF = MKTAG('I','D','L','F'),
SUB_IDLA = MKTAG('I','D','L','A'),
SUB_IDLC = MKTAG('I','D','L','C'),
SUB_IDLT = MKTAG('I','D','L','T'),
SUB_DODT = MKTAG('D','O','D','T'),
SUB_TX00 = MKTAG('T','X','0','0'),
SUB_TX01 = MKTAG('T','X','0','1'),
SUB_TX02 = MKTAG('T','X','0','2'),
SUB_TX03 = MKTAG('T','X','0','3'),
SUB_TX04 = MKTAG('T','X','0','4'),
SUB_TX05 = MKTAG('T','X','0','5'),
SUB_TX06 = MKTAG('T','X','0','6'),
SUB_TX07 = MKTAG('T','X','0','7'),
SUB_BPND = MKTAG('B','P','N','D'),
SUB_BPTN = MKTAG('B','P','T','N'),
SUB_BPNN = MKTAG('B','P','N','N'),
SUB_BPNT = MKTAG('B','P','N','T'),
SUB_BPNI = MKTAG('B','P','N','I'),
SUB_RAGA = MKTAG('R','A','G','A'),
SUB_QSTI = MKTAG('Q','S','T','I'),
SUB_QSTR = MKTAG('Q','S','T','R'),
SUB_QSDT = MKTAG('Q','S','D','T'),
SUB_SCDA = MKTAG('S','C','D','A'),
SUB_SCRO = MKTAG('S','C','R','O'),
SUB_QSTA = MKTAG('Q','S','T','A'),
SUB_CTDT = MKTAG('C','T','D','T'),
SUB_SCHD = MKTAG('S','C','H','D'),
SUB_TCLF = MKTAG('T','C','L','F'),
SUB_TCLT = MKTAG('T','C','L','T'),
SUB_TRDT = MKTAG('T','R','D','T'),
SUB_TPIC = MKTAG('T','P','I','C'),
SUB_PKDT = MKTAG('P','K','D','T'),
SUB_PSDT = MKTAG('P','S','D','T'),
SUB_PLDT = MKTAG('P','L','D','T'),
SUB_PTDT = MKTAG('P','T','D','T'),
SUB_PGRP = MKTAG('P','G','R','P'),
SUB_PGRR = MKTAG('P','G','R','R'),
SUB_PGRI = MKTAG('P','G','R','I'),
SUB_PGRL = MKTAG('P','G','R','L'),
SUB_PGAG = MKTAG('P','G','A','G'),
SUB_FLTV = MKTAG('F','L','T','V'),
SUB_XHLT = MKTAG('X','H','L','T'), // Unofficial Oblivion Patch
SUB_XCHG = MKTAG('X','C','H','G'), // thievery.exp
SUB_ITXT = MKTAG('I','T','X','T'),
SUB_MO5T = MKTAG('M','O','5','T'),
SUB_MOD5 = MKTAG('M','O','D','5'),
SUB_MDOB = MKTAG('M','D','O','B'),
SUB_SPIT = MKTAG('S','P','I','T'),
SUB_PTDA = MKTAG('P','T','D','A'), // TES5
SUB_PFOR = MKTAG('P','F','O','R'), // TES5
SUB_PFO2 = MKTAG('P','F','O','2'), // TES5
SUB_PRCB = MKTAG('P','R','C','B'), // TES5
SUB_PKCU = MKTAG('P','K','C','U'), // TES5
SUB_PKC2 = MKTAG('P','K','C','2'), // TES5
SUB_CITC = MKTAG('C','I','T','C'), // TES5
SUB_CIS1 = MKTAG('C','I','S','1'), // TES5
SUB_CIS2 = MKTAG('C','I','S','2'), // TES5
SUB_TIFC = MKTAG('T','I','F','C'), // TES5
SUB_ALCA = MKTAG('A','L','C','A'), // TES5
SUB_ALCL = MKTAG('A','L','C','L'), // TES5
SUB_ALCO = MKTAG('A','L','C','O'), // TES5
SUB_ALDN = MKTAG('A','L','D','N'), // TES5
SUB_ALEA = MKTAG('A','L','E','A'), // TES5
SUB_ALED = MKTAG('A','L','E','D'), // TES5
SUB_ALEQ = MKTAG('A','L','E','Q'), // TES5
SUB_ALFA = MKTAG('A','L','F','A'), // TES5
SUB_ALFC = MKTAG('A','L','F','C'), // TES5
SUB_ALFD = MKTAG('A','L','F','D'), // TES5
SUB_ALFE = MKTAG('A','L','F','E'), // TES5
SUB_ALFI = MKTAG('A','L','F','I'), // TES5
SUB_ALFL = MKTAG('A','L','F','L'), // TES5
SUB_ALFR = MKTAG('A','L','F','R'), // TES5
SUB_ALID = MKTAG('A','L','I','D'), // TES5
SUB_ALLS = MKTAG('A','L','L','S'), // TES5
SUB_ALNA = MKTAG('A','L','N','A'), // TES5
SUB_ALNT = MKTAG('A','L','N','T'), // TES5
SUB_ALPC = MKTAG('A','L','P','C'), // TES5
SUB_ALRT = MKTAG('A','L','R','T'), // TES5
SUB_ALSP = MKTAG('A','L','S','P'), // TES5
SUB_ALST = MKTAG('A','L','S','T'), // TES5
SUB_ALUA = MKTAG('A','L','U','A'), // TES5
SUB_FLTR = MKTAG('F','L','T','R'), // TES5
SUB_QTGL = MKTAG('Q','T','G','L'), // TES5
SUB_TWAT = MKTAG('T','W','A','T'), // TES5
SUB_XIBS = MKTAG('X','I','B','S'), // FO3
SUB_REPL = MKTAG('R','E','P','L'), // FO3
SUB_BIPL = MKTAG('B','I','P','L'), // FO3
SUB_MODD = MKTAG('M','O','D','D'), // FO3
SUB_MOSD = MKTAG('M','O','S','D'), // FO3
SUB_MO3S = MKTAG('M','O','3','S'), // FO3
SUB_XCET = MKTAG('X','C','E','T'), // FO3
SUB_LVLG = MKTAG('L','V','L','G'), // FO3
SUB_NVCI = MKTAG('N','V','C','I'), // FO3
SUB_NVVX = MKTAG('N','V','V','X'), // FO3
SUB_NVTR = MKTAG('N','V','T','R'), // FO3
SUB_NVCA = MKTAG('N','V','C','A'), // FO3
SUB_NVDP = MKTAG('N','V','D','P'), // FO3
SUB_NVGD = MKTAG('N','V','G','D'), // FO3
SUB_NVEX = MKTAG('N','V','E','X'), // FO3
SUB_XHLP = MKTAG('X','H','L','P'), // FO3
SUB_XRDO = MKTAG('X','R','D','O'), // FO3
SUB_XAMT = MKTAG('X','A','M','T'), // FO3
SUB_XAMC = MKTAG('X','A','M','C'), // FO3
SUB_XRAD = MKTAG('X','R','A','D'), // FO3
SUB_XORD = MKTAG('X','O','R','D'), // FO3
SUB_XCLP = MKTAG('X','C','L','P'), // FO3
SUB_NEXT = MKTAG('N','E','X','T'), // FO3
SUB_QOBJ = MKTAG('Q','O','B','J'), // FO3
SUB_POBA = MKTAG('P','O','B','A'), // FO3
SUB_POCA = MKTAG('P','O','C','A'), // FO3
SUB_POEA = MKTAG('P','O','E','A'), // FO3
SUB_PKDD = MKTAG('P','K','D','D'), // FO3
SUB_PKD2 = MKTAG('P','K','D','2'), // FO3
SUB_PKPT = MKTAG('P','K','P','T'), // FO3
SUB_PKED = MKTAG('P','K','E','D'), // FO3
SUB_PKE2 = MKTAG('P','K','E','2'), // FO3
SUB_PKAM = MKTAG('P','K','A','M'), // FO3
SUB_PUID = MKTAG('P','U','I','D'), // FO3
SUB_PKW3 = MKTAG('P','K','W','3'), // FO3
SUB_PTD2 = MKTAG('P','T','D','2'), // FO3
SUB_PLD2 = MKTAG('P','L','D','2'), // FO3
SUB_PKFD = MKTAG('P','K','F','D'), // FO3
SUB_IDLB = MKTAG('I','D','L','B'), // FO3
SUB_XDCR = MKTAG('X','D','C','R'), // FO3
SUB_DALC = MKTAG('D','A','L','C'), // FO3
SUB_IMPS = MKTAG('I','M','P','S'), // FO3 Anchorage
SUB_IMPF = MKTAG('I','M','P','F'), // FO3 Anchorage
SUB_XATO = MKTAG('X','A','T','O'), // FONV
SUB_INFC = MKTAG('I','N','F','C'), // FONV
SUB_INFX = MKTAG('I','N','F','X'), // FONV
SUB_TDUM = MKTAG('T','D','U','M'), // FONV
SUB_TCFU = MKTAG('T','C','F','U'), // FONV
SUB_DAT2 = MKTAG('D','A','T','2'), // FONV
SUB_RCIL = MKTAG('R','C','I','L'), // FONV
SUB_MMRK = MKTAG('M','M','R','K'), // FONV
SUB_SCRV = MKTAG('S','C','R','V'), // FONV
SUB_SCVR = MKTAG('S','C','V','R'), // FONV
SUB_SLSD = MKTAG('S','L','S','D'), // FONV
SUB_XSRF = MKTAG('X','S','R','F'), // FONV
SUB_XSRD = MKTAG('X','S','R','D'), // FONV
SUB_WMI1 = MKTAG('W','M','I','1'), // FONV
SUB_RDID = MKTAG('R','D','I','D'), // FONV
SUB_RDSB = MKTAG('R','D','S','B'), // FONV
SUB_RDSI = MKTAG('R','D','S','I'), // FONV
SUB_BRUS = MKTAG('B','R','U','S'), // FONV
SUB_VATS = MKTAG('V','A','T','S'), // FONV
SUB_VANM = MKTAG('V','A','N','M'), // FONV
SUB_MWD1 = MKTAG('M','W','D','1'), // FONV
SUB_MWD2 = MKTAG('M','W','D','2'), // FONV
SUB_MWD3 = MKTAG('M','W','D','3'), // FONV
SUB_MWD4 = MKTAG('M','W','D','4'), // FONV
SUB_MWD5 = MKTAG('M','W','D','5'), // FONV
SUB_MWD6 = MKTAG('M','W','D','6'), // FONV
SUB_MWD7 = MKTAG('M','W','D','7'), // FONV
SUB_WMI2 = MKTAG('W','M','I','2'), // FONV
SUB_WMI3 = MKTAG('W','M','I','3'), // FONV
SUB_WMS1 = MKTAG('W','M','S','1'), // FONV
SUB_WMS2 = MKTAG('W','M','S','2'), // FONV
SUB_WNM1 = MKTAG('W','N','M','1'), // FONV
SUB_WNM2 = MKTAG('W','N','M','2'), // FONV
SUB_WNM3 = MKTAG('W','N','M','3'), // FONV
SUB_WNM4 = MKTAG('W','N','M','4'), // FONV
SUB_WNM5 = MKTAG('W','N','M','5'), // FONV
SUB_WNM6 = MKTAG('W','N','M','6'), // FONV
SUB_WNM7 = MKTAG('W','N','M','7'), // FONV
SUB_JNAM = MKTAG('J','N','A','M'), // FONV
SUB_EFSD = MKTAG('E','F','S','D'), // FONV DeadMoney
};
enum MagicEffectID
{
// Alteration
EFI_BRDN = MKTAG('B','R','D','N'),
EFI_FTHR = MKTAG('F','T','H','R'),
EFI_FISH = MKTAG('F','I','S','H'),
EFI_FRSH = MKTAG('F','R','S','H'),
EFI_OPEN = MKTAG('O','P','N','N'),
EFI_SHLD = MKTAG('S','H','L','D'),
EFI_LISH = MKTAG('L','I','S','H'),
EFI_WABR = MKTAG('W','A','B','R'),
EFI_WAWA = MKTAG('W','A','W','A'),
// Conjuration
EFI_BABO = MKTAG('B','A','B','O'), // Bound Boots
EFI_BACU = MKTAG('B','A','C','U'), // Bound Cuirass
EFI_BAGA = MKTAG('B','A','G','A'), // Bound Gauntlets
EFI_BAGR = MKTAG('B','A','G','R'), // Bound Greaves
EFI_BAHE = MKTAG('B','A','H','E'), // Bound Helmet
EFI_BASH = MKTAG('B','A','S','H'), // Bound Shield
EFI_BWAX = MKTAG('B','W','A','X'), // Bound Axe
EFI_BWBO = MKTAG('B','W','B','O'), // Bound Bow
EFI_BWDA = MKTAG('B','W','D','A'), // Bound Dagger
EFI_BWMA = MKTAG('B','W','M','A'), // Bound Mace
EFI_BWSW = MKTAG('B','W','S','W'), // Bound Sword
EFI_Z001 = MKTAG('Z','0','0','1'), // Summon Rufio's Ghost
EFI_Z002 = MKTAG('Z','0','0','2'), // Summon Ancestor Guardian
EFI_Z003 = MKTAG('Z','0','0','3'), // Summon Spiderling
EFI_Z005 = MKTAG('Z','0','0','5'), // Summon Bear
EFI_ZCLA = MKTAG('Z','C','L','A'), // Summon Clannfear
EFI_ZDAE = MKTAG('Z','D','A','E'), // Summon Daedroth
EFI_ZDRE = MKTAG('Z','D','R','E'), // Summon Dremora
EFI_ZDRL = MKTAG('Z','D','R','L'), // Summon Dremora Lord
EFI_ZFIA = MKTAG('Z','F','I','A'), // Summon Flame Atronach
EFI_ZFRA = MKTAG('Z','F','R','A'), // Summon Frost Atronach
EFI_ZGHO = MKTAG('Z','G','H','O'), // Summon Ghost
EFI_ZHDZ = MKTAG('Z','H','D','Z'), // Summon Headless Zombie
EFI_ZLIC = MKTAG('Z','L','I','C'), // Summon Lich
EFI_ZSCA = MKTAG('Z','S','C','A'), // Summon Scamp
EFI_ZSKE = MKTAG('Z','S','K','E'), // Summon Skeleton
EFI_ZSKA = MKTAG('Z','S','K','A'), // Summon Skeleton Guardian
EFI_ZSKH = MKTAG('Z','S','K','H'), // Summon Skeleton Hero
EFI_ZSKC = MKTAG('Z','S','K','C'), // Summon Skeleton Champion
EFI_ZSPD = MKTAG('Z','S','P','D'), // Summon Spider Daedra
EFI_ZSTA = MKTAG('Z','S','T','A'), // Summon Storm Atronach
EFI_ZWRA = MKTAG('Z','W','R','A'), // Summon Faded Wraith
EFI_ZWRL = MKTAG('Z','W','R','L'), // Summon Gloom Wraith
EFI_ZXIV = MKTAG('Z','X','I','V'), // Summon Xivilai
EFI_ZZOM = MKTAG('Z','Z','O','M'), // Summon Zombie
EFI_TURN = MKTAG('T','U','R','N'), // Turn Undead
// Destruction
EFI_DGAT = MKTAG('D','G','A','T'), // Damage Attribute
EFI_DGFA = MKTAG('D','G','F','A'), // Damage Fatigue
EFI_DGHE = MKTAG('D','G','H','E'), // Damage Health
EFI_DGSP = MKTAG('D','G','S','P'), // Damage Magicka
EFI_DIAR = MKTAG('D','I','A','R'), // Disintegrate Armor
EFI_DIWE = MKTAG('D','I','W','E'), // Disintegrate Weapon
EFI_DRAT = MKTAG('D','R','A','T'), // Drain Attribute
EFI_DRFA = MKTAG('D','R','F','A'), // Drain Fatigue
EFI_DRHE = MKTAG('D','R','H','E'), // Drain Health
EFI_DRSP = MKTAG('D','R','S','P'), // Drain Magicka
EFI_DRSK = MKTAG('D','R','S','K'), // Drain Skill
EFI_FIDG = MKTAG('F','I','D','G'), // Fire Damage
EFI_FRDG = MKTAG('F','R','D','G'), // Frost Damage
EFI_SHDG = MKTAG('S','H','D','G'), // Shock Damage
EFI_WKDI = MKTAG('W','K','D','I'), // Weakness to Disease
EFI_WKFI = MKTAG('W','K','F','I'), // Weakness to Fire
EFI_WKFR = MKTAG('W','K','F','R'), // Weakness to Frost
EFI_WKMA = MKTAG('W','K','M','A'), // Weakness to Magic
EFI_WKNW = MKTAG('W','K','N','W'), // Weakness to Normal Weapons
EFI_WKPO = MKTAG('W','K','P','O'), // Weakness to Poison
EFI_WKSH = MKTAG('W','K','S','H'), // Weakness to Shock
// Illusion
EFI_CALM = MKTAG('C','A','L','M'), // Calm
EFI_CHML = MKTAG('C','H','M','L'), // Chameleon
EFI_CHRM = MKTAG('C','H','R','M'), // Charm
EFI_COCR = MKTAG('C','O','C','R'), // Command Creature
EFI_COHU = MKTAG('C','O','H','U'), // Command Humanoid
EFI_DEMO = MKTAG('D','E','M','O'), // Demoralize
EFI_FRNZ = MKTAG('F','R','N','Z'), // Frenzy
EFI_INVI = MKTAG('I','N','V','I'), // Invisibility
EFI_LGHT = MKTAG('L','G','H','T'), // Light
EFI_NEYE = MKTAG('N','E','Y','E'), // Night-Eye
EFI_PARA = MKTAG('P','A','R','A'), // Paralyze
EFI_RALY = MKTAG('R','A','L','Y'), // Rally
EFI_SLNC = MKTAG('S','L','N','C'), // Silence
// Mysticism
EFI_DTCT = MKTAG('D','T','C','T'), // Detect Life
EFI_DSPL = MKTAG('D','S','P','L'), // Dispel
EFI_REDG = MKTAG('R','E','D','G'), // Reflect Damage
EFI_RFLC = MKTAG('R','F','L','C'), // Reflect Spell
EFI_STRP = MKTAG('S','T','R','P'), // Soul Trap
EFI_SABS = MKTAG('S','A','B','S'), // Spell Absorption
EFI_TELE = MKTAG('T','E','L','E'), // Telekinesis
// Restoration
EFI_ABAT = MKTAG('A','B','A','T'), // Absorb Attribute
EFI_ABFA = MKTAG('A','B','F','A'), // Absorb Fatigue
EFI_ABHe = MKTAG('A','B','H','e'), // Absorb Health
EFI_ABSP = MKTAG('A','B','S','P'), // Absorb Magicka
EFI_ABSK = MKTAG('A','B','S','K'), // Absorb Skill
EFI_1400 = MKTAG('1','4','0','0'), // Cure Disease
EFI_CUPA = MKTAG('C','U','P','A'), // Cure Paralysis
EFI_CUPO = MKTAG('C','U','P','O'), // Cure Poison
EFI_FOAT = MKTAG('F','O','A','T'), // Fortify Attribute
EFI_FOFA = MKTAG('F','O','F','A'), // Fortify Fatigue
EFI_FOHE = MKTAG('F','O','H','E'), // Fortify Health
EFI_FOSP = MKTAG('F','O','S','P'), // Fortify Magicka
EFI_FOSK = MKTAG('F','O','S','K'), // Fortify Skill
EFI_RSDI = MKTAG('R','S','D','I'), // Resist Disease
EFI_RSFI = MKTAG('R','S','F','I'), // Resist Fire
EFI_RSFR = MKTAG('R','S','F','R'), // Resist Frost
EFI_RSMA = MKTAG('R','S','M','A'), // Resist Magic
EFI_RSNW = MKTAG('R','S','N','W'), // Resist Normal Weapons
EFI_RSPA = MKTAG('R','S','P','A'), // Resist Paralysis
EFI_RSPO = MKTAG('R','S','P','O'), // Resist Poison
EFI_RSSH = MKTAG('R','S','S','H'), // Resist Shock
EFI_REAT = MKTAG('R','E','A','T'), // Restore Attribute
EFI_REFA = MKTAG('R','E','F','A'), // Restore Fatigue
EFI_REHE = MKTAG('R','E','H','E'), // Restore Health
EFI_RESP = MKTAG('R','E','S','P'), // Restore Magicka
// Effects
EFI_LOCK = MKTAG('L','O','C','K'), // Lock Lock
EFI_SEFF = MKTAG('S','E','F','F'), // Script Effect
EFI_Z020 = MKTAG('Z','0','2','0'), // Summon 20 Extra
EFI_MYHL = MKTAG('M','Y','H','L'), // Summon Mythic Dawn Helmet
EFI_MYTH = MKTAG('M','Y','T','H'), // Summon Mythic Dawn Armor
EFI_REAN = MKTAG('R','E','A','N'), // Reanimate
EFI_DISE = MKTAG('D','I','S','E'), // Disease Info
EFI_POSN = MKTAG('P','O','S','N'), // Poison Info
EFI_DUMY = MKTAG('D','U','M','Y'), // Mehrunes Dagon Custom Effect
EFI_STMA = MKTAG('S','T','M','A'), // Stunted Magicka
EFI_SUDG = MKTAG('S','U','D','G'), // Sun Damage
EFI_VAMP = MKTAG('V','A','M','P'), // Vampirism
EFI_DARK = MKTAG('D','A','R','K'), // Darkness
EFI_RSWD = MKTAG('R','S','W','D') // Resist Water Damage
};
// Based on http://www.uesp.net/wiki/Tes5Mod:Mod_File_Format#Groups
enum GroupType
{
Grp_RecordType = 0,
Grp_WorldChild = 1,
Grp_InteriorCell = 2,
Grp_InteriorSubCell = 3,
Grp_ExteriorCell = 4,
Grp_ExteriorSubCell = 5,
Grp_CellChild = 6,
Grp_TopicChild = 7,
Grp_CellPersistentChild = 8,
Grp_CellTemporaryChild = 9,
Grp_CellVisibleDistChild = 10
};
// Based on http://www.uesp.net/wiki/Tes5Mod:Mod_File_Format#Records
enum RecordFlag
{
Rec_ESM = 0x00000001, // (TES4 record only) Master (ESM) file.
Rec_Deleted = 0x00000020, // Deleted
Rec_Constant = 0x00000040, // Constant
Rec_HiddenLMap = 0x00000040, // (REFR) Hidden From Local Map (Needs Confirmation: Related to shields)
Rec_Localized = 0x00000080, // (TES4 record only) Is localized. This will make Skyrim load the
// .STRINGS, .DLSTRINGS, and .ILSTRINGS files associated with the mod.
// If this flag is not set, lstrings are treated as zstrings.
Rec_FireOff = 0x00000080, // (PHZD) Turn off fire
Rec_UpdateAnim = 0x00000100, // Must Update Anims
Rec_NoAccess = 0x00000100, // (REFR) Inaccessible
Rec_Hidden = 0x00000200, // (REFR) Hidden from local map
Rec_StartDead = 0x00000200, // (ACHR) Starts dead /(REFR) MotionBlurCastsShadows
Rec_Persistent = 0x00000400, // Quest item / Persistent reference
Rec_DispMenu = 0x00000400, // (LSCR) Displays in Main Menu
Rec_Disabled = 0x00000800, // Initially disabled
Rec_Ignored = 0x00001000, // Ignored
Rec_VisDistant = 0x00008000, // Visible when distant
Rec_RandAnim = 0x00010000, // (ACTI) Random Animation Start
Rec_Danger = 0x00020000, // (ACTI) Dangerous / Off limits (Interior cell)
// Dangerous Can't be set withough Ignore Object Interaction
Rec_Compressed = 0x00040000, // Data is compressed
Rec_CanNotWait = 0x00080000, // Can't wait
Rec_IgnoreObj = 0x00100000, // (ACTI) Ignore Object Interaction
// Ignore Object Interaction Sets Dangerous Automatically
Rec_Marker = 0x00800000, // Is Marker
Rec_Obstacle = 0x02000000, // (ACTI) Obstacle / (REFR) No AI Acquire
Rec_NavMFilter = 0x04000000, // NavMesh Gen - Filter
Rec_NavMBBox = 0x08000000, // NavMesh Gen - Bounding Box
Rec_ExitToTalk = 0x10000000, // (FURN) Must Exit to Talk
Rec_Refected = 0x10000000, // (REFR) Reflected By Auto Water
Rec_ChildUse = 0x20000000, // (FURN/IDLM) Child Can Use
Rec_NoHavok = 0x20000000, // (REFR) Don't Havok Settle
Rec_NavMGround = 0x40000000, // NavMesh Gen - Ground
Rec_NoRespawn = 0x40000000, // (REFR) NoRespawn
Rec_MultiBound = 0x80000000 // (REFR) MultiBound
};
#pragma pack(push, 1)
// NOTE: the label field of a group is not reliable (http://www.uesp.net/wiki/Tes4Mod:Mod_File_Format)
union GroupLabel
{
std::uint32_t value; // formId, blockNo or raw int representation of type
char recordType[4]; // record type in ascii
std::int16_t grid[2]; // grid y, x (note the reverse order)
};
struct GroupTypeHeader
{
std::uint32_t typeId;
std::uint32_t groupSize; // includes the 24 bytes (20 for TES4) of header (i.e. this struct)
GroupLabel label; // format based on type
std::int32_t type;
std::uint16_t stamp; // & 0xff for day, & 0xff00 for months since Dec 2002 (i.e. 1 = Jan 2003)
std::uint16_t unknown;
std::uint16_t version; // not in TES4
std::uint16_t unknown2; // not in TES4
};
struct RecordTypeHeader
{
std::uint32_t typeId;
std::uint32_t dataSize; // does *not* include 24 bytes (20 for TES4) of header
std::uint32_t flags;
FormId id;
std::uint32_t revision;
std::uint16_t version; // not in TES4
std::uint16_t unknown; // not in TES4
};
union RecordHeader
{
struct GroupTypeHeader group;
struct RecordTypeHeader record;
};
struct SubRecordHeader
{
std::uint32_t typeId;
std::uint16_t dataSize;
};
// Grid, CellGrid and Vertex are shared by NVMI(NAVI) and NVNM(NAVM)
struct Grid
{
std::int16_t x;
std::int16_t y;
};
union CellGrid
{
FormId cellId;
Grid grid;
};
struct Vertex
{
float x;
float y;
float z;
};
#pragma pack(pop)
// For pretty printing GroupHeader labels
std::string printLabel(const GroupLabel& label, const std::uint32_t type);
void gridToString(std::int16_t x, std::int16_t y, std::string& str);
}
#endif // ESM4_COMMON_H

@ -0,0 +1,46 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_DIALOGUE_H
#define ESM4_DIALOGUE_H
namespace ESM4
{
enum DialType
{
DTYP_Topic = 0,
DTYP_Conversation = 1,
DTYP_Combat = 2,
DTYP_Persuation = 3,
DTYP_Detection = 4,
DTYP_Service = 5,
DTYP_Miscellaneous = 6,
// below FO3/FONV
DTYP_Radio = 7
};
}
#endif // ESM4_DIALOGUE_H

@ -0,0 +1,56 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_EFFECT_H
#define ESM4_EFFECT_H
#include <cstdint>
#include "formid.hpp"
namespace ESM4
{
#pragma pack(push, 1)
union EFI_Label
{
std::uint32_t value;
char effect[4];
};
struct ScriptEffect
{
FormId formId; // Script effect (Magic effect must be SEFF)
std::int32_t school; // Magic school. See Magic schools for more information.
EFI_Label visualEffect; // Visual effect name or 0x00000000 if None
std::uint8_t flags; // 0x01 = Hostile
std::uint8_t unknown1;
std::uint8_t unknown2;
std::uint8_t unknown3;
};
#pragma pack(pop)
}
#endif // ESM4_EFFECT_H

@ -0,0 +1,78 @@
/*
Copyright (C) 2016, 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
*/
#include "formid.hpp"
#include <sstream>
#include <algorithm>
#include <stdexcept>
#include <cstdlib> // strtol
#include <climits> // LONG_MIN, LONG_MAX for gcc
#include <string>
namespace ESM4
{
void formIdToString(FormId formId, std::string& str)
{
char buf[8+1];
int res = snprintf(buf, 8+1, "%08X", formId);
if (res > 0 && res < 8+1)
str.assign(buf);
else
throw std::runtime_error("Possible buffer overflow while converting formId");
}
std::string formIdToString(FormId formId)
{
std::string str;
formIdToString(formId, str);
return str;
}
bool isFormId(const std::string& str, FormId *id)
{
if (str.size() != 8)
return false;
char *tmp;
errno = 0;
unsigned long val = strtol(str.c_str(), &tmp, 16);
if (tmp == str.c_str() || *tmp != '\0'
|| ((val == (unsigned long)LONG_MIN || val == (unsigned long)LONG_MAX) && errno == ERANGE))
return false;
if (id != nullptr)
*id = static_cast<FormId>(val);
return true;
}
FormId stringToFormId(const std::string& str)
{
if (str.size() != 8)
throw std::out_of_range("StringToFormId: incorrect string size");
return static_cast<FormId>(std::stoul(str, nullptr, 16));
}
}

@ -0,0 +1,42 @@
/*
Copyright (C) 2016 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
*/
#ifndef ESM4_FORMID_H
#define ESM4_FORMID_H
#include <cstdint>
#include <string>
namespace ESM4
{
typedef std::uint32_t FormId;
void formIdToString(FormId formId, std::string& str);
std::string formIdToString(FormId formId);
bool isFormId(const std::string& str, FormId *id = nullptr);
FormId stringToFormId(const std::string& str);
}
#endif // ESM4_FORMID_H

@ -0,0 +1,55 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_INVENTORY_H
#define ESM4_INVENTORY_H
#include <cstdint>
#include "formid.hpp"
namespace ESM4
{
#pragma pack(push, 1)
// LVLC, LVLI
struct LVLO
{
std::int16_t level;
std::uint16_t unknown; // sometimes missing
FormId item;
std::int16_t count;
std::uint16_t unknown2; // sometimes missing
};
struct InventoryItem // NPC_, CREA, CONT
{
FormId item;
std::uint32_t count;
};
#pragma pack(pop)
}
#endif // ESM4_INVENTORY_H

@ -0,0 +1,79 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_LIGHTING_H
#define ESM4_LIGHTING_H
#include <cstdint>
namespace ESM4
{
#pragma pack(push, 1)
// guesses only for TES4
struct Lighting
{ // | Aichan Prison values
std::uint32_t ambient; // | 16 17 19 00 (RGBA)
std::uint32_t directional; // | 00 00 00 00 (RGBA)
std::uint32_t fogColor; // | 1D 1B 16 00 (RGBA)
float fogNear; // Fog Near | 00 00 00 00 = 0.f
float fogFar; // Fog Far | 00 80 3B 45 = 3000.f
std::int32_t rotationXY; // rotation xy | 00 00 00 00 = 0
std::int32_t rotationZ; // rotation z | 00 00 00 00 = 0
float fogDirFade; // Fog dir fade | 00 00 80 3F = 1.f
float fogClipDist; // Fog clip dist | 00 80 3B 45 = 3000.f
float fogPower;
};
struct Lighting_TES5
{
std::uint32_t ambient;
std::uint32_t directional;
std::uint32_t fogColor;
float fogNear;
float fogFar;
std::int32_t rotationXY;
std::int32_t rotationZ;
float fogDirFade;
float fogClipDist;
float fogPower;
std::uint32_t unknown1;
std::uint32_t unknown2;
std::uint32_t unknown3;
std::uint32_t unknown4;
std::uint32_t unknown5;
std::uint32_t unknown6;
std::uint32_t unknown7;
std::uint32_t unknown8;
std::uint32_t fogColorFar;
float fogMax;
float LightFadeStart;
float LightFadeEnd;
std::uint32_t padding;
};
#pragma pack(pop)
}
#endif // ESM4_LIGHTING_H

@ -0,0 +1,124 @@
/*
Copyright (C) 2016, 2018, 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadachr.hpp"
#include <stdexcept>
//#include <iostream>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::ActorCharacter::ActorCharacter() : mFormId(0), mFlags(0), mBaseObj(0),
mScale(1.f), mOwner(0), mGlobal(0), mInitiallyDisabled(false)
{
mEditorId.clear();
mFullName.clear();
mEsp.parent = 0;
mEsp.flags = 0;
}
ESM4::ActorCharacter::~ActorCharacter()
{
}
void ESM4::ActorCharacter::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
mParent = reader.currCell(); // NOTE: only for persistent achr? (aren't they all persistent?)
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getZString(mFullName); break;
case ESM4::SUB_NAME: reader.getFormId(mBaseObj); break;
case ESM4::SUB_DATA: reader.get(mPlacement); break;
case ESM4::SUB_XSCL: reader.get(mScale); break;
case ESM4::SUB_XOWN: reader.get(mOwner); break;
case ESM4::SUB_XESP:
{
reader.get(mEsp);
reader.adjustFormId(mEsp.parent);
break;
}
case ESM4::SUB_XRGD: // ragdoll
case ESM4::SUB_XRGB: // ragdoll biped
{
//std::cout << "ACHR " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
case ESM4::SUB_XHRS: // horse formId
case ESM4::SUB_XMRC: // merchant container formId
// TES5
case ESM4::SUB_XAPD: // activation parent
case ESM4::SUB_XAPR: // active parent
case ESM4::SUB_XEZN: // encounter zone
case ESM4::SUB_XHOR:
case ESM4::SUB_XLCM: // levelled creature
case ESM4::SUB_XLCN: // location
case ESM4::SUB_XLKR: // location route?
case ESM4::SUB_XLRT: // location type
//
case ESM4::SUB_XPRD:
case ESM4::SUB_XPPA:
case ESM4::SUB_INAM:
case ESM4::SUB_PDTO:
//
case ESM4::SUB_XIS2:
case ESM4::SUB_XPCI: // formId
case ESM4::SUB_XLOD:
case ESM4::SUB_VMAD:
case ESM4::SUB_XLRL: // Unofficial Skyrim Patch
case ESM4::SUB_XRDS: // FO3
case ESM4::SUB_XIBS: // FO3
case ESM4::SUB_SCHR: // FO3
case ESM4::SUB_TNAM: // FO3
case ESM4::SUB_XATO: // FONV
{
//std::cout << "ACHR " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::ACHR::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::ActorCharacter::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::ActorCharacter::blank()
//{
//}

@ -0,0 +1,70 @@
/*
Copyright (C) 2016, 2018, 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_ACHR_H
#define ESM4_ACHR_H
#include <cstdint>
#include "reference.hpp" // FormId, Placement, EnableParent
namespace ESM4
{
class Reader;
class Writer;
struct ActorCharacter
{
FormId mParent; // cell formId, from the loading sequence
// NOTE: for exterior cells it will be the dummy cell FormId
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
FormId mBaseObj;
Placement mPlacement;
float mScale; // default 1.f
FormId mOwner;
FormId mGlobal;
bool mInitiallyDisabled; // TODO may need to check mFlags & 0x800 (initially disabled)
EnableParent mEsp;
ActorCharacter();
virtual ~ActorCharacter();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_ACHR_H

@ -0,0 +1,106 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadacre.hpp"
#include <stdexcept>
//#include <iostream>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::ActorCreature::ActorCreature() : mFormId(0), mFlags(0), mBaseObj(0), mScale(1.f),
mOwner(0), mGlobal(0), mFactionRank(0), mInitiallyDisabled(false)
{
mEditorId.clear();
mEsp.parent = 0;
mEsp.flags = 0;
}
ESM4::ActorCreature::~ActorCreature()
{
}
void ESM4::ActorCreature::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_NAME: reader.getFormId(mBaseObj); break;
case ESM4::SUB_DATA: reader.get(mPlacement); break;
case ESM4::SUB_XSCL: reader.get(mScale); break;
case ESM4::SUB_XESP:
{
reader.get(mEsp);
reader.adjustFormId(mEsp.parent);
break;
}
case ESM4::SUB_XOWN: reader.getFormId(mOwner); break;
case ESM4::SUB_XGLB: reader.get(mGlobal); break; // FIXME: formId?
case ESM4::SUB_XRNK: reader.get(mFactionRank); break;
case ESM4::SUB_XRGD: // ragdoll
case ESM4::SUB_XRGB: // ragdoll biped
{
// seems to occur only for dead bodies, e.g. DeadMuffy, DeadDogVicious
//std::cout << "ACRE " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
case ESM4::SUB_XLKR: // FO3
case ESM4::SUB_XLCM: // FO3
case ESM4::SUB_XEZN: // FO3
case ESM4::SUB_XMRC: // FO3
case ESM4::SUB_XAPD: // FO3
case ESM4::SUB_XAPR: // FO3
case ESM4::SUB_XRDS: // FO3
case ESM4::SUB_XPRD: // FO3
case ESM4::SUB_XATO: // FONV
{
//std::cout << "ACRE " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::ACRE::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::ActorCreature::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::ActorCreature::blank()
//{
//}

@ -0,0 +1,67 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_ACRE_H
#define ESM4_ACRE_H
#include <cstdint>
#include "reference.hpp" // FormId, Placement, EnableParent
namespace ESM4
{
class Reader;
class Writer;
struct ActorCreature
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
FormId mBaseObj;
Placement mPlacement;
float mScale; // default 1.f
FormId mOwner;
FormId mGlobal;
std::uint32_t mFactionRank;
bool mInitiallyDisabled; // TODO may need to check mFlags & 0x800 (initially disabled)
EnableParent mEsp;
ActorCreature();
virtual ~ActorCreature();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_ACRE_H

@ -0,0 +1,103 @@
/*
Copyright (C) 2016, 2018, 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "acti.hpp"
#include <stdexcept>
#include <iostream> // FIXME
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Activator::Activator() : mFormId(0), mFlags(0), mScriptId(0), mLoopingSound(0), mActivationSound(0),
mBoundRadius(0.f), mRadioTemplate(0), mRadioStation(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mActivationPrompt.clear();
}
ESM4::Activator::~Activator()
{
}
void ESM4::Activator::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_SNAM: reader.getFormId(mLoopingSound); break;
case ESM4::SUB_VNAM: reader.getFormId(mActivationSound); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_INAM: reader.getFormId(mRadioTemplate); break; // FONV
case ESM4::SUB_RNAM: reader.getFormId(mRadioStation); break;
case ESM4::SUB_XATO: reader.getZString(mActivationPrompt); break; // FONV
case ESM4::SUB_MODT:
case ESM4::SUB_MODS:
case ESM4::SUB_DEST:
case ESM4::SUB_DMDL:
case ESM4::SUB_DMDS:
case ESM4::SUB_DMDT:
case ESM4::SUB_DSTD:
case ESM4::SUB_DSTF:
case ESM4::SUB_FNAM:
case ESM4::SUB_KNAM:
case ESM4::SUB_KSIZ:
case ESM4::SUB_KWDA:
case ESM4::SUB_OBND:
case ESM4::SUB_PNAM:
case ESM4::SUB_VMAD:
case ESM4::SUB_WNAM:
{
//std::cout << "ACTI " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::ACTI::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Activator::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Activator::blank()
//{
//}

@ -0,0 +1,121 @@
/*
Copyright (C) 2016, 2018, 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadalch.hpp"
#include <stdexcept>
#include <cstring>
//#include <iostream> // FIXME
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Potion::Potion() : mFormId(0), mFlags(0), mPickUpSound(0), mDropSound(0), mScriptId(0), mBoundRadius(0.f)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mIcon.clear();
mMiniIcon.clear();
mData.weight = 0.f;
std::memset(&mEffect, 0, sizeof(ScriptEffect));
}
ESM4::Potion::~Potion()
{
}
void ESM4::Potion::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
case ESM4::SUB_MICO: reader.getZString(mMiniIcon); break; // FO3
case ESM4::SUB_DATA: reader.get(mData); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_SCIT:
{
reader.get(mEffect);
reader.adjustFormId(mEffect.formId);
break;
}
case ESM4::SUB_ENIT:
{
if (subHdr.dataSize == 8) // TES4
{
reader.get(&mItem, 8);
mItem.withdrawl = 0;
mItem.sound = 0;
break;
}
reader.get(mItem);
reader.adjustFormId(mItem.withdrawl);
reader.adjustFormId(mItem.sound);
break;
}
case ESM4::SUB_YNAM: reader.getFormId(mPickUpSound); break;
case ESM4::SUB_ZNAM: reader.getFormId(mDropSound); break;
case ESM4::SUB_MODT:
case ESM4::SUB_EFID:
case ESM4::SUB_EFIT:
case ESM4::SUB_CTDA:
case ESM4::SUB_KSIZ:
case ESM4::SUB_KWDA:
case ESM4::SUB_MODS:
case ESM4::SUB_OBND:
case ESM4::SUB_ETYP: // FO3
{
//std::cout << "ALCH " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::ALCH::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Potion::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Potion::blank()
//{
//}

@ -0,0 +1,88 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_ALCH_H
#define ESM4_ALCH_H
#include <cstdint>
#include <string>
#include "effect.hpp" // FormId, ScriptEffect
namespace ESM4
{
class Reader;
class Writer;
struct Potion
{
#pragma pack(push, 1)
struct Data
{
float weight;
};
struct EnchantedItem
{
std::int32_t value;
std::uint32_t flags;
FormId withdrawl;
float chanceAddition;
FormId sound;
};
#pragma pack(pop)
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
std::string mIcon; // inventory
std::string mMiniIcon; // inventory
FormId mPickUpSound;
FormId mDropSound;
FormId mScriptId;
ScriptEffect mEffect;
float mBoundRadius;
Data mData;
EnchantedItem mItem;
Potion();
virtual ~Potion();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_ALCH_H

@ -0,0 +1,172 @@
/*
Copyright (C) 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadaloc.hpp"
#include <stdexcept>
#include <cstring>
//#include <iostream> // FIXME: for debugging only
//#include <iomanip> // FIXME: for debugging only
//#include <boost/scoped_array.hpp> // FIXME
//#include "formid.hpp" // FIXME:
#include "reader.hpp"
//#include "writer.hpp"
ESM4::MediaLocationController::MediaLocationController() : mFormId(0), mFlags(0),
mConditionalFaction(0), mLocationDelay(0.f), mRetriggerDelay(0.f), mDayStart(0), mNightStart(0)
{
mEditorId.clear();
mFullName.clear();
std::memset(&mMediaFlags, 0, sizeof(MLC_Flags));
}
ESM4::MediaLocationController::~MediaLocationController()
{
}
void ESM4::MediaLocationController::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getZString(mFullName); break;
case ESM4::SUB_GNAM:
{
FormId id;
reader.getFormId(id);
mBattleSets.push_back(id);
break;
}
case ESM4::SUB_LNAM:
{
FormId id;
reader.getFormId(id);
mLocationSets.push_back(id);
break;
}
case ESM4::SUB_YNAM:
{
FormId id;
reader.getFormId(id);
mEnemySets.push_back(id);
break;
}
case ESM4::SUB_HNAM:
{
FormId id;
reader.getFormId(id);
mNeutralSets.push_back(id);
break;
}
case ESM4::SUB_XNAM:
{
FormId id;
reader.getFormId(id);
mFriendSets.push_back(id);
break;
}
case ESM4::SUB_ZNAM:
{
FormId id;
reader.getFormId(id);
mAllySets.push_back(id);
break;
}
case ESM4::SUB_RNAM: reader.getFormId(mConditionalFaction); break;
case ESM4::SUB_NAM1:
{
reader.get(mMediaFlags);
std::uint8_t flags = mMediaFlags.loopingOptions;
mMediaFlags.loopingOptions = (flags & 0xF0) >> 4;
mMediaFlags.factionNotFound = flags & 0x0F; // WARN: overwriting data
break;
}
case ESM4::SUB_NAM4: reader.get(mLocationDelay); break;
case ESM4::SUB_NAM7: reader.get(mRetriggerDelay); break;
case ESM4::SUB_NAM5: reader.get(mDayStart); break;
case ESM4::SUB_NAM6: reader.get(mNightStart); break;
case ESM4::SUB_NAM2: // always 0? 4 bytes
case ESM4::SUB_NAM3: // always 0? 4 bytes
case ESM4::SUB_FNAM: // always 0? 4 bytes
{
#if 0
boost::scoped_array<unsigned char> mDataBuf(new unsigned char[subHdr.dataSize]);
reader.get(&mDataBuf[0], subHdr.dataSize);
std::ostringstream ss;
ss << mEditorId << " " << ESM::printName(subHdr.typeId) << ":size " << subHdr.dataSize << "\n";
for (std::size_t i = 0; i < subHdr.dataSize; ++i)
{
//if (mDataBuf[i] > 64 && mDataBuf[i] < 91) // looks like printable ascii char
//ss << (char)(mDataBuf[i]) << " ";
//else
ss << std::setfill('0') << std::setw(2) << std::hex << (int)(mDataBuf[i]);
if ((i & 0x000f) == 0xf) // wrap around
ss << "\n";
else if (i < subHdr.dataSize-1)
ss << " ";
}
std::cout << ss.str() << std::endl;
#else
//std::cout << "ALOC " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
reader.skipSubRecordData();
#endif
break;
}
default:
//std::cout << "ALOC " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
//reader.skipSubRecordData();
throw std::runtime_error("ESM4::ALOC::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::MediaLocationController::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::MediaLocationController::blank()
//{
//}

@ -0,0 +1,88 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_ALOC_H
#define ESM4_ALOC_H
#include <cstdint>
#include <string>
#include <vector>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
#pragma pack(push, 1)
struct MLC_Flags
{
// use day/night transition: 0 = loop, 1 = random, 2 = retrigger, 3 = none
// use defaults (6:00/23:54): 4 = loop, 5 = random, 6 = retrigger, 7 = none
std::uint8_t loopingOptions;
// 0 = neutral, 1 = enemy, 2 = ally, 3 = friend, 4 = location, 5 = none
std::uint8_t factionNotFound; // WARN: overwriting whatever is in this
std::uint16_t unknown; // padding?
};
#pragma pack(pop)
struct MediaLocationController
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::vector<FormId> mBattleSets;
std::vector<FormId> mLocationSets;
std::vector<FormId> mEnemySets;
std::vector<FormId> mNeutralSets;
std::vector<FormId> mFriendSets;
std::vector<FormId> mAllySets;
MLC_Flags mMediaFlags;
FormId mConditionalFaction;
float mLocationDelay;
float mRetriggerDelay;
std::uint32_t mDayStart;
std::uint32_t mNightStart;
MediaLocationController();
virtual ~MediaLocationController();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_ALOC_H

@ -0,0 +1,133 @@
/*
Copyright (C) 2016, 2018-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadammo.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Ammunition::Ammunition() : mFormId(0), mFlags(0), mPickUpSound(0), mDropSound(0), mBoundRadius(0.f)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mText.clear();
mIcon.clear();
mMiniIcon.clear();
}
ESM4::Ammunition::~Ammunition()
{
}
void ESM4::Ammunition::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
std::uint32_t esmVer = reader.esmVersion();
bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_DATA:
{
//if (reader.esmVersion() == ESM::VER_094 || reader.esmVersion() == ESM::VER_170)
if (subHdr.dataSize == 16) // FO3 has 13 bytes even though VER_094
{
FormId projectile;
reader.get(projectile); // FIXME: add to mData
reader.get(mData.flags);
reader.get(mData.weight);
float damageInFloat;
reader.get(damageInFloat); // FIXME: add to mData
}
else if (isFONV || subHdr.dataSize == 13)
{
reader.get(mData.speed);
std::uint8_t flags;
reader.get(flags);
mData.flags = flags;
static std::uint8_t dummy;
reader.get(dummy);
reader.get(dummy);
reader.get(dummy);
reader.get(mData.value);
reader.get(mData.clipRounds);
}
else // TES4
{
reader.get(mData.speed);
reader.get(mData.flags);
reader.get(mData.value);
reader.get(mData.weight);
reader.get(mData.damage);
}
break;
}
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
case ESM4::SUB_MICO: reader.getZString(mMiniIcon); break; // FO3
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_ANAM: reader.get(mEnchantmentPoints); break;
case ESM4::SUB_ENAM: reader.getFormId(mEnchantment); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_DESC: reader.getLocalizedString(mText); break;
case ESM4::SUB_YNAM: reader.getFormId(mPickUpSound); break;
case ESM4::SUB_ZNAM: reader.getFormId(mDropSound); break;
case ESM4::SUB_MODT:
case ESM4::SUB_OBND:
case ESM4::SUB_KSIZ:
case ESM4::SUB_KWDA:
case ESM4::SUB_ONAM: // FO3
case ESM4::SUB_DAT2: // FONV
case ESM4::SUB_QNAM: // FONV
case ESM4::SUB_RCIL: // FONV
case ESM4::SUB_SCRI: // FONV
{
//std::cout << "AMMO " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::AMMO::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Ammunition::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Ammunition::blank()
//{
//}

@ -0,0 +1,84 @@
/*
Copyright (C) 2016, 2018-2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_AMMO_H
#define ESM4_AMMO_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Ammunition
{
struct Data // FIXME: TES5 projectile, damage (float)
{
float speed;
std::uint32_t flags;
std::uint32_t value; // gold
float weight;
std::uint16_t damage;
std::uint8_t clipRounds; // only in FO3/FONV
Data() : speed(0.f), flags(0), value(0), weight(0.f), damage(0), clipRounds(0) {}
};
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
std::string mText;
std::string mIcon; // inventory
std::string mMiniIcon; // inventory
FormId mPickUpSound;
FormId mDropSound;
float mBoundRadius;
std::uint16_t mEnchantmentPoints;
FormId mEnchantment;
Data mData;
Ammunition();
virtual ~Ammunition();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_AMMO_H

@ -0,0 +1,80 @@
/*
Copyright (C) 2016, 2018 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadanio.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::AnimObject::AnimObject() : mFormId(0), mFlags(0), mBoundRadius(0.f), mIdleAnim(0)
{
mEditorId.clear();
mModel.clear();
mUnloadEvent.clear();
}
ESM4::AnimObject::~AnimObject()
{
}
void ESM4::AnimObject::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_BNAM: reader.getZString(mUnloadEvent); break;
case ESM4::SUB_DATA: reader.getFormId(mIdleAnim); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_MODT: // TES5 only
case ESM4::SUB_MODS: // TES5 only
{
//std::cout << "ANIO " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::ANIO::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::AnimObject::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::AnimObject::blank()
//{
//}

@ -0,0 +1,63 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_ANIO_H
#define ESM4_ANIO_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct AnimObject
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mModel;
float mBoundRadius;
FormId mIdleAnim; // only in TES4
std::string mUnloadEvent; // only in TES5
AnimObject();
virtual ~AnimObject();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_ANIO_H

@ -0,0 +1,106 @@
/*
Copyright (C) 2016, 2018-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadappa.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Apparatus::Apparatus() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScriptId(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mText.clear();
mIcon.clear();
mData.type = 0;
mData.value = 0;
mData.weight = 0.f;
mData.quality = 0.f;
}
ESM4::Apparatus::~Apparatus()
{
}
void ESM4::Apparatus::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_DATA:
{
if (reader.esmVersion() == ESM::VER_094 || reader.esmVersion() == ESM::VER_170)
{
reader.get(mData.value);
reader.get(mData.weight);
}
else
{
reader.get(mData.type);
reader.get(mData.value);
reader.get(mData.weight);
reader.get(mData.quality);
}
break;
}
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_DESC: reader.getLocalizedString(mText); break;
case ESM4::SUB_MODT:
case ESM4::SUB_OBND:
case ESM4::SUB_QUAL:
{
//std::cout << "APPA " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::APPA::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Apparatus::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Apparatus::blank()
//{
//}

@ -0,0 +1,75 @@
/*
Copyright (C) 2016, 2018-2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_APPA_H
#define ESM4_APPA_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Apparatus
{
struct Data
{
std::uint8_t type; // 0 = Mortar and Pestle, 1 = Alembic, 2 = Calcinator, 3 = Retort
std::uint32_t value; // gold
float weight;
float quality;
};
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
std::string mText;
std::string mIcon; // inventory
float mBoundRadius;
FormId mScriptId;
Data mData;
Apparatus();
virtual ~Apparatus();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_APPA_H

@ -0,0 +1,151 @@
/*
Copyright (C) 2019, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadarma.hpp"
#include <stdexcept>
//#include <iostream> // FIXME: testing only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::ArmorAddon::ArmorAddon() : mFormId(0), mFlags(0), mTextureMale(0), mTextureFemale(0),
mRacePrimary(0)
{
mEditorId.clear();
mModelMale.clear();
mModelFemale.clear();
}
ESM4::ArmorAddon::~ArmorAddon()
{
}
void ESM4::ArmorAddon::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
std::uint32_t esmVer = reader.esmVersion();
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_MOD2: reader.getZString(mModelMale); break;
case ESM4::SUB_MOD3: reader.getZString(mModelFemale); break;
case ESM4::SUB_MOD4:
case ESM4::SUB_MOD5:
{
std::string model;
reader.getZString(model);
//std::cout << mEditorId << " " << ESM::printName(subHdr.typeId) << " " << model << std::endl;
break;
}
case ESM4::SUB_NAM0: reader.getFormId(mTextureMale); break;
case ESM4::SUB_NAM1: reader.getFormId(mTextureFemale); break;
case ESM4::SUB_RNAM: reader.getFormId(mRacePrimary); break;
case ESM4::SUB_MODL:
{
if ((esmVer == ESM::VER_094 || esmVer == ESM::VER_170) && subHdr.dataSize == 4) // TES5
{
FormId formId;
reader.getFormId(formId);
mRaces.push_back(formId);
}
else
reader.skipSubRecordData(); // FIXME: this should be mModelMale for FO3/FONV
break;
}
case ESM4::SUB_BODT: // body template
{
reader.get(mBodyTemplate.bodyPart);
reader.get(mBodyTemplate.flags);
reader.get(mBodyTemplate.unknown1); // probably padding
reader.get(mBodyTemplate.unknown2); // probably padding
reader.get(mBodyTemplate.unknown3); // probably padding
reader.get(mBodyTemplate.type);
break;
}
case ESM4::SUB_BOD2: // TES5
{
reader.get(mBodyTemplate.bodyPart);
mBodyTemplate.flags = 0;
mBodyTemplate.unknown1 = 0; // probably padding
mBodyTemplate.unknown2 = 0; // probably padding
mBodyTemplate.unknown3 = 0; // probably padding
reader.get(mBodyTemplate.type);
break;
}
case ESM4::SUB_DNAM:
case ESM4::SUB_MO2T: // FIXME: should group with MOD2
case ESM4::SUB_MO2S: // FIXME: should group with MOD2
case ESM4::SUB_MO3T: // FIXME: should group with MOD3
case ESM4::SUB_MO3S: // FIXME: should group with MOD3
case ESM4::SUB_MOSD: // FO3 // FIXME: should group with MOD3
case ESM4::SUB_MO4T: // FIXME: should group with MOD4
case ESM4::SUB_MO4S: // FIXME: should group with MOD4
case ESM4::SUB_MO5T:
case ESM4::SUB_NAM2: // txst formid male
case ESM4::SUB_NAM3: // txst formid female
case ESM4::SUB_SNDD: // footset sound formid
case ESM4::SUB_BMDT: // FO3
case ESM4::SUB_DATA: // FO3
case ESM4::SUB_ETYP: // FO3
case ESM4::SUB_FULL: // FO3
case ESM4::SUB_ICO2: // FO3 // female
case ESM4::SUB_ICON: // FO3 // male
case ESM4::SUB_MODT: // FO3 // FIXME: should group with MODL
case ESM4::SUB_MODS: // FO3 // FIXME: should group with MODL
case ESM4::SUB_MODD: // FO3 // FIXME: should group with MODL
case ESM4::SUB_OBND: // FO3
{
//std::cout << "ARMA " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::ARMA::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::ArmorAddon::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::ArmorAddon::blank()
//{
//}

@ -0,0 +1,70 @@
/*
Copyright (C) 2019, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_ARMA_H
#define ESM4_ARMA_H
#include <cstdint>
#include <string>
#include <vector>
#include "formid.hpp"
#include "actor.hpp" // BodyTemplate
namespace ESM4
{
class Reader;
class Writer;
struct ArmorAddon
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mModelMale;
std::string mModelFemale;
FormId mTextureMale;
FormId mTextureFemale;
FormId mRacePrimary;
std::vector<FormId> mRaces; // TES5 only
BodyTemplate mBodyTemplate; // TES5
ArmorAddon();
virtual ~ArmorAddon();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_ARMA_H

@ -0,0 +1,218 @@
/*
Copyright (C) 2016, 2018-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadarmo.hpp"
#include <stdexcept>
//#include <iostream> // FIXME: testing only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Armor::Armor() : mFormId(0), mFlags(0), mIsTES4(false), mIsFO3(false), mIsFONV(false),
mPickUpSound(0), mDropSound(0), mBoundRadius(0.f),
mArmorFlags(0), mGeneralFlags(0), mScriptId(0), mEnchantmentPoints(0), mEnchantment(0)
{
mEditorId.clear();
mFullName.clear();
mModelMale.clear();
mModelMaleWorld.clear();
mModelFemale.clear();
mModelFemaleWorld.clear();
mText.clear();
mIconMale.clear();
mMiniIconMale.clear();
mIconFemale.clear();
mMiniIconFemale.clear();
mData.armor = 0;
mData.value = 0;
mData.health = 0;
mData.weight = 0.f;
}
ESM4::Armor::~Armor()
{
}
void ESM4::Armor::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
std::uint32_t esmVer = reader.esmVersion();
mIsFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_DATA:
{
//if (reader.esmVersion() == ESM::VER_094 || reader.esmVersion() == ESM::VER_170)
if (subHdr.dataSize == 8) // FO3 has 12 bytes even though VER_094
{
reader.get(mData.value);
reader.get(mData.weight);
mIsFO3 = true;
}
else if (mIsFONV || subHdr.dataSize == 12)
{
reader.get(mData.value);
reader.get(mData.health);
reader.get(mData.weight);
}
else
{
reader.get(mData); // TES4
mIsTES4 = true;
}
break;
}
case ESM4::SUB_MODL: // seems only for Dawnguard/Dragonborn?
{
//if (esmVer == ESM::VER_094 || esmVer == ESM::VER_170 || isFONV)
if (subHdr.dataSize == 4) // FO3 has zstring even though VER_094
{
FormId formId;
reader.getFormId(formId);
mAddOns.push_back(formId);
}
else
{
if (!reader.getZString(mModelMale))
throw std::runtime_error ("ARMO MODL data read error");
}
break;
}
case ESM4::SUB_MOD2: reader.getZString(mModelMaleWorld);break;
case ESM4::SUB_MOD3: reader.getZString(mModelFemale); break;
case ESM4::SUB_MOD4: reader.getZString(mModelFemaleWorld); break;
case ESM4::SUB_ICON: reader.getZString(mIconMale); break;
case ESM4::SUB_MICO: reader.getZString(mMiniIconMale); break;
case ESM4::SUB_ICO2: reader.getZString(mIconFemale); break;
case ESM4::SUB_MIC2: reader.getZString(mMiniIconFemale); break;
case ESM4::SUB_BMDT:
{
if (subHdr.dataSize == 8) // FO3
{
reader.get(mArmorFlags);
reader.get(mGeneralFlags);
mGeneralFlags &= 0x000000ff;
mGeneralFlags |= TYPE_FO3;
}
else // TES4
{
reader.get(mArmorFlags);
mGeneralFlags = (mArmorFlags & 0x00ff0000) >> 16;
mGeneralFlags |= TYPE_TES4;
}
break;
}
case ESM4::SUB_BODT:
{
reader.get(mArmorFlags);
uint32_t flags = 0;
if (subHdr.dataSize == 12)
reader.get(flags);
reader.get(mGeneralFlags); // skill
mGeneralFlags &= 0x0000000f; // 0 (light), 1 (heavy) or 2 (none)
if (subHdr.dataSize == 12)
mGeneralFlags |= (flags & 0x0000000f) << 3;
mGeneralFlags |= TYPE_TES5;
break;
}
case ESM4::SUB_BOD2:
{
reader.get(mArmorFlags);
reader.get(mGeneralFlags);
mGeneralFlags &= 0x0000000f; // 0 (light), 1 (heavy) or 2 (none)
mGeneralFlags |= TYPE_TES5;
break;
}
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_ANAM: reader.get(mEnchantmentPoints); break;
case ESM4::SUB_ENAM: reader.getFormId(mEnchantment); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_DESC: reader.getLocalizedString(mText); break;
case ESM4::SUB_YNAM: reader.getFormId(mPickUpSound); break;
case ESM4::SUB_ZNAM: reader.getFormId(mDropSound); break;
case ESM4::SUB_MODT:
case ESM4::SUB_MO2B:
case ESM4::SUB_MO3B:
case ESM4::SUB_MO4B:
case ESM4::SUB_MO2T:
case ESM4::SUB_MO2S:
case ESM4::SUB_MO3T:
case ESM4::SUB_MO4T:
case ESM4::SUB_MO4S:
case ESM4::SUB_OBND:
case ESM4::SUB_RNAM: // race formid
case ESM4::SUB_KSIZ:
case ESM4::SUB_KWDA:
case ESM4::SUB_TNAM:
case ESM4::SUB_DNAM:
case ESM4::SUB_BAMT:
case ESM4::SUB_BIDS:
case ESM4::SUB_ETYP:
case ESM4::SUB_BMCT:
case ESM4::SUB_EAMT:
case ESM4::SUB_EITM:
case ESM4::SUB_VMAD:
case ESM4::SUB_REPL: // FO3
case ESM4::SUB_BIPL: // FO3
case ESM4::SUB_MODD: // FO3
case ESM4::SUB_MOSD: // FO3
case ESM4::SUB_MODS: // FO3
case ESM4::SUB_MO3S: // FO3
case ESM4::SUB_BNAM: // FONV
case ESM4::SUB_SNAM: // FONV
{
//std::cout << "ARMO " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::ARMO::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
//if ((mArmorFlags&0xffff) == 0x02) // only hair
//std::cout << "only hair " << mEditorId << std::endl;
}
//void ESM4::Armor::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Armor::blank()
//{
//}

@ -0,0 +1,196 @@
/*
Copyright (C) 2016, 2018-2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_ARMO_H
#define ESM4_ARMO_H
#include <cstdint>
#include <string>
#include <vector>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Armor
{
// WARN: TES4 Armorflags still has the general flags high bits
enum ArmorFlags
{
TES4_Head = 0x00000001,
TES4_Hair = 0x00000002,
TES4_UpperBody = 0x00000004,
TES4_LowerBody = 0x00000008,
TES4_Hands = 0x00000010,
TES4_Feet = 0x00000020,
TES4_RightRing = 0x00000040,
TES4_LeftRing = 0x00000080,
TES4_Amulet = 0x00000100,
TES4_Weapon = 0x00000200,
TES4_BackWeapon = 0x00000400,
TES4_SideWeapon = 0x00000800,
TES4_Quiver = 0x00001000,
TES4_Shield = 0x00002000,
TES4_Torch = 0x00004000,
TES4_Tail = 0x00008000,
//
FO3_Head = 0x00000001,
FO3_Hair = 0x00000002,
FO3_UpperBody = 0x00000004,
FO3_LeftHand = 0x00000008,
FO3_RightHand = 0x00000010,
FO3_Weapon = 0x00000020,
FO3_PipBoy = 0x00000040,
FO3_Backpack = 0x00000080,
FO3_Necklace = 0x00000100,
FO3_Headband = 0x00000200,
FO3_Hat = 0x00000400,
FO3_EyeGlasses = 0x00000800,
FO3_NoseRing = 0x00001000,
FO3_Earrings = 0x00002000,
FO3_Mask = 0x00004000,
FO3_Choker = 0x00008000,
FO3_MouthObject = 0x00010000,
FO3_BodyAddOn1 = 0x00020000,
FO3_BodyAddOn2 = 0x00040000,
FO3_BodyAddOn3 = 0x00080000,
//
TES5_Head = 0x00000001,
TES5_Hair = 0x00000002,
TES5_Body = 0x00000004,
TES5_Hands = 0x00000008,
TES5_Forearms = 0x00000010,
TES5_Amulet = 0x00000020,
TES5_Ring = 0x00000040,
TES5_Feet = 0x00000080,
TES5_Calves = 0x00000100,
TES5_Shield = 0x00000200,
TES5_Tail = 0x00000400,
TES5_LongHair = 0x00000800,
TES5_Circlet = 0x00001000,
TES5_Ears = 0x00002000,
TES5_BodyAddOn3 = 0x00004000,
TES5_BodyAddOn4 = 0x00008000,
TES5_BodyAddOn5 = 0x00010000,
TES5_BodyAddOn6 = 0x00020000,
TES5_BodyAddOn7 = 0x00040000,
TES5_BodyAddOn8 = 0x00080000,
TES5_DecapHead = 0x00100000,
TES5_Decapitate = 0x00200000,
TES5_BodyAddOn9 = 0x00400000,
TES5_BodyAddOn10 = 0x00800000,
TES5_BodyAddOn11 = 0x01000000,
TES5_BodyAddOn12 = 0x02000000,
TES5_BodyAddOn13 = 0x04000000,
TES5_BodyAddOn14 = 0x08000000,
TES5_BodyAddOn15 = 0x10000000,
TES5_BodyAddOn16 = 0x20000000,
TES5_BodyAddOn17 = 0x40000000,
TES5_FX01 = 0x80000000
};
enum GeneralFlags
{
TYPE_TES4 = 0x1000,
TYPE_FO3 = 0x2000,
TYPE_TES5 = 0x3000,
TYPE_FONV = 0x4000,
//
TES4_HideRings = 0x0001,
TES4_HideAmulet = 0x0002,
TES4_NonPlayable = 0x0040,
TES4_HeavyArmor = 0x0080,
//
FO3_PowerArmor = 0x0020,
FO3_NonPlayable = 0x0040,
FO3_HeavyArmor = 0x0080,
//
TES5_LightArmor = 0x0000,
TES5_HeavyArmor = 0x0001,
TES5_None = 0x0002,
TES5_ModVoice = 0x0004, // note bit shift
TES5_NonPlayable = 0x0040 // note bit shift
};
#pragma pack(push, 1)
struct Data
{
std::uint16_t armor; // only in TES4?
std::uint32_t value;
std::uint32_t health; // not in TES5?
float weight;
};
#pragma pack(pop)
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
bool mIsTES4; // TODO: check that these match the general flags
bool mIsFO3;
bool mIsFONV;
std::string mEditorId;
std::string mFullName;
std::string mModelMale;
std::string mModelMaleWorld;
std::string mModelFemale;
std::string mModelFemaleWorld;
std::string mText;
std::string mIconMale;
std::string mMiniIconMale;
std::string mIconFemale;
std::string mMiniIconFemale;
FormId mPickUpSound;
FormId mDropSound;
std::string mModel; // FIXME: for OpenCS
float mBoundRadius;
std::uint32_t mArmorFlags;
std::uint32_t mGeneralFlags;
FormId mScriptId;
std::uint16_t mEnchantmentPoints;
FormId mEnchantment;
std::vector<FormId> mAddOns; // TES5 ARMA
Data mData;
Armor();
virtual ~Armor();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_ARMO_H

@ -0,0 +1,94 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadaspc.hpp"
#include <stdexcept>
//#include <iostream> // FIXME: for debugging only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::AcousticSpace::AcousticSpace() : mFormId(0), mFlags(0), mEnvironmentType(0), mSoundRegion(0),
mIsInterior(0)
{
mEditorId.clear();
}
ESM4::AcousticSpace::~AcousticSpace()
{
}
void ESM4::AcousticSpace::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_ANAM: reader.get(mEnvironmentType); break;
case ESM4::SUB_SNAM:
{
FormId id;
reader.getFormId(id);
mAmbientLoopSounds.push_back(id);
break;
}
case ESM4::SUB_RDAT: reader.getFormId(mSoundRegion); break;
case ESM4::SUB_INAM: reader.get(mIsInterior); break;
case ESM4::SUB_WNAM: // usually 0 for FONV (maybe # of close Actors for Walla to trigger)
{
std::uint32_t dummy;
reader.get(dummy);
//std::cout << "WNAM " << mEditorId << " " << dummy << std::endl;
break;
}
case ESM4::SUB_BNAM: // TES5 reverb formid
case ESM4::SUB_OBND:
{
//std::cout << "ASPC " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::ASPC::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::AcousticSpace::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::AcousticSpace::blank()
//{
//}

@ -0,0 +1,66 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_ASPC_H
#define ESM4_ASPC_H
#include <cstdint>
#include <string>
#include <vector>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct AcousticSpace
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::uint32_t mEnvironmentType;
// 0 Dawn (5:00 start), 1 Afternoon (8:00), 2 Dusk (18:00), 3 Night (20:00)
std::vector<FormId> mAmbientLoopSounds;
FormId mSoundRegion;
std::uint32_t mIsInterior; // if true only use mAmbientLoopSounds[0]
AcousticSpace();
virtual ~AcousticSpace();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_ASPC_H

@ -0,0 +1,121 @@
/*
Copyright (C) 2016, 2018, 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadbook.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Book::Book() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScriptId(0),
mEnchantmentPoints(0), mEnchantment(0), mPickUpSound(0), mDropSound(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mText.clear();
mIcon.clear();
mData.flags = 0;
mData.type = 0;
mData.bookSkill = 0;
mData.value = 0;
mData.weight = 0.f;
}
ESM4::Book::~Book()
{
}
void ESM4::Book::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
//std::uint32_t esmVer = reader.esmVersion(); // currently unused
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_DESC: reader.getLocalizedString(mText); break;
case ESM4::SUB_DATA:
{
reader.get(mData.flags);
//if (reader.esmVersion() == ESM::VER_094 || reader.esmVersion() == ESM::VER_170)
if (subHdr.dataSize == 16) // FO3 has 10 bytes even though VER_094
{
static std::uint8_t dummy;
reader.get(mData.type);
reader.get(dummy);
reader.get(dummy);
reader.get(mData.teaches);
}
else
{
reader.get(mData.bookSkill);
}
reader.get(mData.value);
reader.get(mData.weight);
break;
}
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_ANAM: reader.get(mEnchantmentPoints); break;
case ESM4::SUB_ENAM: reader.getFormId(mEnchantment); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_YNAM: reader.getFormId(mPickUpSound); break;
case ESM4::SUB_ZNAM: reader.getFormId(mDropSound); break; // TODO: does this exist?
case ESM4::SUB_MODT:
case ESM4::SUB_OBND:
case ESM4::SUB_KSIZ:
case ESM4::SUB_KWDA:
case ESM4::SUB_CNAM:
case ESM4::SUB_INAM:
case ESM4::SUB_VMAD:
{
//std::cout << "BOOK " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::BOOK::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Book::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Book::blank()
//{
//}

@ -0,0 +1,114 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_BOOK_H
#define ESM4_BOOK_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Book
{
enum Flags
{
Flag_Scroll = 0x0001,
Flag_NoTake = 0x0002
};
enum BookSkill // for TES4 only
{
BookSkill_None = -1,
BookSkill_Armorer = 0,
BookSkill_Athletics = 1,
BookSkill_Blade = 2,
BookSkill_Block = 3,
BookSkill_Blunt = 4,
BookSkill_HandToHand = 5,
BookSkill_HeavyArmor = 6,
BookSkill_Alchemy = 7,
BookSkill_Alteration = 8,
BookSkill_Conjuration = 9,
BookSkill_Destruction = 10,
BookSkill_Illusion = 11,
BookSkill_Mysticism = 12,
BookSkill_Restoration = 13,
BookSkill_Acrobatics = 14,
BookSkill_LightArmor = 15,
BookSkill_Marksman = 16,
BookSkill_Mercantile = 17,
BookSkill_Security = 18,
BookSkill_Sneak = 19,
BookSkill_Speechcraft = 20
};
struct Data
{
std::uint8_t flags;
std::uint8_t type; // TES5 only
std::uint32_t teaches; // TES5 only
std::int8_t bookSkill; // not in TES5
std::uint32_t value;
float weight;
};
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
float mBoundRadius;
std::string mText;
FormId mScriptId;
std::string mIcon;
std::uint16_t mEnchantmentPoints;
FormId mEnchantment;
Data mData;
FormId mPickUpSound;
FormId mDropSound;
Book();
virtual ~Book();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_BOOK_H

@ -0,0 +1,113 @@
/*
Copyright (C) 2019-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadbptd.hpp"
#include <stdexcept>
#include <iostream> // FIXME: testing only
#include "reader.hpp"
//#include "writer.hpp"
void ESM4::BodyPartData::BodyPart::clear()
{
mPartName.clear();
mNodeName.clear();
mVATSTarget.clear();
mIKStartNode.clear();
std::memset(&mData, 0, sizeof(BPND));
mLimbReplacementModel.clear();
mGoreEffectsTarget.clear();
}
ESM4::BodyPartData::BodyPartData() : mFormId(0), mFlags(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
}
ESM4::BodyPartData::~BodyPartData()
{
}
void ESM4::BodyPartData::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
BodyPart bodyPart;
bodyPart.clear();
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_BPTN: reader.getLocalizedString(bodyPart.mPartName); break;
case ESM4::SUB_BPNN: reader.getZString(bodyPart.mNodeName); break;
case ESM4::SUB_BPNT: reader.getZString(bodyPart.mVATSTarget); break;
case ESM4::SUB_BPNI: reader.getZString(bodyPart.mIKStartNode); break;
case ESM4::SUB_BPND: reader.get(bodyPart.mData); break;
case ESM4::SUB_NAM1: reader.getZString(bodyPart.mLimbReplacementModel); break;
case ESM4::SUB_NAM4: // FIXME: assumed occurs last
{
reader.getZString(bodyPart.mGoreEffectsTarget); // target bone
mBodyParts.push_back(bodyPart); // FIXME: possible without copying?
bodyPart.clear();
break;
}
case ESM4::SUB_NAM5:
case ESM4::SUB_RAGA: // ragdoll
case ESM4::SUB_MODS:
case ESM4::SUB_MODT:
{
//std::cout << "BPTD " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::BPTD::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
//if (mEditorId == "DefaultBodyPartData")
//std::cout << "BPTD: " << mEditorId << std::endl; // FIXME: testing only
}
//void ESM4::BodyPartData::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::BodyPartData::blank()
//{
//}

@ -0,0 +1,128 @@
/*
Copyright (C) 2019, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_BPTD_H
#define ESM4_BPTD_H
#include <vector>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct BodyPartData
{
#pragma pack(push, 1)
struct BPND
{
float damageMult;
// Severable
// IK Data
// IK Data - Biped Data
// Explodable
// IK Data - Is Head
// IK Data - Headtracking
// To Hit Chance - Absolute
std::uint8_t flags;
// Torso
// Head
// Eye
// LookAt
// Fly Grab
// Saddle
std::uint8_t partType;
std::uint8_t healthPercent;
std::int8_t actorValue; //(Actor Values)
std::uint8_t toHitChance;
std::uint8_t explExplosionChance; // %
std::uint16_t explDebrisCount;
FormId explDebris;
FormId explExplosion;
float trackingMaxAngle;
float explDebrisScale;
std::int32_t sevDebrisCount;
FormId sevDebris;
FormId sevExplosion;
float sevDebrisScale;
//Struct - Gore Effects Positioning
float transX;
float transY;
float transZ;
float rotX;
float rotY;
float rotZ;
FormId sevImpactDataSet;
FormId explImpactDataSet;
uint8_t sevDecalCount;
uint8_t explDecalCount;
uint16_t Unknown;
float limbReplacementScale;
};
#pragma pack(pop)
struct BodyPart
{
std::string mPartName;
std::string mNodeName;
std::string mVATSTarget;
std::string mIKStartNode;
BPND mData;
std::string mLimbReplacementModel;
std::string mGoreEffectsTarget;
void clear();
};
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
std::vector<BodyPart> mBodyParts;
BodyPartData();
virtual ~BodyPartData();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_BPTD_H

@ -0,0 +1,269 @@
/*
Copyright (C) 2015-2016, 2018-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadcell.hpp"
#ifdef NDEBUG // FIXME: debuggigng only
#undef NDEBUG
#endif
#include <cassert>
#include <stdexcept>
#include <cfloat> // FLT_MAX for gcc
#include <iostream> // FIXME: debug only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Cell::Cell() : mParent(0), mFormId(0), mFlags(0), mCellFlags(0), mX(0), mY(0), mOwner(0),
mGlobal(0), mClimate(0), mWater(0), mWaterHeight(0.f),
mLightingTemplate(0), mLightingTemplateFlags(0), mMusic(0), mAcousticSpace(0),
mMusicType(0), mPreloaded(false)
{
mEditorId.clear();
mFullName.clear();
mLighting.ambient = 0;
mLighting.directional = 0;
mLighting.fogColor = 0;
mLighting.fogNear = 0.f;
mLighting.fogFar = 0.f;
mLighting.rotationXY = 0;
mLighting.rotationZ = 0;
mLighting.fogDirFade = 0.f;
mLighting.fogClipDist = 0.f;
mLighting.fogPower = FLT_MAX; // hack way to detect TES4
mRegions.clear();
}
ESM4::Cell::~Cell()
{
}
void ESM4::Cell::init(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
mParent = reader.currWorld();
reader.clearCellGrid(); // clear until XCLC FIXME: somehow do this automatically?
// Sometimes cell 0,0 does not have an XCLC sub record (e.g. ToddLand 000009BF)
// To workaround this issue put a default value if group is "exterior sub cell" and its
// grid from label is "0 0". Note the reversed X/Y order (no matter since they're both 0
// anyway).
if (reader.grp().type == ESM4::Grp_ExteriorSubCell
&& reader.grp().label.grid[1] == 0 && reader.grp().label.grid[0] == 0)
{
ESM4::CellGrid currCellGrid;
currCellGrid.grid.x = 0;
currCellGrid.grid.y = 0;
reader.setCurrCellGrid(currCellGrid); // side effect: sets mCellGridValid true
}
}
// TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent)
//
// But, for external cells we may be scanning the whole record since we don't know if there is
// going to be an EDID subrecord. And the vast majority of cells are these kinds.
//
// So perhaps some testing needs to be done to see if scanning and skipping takes
// longer/shorter/same as loading the subrecords.
bool ESM4::Cell::preload(ESM4::Reader& reader)
{
if (!mPreloaded)
load(reader);
mPreloaded = true;
return true;
}
void ESM4::Cell::load(ESM4::Reader& reader)
{
if (mPreloaded)
return;
// WARN: we need to call setCurrCell (and maybe setCurrCellGrid?) again before loading
// cell child groups if we are loading them after restoring the context
// (may be easier to update the context before saving?)
init(reader);
reader.setCurrCell(mFormId); // save for LAND (and other children) to access later
std::uint32_t esmVer = reader.esmVersion();
bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID:
{
if (!reader.getZString(mEditorId))
throw std::runtime_error ("CELL EDID data read error");
#if 0
std::string padding = "";
padding.insert(0, reader.stackSize()*2, ' ');
std::cout << padding << "CELL Editor ID: " << mEditorId << std::endl;
#endif
break;
}
case ESM4::SUB_XCLC:
{
//(X, Y) grid location of the cell followed by flags. Always in
//exterior cells and never in interior cells.
//
// int32 - X
// int32 - Y
// uint32 - flags (high bits look random)
//
// 0x1 - Force Hide Land Quad 1
// 0x2 - Force Hide Land Quad 2
// 0x4 - Force Hide Land Quad 3
// 0x8 - Force Hide Land Quad 4
uint32_t flags;
reader.get(mX);
reader.get(mY);
#if 0
std::string padding = "";
padding.insert(0, reader.stackSize()*2, ' ');
std::cout << padding << "CELL group " << ESM4::printLabel(reader.grp().label, reader.grp().type) << std::endl;
std::cout << padding << "CELL formId " << std::hex << reader.hdr().record.id << std::endl;
std::cout << padding << "CELL X " << std::dec << mX << ", Y " << mY << std::endl;
#endif
if (esmVer == ESM::VER_094 || esmVer == ESM::VER_170 || isFONV)
if (subHdr.dataSize == 12)
reader.get(flags); // not in Obvlivion, nor FO3/FONV
// Remember cell grid for later (loading LAND, NAVM which should be CELL temporary children)
// Note that grids only apply for external cells. For interior cells use the cell's formid.
ESM4::CellGrid currCell;
currCell.grid.x = (int16_t)mX;
currCell.grid.y = (int16_t)mY;
reader.setCurrCellGrid(currCell);
break;
}
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_DATA:
{
if (esmVer == ESM::VER_094 || esmVer == ESM::VER_170 || isFONV)
if (subHdr.dataSize == 2)
reader.get(mCellFlags);
else
{
assert(subHdr.dataSize == 1 && "CELL unexpected DATA flag size");
reader.get(&mCellFlags, sizeof(std::uint8_t));
}
else
{
reader.get((std::uint8_t&)mCellFlags); // 8 bits in Obvlivion
}
#if 0
std::string padding = "";
padding.insert(0, reader.stackSize()*2, ' ');
std::cout << padding << "flags: " << std::hex << mCellFlags << std::endl;
#endif
break;
}
case ESM4::SUB_XCLR: // for exterior cells
{
mRegions.resize(subHdr.dataSize/sizeof(FormId));
for (std::vector<FormId>::iterator it = mRegions.begin(); it != mRegions.end(); ++it)
{
reader.getFormId(*it);
#if 0
std::string padding = "";
padding.insert(0, reader.stackSize()*2, ' ');
std::cout << padding << "region: " << std::hex << *it << std::endl;
#endif
}
break;
}
case ESM4::SUB_XOWN: reader.getFormId(mOwner); break;
case ESM4::SUB_XGLB: reader.getFormId(mGlobal); break; // Oblivion only?
case ESM4::SUB_XCCM: reader.getFormId(mClimate); break;
case ESM4::SUB_XCWT: reader.getFormId(mWater); break;
case ESM4::SUB_XCLW: reader.get(mWaterHeight); break;
case ESM4::SUB_XCLL:
{
if (esmVer == ESM::VER_094 || esmVer == ESM::VER_170 || isFONV)
{
if (subHdr.dataSize == 40) // FO3/FONV
reader.get(mLighting);
else if (subHdr.dataSize == 92) // TES5
{
reader.get(mLighting);
reader.skipSubRecordData(52); // FIXME
}
else
reader.skipSubRecordData();
}
else
reader.get(&mLighting, 36); // TES4
break;
}
case ESM4::SUB_XCMT: reader.get(mMusicType); break; // Oblivion only?
case ESM4::SUB_LTMP: reader.getFormId(mLightingTemplate); break;
case ESM4::SUB_LNAM: reader.get(mLightingTemplateFlags); break; // seems to always follow LTMP
case ESM4::SUB_XCMO: reader.getFormId(mMusic); break;
case ESM4::SUB_XCAS: reader.getFormId(mAcousticSpace); break;
case ESM4::SUB_TVDT:
case ESM4::SUB_MHDT:
case ESM4::SUB_XCGD:
case ESM4::SUB_XNAM:
case ESM4::SUB_XLCN:
case ESM4::SUB_XWCS:
case ESM4::SUB_XWCU:
case ESM4::SUB_XWCN:
case ESM4::SUB_XCIM:
case ESM4::SUB_XEZN:
case ESM4::SUB_XWEM:
case ESM4::SUB_XILL:
case ESM4::SUB_XRNK: // Oblivion only?
case ESM4::SUB_XCET: // FO3
case ESM4::SUB_IMPF: // FO3 Zeta
{
//std::cout << "CELL " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::CELL::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Cell::save(ESM4::Writer& writer) const
//{
//}
void ESM4::Cell::blank()
{
}

@ -0,0 +1,109 @@
/*
Copyright (C) 2015-2016, 2018-2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_CELL_H
#define ESM4_CELL_H
#include <cstdint>
#include <string>
#include <vector>
#include "formid.hpp"
#include "lighting.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct ReaderContext;
struct CellGroup;
typedef std::uint32_t FormId;
enum CellFlags // TES4 TES5
{ // ----------------------- ------------------------------------
CELL_Interior = 0x0001, // Can't travel from here Interior
CELL_HasWater = 0x0002, // Has water (Int) Has Water (Int)
CELL_NoTravel = 0x0004, // not Can't Travel From Here(Int only)
CELL_HideLand = 0x0008, // Force hide land (Ext) No LOD Water
// Oblivion interior (Int)
CELL_Public = 0x0020, // Public place Public Area
CELL_HandChgd = 0x0040, // Hand changed Hand Changed
CELL_QuasiExt = 0x0080, // Behave like exterior Show Sky
CELL_SkyLight = 0x0100 // Use Sky Lighting
};
// Unlike TES3, multiple cells can have the same exterior co-ordinates.
// The cells need to be organised under world spaces.
struct Cell
{
FormId mParent; // world formId (for grouping cells), from the loading sequence
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::uint16_t mCellFlags; // TES5 can also be 8 bits
std::int32_t mX;
std::int32_t mY;
FormId mOwner;
FormId mGlobal;
FormId mClimate;
FormId mWater;
float mWaterHeight;
std::vector<FormId> mRegions;
Lighting mLighting;
FormId mLightingTemplate; // FO3/FONV
std::uint32_t mLightingTemplateFlags; // FO3/FONV
FormId mMusic; // FO3/FONV
FormId mAcousticSpace; // FO3/FONV
// TES4: 0 = default, 1 = public, 2 = dungeon
// FO3/FONV have more types (not sure how they are used, however)
std::uint8_t mMusicType;
CellGroup *mCellGroup;
Cell();
virtual ~Cell();
void init(ESM4::Reader& reader); // common setup for both preload() and load()
bool mPreloaded;
bool preload(ESM4::Reader& reader);
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void blank();
};
}
#endif // ESM4_CELL_H

@ -0,0 +1,84 @@
/*
Copyright (C) 2016, 2018, 2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadclas.hpp"
//#ifdef NDEBUG // FIXME: debugging only
//#undef NDEBUG
//#endif
//#include <cassert>
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Class::Class()
{
mEditorId.clear();
mFullName.clear();
mDesc.clear();
mIcon.clear();
}
ESM4::Class::~Class()
{
}
void ESM4::Class::load(ESM4::Reader& reader)
{
//mFormId = reader.adjustFormId(reader.hdr().record.id); // FIXME: use master adjusted?
mFormId = reader.hdr().record.id;
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_DESC: reader.getLocalizedString(mDesc); break;
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
case ESM4::SUB_DATA:
{
//std::cout << "CLAS " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::CLAS::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Class::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Class::blank()
//{
//}

@ -0,0 +1,66 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_CLAS_H
#define ESM4_CLAS_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Class
{
struct Data
{
std::uint32_t attr;
};
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mDesc;
std::string mIcon;
Data mData;
Class();
~Class();
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& reader) const;
//void blank();
};
}
#endif // ESM4_CLAS_H

@ -0,0 +1,93 @@
/*
Copyright (C) 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadclfm.hpp"
#include <stdexcept>
#include <iostream> // FIXME: for debugging only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Colour::Colour() : mFormId(0), mFlags(0), mPlayable(0)
{
mEditorId.clear();
mFullName.clear();
mColour.red = 0;
mColour.green = 0;
mColour.blue = 0;
mColour.custom = 0;
}
ESM4::Colour::~Colour()
{
}
void ESM4::Colour::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_CNAM:
{
reader.get(mColour.red);
reader.get(mColour.green);
reader.get(mColour.blue);
reader.get(mColour.custom);
break;
}
case ESM4::SUB_FNAM:
{
reader.get(mPlayable);
break;
}
default:
//std::cout << "CLFM " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
//reader.skipSubRecordData();
throw std::runtime_error("ESM4::CLFM::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Colour::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Colour::blank()
//{
//}

@ -0,0 +1,70 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_CLFM_H
#define ESM4_CLFM_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
// FIXME: duplicate with Npc
struct ColourRGB
{
std::uint8_t red;
std::uint8_t green;
std::uint8_t blue;
std::uint8_t custom; // alpha?
};
struct Colour
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
ColourRGB mColour;
std::uint32_t mPlayable;
Colour();
virtual ~Colour();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_CLFM_H

@ -0,0 +1,106 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadclot.hpp"
#include <stdexcept>
//#include <iostream> // FIXME: for debugging only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Clothing::Clothing() : mFormId(0), mFlags(0), mBoundRadius(0.f), mClothingFlags(0),
mScriptId(0), mEnchantmentPoints(0), mEnchantment(0)
{
mEditorId.clear();
mFullName.clear();
mModelMale.clear();
mModelMaleWorld.clear();
mModelFemale.clear();
mModelFemaleWorld.clear();
mIconMale.clear();
mIconFemale.clear();
mData.value = 0;
mData.weight = 0.f;
}
ESM4::Clothing::~Clothing()
{
}
void ESM4::Clothing::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getZString(mFullName); break;
case ESM4::SUB_DATA: reader.get(mData); break;
case ESM4::SUB_BMDT: reader.get(mClothingFlags); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_ENAM: reader.getFormId(mEnchantment); break;
case ESM4::SUB_ANAM: reader.get(mEnchantmentPoints); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_MODL: reader.getZString(mModelMale); break;
case ESM4::SUB_MOD2: reader.getZString(mModelMaleWorld); break;
case ESM4::SUB_MOD3: reader.getZString(mModelFemale); break;
case ESM4::SUB_MOD4: reader.getZString(mModelFemaleWorld); break;
case ESM4::SUB_ICON: reader.getZString(mIconMale); break;
case ESM4::SUB_ICO2: reader.getZString(mIconFemale); break;
case ESM4::SUB_MODT:
case ESM4::SUB_MO2B:
case ESM4::SUB_MO3B:
case ESM4::SUB_MO4B:
case ESM4::SUB_MO2T:
case ESM4::SUB_MO3T:
case ESM4::SUB_MO4T:
{
//std::cout << "CLOT " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::CLOT::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
//if ((mClothingFlags&0xffff) == 0x02) // only hair
//std::cout << "only hair " << mEditorId << std::endl;
}
//void ESM4::Clothing::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Clothing::blank()
//{
//}

@ -0,0 +1,83 @@
/*
Copyright (C) 2016, 2018-2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_CLOT_H
#define ESM4_CLOT_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Clothing
{
#pragma pack(push, 1)
struct Data
{
std::uint32_t value; // gold
float weight;
};
#pragma pack(pop)
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModelMale;
std::string mModelMaleWorld;
std::string mModelFemale;
std::string mModelFemaleWorld;
std::string mIconMale; // texture
std::string mIconFemale; // texture
std::string mModel; // FIXME: for OpenCS
float mBoundRadius;
std::uint32_t mClothingFlags; // see Armor::ArmorFlags for the values
FormId mScriptId;
std::uint16_t mEnchantmentPoints;
FormId mEnchantment;
Data mData;
Clothing();
virtual ~Clothing();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_CLOT_H

@ -0,0 +1,107 @@
/*
Copyright (C) 2016, 2018, 2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadcont.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Container::Container() : mFormId(0), mFlags(0), mBoundRadius(0.f), mDataFlags(0), mWeight(0.f),
mOpenSound(0), mCloseSound(0), mScriptId(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
}
ESM4::Container::~Container()
{
}
void ESM4::Container::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_DATA:
{
reader.get(mDataFlags);
reader.get(mWeight);
break;
}
case ESM4::SUB_CNTO:
{
static InventoryItem inv; // FIXME: use unique_ptr here?
reader.get(inv);
reader.adjustFormId(inv.item);
mInventory.push_back(inv);
break;
}
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_SNAM: reader.getFormId(mOpenSound); break;
case ESM4::SUB_QNAM: reader.getFormId(mCloseSound); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_MODT:
case ESM4::SUB_MODS: // TES5 only
case ESM4::SUB_VMAD: // TES5 only
case ESM4::SUB_OBND: // TES5 only
case ESM4::SUB_COCT: // TES5 only
case ESM4::SUB_COED: // TES5 only
case ESM4::SUB_DEST: // FONV
case ESM4::SUB_DSTD: // FONV
case ESM4::SUB_DSTF: // FONV
case ESM4::SUB_DMDL: // FONV
case ESM4::SUB_DMDT: // FONV
case ESM4::SUB_RNAM: // FONV
{
//std::cout << "CONT " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::CONT::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Container::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Container::blank()
//{
//}

@ -0,0 +1,71 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_CONT_H
#define ESM4_CONT_H
#include <cstdint>
#include <string>
#include <vector>
#include "formid.hpp"
#include "inventory.hpp" // InventoryItem
namespace ESM4
{
class Reader;
class Writer;
struct Container
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
float mBoundRadius;
unsigned char mDataFlags;
float mWeight;
FormId mOpenSound;
FormId mCloseSound;
FormId mScriptId; // TES4 only
std::vector<InventoryItem> mInventory;
Container();
virtual ~Container();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_CONT_H

@ -0,0 +1,232 @@
/*
Copyright (C) 2016, 2018, 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadcrea.hpp"
#ifdef NDEBUG // FIXME: debuggigng only
#undef NDEBUG
#endif
#include <cassert>
#include <stdexcept>
#include <cstring>
#include <string>
#include <sstream>
#include <iostream> // FIXME
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Creature::Creature() : mFormId(0), mFlags(0), mDeathItem(0), mScriptId(0), mCombatStyle(0),
mSoundBase(0), mSound(0), mSoundChance(0), mBaseScale(0.f),
mTurningSpeed(0.f), mFootWeight(0.f), mBoundRadius(0.f)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mBloodSpray.clear();
mBloodDecal.clear();
mAIData.aggression = 0;
mAIData.confidence = 0;
mAIData.energyLevel = 0;
mAIData.responsibility = 0;
mAIData.aiFlags = 0;
mAIData.trainSkill = 0;
mAIData.trainLevel = 0;
std::memset(&mData, 0, sizeof(Data));
}
ESM4::Creature::~Creature()
{
}
void ESM4::Creature::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getZString(mFullName); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_CNTO:
{
static InventoryItem inv; // FIXME: use unique_ptr here?
reader.get(inv);
reader.adjustFormId(inv.item);
mInventory.push_back(inv);
break;
}
case ESM4::SUB_SPLO:
{
FormId id;
reader.getFormId(id);
mSpell.push_back(id);
break;
}
case ESM4::SUB_PKID:
{
FormId id;
reader.getFormId(id);
mAIPackages.push_back(id);
break;
}
case ESM4::SUB_SNAM:
{
reader.get(mFaction);
reader.adjustFormId(mFaction.faction);
break;
}
case ESM4::SUB_INAM: reader.getFormId(mDeathItem); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_AIDT:
{
if (subHdr.dataSize == 20) // FO3
reader.skipSubRecordData();
else
reader.get(mAIData); // 12 bytes
break;
}
case ESM4::SUB_ACBS:
{
//if (esmVer == ESM::VER_094 || esmVer == ESM::VER_170 || mIsFONV)
if (subHdr.dataSize == 24)
reader.get(mBaseConfig);
else
reader.get(&mBaseConfig, 16); // TES4
break;
}
case ESM4::SUB_DATA:
{
if (subHdr.dataSize == 17) // FO3
reader.skipSubRecordData();
else
reader.get(mData);
break;
}
case ESM4::SUB_ZNAM: reader.getFormId(mCombatStyle); break;
case ESM4::SUB_CSCR: reader.getFormId(mSoundBase); break;
case ESM4::SUB_CSDI: reader.getFormId(mSound); break;
case ESM4::SUB_CSDC: reader.get(mSoundChance); break;
case ESM4::SUB_BNAM: reader.get(mBaseScale); break;
case ESM4::SUB_TNAM: reader.get(mTurningSpeed); break;
case ESM4::SUB_WNAM: reader.get(mFootWeight); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_NAM0: reader.getZString(mBloodSpray); break;
case ESM4::SUB_NAM1: reader.getZString(mBloodDecal); break;
case ESM4::SUB_NIFZ:
{
std::string str;
if (!reader.getZString(str))
throw std::runtime_error ("CREA NIFZ data read error");
std::stringstream ss(str);
std::string file;
while (std::getline(ss, file, '\0')) // split the strings
mNif.push_back(file);
break;
}
case ESM4::SUB_NIFT:
{
if (subHdr.dataSize != 4) // FIXME: FO3
{
reader.skipSubRecordData();
break;
}
assert(subHdr.dataSize == 4 && "CREA NIFT datasize error");
std::uint32_t nift;
reader.get(nift);
if (nift)
std::cout << "CREA NIFT " << mFormId << ", non-zero " << nift << std::endl;
break;
}
case ESM4::SUB_KFFZ:
{
std::string str;
if (!reader.getZString(str))
throw std::runtime_error ("CREA KFFZ data read error");
std::stringstream ss(str);
std::string file;
while (std::getline(ss, file, '\0')) // split the strings
mKf.push_back(file);
break;
}
case ESM4::SUB_TPLT: reader.get(mBaseTemplate); break; // FO3
case ESM4::SUB_PNAM: // FO3/FONV/TES5
{
FormId bodyPart;
reader.get(bodyPart);
mBodyParts.push_back(bodyPart);
break;
}
case ESM4::SUB_MODT:
case ESM4::SUB_RNAM:
case ESM4::SUB_CSDT:
case ESM4::SUB_OBND: // FO3
case ESM4::SUB_EAMT: // FO3
case ESM4::SUB_VTCK: // FO3
case ESM4::SUB_NAM4: // FO3
case ESM4::SUB_NAM5: // FO3
case ESM4::SUB_CNAM: // FO3
case ESM4::SUB_LNAM: // FO3
case ESM4::SUB_EITM: // FO3
case ESM4::SUB_DEST: // FO3
case ESM4::SUB_DSTD: // FO3
case ESM4::SUB_DSTF: // FO3
case ESM4::SUB_DMDL: // FO3
case ESM4::SUB_DMDT: // FO3
case ESM4::SUB_COED: // FO3
{
//std::cout << "CREA " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::CREA::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Creature::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Creature::blank()
//{
//}

@ -0,0 +1,151 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_CREA_H
#define ESM4_CREA_H
#include <cstdint>
#include <string>
#include <vector>
#include "actor.hpp"
#include "inventory.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Creature
{
enum ACBS_TES4
{
TES4_Essential = 0x000002,
TES4_WeapAndShield = 0x000004,
TES4_Respawn = 0x000008,
TES4_PCLevelOffset = 0x000080,
TES4_NoLowLevelProc = 0x000200,
TES4_NoHead = 0x008000, // different meaning to npc_
TES4_NoRightArm = 0x010000,
TES4_NoLeftArm = 0x020000,
TES4_NoCombatWater = 0x040000,
TES4_NoShadow = 0x080000,
TES4_NoCorpseCheck = 0x100000 // opposite of npc_
};
enum ACBS_FO3
{
FO3_Biped = 0x00000001,
FO3_Essential = 0x00000002,
FO3_Weap_Shield = 0x00000004,
FO3_Respawn = 0x00000008,
FO3_CanSwim = 0x00000010,
FO3_CanFly = 0x00000020,
FO3_CanWalk = 0x00000040,
FO3_PCLevelMult = 0x00000080,
FO3_NoLowLevelProc = 0x00000200,
FO3_NoBloodSpray = 0x00000800,
FO3_NoBloodDecal = 0x00001000,
FO3_NoHead = 0x00008000,
FO3_NoRightArm = 0x00010000,
FO3_NoLeftArm = 0x00020000,
FO3_NoWaterCombat = 0x00040000,
FO3_NoShadow = 0x00080000,
FO3_NoVATSMelee = 0x00100000,
FO3_AllowPCDialog = 0x00200000,
FO3_NoOpenDoors = 0x00400000,
FO3_Immobile = 0x00800000,
FO3_TiltFrontBack = 0x01000000,
FO3_TiltLeftRight = 0x02000000,
FO3_NoKnockdown = 0x04000000,
FO3_NotPushable = 0x08000000,
FO3_AllowPickpoket = 0x10000000,
FO3_IsGhost = 0x20000000,
FO3_NoRotateHead = 0x40000000,
FO3_Invulnerable = 0x80000000
};
#pragma pack(push, 1)
struct Data
{
std::uint8_t unknown;
std::uint8_t combat;
std::uint8_t magic;
std::uint8_t stealth;
std::uint16_t soul;
std::uint16_t health;
std::uint16_t unknown2;
std::uint16_t damage;
AttributeValues attribs;
};
#pragma pack(pop)
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
FormId mDeathItem;
std::vector<FormId> mSpell;
FormId mScriptId;
AIData mAIData;
std::vector<FormId> mAIPackages;
ActorBaseConfig mBaseConfig;
ActorFaction mFaction;
Data mData;
FormId mCombatStyle;
FormId mSoundBase;
FormId mSound;
std::uint8_t mSoundChance;
float mBaseScale;
float mTurningSpeed;
float mFootWeight;
std::string mBloodSpray;
std::string mBloodDecal;
float mBoundRadius;
std::vector<std::string> mNif; // NIF filenames, get directory from mModel
std::vector<std::string> mKf;
std::vector<InventoryItem> mInventory;
FormId mBaseTemplate; // FO3/FONV
std::vector<FormId> mBodyParts; // FO3/FONV
Creature();
virtual ~Creature();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_CREA_H

@ -0,0 +1,125 @@
/*
Copyright (C) 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loaddial.hpp"
#include <stdexcept>
#include <cstring>
#include <iostream> // FIXME: for debugging only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Dialogue::Dialogue() : mFormId(0), mFlags(0), mDoAllBeforeRepeat(false),
mDialType(0), mDialFlags(0), mPriority(0.f)
{
mEditorId.clear();
mTopicName.clear();
mTextDumb.clear(); // FIXME: temp name
}
ESM4::Dialogue::~Dialogue()
{
}
void ESM4::Dialogue::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getZString(mTopicName); break;
case ESM4::SUB_QSTI:
{
FormId questId;
reader.getFormId(questId);
mQuests.push_back(questId);
break;
}
case ESM4::SUB_QSTR: // Seems never used in TES4
{
FormId questRem;
reader.getFormId(questRem);
mQuestsRemoved.push_back(questRem);
break;
}
case ESM4::SUB_DATA:
{
if (subHdr.dataSize == 4) // TES5
{
std::uint8_t dummy;
reader.get(dummy);
if (dummy != 0)
mDoAllBeforeRepeat = true;
}
reader.get(mDialType); // TES4/FO3/FONV/TES5
if (subHdr.dataSize >= 2) // FO3/FONV/TES5
reader.get(mDialFlags);
if (subHdr.dataSize >= 3) // TES5
reader.skipSubRecordData(1); // unknown
break;
}
case ESM4::SUB_PNAM: reader.get(mPriority); break; // FO3/FONV
case ESM4::SUB_TDUM: reader.getZString(mTextDumb); break; // FONV
case ESM4::SUB_SCRI:
case ESM4::SUB_INFC: // FONV info connection
case ESM4::SUB_INFX: // FONV info index
case ESM4::SUB_QNAM: // TES5
case ESM4::SUB_BNAM: // TES5
case ESM4::SUB_SNAM: // TES5
case ESM4::SUB_TIFC: // TES5
{
//std::cout << "DIAL " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::DIAL::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Dialogue::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Dialogue::blank()
//{
//}

@ -0,0 +1,70 @@
/*
Copyright (C) 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_DIAL_H
#define ESM4_DIAL_H
#include <cstdint>
#include <string>
#include <vector>
#include "formid.hpp"
#include "dialogue.hpp" // DialType
namespace ESM4
{
class Reader;
class Writer;
struct Dialogue
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::vector<FormId> mQuests;
std::vector<FormId> mQuestsRemoved; // FONV only?
std::string mTopicName;
std::string mTextDumb; // FIXME: temp name
bool mDoAllBeforeRepeat; // TES5 only
std::uint8_t mDialType; // DialType
std::uint8_t mDialFlags; // FO3/FONV: 0x1 rumours, 0x2 top-level
float mPriority;
Dialogue();
virtual ~Dialogue();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_DIAL_H

@ -0,0 +1,128 @@
/*
Copyright (C) 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
Also see https://tes5edit.github.io/fopdoc/ for FO3/FONV specific details.
*/
#include "loaddobj.hpp"
#include <stdexcept>
#include <cstring>
//#include <iostream> // FIXME: for debugging only
//#include "formid.hpp"
#include "reader.hpp"
//#include "writer.hpp"
ESM4::DefaultObj::DefaultObj() : mFormId(0), mFlags(0)
{
mEditorId.clear();
std::memset(&mData, 0, sizeof(Defaults));
}
ESM4::DefaultObj::~DefaultObj()
{
}
void ESM4::DefaultObj::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break; // "DefaultObjectManager"
case ESM4::SUB_DATA:
{
reader.getFormId(mData.stimpack);
reader.getFormId(mData.superStimpack);
reader.getFormId(mData.radX);
reader.getFormId(mData.radAway);
reader.getFormId(mData.morphine);
reader.getFormId(mData.perkParalysis);
reader.getFormId(mData.playerFaction);
reader.getFormId(mData.mysteriousStrangerNPC);
reader.getFormId(mData.mysteriousStrangerFaction);
reader.getFormId(mData.defaultMusic);
reader.getFormId(mData.battleMusic);
reader.getFormId(mData.deathMusic);
reader.getFormId(mData.successMusic);
reader.getFormId(mData.levelUpMusic);
reader.getFormId(mData.playerVoiceMale);
reader.getFormId(mData.playerVoiceMaleChild);
reader.getFormId(mData.playerVoiceFemale);
reader.getFormId(mData.playerVoiceFemaleChild);
reader.getFormId(mData.eatPackageDefaultFood);
reader.getFormId(mData.everyActorAbility);
reader.getFormId(mData.drugWearsOffImageSpace);
// below FONV only
if (subHdr.dataSize == 136) // FONV 136/4 = 34 formid
{
reader.getFormId(mData.doctorsBag);
reader.getFormId(mData.missFortuneNPC);
reader.getFormId(mData.missFortuneFaction);
reader.getFormId(mData.meltdownExplosion);
reader.getFormId(mData.unarmedForwardPA);
reader.getFormId(mData.unarmedBackwardPA);
reader.getFormId(mData.unarmedLeftPA);
reader.getFormId(mData.unarmedRightPA);
reader.getFormId(mData.unarmedCrouchPA);
reader.getFormId(mData.unarmedCounterPA);
reader.getFormId(mData.spotterEffect);
reader.getFormId(mData.itemDetectedEfect);
reader.getFormId(mData.cateyeMobileEffectNYI);
}
break;
}
case ESM4::SUB_DNAM:
{
//std::cout << "DOBJ " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
reader.skipSubRecordData();
break;
}
default:
//std::cout << "DOBJ " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
//reader.skipSubRecordData();
throw std::runtime_error("ESM4::DOBJ::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::DefaultObj::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::DefaultObj::blank()
//{
//}

@ -0,0 +1,100 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
Also see https://tes5edit.github.io/fopdoc/ for FO3/FONV specific details.
*/
#ifndef ESM4_DOBJ_H
#define ESM4_DOBJ_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Defaults
{
FormId stimpack;
FormId superStimpack;
FormId radX;
FormId radAway;
FormId morphine;
FormId perkParalysis;
FormId playerFaction;
FormId mysteriousStrangerNPC;
FormId mysteriousStrangerFaction;
FormId defaultMusic;
FormId battleMusic;
FormId deathMusic;
FormId successMusic;
FormId levelUpMusic;
FormId playerVoiceMale;
FormId playerVoiceMaleChild;
FormId playerVoiceFemale;
FormId playerVoiceFemaleChild;
FormId eatPackageDefaultFood;
FormId everyActorAbility;
FormId drugWearsOffImageSpace;
// below FONV only
FormId doctorsBag;
FormId missFortuneNPC;
FormId missFortuneFaction;
FormId meltdownExplosion;
FormId unarmedForwardPA;
FormId unarmedBackwardPA;
FormId unarmedLeftPA;
FormId unarmedRightPA;
FormId unarmedCrouchPA;
FormId unarmedCounterPA;
FormId spotterEffect;
FormId itemDetectedEfect;
FormId cateyeMobileEffectNYI;
};
struct DefaultObj
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
Defaults mData;
DefaultObj();
virtual ~DefaultObj();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_DOBJ_H

@ -0,0 +1,93 @@
/*
Copyright (C) 2016, 2018, 2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loaddoor.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Door::Door() : mFormId(0), mFlags(0), mBoundRadius(0.f), mDoorFlags(0), mScriptId(0),
mOpenSound(0), mCloseSound(0), mLoopSound(0), mRandomTeleport(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
}
ESM4::Door::~Door()
{
}
void ESM4::Door::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_SNAM: reader.getFormId(mOpenSound); break;
case ESM4::SUB_ANAM: reader.getFormId(mCloseSound); break;
case ESM4::SUB_BNAM: reader.getFormId(mLoopSound); break;
case ESM4::SUB_FNAM: reader.get(mDoorFlags); break;
case ESM4::SUB_TNAM: reader.getFormId(mRandomTeleport); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_MODT:
case ESM4::SUB_MODS:
case ESM4::SUB_OBND:
case ESM4::SUB_VMAD:
case ESM4::SUB_DEST: // FO3
case ESM4::SUB_DSTD: // FO3
case ESM4::SUB_DSTF: // FO3
case ESM4::SUB_DMDL: // FO3
case ESM4::SUB_DMDT: // FO3
{
//std::cout << "DOOR " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::DOOR::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Door::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Door::blank()
//{
//}

@ -0,0 +1,76 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_DOOR_H
#define ESM4_DOOR_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Door
{
enum Flags
{
Flag_OblivionGate = 0x01,
Flag_AutomaticDoor = 0x02,
Flag_Hidden = 0x04,
Flag_MinimalUse = 0x08
};
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
float mBoundRadius;
std::uint8_t mDoorFlags;
FormId mScriptId;
FormId mOpenSound; // SNDR for TES5, SOUN for others
FormId mCloseSound; // SNDR for TES5, SOUN for others
FormId mLoopSound;
FormId mRandomTeleport;
Door();
virtual ~Door();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_DOOR_H

@ -0,0 +1,74 @@
/*
Copyright (C) 2016, 2018, 2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadeyes.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Eyes::Eyes() : mFormId(0), mFlags(0)
{
mEditorId.clear();
mFullName.clear();
mIcon.clear();
mData.flags = 0;
}
ESM4::Eyes::~Eyes()
{
}
void ESM4::Eyes::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
case ESM4::SUB_DATA: reader.get(mData); break;
default:
throw std::runtime_error("ESM4::EYES::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Eyes::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Eyes::blank()
//{
//}

@ -0,0 +1,68 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_EYES_H
#define ESM4_EYES_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Eyes
{
#pragma pack(push, 1)
struct Data
{
std::uint8_t flags; // 0x01 = playable?
};
#pragma pack(pop)
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mIcon; // texture
Data mData;
Eyes();
virtual ~Eyes();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_EYES_H

@ -0,0 +1,89 @@
/*
Copyright (C) 2016, 2018, 2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadflor.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Flora::Flora() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScriptId(0), mIngredient(0),
mSound(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
}
ESM4::Flora::~Flora()
{
}
void ESM4::Flora::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_PFIG: reader.getFormId(mIngredient); break;
case ESM4::SUB_PFPC: reader.get(mPercentHarvest); break;
case ESM4::SUB_SNAM: reader.getFormId(mSound); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_MODT:
case ESM4::SUB_MODS:
case ESM4::SUB_FNAM:
case ESM4::SUB_OBND:
case ESM4::SUB_PNAM:
case ESM4::SUB_RNAM:
case ESM4::SUB_VMAD:
{
//std::cout << "FLOR " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::FLOR::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Flora::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Flora::blank()
//{
//}

@ -0,0 +1,78 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_FLOR_H
#define ESM4_FLOR_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Flora
{
#pragma pack(push, 1)
struct Production
{
std::uint8_t spring;
std::uint8_t summer;
std::uint8_t autumn;
std::uint8_t winter;
Production() : spring(0), summer(0), autumn(0), winter(0) {}
};
#pragma pack(pop)
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
float mBoundRadius;
FormId mScriptId;
FormId mIngredient;
FormId mSound;
Production mPercentHarvest;
Flora();
virtual ~Flora();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_FLOR_H

@ -0,0 +1,81 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadflst.hpp"
#include <stdexcept>
//#include <iostream> // FIXME: for debugging only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::FormIdList::FormIdList() : mFormId(0), mFlags(0)
{
mEditorId.clear();
}
ESM4::FormIdList::~FormIdList()
{
}
void ESM4::FormIdList::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_LNAM:
{
FormId formId;
reader.getFormId(formId);
mObjects.push_back(formId);
break;
}
default:
//std::cout << "FLST " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
//reader.skipSubRecordData();
throw std::runtime_error("ESM4::FLST::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
//std::cout << "flst " << mEditorId << " " << mObjects.size() << std::endl; // FIXME
}
//void ESM4::FormIdList::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::FormIdList::blank()
//{
//}

@ -0,0 +1,60 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_FLST_H
#define ESM4_FLST_H
#include <cstdint>
#include <string>
#include <vector>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct FormIdList
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::vector<FormId> mObjects;
FormIdList();
virtual ~FormIdList();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_FLST_H

@ -0,0 +1,98 @@
/*
Copyright (C) 2016, 2018, 2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadfurn.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Furniture::Furniture() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScriptId(0),
mActiveMarkerFlags(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
}
ESM4::Furniture::~Furniture()
{
}
void ESM4::Furniture::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_MNAM: reader.get(mActiveMarkerFlags); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_MODT:
case ESM4::SUB_DEST:
case ESM4::SUB_DSTD:
case ESM4::SUB_DSTF:
case ESM4::SUB_ENAM:
case ESM4::SUB_FNAM:
case ESM4::SUB_FNMK:
case ESM4::SUB_FNPR:
case ESM4::SUB_KNAM:
case ESM4::SUB_KSIZ:
case ESM4::SUB_KWDA:
case ESM4::SUB_MODS:
case ESM4::SUB_NAM0:
case ESM4::SUB_OBND:
case ESM4::SUB_PNAM:
case ESM4::SUB_VMAD:
case ESM4::SUB_WBDT:
case ESM4::SUB_XMRK:
{
//std::cout << "FURN " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::FURN::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Furniture::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Furniture::blank()
//{
//}

@ -0,0 +1,64 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_FURN_H
#define ESM4_FURN_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Furniture
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
float mBoundRadius;
FormId mScriptId;
std::uint32_t mActiveMarkerFlags;
Furniture();
virtual ~Furniture();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_FURN_H

@ -0,0 +1,82 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadglob.hpp"
#include <stdexcept>
#include <iostream> // FIXME
#include "reader.hpp"
//#include "writer.hpp"
ESM4::GlobalVariable::GlobalVariable() : mFormId(0), mFlags(0), mType(0), mValue(0.f)
{
mEditorId.clear();
}
ESM4::GlobalVariable::~GlobalVariable()
{
}
void ESM4::GlobalVariable::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FNAM: reader.get(mType); break;
case ESM4::SUB_FLTV: reader.get(mValue); break;
case ESM4::SUB_FULL:
case ESM4::SUB_MODL:
case ESM4::SUB_MODB:
case ESM4::SUB_ICON:
case ESM4::SUB_DATA:
case ESM4::SUB_OBND: // TES5
case ESM4::SUB_VMAD: // TES5
{
//std::cout << "GLOB " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::GLOB::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::GlobalVariable::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::GlobalVariable::blank()
//{
//}

@ -0,0 +1,60 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_GLOB_H
#define ESM4_GLOB_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct GlobalVariable
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::uint8_t mType;
float mValue;
GlobalVariable();
virtual ~GlobalVariable();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_GLOB_H

@ -0,0 +1,78 @@
/*
Copyright (C) 2016, 2018 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadgras.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Grass::Grass() : mFormId(0), mFlags(0), mBoundRadius(0.f)
{
mEditorId.clear();
mModel.clear();
}
ESM4::Grass::~Grass()
{
}
void ESM4::Grass::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_DATA: reader.get(mData); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_MODT:
case ESM4::SUB_OBND:
{
//std::cout << "GRAS " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::GRAS::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Grass::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Grass::blank()
//{
//}

@ -0,0 +1,98 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_GRAS_H
#define ESM4_GRAS_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Grass
{
#pragma pack(push, 1)
// unused fields are probably packing
struct Data
{
std::uint8_t density;
std::uint8_t minSlope;
std::uint8_t maxSlope;
std::uint8_t unused;
std::uint16_t distanceFromWater;
std::uint16_t unused2;
/*
1 Above - At Least
2 Above - At Most
3 Below - At Least
4 Below - At Most
5 Either - At Least
6 Either - At Most
7 Either - At Most Above
8 Either - At Most Below
*/
std::uint32_t waterDistApplication;
float positionRange;
float heightRange;
float colorRange;
float wavePeriod;
/*
0x01 Vertex Lighting
0x02 Uniform Scaling
0x04 Fit to Slope
*/
std::uint8_t flags;
std::uint8_t unused3;
std::uint16_t unused4;
};
#pragma pack(pop)
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mModel;
float mBoundRadius;
Data mData;
Grass();
virtual ~Grass();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_GRAS_H

@ -0,0 +1,158 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_GRUP_H
#define ESM4_GRUP_H
#include <cstdint>
#include <vector>
#include "common.hpp" // GroupLabel
namespace ESM4
{
// http://www.uesp.net/wiki/Tes4Mod:Mod_File_Format#Hierarchical_Top_Groups
//
// Type | Info |
// ------+--------------------------------------+-------------------
// 2 | Interior Cell Block |
// 3 | Interior Cell Sub-Block |
// R | CELL |
// 6 | Cell Childen |
// 8 | Persistent children |
// R | REFR, ACHR, ACRE |
// 10 | Visible distant children |
// R | REFR, ACHR, ACRE |
// 9 | Temp Children |
// R | PGRD |
// R | REFR, ACHR, ACRE |
// | |
// 0 | Top (Type) |
// R | WRLD |
// 1 | World Children |
// R | ROAD |
// R | CELL |
// 6 | Cell Childen |
// 8 | Persistent children |
// R | REFR, ACHR, ACRE |
// 10 | Visible distant children |
// R | REFR, ACHR, ACRE |
// 9 | Temp Children |
// R | PGRD |
// R | REFR, ACHR, ACRE |
// 4 | Exterior World Block |
// 5 | Exterior World Sub-block |
// R | CELL |
// 6 | Cell Childen |
// 8 | Persistent children |
// R | REFR, ACHR, ACRE |
// 10 | Visible distant children |
// R | REFR, ACHR, ACRE |
// 9 | Temp Children |
// R | LAND |
// R | PGRD |
// R | REFR, ACHR, ACRE |
//
struct WorldGroup
{
FormId mWorld; // WRLD record for this group
// occurs only after World Child (type 1)
// since GRUP label may not be reliable, need to keep the formid of the current WRLD in
// the reader's context
FormId mRoad;
std::vector<FormId> mCells; // FIXME should this be CellGroup* instead?
WorldGroup() : mWorld(0), mRoad(0) {}
};
// http://www.uesp.net/wiki/Tes4Mod:Mod_File_Format/CELL
//
// The block and subblock groups for an interior cell are determined by the last two decimal
// digits of the lower 3 bytes of the cell form ID (the modindex is not included in the
// calculation). For example, for form ID 0x000CF2=3314, the block is 4 and the subblock is 1.
//
// The block and subblock groups for an exterior cell are determined by the X-Y coordinates of
// the cell. Each block contains 16 subblocks (4x4) and each subblock contains 64 cells (8x8).
// So each block contains 1024 cells (32x32).
//
// NOTE: There may be many CELL records in one subblock
struct CellGroup
{
FormId mCell; // CELL record for this cell group
int mCellModIndex; // from which file to get the CELL record (e.g. may have been updated)
// For retrieving parent group size (for lazy loading or skipping) and sub-block number / grid
// NOTE: There can be more than one file that adds/modifies records to this cell group
//
// Use Case 1: To quickly get only the visble when distant records:
//
// - Find the FormId of the CELL (maybe WRLD/X/Y grid lookup or from XTEL of a REFR)
// - search a map of CELL FormId to CellGroup
// - load CELL and its child groups (or load the visible distant only, or whatever)
//
// Use Case 2: Scan the files but don't load CELL or cell group
//
// - Load referenceables and other records up front, updating them as required
// - Don't load CELL, LAND, PGRD or ROAD (keep FormId's and file index, and file
// context then skip the rest of the group)
//
std::vector<GroupTypeHeader> mHeaders; // FIXME: is this needed?
// FIXME: should these be pairs? i.e. <FormId, modindex> so that we know from which file
// the formid came (it may have been updated by a mod)
// but does it matter? the record itself keeps track of whether it is base,
// added or modified anyway
// FIXME: should these be maps? e.g. std::map<FormId, std::uint8_t>
// or vector for storage with a corresponding map of index?
// cache (modindex adjusted) formId's of children
// FIXME: also need file index + file context of all those that has type 8 GRUP
GroupTypeHeader mHdrPersist;
std::vector<FormId> mPersistent; // REFR, ACHR, ACRE
std::vector<FormId> mdelPersistent;
// FIXME: also need file index + file context of all those that has type 10 GRUP
GroupTypeHeader mHdrVisDist;
std::vector<FormId> mVisibleDist; // REFR, ACHR, ACRE
std::vector<FormId> mdelVisibleDist;
// FIXME: also need file index + file context of all those that has type 9 GRUP
GroupTypeHeader mHdrTemp;
FormId mLand; // if present, assume only one LAND per exterior CELL
FormId mPgrd; // if present, seems to be the first record after LAND in Temp Cell Child GRUP
std::vector<FormId> mTemporary; // REFR, ACHR, ACRE
std::vector<FormId> mdelTemporary;
// need to keep modindex and context for lazy loading (of all the files that contribute
// to this group)
CellGroup() : mCell(0), mLand(0), mPgrd(0) {}
};
}
#endif // ESM4_GRUP_H

@ -0,0 +1,84 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadhair.hpp"
#include <stdexcept>
//#include <iostream> // FIXME: for debugging only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Hair::Hair() : mFormId(0), mFlags(0), mBoundRadius(0.f)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mIcon.clear();
mData.flags = 0;
}
ESM4::Hair::~Hair()
{
}
void ESM4::Hair::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getZString(mFullName); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
case ESM4::SUB_DATA: reader.get(mData); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_MODT:
{
//std::cout << "HAIR " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::HAIR::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Hair::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Hair::blank()
//{
//}

@ -0,0 +1,71 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_HAIR
#define ESM4_HAIR
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Hair
{
#pragma pack(push, 1)
struct Data
{
std::uint8_t flags; // 0x01 = not playable, 0x02 = not male, 0x04 = not female, ?? = fixed
};
#pragma pack(pop)
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel; // mesh
std::string mIcon; // texture
float mBoundRadius;
Data mData;
Hair();
virtual ~Hair();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_HAIR

@ -0,0 +1,104 @@
/*
Copyright (C) 2019-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadhdpt.hpp"
#include <stdexcept>
//#include <iostream> // FIXME: testing only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::HeadPart::HeadPart() : mFormId(0), mFlags(0), mData(0), mAdditionalPart(0), mBaseTexture(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mTriFile.resize(3);
}
ESM4::HeadPart::~HeadPart()
{
}
void ESM4::HeadPart::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
std::uint32_t type;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_DATA: reader.get(mData); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_HNAM: reader.getFormId(mAdditionalPart); break;
case ESM4::SUB_NAM0: // TES5
{
reader.get(type);
break;
}
case ESM4::SUB_NAM1: // TES5
{
std::string file;
reader.getZString(file);
// FIXME: check type >= 0 && type < 3
mTriFile[type] = std::move(file);
break;
}
case ESM4::SUB_TNAM: reader.getFormId(mBaseTexture); break;
case ESM4::SUB_PNAM:
case ESM4::SUB_MODS:
case ESM4::SUB_MODT:
case ESM4::SUB_RNAM:
{
//std::cout << "HDPT " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::HDPT::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::HeadPart::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::HeadPart::blank()
//{
//}

@ -0,0 +1,66 @@
/*
Copyright (C) 2019, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_HDPT_H
#define ESM4_HDPT_H
#include <cstdint>
#include <vector>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct HeadPart
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
std::uint8_t mData;
FormId mAdditionalPart;
std::vector<std::string> mTriFile;
FormId mBaseTexture;
HeadPart();
virtual ~HeadPart();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_HDPT_H

@ -0,0 +1,84 @@
/*
Copyright (C) 2016, 2018 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadidle.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::IdleAnimation::IdleAnimation() : mFormId(0), mFlags(0), mParent(0), mPrevious(0)
{
mEditorId.clear();
mCollision.clear();
mEvent.clear();
}
ESM4::IdleAnimation::~IdleAnimation()
{
}
void ESM4::IdleAnimation::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_DNAM: reader.getZString(mCollision); break;
case ESM4::SUB_ENAM: reader.getZString(mEvent); break;
case ESM4::SUB_ANAM:
{
reader.get(mParent);
reader.get(mPrevious);
break;
}
case ESM4::SUB_CTDA: // formId
case ESM4::SUB_DATA: // formId
{
//std::cout << "IDLE " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::IDLE::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::IdleAnimation::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::IdleAnimation::blank()
//{
//}

@ -0,0 +1,62 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_IDLE_H
#define ESM4_IDLE_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct IdleAnimation
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mCollision;
std::string mEvent;
FormId mParent; // IDLE or AACT
FormId mPrevious;
IdleAnimation();
virtual ~IdleAnimation();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_IDLE_H

@ -0,0 +1,103 @@
/*
Copyright (C) 2019, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadidlm.hpp"
#include <stdexcept>
//#include <iostream> // FIXME: testing only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::IdleMarker::IdleMarker() : mFormId(0), mFlags(0), mIdleFlags(0), mIdleCount(0), mIdleTimer(0.f), mIdleAnim(0)
{
mEditorId.clear();
}
ESM4::IdleMarker::~IdleMarker()
{
}
void ESM4::IdleMarker::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
std::uint32_t esmVer = reader.esmVersion();
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_IDLF: reader.get(mIdleFlags); break;
case ESM4::SUB_IDLC:
{
if (subHdr.dataSize != 1) // FO3 can have 4?
{
reader.skipSubRecordData();
break;
}
reader.get(mIdleCount);
break;
}
case ESM4::SUB_IDLT: reader.get(mIdleTimer); break;
case ESM4::SUB_IDLA:
{
bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134;
if (esmVer == ESM::VER_094 || isFONV) // FO3? 4 or 8 bytes
{
reader.skipSubRecordData();
break;
}
mIdleAnim.resize(mIdleCount);
for (unsigned int i = 0; i < static_cast<unsigned int>(mIdleCount); ++i)
reader.get(mIdleAnim.at(i));
break;
}
case ESM4::SUB_OBND: // object bounds
{
//std::cout << "IDLM " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::IDLM::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::IdleMarker::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::IdleMarker::blank()
//{
//}

@ -0,0 +1,63 @@
/*
Copyright (C) 2019, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_IDLM_H
#define ESM4_IDLM_H
#include <cstdint>
#include <vector>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct IdleMarker
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mModel;
std::uint8_t mIdleFlags;
std::uint8_t mIdleCount;
float mIdleTimer;
std::vector<FormId> mIdleAnim;
IdleMarker();
virtual ~IdleMarker();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_IDLM_H

@ -0,0 +1,89 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
Also see https://tes5edit.github.io/fopdoc/ for FO3/FONV specific details.
*/
#include "loadimod.hpp"
#include <stdexcept>
#include <iostream> // FIXME: for debugging only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::ItemMod::ItemMod() : mFormId(0), mFlags(0)
{
mEditorId.clear();
}
ESM4::ItemMod::~ItemMod()
{
}
void ESM4::ItemMod::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_OBND:
case ESM4::SUB_FULL:
case ESM4::SUB_MODL:
case ESM4::SUB_ICON:
case ESM4::SUB_MICO:
case ESM4::SUB_SCRI:
case ESM4::SUB_DESC:
case ESM4::SUB_YNAM:
case ESM4::SUB_ZNAM:
case ESM4::SUB_DATA:
{
//std::cout << "IMOD " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
reader.skipSubRecordData();
break;
}
default:
std::cout << "IMOD " << ESM::printName(subHdr.typeId) << " skipping..."
<< subHdr.dataSize << std::endl;
reader.skipSubRecordData();
//throw std::runtime_error("ESM4::IMOD::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::ItemMod::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::ItemMod::blank()
//{
//}

@ -0,0 +1,59 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
Also see https://tes5edit.github.io/fopdoc/ for FO3/FONV specific details.
*/
#ifndef ESM4_IMOD_H
#define ESM4_IMOD_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct ItemMod
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
ItemMod();
virtual ~ItemMod();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_IMOD_H

@ -0,0 +1,222 @@
/*
Copyright (C) 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadinfo.hpp"
#include <stdexcept>
#include <cstring>
#include <iostream> // FIXME: for debugging only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::DialogInfo::DialogInfo() : mFormId(0), mFlags(0), mQuest(0), mSound(0),
mDialType(0), mNextSpeaker(0), mInfoFlags(0), mParam3(0)
{
std::memset(&mResponseData, 0, sizeof(TargetResponseData));
mResponse.clear();
mNotes.clear();
mEdits.clear();
std::memset(&mTargetCondition, 0, sizeof(TargetCondition));
std::memset(&mScript.scriptHeader, 0, sizeof(ScriptHeader));
mScript.scriptSource.clear();
mScript.globReference = 0;
}
ESM4::DialogInfo::~DialogInfo()
{
}
void ESM4::DialogInfo::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
mEditorId = formIdToString(mFormId); // FIXME: quick workaround to use existing code
static ScriptLocalVariableData localVar;
bool ignore = false;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_QSTI: reader.getFormId(mQuest); break; // FormId quest id
case ESM4::SUB_SNDD: reader.getFormId(mSound); break; // FO3 (not used in FONV?)
case ESM4::SUB_TRDT:
{
if (subHdr.dataSize == 16) // TES4
reader.get(&mResponseData, 16);
else if (subHdr.dataSize == 20) // FO3
reader.get(&mResponseData, 20);
else // FO3/FONV
{
reader.get(mResponseData);
if (mResponseData.sound)
reader.adjustFormId(mResponseData.sound);
}
break;
}
case ESM4::SUB_NAM1: reader.getZString(mResponse); break; // response text
case ESM4::SUB_NAM2: reader.getZString(mNotes); break; // actor notes
case ESM4::SUB_NAM3: reader.getZString(mEdits); break; // not in TES4
case ESM4::SUB_CTDA: // FIXME: how to detect if 1st/2nd param is a formid?
{
if (subHdr.dataSize == 24) // TES4
reader.get(&mTargetCondition, 24);
else if (subHdr.dataSize == 20) // FO3
reader.get(&mTargetCondition, 20);
else if (subHdr.dataSize == 28)
{
reader.get(mTargetCondition); // FO3/FONV
if (mTargetCondition.reference)
reader.adjustFormId(mTargetCondition.reference);
}
else // TES5
{
reader.get(&mTargetCondition, 20);
if (subHdr.dataSize == 36)
reader.getFormId(mParam3);
reader.get(mTargetCondition.runOn);
reader.get(mTargetCondition.reference);
if (mTargetCondition.reference)
reader.adjustFormId(mTargetCondition.reference);
reader.skipSubRecordData(4); // unknown
}
break;
}
case ESM4::SUB_SCHR:
{
if (!ignore)
reader.get(mScript.scriptHeader);
else
reader.skipSubRecordData(); // TODO: does the second one ever used?
break;
}
case ESM4::SUB_SCDA: reader.skipSubRecordData(); break; // compiled script data
case ESM4::SUB_SCTX: reader.getString(mScript.scriptSource); break;
case ESM4::SUB_SCRO: reader.getFormId(mScript.globReference); break;
case ESM4::SUB_SLSD:
{
localVar.clear();
reader.get(localVar.index);
reader.get(localVar.unknown1);
reader.get(localVar.unknown2);
reader.get(localVar.unknown3);
reader.get(localVar.type);
reader.get(localVar.unknown4);
// WARN: assumes SCVR will follow immediately
break;
}
case ESM4::SUB_SCVR: // assumed always pair with SLSD
{
reader.getZString(localVar.variableName);
mScript.localVarData.push_back(localVar);
break;
}
case ESM4::SUB_SCRV:
{
std::uint32_t index;
reader.get(index);
mScript.localRefVarIndex.push_back(index);
break;
}
case ESM4::SUB_NEXT: // FO3/FONV marker for next script header
{
ignore = true;
break;
}
case ESM4::SUB_DATA: // always 3 for TES4 ?
{
if (subHdr.dataSize == 4) // FO3/FONV
{
reader.get(mDialType);
reader.get(mNextSpeaker);
reader.get(mInfoFlags);
}
else
reader.skipSubRecordData(); // FIXME
break;
}
case ESM4::SUB_NAME: // FormId add topic (not always present)
case ESM4::SUB_CTDT: // older version of CTDA? 20 bytes
case ESM4::SUB_SCHD: // 28 bytes
case ESM4::SUB_TCLT: // FormId choice
case ESM4::SUB_TCLF: // FormId
case ESM4::SUB_PNAM: // TES4 DLC
case ESM4::SUB_TPIC: // TES4 DLC
case ESM4::SUB_ANAM: // FO3 speaker formid
case ESM4::SUB_DNAM: // FO3 speech challenge
case ESM4::SUB_KNAM: // FO3 formid
case ESM4::SUB_LNAM: // FONV
case ESM4::SUB_TCFU: // FONV
case ESM4::SUB_TIFC: // TES5
case ESM4::SUB_TWAT: // TES5
case ESM4::SUB_CIS2: // TES5
case ESM4::SUB_CNAM: // TES5
case ESM4::SUB_ENAM: // TES5
case ESM4::SUB_EDID: // TES5
case ESM4::SUB_VMAD: // TES5
case ESM4::SUB_BNAM: // TES5
case ESM4::SUB_SNAM: // TES5
case ESM4::SUB_ONAM: // TES5
case ESM4::SUB_QNAM: // TES5 for mScript
case ESM4::SUB_RNAM: // TES5
{
//std::cout << "INFO " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
reader.skipSubRecordData();
break;
}
default:
std::cout << "INFO " << ESM::printName(subHdr.typeId) << " skipping..."
<< subHdr.dataSize << std::endl;
reader.skipSubRecordData();
//throw std::runtime_error("ESM4::INFO::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::DialogInfo::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::DialogInfo::blank()
//{
//}

@ -0,0 +1,90 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_INFO_H
#define ESM4_INFO_H
#include <cstdint>
#include <string>
#include "formid.hpp"
#include "script.hpp" // TargetCondition
#include "dialogue.hpp" // DialType
namespace ESM4
{
class Reader;
class Writer;
enum InfoFlag
{
INFO_Goodbye = 0x0001,
INFO_Random = 0x0002,
INFO_SayOnce = 0x0004,
INFO_RunImmediately = 0x0008,
INFO_InfoRefusal = 0x0010,
INFO_RandomEnd = 0x0020,
INFO_RunForRumors = 0x0040,
INFO_SpeechChallenge = 0x0080,
INFO_SayOnceADay = 0x0100,
INFO_AlwaysDarken = 0x0200
};
struct DialogInfo
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId; // FIXME: no such record for INFO, but keep here to avoid extra work for now
FormId mQuest;
FormId mSound; // unused?
TargetResponseData mResponseData;
std::string mResponse;
std::string mNotes;
std::string mEdits;
std::uint8_t mDialType; // DialType
std::uint8_t mNextSpeaker;
std::uint16_t mInfoFlags; // see above enum
TargetCondition mTargetCondition;
FormId mParam3; // TES5 only
ScriptDefinition mScript; // FIXME: ignoring the second one after the NEXT sub-record
DialogInfo();
virtual ~DialogInfo();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_INFO_H

@ -0,0 +1,133 @@
/*
Copyright (C) 2016, 2018, 2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadingr.hpp"
#include <stdexcept>
#include <cstring>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Ingredient::Ingredient() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScriptId(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mIcon.clear();
mData.value = 0;
mData.weight = 0.f;
mEnchantment.value = 0;
mEnchantment.flags = 0;
std::memset(&mEffect, 0, sizeof(ScriptEffect));
}
ESM4::Ingredient::~Ingredient()
{
}
void ESM4::Ingredient::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL:
{
if (mFullName.empty())
{
reader.getLocalizedString(mFullName); break;
}
else // in TES4 subsequent FULL records are script effect names
{
// FIXME: should be part of a struct?
std::string scriptEffectName;
if (!reader.getZString(scriptEffectName))
throw std::runtime_error ("INGR FULL data read error");
mScriptEffect.push_back(scriptEffectName);
break;
}
}
case ESM4::SUB_DATA:
{
//if (reader.esmVersion() == ESM::VER_094 || reader.esmVersion() == ESM::VER_170)
if (subHdr.dataSize == 8) // FO3 is size 4 even though VER_094
reader.get(mData);
else
reader.get(mData.weight);
break;
}
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_ENIT: reader.get(mEnchantment); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_SCIT:
{
reader.get(mEffect);
reader.adjustFormId(mEffect.formId);
break;
}
case ESM4::SUB_MODT:
case ESM4::SUB_MODS: // Dragonborn only?
case ESM4::SUB_EFID:
case ESM4::SUB_EFIT:
case ESM4::SUB_OBND:
case ESM4::SUB_KSIZ:
case ESM4::SUB_KWDA:
case ESM4::SUB_VMAD:
case ESM4::SUB_YNAM:
case ESM4::SUB_ZNAM:
case ESM4::SUB_ETYP: // FO3
{
//std::cout << "INGR " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::INGR::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Ingredient::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Ingredient::blank()
//{
//}

@ -0,0 +1,83 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_INGR_H
#define ESM4_INGR_H
#include <cstdint>
#include <vector>
#include "effect.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Ingredient
{
#pragma pack(push, 1)
struct Data
{
std::uint32_t value;
float weight;
};
struct ENIT
{
std::uint32_t value;
std::uint32_t flags;
};
#pragma pack(pop)
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
std::string mIcon; // inventory
float mBoundRadius;
std::vector<std::string> mScriptEffect; // FIXME: prob. should be in a struct
FormId mScriptId;
ScriptEffect mEffect;
ENIT mEnchantment;
Data mData;
Ingredient();
virtual ~Ingredient();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_INGR_H

@ -0,0 +1,93 @@
/*
Copyright (C) 2016, 2018, 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadkeym.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Key::Key() : mFormId(0), mFlags(0), mPickUpSound(0), mDropSound(0), mBoundRadius(0.f), mScriptId(0)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mIcon.clear();
mMiniIcon.clear();
mData.value = 0;
mData.weight = 0.f;
}
ESM4::Key::~Key()
{
}
void ESM4::Key::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
case ESM4::SUB_MICO: reader.getZString(mMiniIcon); break; // FO3
case ESM4::SUB_DATA: reader.get(mData); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_YNAM: reader.getFormId(mPickUpSound); break;
case ESM4::SUB_ZNAM: reader.getFormId(mDropSound); break;
case ESM4::SUB_MODT:
case ESM4::SUB_KSIZ:
case ESM4::SUB_KWDA:
case ESM4::SUB_OBND:
case ESM4::SUB_VMAD:
{
//std::cout << "KEYM " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::KEYM::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Key::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Key::blank()
//{
//}

@ -0,0 +1,77 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_KEYM_H
#define ESM4_KEYM_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Key
{
#pragma pack(push, 1)
struct Data
{
std::uint32_t value; // gold
float weight;
};
#pragma pack(pop)
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
std::string mIcon; // inventory
std::string mMiniIcon; // inventory
FormId mPickUpSound;
FormId mDropSound;
float mBoundRadius;
FormId mScriptId;
Data mData;
Key();
virtual ~Key();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_KEYM_H

@ -0,0 +1,255 @@
/*
Copyright (C) 2015-2016, 2018, 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadland.hpp"
#ifdef NDEBUG // FIXME: debuggigng only
#undef NDEBUG
#endif
#include <cassert>
#include <stdexcept>
#include <iostream> // FIXME: debug only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Land::Land() : mFormId(0), mFlags(0), mLandFlags(0), mDataTypes(0)
{
for (int i = 0; i < 4; ++i)
{
mTextures[i].base.formId = 0;
mTextures[i].base.quadrant = 0;
mTextures[i].base.unknown1 = 0;
mTextures[i].base.unknown2 = 0;
}
}
ESM4::Land::~Land()
{
}
// overlap north
//
// 32
// 31
// 30
// overlap .
// west .
// .
// 2
// 1
// 0
// 0 1 2 ... 30 31 32
//
// overlap south
//
void ESM4::Land::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
TxtLayer layer;
std::int8_t currentAddQuad = -1; // for VTXT following ATXT
//std::map<FormId, int> uniqueTextures; // FIXME: for temp testing only
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_DATA:
{
reader.get(mLandFlags);
break;
}
case ESM4::SUB_VNML: // vertex normals, 33x33x(1+1+1) = 3267
{
reader.get(mVertNorm);
mDataTypes |= LAND_VNML;
break;
}
case ESM4::SUB_VHGT: // vertex height gradient, 4+33x33+3 = 4+1089+3 = 1096
{
#if 0
reader.get(mHeightMap.heightOffset);
reader.get(mHeightMap.gradientData);
reader.get(mHeightMap.unknown1);
reader.get(mHeightMap.unknown2);
#endif
reader.get(mHeightMap);
mDataTypes |= LAND_VHGT;
break;
}
case ESM4::SUB_VCLR: // vertex colours, 24bit RGB, 33x33x(1+1+1) = 3267
{
reader.get(mVertColr);
mDataTypes |= LAND_VCLR;
break;
}
case ESM4::SUA_BTXT:
{
BTXT base;
if (reader.getExact(base))
{
assert(base.quadrant < 4 && base.quadrant >= 0 && "base texture quadrant index error");
reader.adjustFormId(base.formId);
mTextures[base.quadrant].base = std::move(base);
#if 0
std::cout << "Base Texture formid: 0x"
<< std::hex << mTextures[base.quadrant].base.formId
<< ", quad " << std::dec << (int)base.quadrant << std::endl;
#endif
}
break;
}
case ESM4::SUB_ATXT:
{
if (currentAddQuad != -1)
{
// FIXME: sometimes there are no VTXT following an ATXT? Just add a dummy one for now
std::cout << "ESM4::Land VTXT empty layer " << (int)layer.texture.layerIndex << std::endl;
mTextures[currentAddQuad].layers.push_back(layer);
}
reader.get(layer.texture);
reader.adjustFormId(layer.texture.formId);
assert(layer.texture.quadrant < 4 && layer.texture.quadrant >= 0
&& "additional texture quadrant index error");
#if 0
FormId txt = layer.texture.formId;
std::map<FormId, int>::iterator lb = uniqueTextures.lower_bound(txt);
if (lb != uniqueTextures.end() && !(uniqueTextures.key_comp()(txt, lb->first)))
{
lb->second += 1;
}
else
uniqueTextures.insert(lb, std::make_pair(txt, 1));
#endif
#if 0
std::cout << "Additional Texture formId: 0x"
<< std::hex << layer.texture.formId
<< ", quad " << std::dec << (int)layer.texture.quadrant << std::endl;
std::cout << "Additional Texture layer: "
<< std::dec << (int)layer.texture.layerIndex << std::endl;
#endif
currentAddQuad = layer.texture.quadrant;
break;
}
case ESM4::SUB_VTXT:
{
assert(currentAddQuad != -1 && "VTXT without ATXT found");
int count = (int)reader.subRecordHeader().dataSize / sizeof(ESM4::Land::VTXT);
assert((reader.subRecordHeader().dataSize % sizeof(ESM4::Land::VTXT)) == 0
&& "ESM4::LAND VTXT data size error");
if (count)
{
layer.data.resize(count);
std::vector<ESM4::Land::VTXT>::iterator it = layer.data.begin();
for (;it != layer.data.end(); ++it)
{
reader.get(*it);
// FIXME: debug only
//std::cout << "pos: " << std::dec << (int)(*it).position << std::endl;
}
}
mTextures[currentAddQuad].layers.push_back(layer);
// Assumed that the layers are added in the correct sequence
// FIXME: Knights.esp doesn't seem to observe this - investigate more
//assert(layer.texture.layerIndex == mTextures[currentAddQuad].layers.size()-1
//&& "additional texture layer index error");
currentAddQuad = -1;
layer.data.clear();
// FIXME: debug only
//std::cout << "VTXT: count " << std::dec << count << std::endl;
break;
}
case ESM4::SUB_VTEX: // only in Oblivion?
{
int count = (int)reader.subRecordHeader().dataSize / sizeof(FormId);
assert((reader.subRecordHeader().dataSize % sizeof(FormId)) == 0
&& "ESM4::LAND VTEX data size error");
if (count)
{
mIds.resize(count);
for (std::vector<FormId>::iterator it = mIds.begin(); it != mIds.end(); ++it)
{
reader.getFormId(*it);
// FIXME: debug only
//std::cout << "VTEX: " << std::hex << *it << std::endl;
}
}
break;
}
default:
throw std::runtime_error("ESM4::LAND::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
if (currentAddQuad != -1)
{
// FIXME: not sure if it happens here as well
std::cout << "ESM4::Land VTXT empty layer " << (int)layer.texture.layerIndex << " quad " << (int)layer.texture.quadrant << std::endl;
mTextures[currentAddQuad].layers.push_back(layer);
}
bool missing = false;
for (int i = 0; i < 4; ++i)
{
if (mTextures[i].base.formId == 0)
{
//std::cout << "ESM4::LAND " << ESM4::formIdToString(mFormId) << " missing base, quad " << i << std::endl;
//std::cout << "layers " << mTextures[i].layers.size() << std::endl;
// NOTE: can't set the default here since FO3/FONV may have different defaults
//mTextures[i].base.formId = 0x000008C0; // TerrainHDDirt01.dds
missing = true;
}
//else
//{
// std::cout << "ESM4::LAND " << ESM4::formIdToString(mFormId) << " base, quad " << i << std::endl;
// std::cout << "layers " << mTextures[i].layers.size() << std::endl;
//}
}
// at least one of the quadrants do not have a base texture, return without setting the flag
if (!missing)
mDataTypes |= LAND_VTEX;
}
//void ESM4::Land::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Land::blank()
//{
//}

@ -0,0 +1,136 @@
/*
Copyright (C) 2015-2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_LAND_H
#define ESM4_LAND_H
#include <cstdint>
#include <string>
#include <vector>
#include "formid.hpp"
namespace ESM4
{
class Reader;
struct Land
{
enum
{
LAND_VNML = 1,
LAND_VHGT = 2,
LAND_WNAM = 4, // only in TES3?
LAND_VCLR = 8,
LAND_VTEX = 16
};
// number of vertices per side
static const int VERTS_PER_SIDE = 33;
// cell terrain size in world coords
static const int REAL_SIZE = 4096;
// total number of vertices
static const int LAND_NUM_VERTS = VERTS_PER_SIDE * VERTS_PER_SIDE;
static const int HEIGHT_SCALE = 8;
// number of textures per side of a land quadrant
// (for TES4 - based on vanilla observations)
static const int QUAD_TEXTURE_PER_SIDE = 6;
#pragma pack(push,1)
struct VHGT
{
float heightOffset;
std::int8_t gradientData[VERTS_PER_SIDE * VERTS_PER_SIDE];
std::uint16_t unknown1;
unsigned char unknown2;
};
struct BTXT
{
FormId formId;
std::uint8_t quadrant; // 0 = bottom left, 1 = bottom right, 2 = top left, 3 = top right
std::uint8_t unknown1;
std::uint16_t unknown2;
};
struct ATXT
{
FormId formId;
std::uint8_t quadrant; // 0 = bottom left, 1 = bottom right, 2 = top left, 3 = top right
std::uint8_t unknown;
std::uint16_t layerIndex; // texture layer, 0..7
};
struct VTXT
{
std::uint16_t position; // 0..288 (17x17 grid)
std::uint8_t unknown1;
std::uint8_t unknown2;
float opacity;
};
#pragma pack(pop)
struct TxtLayer
{
ATXT texture;
std::vector<VTXT> data; // alpha data
};
struct Texture
{
BTXT base;
std::vector<TxtLayer> layers;
};
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::uint32_t mLandFlags; // from DATA subrecord
// FIXME: lazy loading not yet implemented
int mDataTypes; // which data types are loaded
signed char mVertNorm[VERTS_PER_SIDE * VERTS_PER_SIDE * 3]; // from VNML subrecord
signed char mVertColr[VERTS_PER_SIDE * VERTS_PER_SIDE * 3]; // from VCLR subrecord
VHGT mHeightMap;
Texture mTextures[4]; // 0 = bottom left, 1 = bottom right, 2 = top left, 3 = top right
std::vector<FormId> mIds; // land texture (LTEX) formids
Land();
virtual ~Land();
virtual void load(Reader& reader);
//virtual void save(Writer& writer) const;
//void blank();
};
}
#endif // ESM4_LAND_H

@ -0,0 +1,105 @@
/*
Copyright (C) 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
Also see https://tes5edit.github.io/fopdoc/ for FO3/FONV specific details.
*/
#include "loadlgtm.hpp"
#include <stdexcept>
#include <cfloat> // FLT_MAX for gcc
//#include <iostream> // FIXME: for debugging only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::LightingTemplate::LightingTemplate() : mFormId(0), mFlags(0)
{
mEditorId.clear();
mLighting.ambient = 0;
mLighting.directional = 0;
mLighting.fogColor = 0;
mLighting.fogNear = 0.f;
mLighting.fogFar = 0.f;
mLighting.rotationXY = 0;
mLighting.rotationZ = 0;
mLighting.fogDirFade = 0.f;
mLighting.fogClipDist = 0.f;
mLighting.fogPower = FLT_MAX; // hack way to detect TES4
}
ESM4::LightingTemplate::~LightingTemplate()
{
}
void ESM4::LightingTemplate::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_DATA:
{
if (subHdr.dataSize == 36) // TES4
reader.get(&mLighting, 36);
if (subHdr.dataSize == 40) // FO3/FONV
reader.get(mLighting);
else if (subHdr.dataSize == 92) // TES5
{
reader.get(mLighting);
reader.skipSubRecordData(52); // FIXME
}
else
reader.skipSubRecordData(); // throw?
break;
}
case ESM4::SUB_DALC: // TES5
{
//std::cout << "LGTM " << ESM::printName(subHdr.typeId) << " skipping..."
//<< subHdr.dataSize << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::LGTM::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::LightingTemplate::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::LightingTemplate::blank()
//{
//}

@ -0,0 +1,63 @@
/*
Copyright (C) 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
Also see https://tes5edit.github.io/fopdoc/ for FO3/FONV specific details.
*/
#ifndef ESM4_LGTM_H
#define ESM4_LGTM_H
#include <cstdint>
#include <string>
#include "formid.hpp"
#include "lighting.hpp"
namespace ESM4
{
class Reader;
class Writer;
typedef std::uint32_t FormId;
struct LightingTemplate
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
Lighting mLighting;
LightingTemplate();
virtual ~LightingTemplate();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_LGTM_H

@ -0,0 +1,120 @@
/*
Copyright (C) 2016, 2018, 2020-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadligh.hpp"
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Light::Light() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScriptId(0), mSound(0),
mFade(0.f)
{
mEditorId.clear();
mFullName.clear();
mModel.clear();
mIcon.clear();
}
ESM4::Light::~Light()
{
}
void ESM4::Light::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
std::uint32_t esmVer = reader.esmVersion();
bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_FULL: reader.getLocalizedString(mFullName); break;
case ESM4::SUB_DATA:
{
// FIXME: TES4 might be uint32 as well, need to check
if (isFONV || (esmVer == ESM::VER_094 && subHdr.dataSize == 32)/*FO3*/)
{
reader.get(mData.time); // uint32
}
else
reader.get(mData.duration); // float
reader.get(mData.radius);
reader.get(mData.colour);
reader.get(mData.flags);
//if (reader.esmVersion() == ESM::VER_094 || reader.esmVersion() == ESM::VER_170)
if (subHdr.dataSize == 48)
{
reader.get(mData.falloff);
reader.get(mData.FOV);
reader.get(mData.nearClip);
reader.get(mData.frequency);
reader.get(mData.intensityAmplitude);
reader.get(mData.movementAmplitude);
}
else if (subHdr.dataSize == 32) // TES4
{
reader.get(mData.falloff);
reader.get(mData.FOV);
}
reader.get(mData.value);
reader.get(mData.weight);
break;
}
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_SNAM: reader.getFormId(mSound); break;
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
case ESM4::SUB_FNAM: reader.get(mFade); break;
case ESM4::SUB_MODT:
case ESM4::SUB_OBND:
case ESM4::SUB_VMAD: // Dragonborn only?
{
//std::cout << "LIGH " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::LIGH::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::Light::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::Light::blank()
//{
//}

@ -0,0 +1,101 @@
/*
Copyright (C) 2016, 2018-2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_LIGH_H
#define ESM4_LIGH_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct Light
{
struct Data
{
std::uint32_t time; // FO/FONV only
float duration;
std::uint32_t radius;
std::uint32_t colour; // RGBA
// flags:
// 0x00000001 = Dynamic
// 0x00000002 = Can be Carried
// 0x00000004 = Negative
// 0x00000008 = Flicker
// 0x00000020 = Off By Default
// 0x00000040 = Flicker Slow
// 0x00000080 = Pulse
// 0x00000100 = Pulse Slow
// 0x00000200 = Spot Light
// 0x00000400 = Spot Shadow
std::int32_t flags;
float falloff;
float FOV;
float nearClip; // TES5 only
float frequency; // TES5 only
float intensityAmplitude; // TES5 only
float movementAmplitude; // TES5 only
std::uint32_t value; // gold
float weight;
Data() : duration(-1), radius(0), colour(0), flags(0), falloff(1.f), FOV(90),
nearClip(0.f), frequency(0.f), intensityAmplitude(0.f), movementAmplitude(0.f),
value(0), weight(0.f) // FIXME: FOV in degrees or radians?
{}
};
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
std::string mModel;
std::string mIcon;
float mBoundRadius;
FormId mScriptId;
FormId mSound;
float mFade;
Data mData;
Light();
virtual ~Light();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_LIGH_H

@ -0,0 +1,107 @@
/*
Copyright (C) 2015-2016, 2018 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadltex.hpp"
#ifdef NDEBUG // FIXME: debuggigng only
#undef NDEBUG
#endif
#include <cassert>
#include <stdexcept>
//#include <iostream> // FIXME: debugging only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::LandTexture::LandTexture() : mFormId(0), mFlags(0), mHavokFriction(0), mHavokRestitution(0),
mTextureSpecular(0), mGrass(0), mHavokMaterial(0), mTexture(0),
mMaterial(0)
{
mEditorId.clear();
mTextureFile.clear();
}
ESM4::LandTexture::~LandTexture()
{
}
void ESM4::LandTexture::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
std::uint32_t esmVer = reader.esmVersion();
bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_HNAM:
{
if (isFONV)
{
reader.skipSubRecordData(); // FIXME: skip FONV for now
break;
}
if ((reader.esmVersion() == ESM::VER_094 || reader.esmVersion() == ESM::VER_170)
&& subHdr.dataSize == 2) // FO3 is VER_094 but dataSize 3
{
//assert(subHdr.dataSize == 2 && "LTEX unexpected HNAM size");
reader.get(mHavokFriction);
reader.get(mHavokRestitution);
}
else
{
assert(subHdr.dataSize == 3 && "LTEX unexpected HNAM size");
reader.get(mHavokMaterial);
reader.get(mHavokFriction);
reader.get(mHavokRestitution);
}
break;
}
case ESM4::SUB_ICON: reader.getZString(mTextureFile); break; // Oblivion only?
case ESM4::SUB_SNAM: reader.get(mTextureSpecular); break;
case ESM4::SUB_GNAM: reader.getFormId(mGrass); break;
case ESM4::SUB_TNAM: reader.getFormId(mTexture); break; // TES5 only
case ESM4::SUB_MNAM: reader.getFormId(mMaterial); break; // TES5 only
default:
throw std::runtime_error("ESM4::LTEX::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::LandTexture::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::LandTexture::blank()
//{
//}

@ -0,0 +1,75 @@
/*
Copyright (C) 2015-2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_LTEX_H
#define ESM4_LTEX_H
#include <cstdint>
#include <string>
#include "formid.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct LandTexture
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::uint8_t mHavokFriction;
std::uint8_t mHavokRestitution;
std::uint8_t mTextureSpecular; // default 30
FormId mGrass;
// ------ TES4 only -----
std::string mTextureFile;
std::uint8_t mHavokMaterial;
// ------ TES5 only -----
FormId mTexture;
FormId mMaterial;
// ----------------------
LandTexture();
virtual ~LandTexture();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_LTEX_H

@ -0,0 +1,130 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadlvlc.hpp"
#include <stdexcept>
//#include <iostream> // FIXME
#include "reader.hpp"
//#include "writer.hpp"
ESM4::LevelledCreature::LevelledCreature() : mFormId(0), mFlags(0), mScriptId(0), mTemplate(0),
mChanceNone(0), mLvlCreaFlags(0)
{
mEditorId.clear();
}
ESM4::LevelledCreature::~LevelledCreature()
{
}
void ESM4::LevelledCreature::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_SCRI: reader.getFormId(mScriptId); break;
case ESM4::SUB_TNAM: reader.getFormId(mTemplate); break;
case ESM4::SUB_LVLD: reader.get(mChanceNone); break;
case ESM4::SUB_LVLF: reader.get(mLvlCreaFlags); break;
case ESM4::SUB_LVLO:
{
static LVLO lvlo;
if (subHdr.dataSize != 12)
{
if (subHdr.dataSize == 8)
{
reader.get(lvlo.level);
reader.get(lvlo.item);
reader.get(lvlo.count);
//std::cout << "LVLC " << mEditorId << " LVLO lev " << lvlo.level << ", item " << lvlo.item
//<< ", count " << lvlo.count << std::endl;
// FIXME: seems to happen only once, don't add to mLvlObject
// LVLC TesKvatchCreature LVLO lev 1, item 1393819648, count 2
// 0x0001, 0x5314 0000, 0x0002
break;
}
else
throw std::runtime_error("ESM4::LVLC::load - " + mEditorId + " LVLO size error");
}
else
reader.get(lvlo);
reader.adjustFormId(lvlo.item);
mLvlObject.push_back(lvlo);
break;
}
case ESM4::SUB_OBND: // FO3
{
//std::cout << "LVLC " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::LVLC::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
bool ESM4::LevelledCreature::calcAllLvlLessThanPlayer() const
{
if (mHasLvlCreaFlags)
return (mLvlCreaFlags & 0x01) != 0;
else
return (mChanceNone & 0x80) != 0; // FIXME: 0x80 is just a guess
}
bool ESM4::LevelledCreature::calcEachItemInCount() const
{
if (mHasLvlCreaFlags)
return (mLvlCreaFlags & 0x02) != 0;
else
return true; // FIXME: just a guess
}
std::int8_t ESM4::LevelledCreature::chanceNone() const
{
if (mHasLvlCreaFlags)
return mChanceNone;
else
return (mChanceNone & 0x7f); // FIXME: 0x80 is just a guess
}
//void ESM4::LevelledCreature::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::LevelledCreature::blank()
//{
//}

@ -0,0 +1,71 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_LVLC_H
#define ESM4_LVLC_H
#include <cstdint>
#include <vector>
#include "formid.hpp"
#include "inventory.hpp"
namespace ESM4
{
class Reader;
class Writer;
struct LevelledCreature
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
FormId mScriptId;
FormId mTemplate;
std::int8_t mChanceNone;
bool mHasLvlCreaFlags;
std::uint8_t mLvlCreaFlags;
std::vector<LVLO> mLvlObject;
bool calcAllLvlLessThanPlayer() const;
bool calcEachItemInCount() const;
std::int8_t chanceNone() const;
LevelledCreature();
virtual ~LevelledCreature();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_LVLC_H

@ -0,0 +1,142 @@
/*
Copyright (C) 2016, 2018-2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadlvli.hpp"
#include <stdexcept>
#include <iostream> // FIXME: for debugging
#include "reader.hpp"
//#include "writer.hpp"
ESM4::LevelledItem::LevelledItem() : mFormId(0), mFlags(0), mChanceNone(0), mHasLvlItemFlags(false),
mLvlItemFlags(0), mData(0)
{
mEditorId.clear();
}
ESM4::LevelledItem::~LevelledItem()
{
}
void ESM4::LevelledItem::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_LVLD: reader.get(mChanceNone); break;
case ESM4::SUB_LVLF: reader.get(mLvlItemFlags); mHasLvlItemFlags = true; break;
case ESM4::SUB_DATA: reader.get(mData); break;
case ESM4::SUB_LVLO:
{
static LVLO lvlo;
if (subHdr.dataSize != 12)
{
if (subHdr.dataSize == 8)
{
reader.get(lvlo.level);
reader.get(lvlo.item);
reader.get(lvlo.count);
// std::cout << "LVLI " << mEditorId << " LVLO lev " << lvlo.level << ", item " << lvlo.item
// << ", count " << lvlo.count << std::endl;
break;
}
else
throw std::runtime_error("ESM4::LVLI::load - " + mEditorId + " LVLO size error");
}
else
reader.get(lvlo);
reader.adjustFormId(lvlo.item);
mLvlObject.push_back(lvlo);
break;
}
case ESM4::SUB_LLCT:
case ESM4::SUB_OBND: // FO3/FONV
case ESM4::SUB_COED: // FO3/FONV
case ESM4::SUB_LVLG: // FO3/FONV
{
//std::cout << "LVLI " << ESM::printName(subHdr.typeId) << " skipping..." << subHdr.dataSize << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::LVLI::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
// FIXME: testing
//if (mHasLvlItemFlags && mChanceNone >= 90)
//std::cout << "LVLI " << mEditorId << " chance none " << int(mChanceNone) << std::endl;
}
bool ESM4::LevelledItem::calcAllLvlLessThanPlayer() const
{
if (mHasLvlItemFlags)
return (mLvlItemFlags & 0x01) != 0;
else
return (mChanceNone & 0x80) != 0; // FIXME: 0x80 is just a guess
}
bool ESM4::LevelledItem::calcEachItemInCount() const
{
if (mHasLvlItemFlags)
return (mLvlItemFlags & 0x02) != 0;
else
return mData != 0;
}
std::int8_t ESM4::LevelledItem::chanceNone() const
{
if (mHasLvlItemFlags)
return mChanceNone;
else
return (mChanceNone & 0x7f); // FIXME: 0x80 is just a guess
}
bool ESM4::LevelledItem::useAll() const
{
if (mHasLvlItemFlags)
return (mLvlItemFlags & 0x04) != 0;
else
return false;
}
//void ESM4::LevelledItem::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::LevelledItem::blank()
//{
//}

@ -0,0 +1,72 @@
/*
Copyright (C) 2016, 2018, 2020 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#ifndef ESM4_LVLI_H
#define ESM4_LVLI_H
#include <cstdint>
#include <vector>
#include "formid.hpp"
#include "inventory.hpp" // LVLO
namespace ESM4
{
class Reader;
class Writer;
struct LevelledItem
{
FormId mFormId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::int8_t mChanceNone;
bool mHasLvlItemFlags;
std::uint8_t mLvlItemFlags;
std::uint8_t mData;
std::vector<LVLO> mLvlObject;
LevelledItem();
virtual ~LevelledItem();
bool calcAllLvlLessThanPlayer() const;
bool calcEachItemInCount() const;
bool useAll() const;
std::int8_t chanceNone() const;
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
//void blank();
};
}
#endif // ESM4_LVLI_H

@ -0,0 +1,114 @@
/*
Copyright (C) 2019-2021 cc9cii
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au
Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
trial & error. See http://en.uesp.net/wiki for details.
*/
#include "loadlvln.hpp"
#include <stdexcept>
//#include <iostream> // FIXME: testing only
#include "reader.hpp"
//#include "writer.hpp"
ESM4::LevelledNpc::LevelledNpc() : mFormId(0), mFlags(0), mChanceNone(0), mLvlActorFlags(0), mListCount(0)
{
mEditorId.clear();
mModel.clear();
}
ESM4::LevelledNpc::~LevelledNpc()
{
}
void ESM4::LevelledNpc::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags;
//std::uint32_t esmVer = reader.esmVersion(); // currently unused
while (reader.getSubRecordHeader())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
switch (subHdr.typeId)
{
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
case ESM4::SUB_MODL: reader.getZString(mModel); break;
case ESM4::SUB_LLCT: reader.get(mListCount); break;
case ESM4::SUB_LVLD: reader.get(mChanceNone); break;
case ESM4::SUB_LVLF: reader.get(mLvlActorFlags); break;
case ESM4::SUB_LVLO:
{
static LVLO lvlo;
if (subHdr.dataSize != 12)
{
if (subHdr.dataSize == 8)
{
reader.get(lvlo.level);
reader.get(lvlo.item);
reader.get(lvlo.count);
break;
}
else
throw std::runtime_error("ESM4::LVLN::load - " + mEditorId + " LVLO size error");
}
// else if (esmVer == ESM::VER_094 || esmVer == ESM::VER_170 || isFONV)
// {
// std::uint32_t level;
// reader.get(level);
// lvlo.level = static_cast<std::uint16_t>(level);
// reader.get(lvlo.item);
// std::uint32_t count;
// reader.get(count);
// lvlo.count = static_cast<std::uint16_t>(count);
// }
else
reader.get(lvlo);
reader.adjustFormId(lvlo.item);
mLvlObject.push_back(lvlo);
break;
}
case ESM4::SUB_COED: // owner
case ESM4::SUB_OBND: // object bounds
case ESM4::SUB_MODT: // model texture data
{
//std::cout << "LVLN " << ESM::printName(subHdr.typeId) << " skipping..." << std::endl;
reader.skipSubRecordData();
break;
}
default:
throw std::runtime_error("ESM4::LVLN::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
}
}
//void ESM4::LevelledNpc::save(ESM4::Writer& writer) const
//{
//}
//void ESM4::LevelledNpc::blank()
//{
//}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save