forked from mirror/openmw-tes3mp
Don't rely on subrecord order when reading (Fixes #2361)
This commit is contained in:
parent
bf1839b370
commit
9009889d24
17 changed files with 574 additions and 253 deletions
|
@ -11,36 +11,55 @@ namespace ESM
|
|||
mServices = 0;
|
||||
}
|
||||
|
||||
void AIPackageList::add(ESMReader &esm)
|
||||
{
|
||||
AIPackage pack;
|
||||
if (esm.retSubName() == AI_CNDT) {
|
||||
mList.back().mCellName = esm.getHString();
|
||||
} else if (esm.retSubName() == AI_Wander) {
|
||||
pack.mType = AI_Wander;
|
||||
esm.getHExact(&pack.mWander, 14);
|
||||
mList.push_back(pack);
|
||||
} else if (esm.retSubName() == AI_Travel) {
|
||||
pack.mType = AI_Travel;
|
||||
esm.getHExact(&pack.mTravel, 16);
|
||||
mList.push_back(pack);
|
||||
} else if (esm.retSubName() == AI_Escort ||
|
||||
esm.retSubName() == AI_Follow)
|
||||
{
|
||||
pack.mType =
|
||||
(esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow;
|
||||
esm.getHExact(&pack.mTarget, 48);
|
||||
mList.push_back(pack);
|
||||
} else if (esm.retSubName() == AI_Activate) {
|
||||
pack.mType = AI_Activate;
|
||||
esm.getHExact(&pack.mActivate, 33);
|
||||
mList.push_back(pack);
|
||||
} else { // not AI package related data, so leave
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AIPackageList::load(ESMReader &esm)
|
||||
{
|
||||
mList.clear();
|
||||
while (esm.hasMoreSubs()) {
|
||||
// initialize every iteration
|
||||
AIPackage pack;
|
||||
esm.getSubName();
|
||||
if (esm.retSubName() == 0x54444e43) { // CNDT
|
||||
mList.back().mCellName = esm.getHString();
|
||||
} else if (esm.retSubName() == AI_Wander) {
|
||||
pack.mType = AI_Wander;
|
||||
esm.getHExact(&pack.mWander, 14);
|
||||
mList.push_back(pack);
|
||||
} else if (esm.retSubName() == AI_Travel) {
|
||||
pack.mType = AI_Travel;
|
||||
esm.getHExact(&pack.mTravel, 16);
|
||||
mList.push_back(pack);
|
||||
} else if (esm.retSubName() == AI_Escort ||
|
||||
esm.retSubName() == AI_Follow)
|
||||
esm.getSubName();
|
||||
switch (esm.retSubName().val)
|
||||
{
|
||||
pack.mType =
|
||||
(esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow;
|
||||
esm.getHExact(&pack.mTarget, 48);
|
||||
mList.push_back(pack);
|
||||
} else if (esm.retSubName() == AI_Activate) {
|
||||
pack.mType = AI_Activate;
|
||||
esm.getHExact(&pack.mActivate, 33);
|
||||
mList.push_back(pack);
|
||||
} else { // not AI package related data, so leave
|
||||
return;
|
||||
case AI_Wander:
|
||||
case AI_Activate:
|
||||
case AI_Escort:
|
||||
case AI_Follow:
|
||||
case AI_Travel:
|
||||
case AI_CNDT:
|
||||
|
||||
add(esm);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,8 @@ namespace ESM
|
|||
AI_Travel = 0x545f4941,
|
||||
AI_Follow = 0x465f4941,
|
||||
AI_Escort = 0x455f4941,
|
||||
AI_Activate = 0x415f4941
|
||||
AI_Activate = 0x415f4941,
|
||||
AI_CNDT = 0x54444e43
|
||||
};
|
||||
|
||||
/// \note Used for storaging packages in a single container
|
||||
|
@ -90,11 +91,12 @@ namespace ESM
|
|||
{
|
||||
std::vector<AIPackage> mList;
|
||||
|
||||
/// \note This breaks consistency of subrecords reading:
|
||||
/// after calling it subrecord name is already read, so
|
||||
/// it needs to use retSubName() if needed. But, hey, there
|
||||
/// is only one field left (XSCL) and only two records uses AI
|
||||
/// 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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,52 +7,87 @@
|
|||
namespace ESM
|
||||
{
|
||||
|
||||
void PartReferenceList::load(ESMReader &esm)
|
||||
{
|
||||
mParts.clear();
|
||||
while (esm.isNextSub("INDX"))
|
||||
void PartReferenceList::add(ESMReader &esm)
|
||||
{
|
||||
PartReference pr;
|
||||
esm.getHT(pr.mPart); // The INDX byte
|
||||
pr.mMale = esm.getHNOString("BNAM");
|
||||
pr.mFemale = esm.getHNOString("CNAM");
|
||||
mParts.push_back(pr);
|
||||
}
|
||||
}
|
||||
|
||||
void PartReferenceList::save(ESMWriter &esm) const
|
||||
{
|
||||
for (std::vector<PartReference>::const_iterator it = mParts.begin(); it != mParts.end(); ++it)
|
||||
}
|
||||
|
||||
void PartReferenceList::load(ESMReader &esm)
|
||||
{
|
||||
esm.writeHNT("INDX", it->mPart);
|
||||
esm.writeHNOString("BNAM", it->mMale);
|
||||
esm.writeHNOString("CNAM", it->mFemale);
|
||||
mParts.clear();
|
||||
while (esm.isNextSub("INDX"))
|
||||
{
|
||||
add(esm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Armor::sRecordId = REC_ARMO;
|
||||
void PartReferenceList::save(ESMWriter &esm) const
|
||||
{
|
||||
for (std::vector<PartReference>::const_iterator it = mParts.begin(); it != mParts.end(); ++it)
|
||||
{
|
||||
esm.writeHNT("INDX", it->mPart);
|
||||
esm.writeHNOString("BNAM", it->mMale);
|
||||
esm.writeHNOString("CNAM", it->mFemale);
|
||||
}
|
||||
}
|
||||
|
||||
void Armor::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
esm.getHNT(mData, "AODT", 24);
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
mParts.load(esm);
|
||||
mEnchant = esm.getHNOString("ENAM");
|
||||
}
|
||||
unsigned int Armor::sRecordId = REC_ARMO;
|
||||
|
||||
void Armor::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNT("AODT", mData, 24);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
mParts.save(esm);
|
||||
esm.writeHNOCString("ENAM", mEnchant);
|
||||
}
|
||||
void Armor::load(ESMReader &esm)
|
||||
{
|
||||
mParts.mParts.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<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'A','O','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<'I','T','E','X'>::value:
|
||||
mIcon = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'E','N','A','M'>::value:
|
||||
mEnchant = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'I','N','D','X'>::value:
|
||||
mParts.add(esm);
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing CTDT subrecord");
|
||||
}
|
||||
|
||||
void Armor::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNT("AODT", mData, 24);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
mParts.save(esm);
|
||||
esm.writeHNOCString("ENAM", mEnchant);
|
||||
}
|
||||
|
||||
void Armor::blank()
|
||||
{
|
||||
|
|
|
@ -55,6 +55,10 @@ struct PartReferenceList
|
|||
{
|
||||
std::vector<PartReference> mParts;
|
||||
|
||||
/// Load one part, assumes the subrecord name was already read
|
||||
void add(ESMReader &esm);
|
||||
|
||||
/// TODO: remove this method. The ESM format does not guarantee that all Part subrecords follow one another.
|
||||
void load(ESMReader &esm);
|
||||
void save(ESMWriter &esm) const;
|
||||
};
|
||||
|
|
|
@ -8,26 +8,54 @@ namespace ESM
|
|||
{
|
||||
unsigned int Book::sRecordId = REC_BOOK;
|
||||
|
||||
void Book::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "BKDT", 20);
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
mText = esm.getHNOString("TEXT");
|
||||
mEnchant = esm.getHNOString("ENAM");
|
||||
}
|
||||
void Book::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("BKDT", mData, 20);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
esm.writeHNOString("TEXT", mText);
|
||||
esm.writeHNOCString("ENAM", mEnchant);
|
||||
}
|
||||
void Book::load(ESMReader &esm)
|
||||
{
|
||||
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<'B','K','D','T'>::value:
|
||||
esm.getHT(mData, 20);
|
||||
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;
|
||||
case ESM::FourCC<'E','N','A','M'>::value:
|
||||
mEnchant = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'T','E','X','T'>::value:
|
||||
mText = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing BKDT subrecord");
|
||||
}
|
||||
void Book::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("BKDT", mData, 20);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
esm.writeHNOString("TEXT", mText);
|
||||
esm.writeHNOCString("ENAM", mEnchant);
|
||||
}
|
||||
|
||||
void Book::blank()
|
||||
{
|
||||
|
|
|
@ -10,17 +10,42 @@ namespace ESM
|
|||
|
||||
void Clothing::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "CTDT", 12);
|
||||
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
|
||||
mParts.load(esm);
|
||||
|
||||
|
||||
mEnchant = esm.getHNOString("ENAM");
|
||||
mParts.mParts.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<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'C','T','D','T'>::value:
|
||||
esm.getHT(mData, 12);
|
||||
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;
|
||||
case ESM::FourCC<'E','N','A','M'>::value:
|
||||
mEnchant = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'I','N','D','X'>::value:
|
||||
mParts.add(esm);
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing CTDT subrecord");
|
||||
}
|
||||
|
||||
void Clothing::save(ESMWriter &esm) const
|
||||
|
|
|
@ -7,14 +7,19 @@
|
|||
namespace ESM
|
||||
{
|
||||
|
||||
void InventoryList::add(ESMReader &esm)
|
||||
{
|
||||
ContItem ci;
|
||||
esm.getHT(ci, 36);
|
||||
mList.push_back(ci);
|
||||
}
|
||||
|
||||
void InventoryList::load(ESMReader &esm)
|
||||
{
|
||||
mList.clear();
|
||||
ContItem ci;
|
||||
while (esm.isNextSub("NPCO"))
|
||||
{
|
||||
esm.getHT(ci, 36);
|
||||
mList.push_back(ci);
|
||||
add(esm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@ struct InventoryList
|
|||
{
|
||||
std::vector<ContItem> mList;
|
||||
|
||||
/// 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;
|
||||
};
|
||||
|
|
|
@ -8,23 +8,43 @@ namespace ESM
|
|||
{
|
||||
unsigned int Door::sRecordId = REC_DOOR;
|
||||
|
||||
void Door::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mOpenSound = esm.getHNOString("SNAM");
|
||||
mCloseSound = esm.getHNOString("ANAM");
|
||||
}
|
||||
void Door::load(ESMReader &esm)
|
||||
{
|
||||
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;
|
||||
case ESM::FourCC<'S','N','A','M'>::value:
|
||||
mOpenSound = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'A','N','A','M'>::value:
|
||||
mCloseSound = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Door::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("SNAM", mOpenSound);
|
||||
esm.writeHNOCString("ANAM", mCloseSound);
|
||||
}
|
||||
void Door::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("SNAM", mOpenSound);
|
||||
esm.writeHNOCString("ANAM", mCloseSound);
|
||||
}
|
||||
|
||||
void Door::blank()
|
||||
{
|
||||
|
|
|
@ -191,33 +191,64 @@ namespace ESM
|
|||
|
||||
void MagicEffect::load(ESMReader &esm)
|
||||
{
|
||||
esm.getHNT(mIndex, "INDX");
|
||||
esm.getHNT(mIndex, "INDX");
|
||||
|
||||
mId = indexToId (mIndex);
|
||||
|
||||
esm.getHNT(mData, "MEDT", 36);
|
||||
if (esm.getFormat() == 0)
|
||||
{
|
||||
// don't allow mods to change fixed flags in the legacy format
|
||||
mData.mFlags &= (AllowSpellmaking | AllowEnchanting | NegativeLight);
|
||||
if (mIndex>=0 && mIndex<NumberOfHardcodedFlags)
|
||||
esm.getHNT(mData, "MEDT", 36);
|
||||
if (esm.getFormat() == 0)
|
||||
{
|
||||
// don't allow mods to change fixed flags in the legacy format
|
||||
mData.mFlags &= (AllowSpellmaking | AllowEnchanting | NegativeLight);
|
||||
if (mIndex>=0 && mIndex<NumberOfHardcodedFlags)
|
||||
mData.mFlags |= HardcodedFlags[mIndex];
|
||||
}
|
||||
}
|
||||
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
mParticle = esm.getHNOString("PTEX");
|
||||
|
||||
mBoltSound = esm.getHNOString("BSND");
|
||||
mCastSound = esm.getHNOString("CSND");
|
||||
mHitSound = esm.getHNOString("HSND");
|
||||
mAreaSound = esm.getHNOString("ASND");
|
||||
|
||||
mCasting = esm.getHNOString("CVFX");
|
||||
mBolt = esm.getHNOString("BVFX");
|
||||
mHit = esm.getHNOString("HVFX");
|
||||
mArea = esm.getHNOString("AVFX");
|
||||
|
||||
mDescription = esm.getHNOString("DESC");
|
||||
// vanilla MW accepts the _SND subrecords before or after DESC... I hope
|
||||
// this isn't true for other records, or we have to do a mass-refactor
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'I','T','E','X'>::value:
|
||||
mIcon = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'P','T','E','X'>::value:
|
||||
mParticle = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'B','S','N','D'>::value:
|
||||
mBoltSound = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'C','S','N','D'>::value:
|
||||
mCastSound = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'H','S','N','D'>::value:
|
||||
mHitSound = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'A','S','N','D'>::value:
|
||||
mAreaSound = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'C','V','F','X'>::value:
|
||||
mCasting = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'B','V','F','X'>::value:
|
||||
mBolt = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'H','V','F','X'>::value:
|
||||
mHit = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'A','V','F','X'>::value:
|
||||
mArea = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'D','E','S','C'>::value:
|
||||
mDescription = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord " + esm.retSubName().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
void MagicEffect::save(ESMWriter &esm) const
|
||||
{
|
||||
|
|
|
@ -8,22 +8,45 @@ namespace ESM
|
|||
{
|
||||
unsigned int Miscellaneous::sRecordId = REC_MISC;
|
||||
|
||||
void Miscellaneous::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "MCDT", 12);
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
}
|
||||
void Miscellaneous::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("MCDT", mData, 12);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
}
|
||||
void Miscellaneous::load(ESMReader &esm)
|
||||
{
|
||||
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<'M','C','D','T'>::value:
|
||||
esm.getHT(mData, 12);
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing MCDT subrecord");
|
||||
}
|
||||
|
||||
void Miscellaneous::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("MCDT", mData, 12);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
}
|
||||
|
||||
void Miscellaneous::blank()
|
||||
{
|
||||
|
|
|
@ -8,93 +8,137 @@ namespace ESM
|
|||
{
|
||||
unsigned int NPC::sRecordId = REC_NPC_;
|
||||
|
||||
void NPC::load(ESMReader &esm)
|
||||
{
|
||||
mPersistent = esm.getRecordFlags() & 0x0400;
|
||||
|
||||
mModel = esm.getHNOString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
|
||||
mRace = esm.getHNString("RNAM");
|
||||
mClass = esm.getHNString("CNAM");
|
||||
mFaction = esm.getHNString("ANAM");
|
||||
mHead = esm.getHNString("BNAM");
|
||||
mHair = esm.getHNString("KNAM");
|
||||
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
|
||||
esm.getSubNameIs("NPDT");
|
||||
esm.getSubHeader();
|
||||
if (esm.getSubSize() == 52)
|
||||
void NPC::load(ESMReader &esm)
|
||||
{
|
||||
mNpdtType = NPC_DEFAULT;
|
||||
esm.getExact(&mNpdt52, 52);
|
||||
}
|
||||
else if (esm.getSubSize() == 12)
|
||||
{
|
||||
mNpdtType = NPC_WITH_AUTOCALCULATED_STATS;
|
||||
esm.getExact(&mNpdt12, 12);
|
||||
}
|
||||
else
|
||||
esm.fail("NPC_NPDT must be 12 or 52 bytes long");
|
||||
mPersistent = esm.getRecordFlags() & 0x0400;
|
||||
|
||||
esm.getHNT(mFlags, "FLAG");
|
||||
mSpells.mList.clear();
|
||||
mInventory.mList.clear();
|
||||
mTransport.clear();
|
||||
mAiPackage.mList.clear();
|
||||
|
||||
mInventory.load(esm);
|
||||
mSpells.load(esm);
|
||||
|
||||
if (esm.isNextSub("AIDT"))
|
||||
{
|
||||
esm.getHExact(&mAiData, sizeof(mAiData));
|
||||
mHasAI= true;
|
||||
}
|
||||
else
|
||||
bool hasNpdt = false;
|
||||
bool hasFlags = false;
|
||||
mHasAI = false;
|
||||
|
||||
mTransport.clear();
|
||||
while (esm.isNextSub("DODT") || esm.isNextSub("DNAM")) {
|
||||
if (esm.retSubName() == 0x54444f44) { // DODT struct
|
||||
Dest dodt;
|
||||
esm.getHExact(&dodt.mPos, 24);
|
||||
mTransport.push_back(dodt);
|
||||
} else if (esm.retSubName() == 0x4d414e44) { // DNAM struct
|
||||
mTransport.back().mCellName = esm.getHString();
|
||||
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','N','A','M'>::value:
|
||||
mRace = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'C','N','A','M'>::value:
|
||||
mClass = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'A','N','A','M'>::value:
|
||||
mFaction = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'B','N','A','M'>::value:
|
||||
mHead = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'K','N','A','M'>::value:
|
||||
mHair = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'N','P','D','T'>::value:
|
||||
hasNpdt = true;
|
||||
esm.getSubHeader();
|
||||
if (esm.getSubSize() == 52)
|
||||
{
|
||||
mNpdtType = NPC_DEFAULT;
|
||||
esm.getExact(&mNpdt52, 52);
|
||||
}
|
||||
else if (esm.getSubSize() == 12)
|
||||
{
|
||||
mNpdtType = NPC_WITH_AUTOCALCULATED_STATS;
|
||||
esm.getExact(&mNpdt12, 12);
|
||||
}
|
||||
else
|
||||
esm.fail("NPC_NPDT must be 12 or 52 bytes long");
|
||||
break;
|
||||
case ESM::FourCC<'F','L','A','G'>::value:
|
||||
hasFlags = true;
|
||||
esm.getHT(mFlags);
|
||||
break;
|
||||
case ESM::FourCC<'N','P','C','S'>::value:
|
||||
mSpells.add(esm);
|
||||
break;
|
||||
case ESM::FourCC<'N','P','C','O'>::value:
|
||||
mInventory.add(esm);
|
||||
break;
|
||||
case ESM::FourCC<'A','I','D','T'>::value:
|
||||
esm.getHExact(&mAiData, sizeof(mAiData));
|
||||
mHasAI= true;
|
||||
break;
|
||||
case ESM::FourCC<'D','O','D','T'>::value:
|
||||
{
|
||||
Dest dodt;
|
||||
esm.getHExact(&dodt.mPos, 24);
|
||||
mTransport.push_back(dodt);
|
||||
break;
|
||||
}
|
||||
case ESM::FourCC<'D','N','A','M'>::value:
|
||||
mTransport.back().mCellName = esm.getHString();
|
||||
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 " + esm.retSubName().toString());
|
||||
}
|
||||
}
|
||||
if (!hasNpdt)
|
||||
esm.fail("Missing NPDT subrecord");
|
||||
if (!hasFlags)
|
||||
esm.fail("Missing FLAG subrecord");
|
||||
}
|
||||
mAiPackage.load(esm);
|
||||
}
|
||||
void NPC::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNOCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNCString("RNAM", mRace);
|
||||
esm.writeHNCString("CNAM", mClass);
|
||||
esm.writeHNCString("ANAM", mFaction);
|
||||
esm.writeHNCString("BNAM", mHead);
|
||||
esm.writeHNCString("KNAM", mHair);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
void NPC::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNOCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNCString("RNAM", mRace);
|
||||
esm.writeHNCString("CNAM", mClass);
|
||||
esm.writeHNCString("ANAM", mFaction);
|
||||
esm.writeHNCString("BNAM", mHead);
|
||||
esm.writeHNCString("KNAM", mHair);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
|
||||
if (mNpdtType == NPC_DEFAULT)
|
||||
esm.writeHNT("NPDT", mNpdt52, 52);
|
||||
else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS)
|
||||
esm.writeHNT("NPDT", mNpdt12, 12);
|
||||
if (mNpdtType == NPC_DEFAULT)
|
||||
esm.writeHNT("NPDT", mNpdt52, 52);
|
||||
else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS)
|
||||
esm.writeHNT("NPDT", mNpdt12, 12);
|
||||
|
||||
esm.writeHNT("FLAG", mFlags);
|
||||
esm.writeHNT("FLAG", mFlags);
|
||||
|
||||
mInventory.save(esm);
|
||||
mSpells.save(esm);
|
||||
if (mHasAI) {
|
||||
esm.writeHNT("AIDT", mAiData, sizeof(mAiData));
|
||||
mInventory.save(esm);
|
||||
mSpells.save(esm);
|
||||
if (mHasAI) {
|
||||
esm.writeHNT("AIDT", mAiData, sizeof(mAiData));
|
||||
}
|
||||
|
||||
typedef std::vector<Dest>::const_iterator DestIter;
|
||||
for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) {
|
||||
esm.writeHNT("DODT", it->mPos, sizeof(it->mPos));
|
||||
esm.writeHNOCString("DNAM", it->mCellName);
|
||||
}
|
||||
mAiPackage.save(esm);
|
||||
}
|
||||
|
||||
typedef std::vector<Dest>::const_iterator DestIter;
|
||||
for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) {
|
||||
esm.writeHNT("DODT", it->mPos, sizeof(it->mPos));
|
||||
esm.writeHNOCString("DNAM", it->mCellName);
|
||||
}
|
||||
mAiPackage.save(esm);
|
||||
}
|
||||
|
||||
bool NPC::isMale() const {
|
||||
return (mFlags & Female) == 0;
|
||||
}
|
||||
|
|
|
@ -20,10 +20,34 @@ namespace ESM
|
|||
|
||||
void Race::load(ESMReader &esm)
|
||||
{
|
||||
mName = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "RADT", 140);
|
||||
mPowers.load(esm);
|
||||
mDescription = esm.getHNOString("DESC");
|
||||
mPowers.mList.clear();
|
||||
|
||||
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','A','D','T'>::value:
|
||||
esm.getHT(mData, 140);
|
||||
hasData = true;
|
||||
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 " + esm.retSubName().toString());
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing RADT subrecord");
|
||||
}
|
||||
void Race::save(ESMWriter &esm) const
|
||||
{
|
||||
|
|
|
@ -10,9 +10,30 @@ namespace ESM
|
|||
|
||||
void Spell::load(ESMReader &esm)
|
||||
{
|
||||
mName = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "SPDT", 12);
|
||||
mEffects.load(esm);
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t val = esm.retSubName().val;
|
||||
|
||||
switch (val)
|
||||
{
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'S','P','D','T'>::value:
|
||||
esm.getHT(mData, 12);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'E','N','A','M'>::value:
|
||||
ENAMstruct s;
|
||||
esm.getHT(s, 24);
|
||||
mEffects.mList.push_back(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing SPDT subrecord");
|
||||
}
|
||||
|
||||
void Spell::save(ESMWriter &esm) const
|
||||
|
|
|
@ -8,24 +8,50 @@ namespace ESM
|
|||
{
|
||||
unsigned int Weapon::sRecordId = REC_WEAP;
|
||||
|
||||
void Weapon::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "WPDT", 32);
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
mEnchant = esm.getHNOString("ENAM");
|
||||
}
|
||||
void Weapon::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("WPDT", mData, 32);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
esm.writeHNOCString("ENAM", mEnchant);
|
||||
}
|
||||
void Weapon::load(ESMReader &esm)
|
||||
{
|
||||
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<'W','P','D','T'>::value:
|
||||
esm.getHT(mData, 32);
|
||||
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;
|
||||
case ESM::FourCC<'E','N','A','M'>::value:
|
||||
mEnchant = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing WPDT subrecord");
|
||||
}
|
||||
void Weapon::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("WPDT", mData, 32);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
esm.writeHNOCString("ENAM", mEnchant);
|
||||
}
|
||||
|
||||
void Weapon::blank()
|
||||
{
|
||||
|
|
|
@ -9,10 +9,15 @@ void SpellList::load(ESMReader &esm)
|
|||
{
|
||||
mList.clear();
|
||||
while (esm.isNextSub("NPCS")) {
|
||||
mList.push_back(esm.getHString());
|
||||
add(esm);
|
||||
}
|
||||
}
|
||||
|
||||
void SpellList::add(ESMReader &esm)
|
||||
{
|
||||
mList.push_back(esm.getHString());
|
||||
}
|
||||
|
||||
void SpellList::save(ESMWriter &esm) const
|
||||
{
|
||||
for (std::vector<std::string>::const_iterator it = mList.begin(); it != mList.end(); ++it) {
|
||||
|
|
|
@ -19,6 +19,11 @@ namespace ESM
|
|||
/// Is this spell ID in mList?
|
||||
bool exists(const std::string& spell) const;
|
||||
|
||||
/// 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…
Reference in a new issue