1
0
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:
AlexVinS 2014-11-24 19:14:10 +03:00
parent a71c452fc6
commit aa31625774
3 changed files with 103 additions and 80 deletions

View File

@ -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();
}

View File

@ -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
*/

View File

@ -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