mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-29 00:41:38 +02:00
More flexible way of spell school access
This commit is contained in:
@ -31,6 +31,42 @@
|
||||
namespace SpellConfig
|
||||
{
|
||||
static const std::string LEVEL_NAMES[] = {"none", "basic", "advanced", "expert"};
|
||||
|
||||
static const SpellSchoolInfo SCHOOL[4] =
|
||||
{
|
||||
{
|
||||
ESpellSchool::AIR,
|
||||
Bonus::AIR_SPELL_DMG_PREMY,
|
||||
Bonus::AIR_IMMUNITY,
|
||||
"air",
|
||||
SecondarySkill::AIR_MAGIC,
|
||||
Bonus::AIR_SPELLS
|
||||
},
|
||||
{
|
||||
ESpellSchool::FIRE,
|
||||
Bonus::FIRE_SPELL_DMG_PREMY,
|
||||
Bonus::FIRE_IMMUNITY,
|
||||
"fire",
|
||||
SecondarySkill::FIRE_MAGIC,
|
||||
Bonus::FIRE_SPELLS
|
||||
},
|
||||
{
|
||||
ESpellSchool::WATER,
|
||||
Bonus::WATER_SPELL_DMG_PREMY,
|
||||
Bonus::WATER_IMMUNITY,
|
||||
"water",
|
||||
SecondarySkill::WATER_MAGIC,
|
||||
Bonus::WATER_SPELLS
|
||||
},
|
||||
{
|
||||
ESpellSchool::EARTH,
|
||||
Bonus::EARTH_SPELL_DMG_PREMY,
|
||||
Bonus::EARTH_IMMUNITY,
|
||||
"earth",
|
||||
SecondarySkill::EARTH_MAGIC,
|
||||
Bonus::EARTH_SPELLS
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
///CSpell::LevelInfo
|
||||
@ -75,14 +111,13 @@ bool CSpell::isCastableBy(const IBonusBearer * caster, bool hasSpellBook, const
|
||||
|
||||
bool inTome = false;
|
||||
|
||||
for(const SpellSchoolInfo & cnf : SPELL_SCHOOL_CONFIG)
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
if(school.at(cnf.id) && caster->hasBonusOfType(cnf.knoledgeBonus))
|
||||
{
|
||||
inTome = true;
|
||||
break;
|
||||
inTome = stop = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (isSpecialSpell())
|
||||
{
|
||||
@ -118,14 +153,11 @@ ui32 CSpell::calculateBonus(ui32 baseDamage, const CGHeroInstance* caster, const
|
||||
ret *= (100.0 + caster->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::SORCERY)) / 100.0;
|
||||
ret *= (100.0 + caster->valOfBonuses(Bonus::SPELL_DAMAGE) + caster->valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, id.toEnum())) / 100.0;
|
||||
|
||||
for(const SpellSchoolInfo & cnf : SPELL_SCHOOL_CONFIG)
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
if(school.at(cnf.id))
|
||||
{
|
||||
ret *= (100.0 + caster->valOfBonuses(cnf.damagePremyBonus)) / 100.0;
|
||||
break; //only bonus from one school is used
|
||||
}
|
||||
}
|
||||
ret *= (100.0 + caster->valOfBonuses(cnf.damagePremyBonus)) / 100.0;
|
||||
stop = true; //only bonus from one school is used
|
||||
});
|
||||
|
||||
if (affectedCreature && affectedCreature->getCreature()->level) //Hero specials like Solmyr, Deemer
|
||||
ret *= (100. + ((caster->valOfBonuses(Bonus::SPECIAL_SPELL_LEV, id.toEnum()) * caster->level) / affectedCreature->getCreature()->level)) / 100.0;
|
||||
@ -149,16 +181,16 @@ ui32 CSpell::calculateDamage(const CGHeroInstance * caster, const CStack * affec
|
||||
{
|
||||
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
|
||||
|
||||
for(const SpellSchoolInfo & cnf : SPELL_SCHOOL_CONFIG)
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
if(school.at(cnf.id) && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, (ui8)cnf.id))
|
||||
if(affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, (ui8)cnf.id))
|
||||
{
|
||||
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, (ui8)cnf.id);
|
||||
ret /= 100;
|
||||
break; //only bonus from one school is used
|
||||
stop = true;//only bonus from one school is used
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//general spell dmg reduction
|
||||
if(affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, -1))
|
||||
{
|
||||
@ -236,6 +268,22 @@ CSpell::TargetInfo CSpell::getTargetInfo(const int level) const
|
||||
return info;
|
||||
}
|
||||
|
||||
void CSpell::forEachSchool(const std::function<void(const SpellSchoolInfo &, bool &)>& cb) const
|
||||
{
|
||||
bool stop = false;
|
||||
for(const SpellSchoolInfo & cnf : SpellConfig::SCHOOL)
|
||||
{
|
||||
if(school.at(cnf.id))
|
||||
{
|
||||
cb(cnf, stop);
|
||||
|
||||
if(stop)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CSpell::isCombatSpell() const
|
||||
{
|
||||
return combatSpell;
|
||||
@ -400,23 +448,30 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj)
|
||||
|
||||
//6. Check elemental immunities
|
||||
|
||||
for(const SpellSchoolInfo & cnf : SPELL_SCHOOL_CONFIG)
|
||||
ESpellCastProblem::ESpellCastProblem tmp = ESpellCastProblem::NOT_DECIDED;
|
||||
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
if(school.at(cnf.id))
|
||||
auto element = cnf.immunityBonus;
|
||||
|
||||
if(obj->hasBonusOfType(element, 0)) //always resist if immune to all spells altogether
|
||||
{
|
||||
auto element = cnf.immunityBonus;
|
||||
|
||||
if(obj->hasBonusOfType(element, 0)) //always resist if immune to all spells altogether
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
else if(!isPositive()) //negative or indifferent
|
||||
tmp = ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
stop = true;
|
||||
}
|
||||
else if(!isPositive()) //negative or indifferent
|
||||
{
|
||||
if((isDamageSpell() && obj->hasBonusOfType(element, 2)) || obj->hasBonusOfType(element, 1))
|
||||
{
|
||||
if((isDamageSpell() && obj->hasBonusOfType(element, 2)) || obj->hasBonusOfType(element, 1))
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tmp = ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(tmp != ESpellCastProblem::NOT_DECIDED)
|
||||
return tmp;
|
||||
|
||||
TBonusListPtr levelImmunities = obj->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY));
|
||||
|
||||
if(obj->hasBonusOfType(Bonus::SPELL_IMMUNITY, id)
|
||||
@ -691,7 +746,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
|
||||
const auto schoolNames = json["school"];
|
||||
|
||||
for(const SpellSchoolInfo & info : SPELL_SCHOOL_CONFIG)
|
||||
for(const SpellSchoolInfo & info : SpellConfig::SCHOOL)
|
||||
{
|
||||
spell->school[info.id] = schoolNames[info.jsonName].Bool();
|
||||
}
|
||||
|
Reference in New Issue
Block a user