#ifndef GAME_MWMECHANICS_ACTIVESPELLS_H #define GAME_MWMECHANICS_ACTIVESPELLS_H #include #include #include #include #include #include #include #include "../mwworld/ptr.hpp" #include "../mwworld/timestamp.hpp" #include "spellcasting.hpp" namespace ESM { struct Enchantment; struct Spell; } namespace MWMechanics { /// \brief Lasting spell effects /// /// \note The name of this class is slightly misleading, since it also handles lasting potion /// effects. class ActiveSpells { public: using ActiveEffect = ESM::ActiveEffect; class ActiveSpellParams { ESM::RefId mActiveSpellId; ESM::RefId mSourceSpellId; std::vector mEffects; std::string mDisplayName; int mCasterActorId; ESM::RefNum mItem; ESM::ActiveSpells::Flags mFlags; int mWorsenings; MWWorld::TimeStamp mNextWorsening; MWWorld::Ptr mSource; ActiveSpellParams(const ESM::ActiveSpells::ActiveSpellParams& params); ActiveSpellParams(const ESM::Spell* spell, const MWWorld::Ptr& actor, bool ignoreResistances = false); ActiveSpellParams( const MWWorld::ConstPtr& item, const ESM::Enchantment* enchantment, const MWWorld::Ptr& actor); ActiveSpellParams(const ActiveSpellParams& params, const MWWorld::Ptr& actor); ESM::ActiveSpells::ActiveSpellParams toEsm() const; friend class ActiveSpells; public: ActiveSpellParams( const MWWorld::Ptr& caster, const ESM::RefId& id, std::string_view sourceName, ESM::RefNum item); ESM::RefId getActiveSpellId() const { return mActiveSpellId; } void setActiveSpellId(ESM::RefId id) { mActiveSpellId = id; } const ESM::RefId& getSourceSpellId() const { return mSourceSpellId; } const std::vector& getEffects() const { return mEffects; } std::vector& getEffects() { return mEffects; } int getCasterActorId() const { return mCasterActorId; } int getWorsenings() const { return mWorsenings; } const std::string& getDisplayName() const { return mDisplayName; } ESM::RefNum getItem() const { return mItem; } ESM::RefId getEnchantment() const; const ESM::Spell* getSpell() const; bool hasFlag(ESM::ActiveSpells::Flags flags) const; void setFlag(ESM::ActiveSpells::Flags flags); // Increments worsenings count and sets the next timestamp void worsen(); bool shouldWorsen() const; void resetWorsenings(); }; typedef std::list Collection; typedef Collection::const_iterator TIterator; void readState(const ESM::ActiveSpells& state); void writeState(ESM::ActiveSpells& state) const; TIterator begin() const; TIterator end() const; TIterator getActiveSpellById(const ESM::RefId& id); void update(const MWWorld::Ptr& ptr, float duration); private: using ParamsPredicate = std::function; using EffectPredicate = std::function; using Predicate = std::variant; struct IterationGuard { ActiveSpells& mActiveSpells; IterationGuard(ActiveSpells& spells); ~IterationGuard(); }; std::list mSpells; std::vector mQueue; std::queue mPurges; bool mIterating; void addToSpells(const MWWorld::Ptr& ptr, const ActiveSpellParams& spell); bool applyPurges(const MWWorld::Ptr& ptr, std::list::iterator* currentSpell = nullptr, std::vector::iterator* currentEffect = nullptr); public: ActiveSpells(); /// Add lasting effects /// /// \brief addSpell /// \param id ID for stacking purposes. /// void addSpell(const ActiveSpellParams& params); /// Bypasses resistances void addSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor); /// Removes the active effects from this spell/potion/.. with \a id void removeEffectsBySourceSpellId(const MWWorld::Ptr& ptr, const ESM::RefId& id); /// Removes the active effects of a specific active spell void removeEffectsByActiveSpellId(const MWWorld::Ptr& ptr, const ESM::RefId& id); /// Remove all active effects with this effect id void purgeEffect(const MWWorld::Ptr& ptr, int effectId, ESM::RefId effectArg = {}); void purge(EffectPredicate predicate, const MWWorld::Ptr& ptr); void purge(ParamsPredicate predicate, const MWWorld::Ptr& ptr); /// Remove all effects that were cast by \a casterActorId void purge(const MWWorld::Ptr& ptr, int casterActorId); /// Remove all spells void clear(const MWWorld::Ptr& ptr); /// True if a spell associated with this id is active /// \note For enchantments, this is the id of the enchanted item, not the enchantment itself bool isSpellActive(const ESM::RefId& id) const; /// True if the enchantment is active bool isEnchantmentActive(const ESM::RefId& id) const; void skipWorsenings(double hours); void unloadActor(const MWWorld::Ptr& ptr); }; } #endif