mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-17 01:10:10 +00:00
47a841d3b7
OpenMW save file assumes the presence of NPC/Creature data but the vanilla save file provides only the delta changes in most situations. The base data are not available without loading all the relevant dependency content files. Duplicating that code in the ESSImporter is not desirable. Ideally a flag should be set but that will mean a change in the save file format. For a minor change such as this doing so seems like an overkill. So a temporary workaround is introduced where the gold carried by the NPC/Creature is used as an indicator as the lack of ACDT data.
312 lines
9.4 KiB
C++
312 lines
9.4 KiB
C++
#ifndef GAME_MWMECHANICS_CREATURESTATS_H
|
|
#define GAME_MWMECHANICS_CREATURESTATS_H
|
|
|
|
#include <set>
|
|
#include <string>
|
|
#include <stdexcept>
|
|
|
|
#include "stat.hpp"
|
|
#include "magiceffects.hpp"
|
|
#include "spells.hpp"
|
|
#include "activespells.hpp"
|
|
#include "aisequence.hpp"
|
|
#include "drawstate.hpp"
|
|
|
|
#include <components/esm/attr.hpp>
|
|
#include <components/esm/magiceffects.hpp>
|
|
|
|
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<float> mDynamic[3]; // health, magicka, fatigue
|
|
Spells mSpells;
|
|
ActiveSpells mActiveSpells;
|
|
MagicEffects mMagicEffects;
|
|
Stat<int> 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)
|
|
// HACK: value of INT_MIN has a special meaning: indicates a converted .ess file
|
|
// (this is a workaround to avoid changing the save file format)
|
|
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<ESM::SummonKey, int> mSummonedCreatures; // <SummonKey, ActorId>
|
|
|
|
// 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<int> mSummonGraveyard;
|
|
|
|
std::map<std::string, CorprusStats> 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<float> & getHealth() const;
|
|
|
|
const DynamicStat<float> & getMagicka() const;
|
|
|
|
const DynamicStat<float> & getFatigue() const;
|
|
|
|
const DynamicStat<float> & 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<float> &value);
|
|
|
|
void setMagicka(const DynamicStat<float> &value);
|
|
|
|
void setFatigue(const DynamicStat<float> &value);
|
|
|
|
void setDynamic (int index, const DynamicStat<float> &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<int> value);
|
|
void setAiSetting (AiSetting index, int base);
|
|
Stat<int> 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.
|
|
|
|
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<ESM::SummonKey, int>& getSummonedCreatureMap(); // <SummonKey, ActorId of summoned creature>
|
|
std::vector<int>& getSummonedCreatureGraveyard(); // ActorIds
|
|
|
|
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<int> 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<std::string, CorprusStats> & 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
|