#ifndef GAME_MWMECHANICS_CREATURESTATS_H #define GAME_MWMECHANICS_CREATURESTATS_H #include #include #include #include "stat.hpp" #include "magiceffects.hpp" #include "spells.hpp" #include "activespells.hpp" #include "aisequence.hpp" #include "drawstate.hpp" #include #include namespace ESM { struct CreatureStats; } namespace MWMechanics { struct CorprusStats { static constexpr int sWorseningPeriod = 24; int mWorsenings[ESM::Attribute::Length]; MWWorld::TimeStamp mNextWorsening; }; /// \brief Common creature stats /// /// class CreatureStats { static int sActorId; DrawState_ mDrawState; AttributeValue mAttributes[ESM::Attribute::Length]; DynamicStat mDynamic[3]; // health, magicka, fatigue Spells mSpells; ActiveSpells mActiveSpells; MagicEffects mMagicEffects; Stat mAiSettings[4]; AiSequence mAiSequence; bool mDead; bool mDeathAnimationFinished; bool mDied; // flag for OnDeath script function bool mMurdered; int mFriendlyHits; bool mTalkedTo; bool mAlarmed; bool mAttacked; bool mKnockdown; bool mKnockdownOneFrame; bool mKnockdownOverOneFrame; bool mHitRecovery; bool mBlock; unsigned int mMovementFlags; float mFallHeight; std::string mLastHitObject; // The last object to hit this actor std::string mLastHitAttemptObject; // The last object to attempt to hit this actor bool mRecalcMagicka; // For merchants: the last time items were restocked and gold pool refilled. MWWorld::TimeStamp mLastRestock; // The pool of merchant gold (not in inventory) int mGoldPool; int mActorId; int mHitAttemptActorId; // Stores an actor that attacked this actor. Only one is stored at a time, // and it is not changed if a different actor attacks. It is cleared when combat ends. // The index of the death animation that was played, or -1 if none played signed char mDeathAnimation; MWWorld::TimeStamp mTimeOfDeath; // The difference between view direction and lower body direction. float mSideMovementAngle; private: std::map mSummonedCreatures; // // Contains ActorIds of summoned creatures with an expired lifetime that have not been deleted yet. // This may be necessary when the creature is in an inactive cell. std::vector mSummonGraveyard; std::map mCorprusSpells; protected: int mLevel; public: CreatureStats(); DrawState_ getDrawState() const; void setDrawState(DrawState_ state); bool needToRecalcDynamicStats(); void setNeedRecalcDynamicStats(bool val); float getFallHeight() const; void addToFallHeight(float height); /// Reset the fall height /// @return total fall height float land(bool isPlayer=false); const AttributeValue & getAttribute(int index) const; const DynamicStat & getHealth() const; const DynamicStat & getMagicka() const; const DynamicStat & getFatigue() const; const DynamicStat & getDynamic (int index) const; const Spells & getSpells() const; const ActiveSpells & getActiveSpells() const; const MagicEffects & getMagicEffects() const; bool getAttackingOrSpell() const; int getLevel() const; Spells & getSpells(); ActiveSpells & getActiveSpells(); MagicEffects & getMagicEffects(); void setAttribute(int index, const AttributeValue &value); // Shortcut to set only the base void setAttribute(int index, float base); void setHealth(const DynamicStat &value); void setMagicka(const DynamicStat &value); void setFatigue(const DynamicStat &value); void setDynamic (int index, const DynamicStat &value); /// Set Modifier for each magic effect according to \a effects. Does not touch Base values. void modifyMagicEffects(const MagicEffects &effects); void setAttackingOrSpell(bool attackingOrSpell); void setLevel(int level); enum AiSetting { AI_Hello = 0, AI_Fight = 1, AI_Flee = 2, AI_Alarm = 3 }; void setAiSetting (AiSetting index, Stat value); void setAiSetting (AiSetting index, int base); Stat getAiSetting (AiSetting index) const; const AiSequence& getAiSequence() const; AiSequence& getAiSequence(); float getFatigueTerm() const; ///< Return effective fatigue bool isParalyzed() const; bool isDead() const; bool isDeathAnimationFinished() const; void setDeathAnimationFinished(bool finished); void notifyDied(); bool hasDied() const; void clearHasDied(); bool hasBeenMurdered() const; void clearHasBeenMurdered(); void notifyMurder(); void resurrect(); bool hasCommonDisease() const; bool hasBlightDisease() const; int getFriendlyHits() const; ///< Number of friendly hits received. /* Start of tes3mp addition Make it possible to set the number of friendly hits from elsewhere */ void setFriendlyHits(int hits); /* End of tes3mp addition */ void friendlyHit(); ///< Increase number of friendly hits by one. bool hasTalkedToPlayer() const; ///< Has this creature talked with the player before? void talkedToPlayer(); bool isAlarmed() const; void setAlarmed (bool alarmed); bool getAttacked() const; void setAttacked (bool attacked); float getEvasion() const; void setKnockedDown(bool value); /// Returns true for the entire duration of the actor being knocked down or knocked out, /// including transition animations (falling down & standing up) bool getKnockedDown() const; void setKnockedDownOneFrame(bool value); ///Returns true only for the first frame of the actor being knocked out; used for "onKnockedOut" command bool getKnockedDownOneFrame() const; void setKnockedDownOverOneFrame(bool value); ///Returns true for all but the first frame of being knocked out; used to know to not reset mKnockedDownOneFrame bool getKnockedDownOverOneFrame() const; void setHitRecovery(bool value); bool getHitRecovery() const; void setBlock(bool value); bool getBlock() const; std::map& getSummonedCreatureMap(); // std::vector& getSummonedCreatureGraveyard(); // ActorIds /* Start of tes3mp addition Make it possible to set a new actorId for summoned creatures, necessary for properly initializing them after syncing them across players */ void setSummonedCreatureActorId(std::string refId, int actorId); /* End of tes3mp addition */ enum Flag { Flag_ForceRun = 1, Flag_ForceSneak = 2, Flag_Run = 4, Flag_Sneak = 8, Flag_ForceJump = 16, Flag_ForceMoveJump = 32 }; enum Stance { Stance_Run, Stance_Sneak }; bool getMovementFlag (Flag flag) const; void setMovementFlag (Flag flag, bool state); /// Like getMovementFlag, but also takes into account if the flag is Forced bool getStance (Stance flag) const; void setLastHitObject(const std::string &objectid); const std::string &getLastHitObject() const; void setLastHitAttemptObject(const std::string &objectid); const std::string &getLastHitAttemptObject() const; void setHitAttemptActorId(const int actorId); int getHitAttemptActorId() const; // Note, this is just a cache to avoid checking the whole container store every frame. We don't need to store it in saves. // TODO: Put it somewhere else? std::set mBoundItems; void writeState (ESM::CreatureStats& state) const; void readState (const ESM::CreatureStats& state); static void writeActorIdCounter (ESM::ESMWriter& esm); static void readActorIdCounter (ESM::ESMReader& esm); void setLastRestockTime(MWWorld::TimeStamp tradeTime); MWWorld::TimeStamp getLastRestockTime() const; void setGoldPool(int pool); int getGoldPool() const; signed char getDeathAnimation() const; // -1 means not decided void setDeathAnimation(signed char index); MWWorld::TimeStamp getTimeOfDeath() const; int getActorId(); ///< Will generate an actor ID, if the actor does not have one yet. bool matchesActorId (int id) const; ///< Check if \a id matches the actor ID of *this (if the actor does not have an ID /// assigned this function will return false). static void cleanup(); std::map & getCorprusSpells(); void addCorprusSpell(const std::string& sourceId, CorprusStats& stats); void removeCorprusSpell(const std::string& sourceId); float getSideMovementAngle() const { return mSideMovementAngle; } void setSideMovementAngle(float angle) { mSideMovementAngle = angle; } }; } #endif