mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
More flexible way of spell school access
This commit is contained in:
parent
a71c452fc6
commit
aa31625774
@ -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)
|
||||
{
|
||||
if(school.at(cnf.id))
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
ret *= (100.0 + caster->valOfBonuses(cnf.damagePremyBonus)) / 100.0;
|
||||
break; //only bonus from one school is used
|
||||
}
|
||||
}
|
||||
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,15 +181,15 @@ 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,22 +448,29 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj)
|
||||
|
||||
//6. Check elemental immunities
|
||||
|
||||
for(const SpellSchoolInfo & cnf : SPELL_SCHOOL_CONFIG)
|
||||
{
|
||||
if(school.at(cnf.id))
|
||||
ESpellCastProblem::ESpellCastProblem tmp = ESpellCastProblem::NOT_DECIDED;
|
||||
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
auto element = cnf.immunityBonus;
|
||||
|
||||
if(obj->hasBonusOfType(element, 0)) //always resist if immune to all spells altogether
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
{
|
||||
tmp = ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
stop = true;
|
||||
}
|
||||
else if(!isPositive()) //negative or indifferent
|
||||
{
|
||||
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));
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
@ -40,42 +40,6 @@ struct SpellSchoolInfo
|
||||
Bonus::BonusType knoledgeBonus;
|
||||
};
|
||||
|
||||
static const SpellSchoolInfo SPELL_SCHOOL_CONFIG[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
|
||||
}
|
||||
};
|
||||
|
||||
///callback to be provided by server
|
||||
class DLL_LINKAGE SpellCastEnvironment
|
||||
{
|
||||
@ -244,6 +208,13 @@ public:
|
||||
|
||||
si32 getProbability(const TFaction factionId) const;
|
||||
|
||||
/**
|
||||
* Calls cb for each school this spell belongs to
|
||||
*
|
||||
* Set stop to true to abort looping
|
||||
*/
|
||||
void forEachSchool(const std::function<void (const SpellSchoolInfo &, bool &)> & cb) const;
|
||||
|
||||
/**
|
||||
* Returns resource name of icon for SPELL_IMMUNITY bonus
|
||||
*/
|
||||
|
@ -864,9 +864,7 @@ ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell, int *outSelectedSc
|
||||
{
|
||||
si16 skill = -1; //skill level
|
||||
|
||||
for(const SpellSchoolInfo & cnf : SPELL_SCHOOL_CONFIG)
|
||||
{
|
||||
if(spell->school.at(cnf.id))
|
||||
spell->forEachSchool([&, this](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
int thisSchool = std::max<int>(getSecSkillLevel(cnf.skill), valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 1 << ((ui8)cnf.id)));
|
||||
if(thisSchool > skill)
|
||||
@ -875,8 +873,7 @@ ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell, int *outSelectedSc
|
||||
if(outSelectedSchool)
|
||||
*outSelectedSchool = (ui8)cnf.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
vstd::amax(skill, valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 0)); //any school bonus
|
||||
vstd::amax(skill, valOfBonuses(Bonus::SPELL, spell->id.toEnum())); //given by artifact or other effect
|
||||
|
Loading…
Reference in New Issue
Block a user