From 9f35637e6db4f67382c2d63a7cc0888f2563e78d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 25 Feb 2016 21:41:38 +0100 Subject: [PATCH] Fixed that a planeswalker that left the battlefield was not correctly removed from combat. --- .../test/cards/control/ItThatBetraysTest.java | 37 +++++++++++++++++++ .../main/java/mage/game/combat/Combat.java | 11 ++++++ .../java/mage/game/combat/CombatGroup.java | 22 +++++++---- .../mage/game/permanent/PermanentImpl.java | 10 +++-- 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java index 4a6a6077a0a..df4398a683c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java @@ -127,4 +127,41 @@ public class ItThatBetraysTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Spreading Seas", 0); assertPermanentCount(playerB, "Spreading Seas", 1); } + + /** + * It That Betrays had a strange bug. Attacked opponent's planeswalker with + * him (I think it was Venser, the Sojourner), then opponent sacrificed said + * planeswalker to ITB (It That Betrays) annihilator ability, ITB ability + * triggered and Venser came over to my control, but ITB was still attacking + * my own planeswalker and killed it. Shouldn't happen because that's an + * entirely new planeswalker, not the one I was attacking. That one died, + * therefore the attack was invalid. + */ + @Test + public void testExileAttackedPlaneswalker() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + + // +2: Exile target permanent you own. Return it to the battlefield under your control at the beginning of the next end step. + // -1: Creatures can't be blocked this turn. + // -8: You get an emblem with "Whenever you cast a spell, exile target permanent." + addCard(Zone.BATTLEFIELD, playerA, "Venser, the Sojourner", 1); + + // Annihilator 2 (Whenever this creature attacks, defending player sacrifices two permanents.) + // Whenever an opponent sacrifices a nontoken permanent, put that card onto the battlefield under your control. + addCard(Zone.BATTLEFIELD, playerB, "It That Betrays"); // 11/11 + + attack(2, playerB, "It That Betrays", "Venser, the Sojourner"); + setChoice(playerA, "Venser, the Sojourner"); + setChoice(playerA, "Mountain"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + // Player B now controls a Silvercoat Lion and Spreading Seas + assertPermanentCount(playerB, "Venser, the Sojourner", 1); + assertPermanentCount(playerB, "Mountain", 1); + } } diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 36c055fd186..a78dc1738c6 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -1110,6 +1110,17 @@ public class Combat implements Serializable, Copyable { } } + public boolean removePlaneswalkerFromCombat(UUID planeswalkerId, Game game, boolean withInfo) { + boolean result = false; + for (CombatGroup group : groups) { + if (group.getDefenderId().equals(planeswalkerId)) { + group.removeAttackedPlaneswalker(planeswalkerId); + result = true; + } + } + return result; + } + public boolean removeFromCombat(UUID creatureId, Game game, boolean withInfo) { boolean result = false; Permanent creature = game.getPermanent(creatureId); diff --git a/Mage/src/main/java/mage/game/combat/CombatGroup.java b/Mage/src/main/java/mage/game/combat/CombatGroup.java index 51c1c196256..d1569afb6f4 100644 --- a/Mage/src/main/java/mage/game/combat/CombatGroup.java +++ b/Mage/src/main/java/mage/game/combat/CombatGroup.java @@ -503,19 +503,25 @@ public class CombatGroup implements Serializable, Copyable { return defenderIsPlaneswalker; } + public boolean removeAttackedPlaneswalker(UUID planeswalkerId) { + if (defenderIsPlaneswalker && defenderId.equals(planeswalkerId)) { + defenderId = null; + return true; + } + return false; + } + public boolean remove(UUID creatureId) { boolean result = false; if (attackers.contains(creatureId)) { attackers.remove(creatureId); result = true; - } else { - if (blockers.contains(creatureId)) { - blockers.remove(creatureId); - result = true; - //20100423 - 509.2a - if (blockerOrder.contains(creatureId)) { - blockerOrder.remove(creatureId); - } + } else if (blockers.contains(creatureId)) { + blockers.remove(creatureId); + result = true; + //20100423 - 509.2a + if (blockerOrder.contains(creatureId)) { + blockerOrder.remove(creatureId); } } return result; diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index c98db5750bd..02e07555776 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1091,10 +1091,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { if (!oneCanBeAttacked) { return false; } - } else { - if (!canAttackCheckRestrictionEffects(defenderId, game)) { - return false; - } + } else if (!canAttackCheckRestrictionEffects(defenderId, game)) { + return false; } return !abilities.containsKey(DefenderAbility.getInstance().getId()) @@ -1223,6 +1221,10 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { public boolean removeFromCombat(Game game, boolean withInfo) { if (this.isAttacking() || this.blocking > 0) { return game.getCombat().removeFromCombat(objectId, game, withInfo); + } else if (getCardType().contains(CardType.PLANESWALKER)) { + if (game.getCombat().getDefenders().contains(getId())) { + game.getCombat().removePlaneswalkerFromCombat(objectId, game, withInfo); + } } return false; }