From 292c9f6eba7c04733292e0e8d3425b75844e7044 Mon Sep 17 00:00:00 2001 From: Quercitron Date: Fri, 20 Jan 2017 04:20:43 +0300 Subject: [PATCH] * Hope of Ghirapur - Fix that ability could be activated if Hope of Ghirapur was removed from the battlefield and returned back (fixes #2808). --- .../src/mage/cards/h/HopeOfGhirapur.java | 41 +++++++------ .../cards/single/aer/HopeOfGhirapurTest.java | 59 +++++++++++++++++++ 2 files changed, 81 insertions(+), 19 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/aer/HopeOfGhirapurTest.java diff --git a/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java b/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java index 0dfb3029ca5..411652317cc 100644 --- a/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java +++ b/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java @@ -33,6 +33,7 @@ import java.util.Set; import java.util.UUID; import mage.MageInt; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -88,7 +89,8 @@ public class HopeOfGhirapur extends CardImpl { if (sourceObject != null) { ability.getTargets().clear(); FilterPlayer playerFilter = new FilterPlayer("player who was dealt combat damage by " + sourceObject.getIdName() + " this turn"); - playerFilter.add(new HopeOfGhirapurPlayerLostLifePredicate(ability.getSourceId())); + MageObjectReference sourceReference = new MageObjectReference(ability.getSourceId(), ability.getSourceObjectZoneChangeCounter(), game); + playerFilter.add(new HopeOfGhirapurPlayerLostLifePredicate(sourceReference)); ability.addTarget(new TargetPlayer(1, 1, false, playerFilter)); } } @@ -155,17 +157,17 @@ class HopeOfGhirapurCantCastEffect extends ContinuousRuleModifyingEffectImpl { class HopeOfGhirapurPlayerLostLifePredicate implements Predicate { - private final UUID sourceId; + private final MageObjectReference sourceReference; - public HopeOfGhirapurPlayerLostLifePredicate(UUID sourceId) { - this.sourceId = sourceId; + public HopeOfGhirapurPlayerLostLifePredicate(MageObjectReference sourceReference) { + this.sourceReference = sourceReference; } @Override public boolean apply(Player input, Game game) { HopeOfGhirapurCombatDamageWatcher watcher = (HopeOfGhirapurCombatDamageWatcher) game.getState().getWatchers().get(HopeOfGhirapurCombatDamageWatcher.class.getName()); if (watcher != null) { - return watcher.playerGotCombatDamage(sourceId, input.getId()); + return watcher.playerGotCombatDamage(sourceReference, input.getId()); } return false; } @@ -173,7 +175,7 @@ class HopeOfGhirapurPlayerLostLifePredicate implements Predicate { class HopeOfGhirapurCombatDamageWatcher extends Watcher { - private final HashMap> combatDamagedPlayers = new HashMap<>(); + private final HashMap> combatDamagedPlayers = new HashMap<>(); public HopeOfGhirapurCombatDamageWatcher() { super(HopeOfGhirapurCombatDamageWatcher.class.getName(), WatcherScope.GAME); @@ -181,10 +183,10 @@ class HopeOfGhirapurCombatDamageWatcher extends Watcher { public HopeOfGhirapurCombatDamageWatcher(final HopeOfGhirapurCombatDamageWatcher watcher) { super(watcher); - for (UUID objectId : watcher.combatDamagedPlayers.keySet()) { + for (MageObjectReference sourceReference : watcher.combatDamagedPlayers.keySet()) { Set players = new HashSet<>(); - players.addAll(watcher.combatDamagedPlayers.get(objectId)); - this.combatDamagedPlayers.put(objectId, players); + players.addAll(watcher.combatDamagedPlayers.get(sourceReference)); + this.combatDamagedPlayers.put(sourceReference, players); } } @@ -196,28 +198,29 @@ class HopeOfGhirapurCombatDamageWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { if (event.getType() == EventType.DAMAGED_PLAYER && ((DamagedPlayerEvent) event).isCombatDamage()) { + MageObjectReference sourceReference = new MageObjectReference(event.getSourceId(), game); Set players; - if (combatDamagedPlayers.containsKey(event.getSourceId())) { - players = combatDamagedPlayers.get(event.getSourceId()); + if (combatDamagedPlayers.containsKey(sourceReference)) { + players = combatDamagedPlayers.get(sourceReference); } else { players = new HashSet<>(); - combatDamagedPlayers.put(event.getSourceId(), players); + combatDamagedPlayers.put(sourceReference, players); } players.add(event.getTargetId()); } } /** - * Checks if the current object with sourceId has damaged the player during - * the current turn. The zoneChangeCounter will be taken into account. + * Checks if the current object has damaged the player during + * the current turn. * - * @param sourceId - * @param game + * @param objectReference + * @param playerId * @return */ - public boolean playerGotCombatDamage(UUID sourceId, UUID playerId) { - if (combatDamagedPlayers.containsKey(sourceId)) { - return combatDamagedPlayers.get(sourceId).contains(playerId); + public boolean playerGotCombatDamage(MageObjectReference objectReference, UUID playerId) { + if (combatDamagedPlayers.containsKey(objectReference)) { + return combatDamagedPlayers.get(objectReference).contains(playerId); } return false; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/aer/HopeOfGhirapurTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/aer/HopeOfGhirapurTest.java new file mode 100644 index 00000000000..b0340abb5b6 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/aer/HopeOfGhirapurTest.java @@ -0,0 +1,59 @@ +package org.mage.test.cards.single.aer; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author Quercitron + */ +public class HopeOfGhirapurTest extends CardTestPlayerBase { + + @Test + public void testThatNoncreatureSpellsCannotBeCast() { + addCard(Zone.BATTLEFIELD, playerA, "Hope of Ghirapur"); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + addCard(Zone.HAND, playerB, "Shock"); + + attack(1, playerA, "Hope of Ghirapur"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Sacrifice", playerB); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Shock", playerA); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + assertPermanentCount(playerA, "Hope of Ghirapur", 0); + } + + // Test that ability cannot be activated if after damage Hope of Ghirapur was removed + // from the battlefield and returned back. + @Test + public void testWhenHopeOfGhirapurWasRemovedAndReturnedBack() { + addCard(Zone.BATTLEFIELD, playerA, "Hope of Ghirapur"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.HAND, playerA, "Cloudshift"); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + addCard(Zone.HAND, playerB, "Shock"); + + attack(1, playerA, "Hope of Ghirapur"); + castSpell(1, PhaseStep.END_COMBAT, playerA, "Cloudshift", "Hope of Ghirapur"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Sacrifice", playerB); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Shock", playerA); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 18); + assertLife(playerB, 19); + assertPermanentCount(playerA, "Hope of Ghirapur", 1); + } + +}