From c31bf97440052941b0ac40935e9e6b47a2e31e7f Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 9 Aug 2016 13:14:29 +0200 Subject: [PATCH] * Fixed some problems if a creature has multiple madness abilities. --- .../FalkenrathGorger.java | 35 +++++++++-- .../cards/abilities/keywords/MadnessTest.java | 62 ++++++++++++++++++- .../continuous/GainControlAllEffect.java | 1 - .../abilities/keyword/MadnessAbility.java | 12 ++-- 4 files changed, 100 insertions(+), 10 deletions(-) diff --git a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/FalkenrathGorger.java b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/FalkenrathGorger.java index 5a939d0d5a..85bcd988c7 100644 --- a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/FalkenrathGorger.java +++ b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/FalkenrathGorger.java @@ -27,6 +27,7 @@ */ package mage.sets.shadowsoverinnistrad; +import java.util.HashMap; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; @@ -60,7 +61,18 @@ public class FalkenrathGorger extends CardImpl { this.subtype.add("Berserker"); this.power = new MageInt(2); this.toughness = new MageInt(1); - + /** + * 4/8/2016 Falkenrath Gorger’s ability only applies while it’s on the + * battlefield. If you discard it, it won’t give itself madness. + * 4/8/2016 If Falkenrath Gorger leaves the battlefield before the + * madness trigger has resolved for a Vampire card that gained madness + * with its ability, the madness ability will still let you cast that + * Vampire card for the appropriate cost even though it no longer has + * madness. 4/8/2016 If you discard a Vampire creature card that already + * has a madness ability, you’ll choose which madness ability exiles it. + * You may choose either the one it normally has or the one it gains + * from Falkenrath Gorger. + */ // Each Vampire creature card you own that isn't on the battlefield has madness. Its madness cost is equal to its mana cost. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new FalkenrathGorgerEffect())); } @@ -84,6 +96,8 @@ class FalkenrathGorgerEffect extends ContinuousEffectImpl { } + HashMap madnessAbilities = new HashMap<>(); // reuse the same ability for the same object + public FalkenrathGorgerEffect() { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); this.staticText = "Each Vampire creature card you own that isn't on the battlefield has madness. Its madness cost is equal to its mana cost"; @@ -91,6 +105,7 @@ class FalkenrathGorgerEffect extends ContinuousEffectImpl { public FalkenrathGorgerEffect(final FalkenrathGorgerEffect effect) { super(effect); + this.madnessAbilities.putAll(effect.madnessAbilities); } @Override @@ -102,25 +117,37 @@ class FalkenrathGorgerEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { + HashMap usedMadnessAbilities = new HashMap<>(); // hand for (Card card : controller.getHand().getCards(filter, game)) { - game.getState().addOtherAbility(card, new MadnessAbility(card, card.getSpellAbility().getManaCosts())); + addMadnessToCard(game, card, usedMadnessAbilities); } // graveyard for (Card card : controller.getGraveyard().getCards(filter, game)) { - game.getState().addOtherAbility(card, new MadnessAbility(card, card.getSpellAbility().getManaCosts())); + addMadnessToCard(game, card, usedMadnessAbilities); } // Exile for (Card card : game.getExile().getAllCards(game)) { if (filter.match(card, source.getSourceId(), controller.getId(), game)) { if (card.getOwnerId().equals(controller.getId())) { - game.getState().addOtherAbility(card, new MadnessAbility(card, card.getSpellAbility().getManaCosts())); + addMadnessToCard(game, card, usedMadnessAbilities); } } } + madnessAbilities.clear(); + madnessAbilities.putAll(usedMadnessAbilities); return true; } return false; } + + private void addMadnessToCard(Game game, Card card, HashMap usedMadnessAbilities) { + MadnessAbility ability = madnessAbilities.get(card.getId()); + if (ability == null) { + ability = new MadnessAbility(card, card.getSpellAbility().getManaCosts()); + } + game.getState().addOtherAbility(card, ability, false); + usedMadnessAbilities.put(card.getId(), ability); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MadnessTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MadnessTest.java index f21b2e3256..d44ac07883 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MadnessTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MadnessTest.java @@ -27,6 +27,7 @@ */ package org.mage.test.cards.abilities.keywords; +import mage.abilities.keyword.HasteAbility; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; @@ -111,7 +112,7 @@ public class MadnessTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Falkenrath Gorger", 1); // Sacrifice a creature: Vampire Aristocrat gets +2/+2 until end of turn. - addCard(Zone.HAND, playerA, "Vampire Aristocrat"); + addCard(Zone.HAND, playerA, "Vampire Aristocrat"); // {2}{B} addCard(Zone.BATTLEFIELD, playerB, "Swamp", 6); // Target player discards two cards. If you cast this spell during your main phase, that player discards four cards instead. @@ -157,4 +158,63 @@ public class MadnessTest extends CardTestPlayerBase { } + /** + * Falkenrath Gorger + Asylum Visitor (& probably any Vampire with printed + * Madness) + Olivia, Mobilized for War - Haste part of the triggered effect + * may not affect entering Vampire properly, please read further for more + * details. + * + * When I cast Falkenrath Gorger and then discarded Asylum Visitor with + * Olivia, Mobilized for War 's triggered ability, two Madness pop-ups + * appeared, I have used the first one, Asylum Visitor entered the + * battlefield, Olivia triggered again and I used the ability to give Asylum + * Visitor Haste and +1/+1. Then the second Madness trigger resolved for the + * Visitor and I have cancelled it (by choosing "No" at first pop-up, but + * from what I have tested, the choice at this point does not matter). + * Asylum Visitor lost Haste and was both visually and functionally affected + * by Summoning Sickness. + * + * I was able to avoid this issue by cancelling the first Madness pop-up and + * then using only the second one. + */ + @Test + public void testFalkenrathGorgerWithAsylumVisitor() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + + // Flying + // Whenever another creature enters the battlefield under your control, you may discard a card. If you do, put a +1/+1 counter on that creature, + // it gains haste until end of turn, and it becomes a Vampire in addition to its other types. + addCard(Zone.BATTLEFIELD, playerA, "Olivia, Mobilized for War", 1); + + // Each Vampire creature card you own that isn't on the battlefield has madness. Its madness cost is equal to its mana cost. + addCard(Zone.HAND, playerA, "Falkenrath Gorger", 1); // Creature Vampire 2/1 {R} + // At the beginning of each player's upkeep, if that player has no cards in hand, you draw a card and you lose 1 life. + // Madness {1}{B} + addCard(Zone.HAND, playerA, "Asylum Visitor"); // Creature Vampire 3/1 {1}{B} + addCard(Zone.HAND, playerA, "Forest"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Falkenrath Gorger"); + setChoice(playerA, "Yes"); // Discard a card and put a +1/+1 counter on that creature, it gains haste until end of turn, and it becomes a Vampire in addition to its other types? + setChoice(playerA, "Asylum Visitor"); + setChoice(playerA, "Yes"); // When this card is exiled this way, you may cast it by paying {1}{B} instead of putting it into your graveyard. + setChoice(playerA, "Yes"); // Cast Asylum Visitor by madness? + setChoice(playerA, "Yes"); // Discard a card and put a +1/+1 counter on that creature, it gains haste until end of turn, and it becomes a Vampire in addition to its other types? + setChoice(playerA, "Forest"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Falkenrath Gorger", 1); + assertPermanentCount(playerA, "Asylum Visitor", 1); + + assertPowerToughness(playerA, "Falkenrath Gorger", 3, 2); + assertAbility(playerA, "Falkenrath Gorger", HasteAbility.getInstance(), true); + + assertPowerToughness(playerA, "Asylum Visitor", 4, 2); + assertAbility(playerA, "Asylum Visitor", HasteAbility.getInstance(), true); + + assertGraveyardCount(playerA, "Forest", 1); + + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllEffect.java index f8ea2cef25..9cbe784ae8 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllEffect.java @@ -54,6 +54,5 @@ public class GainControlAllEffect extends ContinuousEffectImpl { StringBuilder sb = new StringBuilder(); sb.append("Gain control of ").append(filter.getMessage()); return sb.toString(); - //return "Gain control of " + filter; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java index 87dc63d91f..010126bd44 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java @@ -52,7 +52,7 @@ public class MadnessAbility extends StaticAbility { @SuppressWarnings("unchecked") public MadnessAbility(Card card, ManaCosts madnessCost) { super(Zone.HAND, new MadnessReplacementEffect((ManaCosts) madnessCost)); - addSubAbility(new MadnessTriggeredAbility((ManaCosts) madnessCost)); + addSubAbility(new MadnessTriggeredAbility((ManaCosts) madnessCost, getOriginalId())); rule = "Madness " + madnessCost.getText() + " (If you discard this card, discard it into exile. When you do, cast it for its madness cost or put it into your graveyard.)"; } @@ -105,7 +105,8 @@ class MadnessReplacementEffect extends ReplacementEffectImpl { if (card != null) { if (controller.moveCardToExileWithInfo(card, source.getSourceId(), "Madness", source.getSourceId(), game, ((ZoneChangeEvent) event).getFromZone(), true)) { game.applyEffects(); // needed to add Madness ability to cards (e.g. by Falkenrath Gorger) - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.MADNESS_CARD_EXILED, card.getId(), card.getId(), controller.getId())); + GameEvent gameEvent = GameEvent.getEvent(GameEvent.EventType.MADNESS_CARD_EXILED, card.getId(), source.getOriginalId(), controller.getId()); + game.fireEvent(gameEvent); } return true; } @@ -134,14 +135,17 @@ class MadnessTriggeredAbility extends TriggeredAbilityImpl { //This array holds the Id's of all of the cards that activated madness private static ArrayList activatedIds = new ArrayList<>(); + private final UUID madnessOriginalId; - MadnessTriggeredAbility(ManaCosts madnessCost) { + MadnessTriggeredAbility(ManaCosts madnessCost, UUID madnessOriginalId) { super(Zone.EXILED, new MadnessCastEffect(madnessCost), true); + this.madnessOriginalId = madnessOriginalId; this.setRuleVisible(false); } MadnessTriggeredAbility(final MadnessTriggeredAbility ability) { super(ability); + this.madnessOriginalId = ability.madnessOriginalId; } @Override @@ -156,7 +160,7 @@ class MadnessTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getTargetId().equals(getSourceId()); + return event.getSourceId().equals(madnessOriginalId); // Check that the event was from the connected replacement effect } @Override