Don't rely on subrecord order part 2

Nice side effects:
 - Subrecord name comparison now uses magic number instead of string (faster)
 - Improves the error message for unknown subrecords: will print the record in question instead of failing to read the next record with a strange error
celladd
scrawl 10 years ago
parent 75db4d6473
commit 49d912e5b6

@ -41,29 +41,6 @@ namespace ESM
}
void AIPackageList::load(ESMReader &esm)
{
mList.clear();
while (esm.hasMoreSubs()) {
// initialize every iteration
esm.getSubName();
switch (esm.retSubName().val)
{
case AI_Wander:
case AI_Activate:
case AI_Escort:
case AI_Follow:
case AI_Travel:
case AI_CNDT:
add(esm);
break;
default:
return;
}
}
}
void AIPackageList::save(ESMWriter &esm) const
{
typedef std::vector<AIPackage>::const_iterator PackageIter;

@ -94,9 +94,6 @@ namespace ESM
/// Add a single AIPackage, assumes subrecord name was already read
void add(ESMReader &esm);
/// TODO: remove this method. The ESM format does not guarantee that all AI packages follow one another
void load(ESMReader &esm);
void save(ESMWriter &esm) const;
};
}

@ -8,12 +8,17 @@ namespace ESM {
void EffectList::load(ESMReader &esm)
{
mList.clear();
ENAMstruct s;
while (esm.isNextSub("ENAM")) {
add(esm);
}
}
void EffectList::add(ESMReader &esm)
{
ENAMstruct s;
esm.getHT(s, 24);
mList.push_back(s);
}
}
void EffectList::save(ESMWriter &esm) const
{

@ -29,11 +29,15 @@ namespace ESM
};
#pragma pack(pop)
/// EffectList, ENAM subrecord
struct EffectList
{
std::vector<ENAMstruct> mList;
/// Load one effect, assumes subrecord name was already read
void add(ESMReader &esm);
/// Load all effects
void load(ESMReader &esm);
void save(ESMWriter &esm) const;
};

@ -10,9 +10,25 @@ namespace ESM
void Activator::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
mName = esm.getHNOString("FNAM");
mScript = esm.getHNOString("SCRI");
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'S','C','R','I'>::value:
mScript = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
}
}
}
void Activator::save(ESMWriter &esm) const
{

@ -10,12 +10,39 @@ namespace ESM
void Potion::load(ESMReader &esm)
{
mModel = esm.getHNOString("MODL");
mIcon = esm.getHNOString("TEXT"); // not ITEX here for some reason
mScript = esm.getHNOString("SCRI");
mName = esm.getHNOString("FNAM");
esm.getHNT(mData, "ALDT", 12);
mEffects.load(esm);
mEffects.mList.clear();
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
case ESM::FourCC<'T','E','X','T'>::value: // not ITEX here for some reason
mIcon = esm.getHString();
break;
case ESM::FourCC<'S','C','R','I'>::value:
mScript = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'A','L','D','T'>::value:
esm.getHT(mData, 12);
hasData = true;
break;
case ESM::FourCC<'E','N','A','M'>::value:
mEffects.add(esm);
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing ALDT");
}
void Potion::save(ESMWriter &esm) const
{

@ -10,25 +10,35 @@ namespace ESM
void Apparatus::load(ESMReader &esm)
{
// we will not treat duplicated subrecords as errors here
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
NAME subName = esm.retSubName();
if (subName == "MODL")
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
else if (subName == "FNAM")
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
else if (subName == "AADT")
break;
case ESM::FourCC<'A','A','D','T'>::value:
esm.getHT(mData);
else if (subName == "SCRI")
hasData = true;
break;
case ESM::FourCC<'S','C','R','I'>::value:
mScript = esm.getHString();
else if (subName == "ITEX")
break;
case ESM::FourCC<'I','T','E','X'>::value:
mIcon = esm.getHString();
else
esm.fail("wrong subrecord type " + subName.toString() + " for APPA record");
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing AADT");
}
void Apparatus::save(ESMWriter &esm) const

@ -11,9 +11,30 @@ namespace ESM
void BodyPart::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
mRace = esm.getHNOString("FNAM");
esm.getHNT(mData, "BYDT", 4);
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
mRace = esm.getHString();
break;
case ESM::FourCC<'B','Y','D','T'>::value:
esm.getHT(mData, 4);
hasData = true;
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing BYDT subrecord");
}
void BodyPart::save(ESMWriter &esm) const
{

@ -10,11 +10,29 @@ namespace ESM
void BirthSign::load(ESMReader &esm)
{
mName = esm.getHNOString("FNAM");
mTexture = esm.getHNOString("TNAM");
mDescription = esm.getHNOString("DESC");
mPowers.load(esm);
mPowers.mList.clear();
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'T','N','A','M'>::value:
mTexture = esm.getHString();
break;
case ESM::FourCC<'D','E','S','C'>::value:
mDescription = esm.getHString();
break;
case ESM::FourCC<'N','P','C','S'>::value:
mPowers.add(esm);
break;
default:
esm.fail("Unknown subrecord");
}
}
}
void BirthSign::save(ESMWriter &esm) const

@ -41,13 +41,31 @@ const char *Class::sGmstSpecializationIds[3] = {
void Class::load(ESMReader &esm)
{
mName = esm.getHNOString("FNAM");
esm.getHNT(mData, "CLDT", 60);
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'C','L','D','T'>::value:
esm.getHT(mData, 60);
if (mData.mIsPlayable > 1)
esm.fail("Unknown bool value");
mDescription = esm.getHNOString("DESC");
hasData = true;
break;
case ESM::FourCC<'D','E','S','C'>::value:
mDescription = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing CLDT subrecord");
}
void Class::save(ESMWriter &esm) const
{

@ -14,15 +14,6 @@ void InventoryList::add(ESMReader &esm)
mList.push_back(ci);
}
void InventoryList::load(ESMReader &esm)
{
mList.clear();
while (esm.isNextSub("NPCO"))
{
add(esm);
}
}
void InventoryList::save(ESMWriter &esm) const
{
for (std::vector<ContItem>::const_iterator it = mList.begin(); it != mList.end(); ++it)
@ -35,19 +26,47 @@ void InventoryList::save(ESMWriter &esm) const
void Container::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
mName = esm.getHNOString("FNAM");
esm.getHNT(mWeight, "CNDT", 4);
esm.getHNT(mFlags, "FLAG", 4);
mInventory.mList.clear();
bool hasWeight = false;
bool hasFlags = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'C','N','D','T'>::value:
esm.getHT(mWeight, 4);
hasWeight = true;
break;
case ESM::FourCC<'F','L','A','G'>::value:
esm.getHT(mFlags, 4);
if (mFlags & 0xf4)
esm.fail("Unknown flags");
if (!(mFlags & 0x8))
esm.fail("Flag 8 not set");
mScript = esm.getHNOString("SCRI");
mInventory.load(esm);
hasFlags = true;
break;
case ESM::FourCC<'S','C','R','I'>::value:
mScript = esm.getHString();
break;
case ESM::FourCC<'N','P','C','O'>::value:
mInventory.add(esm);
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasWeight)
esm.fail("Missing CNDT subrecord");
if (!hasFlags)
esm.fail("Missing FLAG subrecord");
}
void Container::save(ESMWriter &esm) const

@ -22,6 +22,7 @@ struct ContItem
NAME32 mItem;
};
/// InventoryList, NPCO subrecord
struct InventoryList
{
std::vector<ContItem> mList;
@ -29,8 +30,6 @@ struct InventoryList
/// Load one item, assumes subrecord name is already read
void add(ESMReader &esm);
/// TODO: remove this method, the ESM format doesn't guarantee that all ContItems follow one another
void load(ESMReader &esm);
void save(ESMWriter &esm) const;
};

@ -12,30 +12,69 @@ void Creature::load(ESMReader &esm)
{
mPersistent = esm.getRecordFlags() & 0x0400;
mModel = esm.getHNString("MODL");
mOriginal = esm.getHNOString("CNAM");
mName = esm.getHNOString("FNAM");
mScript = esm.getHNOString("SCRI");
esm.getHNT(mData, "NPDT", 96);
esm.getHNT(mFlags, "FLAG");
mScale = 1.0;
esm.getHNOT(mScale, "XSCL");
mInventory.load(esm);
mSpells.load(esm);
mAiPackage.mList.clear();
mInventory.mList.clear();
mSpells.mList.clear();
if (esm.isNextSub("AIDT"))
mScale = 1.f;
mHasAI = false;
bool hasNpdt = false;
bool hasFlags = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
case ESM::FourCC<'C','N','A','M'>::value:
mOriginal = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'S','C','R','I'>::value:
mScript = esm.getHString();
break;
case ESM::FourCC<'N','P','D','T'>::value:
esm.getHT(mData, 96);
hasNpdt = true;
break;
case ESM::FourCC<'F','L','A','G'>::value:
esm.getHT(mFlags);
hasFlags = true;
break;
case ESM::FourCC<'X','S','C','L'>::value:
esm.getHT(mScale);
break;
case ESM::FourCC<'N','P','C','O'>::value:
mInventory.add(esm);
break;
case ESM::FourCC<'N','P','C','S'>::value:
mSpells.add(esm);
break;
case ESM::FourCC<'A','I','D','T'>::value:
esm.getHExact(&mAiData, sizeof(mAiData));
mHasAI = true;
break;
case AI_Wander:
case AI_Activate:
case AI_Escort:
case AI_Follow:
case AI_Travel:
case AI_CNDT:
mAiPackage.add(esm);
break;
default:
esm.fail("Unknown subrecord");
}
else
mHasAI = false;
mAiPackage.load(esm);
esm.skipRecord();
}
if (!hasNpdt)
esm.fail("Missing NPDT subrecord");
if (!hasFlags)
esm.fail("Missing FLAG subrecord");
}
void Creature::save(ESMWriter &esm) const

@ -10,8 +10,28 @@ namespace ESM
void Enchantment::load(ESMReader &esm)
{
esm.getHNT(mData, "ENDT", 16);
mEffects.load(esm);
mEffects.mList.clear();
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'E','N','D','T'>::value:
esm.getHT(mData, 16);
hasData = true;
break;
case ESM::FourCC<'E','N','A','M'>::value:
mEffects.add(esm);
break;
default:
esm.fail("Unknown subrecord");
break;
}
}
if (!hasData)
esm.fail("Missing ENDT subrecord");
}
void Enchantment::save(ESMWriter &esm) const

@ -28,27 +28,46 @@ namespace ESM
void Faction::load(ESMReader &esm)
{
mName = esm.getHNOString("FNAM");
// Read rank names. These are optional.
int i = 0;
while (esm.isNextSub("RNAM") && i < 10)
mRanks[i++] = esm.getHString();
// Main data struct
esm.getHNT(mData, "FADT", 240);
mReactions.clear();
for (int i=0;i<10;++i)
mRanks[i].clear();
int rankCounter=0;
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'R','N','A','M'>::value:
if (rankCounter >= 10)
esm.fail("Rank out of range");
mRanks[rankCounter++] = esm.getHString();
break;
case ESM::FourCC<'F','A','D','T'>::value:
esm.getHT(mData, 240);
if (mData.mIsHidden > 1)
esm.fail("Unknown flag!");
// Read faction response values
while (esm.hasMoreSubs())
hasData = true;
break;
case ESM::FourCC<'A','N','A','M'>::value:
{
std::string faction = esm.getHNString("ANAM");
std::string faction = esm.getHString();
int reaction;
esm.getHNT(reaction, "INTV");
mReactions[faction] = reaction;
break;
}
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing FADT subrecord");
}
void Faction::save(ESMWriter &esm) const
{

@ -10,11 +10,37 @@ namespace ESM
void Ingredient::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
mName = esm.getHNOString("FNAM");
esm.getHNT(mData, "IRDT", 56);
mScript = esm.getHNOString("SCRI");
mIcon = esm.getHNOString("ITEX");
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'I','R','D','T'>::value:
esm.getHT(mData, 56);
hasData = true;
break;
case ESM::FourCC<'S','C','R','I'>::value:
mScript = esm.getHString();
break;
case ESM::FourCC<'I','T','E','X'>::value:
mIcon = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing IRDT subrecord");
// horrible hack to fix broken data in records
for (int i=0; i<4; ++i)
{

@ -20,6 +20,7 @@ void LevelledListBase::load(ESMReader &esm)
}
else
{
// Original engine ignores rest of the record, even if there are items following
esm.skipRecord();
return;
}

@ -10,13 +10,38 @@ namespace ESM
void Light::load(ESMReader &esm)
{
mModel = esm.getHNOString("MODL");
mName = esm.getHNOString("FNAM");
mIcon = esm.getHNOString("ITEX");
assert(sizeof(mData) == 24);
esm.getHNT(mData, "LHDT", 24);
mScript = esm.getHNOString("SCRI");
mSound = esm.getHNOString("SNAM");
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'I','T','E','X'>::value:
mIcon = esm.getHString();
break;
case ESM::FourCC<'L','H','D','T'>::value:
esm.getHT(mData, 24);
hasData = true;
break;
case ESM::FourCC<'S','C','R','I'>::value:
mScript = esm.getHString();
break;
case ESM::FourCC<'S','N','A','M'>::value:
mSound = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing LHDT subrecord");
}
void Light::save(ESMWriter &esm) const
{

@ -10,13 +10,35 @@ namespace ESM
void Lockpick::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
mName = esm.getHNOString("FNAM");
esm.getHNT(mData, "LKDT", 16);
mScript = esm.getHNOString("SCRI");
mIcon = esm.getHNOString("ITEX");
bool hasData = true;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'L','K','D','T'>::value:
esm.getHT(mData, 16);
hasData = true;
break;
case ESM::FourCC<'S','C','R','I'>::value:
mScript = esm.getHString();
break;
case ESM::FourCC<'I','T','E','X'>::value:
mIcon = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing LKDT subrecord");
}
void Lockpick::save(ESMWriter &esm) const

@ -246,7 +246,7 @@ void MagicEffect::load(ESMReader &esm)
mDescription = esm.getHString();
break;
default:
esm.fail("Unknown subrecord " + esm.retSubName().toString());
esm.fail("Unknown subrecord");
}
}
}

@ -57,9 +57,9 @@ struct MagicEffect
// Glow color for enchanted items with this effect
int mRed, mGreen, mBlue;
float mUnknown1;
float mUnknown1; // Called "Size X" in CS
float mSpeed; // Speed of fired projectile
float mUnknown2;
float mUnknown2; // Called "Size Cap" in CS
}; // 36 bytes
static const std::map<short,std::string> sNames;

@ -99,7 +99,7 @@ namespace ESM
mAiPackage.add(esm);
break;
default:
esm.fail("Unknown subrecord " + esm.retSubName().toString());
esm.fail("Unknown subrecord");
}
}
if (!hasNpdt)

@ -10,13 +10,35 @@ namespace ESM
void Probe::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
mName = esm.getHNOString("FNAM");
esm.getHNT(mData, "PBDT", 16);
mScript = esm.getHNOString("SCRI");
mIcon = esm.getHNOString("ITEX");
bool hasData = true;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'P','B','D','T'>::value:
esm.getHT(mData, 16);
hasData = true;
break;
case ESM::FourCC<'S','C','R','I'>::value:
mScript = esm.getHString();
break;
case ESM::FourCC<'I','T','E','X'>::value:
mIcon = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing PBDT subrecord");
}
void Probe::save(ESMWriter &esm) const

@ -43,7 +43,7 @@ void Race::load(ESMReader &esm)
mPowers.add(esm);
break;
default:
esm.fail("Unknown subrecord " + esm.retSubName().toString());
esm.fail("Unknown subrecord");
}
}
if (!hasData)

@ -10,13 +10,35 @@ namespace ESM
void Repair::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
mName = esm.getHNOString("FNAM");
esm.getHNT(mData, "RIDT", 16);
mScript = esm.getHNOString("SCRI");
mIcon = esm.getHNOString("ITEX");
bool hasData = true;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'M','O','D','L'>::value:
mModel = esm.getHString();
break;
case ESM::FourCC<'F','N','A','M'>::value:
mName = esm.getHString();
break;
case ESM::FourCC<'R','I','D','T'>::value:
esm.getHT(mData, 16);
hasData = true;
break;
case ESM::FourCC<'S','C','R','I'>::value:
mScript = esm.getHString();
break;
case ESM::FourCC<'I','T','E','X'>::value:
mIcon = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing RIDT subrecord");
}
void Repair::save(ESMWriter &esm) const

@ -9,17 +9,7 @@ namespace ESM
unsigned int Script::sRecordId = REC_SCPT;
void Script::load(ESMReader &esm)
{
SCHD data;
esm.getHNT(data, "SCHD", 52);
mData = data.mData;
mId = data.mName.toString();
mVarNames.clear();
// List of local variables
if (esm.isNextSub("SCVR"))
void Script::loadSCVR(ESMReader &esm)
{
int s = mData.mStringTableSize;
@ -66,27 +56,39 @@ void Script::load(ESMReader &esm)
}
}
// Script mData
if (esm.isNextSub("SCDT"))
void Script::load(ESMReader &esm)
{
SCHD data;
esm.getHNT(data, "SCHD", 52);
mData = data.mData;
mId = data.mName.toString();
mVarNames.clear();
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'S','C','V','R'>::value:
// list of local variables
loadSCVR(esm);
break;
case ESM::FourCC<'S','C','D','T'>::value:
// compiled script
mScriptData.resize(mData.mScriptDataSize);
esm.getHExact(&mScriptData[0], mScriptData.size());
break;
case ESM::FourCC<'S','C','T','X'>::value:
mScriptText = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
}
// Script text
mScriptText = esm.getHNOString("SCTX");
// NOTE: A minor hack/workaround...
//
// MAO_Containers.esp from Morrowind Acoustic Overhaul has SCVR records
// at the end (see Bug #1849). Since OpenMW does not use SCVR subrecords
// for variable names just skip these as a quick fix. An alternative
// solution would be to decode and validate SCVR subrecords even if they
// appear here.
if (esm.isNextSub("SCVR")) {
esm.skipHSub();
}
}
void Script::save(ESMWriter &esm) const
{
std::string varNameString;

@ -53,6 +53,9 @@ public:
void blank();
///< Set record to default state (does not touch the ID/index).
private:
void loadSCVR(ESMReader &esm);
};
}
#endif

@ -131,9 +131,33 @@ namespace ESM
void Skill::load(ESMReader &esm)
{
esm.getHNT(mIndex, "INDX");
esm.getHNT(mData, "SKDT", 24);
mDescription = esm.getHNOString("DESC");
bool hasIndex = false;
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'I','N','D','X'>::value:
esm.getHT(mIndex);
hasIndex = true;
break;
case ESM::FourCC<'S','K','D','T'>::value:
esm.getHT(mData, 24);
hasData = true;
break;
case ESM::FourCC<'D','E','S','C'>::value:
mDescription = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasIndex)
esm.fail("Missing INDX");
if (!hasData)
esm.fail("Missing SKDT");
// create an ID from the index and the name (only used in the editor and likely to change in the
// future)

@ -10,10 +10,29 @@ namespace ESM
void SoundGenerator::load(ESMReader &esm)
{
esm.getHNT(mType, "DATA", 4);
mCreature = esm.getHNOString("CNAM");
mSound = esm.getHNOString("SNAM");
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'D','A','T','A'>::value:
esm.getHT(mType, 4);
hasData = true;
break;
case ESM::FourCC<'C','N','A','M'>::value:
mCreature = esm.getHString();
break;
case ESM::FourCC<'S','N','A','M'>::value:
mSound = esm.getHString();
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing DATA");
}
void SoundGenerator::save(ESMWriter &esm) const
{

@ -10,15 +10,28 @@ namespace ESM
void Sound::load(ESMReader &esm)
{
mSound = esm.getHNOString("FNAM");
esm.getHNT(mData, "DATA", 3);
/*
cout << "vol=" << (int)data.volume
<< " min=" << (int)data.minRange
<< " max=" << (int)data.maxRange
<< endl;
*/
bool hasData = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'F','N','A','M'>::value:
mSound = esm.getHString();
break;
case ESM::FourCC<'D','A','T','A'>::value:
esm.getHT(mData, 3);
hasData = true;
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing DATA");
}
void Sound::save(ESMWriter &esm) const
{
esm.writeHNOCString("FNAM", mSound);

@ -10,8 +10,30 @@ namespace ESM
void StartScript::load(ESMReader &esm)
{
mData = esm.getHNString("DATA");
mScript = esm.getHNString("NAME");
bool hasData = false;
bool hasName = false;
while (esm.hasMoreSubs())
{
esm.getSubName();
uint32_t name = esm.retSubName().val;
switch (name)
{
case ESM::FourCC<'D','A','T','A'>::value:
mData = esm.getHString();
hasData = true;
break;
case ESM::FourCC<'N','A','M','E'>::value:
mScript = esm.getHString();
hasName = true;
break;
default:
esm.fail("Unknown subrecord");
}
}
if (!hasData)
esm.fail("Missing DATA");
if (!hasName)
esm.fail("Missing NAME");
}
void StartScript::save(ESMWriter &esm) const
{

@ -11,6 +11,7 @@ namespace ESM
void Static::load(ESMReader &esm)
{
mPersistent = esm.getRecordFlags() & 0x0400;
mModel = esm.getHNString("MODL");
}
void Static::save(ESMWriter &esm) const

@ -50,8 +50,8 @@ namespace ESM
NAME32 mPlayerName;
};
GMDT mGameData; // Used in .ess savegames only
std::vector<unsigned char> mSCRD; // Used in .ess savegames only, screenshot?
std::vector<unsigned char> mSCRS; // Used in .ess savegames only, screenshot?
std::vector<unsigned char> mSCRD; // Used in .ess savegames only, unknown
std::vector<unsigned char> mSCRS; // Used in .ess savegames only, screenshot
Data mData;
int mFormat;

@ -5,14 +5,6 @@
namespace ESM {
void SpellList::load(ESMReader &esm)
{
mList.clear();
while (esm.isNextSub("NPCS")) {
add(esm);
}
}
void SpellList::add(ESMReader &esm)
{
mList.push_back(esm.getHString());

@ -11,6 +11,7 @@ namespace ESM
/** A list of references to spells and spell effects. This is shared
between the records BSGN, NPC and RACE.
NPCS subrecord.
*/
struct SpellList
{
@ -22,9 +23,6 @@ namespace ESM
/// Load one spell, assumes the subrecord name was already read
void add(ESMReader &esm);
/// Load all spells
/// TODO: remove this method, the ESM format doesn't guarantee that all spell subrecords follow one another
void load(ESMReader &esm);
void save(ESMWriter &esm) const;
};
}

Loading…
Cancel
Save