1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-03 15:09:39 +00:00

components/esm header refactoring in progress. Refactored:

esm_reader.hpp
loadacti.hpp
loadalch.hpp
loadappa.hpp
loadarmo.hpp
loadbody.hpp
loadbook.hpp
loadbsgn.hpp
loadcell.hpp
loadclas.hpp
loadclot.hpp
loadland.hpp
Updated code style in defs.hpp
This commit is contained in:
Nikolay Kasyanov 2011-04-06 20:11:08 +04:00
parent 4e7a056e9e
commit a2c42ab5a2
26 changed files with 942 additions and 762 deletions

View file

@ -131,6 +131,19 @@ set(ESM
${COMP_DIR}/esm/skill.cpp ${COMP_DIR}/esm/skill.cpp
${COMP_DIR}/esm/attr.cpp ${COMP_DIR}/esm/attr.cpp
${COMP_DIR}/esm/class.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}) source_group(components\\esm FILES ${ESM_HEADER} ${ESM})

View file

@ -3,13 +3,14 @@
#include "esm_reader.hpp" #include "esm_reader.hpp"
namespace ESM { namespace ESM
{
// Pixel color value. Standard four-byte rr,gg,bb,aa format. // Pixel color value. Standard four-byte rr,gg,bb,aa format.
typedef int32_t Color; typedef int32_t Color;
enum VarType enum VarType
{ {
VT_Unknown, VT_Unknown,
VT_None, VT_None,
VT_Short, VT_Short,
@ -18,79 +19,75 @@ enum VarType
VT_Float, VT_Float,
VT_String, VT_String,
VT_Ignored VT_Ignored
}; };
enum Specialization enum Specialization
{ {
SPC_Combat = 0, SPC_Combat = 0, SPC_Magic = 1, SPC_Stealth = 2
SPC_Magic = 1, };
SPC_Stealth = 2
};
enum RangeType enum RangeType
{ {
RT_Self = 0, RT_Self = 0, RT_Touch = 1, RT_Target = 2
RT_Touch = 1, };
RT_Target = 2
};
/** A list of references to spells and spell effects. This is shared /** 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 struct SpellList
{ {
std::vector<std::string> list; std::vector<std::string> list;
void load(ESMReader &esm) void load(ESMReader &esm)
{ {
while(esm.isNextSub("NPCS")) while (esm.isNextSub("NPCS"))
list.push_back(esm.getHString()); list.push_back(esm.getHString());
} }
}; };
/** Defines a spell effect. Shared between SPEL (Spells), ALCH /** 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(push)
#pragma pack(1) #pragma pack(1)
// Position and rotation // Position and rotation
struct Position struct Position
{ {
float pos[3]; float pos[3];
float rot[3]; float rot[3];
}; };
struct ENAMstruct struct ENAMstruct
{ {
// Magical effect, hard-coded ID // Magical effect, hard-coded ID
short effectID; short effectID;
// Which skills/attributes are affected (for restore/drain spells // Which skills/attributes are affected (for restore/drain spells
// etc.) // etc.)
signed char skill, attribute; // -1 if N/A signed char skill, attribute; // -1 if N/A
// Other spell parameters // Other spell parameters
int range; // 0 - self, 1 - touch, 2 - target (RangeType enum) int range; // 0 - self, 1 - touch, 2 - target (RangeType enum)
int area, duration, magnMin, magnMax; int area, duration, magnMin, magnMax;
// Struct size should be 24 bytes // Struct size should be 24 bytes
}; };
#pragma pack(pop) #pragma pack(pop)
struct EffectList struct EffectList
{ {
std::vector<ENAMstruct> list; std::vector<ENAMstruct> list;
void load(ESMReader &esm) void load(ESMReader &esm)
{ {
ENAMstruct s; ENAMstruct s;
while(esm.isNextSub("ENAM")) while (esm.isNextSub("ENAM"))
{ {
esm.getHT(s, 24); esm.getHT(s, 24);
list.push_back(s); list.push_back(s);
} }
} }
}; };
} }

View file

@ -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<int> (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<int> (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<int> (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());
}
}

View file

@ -171,122 +171,27 @@ public:
/** Save the current file position and information in a ESM_Context /** Save the current file position and information in a ESM_Context
struct struct
*/ */
ESM_Context getContext() ESM_Context getContext();
{
// Update the file position before returning
mCtx.filePos = mEsm->tell();
return mCtx;
}
/** Restore a previously saved context */ /** Restore a previously saved context */
void restoreContext(const ESM_Context &rc) 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);
}
/** Close the file, resets all information. After calling close() /** Close the file, resets all information. After calling close()
the structure may be reused to load a new file. the structure may be reused to load a new file.
*/ */
void close() 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;
}
/// Raw opening. Opens the file and sets everything up but doesn't /// Raw opening. Opens the file and sets everything up but doesn't
/// parse the header. /// parse the header.
void openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name) 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;
}
/// Load ES file from a new stream, parses the header. Closes the /// Load ES file from a new stream, parses the header. Closes the
/// currently open file first, if any. /// currently open file first, if any.
void open(Mangle::Stream::StreamPtr _esm, const std::string &name) void open(Mangle::Stream::StreamPtr _esm, const std::string &name);
{
openRaw(_esm, name);
if(getRecName() != "TES3") void open(const std::string &file);
fail("Not a valid Morrowind file");
getRecHeader(); void openRaw(const std::string &file);
// 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);
}
/************************************************************************* /*************************************************************************
* *
@ -306,8 +211,8 @@ public:
template <typename X> template <typename X>
void getHNOT(X &x, const char* name) void getHNOT(X &x, const char* name)
{ {
if(isNextSub(name)) if(isNextSub(name))
getHT(x); getHT(x);
} }
// Version with extra size checking, to make sure the compiler // Version with extra size checking, to make sure the compiler
@ -315,26 +220,21 @@ public:
template <typename X> template <typename X>
void getHNT(X &x, const char* name, int size) void getHNT(X &x, const char* name, int size)
{ {
assert(sizeof(X) == size); assert(sizeof(X) == size);
getSubNameIs(name); getSubNameIs(name);
getHT(x); getHT(x);
} }
int64_t getHNLong(const char *name) int64_t getHNLong(const char *name);
{
int64_t val;
getHNT(val, name);
return val;
}
// Get data of a given type/size, including subrecord header // Get data of a given type/size, including subrecord header
template <typename X> template <typename X>
void getHT(X &x) void getHT(X &x)
{ {
getSubHeader(); getSubHeader();
if(mCtx.leftSub != sizeof(X)) if (mCtx.leftSub != sizeof(X))
fail("getHT(): subrecord size mismatch"); fail("getHT(): subrecord size mismatch");
getT(x); getT(x);
} }
// Version with extra size checking, to make sure the compiler // Version with extra size checking, to make sure the compiler
@ -342,62 +242,24 @@ public:
template <typename X> template <typename X>
void getHT(X &x, int size) void getHT(X &x, int size)
{ {
assert(sizeof(X) == size); assert(sizeof(X) == size);
getHT(x); getHT(x);
} }
// Read a string by the given name if it is the next record. // Read a string by the given name if it is the next record.
std::string getHNOString(const char* name) std::string getHNOString(const char* name);
{
if(isNextSub(name))
return getHString();
return "";
}
// Read a string with the given sub-record name // Read a string with the given sub-record name
std::string getHNString(const char* name) std::string getHNString(const char* name);
{
getSubNameIs(name);
return getHString();
}
// Read a string, including the sub-record header (but not the name) // Read a string, including the sub-record header (but not the name)
std::string getHString() 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);
}
// Read the given number of bytes from a subrecord // Read the given number of bytes from a subrecord
void getHExact(void*p, int size) void getHExact(void*p, int size);
{
getSubHeader();
if(size !=static_cast<int> (mCtx.leftSub))
fail("getHExact() size mismatch");
getExact(p,size);
}
// Read the given number of bytes from a named subrecord // Read the given number of bytes from a named subrecord
void getHNExact(void*p, int size, const char* name) void getHNExact(void*p, int size, const char* name);
{
getSubNameIs(name);
getHExact(p,size);
}
/************************************************************************* /*************************************************************************
* *
@ -406,100 +268,37 @@ public:
*************************************************************************/ *************************************************************************/
// Get the next subrecord name and check if it matches the parameter // Get the next subrecord name and check if it matches the parameter
void getSubNameIs(const char* name) void getSubNameIs(const char* name);
{
getSubName();
if(mCtx.subName != name)
fail("Expected subrecord " + std::string(name) + " but got " + mCtx.subName.toString());
}
/** Checks if the next sub record name matches the parameter. If it /** Checks if the next sub record name matches the parameter. If it
does, it is read into 'subName' just as if getSubName() was does, it is read into 'subName' just as if getSubName() was
called. If not, the read name will still be available for future called. If not, the read name will still be available for future
calls to getSubName(), isNextSub() and getSubNameIs(). calls to getSubName(), isNextSub() and getSubNameIs().
*/ */
bool isNextSub(const char* name) 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;
}
// Read subrecord name. This gets called a LOT, so I've optimized it // Read subrecord name. This gets called a LOT, so I've optimized it
// slightly. // slightly.
void getSubName() 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;
}
// This is specially optimized for LoadINFO. // This is specially optimized for LoadINFO.
bool isEmptyOrGetName() bool isEmptyOrGetName();
{
if(mCtx.leftRec)
{
mEsm->read(mCtx.subName.name, 4);
mCtx.leftRec -= 4;
return false;
}
return true;
}
// Skip current sub record, including header (but not including // Skip current sub record, including header (but not including
// name.) // name.)
void skipHSub() void skipHSub();
{
getSubHeader();
skip(mCtx.leftSub);
}
// Skip sub record and check its size // Skip sub record and check its size
void skipHSubSize(int size) void skipHSubSize(int size);
{
skipHSub();
if(static_cast<int> (mCtx.leftSub) != size)
fail("skipHSubSize() mismatch");
}
/* Sub-record header. This updates leftRec beyond the current /* Sub-record header. This updates leftRec beyond the current
sub-record as well. leftSub contains size of current sub-record. sub-record as well. leftSub contains size of current sub-record.
*/ */
void getSubHeader() 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;
}
/** Get sub header and check the size /** Get sub header and check the size
*/ */
void getSubHeaderIs(int size) void getSubHeaderIs(int size);
{
getSubHeader();
if(size != static_cast<int> (mCtx.leftSub))
fail("getSubHeaderIs(): Sub header mismatch");
}
/************************************************************************* /*************************************************************************
* *
@ -508,62 +307,21 @@ public:
*************************************************************************/ *************************************************************************/
// Get the next record name // Get the next record name
NAME getRecName() 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;
}
// Skip the rest of this record. Assumes the name and header have // Skip the rest of this record. Assumes the name and header have
// already been read // already been read
void skipRecord() void skipRecord();
{
skip(mCtx.leftRec);
mCtx.leftRec = 0;
}
// Skip an entire record, including the header (but not the name) // Skip an entire record, including the header (but not the name)
void skipHRecord() void skipHRecord();
{
if(!mCtx.leftFile) return;
getRecHeader();
skipRecord();
}
/* Read record header. This updatesleftFile BEYOND the data that /* Read record header. This updatesleftFile BEYOND the data that
follows the header, ie beyond the entire record. You should use follows the header, ie beyond the entire record. You should use
leftRec to orient yourself inside the record itself. leftRec to orient yourself inside the record itself.
*/ */
void getRecHeader() { uint32_t u; getRecHeader(u); } void getRecHeader() { uint32_t u; getRecHeader(u); }
void getRecHeader(uint32_t &flags) 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;
}
bool hasMoreRecs() { return mCtx.leftFile > 0; } bool hasMoreRecs() { return mCtx.leftFile > 0; }
bool hasMoreSubs() { return mCtx.leftRec > 0; } bool hasMoreSubs() { return mCtx.leftRec > 0; }
@ -578,44 +336,19 @@ public:
template <typename X> template <typename X>
void getT(X &x) { getExact(&x, sizeof(X)); } void getT(X &x) { getExact(&x, sizeof(X)); }
void getExact(void*x, int size) void getExact(void*x, int size);
{
int t = mEsm->read(x, size);
if(t != size)
fail("Read error");
}
void getName(NAME &name) { getT(name); } void getName(NAME &name) { getT(name); }
void getUint(uint32_t &u) { getT(u); } void getUint(uint32_t &u) { getT(u); }
// Read the next 'size' bytes and return them as a string. Converts // Read the next 'size' bytes and return them as a string. Converts
// them from native encoding to UTF8 in the process. // them from native encoding to UTF8 in the process.
std::string getString(int size) 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);
}
void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); } void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); }
uint64_t getOffset() { return mEsm->tell(); } uint64_t getOffset() { return mEsm->tell(); }
/// Used for error handling /// Used for error handling
void fail(const std::string &msg) 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());
}
private: private:
Mangle::Stream::StreamPtr mEsm; Mangle::Stream::StreamPtr mEsm;

View file

@ -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");
}
}

View file

@ -3,18 +3,14 @@
#include "esm_reader.hpp" #include "esm_reader.hpp"
namespace ESM { namespace ESM
{
struct Activator struct Activator
{ {
std::string name, script, model; std::string name, script, model;
void load(ESMReader &esm) void load(ESMReader &esm);
{
model = esm.getHNString("MODL");
name = esm.getHNString("FNAM");
script = esm.getHNOString("SCRI");
}
}; };
} }
#endif #endif

View file

@ -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);
}
}

View file

@ -4,7 +4,8 @@
#include "esm_reader.hpp" #include "esm_reader.hpp"
#include "defs.hpp" #include "defs.hpp"
namespace ESM { namespace ESM
{
/* /*
* Alchemy item (potions) * Alchemy item (potions)
@ -12,26 +13,18 @@ namespace ESM {
struct Potion struct Potion
{ {
struct ALDTstruct struct ALDTstruct
{ {
float weight; float weight;
int value; int value;
int autoCalc; int autoCalc;
}; };
ALDTstruct data; ALDTstruct data;
std::string name, model, icon, script; std::string name, model, icon, script;
EffectList effects; EffectList effects;
void load(ESMReader &esm) 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);
}
}; };
} }
#endif #endif

View file

@ -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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp" #include "esm_reader.hpp"
namespace ESM { namespace ESM
{
/* /*
* Alchemist apparatus * Alchemist apparatus
@ -11,33 +12,23 @@ namespace ESM {
struct Apparatus struct Apparatus
{ {
enum AppaType enum AppaType
{ {
MortarPestle = 0, MortarPestle = 0, Albemic = 1, Calcinator = 2, Retort = 3
Albemic = 1,
Calcinator = 2,
Retort = 3
}; };
struct AADTstruct struct AADTstruct
{ {
int type; int type;
float quality; float quality;
float weight; float weight;
int value; int value;
}; };
AADTstruct data; AADTstruct data;
std::string model, icon, script, name; std::string model, icon, script, name;
void load(ESMReader &esm) 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");
}
}; };
} }
#endif #endif

View file

@ -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");
}
}

View file

@ -3,102 +3,85 @@
#include "esm_reader.hpp" #include "esm_reader.hpp"
namespace ESM { namespace ESM
{
enum PartReferenceType enum PartReferenceType
{ {
PRT_Head = 0, PRT_Head = 0,
PRT_Hair = 1, PRT_Hair = 1,
PRT_Neck = 2, PRT_Neck = 2,
PRT_Cuirass = 3, PRT_Cuirass = 3,
PRT_Groin = 4, PRT_Groin = 4,
PRT_Skirt = 5, PRT_Skirt = 5,
PRT_RHand = 6, PRT_RHand = 6,
PRT_LHand = 7, PRT_LHand = 7,
PRT_RWrist = 8, PRT_RWrist = 8,
PRT_LWrist = 9, PRT_LWrist = 9,
PRT_Shield = 10, PRT_Shield = 10,
PRT_RForearm = 11, PRT_RForearm = 11,
PRT_LForearm = 12, PRT_LForearm = 12,
PRT_RUpperarm = 13, PRT_RUpperarm = 13,
PRT_LUpperarm = 14, PRT_LUpperarm = 14,
PRT_RFoot = 15, PRT_RFoot = 15,
PRT_LFoot = 16, PRT_LFoot = 16,
PRT_RAnkle = 17, PRT_RAnkle = 17,
PRT_LAnkle = 18, PRT_LAnkle = 18,
PRT_RKnee = 19, PRT_RKnee = 19,
PRT_LKnee = 20, PRT_LKnee = 20,
PRT_RLeg = 21, PRT_RLeg = 21,
PRT_LLeg = 22, PRT_LLeg = 22,
PRT_RPauldron = 23, PRT_RPauldron = 23,
PRT_LPauldron = 24, PRT_LPauldron = 24,
PRT_Weapon = 25, PRT_Weapon = 25,
PRT_Tail = 26 PRT_Tail = 26
}; };
// Reference to body parts // Reference to body parts
struct PartReference struct PartReference
{ {
char part; char part;
std::string male, female; std::string male, female;
}; };
// A list of references to body parts // A list of references to body parts
struct PartReferenceList struct PartReferenceList
{ {
std::vector<PartReference> parts; std::vector<PartReference> parts;
void load(ESMReader &esm) 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");
}
}
}; };
struct Armor struct Armor
{ {
enum Type enum Type
{ {
Helmet = 0, Helmet = 0,
Cuirass = 1, Cuirass = 1,
LPauldron = 2, LPauldron = 2,
RPauldron = 3, RPauldron = 3,
Greaves = 4, Greaves = 4,
Boots = 5, Boots = 5,
LGauntlet = 6, LGauntlet = 6,
RGauntlet = 7, RGauntlet = 7,
Shield = 8, Shield = 8,
LBracer = 9, LBracer = 9,
RBracer = 10 RBracer = 10
}; };
struct AODTstruct struct AODTstruct
{ {
int type; int type;
float weight; float weight;
int value, health, enchant, armor; int value, health, enchant, armor;
}; };
AODTstruct data; AODTstruct data;
PartReferenceList parts; PartReferenceList parts;
std::string name, model, icon, script, enchant; std::string name, model, icon, script, enchant;
void load(ESMReader &esm) 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");
}
}; };
} }
#endif #endif

View file

@ -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);
}
}

View file

@ -3,59 +3,52 @@
#include "esm_reader.hpp" #include "esm_reader.hpp"
namespace ESM { namespace ESM
{
struct BodyPart struct BodyPart
{ {
enum MeshPart enum MeshPart
{ {
MP_Head = 0, MP_Head = 0,
MP_Hair = 1, MP_Hair = 1,
MP_Neck = 2, MP_Neck = 2,
MP_Chest = 3, MP_Chest = 3,
MP_Groin = 4, MP_Groin = 4,
MP_Hand = 5, MP_Hand = 5,
MP_Wrist = 6, MP_Wrist = 6,
MP_Forearm = 7, MP_Forearm = 7,
MP_Upperarm = 8, MP_Upperarm = 8,
MP_Foot = 9, MP_Foot = 9,
MP_Ankle = 10, MP_Ankle = 10,
MP_Knee = 11, MP_Knee = 11,
MP_Upperleg = 12, MP_Upperleg = 12,
MP_Clavicle = 13, MP_Clavicle = 13,
MP_Tail = 14 MP_Tail = 14
}; };
enum Flags enum Flags
{ {
BPF_Female = 1, BPF_Female = 1, BPF_Playable = 2
BPF_Playable = 2
}; };
enum MeshType enum MeshType
{ {
MT_Skin = 0, MT_Skin = 0, MT_Clothing = 1, MT_Armor = 2
MT_Clothing = 1,
MT_Armor = 2
}; };
struct BYDTstruct struct BYDTstruct
{ {
char part; char part;
char vampire; char vampire;
char flags; char flags;
char type; char type;
}; };
BYDTstruct data; BYDTstruct data;
std::string model, name; std::string model, name;
void load(ESMReader &esm) void load(ESMReader &esm);
{
model = esm.getHNString("MODL");
name = esm.getHNString("FNAM");
esm.getHNT(data, "BYDT", 4);
}
}; };
} }
#endif #endif

View file

@ -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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp" #include "esm_reader.hpp"
namespace ESM { namespace ESM
{
/* /*
* Books, magic scrolls, notes and so on * Books, magic scrolls, notes and so on
@ -11,25 +12,16 @@ namespace ESM {
struct Book struct Book
{ {
struct BKDTstruct struct BKDTstruct
{ {
float weight; float weight;
int value, isScroll, skillID, enchant; int value, isScroll, skillID, enchant;
}; };
BKDTstruct data; BKDTstruct data;
std::string name, model, icon, script, enchant, text; std::string name, model, icon, script, enchant, text;
void load(ESMReader &esm) 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");
}
}; };
} }
#endif #endif

View file

@ -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);
}
}

View file

@ -4,23 +4,17 @@
#include "defs.hpp" #include "defs.hpp"
#include "esm_reader.hpp" #include "esm_reader.hpp"
namespace ESM { namespace ESM
{
struct BirthSign struct BirthSign
{ {
std::string name, description, texture; std::string name, description, texture;
// List of powers and abilities that come with this birth sign. // List of powers and abilities that come with this birth sign.
SpellList powers; SpellList powers;
void load(ESMReader &esm) void load(ESMReader &esm);
{
name = esm.getHNString("FNAM");
texture = esm.getHNOString("TNAM");
description = esm.getHNOString("DESC");
powers.load(esm);
};
}; };
} }
#endif #endif

113
components/esm/loadcell.cpp Normal file
View file

@ -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;
}
}

View file

@ -117,51 +117,14 @@ struct Cell
int water; // Water level int water; // Water level
int mapColor; int mapColor;
void load(ESMReader &esm) 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();
}
// Restore the given reader to the stored position. Will try to open // 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 // 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 // somewhere other than the file system, you need to pre-open the
// ESMReader, and the filename must match the stored filename // ESMReader, and the filename must match the stored filename
// exactly. // exactly.
void restore(ESMReader &esm) const void restore(ESMReader &esm) const;
{ esm.restoreContext(context); }
/* Get the next reference in this cell, if any. Returns false when /* Get the next reference in this cell, if any. Returns false when
there are no more references in the cell. 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 All fields of the CellRef struct are overwritten. You can safely
reuse one memory location without blanking it between calls. reuse one memory location without blanking it between calls.
*/ */
static bool getNextRef(ESMReader &esm, CellRef &ref) 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;
}
}; };
} }
#endif #endif

View file

@ -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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp" #include "esm_reader.hpp"
namespace ESM { namespace ESM
{
/* /*
* Character class definitions * Character class definitions
@ -13,62 +14,51 @@ namespace ESM {
// class // class
struct Class struct Class
{ {
enum AutoCalc enum AutoCalc
{ {
Weapon = 0x00001, Weapon = 0x00001,
Armor = 0x00002, Armor = 0x00002,
Clothing = 0x00004, Clothing = 0x00004,
Books = 0x00008, Books = 0x00008,
Ingredient = 0x00010, Ingredient = 0x00010,
Lockpick = 0x00020, Lockpick = 0x00020,
Probe = 0x00040, Probe = 0x00040,
Lights = 0x00080, Lights = 0x00080,
Apparatus = 0x00100, Apparatus = 0x00100,
Repair = 0x00200, Repair = 0x00200,
Misc = 0x00400, Misc = 0x00400,
Spells = 0x00800, Spells = 0x00800,
MagicItems = 0x01000, MagicItems = 0x01000,
Potions = 0x02000, Potions = 0x02000,
Training = 0x04000, Training = 0x04000,
Spellmaking = 0x08000, Spellmaking = 0x08000,
Enchanting = 0x10000, Enchanting = 0x10000,
RepairItem = 0x20000 RepairItem = 0x20000
}; };
enum Specialization enum Specialization
{ {
Combat = 0, Combat = 0, Magic = 1, Stealth = 2
Magic = 1,
Stealth = 2
}; };
static const Specialization specializationIds[3]; static const Specialization specializationIds[3];
static const char *gmstSpecializationIds[3]; static const char *gmstSpecializationIds[3];
struct CLDTstruct 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)
{ {
name = esm.getHNString("FNAM"); int attribute[2]; // Attributes that get class bonus
esm.getHNT(data, "CLDT", 60); 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) // I have no idea how to autocalculate these items...
esm.fail("Unknown bool value"); int calc;
}; // 60 bytes
description = esm.getHNOString("DESC"); std::string name, description;
} CLDTstruct data;
void load(ESMReader &esm);
}; };
} }
#endif #endif

View file

@ -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");
}
}

View file

@ -4,7 +4,8 @@
#include "esm_reader.hpp" #include "esm_reader.hpp"
#include "loadarmo.hpp" #include "loadarmo.hpp"
namespace ESM { namespace ESM
{
/* /*
* Clothing * Clothing
@ -12,46 +13,34 @@ namespace ESM {
struct Clothing struct Clothing
{ {
enum Type enum Type
{ {
Pants = 0, Pants = 0,
Shoes = 1, Shoes = 1,
Shirt = 2, Shirt = 2,
Belt = 3, Belt = 3,
Robe = 4, Robe = 4,
RGlove = 5, RGlove = 5,
LGlove = 6, LGlove = 6,
Skirt = 7, Skirt = 7,
Ring = 8, Ring = 8,
Amulet = 9 Amulet = 9
}; };
struct CTDTstruct struct CTDTstruct
{ {
int type; int type;
float weight; float weight;
short value; short value;
short enchant; short enchant;
}; };
CTDTstruct data; CTDTstruct data;
PartReferenceList parts; PartReferenceList parts;
std::string name, model, icon, enchant, script; std::string name, model, icon, enchant, script;
void load(ESMReader &esm) 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");
}
}; };
} }
#endif #endif

View file

@ -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<int>(X);
esm.getT<int>(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);
}
}

View file

@ -3,51 +3,25 @@
#include "esm_reader.hpp" #include "esm_reader.hpp"
namespace ESM { namespace ESM
{
/* /*
* Landscape data. * Landscape data.
*/ */
struct Land struct Land
{ {
int flags; // Only first four bits seem to be used, don't know what int flags; // Only first four bits seem to be used, don't know what
// they mean. // they mean.
int X, Y; // Map coordinates. int X, Y; // Map coordinates.
// File context. This allows the ESM reader to be 'reset' to this // File context. This allows the ESM reader to be 'reset' to this
// location later when we are ready to load the full data set. // location later when we are ready to load the full data set.
ESM_Context context; ESM_Context context;
bool hasData; bool hasData;
void load(ESMReader &esm) void load(ESMReader &esm);
{
// Get the grid location
esm.getSubNameIs("INTV");
esm.getSubHeaderIs(8);
esm.getT<int>(X);
esm.getT<int>(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);
}
}; };
} }
#endif #endif