|
|
@@ -19,6 +19,7 @@
|
|
|
#include "../networkPacks/PacksForClientBattle.h"
|
|
|
#include "../networkPacks/SetStackEffect.h"
|
|
|
#include "../CStack.h"
|
|
|
+#include <boost/assign.hpp>
|
|
|
|
|
|
#include <vstd/RNG.h>
|
|
|
|
|
|
@@ -334,6 +335,7 @@ void BattleSpellMechanics::cast(ServerCallback * server, const Target & target)
|
|
|
case Mode::ENCHANTER:
|
|
|
case Mode::HERO:
|
|
|
case Mode::PASSIVE:
|
|
|
+ case Mode::MAGIC_MIRROR:
|
|
|
{
|
|
|
MetaString line;
|
|
|
caster->getCastDescription(owner, affectedUnits, line);
|
|
|
@@ -410,6 +412,11 @@ void BattleSpellMechanics::beforeCast(BattleSpellCast & sc, vstd::RNG & rng, con
|
|
|
|
|
|
std::set<const battle::Unit *> unitTargets = collectTargets();
|
|
|
|
|
|
+ if (unitTargets.size()==1 && isReflected(*(unitTargets.begin()), rng))
|
|
|
+ {
|
|
|
+ return reflect(sc, rng, *(unitTargets.begin()));
|
|
|
+ }
|
|
|
+
|
|
|
//process them
|
|
|
for(const auto * unit : unitTargets)
|
|
|
filterUnit(unit);
|
|
|
@@ -425,16 +432,50 @@ void BattleSpellMechanics::beforeCast(BattleSpellCast & sc, vstd::RNG & rng, con
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- if(mode == Mode::MAGIC_MIRROR)
|
|
|
+ for(const auto * unit : resisted)
|
|
|
+ sc.resistedCres.insert(unit->unitId());
|
|
|
+}
|
|
|
+
|
|
|
+bool BattleSpellMechanics::isReflected(const battle::Unit * unit, vstd::RNG & rng)
|
|
|
+{
|
|
|
+ auto range = owner -> getLevelInfo(getRangeLevel()).range;
|
|
|
+ const auto directSpellRange = boost::assign::list_of(0);
|
|
|
+ const std::string magicMirrorCacheStr = "type_MAGIC_MIRROR";
|
|
|
+ static const auto magicMirrorSelector = Selector::type()(BonusType::MAGIC_MIRROR);
|
|
|
+
|
|
|
+ bool spellIsDirect = !isMassive() && owner -> getLevelInfo(getRangeLevel()).range == directSpellRange;
|
|
|
+ bool spellIsReflectable = spellIsDirect && (mode == Mode::HERO || mode == Mode::MAGIC_MIRROR) && isNegativeSpell();
|
|
|
+ bool targetCanReflectSpell = spellIsReflectable && unit->getAllBonuses(Selector::type()(BonusType::MAGIC_MIRROR))->size()>0;
|
|
|
+ return targetCanReflectSpell && rng.nextInt(0, 99) < unit->valOfBonuses(magicMirrorSelector, magicMirrorCacheStr);
|
|
|
+}
|
|
|
+
|
|
|
+void BattleSpellMechanics::reflect(BattleSpellCast & sc, vstd::RNG & rng, const battle::Unit* unit)
|
|
|
+{
|
|
|
+ auto otherSide = battle()->otherSide(unit->unitSide());
|
|
|
+ auto newTarget = getRandomUnit(rng, otherSide);
|
|
|
+ auto reflectedTo = newTarget->getPosition();
|
|
|
+
|
|
|
+ mode = Mode::MAGIC_MIRROR;
|
|
|
+ sc.reflectedCres.insert(unit->unitId());
|
|
|
+ sc.tile = reflectedTo;
|
|
|
+
|
|
|
+ if (!isReceptive(newTarget))
|
|
|
{
|
|
|
- if(caster->getHeroCaster() == nullptr)
|
|
|
- {
|
|
|
- sc.reflectedCres.insert(caster->getCasterUnitId());
|
|
|
- }
|
|
|
+ sc.resistedCres.insert(newTarget->unitId()); //A spell can be reflected to then resisted by an immune unit. Consistent with the original game.
|
|
|
}
|
|
|
|
|
|
- for(const auto * unit : resisted)
|
|
|
- sc.resistedCres.insert(unit->unitId());
|
|
|
+ beforeCast(sc, rng,
|
|
|
+ boost::assign::list_of(reflectedTo));
|
|
|
+}
|
|
|
+
|
|
|
+const battle::Unit* BattleSpellMechanics::getRandomUnit(vstd::RNG & rng, BattleSide & side)
|
|
|
+{
|
|
|
+ auto targets = battle()->getBattle()->getUnitsIf([this, & side](const battle::Unit * unit)
|
|
|
+ {
|
|
|
+ return unit->unitSide() == side && unit->isValidTarget(false) &&
|
|
|
+ !unit->hasBonusOfType(BonusType::SIEGE_WEAPON);
|
|
|
+ });
|
|
|
+ return !targets.empty() ? (*RandomGeneratorUtil::nextItem(targets, rng)) : nullptr;
|
|
|
}
|
|
|
|
|
|
void BattleSpellMechanics::castEval(ServerCallback * server, const Target & target)
|
|
|
@@ -658,6 +699,11 @@ bool BattleSpellMechanics::isReceptive(const battle::Unit * target) const
|
|
|
return targetCondition->isReceptive(this, target);
|
|
|
}
|
|
|
|
|
|
+bool BattleSpellMechanics::isSmart() const
|
|
|
+{
|
|
|
+ return mode != Mode::MAGIC_MIRROR && BaseMechanics::isSmart();
|
|
|
+}
|
|
|
+
|
|
|
BattleHexArray BattleSpellMechanics::rangeInHexes(const BattleHex & centralHex) const
|
|
|
{
|
|
|
if(isMassive() || !centralHex.isValid())
|