2012-04-11 16:29:36 +00:00
# include "spells.hpp"
2020-07-28 06:33:28 +00:00
# include <components/debug/debuglog.hpp>
2012-04-11 17:40:42 +00:00
# include <components/esm/loadspel.hpp>
2014-05-12 19:04:02 +00:00
# include <components/esm/spellstate.hpp>
2015-07-09 17:22:04 +00:00
# include <components/misc/rng.hpp>
2020-07-28 06:33:28 +00:00
# include <components/misc/stringops.hpp>
2012-04-11 16:29:36 +00:00
2019-11-12 15:44:38 +00:00
/*
Start of tes3mp addition
Include additional headers for multiplayer purposes
*/
# include "../mwmp/Main.hpp"
# include "../mwmp/LocalPlayer.hpp"
/*
End of tes3mp addition
*/
2012-04-23 13:27:03 +00:00
# include "../mwbase/environment.hpp"
2012-07-03 10:30:50 +00:00
# include "../mwbase/world.hpp"
2012-04-11 16:29:36 +00:00
2019-09-30 16:27:42 +00:00
# include "../mwworld/class.hpp"
2013-01-13 13:52:55 +00:00
# include "../mwworld/esmstore.hpp"
2019-09-30 16:27:42 +00:00
# include "actorutil.hpp"
# include "creaturestats.hpp"
2012-04-11 16:29:36 +00:00
# include "magiceffects.hpp"
2019-09-30 16:27:42 +00:00
# include "stat.hpp"
2012-04-11 16:29:36 +00:00
namespace MWMechanics
{
2016-07-02 10:50:00 +00:00
Spells : : Spells ( )
: mSpellsChanged ( false )
{
}
2021-03-14 18:32:03 +00:00
Spells : : Spells ( const Spells & spells ) : mSpellList ( spells . mSpellList ) , mSpells ( spells . mSpells ) ,
mSelectedSpell ( spells . mSelectedSpell ) , mUsedPowers ( spells . mUsedPowers ) ,
mSpellsChanged ( spells . mSpellsChanged ) , mEffects ( spells . mEffects ) , mSourcedEffects ( spells . mSourcedEffects )
{
if ( mSpellList )
mSpellList - > addListener ( this ) ;
}
2021-04-23 21:48:55 +00:00
Spells : : Spells ( Spells & & spells ) : mSpellList ( std : : move ( spells . mSpellList ) ) , mSpells ( std : : move ( spells . mSpells ) ) ,
mSelectedSpell ( std : : move ( spells . mSelectedSpell ) ) , mUsedPowers ( std : : move ( spells . mUsedPowers ) ) ,
mSpellsChanged ( std : : move ( spells . mSpellsChanged ) ) , mEffects ( std : : move ( spells . mEffects ) ) ,
mSourcedEffects ( std : : move ( spells . mSourcedEffects ) )
{
if ( mSpellList )
mSpellList - > updateListener ( & spells , this ) ;
}
2020-07-28 06:33:28 +00:00
std : : map < const ESM : : Spell * , SpellParams > : : const_iterator Spells : : begin ( ) const
2012-04-11 16:29:36 +00:00
{
2012-04-11 17:40:42 +00:00
return mSpells . begin ( ) ;
2012-04-11 16:29:36 +00:00
}
2020-07-28 06:33:28 +00:00
std : : map < const ESM : : Spell * , SpellParams > : : const_iterator Spells : : end ( ) const
2012-04-11 16:29:36 +00:00
{
2012-04-11 17:40:42 +00:00
return mSpells . end ( ) ;
2012-04-11 16:29:36 +00:00
}
2016-07-02 10:50:00 +00:00
void Spells : : rebuildEffects ( ) const
{
mEffects = MagicEffects ( ) ;
mSourcedEffects . clear ( ) ;
2020-07-28 06:33:28 +00:00
for ( const auto & iter : mSpells )
2016-07-02 10:50:00 +00:00
{
2020-07-28 06:33:28 +00:00
const ESM : : Spell * spell = iter . first ;
2016-07-02 10:50:00 +00:00
if ( spell - > mData . mType = = ESM : : Spell : : ST_Ability | | spell - > mData . mType = = ESM : : Spell : : ST_Blight | |
spell - > mData . mType = = ESM : : Spell : : ST_Disease | | spell - > mData . mType = = ESM : : Spell : : ST_Curse )
{
int i = 0 ;
2020-07-28 06:33:28 +00:00
for ( const auto & effect : spell - > mEffects . mList )
2016-07-02 10:50:00 +00:00
{
2020-07-28 06:33:28 +00:00
if ( iter . second . mPurgedEffects . find ( i ) ! = iter . second . mPurgedEffects . end ( ) )
2020-06-08 11:19:25 +00:00
{
+ + i ;
2016-07-02 10:50:00 +00:00
continue ; // effect was purged
2020-06-08 11:19:25 +00:00
}
2016-07-02 10:50:00 +00:00
float random = 1.f ;
2020-07-28 06:33:28 +00:00
if ( iter . second . mEffectRands . find ( i ) ! = iter . second . mEffectRands . end ( ) )
random = iter . second . mEffectRands . at ( i ) ;
2016-07-02 10:50:00 +00:00
2020-07-28 06:33:28 +00:00
float magnitude = effect . mMagnMin + ( effect . mMagnMax - effect . mMagnMin ) * random ;
mEffects . add ( effect , magnitude ) ;
mSourcedEffects [ spell ] . add ( MWMechanics : : EffectKey ( effect ) , magnitude ) ;
2016-07-02 10:50:00 +00:00
+ + i ;
}
}
}
}
2015-11-27 00:02:29 +00:00
bool Spells : : hasSpell ( const std : : string & spell ) const
{
2020-07-28 06:33:28 +00:00
return hasSpell ( SpellList : : getSpell ( spell ) ) ;
2015-11-27 00:02:29 +00:00
}
bool Spells : : hasSpell ( const ESM : : Spell * spell ) const
{
return mSpells . find ( spell ) ! = mSpells . end ( ) ;
}
2014-12-14 00:53:15 +00:00
void Spells : : add ( const ESM : : Spell * spell )
2020-07-28 06:33:28 +00:00
{
mSpellList - > add ( spell ) ;
}
void Spells : : add ( const std : : string & spellId )
{
add ( SpellList : : getSpell ( spellId ) ) ;
}
void Spells : : addSpell ( const ESM : : Spell * spell )
2012-04-11 16:29:36 +00:00
{
2015-11-27 00:02:29 +00:00
if ( mSpells . find ( spell ) = = mSpells . end ( ) )
2013-11-13 17:51:28 +00:00
{
2016-01-25 13:13:16 +00:00
std : : map < int , float > random ;
2014-05-12 19:04:02 +00:00
// Determine the random magnitudes (unless this is a castable spell, in which case
// they will be determined when the spell is cast)
if ( spell - > mData . mType ! = ESM : : Spell : : ST_Power & & spell - > mData . mType ! = ESM : : Spell : : ST_Spell )
{
for ( unsigned int i = 0 ; i < spell - > mEffects . mList . size ( ) ; + + i )
{
if ( spell - > mEffects . mList [ i ] . mMagnMin ! = spell - > mEffects . mList [ i ] . mMagnMax )
2019-04-08 17:22:10 +00:00
{
int delta = spell - > mEffects . mList [ i ] . mMagnMax - spell - > mEffects . mList [ i ] . mMagnMin ;
random [ i ] = Misc : : Rng : : rollDice ( delta + 1 ) / static_cast < float > ( delta ) ;
}
2014-05-12 19:04:02 +00:00
}
}
2016-07-01 16:50:28 +00:00
SpellParams params ;
params . mEffectRands = random ;
2020-06-08 11:19:25 +00:00
mSpells . emplace ( spell , params ) ;
2016-07-02 10:50:00 +00:00
mSpellsChanged = true ;
2013-11-13 17:51:28 +00:00
}
2012-04-11 16:29:36 +00:00
}
2020-07-28 06:33:28 +00:00
void Spells : : remove ( const std : : string & spellId )
2014-12-14 00:53:15 +00:00
{
2020-07-28 06:33:28 +00:00
const auto spell = SpellList : : getSpell ( spellId ) ;
removeSpell ( spell ) ;
mSpellList - > remove ( spell ) ;
if ( spellId = = mSelectedSpell )
mSelectedSpell . clear ( ) ;
2014-12-14 00:53:15 +00:00
}
2020-07-28 06:33:28 +00:00
void Spells : : removeSpell ( const ESM : : Spell * spell )
2012-04-11 16:29:36 +00:00
{
2020-07-28 06:33:28 +00:00
const auto it = mSpells . find ( spell ) ;
if ( it ! = mSpells . end ( ) )
2016-07-02 10:50:00 +00:00
{
2020-07-28 06:33:28 +00:00
mSpells . erase ( it ) ;
2016-07-02 10:50:00 +00:00
mSpellsChanged = true ;
}
2012-04-11 16:29:36 +00:00
}
2012-04-23 13:27:03 +00:00
MagicEffects Spells : : getMagicEffects ( ) const
2012-04-11 16:29:36 +00:00
{
2016-07-02 10:50:00 +00:00
if ( mSpellsChanged ) {
rebuildEffects ( ) ;
mSpellsChanged = false ;
2014-08-21 01:11:49 +00:00
}
2016-07-02 10:50:00 +00:00
return mEffects ;
2012-04-11 16:29:36 +00:00
}
2020-07-28 06:33:28 +00:00
void Spells : : removeAllSpells ( )
2012-04-11 16:29:36 +00:00
{
2012-04-11 17:40:42 +00:00
mSpells . clear ( ) ;
2016-07-02 10:50:00 +00:00
mSpellsChanged = true ;
2012-04-11 16:29:36 +00:00
}
2012-04-13 08:49:45 +00:00
2020-07-28 06:33:28 +00:00
void Spells : : clear ( bool modifyBase )
{
removeAllSpells ( ) ;
if ( modifyBase )
mSpellList - > clear ( ) ;
}
2012-04-13 08:49:45 +00:00
void Spells : : setSelectedSpell ( const std : : string & spellId )
{
mSelectedSpell = spellId ;
}
const std : : string Spells : : getSelectedSpell ( ) const
{
return mSelectedSpell ;
}
2013-01-12 12:10:20 +00:00
2015-05-10 11:04:50 +00:00
bool Spells : : isSpellActive ( const std : : string & id ) const
{
2019-05-14 18:24:03 +00:00
if ( id . empty ( ) )
return false ;
2015-05-10 11:04:50 +00:00
2019-05-14 18:24:03 +00:00
const ESM : : Spell * spell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Spell > ( ) . search ( id ) ;
if ( spell & & hasSpell ( spell ) )
{
auto type = spell - > mData . mType ;
return ( type = = ESM : : Spell : : ST_Ability | | type = = ESM : : Spell : : ST_Blight | | type = = ESM : : Spell : : ST_Disease | | type = = ESM : : Spell : : ST_Curse ) ;
2015-05-10 11:04:50 +00:00
}
2019-05-14 18:24:03 +00:00
2015-05-10 11:04:50 +00:00
return false ;
}
2020-07-28 06:33:28 +00:00
bool Spells : : hasDisease ( const ESM : : Spell : : SpellType type ) const
2012-11-09 17:16:29 +00:00
{
2020-07-28 06:33:28 +00:00
for ( const auto & iter : mSpells )
2012-11-09 17:16:29 +00:00
{
2020-07-28 06:33:28 +00:00
const ESM : : Spell * spell = iter . first ;
if ( spell - > mData . mType = = type )
2012-11-09 17:16:29 +00:00
return true ;
}
2013-01-12 12:10:20 +00:00
2012-11-09 17:16:29 +00:00
return false ;
}
2020-07-28 06:33:28 +00:00
bool Spells : : hasCommonDisease ( ) const
2012-11-09 17:16:29 +00:00
{
2020-07-28 06:33:28 +00:00
return hasDisease ( ESM : : Spell : : ST_Disease ) ;
}
2013-01-12 12:10:20 +00:00
2020-07-28 06:33:28 +00:00
bool Spells : : hasBlightDisease ( ) const
{
return hasDisease ( ESM : : Spell : : ST_Blight ) ;
2012-11-09 17:16:29 +00:00
}
2013-11-15 19:29:47 +00:00
2020-07-28 06:33:28 +00:00
void Spells : : purge ( const SpellFilter & filter )
2013-11-17 22:15:57 +00:00
{
2020-07-28 06:33:28 +00:00
std : : vector < std : : string > purged ;
for ( auto iter = mSpells . begin ( ) ; iter ! = mSpells . end ( ) ; )
2013-11-17 22:15:57 +00:00
{
2015-11-27 00:02:29 +00:00
const ESM : : Spell * spell = iter - > first ;
2020-07-28 06:33:28 +00:00
if ( filter ( spell ) )
2016-07-02 10:50:00 +00:00
{
2019-11-12 15:44:38 +00:00
/*
Start of tes3mp addition
2020-08-04 15:41:01 +00:00
Send an ID_PLAYER_SPELLBOOK packet every time a spell is purged here
2019-11-12 15:44:38 +00:00
*/
mwmp : : Main : : get ( ) . getLocalPlayer ( ) - > sendSpellChange ( spell - > mId , mwmp : : SpellbookChanges : : REMOVE ) ;
/*
End of tes3mp addition
*/
2013-11-17 22:15:57 +00:00
mSpells . erase ( iter + + ) ;
2020-07-28 06:33:28 +00:00
purged . push_back ( spell - > mId ) ;
2016-07-02 10:50:00 +00:00
mSpellsChanged = true ;
}
2013-11-17 22:15:57 +00:00
else
2014-04-27 17:03:33 +00:00
+ + iter ;
2013-11-17 22:15:57 +00:00
}
2020-07-28 06:33:28 +00:00
if ( ! purged . empty ( ) )
mSpellList - > removeAll ( purged ) ;
2013-11-17 22:15:57 +00:00
}
2020-07-28 06:33:28 +00:00
void Spells : : purgeCommonDisease ( )
2013-11-17 22:15:57 +00:00
{
2020-07-28 06:33:28 +00:00
purge ( [ ] ( auto spell ) { return spell - > mData . mType = = ESM : : Spell : : ST_Disease ; } ) ;
2013-11-17 22:15:57 +00:00
}
2019-11-12 15:44:38 +00:00
2013-11-17 22:15:57 +00:00
void Spells : : purgeBlightDisease ( )
{
2020-07-28 06:33:28 +00:00
purge ( [ ] ( auto spell ) { return spell - > mData . mType = = ESM : : Spell : : ST_Blight & & ! hasCorprusEffect ( spell ) ; } ) ;
2013-11-17 22:15:57 +00:00
}
void Spells : : purgeCorprusDisease ( )
{
2020-07-28 06:33:28 +00:00
purge ( & hasCorprusEffect ) ;
2013-11-17 22:15:57 +00:00
}
void Spells : : purgeCurses ( )
{
2020-07-28 06:33:28 +00:00
purge ( [ ] ( auto spell ) { return spell - > mData . mType = = ESM : : Spell : : ST_Curse ; } ) ;
2013-11-17 22:15:57 +00:00
}
2018-08-26 23:17:49 +00:00
void Spells : : removeEffects ( const std : : string & id )
{
if ( isSpellActive ( id ) )
{
2020-07-28 06:33:28 +00:00
for ( auto & spell : mSpells )
2018-08-26 23:17:49 +00:00
{
2020-07-28 06:33:28 +00:00
if ( spell . first = = SpellList : : getSpell ( id ) )
2018-08-29 11:09:43 +00:00
{
2020-07-28 06:33:28 +00:00
for ( long unsigned int i = 0 ; i ! = spell . first - > mEffects . mList . size ( ) ; i + + )
2018-08-29 11:09:43 +00:00
{
2020-07-28 06:33:28 +00:00
spell . second . mPurgedEffects . insert ( i ) ;
2018-08-29 11:09:43 +00:00
}
}
2018-08-26 23:17:49 +00:00
}
2018-08-29 11:09:43 +00:00
mSpellsChanged = true ;
2018-08-26 23:17:49 +00:00
}
}
2013-11-15 19:29:47 +00:00
void Spells : : visitEffectSources ( EffectSourceVisitor & visitor ) const
{
2016-07-02 10:50:00 +00:00
if ( mSpellsChanged ) {
rebuildEffects ( ) ;
mSpellsChanged = false ;
2016-07-02 03:17:24 +00:00
}
2020-07-28 06:33:28 +00:00
for ( const auto & it : mSourcedEffects )
2016-07-02 03:17:24 +00:00
{
2020-07-28 06:33:28 +00:00
const ESM : : Spell * spell = it . first ;
for ( const auto & effectIt : it . second )
2016-07-02 03:17:24 +00:00
{
2020-06-08 11:19:25 +00:00
// FIXME: since Spells merges effects with the same ID, there is no sense to use multiple effects with same ID here
visitor . visit ( effectIt . first , - 1 , spell - > mName , spell - > mId , - 1 , effectIt . second . getMagnitude ( ) ) ;
2013-11-15 19:29:47 +00:00
}
}
}
2014-05-12 19:04:02 +00:00
2014-08-19 01:17:31 +00:00
bool Spells : : hasCorprusEffect ( const ESM : : Spell * spell )
{
2020-07-28 06:33:28 +00:00
for ( const auto & effectIt : spell - > mEffects . mList )
2014-08-19 01:17:31 +00:00
{
2020-07-28 06:33:28 +00:00
if ( effectIt . mEffectID = = ESM : : MagicEffect : : Corprus )
2014-08-19 01:17:31 +00:00
{
return true ;
}
}
return false ;
}
2016-07-01 16:50:28 +00:00
void Spells : : purgeEffect ( int effectId )
{
2020-07-28 06:33:28 +00:00
for ( auto & spellIt : mSpells )
2016-07-01 16:50:28 +00:00
{
int i = 0 ;
2020-07-28 06:33:28 +00:00
for ( auto & effectIt : spellIt . first - > mEffects . mList )
2016-07-01 16:50:28 +00:00
{
2020-07-28 06:33:28 +00:00
if ( effectIt . mEffectID = = effectId )
2016-07-02 10:50:00 +00:00
{
2020-07-28 06:33:28 +00:00
spellIt . second . mPurgedEffects . insert ( i ) ;
2016-07-02 10:50:00 +00:00
mSpellsChanged = true ;
}
2016-07-01 16:50:28 +00:00
+ + i ;
}
}
}
void Spells : : purgeEffect ( int effectId , const std : : string & sourceId )
{
2020-06-08 11:19:25 +00:00
// Effect source may be not a spell
const ESM : : Spell * spell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Spell > ( ) . search ( sourceId ) ;
if ( spell = = nullptr )
return ;
2020-07-28 06:33:28 +00:00
auto spellIt = mSpells . find ( spell ) ;
2016-07-01 16:50:28 +00:00
if ( spellIt = = mSpells . end ( ) )
return ;
2020-06-08 11:19:25 +00:00
int index = 0 ;
2020-07-28 06:33:28 +00:00
for ( auto & effectIt : spellIt - > first - > mEffects . mList )
2016-07-01 16:50:28 +00:00
{
2020-07-28 06:33:28 +00:00
if ( effectIt . mEffectID = = effectId )
2016-07-02 10:50:00 +00:00
{
2020-06-08 11:19:25 +00:00
spellIt - > second . mPurgedEffects . insert ( index ) ;
2016-07-02 10:50:00 +00:00
mSpellsChanged = true ;
}
2020-06-08 11:19:25 +00:00
+ + index ;
2016-07-01 16:50:28 +00:00
}
}
2015-11-27 00:02:29 +00:00
bool Spells : : canUsePower ( const ESM : : Spell * spell ) const
2014-05-12 19:04:02 +00:00
{
2020-07-28 06:33:28 +00:00
const auto it = mUsedPowers . find ( spell ) ;
return it = = mUsedPowers . end ( ) | | it - > second + 24 < = MWBase : : Environment : : get ( ) . getWorld ( ) - > getTimeStamp ( ) ;
2014-05-12 19:04:02 +00:00
}
2015-11-27 00:02:29 +00:00
void Spells : : usePower ( const ESM : : Spell * spell )
2014-05-12 19:04:02 +00:00
{
2015-11-27 00:02:29 +00:00
mUsedPowers [ spell ] = MWBase : : Environment : : get ( ) . getWorld ( ) - > getTimeStamp ( ) ;
2021-07-10 20:15:19 +00:00
/*
Start of tes3mp addition
Send an ID_PLAYER_COOLDOWN packet every time a cooldown is recorded here
*/
mwmp : : Main : : get ( ) . getLocalPlayer ( ) - > sendCooldownChange ( spell - > mId , MWBase : : Environment : : get ( ) . getWorld ( ) - > getTimeStamp ( ) . getDay ( ) ,
MWBase : : Environment : : get ( ) . getWorld ( ) - > getTimeStamp ( ) . getHour ( ) ) ;
/*
End of tes3mp addition
*/
}
/*
Start of tes3mp addition
Make it possible to set timestamps for power cooldowns , necessary for ID_PLAYER_COOLDOWNS packets
*/
void Spells : : setPowerUseTimestamp ( const ESM : : Spell * spell , int startDay , float startHour )
{
ESM : : TimeStamp timestamp ;
timestamp . mDay = startDay ;
timestamp . mHour = startHour ;
mUsedPowers [ spell ] = MWWorld : : TimeStamp ( timestamp ) ;
2014-05-12 19:04:02 +00:00
}
2021-07-10 20:15:19 +00:00
/*
End of tes3mp addition
*/
2014-05-12 19:04:02 +00:00
2019-09-30 16:27:42 +00:00
void Spells : : readState ( const ESM : : SpellState & state , CreatureStats * creatureStats )
2014-05-12 19:04:02 +00:00
{
2020-07-28 06:33:28 +00:00
const auto & baseSpells = mSpellList - > getSpells ( ) ;
2015-11-27 00:02:29 +00:00
for ( ESM : : SpellState : : TContainer : : const_iterator it = state . mSpells . begin ( ) ; it ! = state . mSpells . end ( ) ; + + it )
2014-05-12 19:04:02 +00:00
{
2015-01-21 20:24:25 +00:00
// Discard spells that are no longer available due to changed content files
const ESM : : Spell * spell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Spell > ( ) . search ( it - > first ) ;
if ( spell )
2014-05-12 19:04:02 +00:00
{
2016-07-01 16:50:28 +00:00
mSpells [ spell ] . mEffectRands = it - > second . mEffectRands ;
mSpells [ spell ] . mPurgedEffects = it - > second . mPurgedEffects ;
2015-01-21 20:24:25 +00:00
if ( it - > first = = state . mSelectedSpell )
mSelectedSpell = it - > first ;
2014-05-12 19:04:02 +00:00
}
}
2020-07-28 06:33:28 +00:00
// Add spells from the base record
for ( const std : : string & id : baseSpells )
{
const ESM : : Spell * spell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Spell > ( ) . search ( id ) ;
if ( spell )
addSpell ( spell ) ;
}
2014-05-12 19:04:02 +00:00
for ( std : : map < std : : string , ESM : : TimeStamp > : : const_iterator it = state . mUsedPowers . begin ( ) ; it ! = state . mUsedPowers . end ( ) ; + + it )
2015-11-27 00:02:29 +00:00
{
const ESM : : Spell * spell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Spell > ( ) . search ( it - > first ) ;
if ( ! spell )
continue ;
mUsedPowers [ spell ] = MWWorld : : TimeStamp ( it - > second ) ;
}
2014-08-19 01:17:31 +00:00
2019-09-30 16:27:42 +00:00
for ( std : : map < std : : string , ESM : : SpellState : : CorprusStats > : : const_iterator it = state . mCorprusSpells . begin ( ) ; it ! = state . mCorprusSpells . end ( ) ; + + it )
2014-08-21 01:11:49 +00:00
{
const ESM : : Spell * spell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Spell > ( ) . search ( it - > first ) ;
if ( ! spell )
continue ;
2019-09-30 16:27:42 +00:00
CorprusStats stats ;
int worsening = state . mCorprusSpells . at ( it - > first ) . mWorsenings ;
for ( int i = 0 ; i < ESM : : Attribute : : Length ; + + i )
stats . mWorsenings [ i ] = 0 ;
for ( auto & effect : spell - > mEffects . mList )
2014-08-21 01:11:49 +00:00
{
2019-09-30 16:27:42 +00:00
if ( effect . mEffectID = = ESM : : MagicEffect : : DrainAttribute )
stats . mWorsenings [ effect . mAttribute ] = worsening ;
2014-08-21 01:11:49 +00:00
}
2019-09-30 16:27:42 +00:00
stats . mNextWorsening = MWWorld : : TimeStamp ( state . mCorprusSpells . at ( it - > first ) . mNextWorsening ) ;
creatureStats - > addCorprusSpell ( it - > first , stats ) ;
2014-08-21 01:11:49 +00:00
}
2019-09-30 16:27:42 +00:00
mSpellsChanged = true ;
// Permanent effects are used only to keep the custom magnitude of corprus spells effects (after cure too), and only in old saves. Convert data to the new approach.
for ( std : : map < std : : string , std : : vector < ESM : : SpellState : : PermanentSpellEffectInfo > > : : const_iterator it =
state . mPermanentSpellEffects . begin ( ) ; it ! = state . mPermanentSpellEffects . end ( ) ; + + it )
2014-08-19 01:17:31 +00:00
{
2019-09-30 16:27:42 +00:00
const ESM : : Spell * spell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Spell > ( ) . search ( it - > first ) ;
if ( ! spell )
2015-11-27 00:02:29 +00:00
continue ;
2016-07-02 10:50:00 +00:00
2019-09-30 16:27:42 +00:00
// Import data only for player, other actors should not suffer from corprus worsening.
MWWorld : : Ptr player = getPlayer ( ) ;
if ( creatureStats - > getActorId ( ) ! = player . getClass ( ) . getCreatureStats ( player ) . getActorId ( ) )
return ;
// Note: if target actor has the Restore attirbute effects, stats will be restored.
for ( std : : vector < ESM : : SpellState : : PermanentSpellEffectInfo > : : const_iterator effectIt = it - > second . begin ( ) ; effectIt ! = it - > second . end ( ) ; + + effectIt )
{
// Applied corprus effects are already in loaded stats modifiers
if ( effectIt - > mId = = ESM : : MagicEffect : : FortifyAttribute )
{
AttributeValue attr = creatureStats - > getAttribute ( effectIt - > mArg ) ;
attr . setModifier ( attr . getModifier ( ) - effectIt - > mMagnitude ) ;
attr . damage ( - effectIt - > mMagnitude ) ;
creatureStats - > setAttribute ( effectIt - > mArg , attr ) ;
}
else if ( effectIt - > mId = = ESM : : MagicEffect : : DrainAttribute )
{
AttributeValue attr = creatureStats - > getAttribute ( effectIt - > mArg ) ;
attr . setModifier ( attr . getModifier ( ) + effectIt - > mMagnitude ) ;
attr . damage ( effectIt - > mMagnitude ) ;
creatureStats - > setAttribute ( effectIt - > mArg , attr ) ;
}
}
}
2014-05-12 19:04:02 +00:00
}
void Spells : : writeState ( ESM : : SpellState & state ) const
{
2020-07-28 06:33:28 +00:00
const auto & baseSpells = mSpellList - > getSpells ( ) ;
for ( const auto & it : mSpells )
2016-07-01 16:50:28 +00:00
{
2020-08-07 14:36:59 +00:00
// Don't save spells and powers stored in the base record
if ( ( it . first - > mData . mType ! = ESM : : Spell : : ST_Spell & & it . first - > mData . mType ! = ESM : : Spell : : ST_Power ) | |
std : : find ( baseSpells . begin ( ) , baseSpells . end ( ) , it . first - > mId ) = = baseSpells . end ( ) )
2020-07-28 06:33:28 +00:00
{
ESM : : SpellState : : SpellParams params ;
params . mEffectRands = it . second . mEffectRands ;
params . mPurgedEffects = it . second . mPurgedEffects ;
2020-06-08 11:19:25 +00:00
state . mSpells . emplace ( it . first - > mId , params ) ;
2020-07-28 06:33:28 +00:00
}
2016-07-01 16:50:28 +00:00
}
2015-11-27 00:02:29 +00:00
2014-05-12 19:04:02 +00:00
state . mSelectedSpell = mSelectedSpell ;
2020-07-28 06:33:28 +00:00
for ( const auto & it : mUsedPowers )
state . mUsedPowers [ it . first - > mId ] = it . second . toEsm ( ) ;
}
bool Spells : : setSpells ( const std : : string & actorId )
{
bool result ;
std : : tie ( mSpellList , result ) = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . getSpellList ( actorId ) ;
mSpellList - > addListener ( this ) ;
2020-08-04 16:28:10 +00:00
addAllToInstance ( mSpellList - > getSpells ( ) ) ;
2020-07-28 06:33:28 +00:00
return result ;
}
void Spells : : addAllToInstance ( const std : : vector < std : : string > & spells )
{
for ( const std : : string & id : spells )
{
const ESM : : Spell * spell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Spell > ( ) . search ( id ) ;
if ( spell )
addSpell ( spell ) ;
else
Log ( Debug : : Warning ) < < " Warning: ignoring nonexistent spell ' " < < id < < " ' " ;
}
}
Spells : : ~ Spells ( )
{
if ( mSpellList )
mSpellList - > removeListener ( this ) ;
2014-05-12 19:04:02 +00:00
}
2012-04-11 16:29:36 +00:00
}