Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
10 kB · 337 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338#include "creaturestats.hpp"#include "esmreader.hpp"#include "esmwriter.hpp"
#include <components/esm3/loadmgef.hpp>
#include <limits>
namespace ESM{
void CreatureStats::load(ESMReader& esm) { if (esm.getFormatVersion() <= MaxFixedStatsFormatVersion) { const bool intFallback = esm.getFormatVersion() <= MaxIntFallbackFormatVersion; for (int i = 0; i < ESM::Attribute::Length; ++i) { StatState<float> stat; stat.load(esm, intFallback); mAttributes.emplace(ESM::Attribute::indexToRefId(i), std::move(stat)); } } else { while (esm.isNextSub("ATTR")) { ESM::RefId attribute = esm.getRefId(); mAttributes[attribute].load(esm); } }
for (auto& dynamic : mDynamic) dynamic.load(esm);
mGoldPool = 0; esm.getHNOT(mGoldPool, "GOLD");
mTradeTime.mDay = 0; mTradeTime.mHour = 0; if (esm.peekNextSub("TIME")) mTradeTime.load(esm);
int32_t flags = 0; mDead = false; mDeathAnimationFinished = false; mDied = false; mMurdered = false; mTalkedTo = false; mAlarmed = false; mAttacked = false; mKnockdown = false; mKnockdownOneFrame = false; mKnockdownOverOneFrame = false; mHitRecovery = false; mBlock = false; mRecalcDynamicStats = false; if (esm.getFormatVersion() <= MaxUnoptimizedCharacterDataFormatVersion) { esm.getHNOT(mDead, "DEAD"); esm.getHNOT(mDeathAnimationFinished, "DFNT"); esm.getHNOT(mDied, "DIED"); esm.getHNOT(mMurdered, "MURD"); esm.getHNOT(mTalkedTo, "TALK"); esm.getHNOT(mAlarmed, "ALRM"); esm.getHNOT(mAttacked, "ATKD"); esm.getHNOT(mKnockdown, "KNCK"); esm.getHNOT(mKnockdownOneFrame, "KNC1"); esm.getHNOT(mKnockdownOverOneFrame, "KNCO"); esm.getHNOT(mHitRecovery, "HITR"); esm.getHNOT(mBlock, "BLCK"); } else { esm.getHNOT(flags, "AFLG"); mDead = flags & Dead; mDeathAnimationFinished = flags & DeathAnimationFinished; mDied = flags & Died; mMurdered = flags & Murdered; mTalkedTo = flags & TalkedTo; mAlarmed = flags & Alarmed; mAttacked = flags & Attacked; mKnockdown = flags & Knockdown; mKnockdownOneFrame = flags & KnockdownOneFrame; mKnockdownOverOneFrame = flags & KnockdownOverOneFrame; mHitRecovery = flags & HitRecovery; mBlock = flags & Block; mRecalcDynamicStats = flags & RecalcDynamicStats; }
mMovementFlags = 0; esm.getHNOT(mMovementFlags, "MOVE");
mFallHeight = 0; esm.getHNOT(mFallHeight, "FALL");
mLastHitObject = esm.getHNORefId("LHIT");
mLastHitAttemptObject = esm.getHNORefId("LHAT");
if (esm.getFormatVersion() <= MaxUnoptimizedCharacterDataFormatVersion) esm.getHNOT(mRecalcDynamicStats, "CALC");
mDrawState = 0; esm.getHNOT(mDrawState, "DRAW");
mLevel = 1; esm.getHNOT(mLevel, "LEVL");
mActorId = -1; esm.getHNOT(mActorId, "ACID");
mDeathAnimation = -1; esm.getHNOT(mDeathAnimation, "DANM");
mTimeOfDeath.mDay = 0; mTimeOfDeath.mHour = 0; if (esm.peekNextSub("DTIM")) mTimeOfDeath.load(esm, "DTIM");
mSpells.load(esm); mActiveSpells.load(esm); mAiSequence.load(esm); mMagicEffects.load(esm);
if (esm.getFormatVersion() <= MaxClearModifiersFormatVersion) { while (esm.isNextSub("SUMM")) { int32_t magicEffect; esm.getHT(magicEffect); ESM::RefId source = esm.getHNORefId("SOUR"); int32_t effectIndex = -1; esm.getHNOT(effectIndex, "EIND"); int32_t actorId; esm.getHNT(actorId, "ACID"); mSummonedCreatureMap[SummonKey(ESM::MagicEffect::indexToRefId(magicEffect), source, effectIndex)] = actorId; mSummonedCreatures.emplace(ESM::MagicEffect::indexToRefId(magicEffect), RefNum{ .mIndex = static_cast<uint32_t>(actorId), .mContentFile = -1 }); } } else { while (esm.isNextSub("SUMM")) { RefId effectId; if (esm.getFormatVersion() <= MaxSerializeEffectRefIdFormatVersion) { int32_t magicEffect; esm.getHT(magicEffect); effectId = ESM::MagicEffect::indexToRefId(magicEffect); } else effectId = esm.getRefId(); RefNum actor; if (esm.getFormatVersion() <= MaxActorIdSaveGameFormatVersion) esm.getHNT(actor.mIndex, "ACID"); else actor = esm.getFormId(true, "ACID"); mSummonedCreatures.emplace(effectId, actor); } }
while (esm.isNextSub("GRAV")) { int32_t actorId; esm.getHT(actorId); mSummonGraveyard.push_back(actorId); }
mHasAiSettings = false; esm.getHNOT(mHasAiSettings, "AISE");
if (mHasAiSettings) { for (auto& setting : mAiSettings) setting.load(esm); }
while (esm.isNextSub("CORP")) { ESM::RefId id = esm.getRefId();
CorprusStats stats; esm.getHNT(stats.mWorsenings, "WORS"); stats.mNextWorsening.load(esm);
mCorprusSpells[id] = stats; } if (esm.getFormatVersion() <= MaxOldSkillsAndAttributesFormatVersion) mMissingACDT = mGoldPool == std::numeric_limits<int>::min(); else { mMissingACDT = false; esm.getHNOT(mMissingACDT, "NOAC"); } }
void CreatureStats::save(ESMWriter& esm) const { if (esm.getFormatVersion() <= MaxFixedStatsFormatVersion) { // This branch is only used in tests. It probably shouldn't exist. for (int i = 0; i < ESM::Attribute::Length; ++i) { const auto it = mAttributes.find(ESM::Attribute::indexToRefId(i)); if (it != mAttributes.end()) it->second.save(esm); else StatState<float>{}.save(esm); } } else { for (const auto& [attribute, value] : mAttributes) { esm.writeHNRefId("ATTR", attribute); value.save(esm); } }
for (const auto& dynamic : mDynamic) dynamic.save(esm);
if (mGoldPool) esm.writeHNT("GOLD", mGoldPool);
if (mTradeTime.mDay != 0 || mTradeTime.mHour != 0) esm.writeHNT("TIME", mTradeTime);
int32_t flags = 0; if (mDead) flags |= Dead; if (mDeathAnimationFinished) flags |= DeathAnimationFinished; if (mDied) flags |= Died; if (mMurdered) flags |= Murdered; if (mTalkedTo) flags |= TalkedTo; if (mAlarmed) flags |= Alarmed; if (mAttacked) flags |= Attacked; if (mKnockdown) flags |= Knockdown; if (mKnockdownOneFrame) flags |= KnockdownOneFrame; if (mKnockdownOverOneFrame) flags |= KnockdownOverOneFrame; if (mHitRecovery) flags |= HitRecovery; if (mBlock) flags |= Block; if (mRecalcDynamicStats) flags |= RecalcDynamicStats;
if (flags) esm.writeHNT("AFLG", flags);
if (mMovementFlags) esm.writeHNT("MOVE", mMovementFlags);
if (mFallHeight) esm.writeHNT("FALL", mFallHeight);
if (!mLastHitObject.empty()) esm.writeHNRefId("LHIT", mLastHitObject);
if (!mLastHitAttemptObject.empty()) esm.writeHNRefId("LHAT", mLastHitAttemptObject);
if (mDrawState) esm.writeHNT("DRAW", mDrawState);
if (mLevel != 1) esm.writeHNT("LEVL", mLevel);
if (mDeathAnimation != -1) esm.writeHNT("DANM", mDeathAnimation);
if (mTimeOfDeath.mHour != 0 || mTimeOfDeath.mDay != 0) esm.writeHNT("DTIM", mTimeOfDeath);
mSpells.save(esm); mActiveSpells.save(esm); mAiSequence.save(esm); mMagicEffects.save(esm);
for (const auto& [effectId, actor] : mSummonedCreatures) { esm.writeHNRefId("SUMM", effectId); esm.writeFormId(actor, true, "ACID"); }
esm.writeHNT("AISE", mHasAiSettings); if (mHasAiSettings) { for (const auto& setting : mAiSettings) setting.save(esm); } if (mMissingACDT) esm.writeHNT("NOAC", mMissingACDT); }
void CreatureStats::blank() { mTradeTime.mHour = 0; mTradeTime.mDay = 0; mGoldPool = 0; mActorId = -1; mHasAiSettings = false; mDead = false; mDeathAnimationFinished = false; mDied = false; mMurdered = false; mTalkedTo = false; mAlarmed = false; mAttacked = false; mKnockdown = false; mKnockdownOneFrame = false; mKnockdownOverOneFrame = false; mHitRecovery = false; mBlock = false; mMovementFlags = 0; mFallHeight = 0.f; mRecalcDynamicStats = false; mDrawState = 0; mDeathAnimation = -1; mLevel = 1; mCorprusSpells.clear(); mMissingACDT = false; }
}