Forráskód Böngészése

Fix magic_mirror spell

Opuszek 3 hónapja
szülő
commit
c472427d8c

+ 2 - 1
config/spells/timed.json

@@ -1311,7 +1311,8 @@
 				"bonus.MIND_IMMUNITY":"normal",
 				"bonus.UNDEAD":"normal",
 				"bonus.NON_LIVING":"normal",
-				"bonus.MECHANICAL":"normal"
+				"bonus.MECHANICAL":"normal",
+				"spell.magicMirror":"normal"
 			}
 		},
 		"flags" : {

+ 53 - 7
lib/spells/BattleSpellMechanics.cpp

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

+ 4 - 0
lib/spells/BattleSpellMechanics.h

@@ -59,6 +59,7 @@ public:
 
 	/// Returns true if spell can be cast on unit
 	bool isReceptive(const battle::Unit * target) const override;
+	bool isSmart() const override;
 
 	/// Returns list of hexes that are affected by spell assuming cast at centralHex
 	BattleHexArray rangeInHexes(const BattleHex & centralHex) const override;
@@ -75,6 +76,9 @@ private:
 	effects::Effects::EffectsToApply effectsToApply;
 
 	void beforeCast(BattleSpellCast & sc, vstd::RNG & rng, const Target & target);
+	bool isReflected(const battle::Unit * unit, vstd::RNG & rng);
+	void reflect(BattleSpellCast & sc, vstd::RNG & rng, const battle::Unit* unit);
+	const battle::Unit* getRandomUnit(vstd::RNG & rng, BattleSide & side);
 
 	std::set<const battle::Unit *> collectTargets() const;
 

+ 0 - 58
lib/spells/ISpellMechanics.cpp

@@ -145,20 +145,6 @@ BattleCast::BattleCast(const CBattleInfoCallback * cb_, const Caster * caster_,
 {
 }
 
-BattleCast::BattleCast(const BattleCast & orig, const Caster * caster_)
-	: spell(orig.spell),
-	cb(orig.cb),
-	caster(caster_),
-	mode(Mode::MAGIC_MIRROR),
-	magicSkillLevel(orig.magicSkillLevel),
-	effectPower(orig.effectPower),
-	effectDuration(orig.effectDuration),
-	effectValue(orig.effectValue),
-	smart(true),
-	massive(false)
-{
-}
-
 BattleCast::~BattleCast() = default;
 
 const CSpell * BattleCast::getSpell() const
@@ -245,51 +231,7 @@ void BattleCast::cast(ServerCallback * server, Target target)
 
 	auto m = spell->battleMechanics(this);
 
-	const battle::Unit * mainTarget = nullptr;
-
-	if(target.front().unitValue)
-	{
-		mainTarget = target.front().unitValue;
-	}
-	else if(target.front().hexValue.isValid())
-	{
-		mainTarget = cb->battleGetUnitByPos(target.front().hexValue, true);
-	}
-
-	bool tryMagicMirror = (mainTarget != nullptr) && (mode == Mode::HERO || mode == Mode::CREATURE_ACTIVE);//TODO: recheck
-	tryMagicMirror = tryMagicMirror && (mainTarget->unitOwner() != caster->getCasterOwner()) && !spell->isPositive();//TODO: recheck
-
 	m->cast(server, target);
-
-	//Magic Mirror effect
-	if(tryMagicMirror)
-	{
-		const std::string magicMirrorCacheStr = "type_MAGIC_MIRROR";
-		static const auto magicMirrorSelector = Selector::type()(BonusType::MAGIC_MIRROR);
-
-		const int mirrorChance = mainTarget->valOfBonuses(magicMirrorSelector, magicMirrorCacheStr);
-
-		if(server->getRNG()->nextInt(0, 99) < mirrorChance)
-		{
-			auto mirrorTargets = cb->battleGetUnitsIf([this](const battle::Unit * unit)
-			{
-				//Get all caster stacks. Magic mirror can reflect to immune creature (with no effect)
-				return unit->unitOwner() == caster->getCasterOwner() && unit->isValidTarget(true);
-			});
-
-
-			if(!mirrorTargets.empty())
-			{
-				const auto * mirrorDestination = (*RandomGeneratorUtil::nextItem(mirrorTargets, *server->getRNG()));
-
-				Target mirrorTarget;
-				mirrorTarget.emplace_back(mirrorDestination);
-
-				BattleCast mirror(*this, mainTarget);
-				mirror.cast(server, mirrorTarget);
-			}
-		}
-	}
 }
 
 void BattleCast::castEval(ServerCallback * server, Target target)

+ 0 - 3
lib/spells/ISpellMechanics.h

@@ -102,9 +102,6 @@ public:
 	//normal constructor
 	BattleCast(const CBattleInfoCallback * cb_, const Caster * caster_, const Mode mode_, const CSpell * spell_);
 
-	//magic mirror constructor
-	BattleCast(const BattleCast & orig, const Caster * caster_);
-
 	virtual ~BattleCast();
 
 	///IBattleCast