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