From 96e88d73509f0af81ed900c8944e3cdc1ece8c87 Mon Sep 17 00:00:00 2001 From: fireshoes Date: Tue, 12 Jul 2016 23:10:37 -0500 Subject: [PATCH 01/15] [EMN] Fixed tooltip text on some green, gold, artifact, and land cards. Added Emrakul's Evangel's missing TapSourceCost. --- .../src/mage/sets/eldritchmoon/CropSigil.java | 8 ++--- .../sets/eldritchmoon/EmrakulsEvangel.java | 33 ++++++++++--------- .../eldritchmoon/GeierReachSanitarium.java | 5 ++- .../mage/sets/eldritchmoon/GrimFlayer.java | 2 +- .../sets/eldritchmoon/IshkanahGrafwidow.java | 2 +- .../mage/sets/eldritchmoon/PrimalDruid.java | 5 ++- .../sets/eldritchmoon/SpiritOfTheHunt.java | 5 ++- .../sets/eldritchmoon/StitchersGraft.java | 6 ++-- .../mage/sets/eldritchmoon/WaxingMoon.java | 6 +++- ...nControllersNextUntapStepTargetEffect.java | 2 +- 10 files changed, 46 insertions(+), 28 deletions(-) diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java b/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java index d6e8eb05eb4..75c61fd2103 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java @@ -34,7 +34,6 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; @@ -69,9 +68,10 @@ public class CropSigil extends CardImpl { // Delirium — {2}{G}, Sacrifice Crop Sigil: Return up to one target creature card and up to one target land card from your graveyard to your hand. // Activate this ability only if there are four or more card types among cards in your graveyard. - Effect effect = new ReturnToHandTargetEffect(true, true); - effect.setText("Return up to one target creature card and up to one target land card from your graveyard to your hand"); - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{2}{G}"), DeliriumCondition.getInstance()); + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(true, true), new ManaCostsImpl<>("{2}{G}"), + DeliriumCondition.getInstance(), + "Delirium — {2}{G}, Sacrifice {this}: Return up to one target creature card and up to one target land card from your graveyard to your hand. " + + "Activate this ability only if there are four or more card types among cards in your graveyard"); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCardInGraveyard(0, 1, filterCreature)); ability.addTarget(new TargetCardInGraveyard(0, 1, filterLand)); diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/EmrakulsEvangel.java b/Mage.Sets/src/mage/sets/eldritchmoon/EmrakulsEvangel.java index 75243bc5060..515d0160b6d 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/EmrakulsEvangel.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/EmrakulsEvangel.java @@ -33,6 +33,7 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -54,7 +55,7 @@ import mage.target.common.TargetControlledCreaturePermanent; * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public class EmrakulsEvangel extends CardImpl { - + public EmrakulsEvangel(UUID ownerId) { super(ownerId, 156, "Emrakul's Evangel", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.expansionSetCode = "EMN"; @@ -63,9 +64,11 @@ public class EmrakulsEvangel extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(2); - // {T}, Sacrifice Emrakul's Evangel and any number of other non-Eldrazi creatures: + // {T}, Sacrifice Emrakul's Evangel and any number of other non-Eldrazi creatures: // Put a 3/2 colorless Eldrazi Horror creature token onto the battlefield for each creature sacrificed this way. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new EmrakulsEvangelEffect(), new EmrakulsEvangelCost())); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new EmrakulsEvangelEffect(), new TapSourceCost()); + ability.addCost(new EmrakulsEvangelCost()); + this.addAbility(ability); } public EmrakulsEvangel(final EmrakulsEvangel card) { @@ -79,14 +82,14 @@ public class EmrakulsEvangel extends CardImpl { } class EmrakulsEvangelCost extends CostImpl { - + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("non-Eldrazi creatures you control"); - + static { filter.add(new AnotherPredicate()); filter.add(Predicates.not(new SubtypePredicate("Eldrazi"))); - } - + } + private int numSacrificed = 1; // always sacrifices self at least public EmrakulsEvangelCost() { @@ -117,7 +120,7 @@ class EmrakulsEvangelCost extends CostImpl { } return paid; } - + public int getNumSacrificed() { return numSacrificed; } @@ -125,7 +128,7 @@ class EmrakulsEvangelCost extends CostImpl { @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { Permanent permanent = game.getPermanent(sourceId); - + return permanent != null && game.getPlayer(controllerId).canPaySacrificeCost(permanent, sourceId, controllerId, game); } @@ -136,25 +139,25 @@ class EmrakulsEvangelCost extends CostImpl { } class EmrakulsEvangelEffect extends OneShotEffect { - + EmrakulsEvangelEffect() { super(Outcome.Sacrifice); - this.staticText = "Sacrifice {this} and any number of other non-Eldrazi creatures: Put a 3/2 colorless Eldrazi Horror creature token onto the battlefield for each creature sacrificed this way."; + this.staticText = "Put a 3/2 colorless Eldrazi Horror creature token onto the battlefield for each creature sacrificed this way."; } - + EmrakulsEvangelEffect(final EmrakulsEvangelEffect effect) { super(effect); } - + @Override public EmrakulsEvangelEffect copy() { return new EmrakulsEvangelEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { + if (player != null) { int tokensToCreate = 0; for (Cost cost : source.getCosts()) { if (cost instanceof EmrakulsEvangelCost) { diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/GeierReachSanitarium.java b/Mage.Sets/src/mage/sets/eldritchmoon/GeierReachSanitarium.java index 84e493f7388..f0bdff485f2 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/GeierReachSanitarium.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/GeierReachSanitarium.java @@ -32,6 +32,7 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardAllEffect; import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; import mage.abilities.mana.ColorlessManaAbility; @@ -56,7 +57,9 @@ public class GeierReachSanitarium extends CardImpl { // {2}, {T}: Each player draws a card, then discards a card. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardAllEffect(1), new GenericManaCost(2)); - ability.addEffect(new DiscardEachPlayerEffect()); + Effect effect = new DiscardEachPlayerEffect(); + effect.setText(", then discards a card"); + ability.addEffect(effect); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/GrimFlayer.java b/Mage.Sets/src/mage/sets/eldritchmoon/GrimFlayer.java index f9776940cc2..1cd7057e746 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/GrimFlayer.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/GrimFlayer.java @@ -66,7 +66,7 @@ public class GrimFlayer extends CardImpl { // and the rest back on top of your library in any order. Effect effect = new LookLibraryAndPickControllerEffect( new StaticValue(3), false, new StaticValue(3), new FilterCard(), Zone.LIBRARY, true, false, true, Zone.GRAVEYARD, false); - effect.setText("look at the top three cards of your library. Put any number of them into your graveyard and the rest on top of your library in any order"); + effect.setText("look at the top three cards of your library. Put any number of them into your graveyard and the rest back on top of your library in any order"); this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(effect, false)); // Delirium — Grim Flayer gets +2/+2 as long as there are four or more card types among cards in your graveyard. diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java b/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java index 82d5d9d19f2..bc9cdc5cd9f 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java @@ -54,7 +54,7 @@ import mage.target.common.TargetOpponent; */ public class IshkanahGrafwidow extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("each Spider you control"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Spider you control"); static { filter.add(new SubtypePredicate("Spider")); diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/PrimalDruid.java b/Mage.Sets/src/mage/sets/eldritchmoon/PrimalDruid.java index 48e367f5ab1..3792e57a92c 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/PrimalDruid.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/PrimalDruid.java @@ -30,6 +30,7 @@ package mage.sets.eldritchmoon; import java.util.UUID; import mage.MageInt; import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -52,7 +53,9 @@ public class PrimalDruid extends CardImpl { this.toughness = new MageInt(3); // When Primal Druid dies, you may search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library. - this.addAbility(new DiesTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterBasicLandCard()), true), true)); + Effect effect = new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterBasicLandCard()), true); + effect.setText("you may search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library"); + this.addAbility(new DiesTriggeredAbility(effect, true)); } diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java b/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java index 7a9a50b9d27..04dc445bd5e 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java @@ -30,6 +30,7 @@ package mage.sets.eldritchmoon; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; @@ -65,7 +66,9 @@ public class SpiritOfTheHunt extends CardImpl { this.addAbility(FlashAbility.getInstance()); // When Spirit of the Hunt enters the battlefield, each other creature you control that's a Wolf or a Werewolf gets +0/+3 until end of turn. - this.addAbility(new EntersBattlefieldTriggeredAbility(new BoostControlledEffect(0, 3, Duration.EndOfTurn, filter, true), false)); + Effect effect = new BoostControlledEffect(0, 3, Duration.EndOfTurn, filter, true); + effect.setText("each other creature you control that's a Wolf or a Werewolf gets +0/+3 until end of turn"); + this.addAbility(new EntersBattlefieldTriggeredAbility(effect, false)); } public SpiritOfTheHunt(final SpiritOfTheHunt card) { diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java b/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java index 65876b2e08f..33f3f77342d 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java @@ -45,8 +45,8 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; /** * @@ -68,7 +68,9 @@ public class StitchersGraft extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); // Whenever Stitcher's Graft becomes unattached from a permanent, sacrifice that permanent. - this.addAbility(new UnattachedTriggeredAbility(new SacrificeEquippedEffect(), false)); + effect = new SacrificeEquippedEffect(); + effect.setText("sacrifice that permanent"); + this.addAbility(new UnattachedTriggeredAbility(effect, false)); // Equip {2} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2))); diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/WaxingMoon.java b/Mage.Sets/src/mage/sets/eldritchmoon/WaxingMoon.java index 480cb9fa307..3a7e5d9f774 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/WaxingMoon.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/WaxingMoon.java @@ -28,6 +28,7 @@ package mage.sets.eldritchmoon; import java.util.UUID; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.TransformTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.TrampleAbility; @@ -60,8 +61,11 @@ public class WaxingMoon extends CardImpl { this.expansionSetCode = "EMN"; // Transform up to one target Werewolf you control. - this.getSpellAbility().addEffect(new TransformTargetEffect(false)); + Effect effect = new TransformTargetEffect(false); + effect.setText("Transform up to one target Werewolf you control"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + // Creatures you control gain trample until end of turn. this.getSpellAbility().addEffect(new GainAbilityAllEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent(), "Creatures you control gain trample until end of turn")); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java index 54df18dd219..f59773e1e4e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java @@ -159,7 +159,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR return staticText; } if (targetName != null && targetName.length() > 0) { - if (targetName.equals("Those creatures")) { + if (targetName.equals("Those creatures") || targetName.equals("They")) { return targetName + " don't untap during their controller's next untap step"; } else return targetName + " doesn't untap during its controller's next untap step"; From 8ded1981fb08e1f227d46c411201f11e5b37ca5c Mon Sep 17 00:00:00 2001 From: drmDev Date: Wed, 13 Jul 2016 04:50:57 -0400 Subject: [PATCH 02/15] Gideon Champion of Justice bugfix fixes #2069 --- .../src/mage/sets/gatecrash/GideonChampionOfJustice.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java index debb217f509..6e9e6fb1766 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java +++ b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java @@ -74,7 +74,7 @@ public class GideonChampionOfJustice extends CardImpl { this.addAbility(ability1); // 0: Until end of turn, Gideon becomes an indestructible Human Soldier creature with power and toughness each equal to the number of loyalty counters on him. He's still a planeswalker. Prevent all damage that would be dealt to him this turn. - LoyaltyAbility ability2 = new LoyaltyAbility(new BecomesCreatureSourceEffect(new GideonChampionOfJusticeToken(), "planeswalker", Duration.EndOfTurn), 0); + LoyaltyAbility ability2 = new LoyaltyAbility(new BecomesCreatureSourceEffect(new GideonChampionOfJusticeToken(), "planeswalker", Duration.EndOfTurn, false, true), 0); ability2.addEffect(new PreventAllDamageToSourceEffect(Duration.EndOfTurn)); this.addAbility(ability2); @@ -129,9 +129,11 @@ class GideonChampionOfJusticeToken extends Token { subtype.add("Soldier"); power = new MageInt(0); toughness = new MageInt(0); - + this.addAbility(IndestructibleAbility.getInstance()); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CountersCount(CounterType.LOYALTY), Duration.WhileOnBattlefield))); + + CountersCount loyaltyCount = new CountersCount(CounterType.LOYALTY); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(loyaltyCount, Duration.WhileOnBattlefield))); } } From 0670b24f22aa55d3fbc707069079a4762f9757dc Mon Sep 17 00:00:00 2001 From: drmDev Date: Wed, 13 Jul 2016 05:27:32 -0400 Subject: [PATCH 03/15] Reverting gideon change (no more CDA). added junit test demonstrating issue #2069 --- .../gatecrash/GideonChampionOfJustice.java | 2 +- .../test/cards/planeswalker/GideonTest.java | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java index 6e9e6fb1766..c28565c4edc 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java +++ b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java @@ -74,7 +74,7 @@ public class GideonChampionOfJustice extends CardImpl { this.addAbility(ability1); // 0: Until end of turn, Gideon becomes an indestructible Human Soldier creature with power and toughness each equal to the number of loyalty counters on him. He's still a planeswalker. Prevent all damage that would be dealt to him this turn. - LoyaltyAbility ability2 = new LoyaltyAbility(new BecomesCreatureSourceEffect(new GideonChampionOfJusticeToken(), "planeswalker", Duration.EndOfTurn, false, true), 0); + LoyaltyAbility ability2 = new LoyaltyAbility(new BecomesCreatureSourceEffect(new GideonChampionOfJusticeToken(), "planeswalker", Duration.EndOfTurn, false, false), 0); ability2.addEffect(new PreventAllDamageToSourceEffect(Duration.EndOfTurn)); this.addAbility(ability2); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java index 850f102ffb5..4518ae54d70 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java @@ -75,5 +75,31 @@ public class GideonTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Silvercoat Lion", 1); assertAbility(playerB, "Silvercoat Lion", IndestructibleAbility.getInstance(), false); } + + /* + * Reported bug: When Gideon, Champion of Justice uses his +0 ability to become a creature, + * he is immediately sent to the grave instead. + */ + @Test + public void testGideonChampionOfJusticeSecondAbility() { + + /* + Gideon, Champion of Justice {2}{W}{W} - 4 Loyalty + 0: Until end of turn, Gideon, Champion of Justice becomes a Human Soldier creature with power and toughness + each equal to the number of loyalty counters on him and gains indestructible. He's still a planeswalker. + Prevent all damage that would be dealt to him this turn. + */ + addCard(Zone.BATTLEFIELD, playerA, "Gideon, Champion of Justice", 1); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+0: Until end of turn"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Gideon, Champion of Justice", 0); + assertPermanentCount(playerA, "Gideon, Champion of Justice", 1); + assertPowerToughness(playerA, "Gideon, Champion of Justice", 4, 4); + assertCounterCount(playerA, "Gideon, Champion of Justice", CounterType.LOYALTY, 4); + + } } From 87296b56c3943ec089e7b222260735aa1d873fe9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 13 Jul 2016 11:45:31 +0200 Subject: [PATCH 04/15] * Tamiyo, Field Researcher - Fixed that only one card was drawn from +1 ability if both target creatures did combat damage. --- .../eldritchmoon/TamiyoFieldResearcher.java | 2 +- .../test/cards/planeswalker/TamiyoTest.java | 67 +++++++++---------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/TamiyoFieldResearcher.java b/Mage.Sets/src/mage/sets/eldritchmoon/TamiyoFieldResearcher.java index 2e8464303c2..c79567d3a14 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/TamiyoFieldResearcher.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/TamiyoFieldResearcher.java @@ -157,7 +157,7 @@ class TamiyoFieldResearcherDelayedTriggeredAbility extends DelayedTriggeredAbili private List creatures; public TamiyoFieldResearcherDelayedTriggeredAbility(List creatures) { - super(new DrawCardSourceControllerEffect(1), Duration.UntilYourNextTurn); + super(new DrawCardSourceControllerEffect(1), Duration.UntilYourNextTurn, false); this.creatures = creatures; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java index a22a34506d8..bc7b5689323 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java @@ -29,7 +29,6 @@ package org.mage.test.cards.planeswalker; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -40,120 +39,120 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class TamiyoTest extends CardTestPlayerBase { /* - * Reported bug: I activated Tamiyo's +1 ability on a 5/5 Gideon and his 2/2 Knight Ally, but when they both attacked + * Reported bug: I activated Tamiyo's +1 ability on a 5/5 Gideon and his 2/2 Knight Ally, but when they both attacked * and dealt damage I only drew one card when I'm pretty sure I was supposed to draw for each of the two. */ @Test public void testFieldResearcherFirstEffectOnGideon() { - + // Tamiyo, Field Researcher {1}{G}{W}{U} - 4 loyalty - // +1: Choose up to two target creatures. Until your next turn, + // +1: Choose up to two target creatures. Until your next turn, // whenever either of those creatures deals combat damage, you draw a card. addCard(Zone.BATTLEFIELD, playerA, "Tamiyo, Field Researcher", 1); - + /* Gideon, Ally of Zendikar {2}{W}{W} - 4 loyalty - * +1: Until end of turn, Gideon, Ally of Zendikar becomes a 5/5 Human Soldier Ally creature with indestructible + * +1: Until end of turn, Gideon, Ally of Zendikar becomes a 5/5 Human Soldier Ally creature with indestructible * that's still a planeswalker. Prevent all damage that would be dealt to him this turn. * 0: Put a 2/2 white Knight Ally creature token onto the battlefield. **/ addCard(Zone.BATTLEFIELD, playerA, "Gideon, Ally of Zendikar", 1); - + // put 2/2 knight ally token on battlefield activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+0: Put a"); - + // next, activate Gideon to make him a 5/5 human soldier ally creature activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Until end of turn"); // finally, use Tamiyo +1 on both creatures activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Choose up to two"); addTarget(playerA, "Knight Ally^Gideon, Ally of Zendikar"); // both token and Gideon as creature - + // attack with both unblocked - attack(3, playerA, "Knight Ally"); + attack(3, playerA, "Knight Ally"); attack(3, playerA, "Gideon, Ally of Zendikar"); - + setStopAt(3, PhaseStep.END_COMBAT); - execute(); - + execute(); + assertLife(playerB, 13); // 5 + 2 damage, 20 - 7 = 13 assertPermanentCount(playerA, "Tamiyo, Field Researcher", 1); assertPermanentCount(playerA, "Gideon, Ally of Zendikar", 1); assertPermanentCount(playerA, "Knight Ally", 1); assertHandCount(playerA, 3); // two cards drawn from each creature dealing damage + 1 card drawn on turn } - + /* * Testing more basic scenario with Tamiyo, Field of Researcher +1 effect */ @Test public void testFieldResearcherFirstEffectSimpleCreatureAttacks() { - + // Tamiyo, Field Researcher {1}{G}{W}{U} - 4 loyalty - // +1: Choose up to two target creatures. Until your next turn, + // +1: Choose up to two target creatures. Until your next turn, // whenever either of those creatures deals combat damage, you draw a card. addCard(Zone.BATTLEFIELD, playerA, "Tamiyo, Field Researcher", 1); - + addCard(Zone.BATTLEFIELD, playerA, "Bronze Sable", 1); // 2/1 activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Choose up to two"); addTarget(playerA, "Bronze Sable"); - + attack(1, playerA, "Bronze Sable"); - + setStopAt(1, PhaseStep.END_COMBAT); execute(); - + assertLife(playerB, 18); assertHandCount(playerA, 1); } - + /* * Testing more basic scenario with Tamiyo, Field of Researcher +1 effect */ @Test public void testFieldResearcherFirstEffectSimpleCreaturesAttacks() { - + // Tamiyo, Field Researcher {1}{G}{W}{U} - 4 loyalty - // +1: Choose up to two target creatures. Until your next turn, + // +1: Choose up to two target creatures. Until your next turn, // whenever either of those creatures deals combat damage, you draw a card. addCard(Zone.BATTLEFIELD, playerA, "Tamiyo, Field Researcher", 1); - + addCard(Zone.BATTLEFIELD, playerA, "Bronze Sable", 1); // 2/1 addCard(Zone.BATTLEFIELD, playerA, "Sylvan Advocate", 1); // 2/3 activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Choose up to two"); addTarget(playerA, "Bronze Sable^Sylvan Advocate"); - + attack(1, playerA, "Bronze Sable"); attack(1, playerA, "Sylvan Advocate"); - + setStopAt(1, PhaseStep.END_COMBAT); execute(); - + assertLife(playerB, 16); assertHandCount(playerA, 2); } - + /* * Testing more basic scenarios with Tamiyo, Field of Researcher +1 effect */ @Test public void testFieldResearcherFirstEffectAttackAndBlock() { - + // Tamiyo, Field Researcher {1}{G}{W}{U} - 4 loyalty - // +1: Choose up to two target creatures. Until your next turn, + // +1: Choose up to two target creatures. Until your next turn, // whenever either of those creatures deals combat damage, you draw a card. addCard(Zone.BATTLEFIELD, playerA, "Tamiyo, Field Researcher", 1); - + addCard(Zone.BATTLEFIELD, playerA, "Sylvan Advocate", 1); // 2/3 addCard(Zone.BATTLEFIELD, playerB, "Memnite", 1); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Choose up to two"); addTarget(playerA, "Sylvan Advocate"); - + attack(1, playerA, "Sylvan Advocate"); attack(2, playerB, "Memnite"); block(2, playerA, "Sylvan Advocate", "Memnite"); - + setStopAt(2, PhaseStep.END_COMBAT); execute(); - + assertLife(playerB, 18); assertHandCount(playerA, 2); // Sylvan Advocate dealt combat damage twice } From e1d26e61c691128794eebaf1041fef159cff6c86 Mon Sep 17 00:00:00 2001 From: drmDev Date: Wed, 13 Jul 2016 06:17:06 -0400 Subject: [PATCH 05/15] Test for Urza's Incubator bug. see #2070 --- .../test/cards/single/UrzasIncubatorTest.java | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/UrzasIncubatorTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/UrzasIncubatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/UrzasIncubatorTest.java new file mode 100644 index 00000000000..86daec971b9 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/UrzasIncubatorTest.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.single; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) + */ +public class UrzasIncubatorTest extends CardTestPlayerBase { + + /* + * Reported bug: Urza's Incubator does not reduce the cost of Eldrazi creatures + */ + @Test + public void testEldraziCostReduction() { + + /* + Urza's Incubator (3) Artifact + As Urza's Incubator enters the battlefield, choose a creature type. + Creature spells of the chosen type cost 2 less to cast. + */ + addCard(Zone.HAND, playerA, "Urza's Incubator", 1); + addCard(Zone.HAND, playerA, "Eldrazi Displacer", 1); // {2}{W} eldrazi 3/3 + addCard(Zone.HAND, playerA, "Eldrazi Mimic", 2); // {2} eldrazi 2/1 + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Urza's Incubator"); // taps 3 plains + setChoice(playerA, "Eldrazi"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Eldrazi Displacer"); // taps last plains + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Eldrazi Mimic"); // both mimics should be free + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Eldrazi Mimic"); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Urza's Incubator", 1); + assertPermanentCount(playerA, "Eldrazi Displacer", 1); + assertPermanentCount(playerA, "Eldrazi Mimic", 2); + } + + /* + * Test to make sure incubator only reduces generic cost. Cards with <> requirement + * still require specific colorless mana to cast. + */ + @Test + public void testEldraziCostReductionWastesRequirement() { + + /* + Urza's Incubator (3) Artifact + As Urza's Incubator enters the battlefield, choose a creature type. + Creature spells of the chosen type cost 2 less to cast. + */ + addCard(Zone.HAND, playerA, "Urza's Incubator", 1); + addCard(Zone.HAND, playerA, "Thought-Knot Seer", 1); // {3}{<>} eldrazi 4/4 + addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Urza's Incubator"); // taps 3 plains + setChoice(playerA, "Eldrazi"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Thought-Knot Seer"); // 2 plains remaining, but <> required + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Urza's Incubator", 1); + assertPermanentCount(playerA, "Thought-Knot Seer", 0); // should not be able to cast + } +} From 20fa414838daec13931d3cf9291f82fd53081d51 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 13 Jul 2016 12:25:54 +0200 Subject: [PATCH 06/15] * Gideon, Champion of Justice - Fixed a bug that Gideon dies if its ability to make it a creature was used. --- .../gatecrash/GideonChampionOfJustice.java | 13 +++----- .../test/cards/planeswalker/GideonTest.java | 23 +++++++------ .../BecomesCreatureSourceEffect.java | 32 +++++++++++++------ 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java index c28565c4edc..75875b97e91 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java +++ b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java @@ -32,13 +32,11 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; -import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.CountersCount; import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.PreventAllDamageToSourceEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; -import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; @@ -46,7 +44,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; @@ -74,7 +71,9 @@ public class GideonChampionOfJustice extends CardImpl { this.addAbility(ability1); // 0: Until end of turn, Gideon becomes an indestructible Human Soldier creature with power and toughness each equal to the number of loyalty counters on him. He's still a planeswalker. Prevent all damage that would be dealt to him this turn. - LoyaltyAbility ability2 = new LoyaltyAbility(new BecomesCreatureSourceEffect(new GideonChampionOfJusticeToken(), "planeswalker", Duration.EndOfTurn, false, false), 0); + CountersCount loyaltyCount = new CountersCount(CounterType.LOYALTY); + LoyaltyAbility ability2 = new LoyaltyAbility(new BecomesCreatureSourceEffect( + new GideonChampionOfJusticeToken(), "planeswalker", Duration.EndOfTurn, false, false, loyaltyCount, loyaltyCount), 0); ability2.addEffect(new PreventAllDamageToSourceEffect(Duration.EndOfTurn)); this.addAbility(ability2); @@ -129,11 +128,9 @@ class GideonChampionOfJusticeToken extends Token { subtype.add("Soldier"); power = new MageInt(0); toughness = new MageInt(0); - + this.addAbility(IndestructibleAbility.getInstance()); - - CountersCount loyaltyCount = new CountersCount(CounterType.LOYALTY); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(loyaltyCount, Duration.WhileOnBattlefield))); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java index 4518ae54d70..78d4d81a443 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java @@ -75,31 +75,36 @@ public class GideonTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Silvercoat Lion", 1); assertAbility(playerB, "Silvercoat Lion", IndestructibleAbility.getInstance(), false); } - + /* * Reported bug: When Gideon, Champion of Justice uses his +0 ability to become a creature, * he is immediately sent to the grave instead. - */ + */ @Test public void testGideonChampionOfJusticeSecondAbility() { - + /* Gideon, Champion of Justice {2}{W}{W} - 4 Loyalty - 0: Until end of turn, Gideon, Champion of Justice becomes a Human Soldier creature with power and toughness - each equal to the number of loyalty counters on him and gains indestructible. He's still a planeswalker. + +1: Put a loyalty counter on Gideon, Champion of Justice for each creature target opponent controls. + + 0: Until end of turn, Gideon, Champion of Justice becomes a Human Soldier creature with power and toughness + each equal to the number of loyalty counters on him and gains indestructible. He's still a planeswalker. Prevent all damage that would be dealt to him this turn. - */ + LoyaltyAbility ability1 = new LoyaltyAbility( + + -15: Exile all other permanents. + */ addCard(Zone.BATTLEFIELD, playerA, "Gideon, Champion of Justice", 1); - + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+0: Until end of turn"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + assertGraveyardCount(playerA, "Gideon, Champion of Justice", 0); assertPermanentCount(playerA, "Gideon, Champion of Justice", 1); assertPowerToughness(playerA, "Gideon, Champion of Justice", 4, 4); assertCounterCount(playerA, "Gideon, Champion of Justice", CounterType.LOYALTY, 4); - + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java index c8606d07b8b..507fa018039 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java @@ -27,9 +27,9 @@ */ package mage.abilities.effects.common.continuous; -import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.repository.CardRepository; import mage.constants.CardType; @@ -50,17 +50,25 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements protected Token token; protected String type; protected boolean losePreviousTypes; + protected DynamicValue power; + protected DynamicValue toughness; public BecomesCreatureSourceEffect(Token token, String type, Duration duration) { this(token, type, duration, false, false); } public BecomesCreatureSourceEffect(Token token, String type, Duration duration, boolean losePreviousTypes, boolean characterDefining) { + this(token, type, duration, losePreviousTypes, characterDefining, null, null); + } + + public BecomesCreatureSourceEffect(Token token, String type, Duration duration, boolean losePreviousTypes, boolean characterDefining, DynamicValue power, DynamicValue toughness) { super(duration, Outcome.BecomeCreature); this.characterDefining = characterDefining; this.token = token; this.type = type; this.losePreviousTypes = losePreviousTypes; + this.power = power; + this.toughness = toughness; setText(); } @@ -69,6 +77,8 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements this.token = effect.token.copy(); this.type = effect.type; this.losePreviousTypes = effect.losePreviousTypes; + this.power = effect.power; + this.toughness = effect.toughness; } @Override @@ -133,19 +143,21 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements case PTChangingEffects_7: if ((sublayer == SubLayer.CharacteristicDefining_7a && isCharacterDefining()) || (sublayer == SubLayer.SetPT_7b && !isCharacterDefining())) { - MageInt power = token.getPower(); - MageInt toughness = token.getToughness(); - if (power != null && toughness != null) { - permanent.getPower().setValue(power.getValue()); - permanent.getToughness().setValue(toughness.getValue()); + if (power != null) { + permanent.getPower().setValue(power.calculate(game, source, this)); + } else if (token.getPower() != null) { + permanent.getPower().setValue(token.getPower().getValue()); + } + if (toughness != null) { + permanent.getToughness().setValue(toughness.calculate(game, source, this)); + } else if (token.getToughness() != null) { + permanent.getToughness().setValue(token.getToughness().getValue()); } } } return true; - } else { - if (duration.equals(Duration.Custom)) { - this.discard(); - } + } else if (duration.equals(Duration.Custom)) { + this.discard(); } return false; } From b6ecd3931b73c9aa3e5ce229fdb957fffd7cad79 Mon Sep 17 00:00:00 2001 From: drmDev Date: Wed, 13 Jul 2016 08:51:47 -0400 Subject: [PATCH 07/15] Kalitas Traitor of Ghet JUnit test for bug. see #2071 --- .../replacement/KalitasTraitorOfGhetTest.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java new file mode 100644 index 00000000000..5191c1ae612 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java @@ -0,0 +1,55 @@ +/* + * 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.replacement; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) + */ +public class KalitasTraitorOfGhetTest extends CardTestPlayerBase { + + /* + * Reported bug: Damnation with Kalitas, Traitor of Ghet on my side and 3 opponent creatures, it only exiled 1 creature giving me only 1 zombie instead of 3. + */ + @Test + public void testDamnation() { + + /* + Kalitas, Traitor of Ghet {2}{B}{B} 3/4 lifelink - Legendary Vampire + If a nontoken creature an opponent controls would die, instead exile that card and put a 2/2 black Zombie creature token onto the battlefield. + */ + addCard(Zone.BATTLEFIELD, playerA, "Kalitas, Traitor of Ghet", 1); + /* + Damnation {2}{B}{B} - Sorcery + Destroy all creatures. They can't be regenerated. + */ + addCard(Zone.HAND, playerA, "Damnation", 1); + + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + + addCard(Zone.BATTLEFIELD, playerB, "Bronze Sable", 1); + addCard(Zone.BATTLEFIELD, playerB, "Wall of Roots", 1); + addCard(Zone.BATTLEFIELD, playerB, "Sigiled Starfish", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Damnation"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Kalitas, Traitor of Ghet", 1); + assertGraveyardCount(playerA, "Damnation", 1); + assertExileCount("Bronze Sable", 1); + assertExileCount("Wall of Roots", 1); + assertExileCount("Sigiled Starfish", 1); + assertGraveyardCount(playerB, 0); // all 3 creatures of playerB should be exiled not in graveyard + assertExileCount("Kalitas, Traitor of Ghet", 0); // player controlled, not opponent so not exiled + assertPermanentCount(playerA, "Zombie", 3); // 3 tokens generated from exiling 3 opponent's creatures + } +} From fc1a1523c50147f3f825f768fd465a0021e8c4d1 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 13 Jul 2016 17:04:52 +0200 Subject: [PATCH 08/15] * Gideon, Champion of Justice - Fixed that the P/T did not change if loyality counters were added after using the 0 ability. --- .../gatecrash/GideonChampionOfJustice.java | 3 +- .../test/cards/planeswalker/GideonTest.java | 18 +++-- .../dynamicvalue/LockedInDynamicValue.java | 77 +++++++++++++++++++ .../BecomesCreatureSourceEffect.java | 4 +- 4 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 Mage/src/main/java/mage/abilities/dynamicvalue/LockedInDynamicValue.java diff --git a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java index 75875b97e91..ca21e65092f 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java +++ b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java @@ -32,6 +32,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.dynamicvalue.LockedInDynamicValue; import mage.abilities.dynamicvalue.common.CountersCount; import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount; import mage.abilities.effects.OneShotEffect; @@ -71,7 +72,7 @@ public class GideonChampionOfJustice extends CardImpl { this.addAbility(ability1); // 0: Until end of turn, Gideon becomes an indestructible Human Soldier creature with power and toughness each equal to the number of loyalty counters on him. He's still a planeswalker. Prevent all damage that would be dealt to him this turn. - CountersCount loyaltyCount = new CountersCount(CounterType.LOYALTY); + LockedInDynamicValue loyaltyCount = new LockedInDynamicValue(new CountersCount(CounterType.LOYALTY)); LoyaltyAbility ability2 = new LoyaltyAbility(new BecomesCreatureSourceEffect( new GideonChampionOfJusticeToken(), "planeswalker", Duration.EndOfTurn, false, false, loyaltyCount, loyaltyCount), 0); ability2.addEffect(new PreventAllDamageToSourceEffect(Duration.EndOfTurn)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java index 78d4d81a443..ef3fe0da492 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java @@ -82,7 +82,7 @@ public class GideonTest extends CardTestPlayerBase { */ @Test public void testGideonChampionOfJusticeSecondAbility() { - + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); /* Gideon, Champion of Justice {2}{W}{W} - 4 Loyalty +1: Put a loyalty counter on Gideon, Champion of Justice for each creature target opponent controls. @@ -94,16 +94,24 @@ public class GideonTest extends CardTestPlayerBase { -15: Exile all other permanents. */ - addCard(Zone.BATTLEFIELD, playerA, "Gideon, Champion of Justice", 1); + addCard(Zone.HAND, playerA, "Gideon, Champion of Justice", 1); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gideon, Champion of Justice"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+0: Until end of turn"); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Put a loyalty counter on", playerB); + + activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "+0: Until end of turn"); + + setStopAt(5, PhaseStep.BEGIN_COMBAT); execute(); assertGraveyardCount(playerA, "Gideon, Champion of Justice", 0); assertPermanentCount(playerA, "Gideon, Champion of Justice", 1); - assertPowerToughness(playerA, "Gideon, Champion of Justice", 4, 4); - assertCounterCount(playerA, "Gideon, Champion of Justice", CounterType.LOYALTY, 4); + assertCounterCount(playerA, "Gideon, Champion of Justice", CounterType.LOYALTY, 7); + assertPowerToughness(playerA, "Gideon, Champion of Justice", 7, 7); } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/LockedInDynamicValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/LockedInDynamicValue.java new file mode 100644 index 00000000000..81e2a9a1b51 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/LockedInDynamicValue.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.dynamicvalue; + +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.game.Game; + +/** + * The first calculated value is used as long as the class instance is in use + * + * IMPORTANT: If used the ability / effect that uses a locked in dynamic value + * has to really copy the dnamic value in its copy method (not reference) + * + * @author LevelX2 + */ +public class LockedInDynamicValue implements DynamicValue { + + private boolean valueChecked = false; + private int lockedInValue; + private final DynamicValue basicDynamicValue; + + public LockedInDynamicValue(DynamicValue dynamicValue) { + this.basicDynamicValue = dynamicValue; + } + + public LockedInDynamicValue(LockedInDynamicValue dynamicValue, final boolean copy) { + this.basicDynamicValue = dynamicValue.basicDynamicValue; + this.lockedInValue = dynamicValue.lockedInValue; + this.valueChecked = dynamicValue.valueChecked; + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + if (!valueChecked) { + lockedInValue = basicDynamicValue.calculate(game, sourceAbility, effect); + valueChecked = true; + } + return lockedInValue; + } + + @Override + public LockedInDynamicValue copy() { + return new LockedInDynamicValue(this, true); + } + + @Override + public String getMessage() { + return basicDynamicValue.getMessage(); + } + +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java index 507fa018039..2a04f2e1a11 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java @@ -77,8 +77,8 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements this.token = effect.token.copy(); this.type = effect.type; this.losePreviousTypes = effect.losePreviousTypes; - this.power = effect.power; - this.toughness = effect.toughness; + this.power = effect.power.copy(); + this.toughness = effect.toughness.copy(); } @Override From ea616291e41567683f5327f74442a9d28f98683a Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 13 Jul 2016 17:55:32 +0200 Subject: [PATCH 09/15] * Added test. --- .../abilities/keywords/EscalateTest.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EscalateTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EscalateTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EscalateTest.java new file mode 100644 index 00000000000..22626a912a5 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EscalateTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.keywords; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class EscalateTest extends CardTestPlayerBase { + + @Test + public void testUseOneMode() { + + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + // Escalate {1} (Pay this cost for each mode chosen beyond the first.) + // Choose one or more — + // Creatures target player controls gain trample until end of turn. + // Savage Alliance deals 2 damage to target creature; + // Savage Alliance deals 1 damage to each creature target opponent controls. + addCard(Zone.HAND, playerA, "Savage Alliance"); // Instant {2}{R} + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Savage Alliance", "mode=2Silvercoat Lion"); + setModeChoice(playerA, "2"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerB, "Silvercoat Lion", 1); + assertGraveyardCount(playerA, "Savage Alliance", 1); + + } + +} From cba91dc1d133a94d122952961a529000155f50b1 Mon Sep 17 00:00:00 2001 From: Quercitron Date: Thu, 14 Jul 2016 02:35:21 +0300 Subject: [PATCH 10/15] Add \me chat command. --- .../main/java/mage/server/ChatManager.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java index e30923010bd..c8d95300c5c 100644 --- a/Mage.Server/src/main/java/mage/server/ChatManager.java +++ b/Mage.Server/src/main/java/mage/server/ChatManager.java @@ -122,20 +122,28 @@ public class ChatManager { } } + private static final String COMMANDS_LIST = + "
List of commands:" + + "
\\history or \\h [username] - shows the history of a player" + + "
\\me - shows the history of the current player" + + "
\\list or \\l - Show a list of commands" + + "
\\whisper or \\w [player name] [text] - whisper to the player with the given name"; + private boolean performUserCommand(User user, String message, UUID chatId, boolean doError) { String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH); if (doError) { - message += new StringBuilder("
Invalid User Command '" + message + "'.") - .append("
List of commands:") - .append("
\\history or \\h [username] - shows the history of a player") - .append("
\\list or \\l - Show a list of commands") - .append("
\\whisper or \\w [player name] [text] - whisper to the player with the given name").toString(); + message += new StringBuilder("
Invalid User Command '" + message + "'.").append(COMMANDS_LIST).toString(); chatSessions.get(chatId).broadcastInfoToUser(user, message); return true; } if (command.startsWith("H ") || command.startsWith("HISTORY ")) { - message = UserManager.getInstance().getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9)); + message += "
" + UserManager.getInstance().getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9)); + chatSessions.get(chatId).broadcastInfoToUser(user, message); + return true; + } + if (command.equals("ME")) { + message += "
" + UserManager.getInstance().getUserHistory(user.getName()); chatSessions.get(chatId).broadcastInfoToUser(user, message); return true; } @@ -159,10 +167,7 @@ public class ChatManager { } } if (command.equals("L") || command.equals("LIST")) { - message += new StringBuilder("
List of commands:") - .append("
\\history or \\h [username] - shows the history of a player") - .append("
\\list or \\l - Show a list of commands") - .append("
\\whisper or \\w [player name] [text] - whisper to the player with the given name").toString(); + message += COMMANDS_LIST; chatSessions.get(chatId).broadcastInfoToUser(user, message); return true; } From 4d0cfb332c29548c2d6ce2c00c7b6301eda15a84 Mon Sep 17 00:00:00 2001 From: drmDev Date: Thu, 14 Jul 2016 09:15:14 -0400 Subject: [PATCH 11/15] Minds Dilation JUnit test for #2077 --- .../cards/enchantments/MindsDilationTest.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java new file mode 100644 index 00000000000..c98508450a7 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java @@ -0,0 +1,72 @@ +/* + * 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.enchantments; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) + */ +public class MindsDilationTest extends CardTestPlayerBase { + + @Test + public void testExileNonLandCardAndCastIt() { + + removeAllCardsFromLibrary(playerA); + + /** + * Mind's Dilation {5}{U}{U} Enchantment + * Whenever an opponent casts his or her first spell each turn, that player exiles the top card of his or her library. + * If it's a nonland card, you may cast it without paying its mana cost. + */ + + addCard(Zone.BATTLEFIELD, playerB, "Mind's Dilation", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, "Lightning Bolt", 1); + addCard(Zone.LIBRARY, playerA, "Divination", 1); // draw 2 cards + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + setChoice(playerB, "Yes"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerB, 17); + assertExileCount("Divination", 1); + assertHandCount(playerB, 2); // free divination! + } + + @Test + public void testExileNonLandCardDontCastIt() { + + removeAllCardsFromLibrary(playerA); + + /** + * Mind's Dilation {5}{U}{U} Enchantment + * Whenever an opponent casts his or her first spell each turn, that player exiles the top card of his or her library. + * If it's a nonland card, you may cast it without paying its mana cost. + */ + + addCard(Zone.BATTLEFIELD, playerB, "Mind's Dilation", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, "Lightning Bolt", 1); + addCard(Zone.LIBRARY, playerA, "Divination", 1); // draw 2 cards + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + setChoice(playerB, "No"); // no, I don't want my free 2 cards + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerB, 17); + assertExileCount("Divination", 1); + assertHandCount(playerB, 0); // Divination never cast + } +} From 4bdc4936f0504a73625f2bb0d4f45174d1613418 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 14 Jul 2016 17:14:06 +0200 Subject: [PATCH 12/15] * Fixed Mid's Dilation bugs (fixes #2077). --- .../mage/sets/eldritchmoon/MindsDilation.java | 62 +++---------------- .../BecomesCreatureSourceEffect.java | 12 ++-- .../watchers/common/SpellsCastWatcher.java | 1 + 3 files changed, 19 insertions(+), 56 deletions(-) diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/MindsDilation.java b/Mage.Sets/src/mage/sets/eldritchmoon/MindsDilation.java index ca777a1c688..06354f26ebe 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/MindsDilation.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/MindsDilation.java @@ -32,15 +32,11 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; -import mage.constants.AsThoughEffectType; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; @@ -64,8 +60,7 @@ public class MindsDilation extends CardImpl { // Whenever an opponent casts his or her first spell each turn, that player exiles the top card of his or her library. If it's a nonland card, // you may cast it without paying its mana cost. - Ability ability = new MindsDilationTriggeredAbility(new MindsDilationEffect(), false); - this.addAbility(ability, new SpellsCastWatcher()); + this.addAbility(new MindsDilationTriggeredAbility(new MindsDilationEffect(), false), new SpellsCastWatcher()); } public MindsDilation(final MindsDilation card) { @@ -113,7 +108,7 @@ class MindsDilationTriggeredAbility extends SpellCastOpponentTriggeredAbility { @Override public String getRule() { return "Whenever an opponent casts his or her first spell each turn, that player exiles the top card of his or her library." - + " If it's a nonland card, you may cast it without paying its mana cost"; + + " If it's a nonland card, you may cast it without paying its mana cost."; } } @@ -121,7 +116,7 @@ class MindsDilationEffect extends OneShotEffect { MindsDilationEffect() { super(Outcome.Benefit); - this.staticText = "that player exiles the top card of his or her library. If it's a nonland card, you may cast it without paying its mana cost."; + this.staticText = "that player exiles the top card of his or her library. If it's a nonland card, you may cast it without paying its mana cost"; } MindsDilationEffect(final MindsDilationEffect effect) { @@ -140,12 +135,13 @@ class MindsDilationEffect extends OneShotEffect { Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); if (controller != null && sourceObject != null && opponent != null) { if (opponent.getLibrary().size() > 0) { - Card card = opponent.getLibrary().removeFromTop(game); - if (card != null) { - opponent.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); - ContinuousEffect effect = new MindsDilationCastFromExileEffect(); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); + Card card = opponent.getLibrary().getFromTop(game); + if (card != null && opponent.moveCards(card, Zone.EXILED, source, game)) { + if (!card.getCardType().contains(CardType.LAND)) { + if (controller.chooseUse(outcome, "Cast " + card.getLogName() + " without paying its mana cost from exile?", source, game)) { + controller.cast(card.getSpellAbility(), game, true); + } + } } } return true; @@ -153,41 +149,3 @@ class MindsDilationEffect extends OneShotEffect { return false; } } - -class MindsDilationCastFromExileEffect extends AsThoughEffectImpl { - - MindsDilationCastFromExileEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - staticText = "If it's a nonland card, you may cast it without paying its mana cost"; - } - - MindsDilationCastFromExileEffect(final MindsDilationCastFromExileEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public MindsDilationCastFromExileEffect copy() { - return new MindsDilationCastFromExileEffect(this); - } - - @Override - public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { - UUID targetId = getTargetPointer().getFirst(game, source); - Player controller = game.getPlayer(source.getControllerId()); - if (targetId != null && controller != null) { - Card card = game.getCard(targetId); - if (card != null && !card.getCardType().contains(CardType.LAND) && game.getState().getZone(targetId) == Zone.EXILED) { - if (controller.chooseUse(outcome, "Cast " + card.getLogName() + "?", source, game)) { - controller.cast(card.getSpellAbility(), game, true); - } - return true; - } - } - return false; - } -} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java index 2a04f2e1a11..99399d7c278 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java @@ -50,8 +50,8 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements protected Token token; protected String type; protected boolean losePreviousTypes; - protected DynamicValue power; - protected DynamicValue toughness; + protected DynamicValue power = null; + protected DynamicValue toughness = null; public BecomesCreatureSourceEffect(Token token, String type, Duration duration) { this(token, type, duration, false, false); @@ -77,8 +77,12 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements this.token = effect.token.copy(); this.type = effect.type; this.losePreviousTypes = effect.losePreviousTypes; - this.power = effect.power.copy(); - this.toughness = effect.toughness.copy(); + if (effect.power != null) { + this.power = effect.power.copy(); + } + if (effect.toughness != null) { + this.toughness = effect.toughness.copy(); + } } @Override diff --git a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java index a175971151e..f0309d0ff89 100644 --- a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java @@ -32,6 +32,7 @@ public class SpellsCastWatcher extends Watcher { public SpellsCastWatcher(final SpellsCastWatcher watcher) { super(watcher); + this.spellsCast.putAll(watcher.spellsCast); } @Override From 97e44d10009986268c75a72f9cd70daed36b5592 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 14 Jul 2016 20:30:16 +0200 Subject: [PATCH 13/15] Fixed two bugged tests. --- .../cards/enchantments/MindsDilationTest.java | 48 +++++++++---------- .../java/org/mage/test/player/TestPlayer.java | 5 +- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java index c98508450a7..5088a35ffdd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java @@ -15,56 +15,56 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public class MindsDilationTest extends CardTestPlayerBase { - + @Test public void testExileNonLandCardAndCastIt() { - - removeAllCardsFromLibrary(playerA); - + /** - * Mind's Dilation {5}{U}{U} Enchantment - * Whenever an opponent casts his or her first spell each turn, that player exiles the top card of his or her library. - * If it's a nonland card, you may cast it without paying its mana cost. + * Mind's Dilation {5}{U}{U} Enchantment Whenever an opponent casts his + * or her first spell each turn, that player exiles the top card of his + * or her library. If it's a nonland card, you may cast it without + * paying its mana cost. */ - - addCard(Zone.BATTLEFIELD, playerB, "Mind's Dilation", 1); + addCard(Zone.BATTLEFIELD, playerB, "Mind's Dilation", 1); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); addCard(Zone.HAND, playerA, "Lightning Bolt", 1); addCard(Zone.LIBRARY, playerA, "Divination", 1); // draw 2 cards - + + skipInitShuffling(); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); setChoice(playerB, "Yes"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + assertLife(playerB, 17); - assertExileCount("Divination", 1); + assertExileCount("Divination", 0); assertHandCount(playerB, 2); // free divination! } - + @Test public void testExileNonLandCardDontCastIt() { - + removeAllCardsFromLibrary(playerA); - + /** - * Mind's Dilation {5}{U}{U} Enchantment - * Whenever an opponent casts his or her first spell each turn, that player exiles the top card of his or her library. - * If it's a nonland card, you may cast it without paying its mana cost. + * Mind's Dilation {5}{U}{U} Enchantment Whenever an opponent casts his + * or her first spell each turn, that player exiles the top card of his + * or her library. If it's a nonland card, you may cast it without + * paying its mana cost. */ - - addCard(Zone.BATTLEFIELD, playerB, "Mind's Dilation", 1); + addCard(Zone.BATTLEFIELD, playerB, "Mind's Dilation", 1); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); addCard(Zone.HAND, playerA, "Lightning Bolt", 1); addCard(Zone.LIBRARY, playerA, "Divination", 1); // draw 2 cards - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); setChoice(playerB, "No"); // no, I don't want my free 2 cards - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + assertLife(playerB, 17); assertExileCount("Divination", 1); assertHandCount(playerB, 0); // Divination never cast diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 44ce17cfbb8..97c83236776 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -574,6 +574,9 @@ public class TestPlayer implements Player { i++; } } + if (modes.getMinModes() <= modes.getSelectedModes().size()) { + return null; + } return computerPlayer.chooseMode(modes, source, game); //To change body of generated methods, choose Tools | Templates. } @@ -1734,7 +1737,7 @@ public class TestPlayer implements Player { public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, UUID controllerId, Game game) { return computerPlayer.canPaySacrificeCost(permanent, sourceId, controllerId, game); } - + @Override public FilterPermanent getSacrificeCostFilter() { return computerPlayer.getSacrificeCostFilter(); From 88d66784dfdf010c3f16f27000860823c652f3bd Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 15 Jul 2016 14:25:25 +0200 Subject: [PATCH 14/15] * Crop Sigil - Fixed that it can't be activated without both a creature and land in the graveyard (fixes #2079 ). --- .../src/mage/sets/eldritchmoon/CropSigil.java | 8 +++---- .../src/main/java/mage/target/TargetCard.java | 23 ++++++++++--------- Mage/src/main/java/mage/target/Targets.java | 2 +- .../common/TargetCardInYourGraveyard.java | 7 ++---- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java b/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java index 75c61fd2103..66e8358a08b 100644 --- a/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java +++ b/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java @@ -43,7 +43,7 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.events.GameEvent; -import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInYourGraveyard; /** * @@ -71,10 +71,10 @@ public class CropSigil extends CardImpl { Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(true, true), new ManaCostsImpl<>("{2}{G}"), DeliriumCondition.getInstance(), "Delirium — {2}{G}, Sacrifice {this}: Return up to one target creature card and up to one target land card from your graveyard to your hand. " - + "Activate this ability only if there are four or more card types among cards in your graveyard"); + + "Activate this ability only if there are four or more card types among cards in your graveyard"); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCardInGraveyard(0, 1, filterCreature)); - ability.addTarget(new TargetCardInGraveyard(0, 1, filterLand)); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, filterCreature)); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, filterLand)); this.addAbility(ability); } diff --git a/Mage/src/main/java/mage/target/TargetCard.java b/Mage/src/main/java/mage/target/TargetCard.java index 92d00489275..04885dd42e5 100644 --- a/Mage/src/main/java/mage/target/TargetCard.java +++ b/Mage/src/main/java/mage/target/TargetCard.java @@ -24,21 +24,19 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ - + */ package mage.target; -import mage.constants.Zone; -import mage.cards.Card; -import mage.cards.Cards; -import mage.filter.FilterCard; -import mage.game.Game; -import mage.players.Player; - import java.util.HashSet; import java.util.Set; import java.util.UUID; +import mage.cards.Card; +import mage.cards.Cards; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; import mage.game.events.GameEvent; +import mage.players.Player; /** * @@ -87,9 +85,12 @@ public class TargetCard extends TargetObject { @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { int possibleTargets = 0; - for (UUID playerId: game.getState().getPlayersInRange(sourceControllerId, game)) { + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null) { + if (this.minNumberOfTargets == 0) { + return true; + } switch (zone) { case HAND: for (Card card : player.getHand().getCards(filter, sourceId, sourceControllerId, game)) { @@ -200,7 +201,7 @@ public class TargetCard extends TargetObject { public Set possibleTargets(UUID sourceControllerId, Cards cards, Game game) { Set possibleTargets = new HashSet<>(); - for (Card card: cards.getCards(filter, game)) { + for (Card card : cards.getCards(filter, game)) { possibleTargets.add(card.getId()); } return possibleTargets; diff --git a/Mage/src/main/java/mage/target/Targets.java b/Mage/src/main/java/mage/target/Targets.java index c29f1932d90..be2bbe1d6e8 100644 --- a/Mage/src/main/java/mage/target/Targets.java +++ b/Mage/src/main/java/mage/target/Targets.java @@ -121,7 +121,7 @@ public class Targets extends ArrayList { } } // it is legal when either there is no target or not all targets are illegal - return this.size() == 0 || this.size() != illegalCount; + return this.isEmpty() || this.size() != illegalCount; } /** diff --git a/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java b/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java index eba50fb268d..de6b3863873 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java @@ -30,10 +30,10 @@ package mage.target.common; import java.util.HashSet; import java.util.Set; import java.util.UUID; -import mage.constants.Zone; import mage.abilities.Ability; import mage.cards.Card; import mage.cards.Cards; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.game.events.GameEvent; @@ -122,10 +122,7 @@ public class TargetCardInYourGraveyard extends TargetCard { */ @Override public boolean canChoose(UUID sourceControllerId, Game game) { - if (game.getPlayer(sourceControllerId).getGraveyard().count(filter, game) >= this.minNumberOfTargets) { - return true; - } - return false; + return game.getPlayer(sourceControllerId).getGraveyard().count(filter, game) >= this.minNumberOfTargets; } @Override From 4302186032cb5c71f016583e90228d89860e4961 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 15 Jul 2016 14:47:20 +0200 Subject: [PATCH 15/15] * Devils' Playground - Fixed name spelling bug. --- .../src/mage/sets/shadowsoverinnistrad/DevilsPlayground.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/DevilsPlayground.java b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/DevilsPlayground.java index 6f5bee35e38..6c04fd98126 100644 --- a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/DevilsPlayground.java +++ b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/DevilsPlayground.java @@ -42,7 +42,7 @@ import mage.game.permanent.token.DevilToken; public class DevilsPlayground extends CardImpl { public DevilsPlayground(UUID ownerId) { - super(ownerId, 151, "Devil's Playground", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{R}{R}"); + super(ownerId, 151, "Devils' Playground", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{R}{R}"); this.expansionSetCode = "SOI"; // Put four 1/1 red Devil creature tokens onto the battlefield. They have "When this creature dies, it deals 1 damage to target creature or player."