#include "creaturestats.hpp" #include #include #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" namespace MWMechanics { int CreatureStats::sActorId = 0; CreatureStats::CreatureStats() : mLevel (0), mDead (false), mDied (false), mMurdered(false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), mAttacked (false), mAttackingOrSpell(false), mIsWerewolf(false), mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mDeathAnimation(0) { for (int i=0; i<4; ++i) mAiSettings[i] = 0; } const AiSequence& CreatureStats::getAiSequence() const { return mAiSequence; } AiSequence& CreatureStats::getAiSequence() { return mAiSequence; } float CreatureStats::getFatigueTerm() const { int max = getFatigue().getModified(); int current = getFatigue().getCurrent(); float normalised = max==0 ? 1 : std::max (0.0f, static_cast (current)/max); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); return gmst.find ("fFatigueBase")->getFloat() - gmst.find ("fFatigueMult")->getFloat() * (1-normalised); } const AttributeValue &CreatureStats::getAttribute(int index) const { if (index < 0 || index > 7) { throw std::runtime_error("attribute index is out of range"); } return (!mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]); } const DynamicStat &CreatureStats::getHealth() const { return mDynamic[0]; } const DynamicStat &CreatureStats::getMagicka() const { return mDynamic[1]; } const DynamicStat &CreatureStats::getFatigue() const { return mDynamic[2]; } const Spells &CreatureStats::getSpells() const { return mSpells; } const ActiveSpells &CreatureStats::getActiveSpells() const { return mActiveSpells; } const MagicEffects &CreatureStats::getMagicEffects() const { return mMagicEffects; } bool CreatureStats::getAttackingOrSpell() const { return mAttackingOrSpell; } int CreatureStats::getLevel() const { return mLevel; } Stat CreatureStats::getAiSetting (AiSetting index) const { return mAiSettings[index]; } const DynamicStat &CreatureStats::getDynamic(int index) const { if (index < 0 || index > 2) { throw std::runtime_error("dynamic stat index is out of range"); } return mDynamic[index]; } Spells &CreatureStats::getSpells() { return mSpells; } void CreatureStats::setSpells(const Spells &spells) { mSpells = spells; } ActiveSpells &CreatureStats::getActiveSpells() { return mActiveSpells; } MagicEffects &CreatureStats::getMagicEffects() { return mMagicEffects; } void CreatureStats::setAttribute(int index, int base) { AttributeValue current = getAttribute(index); current.setBase(base); setAttribute(index, current); } void CreatureStats::setAttribute(int index, const AttributeValue &value) { if (index < 0 || index > 7) { throw std::runtime_error("attribute index is out of range"); } const AttributeValue& currentValue = !mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]; if (value != currentValue) { if (index != ESM::Attribute::Luck && index != ESM::Attribute::Personality && index != ESM::Attribute::Speed) mRecalcDynamicStats = true; } if(!mIsWerewolf) mAttributes[index] = value; else mWerewolfAttributes[index] = value; } void CreatureStats::setHealth(const DynamicStat &value) { setDynamic (0, value); } void CreatureStats::setMagicka(const DynamicStat &value) { setDynamic (1, value); } void CreatureStats::setFatigue(const DynamicStat &value) { setDynamic (2, value); } void CreatureStats::setDynamic (int index, const DynamicStat &value) { if (index < 0 || index > 2) throw std::runtime_error("dynamic stat index is out of range"); mDynamic[index] = value; if (index==0 && mDynamic[index].getCurrent()<1) { if (!mDead) mDied = true; mDead = true; if (mDied) // Must increase death count immediately. There are scripts that use getDeadCount as reaction to onDeath // and rely on the increased value. // Would be more appropriate to use a killActor(actor) function, but we don't have access to the Ptr in CreatureStats. MWBase::Environment::get().getMechanicsManager()->killDeadActors(); } } void CreatureStats::setLevel(int level) { mLevel = level; } void CreatureStats::setActiveSpells(const ActiveSpells &active) { mActiveSpells = active; } void CreatureStats::modifyMagicEffects(const MagicEffects &effects) { if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).getModifier() != mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).getModifier()) mRecalcDynamicStats = true; mMagicEffects.setModifiers(effects); } void CreatureStats::setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; } void CreatureStats::setAiSetting (AiSetting index, Stat value) { mAiSettings[index] = value; } void CreatureStats::setAiSetting (AiSetting index, int base) { Stat stat = getAiSetting(index); stat.setBase(base); setAiSetting(index, stat); } bool CreatureStats::isDead() const { return mDead; } bool CreatureStats::hasDied() const { return mDied; } void CreatureStats::clearHasDied() { mDied = false; } bool CreatureStats::hasBeenMurdered() const { return mMurdered; } void CreatureStats::notifyMurder() { mMurdered = true; } void CreatureStats::clearHasBeenMurdered() { mMurdered = false; } void CreatureStats::resurrect() { if (mDead) { if (mDynamic[0].getCurrent()<1) { mDynamic[0].setModified(mDynamic[0].getModified(), 1); mDynamic[0].setCurrent(1); } if (mDynamic[0].getCurrent()>=1) mDead = false; } } bool CreatureStats::hasCommonDisease() const { return mSpells.hasCommonDisease(); } bool CreatureStats::hasBlightDisease() const { return mSpells.hasBlightDisease(); } int CreatureStats::getFriendlyHits() const { return mFriendlyHits; } void CreatureStats::friendlyHit() { ++mFriendlyHits; } bool CreatureStats::hasTalkedToPlayer() const { return mTalkedTo; } void CreatureStats::talkedToPlayer() { mTalkedTo = true; } bool CreatureStats::isAlarmed() const { return mAlarmed; } void CreatureStats::setAlarmed (bool alarmed) { mAlarmed = alarmed; } bool CreatureStats::getAttacked() const { return mAttacked; } void CreatureStats::setAttacked (bool attacked) { mAttacked = attacked; } bool CreatureStats::getCreatureTargetted() const { MWWorld::Ptr targetPtr; if (mAiSequence.getCombatTarget(targetPtr)) { return targetPtr.getTypeName() == typeid(ESM::Creature).name(); } return false; } float CreatureStats::getEvasion() const { float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); evasion *= getFatigueTerm(); evasion += mMagicEffects.get(ESM::MagicEffect::Sanctuary).getMagnitude(); return evasion; } void CreatureStats::setLastHitObject(const std::string& objectid) { mLastHitObject = objectid; } const std::string &CreatureStats::getLastHitObject() const { return mLastHitObject; } void CreatureStats::addToFallHeight(float height) { mFallHeight += height; } float CreatureStats::land() { float height = mFallHeight; mFallHeight = 0; return height; } bool CreatureStats::needToRecalcDynamicStats() { if (mRecalcDynamicStats) { mRecalcDynamicStats = false; return true; } return false; } void CreatureStats::setKnockedDown(bool value) { mKnockdown = value; if(!value) //Resets the "OverOneFrame" flag setKnockedDownOverOneFrame(false); } bool CreatureStats::getKnockedDown() const { return mKnockdown; } void CreatureStats::setKnockedDownOneFrame(bool value) { mKnockdownOneFrame = value; } bool CreatureStats::getKnockedDownOneFrame() const { return mKnockdownOneFrame; } void CreatureStats::setKnockedDownOverOneFrame(bool value) { mKnockdownOverOneFrame = value; } bool CreatureStats::getKnockedDownOverOneFrame() const { return mKnockdownOverOneFrame; } void CreatureStats::setHitRecovery(bool value) { mHitRecovery = value; } bool CreatureStats::getHitRecovery() const { return mHitRecovery; } void CreatureStats::setBlock(bool value) { mBlock = value; } bool CreatureStats::getBlock() const { return mBlock; } bool CreatureStats::getMovementFlag (Flag flag) const { return mMovementFlags & flag; } void CreatureStats::setMovementFlag (Flag flag, bool state) { if (state) mMovementFlags |= flag; else mMovementFlags &= ~flag; } bool CreatureStats::getStance(Stance flag) const { switch (flag) { case Stance_Run: return getMovementFlag (Flag_Run) || getMovementFlag (Flag_ForceRun); case Stance_Sneak: return getMovementFlag (Flag_Sneak) || getMovementFlag (Flag_ForceSneak); default: return false; } } DrawState_ CreatureStats::getDrawState() const { return mDrawState; } void CreatureStats::setDrawState(DrawState_ state) { mDrawState = state; } float CreatureStats::getAttackStrength() const { return mAttackStrength; } void CreatureStats::setAttackStrength(float value) { mAttackStrength = value; } void CreatureStats::writeState (ESM::CreatureStats& state) const { for (int i=0; i& CreatureStats::getSummonedCreatureMap() { return mSummonedCreatures; } std::vector& CreatureStats::getSummonedCreatureGraveyard() { return mSummonGraveyard; } }