diff --git a/CMakeLists.txt b/CMakeLists.txt index b0ae91388..534b1e0bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,6 +131,19 @@ set(ESM ${COMP_DIR}/esm/skill.cpp ${COMP_DIR}/esm/attr.cpp ${COMP_DIR}/esm/class.cpp + ${COMP_DIR}/esm/esm_reader.cpp + ${COMP_DIR}/esm/loadland.cpp + ${COMP_DIR}/esm/loadacti.cpp + ${COMP_DIR}/esm/loadalch.cpp + ${COMP_DIR}/esm/loadappa.cpp + ${COMP_DIR}/esm/loadarmo.cpp + ${COMP_DIR}/esm/loadbody.cpp + ${COMP_DIR}/esm/loadbook.cpp + ${COMP_DIR}/esm/loadbsgn.cpp + ${COMP_DIR}/esm/loadcell.cpp + ${COMP_DIR}/esm/loadclas.cpp + ${COMP_DIR}/esm/loadclot.cpp + ) source_group(components\\esm FILES ${ESM_HEADER} ${ESM}) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 9a4cefa37..0fdbe45aa 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -3,13 +3,14 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ // Pixel color value. Standard four-byte rr,gg,bb,aa format. typedef int32_t Color; enum VarType - { +{ VT_Unknown, VT_None, VT_Short, @@ -18,79 +19,75 @@ enum VarType VT_Float, VT_String, VT_Ignored - }; +}; enum Specialization - { - SPC_Combat = 0, - SPC_Magic = 1, - SPC_Stealth = 2 - }; +{ + SPC_Combat = 0, SPC_Magic = 1, SPC_Stealth = 2 +}; enum RangeType - { - RT_Self = 0, - RT_Touch = 1, - RT_Target = 2 - }; +{ + RT_Self = 0, RT_Touch = 1, RT_Target = 2 +}; /** A list of references to spells and spell effects. This is shared - between the records BSGN, NPC and RACE. -*/ + between the records BSGN, NPC and RACE. + */ struct SpellList { - std::vector list; + std::vector list; - void load(ESMReader &esm) - { - while(esm.isNextSub("NPCS")) - list.push_back(esm.getHString()); - } + void load(ESMReader &esm) + { + while (esm.isNextSub("NPCS")) + list.push_back(esm.getHString()); + } }; /** Defines a spell effect. Shared between SPEL (Spells), ALCH - (Potions) and ENCH (Item enchantments) records -*/ + (Potions) and ENCH (Item enchantments) records + */ #pragma pack(push) #pragma pack(1) // Position and rotation struct Position { - float pos[3]; - float rot[3]; + float pos[3]; + float rot[3]; }; struct ENAMstruct { - // Magical effect, hard-coded ID - short effectID; + // Magical effect, hard-coded ID + short effectID; - // Which skills/attributes are affected (for restore/drain spells - // etc.) - signed char skill, attribute; // -1 if N/A + // Which skills/attributes are affected (for restore/drain spells + // etc.) + signed char skill, attribute; // -1 if N/A - // Other spell parameters - int range; // 0 - self, 1 - touch, 2 - target (RangeType enum) - int area, duration, magnMin, magnMax; + // Other spell parameters + int range; // 0 - self, 1 - touch, 2 - target (RangeType enum) + int area, duration, magnMin, magnMax; - // Struct size should be 24 bytes + // Struct size should be 24 bytes }; #pragma pack(pop) struct EffectList { - std::vector list; + std::vector list; - void load(ESMReader &esm) - { - ENAMstruct s; - while(esm.isNextSub("ENAM")) - { - esm.getHT(s, 24); - list.push_back(s); - } - } + void load(ESMReader &esm) + { + ENAMstruct s; + while (esm.isNextSub("ENAM")) + { + esm.getHT(s, 24); + list.push_back(s); + } + } }; } diff --git a/components/esm/esm_reader.cpp b/components/esm/esm_reader.cpp new file mode 100644 index 000000000..00a34e2df --- /dev/null +++ b/components/esm/esm_reader.cpp @@ -0,0 +1,345 @@ +#include "esm_reader.hpp" + +namespace ESM +{ + +ESM_Context ESMReader::getContext() +{ + // Update the file position before returning + mCtx.filePos = mEsm->tell(); + return mCtx; +} + +void ESMReader::restoreContext(const ESM_Context &rc) +{ + // Reopen the file if necessary + if (mCtx.filename != rc.filename) + openRaw(rc.filename); + + // Copy the data + mCtx = rc; + + // Make sure we seek to the right place + mEsm->seek(mCtx.filePos); +} + +void ESMReader::close() +{ + mEsm.reset(); + mCtx.filename.clear(); + mCtx.leftFile = 0; + mCtx.leftRec = 0; + mCtx.leftSub = 0; + mCtx.subCached = false; + mCtx.recName.val = 0; + mCtx.subName.val = 0; +} + +void ESMReader::openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name) +{ + close(); + mEsm = _esm; + mCtx.filename = name; + mCtx.leftFile = mEsm->size(); + + // Flag certain files for special treatment, based on the file + // name. + const char *cstr = mCtx.filename.c_str(); + if (iends(cstr, "Morrowind.esm")) + mSpf = SF_Morrowind; + else if (iends(cstr, "Tribunal.esm")) + mSpf = SF_Tribunal; + else if (iends(cstr, "Bloodmoon.esm")) + mSpf = SF_Bloodmoon; + else + mSpf = SF_Other; +} + +void ESMReader::open(Mangle::Stream::StreamPtr _esm, const std::string &name) +{ + openRaw(_esm, name); + + if (getRecName() != "TES3") + fail("Not a valid Morrowind file"); + + getRecHeader(); + + // Get the header + getHNT(mCtx.header, "HEDR", 300); + + if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) + fail("Unsupported file format version"); + + while (isNextSub("MAST")) + { + MasterData m; + m.name = getHString(); + m.size = getHNLong("DATA"); + mMasters.push_back(m); + } + + if (mCtx.header.type == FT_ESS) + { + // Savegame-related data + + // Player position etc + getHNT(mSaveData, "GMDT", 124); + + /* Image properties, five ints. Is always: + Red-mask: 0xff0000 + Blue-mask: 0x00ff00 + Green-mask: 0x0000ff + Alpha-mask: 0x000000 + Bpp: 32 + */ + getSubNameIs("SCRD"); + skipHSubSize(20); + + /* Savegame screenshot: + 128x128 pixels * 4 bytes per pixel + */ + getSubNameIs("SCRS"); + skipHSubSize(65536); + } +} + +void ESMReader::open(const std::string &file) +{ + using namespace Mangle::Stream; + open(StreamPtr(new FileStream(file)), file); +} + +void ESMReader::openRaw(const std::string &file) +{ + using namespace Mangle::Stream; + openRaw(StreamPtr(new FileStream(file)), file); +} + +int64_t ESMReader::getHNLong(const char *name) +{ + int64_t val; + getHNT(val, name); + return val; +} + +std::string ESMReader::getHNOString(const char* name) +{ + if (isNextSub(name)) + return getHString(); + return ""; +} + +std::string ESMReader::getHNString(const char* name) +{ + getSubNameIs(name); + return getHString(); +} + +std::string ESMReader::getHString() +{ + getSubHeader(); + + // Hack to make MultiMark.esp load. Zero-length strings do not + // occur in any of the official mods, but MultiMark makes use of + // them. For some reason, they break the rules, and contain a byte + // (value 0) even if the header says there is no data. If + // Morrowind accepts it, so should we. + if (mCtx.leftSub == 0) + { + // Skip the following zero byte + mCtx.leftRec--; + char c; + mEsm->read(&c, 1); + return ""; + } + + return getString(mCtx.leftSub); +} + +void ESMReader::getHExact(void*p, int size) +{ + getSubHeader(); + if (size != static_cast (mCtx.leftSub)) + fail("getHExact() size mismatch"); + getExact(p, size); +} + +// Read the given number of bytes from a named subrecord +void ESMReader::getHNExact(void*p, int size, const char* name) +{ + getSubNameIs(name); + getHExact(p, size); +} + +// Get the next subrecord name and check if it matches the parameter +void ESMReader::getSubNameIs(const char* name) +{ + getSubName(); + if (mCtx.subName != name) + fail( + "Expected subrecord " + std::string(name) + " but got " + + mCtx.subName.toString()); +} + +bool ESMReader::isNextSub(const char* name) +{ + if (!mCtx.leftRec) + return false; + + getSubName(); + + // If the name didn't match, then mark the it as 'cached' so it's + // available for the next call to getSubName. + mCtx.subCached = (mCtx.subName != name); + + // If subCached is false, then subName == name. + return !mCtx.subCached; +} + +// Read subrecord name. This gets called a LOT, so I've optimized it +// slightly. +void ESMReader::getSubName() +{ + // If the name has already been read, do nothing + if (mCtx.subCached) + { + mCtx.subCached = false; + return; + } + + // reading the subrecord data anyway. + mEsm->read(mCtx.subName.name, 4); + mCtx.leftRec -= 4; +} + +bool ESMReader::isEmptyOrGetName() +{ + if (mCtx.leftRec) + { + mEsm->read(mCtx.subName.name, 4); + mCtx.leftRec -= 4; + return false; + } + return true; +} + +void ESMReader::skipHSub() +{ + getSubHeader(); + skip(mCtx.leftSub); +} + +void ESMReader::skipHSubSize(int size) +{ + skipHSub(); + if (static_cast (mCtx.leftSub) != size) + fail("skipHSubSize() mismatch"); +} + +void ESMReader::getSubHeader() +{ + if (mCtx.leftRec < 4) + fail("End of record while reading sub-record header"); + + // Get subrecord size + getT(mCtx.leftSub); + + // Adjust number of record bytes left + mCtx.leftRec -= mCtx.leftSub + 4; +} + +void ESMReader::getSubHeaderIs(int size) +{ + getSubHeader(); + if (size != static_cast (mCtx.leftSub)) + fail("getSubHeaderIs(): Sub header mismatch"); +} + +NAME ESMReader::getRecName() +{ + if (!hasMoreRecs()) + fail("No more records, getRecName() failed"); + getName(mCtx.recName); + mCtx.leftFile -= 4; + + // Make sure we don't carry over any old cached subrecord + // names. This can happen in some cases when we skip parts of a + // record. + mCtx.subCached = false; + + return mCtx.recName; +} + +void ESMReader::skipRecord() +{ + skip(mCtx.leftRec); + mCtx.leftRec = 0; +} + +void ESMReader::skipHRecord() +{ + if (!mCtx.leftFile) + return; + getRecHeader(); + skipRecord(); +} + +void ESMReader::getRecHeader(uint32_t &flags) +{ + // General error checking + if (mCtx.leftFile < 12) + fail("End of file while reading record header"); + if (mCtx.leftRec) + fail("Previous record contains unread bytes"); + + getUint(mCtx.leftRec); + getUint(flags);// This header entry is always zero + getUint(flags); + mCtx.leftFile -= 12; + + // Check that sizes add up + if (mCtx.leftFile < mCtx.leftRec) + fail("Record size is larger than rest of file"); + + // Adjust number of bytes mCtx.left in file + mCtx.leftFile -= mCtx.leftRec; +} + +/************************************************************************* + * + * Lowest level data reading and misc methods + * + *************************************************************************/ + +void ESMReader::getExact(void*x, int size) +{ + int t = mEsm->read(x, size); + if (t != size) + fail("Read error"); +} + +std::string ESMReader::getString(int size) +{ + char *ptr = ToUTF8::getBuffer(size); + mEsm->read(ptr, size); + + // Convert to UTF8 and return + return ToUTF8::getUtf8(ToUTF8::WINDOWS_1252); +} + +void ESMReader::fail(const std::string &msg) +{ + using namespace std; + + stringstream ss; + + ss << "ESM Error: " << msg; + ss << "\n File: " << mCtx.filename; + ss << "\n Record: " << mCtx.recName.toString(); + ss << "\n Subrecord: " << mCtx.subName.toString(); + if (mEsm != NULL) + ss << "\n Offset: 0x" << hex << mEsm->tell(); + throw std::runtime_error(ss.str()); +} + +} diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index 8f4fafd88..dea1980e2 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -171,122 +171,27 @@ public: /** Save the current file position and information in a ESM_Context struct */ - ESM_Context getContext() - { - // Update the file position before returning - mCtx.filePos = mEsm->tell(); - return mCtx; - } + ESM_Context getContext(); /** Restore a previously saved context */ - void restoreContext(const ESM_Context &rc) - { - // Reopen the file if necessary - if(mCtx.filename != rc.filename) - openRaw(rc.filename); - - // Copy the data - mCtx = rc; - - // Make sure we seek to the right place - mEsm->seek(mCtx.filePos); - } + void restoreContext(const ESM_Context &rc); /** Close the file, resets all information. After calling close() the structure may be reused to load a new file. */ - void close() - { - mEsm.reset(); - mCtx.filename.clear(); - mCtx.leftFile = 0; - mCtx.leftRec = 0; - mCtx.leftSub = 0; - mCtx.subCached = false; - mCtx.recName.val = 0; - mCtx.subName.val = 0; - } + void close(); /// Raw opening. Opens the file and sets everything up but doesn't /// parse the header. - void openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name) - { - close(); - mEsm = _esm; - mCtx.filename = name; - mCtx.leftFile = mEsm->size(); - - // Flag certain files for special treatment, based on the file - // name. - const char *cstr = mCtx.filename.c_str(); - if(iends(cstr, "Morrowind.esm")) mSpf = SF_Morrowind; - else if(iends(cstr, "Tribunal.esm")) mSpf = SF_Tribunal; - else if(iends(cstr, "Bloodmoon.esm")) mSpf = SF_Bloodmoon; - else mSpf = SF_Other; - } + void openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name); /// Load ES file from a new stream, parses the header. Closes the /// currently open file first, if any. - void open(Mangle::Stream::StreamPtr _esm, const std::string &name) - { - openRaw(_esm, name); + void open(Mangle::Stream::StreamPtr _esm, const std::string &name); - if(getRecName() != "TES3") - fail("Not a valid Morrowind file"); + void open(const std::string &file); - getRecHeader(); - - // Get the header - getHNT(mCtx.header, "HEDR", 300); - - if(mCtx.header.version != VER_12 && - mCtx.header.version != VER_13) - fail("Unsupported file format version"); - - while(isNextSub("MAST")) - { - MasterData m; - m.name = getHString(); - m.size = getHNLong("DATA"); - mMasters.push_back(m); - } - - if(mCtx.header.type == FT_ESS) - { - // Savegame-related data - - // Player position etc - getHNT(mSaveData, "GMDT", 124); - - /* Image properties, five ints. Is always: - Red-mask: 0xff0000 - Blue-mask: 0x00ff00 - Green-mask: 0x0000ff - Alpha-mask: 0x000000 - Bpp: 32 - */ - getSubNameIs("SCRD"); - skipHSubSize(20); - - /* Savegame screenshot: - 128x128 pixels * 4 bytes per pixel - */ - getSubNameIs("SCRS"); - skipHSubSize(65536); - } - } - - void open(const std::string &file) - { - using namespace Mangle::Stream; - open(StreamPtr(new FileStream(file)), file); - } - - void openRaw(const std::string &file) - { - using namespace Mangle::Stream; - openRaw(StreamPtr(new FileStream(file)), file); - } + void openRaw(const std::string &file); /************************************************************************* * @@ -306,8 +211,8 @@ public: template void getHNOT(X &x, const char* name) { - if(isNextSub(name)) - getHT(x); + if(isNextSub(name)) + getHT(x); } // Version with extra size checking, to make sure the compiler @@ -315,26 +220,21 @@ public: template void getHNT(X &x, const char* name, int size) { - assert(sizeof(X) == size); - getSubNameIs(name); - getHT(x); + assert(sizeof(X) == size); + getSubNameIs(name); + getHT(x); } - int64_t getHNLong(const char *name) - { - int64_t val; - getHNT(val, name); - return val; - } + int64_t getHNLong(const char *name); // Get data of a given type/size, including subrecord header template void getHT(X &x) { - getSubHeader(); - if(mCtx.leftSub != sizeof(X)) - fail("getHT(): subrecord size mismatch"); - getT(x); + getSubHeader(); + if (mCtx.leftSub != sizeof(X)) + fail("getHT(): subrecord size mismatch"); + getT(x); } // Version with extra size checking, to make sure the compiler @@ -342,62 +242,24 @@ public: template void getHT(X &x, int size) { - assert(sizeof(X) == size); - getHT(x); + assert(sizeof(X) == size); + getHT(x); } // Read a string by the given name if it is the next record. - std::string getHNOString(const char* name) - { - if(isNextSub(name)) - return getHString(); - return ""; - } + std::string getHNOString(const char* name); // Read a string with the given sub-record name - std::string getHNString(const char* name) - { - getSubNameIs(name); - return getHString(); - } + std::string getHNString(const char* name); // Read a string, including the sub-record header (but not the name) - std::string getHString() - { - getSubHeader(); - - // Hack to make MultiMark.esp load. Zero-length strings do not - // occur in any of the official mods, but MultiMark makes use of - // them. For some reason, they break the rules, and contain a byte - // (value 0) even if the header says there is no data. If - // Morrowind accepts it, so should we. - if(mCtx.leftSub == 0) - { - // Skip the following zero byte - mCtx.leftRec--; - char c; - mEsm->read(&c,1); - return ""; - } - - return getString(mCtx.leftSub); - } + std::string getHString(); // Read the given number of bytes from a subrecord - void getHExact(void*p, int size) - { - getSubHeader(); - if(size !=static_cast (mCtx.leftSub)) - fail("getHExact() size mismatch"); - getExact(p,size); - } + void getHExact(void*p, int size); // Read the given number of bytes from a named subrecord - void getHNExact(void*p, int size, const char* name) - { - getSubNameIs(name); - getHExact(p,size); - } + void getHNExact(void*p, int size, const char* name); /************************************************************************* * @@ -406,100 +268,37 @@ public: *************************************************************************/ // Get the next subrecord name and check if it matches the parameter - void getSubNameIs(const char* name) - { - getSubName(); - if(mCtx.subName != name) - fail("Expected subrecord " + std::string(name) + " but got " + mCtx.subName.toString()); - } + void getSubNameIs(const char* name); /** Checks if the next sub record name matches the parameter. If it does, it is read into 'subName' just as if getSubName() was called. If not, the read name will still be available for future calls to getSubName(), isNextSub() and getSubNameIs(). */ - bool isNextSub(const char* name) - { - if(!mCtx.leftRec) return false; - - getSubName(); - - // If the name didn't match, then mark the it as 'cached' so it's - // available for the next call to getSubName. - mCtx.subCached = (mCtx.subName != name); - - // If subCached is false, then subName == name. - return !mCtx.subCached; - } + bool isNextSub(const char* name); // Read subrecord name. This gets called a LOT, so I've optimized it // slightly. - void getSubName() - { - // If the name has already been read, do nothing - if(mCtx.subCached) - { - mCtx.subCached = false; - return; - } - - // Don't bother with error checking, we will catch an EOF upon - // reading the subrecord data anyway. - mEsm->read(mCtx.subName.name, 4); - mCtx.leftRec -= 4; - } + void getSubName(); // This is specially optimized for LoadINFO. - bool isEmptyOrGetName() - { - if(mCtx.leftRec) - { - mEsm->read(mCtx.subName.name, 4); - mCtx.leftRec -= 4; - return false; - } - return true; - } + bool isEmptyOrGetName(); // Skip current sub record, including header (but not including // name.) - void skipHSub() - { - getSubHeader(); - skip(mCtx.leftSub); - } + void skipHSub(); // Skip sub record and check its size - void skipHSubSize(int size) - { - skipHSub(); - if(static_cast (mCtx.leftSub) != size) - fail("skipHSubSize() mismatch"); - } + void skipHSubSize(int size); /* Sub-record header. This updates leftRec beyond the current sub-record as well. leftSub contains size of current sub-record. */ - void getSubHeader() - { - if(mCtx.leftRec < 4) - fail("End of record while reading sub-record header"); - - // Get subrecord size - getT(mCtx.leftSub); - - // Adjust number of record bytes left - mCtx.leftRec -= mCtx.leftSub + 4; - } + void getSubHeader(); /** Get sub header and check the size */ - void getSubHeaderIs(int size) - { - getSubHeader(); - if(size != static_cast (mCtx.leftSub)) - fail("getSubHeaderIs(): Sub header mismatch"); - } + void getSubHeaderIs(int size); /************************************************************************* * @@ -508,62 +307,21 @@ public: *************************************************************************/ // Get the next record name - NAME getRecName() - { - if(!hasMoreRecs()) - fail("No more records, getRecName() failed"); - getName(mCtx.recName); - mCtx.leftFile -= 4; - - // Make sure we don't carry over any old cached subrecord - // names. This can happen in some cases when we skip parts of a - // record. - mCtx.subCached = false; - - return mCtx.recName; - } + NAME getRecName(); // Skip the rest of this record. Assumes the name and header have // already been read - void skipRecord() - { - skip(mCtx.leftRec); - mCtx.leftRec = 0; - } + void skipRecord(); // Skip an entire record, including the header (but not the name) - void skipHRecord() - { - if(!mCtx.leftFile) return; - getRecHeader(); - skipRecord(); - } + void skipHRecord(); /* Read record header. This updatesleftFile BEYOND the data that follows the header, ie beyond the entire record. You should use leftRec to orient yourself inside the record itself. */ void getRecHeader() { uint32_t u; getRecHeader(u); } - void getRecHeader(uint32_t &flags) - { - // General error checking - if(mCtx.leftFile < 12) - fail("End of file while reading record header"); - if(mCtx.leftRec) - fail("Previous record contains unread bytes"); - - getUint(mCtx.leftRec); - getUint(flags);// This header entry is always zero - getUint(flags); - mCtx.leftFile -= 12; - - // Check that sizes add up - if(mCtx.leftFile < mCtx.leftRec) - fail("Record size is larger than rest of file"); - - // Adjust number of bytes mCtx.left in file - mCtx.leftFile -= mCtx.leftRec; - } + void getRecHeader(uint32_t &flags); bool hasMoreRecs() { return mCtx.leftFile > 0; } bool hasMoreSubs() { return mCtx.leftRec > 0; } @@ -578,44 +336,19 @@ public: template void getT(X &x) { getExact(&x, sizeof(X)); } - void getExact(void*x, int size) - { - int t = mEsm->read(x, size); - if(t != size) - fail("Read error"); - } + void getExact(void*x, int size); void getName(NAME &name) { getT(name); } void getUint(uint32_t &u) { getT(u); } // Read the next 'size' bytes and return them as a string. Converts // them from native encoding to UTF8 in the process. - std::string getString(int size) - { - char *ptr = ToUTF8::getBuffer(size); - mEsm->read(ptr,size); - - // Convert to UTF8 and return - return ToUTF8::getUtf8(ToUTF8::WINDOWS_1252); - } + std::string getString(int size); void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); } uint64_t getOffset() { return mEsm->tell(); } /// Used for error handling - void fail(const std::string &msg) - { - using namespace std; - - stringstream ss; - - ss << "ESM Error: " << msg; - ss << "\n File: " << mCtx.filename; - ss << "\n Record: " << mCtx.recName.toString(); - ss << "\n Subrecord: " << mCtx.subName.toString(); - if(mEsm != NULL) - ss << "\n Offset: 0x" << hex << mEsm->tell(); - throw std::runtime_error(ss.str()); - } + void fail(const std::string &msg); private: Mangle::Stream::StreamPtr mEsm; diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp new file mode 100644 index 000000000..40c9b635c --- /dev/null +++ b/components/esm/loadacti.cpp @@ -0,0 +1,11 @@ +#include "loadacti.hpp" + +namespace ESM +{ +void Activator::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNString("FNAM"); + script = esm.getHNOString("SCRI"); +} +} diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index a50a58f6d..783559e11 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -3,18 +3,14 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ struct Activator { - std::string name, script, model; + std::string name, script, model; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNString("FNAM"); - script = esm.getHNOString("SCRI"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp new file mode 100644 index 000000000..d3bc36a77 --- /dev/null +++ b/components/esm/loadalch.cpp @@ -0,0 +1,14 @@ +#include "loadalch.hpp" + +namespace ESM +{ +void Potion::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + icon = esm.getHNOString("TEXT"); // not ITEX here for some reason + script = esm.getHNOString("SCRI"); + name = esm.getHNOString("FNAM"); + esm.getHNT(data, "ALDT", 12); + effects.load(esm); +} +} diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index a556350b0..c21e5dea0 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -4,7 +4,8 @@ #include "esm_reader.hpp" #include "defs.hpp" -namespace ESM { +namespace ESM +{ /* * Alchemy item (potions) @@ -12,26 +13,18 @@ namespace ESM { struct Potion { - struct ALDTstruct - { - float weight; - int value; - int autoCalc; - }; - ALDTstruct data; + struct ALDTstruct + { + float weight; + int value; + int autoCalc; + }; + ALDTstruct data; - std::string name, model, icon, script; - EffectList effects; + std::string name, model, icon, script; + EffectList effects; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - icon = esm.getHNOString("TEXT"); // not ITEX here for some reason - script = esm.getHNOString("SCRI"); - name = esm.getHNOString("FNAM"); - esm.getHNT(data, "ALDT", 12); - effects.load(esm); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp new file mode 100644 index 000000000..c76ad5350 --- /dev/null +++ b/components/esm/loadappa.cpp @@ -0,0 +1,13 @@ +#include "loadappa.hpp" + +namespace ESM +{ +void Apparatus::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNString("FNAM"); + esm.getHNT(data, "AADT", 16); + script = esm.getHNOString("SCRI"); + icon = esm.getHNString("ITEX"); +} +} diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 6fd1d00d8..bbb4aefde 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Alchemist apparatus @@ -11,33 +12,23 @@ namespace ESM { struct Apparatus { - enum AppaType + enum AppaType { - MortarPestle = 0, - Albemic = 1, - Calcinator = 2, - Retort = 3 + MortarPestle = 0, Albemic = 1, Calcinator = 2, Retort = 3 }; - struct AADTstruct - { - int type; - float quality; - float weight; - int value; - }; + struct AADTstruct + { + int type; + float quality; + float weight; + int value; + }; - AADTstruct data; - std::string model, icon, script, name; + AADTstruct data; + std::string model, icon, script, name; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNString("FNAM"); - esm.getHNT(data, "AADT", 16); - script = esm.getHNOString("SCRI"); - icon = esm.getHNString("ITEX"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp new file mode 100644 index 000000000..ddc25e176 --- /dev/null +++ b/components/esm/loadarmo.cpp @@ -0,0 +1,28 @@ +#include "loadarmo.hpp" + +namespace ESM +{ + +void PartReferenceList::load(ESMReader &esm) +{ + while (esm.isNextSub("INDX")) + { + PartReference pr; + esm.getHT(pr.part); // The INDX byte + pr.male = esm.getHNOString("BNAM"); + pr.female = esm.getHNOString("CNAM"); + } +} + +void Armor::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNString("FNAM"); + script = esm.getHNOString("SCRI"); + esm.getHNT(data, "AODT", 24); + icon = esm.getHNOString("ITEX"); + parts.load(esm); + enchant = esm.getHNOString("ENAM"); +} + +} diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index c10287869..16b6b1d3a 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -3,102 +3,85 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ enum PartReferenceType - { - PRT_Head = 0, - PRT_Hair = 1, - PRT_Neck = 2, - PRT_Cuirass = 3, - PRT_Groin = 4, - PRT_Skirt = 5, - PRT_RHand = 6, - PRT_LHand = 7, - PRT_RWrist = 8, - PRT_LWrist = 9, - PRT_Shield = 10, - PRT_RForearm = 11, - PRT_LForearm = 12, - PRT_RUpperarm = 13, - PRT_LUpperarm = 14, - PRT_RFoot = 15, - PRT_LFoot = 16, - PRT_RAnkle = 17, - PRT_LAnkle = 18, - PRT_RKnee = 19, - PRT_LKnee = 20, - PRT_RLeg = 21, - PRT_LLeg = 22, - PRT_RPauldron = 23, - PRT_LPauldron = 24, - PRT_Weapon = 25, - PRT_Tail = 26 - }; +{ + PRT_Head = 0, + PRT_Hair = 1, + PRT_Neck = 2, + PRT_Cuirass = 3, + PRT_Groin = 4, + PRT_Skirt = 5, + PRT_RHand = 6, + PRT_LHand = 7, + PRT_RWrist = 8, + PRT_LWrist = 9, + PRT_Shield = 10, + PRT_RForearm = 11, + PRT_LForearm = 12, + PRT_RUpperarm = 13, + PRT_LUpperarm = 14, + PRT_RFoot = 15, + PRT_LFoot = 16, + PRT_RAnkle = 17, + PRT_LAnkle = 18, + PRT_RKnee = 19, + PRT_LKnee = 20, + PRT_RLeg = 21, + PRT_LLeg = 22, + PRT_RPauldron = 23, + PRT_LPauldron = 24, + PRT_Weapon = 25, + PRT_Tail = 26 +}; // Reference to body parts struct PartReference { - char part; - std::string male, female; + char part; + std::string male, female; }; // A list of references to body parts struct PartReferenceList { - std::vector parts; + std::vector parts; - void load(ESMReader &esm) - { - while(esm.isNextSub("INDX")) - { - PartReference pr; - esm.getHT(pr.part); // The INDX byte - pr.male = esm.getHNOString("BNAM"); - pr.female = esm.getHNOString("CNAM"); - } - } + void load(ESMReader &esm); }; struct Armor { - enum Type - { - Helmet = 0, - Cuirass = 1, - LPauldron = 2, - RPauldron = 3, - Greaves = 4, - Boots = 5, - LGauntlet = 6, - RGauntlet = 7, - Shield = 8, - LBracer = 9, - RBracer = 10 - }; + enum Type + { + Helmet = 0, + Cuirass = 1, + LPauldron = 2, + RPauldron = 3, + Greaves = 4, + Boots = 5, + LGauntlet = 6, + RGauntlet = 7, + Shield = 8, + LBracer = 9, + RBracer = 10 + }; - struct AODTstruct - { - int type; - float weight; - int value, health, enchant, armor; - }; + struct AODTstruct + { + int type; + float weight; + int value, health, enchant, armor; + }; - AODTstruct data; - PartReferenceList parts; + AODTstruct data; + PartReferenceList parts; - std::string name, model, icon, script, enchant; + std::string name, model, icon, script, enchant; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNString("FNAM"); - script = esm.getHNOString("SCRI"); - esm.getHNT(data, "AODT", 24); - icon = esm.getHNOString("ITEX"); - parts.load(esm); - enchant = esm.getHNOString("ENAM"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp new file mode 100644 index 000000000..1c72b0fe0 --- /dev/null +++ b/components/esm/loadbody.cpp @@ -0,0 +1,13 @@ +#include "loadbody.hpp" + +namespace ESM +{ + +void BodyPart::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNString("FNAM"); + esm.getHNT(data, "BYDT", 4); +} + +} diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index 5da0e6acb..14e28f59c 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -3,59 +3,52 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ struct BodyPart { - enum MeshPart + enum MeshPart { - MP_Head = 0, - MP_Hair = 1, - MP_Neck = 2, - MP_Chest = 3, - MP_Groin = 4, - MP_Hand = 5, - MP_Wrist = 6, - MP_Forearm = 7, - MP_Upperarm = 8, - MP_Foot = 9, - MP_Ankle = 10, - MP_Knee = 11, - MP_Upperleg = 12, - MP_Clavicle = 13, - MP_Tail = 14 + MP_Head = 0, + MP_Hair = 1, + MP_Neck = 2, + MP_Chest = 3, + MP_Groin = 4, + MP_Hand = 5, + MP_Wrist = 6, + MP_Forearm = 7, + MP_Upperarm = 8, + MP_Foot = 9, + MP_Ankle = 10, + MP_Knee = 11, + MP_Upperleg = 12, + MP_Clavicle = 13, + MP_Tail = 14 }; - enum Flags + enum Flags { - BPF_Female = 1, - BPF_Playable = 2 + BPF_Female = 1, BPF_Playable = 2 }; - enum MeshType + enum MeshType { - MT_Skin = 0, - MT_Clothing = 1, - MT_Armor = 2 + MT_Skin = 0, MT_Clothing = 1, MT_Armor = 2 }; - struct BYDTstruct - { - char part; - char vampire; - char flags; - char type; - }; + struct BYDTstruct + { + char part; + char vampire; + char flags; + char type; + }; - BYDTstruct data; - std::string model, name; + BYDTstruct data; + std::string model, name; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNString("FNAM"); - esm.getHNT(data, "BYDT", 4); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp new file mode 100644 index 000000000..ffa958e14 --- /dev/null +++ b/components/esm/loadbook.cpp @@ -0,0 +1,17 @@ +#include "loadbook.hpp" + +namespace ESM +{ + +void Book::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNOString("FNAM"); + esm.getHNT(data, "BKDT", 20); + script = esm.getHNOString("SCRI"); + icon = esm.getHNOString("ITEX"); + text = esm.getHNOString("TEXT"); + enchant = esm.getHNOString("ENAM"); +} + +} diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index 8e9da0d51..3a4ab441e 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Books, magic scrolls, notes and so on @@ -11,25 +12,16 @@ namespace ESM { struct Book { - struct BKDTstruct - { - float weight; - int value, isScroll, skillID, enchant; - }; + struct BKDTstruct + { + float weight; + int value, isScroll, skillID, enchant; + }; - BKDTstruct data; - std::string name, model, icon, script, enchant, text; + BKDTstruct data; + std::string name, model, icon, script, enchant, text; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNOString("FNAM"); - esm.getHNT(data, "BKDT", 20); - script = esm.getHNOString("SCRI"); - icon = esm.getHNOString("ITEX"); - text = esm.getHNOString("TEXT"); - enchant = esm.getHNOString("ENAM"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp new file mode 100644 index 000000000..976cb7d20 --- /dev/null +++ b/components/esm/loadbsgn.cpp @@ -0,0 +1,15 @@ +#include "loadbsgn.hpp" + +namespace ESM +{ + +void BirthSign::load(ESMReader &esm) +{ + name = esm.getHNString("FNAM"); + texture = esm.getHNOString("TNAM"); + description = esm.getHNOString("DESC"); + + powers.load(esm); +} + +} diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index 8c713e5ef..53964b02c 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -4,23 +4,17 @@ #include "defs.hpp" #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ struct BirthSign { - std::string name, description, texture; + std::string name, description, texture; - // List of powers and abilities that come with this birth sign. - SpellList powers; + // List of powers and abilities that come with this birth sign. + SpellList powers; - void load(ESMReader &esm) - { - name = esm.getHNString("FNAM"); - texture = esm.getHNOString("TNAM"); - description = esm.getHNOString("DESC"); - - powers.load(esm); - }; + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp new file mode 100644 index 000000000..2d1085260 --- /dev/null +++ b/components/esm/loadcell.cpp @@ -0,0 +1,113 @@ +#include "loadcell.hpp" + +namespace ESM +{ + +void Cell::load(ESMReader &esm) +{ + // Ignore this for now, it might mean we should delete the entire + // cell? + if (esm.isNextSub("DELE")) + esm.skipHSub(); + + esm.getHNT(data, "DATA", 12); + + // Water level + water = 0; + + if (data.flags & Interior) + { + // Interior cells + + if (esm.isNextSub("INTV") || esm.isNextSub("WHGT")) + esm.getHT(water); + + // Quasi-exterior cells have a region (which determines the + // weather), pure interior cells have ambient lighting + // instead. + if (data.flags & QuasiEx) + region = esm.getHNOString("RGNN"); + else + esm.getHNT(ambi, "AMBI", 16); + } + else + { + // Exterior cells + region = esm.getHNOString("RGNN"); + esm.getHNOT(mapColor, "NAM5"); + } + + // Save position of the cell references and move on + context = esm.getContext(); + esm.skipRecord(); +} + +void Cell::restore(ESMReader &esm) const +{ + esm.restoreContext(context); +} + +bool Cell::getNextRef(ESMReader &esm, CellRef &ref) +{ + if (!esm.hasMoreSubs()) + return false; + + // Number of references in the cell? Maximum once in each cell, + // but not always at the beginning, and not always right. In other + // words, completely useless. + { + int i; + esm.getHNOT(i, "NAM0"); + } + + esm.getHNT(ref.refnum, "FRMR"); + ref.refID = esm.getHNString("NAME"); + + // getHNOT will not change the existing value if the subrecord is + // missing + ref.scale = 1.0; + esm.getHNOT(ref.scale, "XSCL"); + + ref.owner = esm.getHNOString("ANAM"); + ref.glob = esm.getHNOString("BNAM"); + ref.soul = esm.getHNOString("XSOL"); + + ref.faction = esm.getHNOString("CNAM"); + ref.factIndex = -1; + esm.getHNOT(ref.factIndex, "INDX"); + + ref.charge = -1.0; + esm.getHNOT(ref.charge, "XCHG"); + + ref.intv = 0; + ref.nam9 = 0; + esm.getHNOT(ref.intv, "INTV"); + esm.getHNOT(ref.nam9, "NAM9"); + + // Present for doors that teleport you to another cell. + if (esm.isNextSub("DODT")) + { + ref.teleport = true; + esm.getHT(ref.doorDest); + ref.destCell = esm.getHNOString("DNAM"); + } + else + ref.teleport = false; + + // Integer, despite the name suggesting otherwise + ref.lockLevel = 0; + esm.getHNOT(ref.lockLevel, "FLTV"); + ref.key = esm.getHNOString("KNAM"); + ref.trap = esm.getHNOString("TNAM"); + + ref.unam = 0; + ref.fltv = 0; + esm.getHNOT(ref.unam, "UNAM"); + esm.getHNOT(ref.fltv, "FLTV"); + + esm.getHNT(ref.pos, "DATA", 24); + + return true; +} + +} diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 3f2a6b5a2..bf3ec6f73 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -117,51 +117,14 @@ struct Cell int water; // Water level int mapColor; - void load(ESMReader &esm) - { - // Ignore this for now, it might mean we should delete the entire - // cell? - if(esm.isNextSub("DELE")) esm.skipHSub(); - - esm.getHNT(data, "DATA", 12); - - // Water level - water = 0; - - if(data.flags & Interior) - { - // Interior cells - - if(esm.isNextSub("INTV") || esm.isNextSub("WHGT")) - esm.getHT(water); - - // Quasi-exterior cells have a region (which determines the - // weather), pure interior cells have ambient lighting - // instead. - if(data.flags & QuasiEx) - region = esm.getHNOString("RGNN"); - else - esm.getHNT(ambi, "AMBI", 16); - } - else - { - // Exterior cells - region = esm.getHNOString("RGNN"); - esm.getHNOT(mapColor, "NAM5"); - } - - // Save position of the cell references and move on - context = esm.getContext(); - esm.skipRecord(); - } + void load(ESMReader &esm); // Restore the given reader to the stored position. Will try to open // the file matching the stored file name. If you want to read from // somewhere other than the file system, you need to pre-open the // ESMReader, and the filename must match the stored filename // exactly. - void restore(ESMReader &esm) const - { esm.restoreContext(context); } + void restore(ESMReader &esm) const; /* Get the next reference in this cell, if any. Returns false when there are no more references in the cell. @@ -169,66 +132,7 @@ struct Cell All fields of the CellRef struct are overwritten. You can safely reuse one memory location without blanking it between calls. */ - static bool getNextRef(ESMReader &esm, CellRef &ref) - { - if(!esm.hasMoreSubs()) return false; - - // Number of references in the cell? Maximum once in each cell, - // but not always at the beginning, and not always right. In other - // words, completely useless. - { - int i; - esm.getHNOT(i, "NAM0"); - } - - esm.getHNT(ref.refnum, "FRMR"); - ref.refID = esm.getHNString("NAME"); - - // getHNOT will not change the existing value if the subrecord is - // missing - ref.scale = 1.0; - esm.getHNOT(ref.scale, "XSCL"); - - ref.owner = esm.getHNOString("ANAM"); - ref.glob = esm.getHNOString("BNAM"); - ref.soul = esm.getHNOString("XSOL"); - - ref.faction = esm.getHNOString("CNAM"); - ref.factIndex = -1; - esm.getHNOT(ref.factIndex, "INDX"); - - ref.charge = -1.0; - esm.getHNOT(ref.charge, "XCHG"); - - ref.intv = 0; - ref.nam9 = 0; - esm.getHNOT(ref.intv, "INTV"); - esm.getHNOT(ref.nam9, "NAM9"); - - // Present for doors that teleport you to another cell. - if(esm.isNextSub("DODT")) - { - ref.teleport = true; - esm.getHT(ref.doorDest); - ref.destCell = esm.getHNOString("DNAM"); - } - else ref.teleport = false; - - // Integer, despite the name suggesting otherwise - ref.lockLevel = 0; - esm.getHNOT(ref.lockLevel, "FLTV"); - ref.key = esm.getHNOString("KNAM"); - ref.trap = esm.getHNOString("TNAM"); - - ref.unam = 0; - ref.fltv = 0; - esm.getHNOT(ref.unam, "UNAM"); - esm.getHNOT(ref.fltv, "FLTV"); - - esm.getHNT(ref.pos, "DATA", 24); - - return true; - } + static bool getNextRef(ESMReader &esm, CellRef &ref); }; } #endif diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp new file mode 100644 index 000000000..9a0b847ab --- /dev/null +++ b/components/esm/loadclas.cpp @@ -0,0 +1,17 @@ +#include "loadclas.hpp" + +namespace ESM +{ + +void Class::load(ESMReader &esm) +{ + name = esm.getHNString("FNAM"); + esm.getHNT(data, "CLDT", 60); + + if (data.isPlayable > 1) + esm.fail("Unknown bool value"); + + description = esm.getHNOString("DESC"); +} + +} diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 999fdfffd..5fc44abe5 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Character class definitions @@ -13,62 +14,51 @@ namespace ESM { // class struct Class { - enum AutoCalc + enum AutoCalc { - Weapon = 0x00001, - Armor = 0x00002, - Clothing = 0x00004, - Books = 0x00008, - Ingredient = 0x00010, - Lockpick = 0x00020, - Probe = 0x00040, - Lights = 0x00080, - Apparatus = 0x00100, - Repair = 0x00200, - Misc = 0x00400, - Spells = 0x00800, - MagicItems = 0x01000, - Potions = 0x02000, - Training = 0x04000, - Spellmaking = 0x08000, - Enchanting = 0x10000, - RepairItem = 0x20000 + Weapon = 0x00001, + Armor = 0x00002, + Clothing = 0x00004, + Books = 0x00008, + Ingredient = 0x00010, + Lockpick = 0x00020, + Probe = 0x00040, + Lights = 0x00080, + Apparatus = 0x00100, + Repair = 0x00200, + Misc = 0x00400, + Spells = 0x00800, + MagicItems = 0x01000, + Potions = 0x02000, + Training = 0x04000, + Spellmaking = 0x08000, + Enchanting = 0x10000, + RepairItem = 0x20000 }; - enum Specialization + enum Specialization { - Combat = 0, - Magic = 1, - Stealth = 2 + Combat = 0, Magic = 1, Stealth = 2 }; - static const Specialization specializationIds[3]; - static const char *gmstSpecializationIds[3]; + static const Specialization specializationIds[3]; + static const char *gmstSpecializationIds[3]; - struct CLDTstruct - { - int attribute[2]; // Attributes that get class bonus - int specialization; // 0 = Combat, 1 = Magic, 2 = Stealth - int skills[5][2]; // Minor and major skills. - int isPlayable; // 0x0001 - Playable class - - // I have no idea how to autocalculate these items... - int calc; - }; // 60 bytes - - std::string name, description; - CLDTstruct data; - - void load(ESMReader &esm) + struct CLDTstruct { - name = esm.getHNString("FNAM"); - esm.getHNT(data, "CLDT", 60); + int attribute[2]; // Attributes that get class bonus + int specialization; // 0 = Combat, 1 = Magic, 2 = Stealth + int skills[5][2]; // Minor and major skills. + int isPlayable; // 0x0001 - Playable class - if(data.isPlayable > 1) - esm.fail("Unknown bool value"); + // I have no idea how to autocalculate these items... + int calc; + }; // 60 bytes - description = esm.getHNOString("DESC"); - } + std::string name, description; + CLDTstruct data; + + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp new file mode 100644 index 000000000..1d6c9d4a1 --- /dev/null +++ b/components/esm/loadclot.cpp @@ -0,0 +1,20 @@ +#include "loadclot.hpp" + +namespace ESM +{ + +void Clothing::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNOString("FNAM"); + esm.getHNT(data, "CTDT", 12); + + script = esm.getHNOString("SCRI"); + icon = esm.getHNOString("ITEX"); + + parts.load(esm); + + enchant = esm.getHNOString("ENAM"); +} + +} diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 47b24ddb1..8fa06e7e4 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -4,7 +4,8 @@ #include "esm_reader.hpp" #include "loadarmo.hpp" -namespace ESM { +namespace ESM +{ /* * Clothing @@ -12,46 +13,34 @@ namespace ESM { struct Clothing { - enum Type + enum Type { - Pants = 0, - Shoes = 1, - Shirt = 2, - Belt = 3, - Robe = 4, - RGlove = 5, - LGlove = 6, - Skirt = 7, - Ring = 8, - Amulet = 9 + Pants = 0, + Shoes = 1, + Shirt = 2, + Belt = 3, + Robe = 4, + RGlove = 5, + LGlove = 6, + Skirt = 7, + Ring = 8, + Amulet = 9 }; - struct CTDTstruct - { - int type; - float weight; - short value; - short enchant; - }; - CTDTstruct data; + struct CTDTstruct + { + int type; + float weight; + short value; + short enchant; + }; + CTDTstruct data; - PartReferenceList parts; + PartReferenceList parts; - std::string name, model, icon, enchant, script; + std::string name, model, icon, enchant, script; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNOString("FNAM"); - esm.getHNT(data, "CTDT", 12); - - script = esm.getHNOString("SCRI"); - icon = esm.getHNOString("ITEX"); - - parts.load(esm); - - enchant = esm.getHNOString("ENAM"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp new file mode 100644 index 000000000..740d15a40 --- /dev/null +++ b/components/esm/loadland.cpp @@ -0,0 +1,32 @@ +#include "loadland.hpp" + +namespace ESM +{ +void Land::load(ESMReader &esm) +{ + // Get the grid location + esm.getSubNameIs("INTV"); + esm.getSubHeaderIs(8); + esm.getT(X); + esm.getT(Y); + + esm.getHNT(flags, "DATA"); + + // Store the file position + context = esm.getContext(); + + hasData = false; + int cnt = 0; + + // Skip these here. Load the actual data when the cell is loaded. + if(esm.isNextSub("VNML")) {esm.skipHSubSize(12675);cnt++;} + if(esm.isNextSub("VHGT")) {esm.skipHSubSize(4232);cnt++;} + if(esm.isNextSub("WNAM")) esm.skipHSubSize(81); + if(esm.isNextSub("VCLR")) esm.skipHSubSize(12675); + if(esm.isNextSub("VTEX")) {esm.skipHSubSize(512);cnt++;} + + // We need all three of VNML, VHGT and VTEX in order to use the + // landscape. + hasData = (cnt == 3); +} +} diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index d1a9e4068..af91850ac 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -3,51 +3,25 @@ #include "esm_reader.hpp" -namespace ESM { - +namespace ESM +{ /* * Landscape data. */ struct Land { - int flags; // Only first four bits seem to be used, don't know what - // they mean. - int X, Y; // Map coordinates. + int flags; // Only first four bits seem to be used, don't know what + // they mean. + int X, Y; // Map coordinates. - // File context. This allows the ESM reader to be 'reset' to this - // location later when we are ready to load the full data set. - ESM_Context context; + // File context. This allows the ESM reader to be 'reset' to this + // location later when we are ready to load the full data set. + ESM_Context context; - bool hasData; + bool hasData; - void load(ESMReader &esm) - { - // Get the grid location - esm.getSubNameIs("INTV"); - esm.getSubHeaderIs(8); - esm.getT(X); - esm.getT(Y); - - esm.getHNT(flags, "DATA"); - - // Store the file position - context = esm.getContext(); - - hasData = false; - int cnt = 0; - - // Skip these here. Load the actual data when the cell is loaded. - if(esm.isNextSub("VNML")) {esm.skipHSubSize(12675);cnt++;} - if(esm.isNextSub("VHGT")) {esm.skipHSubSize(4232);cnt++;} - if(esm.isNextSub("WNAM")) esm.skipHSubSize(81); - if(esm.isNextSub("VCLR")) esm.skipHSubSize(12675); - if(esm.isNextSub("VTEX")) {esm.skipHSubSize(512);cnt++;} - - // We need all three of VNML, VHGT and VTEX in order to use the - // landscape. - hasData = (cnt == 3); - } + void load(ESMReader &esm); }; } #endif