1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-26 03:52:01 +02:00

More general spell school handling

This commit is contained in:
AlexVinS 2014-11-12 11:03:55 +03:00
parent d7800b834e
commit 22178151aa
3 changed files with 91 additions and 52 deletions

View File

@ -337,15 +337,15 @@ 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;
if(air)
ret *= (100.0 + caster->valOfBonuses(Bonus::AIR_SPELL_DMG_PREMY)) / 100.0;
else if(fire) //only one type of bonus for Magic Arrow
ret *= (100.0 + caster->valOfBonuses(Bonus::FIRE_SPELL_DMG_PREMY)) / 100.0;
else if(water)
ret *= (100.0 + caster->valOfBonuses(Bonus::WATER_SPELL_DMG_PREMY)) / 100.0;
else if(earth)
ret *= (100.0 + caster->valOfBonuses(Bonus::EARTH_SPELL_DMG_PREMY)) / 100.0;
for(const SpellSchoolInfo & cnf : spellSchoolConfig)
{
if(school.at(cnf.id))
{
ret *= (100.0 + caster->valOfBonuses(cnf.damagePremyBonus)) / 100.0;
break; //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;
@ -368,26 +368,17 @@ ui32 CSpell::calculateDamage(const CGHeroInstance * caster, const CStack * affec
if(nullptr != affectedCreature)
{
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
if(air && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 0)) //air spell & protection from air
for(const SpellSchoolInfo & cnf : spellSchoolConfig)
{
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 0);
ret /= 100;
}
else if(fire && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 1)) //fire spell & protection from fire
{
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 1);
ret /= 100;
}
else if(water && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 2)) //water spell & protection from water
{
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 2);
ret /= 100;
}
else if (earth && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 3)) //earth spell & protection from earth
{
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 3);
ret /= 100;
}
if(school.at(cnf.id) && 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
}
}
//general spell dmg reduction
//FIXME?
if(air && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, -1))
@ -727,27 +718,14 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj)
};
//6. Check elemental immunities
if(fire)
for(const SpellSchoolInfo & cnf : spellSchoolConfig)
{
if(battleTestElementalImmunity(Bonus::FIRE_IMMUNITY))
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
}
if(water)
{
if(battleTestElementalImmunity(Bonus::WATER_IMMUNITY))
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
if(school.at(cnf.id))
if(battleTestElementalImmunity(cnf.immunityBonus))
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
}
if(earth)
{
if(battleTestElementalImmunity(Bonus::EARTH_IMMUNITY))
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
}
if(air)
{
if(battleTestElementalImmunity(Bonus::AIR_IMMUNITY))
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
}
TBonusListPtr levelImmunities = obj->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY));
@ -791,6 +769,17 @@ void CSpell::setIsRising(const bool val)
}
}
void CSpell::setup()
{
setupMechanics();
school[ESpellSchool::AIR] = air;
school[ESpellSchool::FIRE] = fire;
school[ESpellSchool::WATER] = water;
school[ESpellSchool::EARTH] = earth;
}
void CSpell::setupMechanics()
{
if(nullptr != mechanics)
@ -1164,7 +1153,7 @@ void CSpellHandler::afterLoadFinalization()
for(auto & level: spell->levels)
for(auto & bonus: level.effects)
bonus.sid = spell->id;
spell->setupMechanics();
spell->setup();
}
}

View File

@ -23,6 +23,44 @@ class CSpell;
class CGHeroInstance;
class CStack;
struct SpellSchoolInfo
{
ESpellSchool id; //backlink
Bonus::BonusType damagePremyBonus;
Bonus::BonusType immunityBonus;
std::string jsonName;
};
static SpellSchoolInfo spellSchoolConfig[4] =
{
{
ESpellSchool::AIR,
Bonus::AIR_SPELL_DMG_PREMY,
Bonus::AIR_IMMUNITY,
"air"
},
{
ESpellSchool::FIRE,
Bonus::FIRE_SPELL_DMG_PREMY,
Bonus::FIRE_IMMUNITY,
"fire"
},
{
ESpellSchool::WATER,
Bonus::WATER_SPELL_DMG_PREMY,
Bonus::WATER_IMMUNITY,
"water"
},
{
ESpellSchool::EARTH,
Bonus::EARTH_SPELL_DMG_PREMY,
Bonus::EARTH_IMMUNITY,
"earth"
}
};
class CPackForClient;
class DLL_LINKAGE CSpellMechanics
{
public:
@ -82,10 +120,13 @@ public:
std::string name;
si32 level;
bool earth;
bool water;
bool fire;
bool air;
bool earth; //deprecated
bool water; //deprecated
bool fire; //deprecated
bool air; //deprecated
std::map<ESpellSchool, bool> school; //todo: use this instead of separate boolean fields
si32 power; //spell's power
std::map<TFaction, si32> probabilities; //% chance to gain for castles
@ -178,7 +219,7 @@ public:
h & levels;
if(!h.saving)
setupMechanics();
setup();
}
friend class CSpellHandler;
friend class Graphics;
@ -188,6 +229,7 @@ private:
void setIsRising(const bool val);
//call this after load or deserialization. cant be done in constructor.
void setup();
void setupMechanics();
private:
si32 defaultProbability;

View File

@ -890,6 +890,14 @@ public:
ESpellID num;
};
enum class ESpellSchool: ui8
{
AIR = 0,
FIRE = 1,
WATER = 2,
EARTH = 3
};
ID_LIKE_OPERATORS_DECLS(SpellID, SpellID::ESpellID)
// Typedef declarations