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

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

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "util.hpp"
ESM::CellRef::CellRef()
: 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)
{
mIsDeleted = false;
loadId(esm, wideRefNum);
loadData(esm);
}
@ -55,62 +53,90 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum)
mRefNum.load (esm, wideRefNum);
mRefID = esm.getHNString ("NAME");
mIsDeleted = false;
}
void ESM::CellRef::loadData(ESMReader &esm)
{
// Again, UNAM sometimes appears after NAME and sometimes later.
// 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");
mScale = 1.0f;
mFactionRank = -2;
esm.getHNOT (mFactionRank, "INDX");
mGoldValue = 1;
mChargeInt = -1;
mEnchantmentCharge = -1;
mGoldValue = 1;
mLockLevel = 0;
mReferenceBlocked = -1;
mTeleport = false;
mIsDeleted = false;
esm.getHNOT (mEnchantmentCharge, "XCHG");
esm.getHNOT (mChargeInt, "INTV");
esm.getHNOT (mGoldValue, "NAM9");
// Present for doors that teleport you to another cell.
if (esm.isNextSub ("DODT"))
bool isLoaded = false;
while (!isLoaded && esm.hasMoreSubs())
{
mTeleport = true;
esm.getHT (mDoorDest);
mDestCell = esm.getHNOString ("DNAM");
esm.getSubName();
uint32_t name = esm.retSubName().val;
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
@ -149,7 +175,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons
}
if (!inInventory && mLockLevel != 0) {
esm.writeHNT("FLTV", mLockLevel);
esm.writeHNT("FLTV", mLockLevel);
}
if (!inInventory)
@ -166,7 +192,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
}
}

@ -187,6 +187,11 @@ bool ESMReader::peekNextSub(const char *name)
return mCtx.subName == name;
}
void ESMReader::cacheSubName()
{
mCtx.subCached = true;
}
// Read subrecord name. This gets called a LOT, so I've optimized it
// slightly.
void ESMReader::getSubName()

@ -185,6 +185,9 @@ public:
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
// slightly.
void getSubName();

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,18 +14,23 @@ namespace ESM
void Activator::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasName = 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 = 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;
@ -38,15 +42,20 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasName)
esm.fail("Missing NAME subrecord");
}
void Activator::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -16,13 +15,9 @@ namespace ESM
void Potion::load(ESMReader &esm)
{
mEffects.mList.clear();
mIsDeleted = false;
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -30,6 +25,14 @@ namespace ESM
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;
@ -51,17 +54,22 @@ namespace ESM
break;
default:
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
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,12 +14,9 @@ namespace ESM
void Apparatus::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -28,6 +24,14 @@ namespace ESM
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;
@ -46,18 +50,23 @@ namespace ESM
break;
default:
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
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -46,13 +45,9 @@ namespace ESM
void Armor::load(ESMReader &esm)
{
mParts.mParts.clear();
mIsDeleted = false;
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -60,6 +55,14 @@ namespace ESM
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;
@ -84,18 +87,23 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing CTDT subrecord");
}
void Armor::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,12 +14,9 @@ namespace ESM
void BodyPart::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -28,6 +24,14 @@ namespace ESM
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;
@ -40,19 +44,23 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing BYDT subrecord");
}
void BodyPart::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,12 +14,9 @@ namespace ESM
void Book::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -28,6 +24,14 @@ namespace ESM
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;
@ -52,17 +56,22 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing BKDT subrecord");
}
void Book::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -16,16 +16,23 @@ namespace ESM
void BirthSign::load(ESMReader &esm)
{
mPowers.mList.clear();
mIsDeleted = false;
mIsDeleted = readDeleSubRecord(esm);
mId = esm.getHNString("NAME");
bool hasName = 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 = 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;
@ -40,16 +47,21 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasName)
esm.fail("Missing NAME subrecord");
}
void BirthSign::save(ESMWriter &esm) const
{
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
}
esm.writeHNCString("NAME", mId);
esm.writeHNOCString("FNAM", mName);
esm.writeHNOCString("TNAM", mTexture);

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

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -16,13 +15,9 @@ namespace ESM
void Clothing::load(ESMReader &esm)
{
mParts.mParts.clear();
mIsDeleted = false;
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -30,6 +25,14 @@ namespace ESM
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;
@ -54,18 +57,23 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing CTDT subrecord");
}
void Clothing::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -26,19 +25,17 @@ namespace ESM
unsigned int Container::sRecordId = REC_CONT;
Container::Container()
: mIsDeleted(false)
: mWeight(0),
mFlags(0x8),
mIsDeleted(false)
{}
void Container::load(ESMReader &esm)
{
mInventory.mList.clear();
mIsDeleted = false;
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasWeight = false;
bool hasFlags = false;
while (esm.hasMoreSubs())
@ -47,6 +44,14 @@ namespace ESM
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;
@ -73,20 +78,25 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasWeight)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasWeight && !mIsDeleted)
esm.fail("Missing CNDT subrecord");
if (!hasFlags)
if (!hasFlags && !mIsDeleted)
esm.fail("Missing FLAG subrecord");
}
void Container::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,14 +3,15 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM {
unsigned int Creature::sRecordId = REC_CREA;
Creature::Creature()
: mIsDeleted(false)
: mFlags(0),
mScale(0.0f),
mIsDeleted(false)
{}
void Creature::load(ESMReader &esm)
@ -22,14 +23,11 @@ namespace ESM {
mSpells.mList.clear();
mTransport.mList.clear();
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mScale = 1.f;
mHasAI = false;
mIsDeleted = false;
bool hasName = false;
bool hasNpdt = false;
bool hasFlags = false;
while (esm.hasMoreSubs())
@ -38,6 +36,14 @@ namespace ESM {
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;
@ -85,20 +91,25 @@ namespace ESM {
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasNpdt)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasNpdt && !mIsDeleted)
esm.fail("Missing NPDT subrecord");
if (!hasFlags)
if (!hasFlags && !mIsDeleted)
esm.fail("Missing FLAG subrecord");
}
void Creature::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -7,7 +7,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -31,20 +30,36 @@ namespace ESM
void Dialogue::loadData(ESMReader &esm)
{
esm.getSubNameIs("DATA");
esm.getSubHeader();
int si = esm.getSubSize();
if (si == 1)
esm.getT(mType);
else if (si == 4) // The dialogue is deleted
while (esm.hasMoreSubs())
{
int32_t empty;
esm.getT(empty); // Skip an empty DATA
mIsDeleted = readDeleSubRecord(esm);
mType = Unknown;
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
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
@ -52,8 +67,7 @@ namespace ESM
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
esm.writeHNT("DATA", static_cast<int32_t>(0));
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
}
else
{
@ -138,7 +152,7 @@ namespace ESM
{
for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); )
{
if (it->mIsDeleted || it->mQuestStatus == DialInfo::QS_Deleted)
if (it->mIsDeleted)
it = mInfo.erase(it);
else
++it;

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,18 +14,23 @@ namespace ESM
void Door::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasName = 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 = 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;
@ -44,16 +48,21 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasName)
esm.fail("Missing NAME subrecord");
}
void Door::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

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

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

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

@ -3,14 +3,15 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
unsigned int DialInfo::sRecordId = REC_INFO;
DialInfo::DialInfo()
: mIsDeleted(false)
: mFactionLess(false),
mQuestStatus(QS_None),
mIsDeleted(false)
{}
void DialInfo::load(ESMReader &esm)
@ -29,6 +30,7 @@ namespace ESM
{
mQuestStatus = QS_None;
mFactionLess = false;
mIsDeleted = false;
mPrev = esm.getHNString("PNAM");
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
mSelects.clear();
// If the info is deleted, NAME and DELE sub-records are followed after NNAM
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)
while (esm.hasMoreSubs())
{
SelectStruct ss;
ss.mSelectRule = esm.getHString();
ss.mValue.read (esm, Variant::Format_Info);
mSelects.push_back(ss);
if (esm.isEmptyOrGetName())
return;
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'D','E','L','E'>::value:
esm.skipHSub();
mIsDeleted = true;
break;
case ESM::FourCC<'D','A','T','A'>::value:
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
@ -158,8 +119,7 @@ namespace ESM
if (mIsDeleted)
{
esm.writeHNCString("NAME", mResponse);
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}
@ -186,7 +146,6 @@ namespace ESM
case QS_Name: esm.writeHNT("QSTN",'\1'); break;
case QS_Finished: esm.writeHNT("QSTF", '\1'); break;
case QS_Restart: esm.writeHNT("QSTR", '\1'); break;
case QS_Deleted: esm.writeHNT("DELE", '\1'); break;
default: break;
}
}

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

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,12 +14,9 @@ namespace ESM
void Ingredient::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -28,6 +24,14 @@ namespace ESM
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;
@ -46,10 +50,13 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing IRDT subrecord");
// horrible hack to fix broken data in records
@ -79,9 +86,10 @@ namespace ESM
void Ingredient::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -13,49 +12,67 @@ namespace ESM
void LevelledListBase::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
esm.getHNT(mFlags, "DATA");
esm.getHNT(mChanceNone, "NNAM");
mIsDeleted = false;
if (esm.isNextSub("INDX"))
{
int len;
esm.getHT(len);
mList.resize(len);
}
else
bool hasName = false;
while (esm.hasMoreSubs())
{
// Original engine ignores rest of the record, even if there are items following
mList.clear();
esm.skipRecord();
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<'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,
// 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
// 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
// that does something with that list.
for (size_t i = 0; i < mList.size(); i++)
{
LevelItem &li = mList[i];
li.mId = esm.getHNString(mRecName);
esm.getHNT(li.mLevel, "INTV");
// 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,
// 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
// to actually track list changes instead of including the whole list for every file
// that does something with that list.
for (size_t i = 0; i < mList.size(); i++)
{
LevelItem &li = mList[i];
li.mId = esm.getHNString(mRecName);
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
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,12 +14,9 @@ namespace ESM
void Light::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -28,6 +24,14 @@ namespace ESM
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;
@ -49,17 +53,22 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing LHDT subrecord");
}
void Light::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,19 +14,23 @@ namespace ESM
void Lockpick::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasData = true;
bool hasName = false;
bool hasData = 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();
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;
@ -46,18 +49,23 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing LKDT subrecord");
}
void Lockpick::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,17 +14,49 @@ namespace ESM
void LandTexture::load(ESMReader &esm)
{
mIsDeleted = readDeleSubRecord(esm);
mId = esm.getHNString("NAME");
esm.getHNT(mIndex, "INTV");
mTexture = esm.getHNString("DATA");
mIsDeleted = false;
bool hasName = false;
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
{
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
}
esm.writeHNCString("NAME", mId);
esm.writeHNT("INTV", mIndex);
esm.writeHNCString("DATA", mTexture);

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

@ -3,40 +3,45 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
unsigned int NPC::sRecordId = REC_NPC_;
NPC::NPC()
: mIsDeleted(false)
: mFlags(0),
mHasAI(false),
mIsDeleted(false)
{}
void NPC::load(ESMReader &esm)
{
mIsDeleted = false;
mPersistent = (esm.getRecordFlags() & 0x0400) != 0;
mSpells.mList.clear();
mInventory.mList.clear();
mTransport.mList.clear();
mAiPackage.mList.clear();
mHasAI = false;
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
bool hasName = false;
bool hasNpdt = false;
bool hasFlags = false;
mHasAI = 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 = 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;
@ -105,19 +110,24 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasNpdt)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasNpdt && !mIsDeleted)
esm.fail("Missing NPDT subrecord");
if (!hasFlags)
if (!hasFlags && !mIsDeleted)
esm.fail("Missing FLAG subrecord");
}
void NPC::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,19 +14,24 @@ namespace ESM
void Probe::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasData = true;
bool hasName = false;
bool hasData = 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 = 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;
@ -46,18 +50,23 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing PBDT subrecord");
}
void Probe::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,64 +3,95 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
unsigned int Region::sRecordId = REC_REGN;
Region::Region()
: mIsDeleted(false)
: mMapColor(0),
mIsDeleted(false)
{}
void Region::load(ESMReader &esm)
{
mIsDeleted = readDeleSubRecord(esm);
mId = esm.getHNString("NAME");
mName = esm.getHNOString("FNAM");
mIsDeleted = false;
esm.getSubNameIs("WEAT");
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)
bool hasName = false;
while (esm.hasMoreSubs())
{
// May include the additional two bytes (but not necessarily)
if (esm.getSubSize() == sizeof(mData))
esm.getExact(&mData, sizeof(mData));
else
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
mData.mA = 0;
mData.mB = 0;
esm.getExact(&mData, sizeof(mData)-2);
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:
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");
mSoundList.clear();
while (esm.hasMoreSubs())
{
SoundRef sr;
esm.getHNT(sr, "SNAM", 33);
mSoundList.push_back(sr);
}
if (!hasName)
esm.fail("Missing NAME subrecord");
}
void Region::save(ESMWriter &esm) const
{
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
}
esm.writeHNString("NAME", mId);
esm.writeHNOCString("FNAM", mName);

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,19 +14,24 @@ namespace ESM
void Repair::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasData = true;
bool hasName = false;
bool hasData = 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 = 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;
@ -46,18 +50,23 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing RIDT subrecord");
}
void Repair::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
#include <iostream>
@ -64,23 +63,27 @@ namespace 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();
mIsDeleted = false;
bool hasHeader = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
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:
// list of local variables
loadSCVR(esm);
@ -95,8 +98,12 @@ namespace ESM
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasHeader)
esm.fail("Missing SCHD subrecord");
}
void Script::save(ESMWriter &esm) const
@ -116,7 +123,7 @@ namespace ESM
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
}
if (!mVarNames.empty())

@ -3,24 +3,21 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
unsigned int SoundGenerator::sRecordId = REC_SNDG;
SoundGenerator::SoundGenerator()
: mIsDeleted(false)
: mType(LeftFoot),
mIsDeleted(false)
{}
void SoundGenerator::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -28,6 +25,14 @@ namespace ESM
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<'D','A','T','A'>::value:
esm.getHT(mType, 4);
hasData = true;
@ -40,23 +45,26 @@ namespace ESM
break;
default:
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
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
return;
}
esm.writeHNT("DATA", mType, 4);
esm.writeHNOCString("CNAM", mCreature);
esm.writeHNOCString("SNAM", mSound);
if (mIsDeleted)
{
esm.writeHNCString("DELE", "");
}
}
void SoundGenerator::blank()

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,12 +14,9 @@ namespace ESM
void Sound::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -28,6 +24,14 @@ namespace ESM
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<'F','N','A','M'>::value:
mSound = esm.getHString();
break;
@ -37,18 +41,23 @@ namespace ESM
break;
default:
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
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

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

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,24 +14,46 @@ namespace ESM
void Static::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
mIsDeleted = false;
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
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
return;
esm.writeHNCString("DELE", "");
}
else
{
esm.writeHNCString("MODL", mModel);
}
esm.writeHNCString("MODL", mModel);
}
void Static::blank()

@ -3,7 +3,6 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
#include "util.hpp"
namespace ESM
{
@ -15,12 +14,9 @@ namespace ESM
void Weapon::load(ESMReader &esm)
{
mId = esm.getHNString("NAME");
if (mIsDeleted = readDeleSubRecord(esm))
{
return;
}
mIsDeleted = false;
bool hasName = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
@ -28,6 +24,14 @@ namespace ESM
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;
@ -51,15 +55,19 @@ namespace ESM
esm.fail("Unknown subrecord");
}
}
if (!hasData)
if (!hasName)
esm.fail("Missing NAME subrecord");
if (!hasData && !mIsDeleted)
esm.fail("Missing WPDT subrecord");
}
void Weapon::save(ESMWriter &esm) const
{
esm.writeHNCString("NAME", mId);
if (mIsDeleted)
{
writeDeleSubRecord(esm);
esm.writeHNCString("DELE", "");
return;
}

Loading…
Cancel
Save