|
@@ -226,14 +226,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
|
|
logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode<<"; level: "<<parameters.spellLvl<<"; SP: "<<parameters.usedSpellPower;
|
|
logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode<<"; level: "<<parameters.spellLvl<<"; SP: "<<parameters.usedSpellPower;
|
|
|
|
|
|
BattleSpellCast sc;
|
|
BattleSpellCast sc;
|
|
- sc.side = parameters.casterSide;
|
|
|
|
- sc.id = owner->id;
|
|
|
|
- sc.skill = parameters.spellLvl;
|
|
|
|
- sc.tile = parameters.destination;
|
|
|
|
- sc.dmgToDisplay = 0;
|
|
|
|
- sc.castByHero = nullptr != parameters.casterHero;
|
|
|
|
- sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1);
|
|
|
|
- sc.manaGained = 0;
|
|
|
|
|
|
+ prepareBattleCast(parameters, sc);
|
|
|
|
|
|
//check it there is opponent hero
|
|
//check it there is opponent hero
|
|
const ui8 otherSide = 1-parameters.casterSide;
|
|
const ui8 otherSide = 1-parameters.casterSide;
|
|
@@ -270,44 +263,24 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
|
|
logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks";
|
|
logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks";
|
|
|
|
|
|
std::vector <const CStack*> reflected;//for magic mirror
|
|
std::vector <const CStack*> reflected;//for magic mirror
|
|
-
|
|
|
|
- //checking if creatures resist
|
|
|
|
- //resistance/reflection is applied only to negative spells
|
|
|
|
- if(owner->isNegative())
|
|
|
|
|
|
+ //checking if creatures resist
|
|
|
|
+ handleResistance(env, attackedCres, sc);
|
|
|
|
+ //it is actual spell and can be reflected to single target, no recurrence
|
|
|
|
+ const bool tryMagicMirror = owner->isNegative() && owner->level && owner->getLevelInfo(0).range == "0";
|
|
|
|
+ if(tryMagicMirror)
|
|
{
|
|
{
|
|
- //it is actual spell and can be reflected to single target, no recurrence
|
|
|
|
- const bool tryMagicMirror = parameters.mode != ECastingMode::MAGIC_MIRROR && owner->level && owner->getLevelInfo(0).range == "0";
|
|
|
|
- std::vector <const CStack*> resisted;
|
|
|
|
for(auto s : attackedCres)
|
|
for(auto s : attackedCres)
|
|
{
|
|
{
|
|
- //magic resistance
|
|
|
|
- const int prob = std::min((s)->magicResistance(), 100); //probability of resistance in %
|
|
|
|
-
|
|
|
|
- if(env->getRandomGenerator().nextInt(99) < prob)
|
|
|
|
- {
|
|
|
|
- resisted.push_back(s);
|
|
|
|
- }
|
|
|
|
- //magic mirror
|
|
|
|
- if(tryMagicMirror)
|
|
|
|
- {
|
|
|
|
- const int mirrorChance = (s)->valOfBonuses(Bonus::MAGIC_MIRROR);
|
|
|
|
- if(env->getRandomGenerator().nextInt(99) < mirrorChance)
|
|
|
|
- reflected.push_back(s);
|
|
|
|
- }
|
|
|
|
|
|
+ const int mirrorChance = (s)->valOfBonuses(Bonus::MAGIC_MIRROR);
|
|
|
|
+ if(env->getRandomGenerator().nextInt(99) < mirrorChance)
|
|
|
|
+ reflected.push_back(s);
|
|
}
|
|
}
|
|
|
|
|
|
- vstd::erase_if(attackedCres, [&resisted, reflected](const CStack * s)
|
|
|
|
|
|
+ vstd::erase_if(attackedCres, [&reflected](const CStack * s)
|
|
{
|
|
{
|
|
- return vstd::contains(resisted, s) || vstd::contains(reflected, s);
|
|
|
|
|
|
+ return vstd::contains(reflected, s);
|
|
});
|
|
});
|
|
|
|
|
|
- for(auto s : resisted)
|
|
|
|
- {
|
|
|
|
- BattleSpellCast::CustomEffect effect;
|
|
|
|
- effect.effect = 78;
|
|
|
|
- effect.stack = s->ID;
|
|
|
|
- sc.customEffects.push_back(effect);
|
|
|
|
- }
|
|
|
|
for(auto s : reflected)
|
|
for(auto s : reflected)
|
|
{
|
|
{
|
|
BattleSpellCast::CustomEffect effect;
|
|
BattleSpellCast::CustomEffect effect;
|
|
@@ -333,7 +306,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
|
|
else if(parameters.mode == ECastingMode::HERO_CASTING)
|
|
else if(parameters.mode == ECastingMode::HERO_CASTING)
|
|
ctx.caster = parameters.cb->battleGetFightingHero(parameters.casterSide);
|
|
ctx.caster = parameters.cb->battleGetFightingHero(parameters.casterSide);
|
|
|
|
|
|
- if(parameters.casterStack && parameters.mode != ECastingMode::MAGIC_MIRROR)
|
|
|
|
|
|
+ if(parameters.casterStack)
|
|
{
|
|
{
|
|
auto enchantPower = parameters.casterStack->valOfBonuses(Bonus::CREATURE_ENCHANT_POWER);
|
|
auto enchantPower = parameters.casterStack->valOfBonuses(Bonus::CREATURE_ENCHANT_POWER);
|
|
if(ctx.enchantPower == 0)
|
|
if(ctx.enchantPower == 0)
|
|
@@ -413,7 +386,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
|
|
mirrorParameters.casterStack = (attackedCre);
|
|
mirrorParameters.casterStack = (attackedCre);
|
|
mirrorParameters.selectedStack = nullptr;
|
|
mirrorParameters.selectedStack = nullptr;
|
|
|
|
|
|
- battleCast(env, mirrorParameters);
|
|
|
|
|
|
+ castMagicMirror(env, mirrorParameters, ctx);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -826,3 +799,97 @@ void DefaultSpellMechanics::doDispell(BattleInfo * battle, const BattleSpellCast
|
|
s->popBonuses(selector);
|
|
s->popBonuses(selector);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, BattleSpellCastParameters& parameters, const SpellCastContext& originalContext) const
|
|
|
|
+{
|
|
|
|
+ logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode: MAGIC_MIRROR";
|
|
|
|
+ if(parameters.mode != ECastingMode::MAGIC_MIRROR)
|
|
|
|
+ {
|
|
|
|
+ env->complain("MagicMirror: invalid mode");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if(!parameters.destination.isValid())
|
|
|
|
+ {
|
|
|
|
+ env->complain("MagicMirror: invalid destination");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ BattleSpellCast sc;
|
|
|
|
+ prepareBattleCast(parameters, sc);
|
|
|
|
+
|
|
|
|
+ //calculating affected creatures for all spells
|
|
|
|
+ //must be vector, as in Chain Lightning order matters
|
|
|
|
+ std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector
|
|
|
|
+
|
|
|
|
+ auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, parameters.destination, parameters.casterHero);
|
|
|
|
+ std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres));
|
|
|
|
+
|
|
|
|
+ logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks";
|
|
|
|
+
|
|
|
|
+ handleResistance(env, attackedCres, sc);
|
|
|
|
+
|
|
|
|
+ for(auto cre : attackedCres)
|
|
|
|
+ {
|
|
|
|
+ sc.affectedCres.insert(cre->ID);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ StacksInjured si;
|
|
|
|
+ SpellCastContext ctx(attackedCres, sc, si);
|
|
|
|
+ ctx.effectLevel = originalContext.effectLevel;
|
|
|
|
+ ctx.effectPower = originalContext.effectPower;
|
|
|
|
+ ctx.enchantPower = originalContext.enchantPower;
|
|
|
|
+ ctx.effectValue = originalContext.effectValue;
|
|
|
|
+ ctx.caster = parameters.casterStack;
|
|
|
|
+ applyBattleEffects(env, parameters, ctx);
|
|
|
|
+
|
|
|
|
+ env->sendAndApply(&sc);
|
|
|
|
+ if(!si.stacks.empty()) //after spellcast info shows
|
|
|
|
+ env->sendAndApply(&si);
|
|
|
|
+ logGlobal->debugStream() << "Finished spell cast. Spell: "<<owner->name<<"; mode: MAGIC_MIRROR";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DefaultSpellMechanics::handleResistance(const SpellCastEnvironment * env, std::vector<const CStack* >& attackedCres, BattleSpellCast& sc) const
|
|
|
|
+{
|
|
|
|
+ //checking if creatures resist
|
|
|
|
+ //resistance/reflection is applied only to negative spells
|
|
|
|
+ if(owner->isNegative())
|
|
|
|
+ {
|
|
|
|
+ std::vector <const CStack*> resisted;
|
|
|
|
+ for(auto s : attackedCres)
|
|
|
|
+ {
|
|
|
|
+ //magic resistance
|
|
|
|
+ const int prob = std::min((s)->magicResistance(), 100); //probability of resistance in %
|
|
|
|
+
|
|
|
|
+ if(env->getRandomGenerator().nextInt(99) < prob)
|
|
|
|
+ {
|
|
|
|
+ resisted.push_back(s);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ vstd::erase_if(attackedCres, [&resisted](const CStack * s)
|
|
|
|
+ {
|
|
|
|
+ return vstd::contains(resisted, s);
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ for(auto s : resisted)
|
|
|
|
+ {
|
|
|
|
+ BattleSpellCast::CustomEffect effect;
|
|
|
|
+ effect.effect = 78;
|
|
|
|
+ effect.stack = s->ID;
|
|
|
|
+ sc.customEffects.push_back(effect);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DefaultSpellMechanics::prepareBattleCast(const BattleSpellCastParameters& parameters, BattleSpellCast& sc) const
|
|
|
|
+{
|
|
|
|
+ sc.side = parameters.casterSide;
|
|
|
|
+ sc.id = owner->id;
|
|
|
|
+ sc.skill = parameters.spellLvl;
|
|
|
|
+ sc.tile = parameters.destination;
|
|
|
|
+ sc.dmgToDisplay = 0;
|
|
|
|
+ sc.castByHero = nullptr != parameters.casterHero;
|
|
|
|
+ sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1);
|
|
|
|
+ sc.manaGained = 0;
|
|
|
|
+}
|
|
|
|
+
|