#include "creaturestats.hpp" #include #include #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() : mDrawState (DrawState_Nothing), mDead (false), mDeathAnimationFinished(false), mDied (false), mMurdered(false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), mAttacked (false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mHitAttemptActorId(-1), mDeathAnimation(-1), mTimeOfDeath(), mLevel (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 { float max = getFatigue().getModified(); float current = getFatigue().getCurrent(); float normalised = floor(max) == 0 ? 1 : std::max (0.0f, current / max); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); static const float fFatigueBase = gmst.find("fFatigueBase")->getFloat(); static const float fFatigueMult = gmst.find("fFatigueMult")->getFloat(); return fFatigueBase - fFatigueMult * (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 mAttributes[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; } 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; } 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 = mAttributes[index]; if (value != currentValue) { mAttributes[index] = value; if (index == ESM::Attribute::Intelligence) mRecalcMagicka = true; else if (index == ESM::Attribute::Strength || index == ESM::Attribute::Willpower || index == ESM::Attribute::Agility || index == ESM::Attribute::Endurance) { int strength = getAttribute(ESM::Attribute::Strength).getModified(); int willpower = getAttribute(ESM::Attribute::Willpower).getModified(); int agility = getAttribute(ESM::Attribute::Agility).getModified(); int endurance = getAttribute(ESM::Attribute::Endurance).getModified(); DynamicStat fatigue = getFatigue(); float diff = (strength+willpower+agility+endurance) - fatigue.getBase(); float currentToBaseRatio = (fatigue.getCurrent() / fatigue.getBase()); fatigue.setModified(fatigue.getModified() + diff, 0); fatigue.setCurrent(fatigue.getBase() * currentToBaseRatio); setFatigue(fatigue); } } } 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) mTimeOfDeath = MWBase::Environment::get().getWorld()->getTimeStamp(); mDead = true; mDynamic[index].setModifier(0); mDynamic[index].setCurrent(0); if (MWBase::Environment::get().getWorld()->getGodModeState()) MWBase::Environment::get().getMechanicsManager()->keepPlayerAlive(); } } void CreatureStats::setLevel(int level) { mLevel = level; } void CreatureStats::modifyMagicEffects(const MagicEffects &effects) { if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).getModifier() != mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).getModifier()) mRecalcMagicka = true; mMagicEffects.setModifiers(effects); } 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::isParalyzed() const { return mMagicEffects.get(ESM::MagicEffect::Paralyze).getMagnitude() > 0; } bool CreatureStats::isDead() const { return mDead; } bool CreatureStats::isDeathAnimationFinished() const { return mDeathAnimationFinished; } void CreatureStats::setDeathAnimationFinished(bool finished) { mDeathAnimationFinished = finished; } void CreatureStats::notifyDied() { mDied = true; } 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].getModified() < 1) mDynamic[0].setModified(1, 0); mDynamic[0].setCurrent(mDynamic[0].getModified()); mDead = false; mDeathAnimationFinished = 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; } float CreatureStats::getEvasion() const { float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); evasion *= getFatigueTerm(); evasion += std::min(100.f, 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::setLastHitAttemptObject(const std::string& objectid) { mLastHitAttemptObject = objectid; } const std::string &CreatureStats::getLastHitAttemptObject() const { return mLastHitAttemptObject; } void CreatureStats::setHitAttemptActorId(int actorId) { mHitAttemptActorId = actorId; } int CreatureStats::getHitAttemptActorId() const { return mHitAttemptActorId; } void CreatureStats::addToFallHeight(float height) { mFallHeight += height; } float CreatureStats::land() { float height = mFallHeight; mFallHeight = 0; return height; } bool CreatureStats::needToRecalcDynamicStats() { if (mRecalcMagicka) { mRecalcMagicka = false; return true; } return false; } void CreatureStats::setNeedRecalcDynamicStats(bool val) { mRecalcMagicka = val; } 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) != 0; } 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; } void CreatureStats::writeState (ESM::CreatureStats& state) const { for (int i=0; i& CreatureStats::getSummonedCreatureMap() { return mSummonedCreatures; } std::vector& CreatureStats::getSummonedCreatureGraveyard() { return mSummonGraveyard; } }