1 #ifndef GAME_MWMECHANICS_CREATURESTATS_H 2 #define GAME_MWMECHANICS_CREATURESTATS_H 3 4 #include <set> 5 #include <string> 6 #include <stdexcept> 7 8 #include "stat.hpp" 9 #include "magiceffects.hpp" 10 #include "spells.hpp" 11 #include "activespells.hpp" 12 #include "aisequence.hpp" 13 #include "drawstate.hpp" 14 15 #include <components/esm/attr.hpp> 16 #include <components/esm/magiceffects.hpp> 17 18 namespace ESM 19 { 20 struct CreatureStats; 21 } 22 23 namespace MWMechanics 24 { 25 struct CorprusStats 26 { 27 static constexpr int sWorseningPeriod = 24; 28 29 int mWorsenings[ESM::Attribute::Length]; 30 MWWorld::TimeStamp mNextWorsening; 31 }; 32 33 /// \brief Common creature stats 34 /// 35 /// 36 class CreatureStats 37 { 38 static int sActorId; 39 DrawState_ mDrawState; 40 AttributeValue mAttributes[ESM::Attribute::Length]; 41 DynamicStat<float> mDynamic[3]; // health, magicka, fatigue 42 Spells mSpells; 43 ActiveSpells mActiveSpells; 44 MagicEffects mMagicEffects; 45 Stat<int> mAiSettings[4]; 46 AiSequence mAiSequence; 47 bool mDead; 48 bool mDeathAnimationFinished; 49 bool mDied; // flag for OnDeath script function 50 bool mMurdered; 51 int mFriendlyHits; 52 bool mTalkedTo; 53 bool mAlarmed; 54 bool mAttacked; 55 bool mKnockdown; 56 bool mKnockdownOneFrame; 57 bool mKnockdownOverOneFrame; 58 bool mHitRecovery; 59 bool mBlock; 60 unsigned int mMovementFlags; 61 62 float mFallHeight; 63 64 std::string mLastHitObject; // The last object to hit this actor 65 std::string mLastHitAttemptObject; // The last object to attempt to hit this actor 66 67 bool mRecalcMagicka; 68 69 // For merchants: the last time items were restocked and gold pool refilled. 70 MWWorld::TimeStamp mLastRestock; 71 72 // The pool of merchant gold (not in inventory) 73 int mGoldPool; 74 75 int mActorId; 76 int mHitAttemptActorId; // Stores an actor that attacked this actor. Only one is stored at a time, 77 // and it is not changed if a different actor attacks. It is cleared when combat ends. 78 79 // The index of the death animation that was played, or -1 if none played 80 signed char mDeathAnimation; 81 82 MWWorld::TimeStamp mTimeOfDeath; 83 84 // The difference between view direction and lower body direction. 85 float mSideMovementAngle; 86 87 private: 88 std::map<ESM::SummonKey, int> mSummonedCreatures; // <SummonKey, ActorId> 89 90 // Contains ActorIds of summoned creatures with an expired lifetime that have not been deleted yet. 91 // This may be necessary when the creature is in an inactive cell. 92 std::vector<int> mSummonGraveyard; 93 94 std::map<std::string, CorprusStats> mCorprusSpells; 95 96 protected: 97 int mLevel; 98 99 public: 100 CreatureStats(); 101 102 DrawState_ getDrawState() const; 103 void setDrawState(DrawState_ state); 104 105 bool needToRecalcDynamicStats(); 106 void setNeedRecalcDynamicStats(bool val); 107 108 float getFallHeight() const; 109 void addToFallHeight(float height); 110 111 /// Reset the fall height 112 /// @return total fall height 113 float land(bool isPlayer=false); 114 115 const AttributeValue & getAttribute(int index) const; 116 117 const DynamicStat<float> & getHealth() const; 118 119 const DynamicStat<float> & getMagicka() const; 120 121 const DynamicStat<float> & getFatigue() const; 122 123 const DynamicStat<float> & getDynamic (int index) const; 124 125 const Spells & getSpells() const; 126 127 const ActiveSpells & getActiveSpells() const; 128 129 const MagicEffects & getMagicEffects() const; 130 131 bool getAttackingOrSpell() const; 132 133 int getLevel() const; 134 135 Spells & getSpells(); 136 137 ActiveSpells & getActiveSpells(); 138 139 MagicEffects & getMagicEffects(); 140 141 void setAttribute(int index, const AttributeValue &value); 142 // Shortcut to set only the base 143 void setAttribute(int index, float base); 144 145 void setHealth(const DynamicStat<float> &value); 146 147 void setMagicka(const DynamicStat<float> &value); 148 149 void setFatigue(const DynamicStat<float> &value); 150 151 void setDynamic (int index, const DynamicStat<float> &value); 152 153 /// Set Modifier for each magic effect according to \a effects. Does not touch Base values. 154 void modifyMagicEffects(const MagicEffects &effects); 155 156 void setAttackingOrSpell(bool attackingOrSpell); 157 158 void setLevel(int level); 159 160 enum AiSetting 161 { 162 AI_Hello = 0, 163 AI_Fight = 1, 164 AI_Flee = 2, 165 AI_Alarm = 3 166 }; 167 void setAiSetting (AiSetting index, Stat<int> value); 168 void setAiSetting (AiSetting index, int base); 169 Stat<int> getAiSetting (AiSetting index) const; 170 171 const AiSequence& getAiSequence() const; 172 173 AiSequence& getAiSequence(); 174 175 float getFatigueTerm() const; 176 ///< Return effective fatigue 177 178 bool isParalyzed() const; 179 180 bool isDead() const; 181 182 bool isDeathAnimationFinished() const; 183 void setDeathAnimationFinished(bool finished); 184 185 void notifyDied(); 186 187 bool hasDied() const; 188 189 void clearHasDied(); 190 191 bool hasBeenMurdered() const; 192 193 void clearHasBeenMurdered(); 194 195 void notifyMurder(); 196 197 void resurrect(); 198 199 bool hasCommonDisease() const; 200 201 bool hasBlightDisease() const; 202 203 int getFriendlyHits() const; 204 ///< Number of friendly hits received. 205 206 void friendlyHit(); 207 ///< Increase number of friendly hits by one. 208 209 bool hasTalkedToPlayer() const; 210 ///< Has this creature talked with the player before? 211 212 void talkedToPlayer(); 213 214 bool isAlarmed() const; 215 void setAlarmed (bool alarmed); 216 217 bool getAttacked() const; 218 void setAttacked (bool attacked); 219 220 float getEvasion() const; 221 222 void setKnockedDown(bool value); 223 /// Returns true for the entire duration of the actor being knocked down or knocked out, 224 /// including transition animations (falling down & standing up) 225 bool getKnockedDown() const; 226 void setKnockedDownOneFrame(bool value); 227 ///Returns true only for the first frame of the actor being knocked out; used for "onKnockedOut" command 228 bool getKnockedDownOneFrame() const; 229 void setKnockedDownOverOneFrame(bool value); 230 ///Returns true for all but the first frame of being knocked out; used to know to not reset mKnockedDownOneFrame 231 bool getKnockedDownOverOneFrame() const; 232 void setHitRecovery(bool value); 233 bool getHitRecovery() const; 234 void setBlock(bool value); 235 bool getBlock() const; 236 237 std::map<ESM::SummonKey, int>& getSummonedCreatureMap(); // <SummonKey, ActorId of summoned creature> 238 std::vector<int>& getSummonedCreatureGraveyard(); // ActorIds 239 240 enum Flag 241 { 242 Flag_ForceRun = 1, 243 Flag_ForceSneak = 2, 244 Flag_Run = 4, 245 Flag_Sneak = 8, 246 Flag_ForceJump = 16, 247 Flag_ForceMoveJump = 32 248 }; 249 enum Stance 250 { 251 Stance_Run, 252 Stance_Sneak 253 }; 254 255 bool getMovementFlag (Flag flag) const; 256 void setMovementFlag (Flag flag, bool state); 257 /// Like getMovementFlag, but also takes into account if the flag is Forced 258 bool getStance (Stance flag) const; 259 260 void setLastHitObject(const std::string &objectid); 261 const std::string &getLastHitObject() const; 262 void setLastHitAttemptObject(const std::string &objectid); 263 const std::string &getLastHitAttemptObject() const; 264 void setHitAttemptActorId(const int actorId); 265 int getHitAttemptActorId() const; 266 267 // Note, this is just a cache to avoid checking the whole container store every frame. We don't need to store it in saves. 268 // TODO: Put it somewhere else? 269 std::set<int> mBoundItems; 270 271 void writeState (ESM::CreatureStats& state) const; 272 273 void readState (const ESM::CreatureStats& state); 274 275 static void writeActorIdCounter (ESM::ESMWriter& esm); 276 static void readActorIdCounter (ESM::ESMReader& esm); 277 278 void setLastRestockTime(MWWorld::TimeStamp tradeTime); 279 MWWorld::TimeStamp getLastRestockTime() const; 280 281 void setGoldPool(int pool); 282 int getGoldPool() const; 283 284 signed char getDeathAnimation() const; // -1 means not decided 285 void setDeathAnimation(signed char index); 286 287 MWWorld::TimeStamp getTimeOfDeath() const; 288 289 int getActorId(); 290 ///< Will generate an actor ID, if the actor does not have one yet. 291 292 bool matchesActorId (int id) const; 293 ///< Check if \a id matches the actor ID of *this (if the actor does not have an ID 294 /// assigned this function will return false). 295 296 static void cleanup(); 297 298 std::map<std::string, CorprusStats> & getCorprusSpells(); 299 300 void addCorprusSpell(const std::string& sourceId, CorprusStats& stats); 301 302 void removeCorprusSpell(const std::string& sourceId); 303 getSideMovementAngle() const304 float getSideMovementAngle() const { return mSideMovementAngle; } setSideMovementAngle(float angle)305 void setSideMovementAngle(float angle) { mSideMovementAngle = angle; } 306 }; 307 } 308 309 #endif 310