Refine DELE handling in ESM records. Add position-independent DELE search

openmw-38
Stanislav Bas 10 years ago
parent 3ba73f5fd9
commit ad353e6dd0

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "util.hpp"
ESM::CellRef::CellRef() ESM::CellRef::CellRef()
: mScale(1.0f), : mScale(1.0f),
@ -38,7 +37,6 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const
void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) void ESM::CellRef::load (ESMReader& esm, bool wideRefNum)
{ {
mIsDeleted = false;
loadId(esm, wideRefNum); loadId(esm, wideRefNum);
loadData(esm); loadData(esm);
} }
@ -55,62 +53,90 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum)
mRefNum.load (esm, wideRefNum); mRefNum.load (esm, wideRefNum);
mRefID = esm.getHNString ("NAME"); mRefID = esm.getHNString ("NAME");
mIsDeleted = false;
} }
void ESM::CellRef::loadData(ESMReader &esm) void ESM::CellRef::loadData(ESMReader &esm)
{ {
// Again, UNAM sometimes appears after NAME and sometimes later. mScale = 1.0f;
// Or perhaps this UNAM means something different?
mReferenceBlocked = -1;
esm.getHNOT (mReferenceBlocked, "UNAM");
mScale = 1.0;
esm.getHNOT (mScale, "XSCL");
mOwner = esm.getHNOString ("ANAM");
mGlobalVariable = esm.getHNOString ("BNAM");
mSoul = esm.getHNOString ("XSOL");
mFaction = esm.getHNOString ("CNAM");
mFactionRank = -2; mFactionRank = -2;
esm.getHNOT (mFactionRank, "INDX");
mGoldValue = 1;
mChargeInt = -1; mChargeInt = -1;
mEnchantmentCharge = -1; mEnchantmentCharge = -1;
mGoldValue = 1;
mLockLevel = 0;
mReferenceBlocked = -1;
mTeleport = false;
mIsDeleted = false;
esm.getHNOT (mEnchantmentCharge, "XCHG"); bool isLoaded = false;
while (!isLoaded && esm.hasMoreSubs())
esm.getHNOT (mChargeInt, "INTV");
esm.getHNOT (mGoldValue, "NAM9");
// Present for doors that teleport you to another cell.
if (esm.isNextSub ("DODT"))
{ {
mTeleport = true; esm.getSubName();
esm.getHT (mDoorDest); uint32_t name = esm.retSubName().val;
mDestCell = esm.getHNOString ("DNAM"); switch (name)
{
case ESM::FourCC<'U','N','A','M'>::value:
esm.getHT(mReferenceBlocked);
break;
case ESM::FourCC<'X','S','C','L'>::value:
esm.getHT(mScale);
break;
case ESM::FourCC<'A','N','A','M'>::value:
mOwner = esm.getHString();
break;
case ESM::FourCC<'B','N','A','M'>::value:
mGlobalVariable = esm.getHString();
break;
case ESM::FourCC<'X','S','O','L'>::value:
mSoul = esm.getHString();
break;
case ESM::FourCC<'C','N','A','M'>::value:
mFaction = esm.getHString();
break;
case ESM::FourCC<'I','N','D','X'>::value:
esm.getHT(mFactionRank);
break;
case ESM::FourCC<'X','C','H','G'>::value:
esm.getHT(mEnchantmentCharge);
break;
case ESM::FourCC<'I','N','T','V'>::value:
esm.getHT(mChargeInt);
break;
case ESM::FourCC<'N','A','M','9'>::value:
esm.getHT(mGoldValue);
break;
case ESM::FourCC<'D','O','D','T'>::value:
esm.getHT(mDoorDest);
mTeleport = true;
break;
case ESM::FourCC<'D','N','A','M'>::value:
mDestCell = esm.getHString();
break;
case ESM::FourCC<'F','L','T','V'>::value:
esm.getHT(mLockLevel);
break;
case ESM::FourCC<'K','N','A','M'>::value:
mKey = esm.getHString();
break;
case ESM::FourCC<'T','N','A','M'>::value:
mTrap = esm.getHString();
break;
case ESM::FourCC<'D','A','T','A'>::value:
esm.getHT(mPos, 24);
break;
case ESM::FourCC<'N','A','M','0'>::value:
esm.skipHSub();
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
default:
esm.cacheSubName();
isLoaded = true;
break;
}
} }
else
mTeleport = false;
mLockLevel = 0; //Set to 0 to indicate no lock
esm.getHNOT (mLockLevel, "FLTV");
mKey = esm.getHNOString ("KNAM");
mTrap = esm.getHNOString ("TNAM");
esm.getHNOT (mReferenceBlocked, "UNAM");
if (esm.isNextSub("FLTV")) // no longer used
esm.skipHSub();
esm.getHNOT(mPos, "DATA", 24);
if (esm.isNextSub("NAM0"))
esm.skipHSub();
mIsDeleted = readDeleSubRecord (esm);
} }
void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const
@ -149,7 +175,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons
} }
if (!inInventory && mLockLevel != 0) { if (!inInventory && mLockLevel != 0) {
esm.writeHNT("FLTV", mLockLevel); esm.writeHNT("FLTV", mLockLevel);
} }
if (!inInventory) if (!inInventory)
@ -166,7 +192,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
} }
} }

@ -187,6 +187,11 @@ bool ESMReader::peekNextSub(const char *name)
return mCtx.subName == name; return mCtx.subName == name;
} }
void ESMReader::cacheSubName()
{
mCtx.subCached = true;
}
// 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 ESMReader::getSubName() void ESMReader::getSubName()

@ -185,6 +185,9 @@ public:
bool peekNextSub(const char* name); bool peekNextSub(const char* name);
// Store the current subrecord name for the next call of getSubName()
void cacheSubName();
// 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();

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,18 +14,23 @@ namespace ESM
void Activator::load(ESMReader &esm) void Activator::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
esm.getSubName(); esm.getSubName();
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -38,15 +42,20 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasName)
esm.fail("Missing NAME subrecord");
} }
void Activator::save(ESMWriter &esm) const void Activator::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -16,13 +15,9 @@ namespace ESM
void Potion::load(ESMReader &esm) void Potion::load(ESMReader &esm)
{ {
mEffects.mList.clear(); mEffects.mList.clear();
mIsDeleted = false;
mId = esm.getHNString("NAME"); bool hasName = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -30,6 +25,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -51,17 +54,22 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
esm.fail("Missing ALDT"); if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing ALDT subrecord");
} }
void Potion::save(ESMWriter &esm) const void Potion::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,12 +14,9 @@ namespace ESM
void Apparatus::load(ESMReader &esm) void Apparatus::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -28,6 +24,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -46,18 +50,23 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
esm.fail("Missing AADT"); if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing AADT subrecord");
} }
void Apparatus::save(ESMWriter &esm) const void Apparatus::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -46,13 +45,9 @@ namespace ESM
void Armor::load(ESMReader &esm) void Armor::load(ESMReader &esm)
{ {
mParts.mParts.clear(); mParts.mParts.clear();
mIsDeleted = false;
mId = esm.getHNString("NAME"); bool hasName = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -60,6 +55,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -84,18 +87,23 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing CTDT subrecord"); esm.fail("Missing CTDT subrecord");
} }
void Armor::save(ESMWriter &esm) const void Armor::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,12 +14,9 @@ namespace ESM
void BodyPart::load(ESMReader &esm) void BodyPart::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -28,6 +24,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -40,19 +44,23 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData) if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing BYDT subrecord"); esm.fail("Missing BYDT subrecord");
} }
void BodyPart::save(ESMWriter &esm) const void BodyPart::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,12 +14,9 @@ namespace ESM
void Book::load(ESMReader &esm) void Book::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -28,6 +24,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -52,17 +56,22 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing BKDT subrecord"); esm.fail("Missing BKDT subrecord");
} }
void Book::save(ESMWriter &esm) const void Book::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -16,16 +16,23 @@ namespace ESM
void BirthSign::load(ESMReader &esm) void BirthSign::load(ESMReader &esm)
{ {
mPowers.mList.clear(); mPowers.mList.clear();
mIsDeleted = false;
mIsDeleted = readDeleSubRecord(esm); bool hasName = false;
mId = esm.getHNString("NAME");
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
esm.getSubName(); esm.getSubName();
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'F','N','A','M'>::value: case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString(); mName = esm.getHString();
break; break;
@ -40,16 +47,21 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasName)
esm.fail("Missing NAME subrecord");
} }
void BirthSign::save(ESMWriter &esm) const void BirthSign::save(ESMWriter &esm) const
{ {
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
} }
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("FNAM", mName);
esm.writeHNOCString("TNAM", mTexture); esm.writeHNOCString("TNAM", mTexture);

@ -5,7 +5,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -45,12 +44,9 @@ namespace ESM
void Class::load(ESMReader &esm) void Class::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -58,6 +54,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'F','N','A','M'>::value: case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString(); mName = esm.getHString();
break; break;
@ -72,17 +76,22 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing CLDT subrecord"); esm.fail("Missing CLDT subrecord");
} }
void Class::save(ESMWriter &esm) const void Class::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -16,13 +15,9 @@ namespace ESM
void Clothing::load(ESMReader &esm) void Clothing::load(ESMReader &esm)
{ {
mParts.mParts.clear(); mParts.mParts.clear();
mIsDeleted = false;
mId = esm.getHNString("NAME"); bool hasName = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -30,6 +25,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -54,18 +57,23 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing CTDT subrecord"); esm.fail("Missing CTDT subrecord");
} }
void Clothing::save(ESMWriter &esm) const void Clothing::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -26,19 +25,17 @@ namespace ESM
unsigned int Container::sRecordId = REC_CONT; unsigned int Container::sRecordId = REC_CONT;
Container::Container() Container::Container()
: mIsDeleted(false) : mWeight(0),
mFlags(0x8),
mIsDeleted(false)
{} {}
void Container::load(ESMReader &esm) void Container::load(ESMReader &esm)
{ {
mInventory.mList.clear(); mInventory.mList.clear();
mIsDeleted = false;
mId = esm.getHNString("NAME"); bool hasName = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasWeight = false; bool hasWeight = false;
bool hasFlags = false; bool hasFlags = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
@ -47,6 +44,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -73,20 +78,25 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasWeight)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasWeight && !mIsDeleted)
esm.fail("Missing CNDT subrecord"); esm.fail("Missing CNDT subrecord");
if (!hasFlags) if (!hasFlags && !mIsDeleted)
esm.fail("Missing FLAG subrecord"); esm.fail("Missing FLAG subrecord");
} }
void Container::save(ESMWriter &esm) const void Container::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,14 +3,15 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM { namespace ESM {
unsigned int Creature::sRecordId = REC_CREA; unsigned int Creature::sRecordId = REC_CREA;
Creature::Creature() Creature::Creature()
: mIsDeleted(false) : mFlags(0),
mScale(0.0f),
mIsDeleted(false)
{} {}
void Creature::load(ESMReader &esm) void Creature::load(ESMReader &esm)
@ -22,14 +23,11 @@ namespace ESM {
mSpells.mList.clear(); mSpells.mList.clear();
mTransport.mList.clear(); mTransport.mList.clear();
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mScale = 1.f; mScale = 1.f;
mHasAI = false; mHasAI = false;
mIsDeleted = false;
bool hasName = false;
bool hasNpdt = false; bool hasNpdt = false;
bool hasFlags = false; bool hasFlags = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
@ -38,6 +36,14 @@ namespace ESM {
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -85,20 +91,25 @@ namespace ESM {
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasNpdt)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasNpdt && !mIsDeleted)
esm.fail("Missing NPDT subrecord"); esm.fail("Missing NPDT subrecord");
if (!hasFlags) if (!hasFlags && !mIsDeleted)
esm.fail("Missing FLAG subrecord"); esm.fail("Missing FLAG subrecord");
} }
void Creature::save(ESMWriter &esm) const void Creature::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -7,7 +7,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -31,20 +30,36 @@ namespace ESM
void Dialogue::loadData(ESMReader &esm) void Dialogue::loadData(ESMReader &esm)
{ {
esm.getSubNameIs("DATA"); while (esm.hasMoreSubs())
esm.getSubHeader();
int si = esm.getSubSize();
if (si == 1)
esm.getT(mType);
else if (si == 4) // The dialogue is deleted
{ {
int32_t empty; esm.getSubName();
esm.getT(empty); // Skip an empty DATA uint32_t name = esm.retSubName().val;
mIsDeleted = readDeleSubRecord(esm); switch (name)
mType = Unknown; {
case ESM::FourCC<'D','A','T','A'>::value:
{
esm.getSubHeader();
int size = esm.getSubSize();
if (size == 1)
{
esm.getT(mType);
}
else
{
esm.skip(size);
}
break;
}
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mType = Unknown;
mIsDeleted = true;
break;
default:
esm.fail("Unknown subrecord");
break;
}
} }
else
esm.fail("Unknown sub record size");
} }
void Dialogue::save(ESMWriter &esm) const void Dialogue::save(ESMWriter &esm) const
@ -52,8 +67,7 @@ namespace ESM
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
esm.writeHNT("DATA", static_cast<int32_t>(0)); esm.writeHNCString("DELE", "");
writeDeleSubRecord(esm);
} }
else else
{ {
@ -138,7 +152,7 @@ namespace ESM
{ {
for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); )
{ {
if (it->mIsDeleted || it->mQuestStatus == DialInfo::QS_Deleted) if (it->mIsDeleted)
it = mInfo.erase(it); it = mInfo.erase(it);
else else
++it; ++it;

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,18 +14,23 @@ namespace ESM
void Door::load(ESMReader &esm) void Door::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
esm.getSubName(); esm.getSubName();
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -44,16 +48,21 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasName)
esm.fail("Missing NAME subrecord");
} }
void Door::save(ESMWriter &esm) const void Door::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -16,13 +15,9 @@ namespace ESM
void Enchantment::load(ESMReader &esm) void Enchantment::load(ESMReader &esm)
{ {
mEffects.mList.clear(); mEffects.mList.clear();
mIsDeleted = false;
mId = esm.getHNString("NAME"); bool hasName = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -30,6 +25,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'E','N','D','T'>::value: case ESM::FourCC<'E','N','D','T'>::value:
esm.getHT(mData, 16); esm.getHT(mData, 16);
hasData = true; hasData = true;
@ -42,16 +45,20 @@ namespace ESM
break; break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing ENDT subrecord"); esm.fail("Missing ENDT subrecord");
} }
void Enchantment::save(ESMWriter &esm) const void Enchantment::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -5,7 +5,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -33,17 +32,13 @@ namespace ESM
void Faction::load(ESMReader &esm) void Faction::load(ESMReader &esm)
{ {
mIsDeleted = false;
mReactions.clear(); mReactions.clear();
for (int i=0;i<10;++i) for (int i=0;i<10;++i)
mRanks[i].clear(); mRanks[i].clear();
mId = esm.getHNString("NAME"); int rankCounter = 0;
if (mIsDeleted = readDeleSubRecord(esm)) bool hasName = false;
{
return;
}
int rankCounter=0;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -51,6 +46,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'F','N','A','M'>::value: case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString(); mName = esm.getHString();
break; break;
@ -75,18 +78,23 @@ namespace ESM
} }
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing FADT subrecord"); esm.fail("Missing FADT subrecord");
} }
void Faction::save(ESMWriter &esm) const void Faction::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,30 +14,38 @@ namespace ESM
void Global::load (ESMReader &esm) void Global::load (ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm)) mId = esm.getHNString ("NAME");
if (esm.isNextSub ("DELE"))
{ {
return; esm.skipHSub();
mIsDeleted = true;
}
else
{
mValue.read (esm, ESM::Variant::Format_Global);
} }
mValue.read (esm, ESM::Variant::Format_Global);
} }
void Global::save (ESMWriter &esm) const void Global::save (ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString ("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString ("DELE", "");
return; }
else
{
mValue.write (esm, ESM::Variant::Format_Global);
} }
mValue.write (esm, ESM::Variant::Format_Global);
} }
void Global::blank() void Global::blank()
{ {
mValue.setType (ESM::VT_None); mValue.setType (ESM::VT_None);
mIsDeleted = false;
} }
bool operator== (const Global& left, const Global& right) bool operator== (const Global& left, const Global& right)

@ -3,14 +3,15 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
unsigned int DialInfo::sRecordId = REC_INFO; unsigned int DialInfo::sRecordId = REC_INFO;
DialInfo::DialInfo() DialInfo::DialInfo()
: mIsDeleted(false) : mFactionLess(false),
mQuestStatus(QS_None),
mIsDeleted(false)
{} {}
void DialInfo::load(ESMReader &esm) void DialInfo::load(ESMReader &esm)
@ -29,6 +30,7 @@ namespace ESM
{ {
mQuestStatus = QS_None; mQuestStatus = QS_None;
mFactionLess = false; mFactionLess = false;
mIsDeleted = false;
mPrev = esm.getHNString("PNAM"); mPrev = esm.getHNString("PNAM");
mNext = esm.getHNString("NNAM"); mNext = esm.getHNString("NNAM");
@ -36,118 +38,77 @@ namespace ESM
// Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings // Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings
mSelects.clear(); mSelects.clear();
// If the info is deleted, NAME and DELE sub-records are followed after NNAM while (esm.hasMoreSubs())
if (esm.isNextSub("NAME"))
{
mResponse = esm.getHString();
mIsDeleted = readDeleSubRecord(esm);
return;
}
esm.getSubNameIs("DATA");
esm.getHT(mData, 12);
if (!esm.hasMoreSubs())
return;
// What follows is somewhat spaghetti-ish, but it's worth if for
// an extra speedup. INFO is by far the most common record type.
// subName is a reference to the original, so it changes whenever
// a new sub name is read. esm.isEmptyOrGetName() will get the
// next name for us, or return true if there are no more records.
esm.getSubName();
const NAME &subName = esm.retSubName();
if (subName.val == REC_ONAM)
{
mActor = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_RNAM)
{
mRace = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_CNAM)
{
mClass = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_FNAM)
{
mFaction = esm.getHString();
if (mFaction == "FFFF")
mFactionLess = true;
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_ANAM)
{
mCell = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_DNAM)
{
mPcFaction = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_SNAM)
{
mSound = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_NAME)
{
mResponse = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
while (subName.val == REC_SCVR)
{ {
SelectStruct ss; esm.getSubName();
uint32_t name = esm.retSubName().val;
ss.mSelectRule = esm.getHString(); switch (name)
{
ss.mValue.read (esm, Variant::Format_Info); case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mSelects.push_back(ss); mIsDeleted = true;
break;
if (esm.isEmptyOrGetName()) case ESM::FourCC<'D','A','T','A'>::value:
return; esm.getHT(mData, 12);
break;
case ESM::FourCC<'O','N','A','M'>::value:
mActor = esm.getHString();
break;
case ESM::FourCC<'R','N','A','M'>::value:
mRace = esm.getHString();
break;
case ESM::FourCC<'C','N','A','M'>::value:
mClass = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
{
mFaction = esm.getHString();
if (mFaction == "FFFF")
{
mFactionLess = true;
}
break;
}
case ESM::FourCC<'A','N','A','M'>::value:
mCell = esm.getHString();
break;
case ESM::FourCC<'D','N','A','M'>::value:
mPcFaction = esm.getHString();
break;
case ESM::FourCC<'S','N','A','M'>::value:
mSound = esm.getHString();
break;
case ESM::FourCC<'N','A','M','E'>::value:
mResponse = esm.getHString();
break;
case ESM::FourCC<'S','C','V','R'>::value:
{
SelectStruct ss;
ss.mSelectRule = esm.getHString();
ss.mValue.read(esm, Variant::Format_Info);
mSelects.push_back(ss);
break;
}
case ESM::FourCC<'B','N','A','M'>::value:
mResultScript = esm.getHString();
break;
case ESM::FourCC<'Q','S','T','N'>::value:
mQuestStatus = QS_Name;
esm.skipRecord();
break;
case ESM::FourCC<'Q','S','T','F'>::value:
mQuestStatus = QS_Finished;
esm.skipRecord();
break;
case ESM::FourCC<'Q','S','T','R'>::value:
mQuestStatus = QS_Restart;
esm.skipRecord();
break;
default:
esm.fail("Unknown subrecord");
break;
}
} }
if (subName.val == REC_BNAM)
{
mResultScript = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_QSTN)
mQuestStatus = QS_Name;
else if (subName.val == REC_QSTF)
mQuestStatus = QS_Finished;
else if (subName.val == REC_QSTR)
mQuestStatus = QS_Restart;
else if (subName.val == REC_DELE)
mQuestStatus = QS_Deleted;
else
esm.fail(
"Don't know what to do with " + subName.toString()
+ " in INFO " + mId);
if (mQuestStatus != QS_None)
// Skip rest of record
esm.skipRecord();
} }
void DialInfo::save(ESMWriter &esm) const void DialInfo::save(ESMWriter &esm) const
@ -158,8 +119,7 @@ namespace ESM
if (mIsDeleted) if (mIsDeleted)
{ {
esm.writeHNCString("NAME", mResponse); esm.writeHNCString("DELE", "");
writeDeleSubRecord(esm);
return; return;
} }
@ -186,7 +146,6 @@ namespace ESM
case QS_Name: esm.writeHNT("QSTN",'\1'); break; case QS_Name: esm.writeHNT("QSTN",'\1'); break;
case QS_Finished: esm.writeHNT("QSTF", '\1'); break; case QS_Finished: esm.writeHNT("QSTF", '\1'); break;
case QS_Restart: esm.writeHNT("QSTR", '\1'); break; case QS_Restart: esm.writeHNT("QSTR", '\1'); break;
case QS_Deleted: esm.writeHNT("DELE", '\1'); break;
default: break; default: break;
} }
} }

@ -59,8 +59,7 @@ struct DialInfo
QS_None = 0, QS_None = 0,
QS_Name = 1, QS_Name = 1,
QS_Finished = 2, QS_Finished = 2,
QS_Restart = 3, QS_Restart = 3
QS_Deleted
}; };
// Rules for when to include this item in the final list of options // Rules for when to include this item in the final list of options

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,12 +14,9 @@ namespace ESM
void Ingredient::load(ESMReader &esm) void Ingredient::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -28,6 +24,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -46,10 +50,13 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData) if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing IRDT subrecord"); esm.fail("Missing IRDT subrecord");
// horrible hack to fix broken data in records // horrible hack to fix broken data in records
@ -79,9 +86,10 @@ namespace ESM
void Ingredient::save(ESMWriter &esm) const void Ingredient::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -13,49 +12,67 @@ namespace ESM
void LevelledListBase::load(ESMReader &esm) void LevelledListBase::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
esm.getHNT(mFlags, "DATA");
esm.getHNT(mChanceNone, "NNAM");
if (esm.isNextSub("INDX")) bool hasName = false;
{ while (esm.hasMoreSubs())
int len;
esm.getHT(len);
mList.resize(len);
}
else
{ {
// Original engine ignores rest of the record, even if there are items following esm.getSubName();
mList.clear(); uint32_t name = esm.retSubName().val;
esm.skipRecord(); switch (name)
return; {
} case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'D','A','T','A'>::value:
esm.getHT(mFlags);
break;
case ESM::FourCC<'N','N','A','M'>::value:
esm.getHT(mChanceNone);
break;
case ESM::FourCC<'I','N','D','X'>::value:
{
int length = 0;
esm.getHT(length);
mList.resize(length);
// If this levelled list was already loaded by a previous content file, // If this levelled list was already loaded by a previous content file,
// we overwrite the list. Merging lists should probably be left to external tools, // we overwrite the list. Merging lists should probably be left to external tools,
// with the limited amount of information there is in the records, all merging methods // with the limited amount of information there is in the records, all merging methods
// will be flawed in some way. For a proper fix the ESM format would have to be changed // will be flawed in some way. For a proper fix the ESM format would have to be changed
// to actually track list changes instead of including the whole list for every file // to actually track list changes instead of including the whole list for every file
// that does something with that list. // that does something with that list.
for (size_t i = 0; i < mList.size(); i++)
for (size_t i = 0; i < mList.size(); i++) {
{ LevelItem &li = mList[i];
LevelItem &li = mList[i]; li.mId = esm.getHNString(mRecName);
li.mId = esm.getHNString(mRecName); esm.getHNT(li.mLevel, "INTV");
esm.getHNT(li.mLevel, "INTV"); }
break;
}
default:
mList.clear();
esm.skipRecord();
break;
}
} }
if (!hasName)
esm.fail("Missing NAME subrecord");
} }
void LevelledListBase::save(ESMWriter &esm) const void LevelledListBase::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,12 +14,9 @@ namespace ESM
void Light::load(ESMReader &esm) void Light::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -28,6 +24,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -49,17 +53,22 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing LHDT subrecord"); esm.fail("Missing LHDT subrecord");
} }
void Light::save(ESMWriter &esm) const void Light::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,19 +14,23 @@ namespace ESM
void Lockpick::load(ESMReader &esm) void Lockpick::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasData = true; bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
esm.getSubName(); esm.getSubName();
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -46,18 +49,23 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing LKDT subrecord"); esm.fail("Missing LKDT subrecord");
} }
void Lockpick::save(ESMWriter &esm) const void Lockpick::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,17 +14,49 @@ namespace ESM
void LandTexture::load(ESMReader &esm) void LandTexture::load(ESMReader &esm)
{ {
mIsDeleted = readDeleSubRecord(esm); mIsDeleted = false;
mId = esm.getHNString("NAME");
esm.getHNT(mIndex, "INTV"); bool hasName = false;
mTexture = esm.getHNString("DATA"); bool hasIndex = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = false;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'I','N','T','V'>::value:
esm.getHT(mIndex);
hasIndex = true;
break;
case ESM::FourCC<'D','A','T','A'>::value:
mTexture = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasIndex)
esm.fail("Missing INTV subrecord");
} }
void LandTexture::save(ESMWriter &esm) const void LandTexture::save(ESMWriter &esm) const
{ {
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
} }
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
esm.writeHNT("INTV", mIndex); esm.writeHNT("INTV", mIndex);
esm.writeHNCString("DATA", mTexture); esm.writeHNCString("DATA", mTexture);

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,12 +14,9 @@ namespace ESM
void Miscellaneous::load(ESMReader &esm) void Miscellaneous::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -28,6 +24,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -44,18 +48,25 @@ namespace ESM
case ESM::FourCC<'I','T','E','X'>::value: case ESM::FourCC<'I','T','E','X'>::value:
mIcon = esm.getHString(); mIcon = esm.getHString();
break; break;
default:
esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing MCDT subrecord"); esm.fail("Missing MCDT subrecord");
} }
void Miscellaneous::save(ESMWriter &esm) const void Miscellaneous::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,40 +3,45 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
unsigned int NPC::sRecordId = REC_NPC_; unsigned int NPC::sRecordId = REC_NPC_;
NPC::NPC() NPC::NPC()
: mIsDeleted(false) : mFlags(0),
mHasAI(false),
mIsDeleted(false)
{} {}
void NPC::load(ESMReader &esm) void NPC::load(ESMReader &esm)
{ {
mIsDeleted = false;
mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mPersistent = (esm.getRecordFlags() & 0x0400) != 0;
mSpells.mList.clear(); mSpells.mList.clear();
mInventory.mList.clear(); mInventory.mList.clear();
mTransport.mList.clear(); mTransport.mList.clear();
mAiPackage.mList.clear(); mAiPackage.mList.clear();
mHasAI = false;
mId = esm.getHNString("NAME"); bool hasName = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasNpdt = false; bool hasNpdt = false;
bool hasFlags = false; bool hasFlags = false;
mHasAI = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
esm.getSubName(); esm.getSubName();
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -105,19 +110,24 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasNpdt)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasNpdt && !mIsDeleted)
esm.fail("Missing NPDT subrecord"); esm.fail("Missing NPDT subrecord");
if (!hasFlags) if (!hasFlags && !mIsDeleted)
esm.fail("Missing FLAG subrecord"); esm.fail("Missing FLAG subrecord");
} }
void NPC::save(ESMWriter &esm) const void NPC::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,19 +14,24 @@ namespace ESM
void Probe::load(ESMReader &esm) void Probe::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasData = true; bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
esm.getSubName(); esm.getSubName();
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -46,18 +50,23 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing PBDT subrecord"); esm.fail("Missing PBDT subrecord");
} }
void Probe::save(ESMWriter &esm) const void Probe::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,64 +3,95 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
unsigned int Region::sRecordId = REC_REGN; unsigned int Region::sRecordId = REC_REGN;
Region::Region() Region::Region()
: mIsDeleted(false) : mMapColor(0),
mIsDeleted(false)
{} {}
void Region::load(ESMReader &esm) void Region::load(ESMReader &esm)
{ {
mIsDeleted = readDeleSubRecord(esm); mIsDeleted = false;
mId = esm.getHNString("NAME");
mName = esm.getHNOString("FNAM");
esm.getSubNameIs("WEAT"); bool hasName = false;
esm.getSubHeader(); while (esm.hasMoreSubs())
if (esm.getVer() == VER_12)
{
mData.mA = 0;
mData.mB = 0;
esm.getExact(&mData, sizeof(mData) - 2);
}
else if (esm.getVer() == VER_13)
{ {
// May include the additional two bytes (but not necessarily) esm.getSubName();
if (esm.getSubSize() == sizeof(mData)) uint32_t name = esm.retSubName().val;
esm.getExact(&mData, sizeof(mData)); switch (name)
else
{ {
mData.mA = 0; case ESM::FourCC<'N','A','M','E'>::value:
mData.mB = 0; mId = esm.getHString();
esm.getExact(&mData, sizeof(mData)-2); hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'W','E','A','T'>::value:
{
esm.getSubHeader();
if (esm.getVer() == VER_12)
{
mData.mA = 0;
mData.mB = 0;
esm.getExact(&mData, sizeof(mData) - 2);
}
else if (esm.getVer() == VER_13)
{
// May include the additional two bytes (but not necessarily)
if (esm.getSubSize() == sizeof(mData))
{
esm.getExact(&mData, sizeof(mData));
}
else
{
mData.mA = 0;
mData.mB = 0;
esm.getExact(&mData, sizeof(mData)-2);
}
}
else
{
esm.fail("Don't know what to do in this version");
}
break;
}
case ESM::FourCC<'B','N','A','M'>::value:
mSleepList = esm.getHString();
break;
case ESM::FourCC<'C','N','A','M'>::value:
esm.getHT(mMapColor);
break;
case ESM::FourCC<'S','N','A','M'>::value:
SoundRef sr;
esm.getHT(sr, 33);
mSoundList.push_back(sr);
break;
default:
esm.fail("Unknown subrecord");
break;
} }
} }
else
esm.fail("Don't know what to do in this version");
mSleepList = esm.getHNOString("BNAM");
esm.getHNT(mMapColor, "CNAM"); if (!hasName)
esm.fail("Missing NAME subrecord");
mSoundList.clear();
while (esm.hasMoreSubs())
{
SoundRef sr;
esm.getHNT(sr, "SNAM", 33);
mSoundList.push_back(sr);
}
} }
void Region::save(ESMWriter &esm) const void Region::save(ESMWriter &esm) const
{ {
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
} }
esm.writeHNString("NAME", mId); esm.writeHNString("NAME", mId);
esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("FNAM", mName);

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,19 +14,24 @@ namespace ESM
void Repair::load(ESMReader &esm) void Repair::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasData = true; bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
esm.getSubName(); esm.getSubName();
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -46,18 +50,23 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing RIDT subrecord"); esm.fail("Missing RIDT subrecord");
} }
void Repair::save(ESMWriter &esm) const void Repair::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
#include <iostream> #include <iostream>
@ -64,23 +63,27 @@ namespace ESM
void Script::load(ESMReader &esm) void Script::load(ESMReader &esm)
{ {
SCHD data;
esm.getHNT(data, "SCHD", 52);
mData = data.mData;
mId = data.mName.toString();
// In scripts DELE sub-record appears after a header.
// The script data is following after DELE in this case.
mIsDeleted = readDeleSubRecord(esm);
mVarNames.clear(); mVarNames.clear();
mIsDeleted = false;
bool hasHeader = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
esm.getSubName(); esm.getSubName();
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'S','C','H','D'>::value:
SCHD data;
esm.getHT(data, 52);
mData = data.mData;
mId = data.mName.toString();
hasHeader = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'S','C','V','R'>::value: case ESM::FourCC<'S','C','V','R'>::value:
// list of local variables // list of local variables
loadSCVR(esm); loadSCVR(esm);
@ -95,8 +98,12 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasHeader)
esm.fail("Missing SCHD subrecord");
} }
void Script::save(ESMWriter &esm) const void Script::save(ESMWriter &esm) const
@ -116,7 +123,7 @@ namespace ESM
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
} }
if (!mVarNames.empty()) if (!mVarNames.empty())

@ -3,24 +3,21 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
unsigned int SoundGenerator::sRecordId = REC_SNDG; unsigned int SoundGenerator::sRecordId = REC_SNDG;
SoundGenerator::SoundGenerator() SoundGenerator::SoundGenerator()
: mIsDeleted(false) : mType(LeftFoot),
mIsDeleted(false)
{} {}
void SoundGenerator::load(ESMReader &esm) void SoundGenerator::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -28,6 +25,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'D','A','T','A'>::value: case ESM::FourCC<'D','A','T','A'>::value:
esm.getHT(mType, 4); esm.getHT(mType, 4);
hasData = true; hasData = true;
@ -40,23 +45,26 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
esm.fail("Missing DATA"); if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing DATA subrecord");
} }
void SoundGenerator::save(ESMWriter &esm) const void SoundGenerator::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
return;
}
esm.writeHNT("DATA", mType, 4); esm.writeHNT("DATA", mType, 4);
esm.writeHNOCString("CNAM", mCreature); esm.writeHNOCString("CNAM", mCreature);
esm.writeHNOCString("SNAM", mSound); esm.writeHNOCString("SNAM", mSound);
if (mIsDeleted)
{
esm.writeHNCString("DELE", "");
}
} }
void SoundGenerator::blank() void SoundGenerator::blank()

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,12 +14,9 @@ namespace ESM
void Sound::load(ESMReader &esm) void Sound::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -28,6 +24,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'F','N','A','M'>::value: case ESM::FourCC<'F','N','A','M'>::value:
mSound = esm.getHString(); mSound = esm.getHString();
break; break;
@ -37,18 +41,23 @@ namespace ESM
break; break;
default: default:
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
esm.fail("Missing DATA"); if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing DATA subrecord");
} }
void Sound::save(ESMWriter &esm) const void Sound::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -16,13 +15,9 @@ namespace ESM
void Spell::load(ESMReader &esm) void Spell::load(ESMReader &esm)
{ {
mEffects.mList.clear(); mEffects.mList.clear();
mIsDeleted = false;
mId = esm.getHNString("NAME"); bool hasName = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -31,6 +26,14 @@ namespace ESM
switch (val) switch (val)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'F','N','A','M'>::value: case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString(); mName = esm.getHString();
break; break;
@ -43,18 +46,25 @@ namespace ESM
esm.getHT(s, 24); esm.getHT(s, 24);
mEffects.mList.push_back(s); mEffects.mList.push_back(s);
break; break;
default:
esm.fail("Unknown subrecord");
break;
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing SPDT subrecord"); esm.fail("Missing SPDT subrecord");
} }
void Spell::save(ESMWriter &esm) const void Spell::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }
@ -70,9 +80,7 @@ namespace ESM
mData.mFlags = 0; mData.mFlags = 0;
mName.clear(); mName.clear();
mEffects.mList.clear(); mEffects.mList.clear();
mIsDeleted = false; mIsDeleted = false;
} }
} }

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,24 +14,46 @@ namespace ESM
void Static::load(ESMReader &esm) void Static::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
bool hasName = false;
while (esm.hasMoreSubs())
{ {
return; esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
break;
}
} }
mModel = esm.getHNString("MODL"); if (!hasName)
esm.fail("Missing NAME subrecord");
} }
void Static::save(ESMWriter &esm) const void Static::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; }
else
{
esm.writeHNCString("MODL", mModel);
} }
esm.writeHNCString("MODL", mModel);
} }
void Static::blank() void Static::blank()

@ -3,7 +3,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -15,12 +14,9 @@ namespace ESM
void Weapon::load(ESMReader &esm) void Weapon::load(ESMReader &esm)
{ {
mId = esm.getHNString("NAME"); mIsDeleted = false;
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false; bool hasData = false;
while (esm.hasMoreSubs()) while (esm.hasMoreSubs())
{ {
@ -28,6 +24,14 @@ namespace ESM
uint32_t name = esm.retSubName().val; uint32_t name = esm.retSubName().val;
switch (name) switch (name)
{ {
case ESM::FourCC<'N','A','M','E'>::value:
mId = esm.getHString();
hasName = true;
break;
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'M','O','D','L'>::value: case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString(); mModel = esm.getHString();
break; break;
@ -51,15 +55,19 @@ namespace ESM
esm.fail("Unknown subrecord"); esm.fail("Unknown subrecord");
} }
} }
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing WPDT subrecord"); esm.fail("Missing WPDT subrecord");
} }
void Weapon::save(ESMWriter &esm) const void Weapon::save(ESMWriter &esm) const
{ {
esm.writeHNCString("NAME", mId); esm.writeHNCString("NAME", mId);
if (mIsDeleted) if (mIsDeleted)
{ {
writeDeleSubRecord(esm); esm.writeHNCString("DELE", "");
return; return;
} }

Loading…
Cancel
Save