mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-05 15:05:40 +02:00
vcmi: spell resistance rework
Now instead of XXX_IMMUNITY bonuses we have 2 bonuses with spellSchool subtype: SPELL_SCHOOL_IMMUNITY and NEGATIVE_EFFECT_IMMUNITY. All previous bonuses of subtype 0 is covered by SPELL_SCHOOL_IMMUNITY, and all previous bonuses of subtype 1 is covered by NEGATIVE_EFFECT_IMMUNITY. Unit tests are updated accordingly.
This commit is contained in:
parent
c9bc3fd4e1
commit
8724181a0f
@ -122,9 +122,9 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
|
||||
|
||||
++sitesPerOurTab[4];
|
||||
|
||||
spell->forEachSchool([&sitesPerOurTab](const spells::SchoolInfo & school, bool & stop)
|
||||
spell->forEachSchool([&sitesPerOurTab](const ESpellSchool & school, bool & stop)
|
||||
{
|
||||
++sitesPerOurTab[(ui8)school.id];
|
||||
++sitesPerOurTab[(ui8)school];
|
||||
});
|
||||
}
|
||||
if(sitesPerTabAdv[4] % 12 == 0)
|
||||
|
@ -19,13 +19,12 @@ enum class ESpellSchool: int8_t;
|
||||
|
||||
namespace spells
|
||||
{
|
||||
struct SchoolInfo;
|
||||
class Caster;
|
||||
|
||||
class DLL_LINKAGE Spell: public EntityT<SpellID>
|
||||
{
|
||||
public:
|
||||
using SchoolCallback = std::function<void(const SchoolInfo &, bool &)>;
|
||||
using SchoolCallback = std::function<void(const ESpellSchool &, bool &)>;
|
||||
|
||||
///calculate spell damage on stack taking caster`s secondary skills into account
|
||||
virtual int64_t calculateDamage(const Caster * caster) const = 0;
|
||||
|
@ -99,60 +99,47 @@ std::string CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bo
|
||||
fileName = sp->getIconImmune();
|
||||
break;
|
||||
}
|
||||
case BonusType::FIRE_IMMUNITY:
|
||||
case BonusType::SPELL_SCHOOL_IMMUNITY: //for all school
|
||||
{
|
||||
switch(bonus->subtype)
|
||||
{
|
||||
case 0:
|
||||
fileName = "E_SPFIRE.bmp";
|
||||
break;//all
|
||||
case 1:
|
||||
fileName = "E_SPFIRE1.bmp";
|
||||
break;//not positive
|
||||
case 2:
|
||||
fileName = "E_FIRE.bmp";
|
||||
break;//direct damage
|
||||
}
|
||||
break;
|
||||
case BonusType::WATER_IMMUNITY:
|
||||
switch(bonus->subtype)
|
||||
{
|
||||
case 0:
|
||||
fileName = "E_SPWATER.bmp";
|
||||
break;//all
|
||||
case 1:
|
||||
fileName = "E_SPWATER1.bmp";
|
||||
break;//not positive
|
||||
case 2:
|
||||
fileName = "E_SPCOLD.bmp";
|
||||
break;//direct damage
|
||||
}
|
||||
break;
|
||||
case BonusType::AIR_IMMUNITY:
|
||||
switch(bonus->subtype)
|
||||
{
|
||||
case 0:
|
||||
case SpellSchool(ESpellSchool::AIR):
|
||||
fileName = "E_SPAIR.bmp";
|
||||
break;//all
|
||||
case 1:
|
||||
fileName = "E_SPAIR1.bmp";
|
||||
break;//not positive
|
||||
case 2:
|
||||
fileName = "E_LIGHT.bmp";
|
||||
break;//direct damage
|
||||
break;
|
||||
case SpellSchool(ESpellSchool::FIRE):
|
||||
fileName = "E_SPFIRE.bmp";
|
||||
break;
|
||||
case SpellSchool(ESpellSchool::WATER):
|
||||
fileName = "E_SPWATER.bmp";
|
||||
break;
|
||||
case SpellSchool(ESpellSchool::EARTH):
|
||||
fileName = "E_SPEATH.bmp";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BonusType::EARTH_IMMUNITY:
|
||||
}
|
||||
// fileName = "E_FIRE.bmp"; //fire damage
|
||||
// fileName = "E_COLD.bmp"; //cold damage
|
||||
// fileName = "E_LIGHT.bmp"; //lightning damage
|
||||
case BonusType::NEGATIVE_EFFECTS_IMMUNITY:
|
||||
{
|
||||
switch(bonus->subtype)
|
||||
{
|
||||
case 0:
|
||||
fileName = "E_SPEATH.bmp";
|
||||
break;//all
|
||||
case 1:
|
||||
case 2://no specific icon for direct damage immunity
|
||||
case SpellSchool(ESpellSchool::AIR):
|
||||
fileName = "E_SPAIR1.bmp";
|
||||
break;
|
||||
case SpellSchool(ESpellSchool::FIRE):
|
||||
fileName = "E_SPFIRE1.bmp";
|
||||
break;
|
||||
case SpellSchool(ESpellSchool::WATER):
|
||||
fileName = "E_SPWATER1.bmp";
|
||||
break;
|
||||
case SpellSchool(ESpellSchool::EARTH):
|
||||
fileName = "E_SPEATH1.bmp";
|
||||
break;//not positive
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BonusType::LEVEL_SPELL_IMMUNITY:
|
||||
{
|
||||
if(vstd::iswithin(bonus->val, 1, 5))
|
||||
|
@ -1181,8 +1181,8 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
||||
b.val = GameConstants::SPELL_LEVELS; //in case someone adds higher level spells?
|
||||
break;
|
||||
case 'F':
|
||||
b.type = BonusType::FIRE_IMMUNITY;
|
||||
b.subtype = 1; //not positive
|
||||
b.type = BonusType::NEGATIVE_EFFECTS_IMMUNITY;
|
||||
b.subtype = SpellSchool(ESpellSchool::FIRE);
|
||||
break;
|
||||
case 'O':
|
||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||
@ -1190,12 +1190,12 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
||||
b.val = 100; //Full damage immunity
|
||||
break;
|
||||
case 'f':
|
||||
b.type = BonusType::FIRE_IMMUNITY;
|
||||
b.subtype = 0; //all
|
||||
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
||||
b.subtype = SpellSchool(ESpellSchool::FIRE);
|
||||
break;
|
||||
case 'C':
|
||||
b.type = BonusType::WATER_IMMUNITY;
|
||||
b.subtype = 1; //not positive
|
||||
b.type = BonusType::NEGATIVE_EFFECTS_IMMUNITY;
|
||||
b.subtype = SpellSchool(ESpellSchool::WATER);
|
||||
break;
|
||||
case 'W':
|
||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||
@ -1203,8 +1203,8 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
||||
b.val = 100; //Full damage immunity
|
||||
break;
|
||||
case 'w':
|
||||
b.type = BonusType::WATER_IMMUNITY;
|
||||
b.subtype = 0; //all
|
||||
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
||||
b.subtype = SpellSchool(ESpellSchool::WATER);
|
||||
break;
|
||||
case 'E':
|
||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||
@ -1212,8 +1212,8 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
||||
b.val = 100; //Full damage immunity
|
||||
break;
|
||||
case 'e':
|
||||
b.type = BonusType::EARTH_IMMUNITY;
|
||||
b.subtype = 0; //all
|
||||
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
||||
b.subtype = SpellSchool(ESpellSchool::EARTH);
|
||||
break;
|
||||
case 'A':
|
||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||
@ -1221,8 +1221,8 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
||||
b.val = 100; //Full damage immunity
|
||||
break;
|
||||
case 'a':
|
||||
b.type = BonusType::AIR_IMMUNITY;
|
||||
b.subtype = 0; //all
|
||||
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
||||
b.subtype = SpellSchool(ESpellSchool::AIR);
|
||||
break;
|
||||
case 'D':
|
||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||
|
@ -74,10 +74,6 @@ class JsonNode;
|
||||
BONUS_NAME(SPELL_LIKE_ATTACK) /*subtype - spell, value - spell level; range is taken from spell, but damage from creature; eg. magog*/ \
|
||||
BONUS_NAME(THREE_HEADED_ATTACK) /*eg. cerberus*/ \
|
||||
BONUS_NAME(GENERAL_DAMAGE_PREMY) \
|
||||
BONUS_NAME(FIRE_IMMUNITY) /*subtype 0 - all, 1 - all except positive*/ \
|
||||
BONUS_NAME(WATER_IMMUNITY) \
|
||||
BONUS_NAME(EARTH_IMMUNITY) \
|
||||
BONUS_NAME(AIR_IMMUNITY) \
|
||||
BONUS_NAME(MIND_IMMUNITY) \
|
||||
BONUS_NAME(FIRE_SHIELD) \
|
||||
BONUS_NAME(UNDEAD) \
|
||||
@ -175,6 +171,8 @@ class JsonNode;
|
||||
BONUS_NAME(BONUS_DAMAGE_PERCENTAGE) /*If hero can grant conditional damage to creature, value is percentage, subtype is creatureID*/\
|
||||
BONUS_NAME(BONUS_DAMAGE_CHANCE) /*If hero can grant additional damage to creature, value is chance, subtype is creatureID*/\
|
||||
BONUS_NAME(MAX_LEARNABLE_SPELL_LEVEL) /*This can work as wisdom before. val = max learnable spell level*/\
|
||||
BONUS_NAME(SPELL_SCHOOL_IMMUNITY) /*This bonus will work as spell school immunity for all spells, subtype - spell school: 0 - air, 1 - fire, 2 - water, 3 - earth. Any is not handled for reducing overlap from LEVEL_SPELL_IMMUNITY*/\
|
||||
BONUS_NAME(NEGATIVE_EFFECTS_IMMUNITY) /*This bonus will work as spell school immunity for negative effects from spells of school, subtype - spell school: -1 - any, 0 - air, 1 - fire, 2 - water, 3 - earth*/\
|
||||
/* end of list */
|
||||
|
||||
|
||||
|
@ -620,14 +620,14 @@ int32_t CGHeroInstance::getSpellSchoolLevel(const spells::Spell * spell, int32_t
|
||||
{
|
||||
int32_t skill = -1; //skill level
|
||||
|
||||
spell->forEachSchool([&, this](const spells::SchoolInfo & cnf, bool & stop)
|
||||
spell->forEachSchool([&, this](const ESpellSchool & cnf, bool & stop)
|
||||
{
|
||||
int32_t thisSchool = valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, cnf.id); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies)
|
||||
int32_t thisSchool = valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, SpellSchool(cnf)); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies)
|
||||
if(thisSchool > skill)
|
||||
{
|
||||
skill = thisSchool;
|
||||
if(outSelectedSchool)
|
||||
*outSelectedSchool = static_cast<ui8>(cnf.id);
|
||||
*outSelectedSchool = SpellSchool(cnf);
|
||||
}
|
||||
});
|
||||
|
||||
@ -650,9 +650,9 @@ int64_t CGHeroInstance::getSpellBonus(const spells::Spell * spell, int64_t base,
|
||||
|
||||
int maxSchoolBonus = 0;
|
||||
|
||||
spell->forEachSchool([&maxSchoolBonus, this](const spells::SchoolInfo & cnf, bool & stop)
|
||||
spell->forEachSchool([&maxSchoolBonus, this](const ESpellSchool & cnf, bool & stop)
|
||||
{
|
||||
vstd::amax(maxSchoolBonus, valOfBonuses(BonusType::SPELL_DAMAGE, cnf.id));
|
||||
vstd::amax(maxSchoolBonus, valOfBonuses(BonusType::SPELL_DAMAGE, SpellSchool(cnf)));
|
||||
});
|
||||
|
||||
base = static_cast<int64_t>(base * (100 + maxSchoolBonus) / 100.0);
|
||||
@ -739,9 +739,9 @@ bool CGHeroInstance::canCastThisSpell(const spells::Spell * spell) const
|
||||
|
||||
bool schoolBonus = false;
|
||||
|
||||
spell->forEachSchool([this, &schoolBonus](const spells::SchoolInfo & cnf, bool & stop)
|
||||
spell->forEachSchool([this, &schoolBonus](const ESpellSchool & cnf, bool & stop)
|
||||
{
|
||||
if(hasBonusOfType(BonusType::SPELLS_OF_SCHOOL, cnf.id))
|
||||
if(hasBonusOfType(BonusType::SPELLS_OF_SCHOOL, SpellSchool(cnf)))
|
||||
{
|
||||
schoolBonus = stop = true;
|
||||
}
|
||||
|
@ -43,22 +43,18 @@ const spells::SchoolInfo SCHOOL[4] =
|
||||
{
|
||||
{
|
||||
ESpellSchool::AIR,
|
||||
BonusType::AIR_IMMUNITY,
|
||||
"air"
|
||||
},
|
||||
{
|
||||
ESpellSchool::FIRE,
|
||||
BonusType::FIRE_IMMUNITY,
|
||||
"fire"
|
||||
},
|
||||
{
|
||||
ESpellSchool::WATER,
|
||||
BonusType::WATER_IMMUNITY,
|
||||
"water"
|
||||
},
|
||||
{
|
||||
ESpellSchool::EARTH,
|
||||
BonusType::EARTH_IMMUNITY,
|
||||
"earth"
|
||||
}
|
||||
};
|
||||
@ -153,7 +149,7 @@ spells::AimType CSpell::getTargetType() const
|
||||
return targetType;
|
||||
}
|
||||
|
||||
void CSpell::forEachSchool(const std::function<void(const spells::SchoolInfo &, bool &)>& cb) const
|
||||
void CSpell::forEachSchool(const std::function<void(const ESpellSchool &, bool &)>& cb) const
|
||||
{
|
||||
bool stop = false;
|
||||
for(auto iter : SpellConfig::SCHOOL_ORDER)
|
||||
@ -161,7 +157,7 @@ void CSpell::forEachSchool(const std::function<void(const spells::SchoolInfo &,
|
||||
const spells::SchoolInfo & cnf = SpellConfig::SCHOOL[iter];
|
||||
if(school.at(cnf.id))
|
||||
{
|
||||
cb(cnf, stop);
|
||||
cb(cnf.id.toEnum(), stop);
|
||||
|
||||
if(stop)
|
||||
break;
|
||||
@ -385,11 +381,11 @@ int64_t CSpell::adjustRawDamage(const spells::Caster * caster, const battle::Uni
|
||||
{
|
||||
const auto * bearer = affectedCreature->getBonusBearer();
|
||||
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
|
||||
forEachSchool([&](const spells::SchoolInfo & cnf, bool & stop)
|
||||
forEachSchool([&](const ESpellSchool & cnf, bool & stop)
|
||||
{
|
||||
if(bearer->hasBonusOfType(BonusType::SPELL_DAMAGE_REDUCTION, cnf.id))
|
||||
if(bearer->hasBonusOfType(BonusType::SPELL_DAMAGE_REDUCTION, SpellSchool(cnf)))
|
||||
{
|
||||
ret *= 100 - bearer->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, cnf.id);
|
||||
ret *= 100 - bearer->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, SpellSchool(cnf));
|
||||
ret /= 100;
|
||||
stop = true; //only bonus from one school is used
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ class IBattleCast;
|
||||
struct SchoolInfo
|
||||
{
|
||||
SpellSchool id; //backlink
|
||||
BonusType immunityBonus;
|
||||
std::string jsonName;
|
||||
};
|
||||
|
||||
@ -216,7 +215,7 @@ public:
|
||||
*
|
||||
* Set stop to true to abort looping
|
||||
*/
|
||||
void forEachSchool(const std::function<void(const spells::SchoolInfo &, bool &)> & cb) const override;
|
||||
void forEachSchool(const std::function<void(const ESpellSchool &, bool &)> & cb) const override;
|
||||
|
||||
spells::AimType getTargetType() const;
|
||||
|
||||
|
@ -620,18 +620,6 @@ int64_t BaseMechanics::calculateRawEffectValue(int32_t basePowerMultiplier, int3
|
||||
return owner->calculateRawEffectValue(getEffectLevel(), basePowerMultiplier, levelPowerMultiplier);
|
||||
}
|
||||
|
||||
std::vector<BonusType> BaseMechanics::getElementalImmunity() const
|
||||
{
|
||||
std::vector<BonusType> ret;
|
||||
|
||||
owner->forEachSchool([&](const SchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
ret.push_back(cnf.immunityBonus);
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool BaseMechanics::ownerMatches(const battle::Unit * unit) const
|
||||
{
|
||||
return ownerMatches(unit, owner->getPositiveness());
|
||||
|
@ -235,8 +235,6 @@ public:
|
||||
virtual int64_t applySpecificSpellBonus(int64_t value) const = 0;
|
||||
virtual int64_t calculateRawEffectValue(int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const = 0;
|
||||
|
||||
virtual std::vector<BonusType> getElementalImmunity() const = 0;
|
||||
|
||||
//Battle facade
|
||||
virtual bool ownerMatches(const battle::Unit * unit) const = 0;
|
||||
virtual bool ownerMatches(const battle::Unit * unit, const boost::logic::tribool positivness) const = 0;
|
||||
@ -296,8 +294,6 @@ public:
|
||||
int64_t applySpecificSpellBonus(int64_t value) const override;
|
||||
int64_t calculateRawEffectValue(int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const override;
|
||||
|
||||
std::vector<BonusType> getElementalImmunity() const override;
|
||||
|
||||
bool ownerMatches(const battle::Unit * unit) const override;
|
||||
bool ownerMatches(const battle::Unit * unit, const boost::logic::tribool positivness) const override;
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "../serializer/JsonSerializeFormat.h"
|
||||
#include "../VCMI_Lib.h"
|
||||
|
||||
#include <vcmi/spells/Spell.h>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
@ -173,25 +175,25 @@ protected:
|
||||
bool check(const Mechanics * m, const battle::Unit * target) const override
|
||||
{
|
||||
bool elementalImmune = false;
|
||||
auto bearer = target->getBonusBearer();
|
||||
|
||||
auto filter = m->getElementalImmunity();
|
||||
|
||||
for(auto element : filter)
|
||||
m->getSpell()->forEachSchool([&](const ESpellSchool & cnf, bool & stop)
|
||||
{
|
||||
if(target->hasBonusOfType(element, 0)) //always resist if immune to all spells altogether
|
||||
if (bearer->hasBonusOfType(BonusType::SPELL_SCHOOL_IMMUNITY, SpellSchool(cnf)))
|
||||
{
|
||||
elementalImmune = true;
|
||||
break;
|
||||
stop = true; //only bonus from one school is used
|
||||
}
|
||||
else if(!m->isPositiveSpell()) //negative or indifferent
|
||||
{
|
||||
if(target->hasBonusOfType(element, 1))
|
||||
if (bearer->hasBonusOfType(BonusType::NEGATIVE_EFFECTS_IMMUNITY, SpellSchool(cnf)))
|
||||
{
|
||||
elementalImmune = true;
|
||||
break;
|
||||
stop = true; //only bonus from one school is used
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return elementalImmune;
|
||||
}
|
||||
};
|
||||
|
@ -87,9 +87,9 @@ bool Damage::isReceptive(const Mechanics * m, const battle::Unit * unit) const
|
||||
|
||||
bool isImmune = m->getSpell()->isMagical() && (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, SpellSchool(ESpellSchool::ANY)) >= 100); //General spell damage immunity
|
||||
//elemental immunity for damage
|
||||
m->getSpell()->forEachSchool([&](const SchoolInfo & cnf, bool & stop)
|
||||
m->getSpell()->forEachSchool([&](const ESpellSchool & cnf, bool & stop)
|
||||
{
|
||||
isImmune |= (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, cnf.id) >= 100); //100% reduction is immunity
|
||||
isImmune |= (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, SpellSchool(cnf)) >= 100); //100% reduction is immunity
|
||||
});
|
||||
|
||||
return !isImmune;
|
||||
|
@ -1331,7 +1331,9 @@ int64_t BattleActionProcessor::applyBattleEffects(BattleAttack & bat, std::share
|
||||
if(!bat.shot() &&
|
||||
!def->isClone() &&
|
||||
def->hasBonusOfType(BonusType::FIRE_SHIELD) &&
|
||||
!attackerState->hasBonusOfType(BonusType::FIRE_IMMUNITY) &&
|
||||
!attackerState->hasBonusOfType(BonusType::SPELL_SCHOOL_IMMUNITY, SpellSchool(ESpellSchool::FIRE)) &&
|
||||
!attackerState->hasBonusOfType(BonusType::NEGATIVE_EFFECTS_IMMUNITY, SpellSchool(ESpellSchool::FIRE)) &&
|
||||
attackerState->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, SpellSchool(ESpellSchool::FIRE)) < 100 &&
|
||||
CStack::isMeleeAttackPossible(attackerState.get(), def) // attacked needs to be adjacent to defender for fire shield to trigger (e.g. Dragon Breath attack)
|
||||
)
|
||||
{
|
||||
|
@ -64,8 +64,6 @@ public:
|
||||
MOCK_CONST_METHOD1(applySpecificSpellBonus,int64_t(int64_t));
|
||||
MOCK_CONST_METHOD2(calculateRawEffectValue, int64_t(int32_t, int32_t));
|
||||
|
||||
MOCK_CONST_METHOD0(getElementalImmunity, std::vector<BonusType>());
|
||||
|
||||
MOCK_CONST_METHOD1(ownerMatches, bool(const battle::Unit *));
|
||||
MOCK_CONST_METHOD2(ownerMatches, bool(const battle::Unit *, const boost::logic::tribool));
|
||||
|
||||
|
@ -49,7 +49,7 @@ TEST_F(BonusConditionTest, ReceptiveIfMatchesType)
|
||||
TEST_F(BonusConditionTest, ImmuneIfTypeMismatch)
|
||||
{
|
||||
setDefaultExpectations();
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::FIRE_IMMUNITY, BonusSource::OTHER, 0, 0));
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::OTHER, 0, SpellSchool(ESpellSchool::FIRE)));
|
||||
EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
|
||||
}
|
||||
|
||||
|
@ -20,18 +20,20 @@ class ElementalConditionTest : public TargetConditionItemTest, public WithParamI
|
||||
{
|
||||
public:
|
||||
bool isPositive;
|
||||
|
||||
void setDefaultExpectations()
|
||||
{
|
||||
EXPECT_CALL(unitMock, getAllBonuses(_, _, _, _)).Times(AtLeast(1));
|
||||
EXPECT_CALL(unitMock, getTreeVersion()).Times(AtLeast(0));
|
||||
|
||||
std::vector<BonusType> immunityList =
|
||||
EXPECT_CALL(mechanicsMock, getSpell()).Times(AtLeast(1)).WillRepeatedly(Return(&spellMock));
|
||||
EXPECT_CALL(spellMock, forEachSchool(NotNull())).Times(AtLeast(1)).WillRepeatedly([](const spells::Spell::SchoolCallback & cb)
|
||||
{
|
||||
BonusType::AIR_IMMUNITY,
|
||||
BonusType::FIRE_IMMUNITY,
|
||||
};
|
||||
bool stop = false;
|
||||
cb(ESpellSchool::AIR, stop);
|
||||
cb(ESpellSchool::FIRE, stop);
|
||||
});
|
||||
|
||||
EXPECT_CALL(mechanicsMock, getElementalImmunity()).Times(AtLeast(1)).WillRepeatedly(Return(immunityList));
|
||||
EXPECT_CALL(mechanicsMock, isPositiveSpell()).WillRepeatedly(Return(isPositive));
|
||||
}
|
||||
|
||||
@ -54,15 +56,23 @@ TEST_P(ElementalConditionTest, ReceptiveIfNoBonus)
|
||||
TEST_P(ElementalConditionTest, ImmuneIfBonusMatches)
|
||||
{
|
||||
setDefaultExpectations();
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::AIR_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, 0));
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, SpellSchool(ESpellSchool::AIR)));
|
||||
|
||||
EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
|
||||
}
|
||||
|
||||
TEST_P(ElementalConditionTest, NotImmuneIfBonusMismatches)
|
||||
{
|
||||
setDefaultExpectations();
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, SpellSchool(ESpellSchool::WATER)));
|
||||
|
||||
EXPECT_TRUE(subject->isReceptive(&mechanicsMock, &unitMock));
|
||||
}
|
||||
|
||||
TEST_P(ElementalConditionTest, DependsOnPositivness)
|
||||
{
|
||||
setDefaultExpectations();
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::AIR_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, 1));
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATIVE_EFFECTS_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, SpellSchool(ESpellSchool::AIR)));
|
||||
|
||||
EXPECT_EQ(isPositive, subject->isReceptive(&mechanicsMock, &unitMock));
|
||||
}
|
||||
@ -70,8 +80,8 @@ TEST_P(ElementalConditionTest, DependsOnPositivness)
|
||||
TEST_P(ElementalConditionTest, ImmuneIfBothBonusesPresent)
|
||||
{
|
||||
setDefaultExpectations();
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::AIR_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, 0));
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::AIR_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, 1));
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, SpellSchool(ESpellSchool::AIR)));
|
||||
unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATIVE_EFFECTS_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, SpellSchool(ESpellSchool::AIR)));
|
||||
|
||||
EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
|
||||
#include "mock/mock_spells_Mechanics.h"
|
||||
#include "mock/mock_spells_Spell.h"
|
||||
#include "mock/mock_BonusBearer.h"
|
||||
#include "mock/mock_battle_Unit.h"
|
||||
|
||||
@ -30,6 +31,8 @@ public:
|
||||
|
||||
::testing::StrictMock<spells::MechanicsMock> mechanicsMock;
|
||||
::testing::StrictMock<UnitMock> unitMock;
|
||||
::testing::StrictMock<spells::SpellMock> spellMock;
|
||||
|
||||
BonusBearerMock unitBonuses;
|
||||
protected:
|
||||
void SetUp() override
|
||||
|
Loading…
x
Reference in New Issue
Block a user