From 2f7e10a06f152d19498ad2386e32ca2cc9006fea Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Fri, 30 Sep 2016 17:11:17 +0300 Subject: [PATCH] Use range limit selector when modifying bonus lists and checking for spell bonuses * fixes http://bugs.vcmi.eu/view.php?id=2532 --- lib/HeroBonus.cpp | 35 ++++++++++------------------- lib/HeroBonus.h | 5 ++++- lib/spells/BattleSpellMechanics.cpp | 4 ++-- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 1c055a4d1..a3eff811f 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -331,6 +331,11 @@ bool IBonusBearer::hasBonus(const CSelector &selector, const std::string &cachin return getBonuses(selector, cachingStr)->size() > 0; } +bool IBonusBearer::hasBonus(const CSelector &selector, const CSelector &limit, const std::string &cachingStr /*= ""*/) const +{ + return getBonuses(selector, limit, cachingStr)->size() > 0; +} + bool IBonusBearer::hasBonusOfType(Bonus::BonusType type, int subtype /*= -1*/) const { std::stringstream cachingStr; @@ -369,7 +374,7 @@ bool IBonusBearer::hasBonusFrom(Bonus::BonusSource source, ui32 sourceID) const { std::stringstream cachingStr; cachingStr << "source_" << source << "id_" << sourceID; - return hasBonus(Selector::source(source,sourceID), cachingStr.str()); + return hasBonus(Selector::source(source,sourceID), Selector::all, cachingStr.str()); } int IBonusBearer::MoraleVal() const @@ -521,28 +526,9 @@ const std::shared_ptr IBonusBearer::getEffect(ui16 id, int turn /*= 0*/) return nullptr; } -ui8 IBonusBearer::howManyEffectsSet(ui16 id) const -{ - //TODO should check only local bonuses? - ui8 ret = 0; - - auto bonuses = getAllBonuses(); - for(auto& it : *bonuses) - { - if(it->source == Bonus::SPELL_EFFECT && it->sid == id) //effect found - { - ++ret; - } - } - - return ret; -} - const TBonusListPtr IBonusBearer::getAllBonuses() const { - auto matchAll = [] (const Bonus *) { return true; }; - auto matchNone = [] (const Bonus *) { return true; }; - return getAllBonuses(matchAll, matchNone); + return getAllBonuses(Selector::all, Selector::all); } const std::shared_ptr IBonusBearer::getBonus(const CSelector &selector) const @@ -778,7 +764,7 @@ void CBonusSystemNode::detachFrom(CBonusSystemNode *parent) void CBonusSystemNode::popBonuses(const CSelector &s) { BonusList bl; - exportedBonuses.getBonuses(bl, s); + exportedBonuses.getBonuses(bl, s, Selector::all); for(auto b : bl) removeBonus(b); @@ -789,7 +775,7 @@ void CBonusSystemNode::popBonuses(const CSelector &s) void CBonusSystemNode::updateBonuses(const CSelector &s) { BonusList bl; - exportedBonuses.getBonuses(bl, s); + exportedBonuses.getBonuses(bl, s, Selector::all); for(auto b : bl) { b->turnsRemain--; @@ -1237,6 +1223,9 @@ namespace Selector return CSelectFieldEqual(&Bonus::source)(source); } + DLL_LINKAGE CSelector all([](const Bonus * b){return true;}); + DLL_LINKAGE CSelector none([](const Bonus * b){return false;}); + bool DLL_LINKAGE matchesType(const CSelector &sel, Bonus::BonusType type) { Bonus dummy; diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index fe488472c..7e0ecd0da 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -582,6 +582,7 @@ public: int getBonusesCount(const CSelector &selector, const std::string &cachingStr = "") const; int valOfBonuses(const CSelector &selector, const std::string &cachingStr = "") const; bool hasBonus(const CSelector &selector, const std::string &cachingStr = "") const; + bool hasBonus(const CSelector &selector, const CSelector &limit, const std::string &cachingStr = "") const; const TBonusListPtr getBonuses(const CSelector &selector, const CSelector &limit, const std::string &cachingStr = "") const; const TBonusListPtr getBonuses(const CSelector &selector, const std::string &cachingStr = "") const; @@ -607,7 +608,6 @@ public: virtual si32 magicResistance() const; ui32 Speed(int turn = 0, bool useBind = false) const; //get speed of creature with all modificators const std::shared_ptr getEffect(ui16 id, int turn = 0) const; //effect id (SP) - ui8 howManyEffectsSet(ui16 id) const; //returns amount of effects with given id set for this stack si32 manaLimit() const; //maximum mana value for this hero (basically 10*knowledge) int getPrimSkillLevel(PrimarySkill::PrimarySkill id) const; @@ -991,6 +991,9 @@ namespace Selector CSelector DLL_LINKAGE source(Bonus::BonusSource source, ui32 sourceID); CSelector DLL_LINKAGE sourceTypeSel(Bonus::BonusSource source); + extern DLL_LINKAGE CSelector all; + extern DLL_LINKAGE CSelector none; + bool DLL_LINKAGE matchesType(const CSelector &sel, Bonus::BonusType type); bool DLL_LINKAGE matchesTypeSubtype(const CSelector &sel, Bonus::BonusType type, TBonusSubtype subtype); bool DLL_LINKAGE positiveSpellEffects(const Bonus *b); diff --git a/lib/spells/BattleSpellMechanics.cpp b/lib/spells/BattleSpellMechanics.cpp index 5d35feaf2..37e62b3e7 100644 --- a/lib/spells/BattleSpellMechanics.cpp +++ b/lib/spells/BattleSpellMechanics.cpp @@ -203,7 +203,7 @@ bool CureMechanics::dispellSelector(const Bonus * b) ESpellCastProblem::ESpellCastProblem CureMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const { //Selector method name is ok as cashing string. --AVS - if(!obj->canBeHealed() && !obj->hasBonus(CSelector(DefaultSpellMechanics::dispellSelector).And(CSelector(CureMechanics::dispellSelector)), "CureMechanics::dispellSelector")) + if(!obj->canBeHealed() && !obj->hasBonus(CSelector(DefaultSpellMechanics::dispellSelector).And(CSelector(CureMechanics::dispellSelector)), Selector::all, "CureMechanics::dispellSelector")) return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; return DefaultSpellMechanics::isImmuneByStack(caster, obj); @@ -231,7 +231,7 @@ ESpellCastProblem::ESpellCastProblem DispellMechanics::isImmuneByStack(const ISp return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; } - if(obj->hasBonus(CSelector(DefaultSpellMechanics::dispellSelector), "DefaultSpellMechanics::dispellSelector")) + if(obj->hasBonus(CSelector(DefaultSpellMechanics::dispellSelector), Selector::all, "DefaultSpellMechanics::dispellSelector")) return ESpellCastProblem::OK; else return ESpellCastProblem::WRONG_SPELL_TARGET;