Optimize MWMechanics::Spells

Use pointers as map keys instead of string IDs. Resolves a nasty performance bottleneck on functions like hasCommonDisease() that previously had to look up all contained spells from the ESM store on every call. hasCommonDisease() is called hundreds of times per frame by the AI target update since it's used to calculate target disposition.

The total cost of hasCommonDisease() was 2.7% of the frame loop, now it's negligible.
This commit is contained in:
scrawl 2015-11-27 01:02:29 +01:00
parent 984c455027
commit 783594033a
9 changed files with 102 additions and 93 deletions

View file

@ -95,8 +95,7 @@ namespace MWGui
for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter) for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter)
{ {
const ESM::Spell* spell = const ESM::Spell* spell = iter->first;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mType!=ESM::Spell::ST_Spell) if (spell->mData.mType!=ESM::Spell::ST_Spell)
continue; // don't try to sell diseases, curses or powers continue; // don't try to sell diseases, curses or powers
@ -110,10 +109,10 @@ namespace MWGui
continue; continue;
} }
if (playerHasSpell(iter->first)) if (playerHasSpell(iter->first->mId))
continue; continue;
addSpell (iter->first); addSpell (iter->first->mId);
} }
updateLabels(); updateLabels();

View file

@ -516,8 +516,7 @@ namespace MWGui
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{ {
const ESM::Spell* spell = const ESM::Spell* spell = it->first;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (it->first);
// only normal spells count // only normal spells count
if (spell->mData.mType != ESM::Spell::ST_Spell) if (spell->mData.mType != ESM::Spell::ST_Spell)

View file

@ -52,7 +52,7 @@ namespace MWGui
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{ {
const ESM::Spell* spell = esmStore.get<ESM::Spell>().find(it->first); const ESM::Spell* spell = it->first;
if (spell->mData.mType != ESM::Spell::ST_Power && spell->mData.mType != ESM::Spell::ST_Spell) if (spell->mData.mType != ESM::Spell::ST_Power && spell->mData.mType != ESM::Spell::ST_Spell)
continue; continue;
@ -67,9 +67,9 @@ namespace MWGui
} }
else else
newSpell.mType = Spell::Type_Power; newSpell.mType = Spell::Type_Power;
newSpell.mId = it->first; newSpell.mId = spell->mId;
newSpell.mSelected = (MWBase::Environment::get().getWindowManager()->getSelectedSpell() == it->first); newSpell.mSelected = (MWBase::Environment::get().getWindowManager()->getSelectedSpell() == spell->mId);
newSpell.mActive = true; newSpell.mActive = true;
mSpells.push_back(newSpell); mSpells.push_back(newSpell);
} }

View file

@ -541,7 +541,7 @@ namespace MWMechanics
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{ {
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(it->first); const ESM::Spell* spell = it->first;
float rating = rateSpell(spell, actor, target); float rating = rateSpell(spell, actor, target);
if (rating > bestActionRating) if (rating > bestActionRating)

View file

@ -34,8 +34,7 @@ namespace MWMechanics
Spells& spells = carrier.getClass().getCreatureStats(carrier).getSpells(); Spells& spells = carrier.getClass().getCreatureStats(carrier).getSpells();
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{ {
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(it->first); const ESM::Spell* spell = it->first;
if (actor.getClass().getCreatureStats(actor).getSpells().hasSpell(spell->mId)) if (actor.getClass().getCreatureStats(actor).getSpells().hasSpell(spell->mId))
continue; continue;

View file

@ -124,7 +124,7 @@ namespace MWMechanics
} }
if (spell->mData.mType == ESM::Spell::ST_Power) if (spell->mData.mType == ESM::Spell::ST_Power)
return stats.getSpells().canUsePower(spell->mId) ? 100 : 0; return stats.getSpells().canUsePower(spell) ? 100 : 0;
if (spell->mData.mType != ESM::Spell::ST_Spell) if (spell->mData.mType != ESM::Spell::ST_Spell)
return 100; return 100;
@ -823,7 +823,7 @@ namespace MWMechanics
// A power can be used once per 24h // A power can be used once per 24h
if (spell->mData.mType == ESM::Spell::ST_Power) if (spell->mData.mType == ESM::Spell::ST_Power)
stats.getSpells().usePower(spell->mId); stats.getSpells().usePower(spell);
} }
if (mCaster == getPlayer() && spellIncreasesSkill(spell)) if (mCaster == getPlayer() && spellIncreasesSkill(spell))

View file

@ -25,9 +25,24 @@ namespace MWMechanics
return mSpells.end(); return mSpells.end();
} }
const ESM::Spell* Spells::getSpell(const std::string& id) const
{
return MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(id);
}
bool Spells::hasSpell(const std::string &spell) const
{
return hasSpell(getSpell(spell));
}
bool Spells::hasSpell(const ESM::Spell *spell) const
{
return mSpells.find(spell) != mSpells.end();
}
void Spells::add (const ESM::Spell* spell) void Spells::add (const ESM::Spell* spell)
{ {
if (mSpells.find (spell->mId)==mSpells.end()) if (mSpells.find (spell)==mSpells.end())
{ {
std::map<const int, float> random; std::map<const int, float> random;
@ -48,32 +63,32 @@ namespace MWMechanics
corprus.mWorsenings = 0; corprus.mWorsenings = 0;
corprus.mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod; corprus.mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod;
mCorprusSpells[spell->mId] = corprus; mCorprusSpells[spell] = corprus;
} }
mSpells.insert (std::make_pair (spell->mId, random)); mSpells.insert (std::make_pair (spell, random));
} }
} }
void Spells::add (const std::string& spellId) void Spells::add (const std::string& spellId)
{ {
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId); add(getSpell(spellId));
add(spell);
} }
void Spells::remove (const std::string& spellId) void Spells::remove (const std::string& spellId)
{ {
std::string lower = Misc::StringUtils::lowerCase(spellId); const ESM::Spell* spell = getSpell(spellId);
TContainer::iterator iter = mSpells.find (lower); TContainer::iterator iter = mSpells.find (spell);
std::map<std::string, CorprusStats>::iterator corprusIt = mCorprusSpells.find(lower);
std::map<SpellKey, CorprusStats>::iterator corprusIt = mCorprusSpells.find(spell);
// if it's corprus, remove negative and keep positive effects // if it's corprus, remove negative and keep positive effects
if (corprusIt != mCorprusSpells.end()) if (corprusIt != mCorprusSpells.end())
{ {
worsenCorprus(lower); worsenCorprus(spell);
if (mPermanentSpellEffects.find(lower) != mPermanentSpellEffects.end()) if (mPermanentSpellEffects.find(spell) != mPermanentSpellEffects.end())
{ {
MagicEffects & effects = mPermanentSpellEffects[lower]; MagicEffects & effects = mPermanentSpellEffects[spell];
for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end();) for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end();)
{ {
const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->first.mId); const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->first.mId);
@ -101,8 +116,7 @@ namespace MWMechanics
for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter)
{ {
const ESM::Spell *spell = const ESM::Spell *spell = iter->first;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || 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) spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse)
@ -120,7 +134,7 @@ namespace MWMechanics
} }
} }
for (std::map<std::string, MagicEffects>::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) for (std::map<SpellKey, MagicEffects>::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it)
{ {
effects += it->second; effects += it->second;
} }
@ -145,11 +159,10 @@ namespace MWMechanics
bool Spells::isSpellActive(const std::string &id) const bool Spells::isSpellActive(const std::string &id) const
{ {
TContainer::const_iterator found = mSpells.find(id); TContainer::const_iterator found = mSpells.find(getSpell(id));
if (found != mSpells.end()) if (found != mSpells.end())
{ {
const ESM::Spell *spell = const ESM::Spell *spell = found->first;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (id);
return (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || return (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); spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse);
@ -161,9 +174,7 @@ namespace MWMechanics
{ {
for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter)
{ {
const ESM::Spell *spell = const ESM::Spell *spell = iter->first;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mType == ESM::Spell::ST_Disease) if (spell->mData.mType == ESM::Spell::ST_Disease)
return true; return true;
} }
@ -175,9 +186,7 @@ namespace MWMechanics
{ {
for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter)
{ {
const ESM::Spell *spell = const ESM::Spell *spell = iter->first;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mType == ESM::Spell::ST_Blight) if (spell->mData.mType == ESM::Spell::ST_Blight)
return true; return true;
} }
@ -189,9 +198,7 @@ namespace MWMechanics
{ {
for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();)
{ {
const ESM::Spell *spell = const ESM::Spell *spell = iter->first;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mType == ESM::Spell::ST_Disease) if (spell->mData.mType == ESM::Spell::ST_Disease)
mSpells.erase(iter++); mSpells.erase(iter++);
else else
@ -203,9 +210,7 @@ namespace MWMechanics
{ {
for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();)
{ {
const ESM::Spell *spell = const ESM::Spell *spell = iter->first;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mType == ESM::Spell::ST_Blight && !hasCorprusEffect(spell)) if (spell->mData.mType == ESM::Spell::ST_Blight && !hasCorprusEffect(spell))
mSpells.erase(iter++); mSpells.erase(iter++);
else else
@ -217,9 +222,7 @@ namespace MWMechanics
{ {
for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();)
{ {
const ESM::Spell *spell = const ESM::Spell *spell = iter->first;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (hasCorprusEffect(spell)) if (hasCorprusEffect(spell))
mSpells.erase(iter++); mSpells.erase(iter++);
else else
@ -231,9 +234,7 @@ namespace MWMechanics
{ {
for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();)
{ {
const ESM::Spell *spell = const ESM::Spell *spell = iter->first;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mType == ESM::Spell::ST_Curse) if (spell->mData.mType == ESM::Spell::ST_Curse)
mSpells.erase(iter++); mSpells.erase(iter++);
else else
@ -245,7 +246,7 @@ namespace MWMechanics
{ {
for (TIterator it = begin(); it != end(); ++it) for (TIterator it = begin(); it != end(); ++it)
{ {
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(it->first); const ESM::Spell* spell = it->first;
// these are the spell types that are permanently in effect // these are the spell types that are permanently in effect
if (!(spell->mData.mType == ESM::Spell::ST_Ability) if (!(spell->mData.mType == ESM::Spell::ST_Ability)
@ -268,14 +269,13 @@ namespace MWMechanics
} }
} }
void Spells::worsenCorprus(const std::string &corpSpellId) void Spells::worsenCorprus(const ESM::Spell* spell)
{ {
mCorprusSpells[corpSpellId].mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod; mCorprusSpells[spell].mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod;
mCorprusSpells[corpSpellId].mWorsenings++; mCorprusSpells[spell].mWorsenings++;
// update worsened effects // update worsened effects
mPermanentSpellEffects[corpSpellId] = MagicEffects(); mPermanentSpellEffects[spell] = MagicEffects();
const ESM::Spell * spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(corpSpellId);
int i=0; int i=0;
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt, ++i) for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt, ++i)
{ {
@ -283,12 +283,12 @@ namespace MWMechanics
if ((effectIt->mEffectID != ESM::MagicEffect::Corprus) && (magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) // APPLIED_ONCE if ((effectIt->mEffectID != ESM::MagicEffect::Corprus) && (magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) // APPLIED_ONCE
{ {
float random = 1.f; float random = 1.f;
if (mSpells[corpSpellId].find(i) != mSpells[corpSpellId].end()) if (mSpells[spell].find(i) != mSpells[spell].end())
random = mSpells[corpSpellId].at(i); random = mSpells[spell].at(i);
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
magnitude *= std::max(1, mCorprusSpells[corpSpellId].mWorsenings); magnitude *= std::max(1, mCorprusSpells[spell].mWorsenings);
mPermanentSpellEffects[corpSpellId].add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(magnitude)); mPermanentSpellEffects[spell].add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(magnitude));
} }
} }
} }
@ -305,43 +305,47 @@ namespace MWMechanics
return false; return false;
} }
const std::map<std::string, Spells::CorprusStats> &Spells::getCorprusSpells() const const std::map<Spells::SpellKey, Spells::CorprusStats> &Spells::getCorprusSpells() const
{ {
return mCorprusSpells; return mCorprusSpells;
} }
bool Spells::canUsePower(const std::string &power) const bool Spells::canUsePower(const ESM::Spell* spell) const
{ {
std::map<std::string, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.find(Misc::StringUtils::lowerCase(power)); std::map<SpellKey, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.find(spell);
if (it == mUsedPowers.end() || it->second + 24 <= MWBase::Environment::get().getWorld()->getTimeStamp()) if (it == mUsedPowers.end() || it->second + 24 <= MWBase::Environment::get().getWorld()->getTimeStamp())
return true; return true;
else else
return false; return false;
} }
void Spells::usePower(const std::string &power) void Spells::usePower(const ESM::Spell* spell)
{ {
mUsedPowers[Misc::StringUtils::lowerCase(power)] = MWBase::Environment::get().getWorld()->getTimeStamp(); mUsedPowers[spell] = MWBase::Environment::get().getWorld()->getTimeStamp();
} }
void Spells::readState(const ESM::SpellState &state) void Spells::readState(const ESM::SpellState &state)
{ {
for (TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it) for (ESM::SpellState::TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it)
{ {
// Discard spells that are no longer available due to changed content files // 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); const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(it->first);
if (spell) if (spell)
{ {
mSpells[it->first] = it->second; mSpells[spell] = it->second;
if (it->first == state.mSelectedSpell) if (it->first == state.mSelectedSpell)
mSelectedSpell = it->first; mSelectedSpell = it->first;
} }
} }
// No need to discard spells here (doesn't really matter if non existent ids are kept)
for (std::map<std::string, ESM::TimeStamp>::const_iterator it = state.mUsedPowers.begin(); it != state.mUsedPowers.end(); ++it) for (std::map<std::string, ESM::TimeStamp>::const_iterator it = state.mUsedPowers.begin(); it != state.mUsedPowers.end(); ++it)
mUsedPowers[it->first] = MWWorld::TimeStamp(it->second); {
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(it->first);
if (!spell)
continue;
mUsedPowers[spell] = MWWorld::TimeStamp(it->second);
}
for (std::map<std::string, std::vector<ESM::SpellState::PermanentSpellEffectInfo> >::const_iterator it = for (std::map<std::string, std::vector<ESM::SpellState::PermanentSpellEffectInfo> >::const_iterator it =
state.mPermanentSpellEffects.begin(); it != state.mPermanentSpellEffects.end(); ++it) state.mPermanentSpellEffects.begin(); it != state.mPermanentSpellEffects.end(); ++it)
@ -350,33 +354,35 @@ namespace MWMechanics
if (!spell) if (!spell)
continue; continue;
mPermanentSpellEffects[it->first] = MagicEffects(); mPermanentSpellEffects[spell] = MagicEffects();
for (std::vector<ESM::SpellState::PermanentSpellEffectInfo>::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt) for (std::vector<ESM::SpellState::PermanentSpellEffectInfo>::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt)
{ {
mPermanentSpellEffects[it->first].add(EffectKey(effectIt->mId, effectIt->mArg), effectIt->mMagnitude); mPermanentSpellEffects[spell].add(EffectKey(effectIt->mId, effectIt->mArg), effectIt->mMagnitude);
} }
} }
mCorprusSpells.clear(); mCorprusSpells.clear();
for (std::map<std::string, ESM::SpellState::CorprusStats>::const_iterator it = state.mCorprusSpells.begin(); it != state.mCorprusSpells.end(); ++it) for (std::map<std::string, ESM::SpellState::CorprusStats>::const_iterator it = state.mCorprusSpells.begin(); it != state.mCorprusSpells.end(); ++it)
{ {
if (mSpells.find(it->first) != mSpells.end()) // Discard unavailable corprus spells const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(it->first);
{ if (!spell) // Discard unavailable corprus spells
mCorprusSpells[it->first].mWorsenings = state.mCorprusSpells.at(it->first).mWorsenings; continue;
mCorprusSpells[it->first].mNextWorsening = MWWorld::TimeStamp(state.mCorprusSpells.at(it->first).mNextWorsening); mCorprusSpells[spell].mWorsenings = state.mCorprusSpells.at(it->first).mWorsenings;
} mCorprusSpells[spell].mNextWorsening = MWWorld::TimeStamp(state.mCorprusSpells.at(it->first).mNextWorsening);
} }
} }
void Spells::writeState(ESM::SpellState &state) const void Spells::writeState(ESM::SpellState &state) const
{ {
state.mSpells = mSpells; for (TContainer::const_iterator it = mSpells.begin(); it != mSpells.end(); ++it)
state.mSpells.insert(std::make_pair(it->first->mId, it->second));
state.mSelectedSpell = mSelectedSpell; state.mSelectedSpell = mSelectedSpell;
for (std::map<std::string, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it) for (std::map<SpellKey, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it)
state.mUsedPowers[it->first] = it->second.toEsm(); state.mUsedPowers[it->first->mId] = it->second.toEsm();
for (std::map<std::string, MagicEffects>::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it) for (std::map<SpellKey, MagicEffects>::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it)
{ {
std::vector<ESM::SpellState::PermanentSpellEffectInfo> effectList; std::vector<ESM::SpellState::PermanentSpellEffectInfo> effectList;
for (MagicEffects::Collection::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt) for (MagicEffects::Collection::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt)
@ -388,13 +394,13 @@ namespace MWMechanics
effectList.push_back(info); effectList.push_back(info);
} }
state.mPermanentSpellEffects[it->first] = effectList; state.mPermanentSpellEffects[it->first->mId] = effectList;
} }
for (std::map<std::string, CorprusStats>::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it) for (std::map<SpellKey, CorprusStats>::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it)
{ {
state.mCorprusSpells[it->first].mWorsenings = mCorprusSpells.at(it->first).mWorsenings; state.mCorprusSpells[it->first->mId].mWorsenings = mCorprusSpells.at(it->first).mWorsenings;
state.mCorprusSpells[it->first].mNextWorsening = mCorprusSpells.at(it->first).mNextWorsening.toEsm(); state.mCorprusSpells[it->first->mId].mNextWorsening = mCorprusSpells.at(it->first).mNextWorsening.toEsm();
} }
} }
} }

View file

@ -31,7 +31,9 @@ namespace MWMechanics
{ {
public: public:
typedef std::map<std::string, std::map<const int, float> > TContainer; // ID, <effect index, normalised random magnitude> typedef const ESM::Spell* SpellKey;
typedef std::map<SpellKey, std::map<const int, float> > TContainer; // ID, <effect index, normalised random magnitude>
typedef TContainer::const_iterator TIterator; typedef TContainer::const_iterator TIterator;
struct CorprusStats struct CorprusStats
@ -47,23 +49,26 @@ namespace MWMechanics
TContainer mSpells; TContainer mSpells;
// spell-tied effects that will be applied even after removing the spell (currently used to keep positive effects when corprus is removed) // spell-tied effects that will be applied even after removing the spell (currently used to keep positive effects when corprus is removed)
std::map<std::string, MagicEffects> mPermanentSpellEffects; std::map<SpellKey, MagicEffects> mPermanentSpellEffects;
// Note: this is the spell that's about to be cast, *not* the spell selected in the GUI (which may be different) // Note: this is the spell that's about to be cast, *not* the spell selected in the GUI (which may be different)
std::string mSelectedSpell; std::string mSelectedSpell;
std::map<std::string, MWWorld::TimeStamp> mUsedPowers; std::map<SpellKey, MWWorld::TimeStamp> mUsedPowers;
std::map<std::string, CorprusStats> mCorprusSpells; std::map<SpellKey, CorprusStats> mCorprusSpells;
/// Get spell from ID, throws exception if not found
const ESM::Spell* getSpell(const std::string& id) const;
public: public:
void worsenCorprus(const std::string &corpSpellId); void worsenCorprus(const ESM::Spell* spell);
static bool hasCorprusEffect(const ESM::Spell *spell); static bool hasCorprusEffect(const ESM::Spell *spell);
const std::map<std::string, CorprusStats> & getCorprusSpells() const; const std::map<SpellKey, CorprusStats> & getCorprusSpells() const;
bool canUsePower (const std::string& power) const; bool canUsePower (const ESM::Spell* spell) const;
void usePower (const std::string& power); void usePower (const ESM::Spell* spell);
void purgeCommonDisease(); void purgeCommonDisease();
void purgeBlightDisease(); void purgeBlightDisease();
@ -74,7 +79,8 @@ namespace MWMechanics
TIterator end() const; TIterator end() const;
bool hasSpell(const std::string& spell) const { return mSpells.find(Misc::StringUtils::lowerCase(spell)) != mSpells.end(); } bool hasSpell(const std::string& spell) const;
bool hasSpell(const ESM::Spell* spell) const;
void add (const std::string& spell); void add (const std::string& spell);
///< Adding a spell that is already listed in *this is a no-op. ///< Adding a spell that is already listed in *this is a no-op.

View file

@ -2581,7 +2581,7 @@ namespace MWWorld
} }
// If this is a power, check if it was already used in the last 24h // If this is a power, check if it was already used in the last 24h
if (!fail && spell->mData.mType == ESM::Spell::ST_Power && !stats.getSpells().canUsePower(spell->mId)) if (!fail && spell->mData.mType == ESM::Spell::ST_Power && !stats.getSpells().canUsePower(spell))
{ {
message = "#{sPowerAlreadyUsed}"; message = "#{sPowerAlreadyUsed}";
fail = true; fail = true;