Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
9.3 kB · 289 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290#include "loadcrea.hpp"
#include <array>
#include <components/debug/debuglog.hpp>#include <components/misc/concepts.hpp>
#include "esmreader.hpp"#include "esmwriter.hpp"
namespace ESM{ namespace { struct EsmNPDTstruct { int32_t mType; int32_t mLevel; std::array<int32_t, Attribute::Length> mAttributes; int32_t mHealth, mMana, mFatigue; int32_t mSoul; int32_t mCombat, mMagic, mStealth; int32_t mAttack[6]; int32_t mGold; };
void toBinary(const Creature::NPDTstruct& src, EsmNPDTstruct& dst) { dst.mType = src.mType; dst.mLevel = src.mLevel; for (int i = 0; i < ESM::Attribute::Length; ++i) { const ESM::RefId id = ESM::Attribute::indexToRefId(i); dst.mAttributes[i] = src.getAttribute(id); } dst.mHealth = src.mHealth; dst.mMana = src.mMana; dst.mFatigue = src.mFatigue; dst.mSoul = src.mSoul; dst.mCombat = src.mCombat; dst.mMagic = src.mMagic; dst.mStealth = src.mStealth; for (std::size_t i = 0; i < std::size(dst.mAttack); ++i) dst.mAttack[i] = src.mAttack[i]; dst.mGold = src.mGold; }
void fromBinary(const EsmNPDTstruct& src, Creature::NPDTstruct& dst) { dst.mType = src.mType; dst.mLevel = src.mLevel; dst.mAttributes.clear(); for (int i = 0; i < ESM::Attribute::Length; ++i) { const ESM::RefId id = ESM::Attribute::indexToRefId(i); dst.mAttributes.emplace(id, src.mAttributes[i]); } dst.mHealth = src.mHealth; dst.mMana = src.mMana; dst.mFatigue = src.mFatigue; dst.mSoul = src.mSoul; dst.mCombat = src.mCombat; dst.mMagic = src.mMagic; dst.mStealth = src.mStealth; for (std::size_t i = 0; i < std::size(dst.mAttack); ++i) dst.mAttack[i] = src.mAttack[i]; dst.mGold = src.mGold; } }
template <Misc::SameAsWithoutCvref<EsmNPDTstruct> T> void decompose(T&& v, const auto& f) { f(v.mType, v.mLevel, v.mAttributes, v.mHealth, v.mMana, v.mFatigue, v.mSoul, v.mCombat, v.mMagic, v.mStealth, v.mAttack, v.mGold); }
template <Misc::SameAsWithoutCvref<Creature::NPDTstruct> T> void decompose(T&& v, const auto& f) { f(v.mType, v.mLevel, v.mHealth, v.mMana, v.mFatigue, v.mSoul, v.mCombat, v.mMagic, v.mStealth, v.mAttack, v.mGold); }
void Creature::load(ESMReader& esm, bool& isDeleted) { isDeleted = false; mRecordFlags = esm.getRecordFlags();
mAiPackage.mList.clear(); mInventory.mList.clear(); mSpells.mList.clear(); mTransport.mList.clear();
mScale = 1.f; mAiData.blank(); mAiData.mFight = 90; mAiData.mFlee = 20;
bool hasName = false; bool hasNpdt = false; bool hasFlags = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().toInt()) { case SREC_NAME: mId = esm.getRefId(); hasName = true; break; case fourCC("MODL"): mModel = esm.getHString(); break; case fourCC("CNAM"): mOriginal = esm.getRefId(); break; case fourCC("FNAM"): mName = esm.getHString(); break; case fourCC("SCRI"): mScript = esm.getRefId(); break; case fourCC("NPDT"): { if (esm.getFormatVersion() <= MaxFixedStatsFormatVersion) { EsmNPDTstruct data; esm.getSubComposite(data); fromBinary(data, mData); } else { esm.getSubComposite(mData); while (esm.isNextSub("ATTR")) { esm.getSubHeader(); int32_t value; esm.getT(value); ESM::RefId attribute = esm.getRefId(esm.getSubSize() - sizeof(value)); mData.mAttributes.emplace(attribute, value); } } hasNpdt = true; break; } case fourCC("FLAG"): int flags; esm.getHT(flags); mFlags = flags & 0xFF; mBloodType = ((flags >> 8) & 0xFF) >> 2; hasFlags = true; break; case fourCC("XSCL"): esm.getHT(mScale); break; case fourCC("NPCO"): mInventory.add(esm); break; case fourCC("NPCS"): mSpells.add(esm); break; case fourCC("AIDT"): esm.getSubComposite(mAiData); break; case fourCC("DODT"): case fourCC("DNAM"): mTransport.add(esm); break; case AI_Wander: case AI_Activate: case AI_Escort: case AI_Follow: case AI_Travel: case AI_CNDT: mAiPackage.add(esm); break; case SREC_DELE: esm.skipHSub(); isDeleted = true; break; case fourCC("INDX"): // seems to occur only in .ESS files, unsure of purpose int index; esm.getHT(index); Log(Debug::Warning) << "Creature::load: Unhandled INDX " << index; break; default: esm.fail("Unknown subrecord"); break; } }
if (!hasName) esm.fail("Missing NAME subrecord"); if (!hasNpdt && !isDeleted) esm.fail("Missing NPDT subrecord"); if (!hasFlags && !isDeleted) esm.fail("Missing FLAG subrecord"); }
void Creature::save(ESMWriter& esm, bool isDeleted) const { esm.writeHNCRefId("NAME", mId);
if (isDeleted) { esm.writeHNString("DELE", "", 3); return; }
esm.writeHNCString("MODL", mModel.getOriginal()); esm.writeHNOCRefId("CNAM", mOriginal); esm.writeHNOCString("FNAM", mName); esm.writeHNOCRefId("SCRI", mScript); if (esm.getFormatVersion() <= MaxFixedStatsFormatVersion) { EsmNPDTstruct data; toBinary(mData, data); esm.writeNamedComposite("NPDT", data); } else { esm.writeNamedComposite("NPDT", mData); for (const auto& [attribute, value] : mData.mAttributes) { if (!attribute.empty() && value != 0) { esm.startSubRecord("ATTR"); esm.writeT(value); esm.writeHRefId(attribute); esm.endRecord("ATTR"); } } } esm.writeHNT("FLAG", ((mBloodType << 10) + mFlags)); if (mScale != 1.0) { esm.writeHNT("XSCL", mScale); }
mInventory.save(esm); mSpells.save(esm); esm.writeNamedComposite("AIDT", mAiData); mTransport.save(esm); mAiPackage.save(esm); }
void Creature::blank() { mRecordFlags = 0; mData.mType = 0; mData.mLevel = 0; mData.mAttributes.clear(); mData.mHealth = mData.mMana = mData.mFatigue = 0; mData.mSoul = 0; mData.mCombat = mData.mMagic = mData.mStealth = 0; for (int i = 0; i < 6; ++i) mData.mAttack[i] = 0; mData.mGold = 0; mBloodType = 0; mFlags = 0; mScale = 1.f; mModel.clear(); mName.clear(); mScript = ESM::RefId(); mOriginal = ESM::RefId(); mInventory.mList.clear(); mSpells.mList.clear(); mAiData.blank(); mAiData.mFight = 90; mAiData.mFlee = 20; mAiPackage.mList.clear(); mTransport.mList.clear(); }
const std::vector<Transport::Dest>& Creature::getTransport() const { return mTransport.mList; }
int32_t Creature::NPDTstruct::getAttribute(ESM::RefId id) const { const auto it = mAttributes.find(id); if (it != mAttributes.end()) return it->second; return 0; }}