diff --git a/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java b/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java index 38925586f8..fc4253b964 100644 --- a/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java +++ b/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java @@ -99,7 +99,7 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { boolean cardWasCycledThisTurn = false; boolean cardHasCycling = false; - if (!(((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) || game.isSimulation()) { + if (!(((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD)) { return false; } Player controller = game.getPlayer(source.getControllerId()); @@ -137,8 +137,7 @@ class AbandonedSarcophagusWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.CYCLE_CARD - && !game.isSimulation()) { + if (event.getType() == GameEvent.EventType.CYCLE_CARD) { Card card = game.getCard(event.getSourceId()); Player controller = game.getPlayer(event.getPlayerId()); if (card != null diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/KardurDoomscourgeAndKithkinMourncallerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/KardurDoomscourgeAndKithkinMourncallerTest.java new file mode 100644 index 0000000000..4895bca974 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/KardurDoomscourgeAndKithkinMourncallerTest.java @@ -0,0 +1,103 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.mage.test.cards.triggers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author jeffwadsworth + */ +public class KardurDoomscourgeAndKithkinMourncallerTest extends CardTestPlayerBase { + + @Test + public void testKDRemovedFromCombatViaRegenerateAbility() { + setStrictChooseMode(true); + // Kardur, Doomscourge: if an attacking creature dies, each opponent loses 1 life and you gain 1 life + addCard(Zone.BATTLEFIELD, playerA, "Kardur, Doomscourge"); + addCard(Zone.BATTLEFIELD, playerA, "Elvish Archers"); + addCard(Zone.BATTLEFIELD, playerB, "Serra Angel"); + addCard(Zone.HAND, playerA, "Regenerate"); + addCard(Zone.HAND, playerA, "Terror"); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Regenerate", "Elvish Archers"); + + attack(1, playerA, "Elvish Archers"); + block(1, playerB, "Serra Angel", "Elvish Archers"); // regeneration shield used up and EA is removed from combat + + castSpell(1, PhaseStep.END_COMBAT, playerA, "Terror", "Elvish Archers"); // still within the combat phase, the EA is destroyed/dies + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Elvish Archers", 1); + + // does not fire due to the Elvish Archers not in an attacking state + assertLife(playerA, 20); + assertLife(playerB, 20); + + } + + @Test + public void testSuccessfulKDTrigger() { + setStrictChooseMode(true); + // Kardur, Doomscourge: if an attacking creature dies, each opponent loses 1 life and you gain 1 life + addCard(Zone.BATTLEFIELD, playerA, "Kardur, Doomscourge"); + addCard(Zone.BATTLEFIELD, playerA, "Elvish Archers"); // 2/2 first strike + addCard(Zone.BATTLEFIELD, playerB, "Serra Angel"); // 4/4 vigilance + + attack(1, playerA, "Elvish Archers"); + block(1, playerB, "Serra Angel", "Elvish Archers"); // Elvish Archer dies causing KD to trigger + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Elvish Archers", 1); + + // successful fire so playerA gains 1 life and playerB loses 1 life + assertLife(playerA, 21); + assertLife(playerB, 19); + + } + + @Test + public void testKMTrigger() { + setStrictChooseMode(true); + // Kithkin Mourncaller: if an elf or kithkin dies, you may draw a card + addCard(Zone.BATTLEFIELD, playerA, "Kithkin Mourncaller"); + addCard(Zone.BATTLEFIELD, playerA, "Elvish Archers"); // 2/1 first strike + addCard(Zone.BATTLEFIELD, playerA, "Pearled Unicorn"); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Serra Angel"); // 4/4 vigilance + addCard(Zone.BATTLEFIELD, playerB, "Runeclaw Bear"); // 2/2 + addCard(Zone.LIBRARY, playerA, "Island", 2); // used for draw trigger + + attack(1, playerA, "Elvish Archers"); + attack(1, playerA, "Pearled Unicorn"); + block(1, playerB, "Serra Angel", "Elvish Archers"); // Elvish Achers will die and trigger KM + block(1, playerB, "Runeclaw Bear", "Pearled Unicorn"); // Pearled Unicorn will die but not trigger KM + + setChoice(playerA, "Yes"); // accept the drawing of a card from the single trigger (Elvish Archers "elf type") + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Elvish Archers", 1); + assertGraveyardCount(playerA, "Pearled Unicorn", 1); + + // successful fire due to dead Elvish Archers (elf) so playerA draws a card + assertHandCount(playerA, 1); + + } + +} diff --git a/Mage/src/main/java/mage/abilities/common/AttackingCreaturePutIntoGraveyardTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttackingCreaturePutIntoGraveyardTriggeredAbility.java index e0f7e1b84d..58f656fdd8 100644 --- a/Mage/src/main/java/mage/abilities/common/AttackingCreaturePutIntoGraveyardTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AttackingCreaturePutIntoGraveyardTriggeredAbility.java @@ -5,6 +5,7 @@ */ package mage.abilities.common; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; @@ -13,7 +14,6 @@ import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.events.GameEvent; -import static mage.game.events.GameEvent.EventType.DECLARE_ATTACKERS_STEP; import static mage.game.events.GameEvent.EventType.END_COMBAT_STEP_POST; import static mage.game.events.GameEvent.EventType.REMOVED_FROM_COMBAT; import static mage.game.events.GameEvent.EventType.ZONE_CHANGE; @@ -52,7 +52,7 @@ public class AttackingCreaturePutIntoGraveyardTriggeredAbility extends Triggered @Override public boolean checkEventType(GameEvent event, Game game) { switch (event.getType()) { - case DECLARE_ATTACKERS_STEP: + case ATTACKER_DECLARED: case END_COMBAT_STEP_POST: case ZONE_CHANGE: case REMOVED_FROM_COMBAT: @@ -65,13 +65,19 @@ public class AttackingCreaturePutIntoGraveyardTriggeredAbility extends Triggered @Override public boolean checkTrigger(GameEvent event, Game game) { switch (event.getType()) { - case DECLARE_ATTACKERS_STEP: - Permanent permanent = game.getPermanent(event.getTargetId()); + case ATTACKER_DECLARED: + Permanent permanent = game.getPermanent(event.getSourceId()); if (permanent != null && !filterPermanent.match(permanent, game)) { return false; } - game.getState().setValue(this.getSourceId() + "Attackers", game.getCombat().getAttackers()); + List attackersList = new ArrayList<>(); + List attackersListCopy = (List) game.getState().getValue(this.getSourceId() + "Attackers"); + if (attackersListCopy == null) { + attackersListCopy = attackersList; + } + attackersListCopy.add(event.getSourceId()); // add the filtered creature to the list + game.getState().setValue(this.getSourceId() + "Attackers", attackersListCopy); return false; case END_COMBAT_STEP_POST: game.getState().setValue(this.getSourceId() + "Attackers", null); @@ -94,11 +100,11 @@ public class AttackingCreaturePutIntoGraveyardTriggeredAbility extends Triggered } case REMOVED_FROM_COMBAT: // a card removed from combat is no longer an attacker or blocker so remove it from the list - List attackersList = (List) game.getState().getValue(this.getSourceId() + "Attackers"); - if (attackersList != null - && attackersList.contains(event.getTargetId())) { - attackersList.remove(event.getTargetId()); - game.getState().setValue(this.getSourceId() + "Attackers", attackersList); + List attackersListRFC = (List) game.getState().getValue(this.getSourceId() + "Attackers"); + if (attackersListRFC != null + && attackersListRFC.contains(event.getTargetId())) { + attackersListRFC.remove(event.getTargetId()); + game.getState().setValue(this.getSourceId() + "Attackers", attackersListRFC); } default: