mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
299 lines
8.4 KiB
C++
299 lines
8.4 KiB
C++
#include "creaturestats.hpp"
|
|
#include "esmreader.hpp"
|
|
#include "esmwriter.hpp"
|
|
|
|
#include <limits>
|
|
|
|
namespace ESM
|
|
{
|
|
|
|
void CreatureStats::load(ESMReader& esm)
|
|
{
|
|
const bool intFallback = esm.getFormatVersion() <= MaxIntFallbackFormatVersion;
|
|
for (auto& attribute : mAttributes)
|
|
attribute.load(esm, intFallback);
|
|
|
|
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(magicEffect, source, effectIndex)] = actorId;
|
|
mSummonedCreatures.emplace(magicEffect, actorId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (esm.isNextSub("SUMM"))
|
|
{
|
|
int32_t magicEffect;
|
|
esm.getHT(magicEffect);
|
|
int32_t actorId;
|
|
esm.getHNT(actorId, "ACID");
|
|
mSummonedCreatures.emplace(magicEffect, actorId);
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
for (const auto& attribute : mAttributes)
|
|
attribute.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 (mActorId != -1)
|
|
esm.writeHNT("ACID", mActorId);
|
|
|
|
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, actorId] : mSummonedCreatures)
|
|
{
|
|
esm.writeHNT("SUMM", effectId);
|
|
esm.writeHNT("ACID", actorId);
|
|
}
|
|
|
|
for (int32_t key : mSummonGraveyard)
|
|
{
|
|
esm.writeHNT("GRAV", key);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
}
|