From e1fea330dd5ede4d7e9f17c46250ad12febdb9d4 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Sun, 12 Jan 2020 01:17:39 +0400 Subject: [PATCH] Test framework - multiple improves: * Added support of spell ability choice in free cast (chooseSpellAbilityForCast); * Added support of "up to" targets setup in addTargetAmount (use TestPlayer.TARGET_SKIP to stop target choose); * Restored multiple checks for addTargetAmount; * Fixed many wrong tests (wrong order or missing commands); --- .../java/mage/player/ai/ComputerPlayer.java | 2 +- .../src/mage/player/human/HumanPlayer.java | 4 +- .../activated/PutToGraveyardTest.java | 5 +- .../cards/abilities/keywords/MadnessTest.java | 35 ++- .../cards/abilities/keywords/MorphTest.java | 5 +- .../abilities/other/EndTurnEffectTest.java | 12 +- .../cards/continuous/BoostEnchantedTest.java | 8 +- .../cards/continuous/PaintersServantTest.java | 105 ++++---- .../continuous/UnboundFlourishingTest.java | 2 +- .../CastSplitCardsFromOtherZonesTest.java | 21 +- .../cards/enchantments/SpreadingSeasTest.java | 8 +- .../test/cards/planeswalker/VivienTest.java | 75 ++++-- .../replacement/HallowedMoonlightTest.java | 5 +- .../cards/single/ChaliceOfTheVoidTest.java | 8 +- .../single/lrw/BurrentonForgeTenderTest.java | 45 ++-- .../split/CastSplitCardsWithFuseTest.java | 17 +- .../ReturnToBattlefieldEffectsTest.java | 5 +- .../test/cards/triggers/SpellskiteTest.java | 12 +- .../mage/test/player/TestComputerPlayer.java | 2 +- .../mage/test/player/TestComputerPlayer7.java | 2 +- .../java/org/mage/test/player/TestPlayer.java | 243 ++++++++++-------- .../base/impl/CardTestPlayerAPIImpl.java | 29 ++- .../main/java/mage/players/PlayerImpl.java | 99 +++---- .../java/mage/target/TargetPermanent.java | 13 +- 24 files changed, 435 insertions(+), 327 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 54c8faf01a8..bee7421c941 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -1885,7 +1885,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { case SPLIT_AFTERMATH: MageObject object = game.getObject(ability.getSourceId()); if (object != null) { - LinkedHashMap useableAbilities = getSpellAbilities(object, game.getState().getZone(object.getId()), game); + LinkedHashMap useableAbilities = getSpellAbilities(playerId, object, game.getState().getZone(object.getId()), game); if (useableAbilities != null && !useableAbilities.isEmpty()) { // game.fireGetChoiceEvent(playerId, name, object, new ArrayList<>(useableAbilities.values())); // TODO: Improve this diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 116ce13c7af..dbf11eaedf0 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -1969,7 +1969,7 @@ public class HumanPlayer extends PlayerImpl { case SPLIT_AFTERMATH: MageObject object = game.getObject(ability.getSourceId()); if (object != null) { - LinkedHashMap useableAbilities = getSpellAbilities(object, game.getState().getZone(object.getId()), game); + LinkedHashMap useableAbilities = getSpellAbilities(playerId, object, game.getState().getZone(object.getId()), game); if (useableAbilities != null && useableAbilities.size() == 1) { return (SpellAbility) useableAbilities.values().iterator().next(); @@ -2009,7 +2009,7 @@ public class HumanPlayer extends PlayerImpl { MageObject object = game.getObject(card.getId()); if (object != null) { - LinkedHashMap useableAbilities = getSpellAbilities(object, game.getState().getZone(object.getId()), game); + LinkedHashMap useableAbilities = getSpellAbilities(playerId, object, game.getState().getZone(object.getId()), game); if (useableAbilities != null && useableAbilities.size() == 1) { return (SpellAbility) useableAbilities.values().iterator().next(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java index 63d819e9ade..df738625941 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java @@ -1,13 +1,12 @@ - package org.mage.test.cards.abilities.activated; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class PutToGraveyardTest extends CardTestPlayerBase { @@ -32,7 +31,7 @@ public class PutToGraveyardTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Stasis Snare"); addTarget(playerA, "Silvercoat Lion"); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G},", NO_TARGET, ""); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G},", TestPlayer.NO_TARGET, ""); addTarget(playerA, "Silvercoat Lion"); setStopAt(1, PhaseStep.BEGIN_COMBAT); 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 df635307a76..26871817688 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 @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.keywords; import mage.abilities.keyword.HasteAbility; @@ -8,7 +7,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author BetaSteward */ public class MadnessTest extends CardTestPlayerBase { @@ -37,7 +35,6 @@ public class MadnessTest extends CardTestPlayerBase { * Raven's Crime B Sorcery Target player discards a card. Retrace (You may * cast this card from your graveyard by discarding a land card in addition * to paying its other costs.) - * */ @Test public void testMadness() { @@ -47,10 +44,13 @@ public class MadnessTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Raven's Crime"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Raven's Crime", playerA); - setChoice(playerA, "Yes"); + setChoice(playerA, "Yes"); // use madness triggered ability + setChoice(playerA, "Yes"); // use madness cast + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Arrogant Wurm", 1); assertGraveyardCount(playerA, "Raven's Crime", 1); @@ -68,8 +68,10 @@ public class MadnessTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Raven's Crime", playerA); setChoice(playerA, "No"); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Arrogant Wurm", 0); assertGraveyardCount(playerA, "Raven's Crime", 1); @@ -93,10 +95,13 @@ public class MadnessTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Haunting Hymn"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Haunting Hymn", playerA); - setChoice(playerA, "Yes"); + setChoice(playerA, "Yes"); // use madness triggered ability + setChoice(playerA, "Yes"); // use madness cast + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + setStrictChooseMode(true); assertGraveyardCount(playerB, "Haunting Hymn", 1); assertGraveyardCount(playerB, "Haunting Hymn", 1); @@ -119,12 +124,15 @@ public class MadnessTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Haunting Hymn"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Haunting Hymn", playerA); - setChoice(playerA, "Yes"); + setChoice(playerA, "Yes"); // use madness triggered ability + setChoice(playerA, "Yes"); // use madness cast setChoice(playerA, "X=4"); - addTarget(playerA, "Pillarfield Ox"); + addTargetAmount(playerA, "Pillarfield Ox", 4); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerB, "Haunting Hymn", 1); assertGraveyardCount(playerA, "Avacyn's Judgment", 1); @@ -137,7 +145,7 @@ public class MadnessTest extends CardTestPlayerBase { * 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 @@ -147,7 +155,7 @@ public class MadnessTest extends CardTestPlayerBase { * 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. */ @@ -171,13 +179,17 @@ public class MadnessTest extends CardTestPlayerBase { 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, "Asylum Visitor: Madness {1}{B}"); // choose replacement effect (TODO: 2 same madness effetcs: one from Asylum Visitor, one from Falkenrath -- is that ok?!) + // + setChoice(playerA, "Yes"); // use madness triggered ability + setChoice(playerA, "Yes"); // use madness cast 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"); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Falkenrath Gorger", 1); assertPermanentCount(playerA, "Asylum Visitor", 1); @@ -189,6 +201,5 @@ public class MadnessTest extends CardTestPlayerBase { assertAbility(playerA, "Asylum Visitor", HasteAbility.getInstance(), true); assertGraveyardCount(playerA, "Forest", 1); - } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java index dc8ced15240..dacc8d11e2c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java @@ -6,6 +6,7 @@ import mage.filter.Filter; import mage.game.permanent.Permanent; import org.junit.Assert; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** @@ -100,7 +101,7 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Icefeather Aven", NO_TARGET, "Pine Walker", StackClause.WHILE_NOT_ON_STACK); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Icefeather Aven", TestPlayer.NO_TARGET, "Pine Walker", StackClause.WHILE_NOT_ON_STACK); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature attack(3, playerA, EmptyNames.FACE_DOWN_CREATURE.toString()); @@ -359,7 +360,7 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sagu Mauler"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sagu Mauler", NO_TARGET, "Sagu Mauler", StackClause.WHILE_NOT_ON_STACK); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sagu Mauler", TestPlayer.NO_TARGET, "Sagu Mauler", StackClause.WHILE_NOT_ON_STACK); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature // showBattlefield("A battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/EndTurnEffectTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/EndTurnEffectTest.java index acabaf5828a..841c8e177d7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/EndTurnEffectTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/EndTurnEffectTest.java @@ -1,13 +1,12 @@ - package org.mage.test.cards.abilities.other; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class EndTurnEffectTest extends CardTestPlayerBase { @@ -16,9 +15,8 @@ public class EndTurnEffectTest extends CardTestPlayerBase { * Additional bug: Days Undoing and Sphinx's Tutelage are broken. You * shouldn't get triggers off of Tutelage, since the turn ends, but it has * you resolve them in your cleanup step. - * + *

* http://tabakrules.tumblr.com/post/122350751009/days-undoing-has-been-officially-spoiled-on - * */ @Test public void testSpellsAffinity() { @@ -69,7 +67,7 @@ public class EndTurnEffectTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Ice", "Silvercoat Lion"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Time Stop", NO_TARGET, "Ice"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Time Stop", TestPlayer.NO_TARGET, "Ice"); setStopAt(2, PhaseStep.UPKEEP); execute(); @@ -105,7 +103,7 @@ public class EndTurnEffectTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Injury", "Silvercoat Lion"); addTarget(playerA, playerB); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Glorious End", NO_TARGET, "Injury"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Glorious End", TestPlayer.NO_TARGET, "Injury"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -137,7 +135,7 @@ public class EndTurnEffectTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sundial of the Infinite"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Disenchant", "Sundial of the Infinite"); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1},", NO_TARGET, "Disenchant"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1},", TestPlayer.NO_TARGET, "Disenchant"); setStopAt(2, PhaseStep.PRECOMBAT_MAIN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/BoostEnchantedTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/BoostEnchantedTest.java index 3dfee9c4d7a..d195a57e2ba 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/BoostEnchantedTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/BoostEnchantedTest.java @@ -1,13 +1,12 @@ - package org.mage.test.cards.continuous; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class BoostEnchantedTest extends CardTestPlayerBase { @@ -35,12 +34,11 @@ public class BoostEnchantedTest extends CardTestPlayerBase { * return Ghitu Firebreathing to your hand, the +1/0 goes away on the * creature. If you re-cast Ghitu Firebreathing onto the creature, the boost * returns. - * + *

* Gatherer Rulings: 9/25/2006 If you return Ghitu Firebreathing to its * owner's hand while the +1/+0 ability is on the stack, that ability will * still give the creature that was last enchanted by Ghitu Firebreathing * +1/+0. - * */ @Test public void testFirebreathingReturnToHand() { @@ -54,7 +52,7 @@ public class BoostEnchantedTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Firebreathing", "Silvercoat Lion"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Boomerang", "Firebreathing"); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: Enchanted creature", NO_TARGET, "Boomerang"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: Enchanted creature", TestPlayer.NO_TARGET, "Boomerang"); setStopAt(1, PhaseStep.END_COMBAT); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/PaintersServantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/PaintersServantTest.java index ab8a1093bc2..f5e068e5a62 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/PaintersServantTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/PaintersServantTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.continuous; import mage.cards.Card; @@ -7,10 +6,10 @@ import mage.constants.Zone; import mage.game.permanent.Permanent; import org.junit.Assert; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class PaintersServantTest extends CardTestPlayerBase { @@ -22,9 +21,9 @@ public class PaintersServantTest extends CardTestPlayerBase { public void testColorSet() { // As Painter's Servant enters the battlefield, choose a color. // All cards that aren't on the battlefield, spells, and permanents are the chosen color in addition to their other colors. - addCard(Zone.HAND, playerA, "Painter's Servant", 1); + addCard(Zone.HAND, playerA, "Painter's Servant", 1); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); - + addCard(Zone.HAND, playerA, "Lightning Bolt"); addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion"); @@ -35,40 +34,40 @@ public class PaintersServantTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Painter's Servant"); setChoice(playerA, "Blue"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Painter's Servant", 1); - + Permanent silvercoatLion = getPermanent("Silvercoat Lion", playerA); Assert.assertEquals(true, silvercoatLion.getColor(currentGame).isWhite()); Assert.assertEquals(true, silvercoatLion.getColor(currentGame).isBlue()); - + silvercoatLion = getPermanent("Silvercoat Lion", playerB); Assert.assertEquals(true, silvercoatLion.getColor(currentGame).isWhite()); Assert.assertEquals(true, silvercoatLion.getColor(currentGame).isBlue()); - for(Card card: playerA.getLibrary().getCards(currentGame)) { - Assert.assertEquals(card.getName() + " should be blue",true, card.getColor(currentGame).isBlue()); + for (Card card : playerA.getLibrary().getCards(currentGame)) { + Assert.assertEquals(card.getName() + " should be blue", true, card.getColor(currentGame).isBlue()); } - for(Card card: playerB.getLibrary().getCards(currentGame)) { - Assert.assertEquals(card.getName() + " should be blue",true, card.getColor(currentGame).isBlue()); + for (Card card : playerB.getLibrary().getCards(currentGame)) { + Assert.assertEquals(card.getName() + " should be blue", true, card.getColor(currentGame).isBlue()); } - - for(Card card: playerA.getHand().getCards(currentGame)) { + + for (Card card : playerA.getHand().getCards(currentGame)) { Assert.assertEquals(true, card.getColor(currentGame).isRed()); Assert.assertEquals(true, card.getColor(currentGame).isBlue()); } - for(Card card: playerB.getHand().getCards(currentGame)) { + for (Card card : playerB.getHand().getCards(currentGame)) { Assert.assertEquals(true, card.getColor(currentGame).isRed()); Assert.assertEquals(true, card.getColor(currentGame).isBlue()); } - for(Card card: playerA.getGraveyard().getCards(currentGame)) { + for (Card card : playerA.getGraveyard().getCards(currentGame)) { Assert.assertEquals(true, card.getColor(currentGame).isWhite()); Assert.assertEquals(true, card.getColor(currentGame).isBlue()); } - for(Card card: playerB.getGraveyard().getCards(currentGame)) { + for (Card card : playerB.getGraveyard().getCards(currentGame)) { Assert.assertEquals(true, card.getColor(currentGame).isWhite()); Assert.assertEquals(true, card.getColor(currentGame).isBlue()); } @@ -82,14 +81,14 @@ public class PaintersServantTest extends CardTestPlayerBase { public void testColorReset() { // As Painter's Servant enters the battlefield, choose a color. // All cards that aren't on the battlefield, spells, and permanents are the chosen color in addition to their other colors. - addCard(Zone.HAND, playerA, "Painter's Servant", 1); + addCard(Zone.HAND, playerA, "Painter's Servant", 1); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); - + addCard(Zone.HAND, playerA, "Lightning Bolt"); addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion"); - addCard(Zone.HAND, playerB, "Lightning Bolt",2); + addCard(Zone.HAND, playerB, "Lightning Bolt", 2); addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); addCard(Zone.GRAVEYARD, playerB, "Silvercoat Lion"); addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); @@ -98,43 +97,43 @@ public class PaintersServantTest extends CardTestPlayerBase { setChoice(playerA, "Blue"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Painter's Servant"); - + setStopAt(1, PhaseStep.END_TURN); execute(); assertGraveyardCount(playerA, "Painter's Servant", 1); - + Permanent silvercoatLion = getPermanent("Silvercoat Lion", playerA); Assert.assertEquals(true, silvercoatLion.getColor(currentGame).isWhite()); Assert.assertEquals(false, silvercoatLion.getColor(currentGame).isBlue()); - + silvercoatLion = getPermanent("Silvercoat Lion", playerB); Assert.assertEquals(true, silvercoatLion.getColor(currentGame).isWhite()); Assert.assertEquals(false, silvercoatLion.getColor(currentGame).isBlue()); - for(Card card: playerA.getLibrary().getCards(currentGame)) { - Assert.assertEquals(card.getName() + " should not be blue",false, card.getColor(currentGame).isBlue()); + for (Card card : playerA.getLibrary().getCards(currentGame)) { + Assert.assertEquals(card.getName() + " should not be blue", false, card.getColor(currentGame).isBlue()); } - for(Card card: playerB.getLibrary().getCards(currentGame)) { - Assert.assertEquals(card.getName() + " should not be blue",false, card.getColor(currentGame).isBlue()); + for (Card card : playerB.getLibrary().getCards(currentGame)) { + Assert.assertEquals(card.getName() + " should not be blue", false, card.getColor(currentGame).isBlue()); } - for(Card card: playerA.getHand().getCards(currentGame)) { + for (Card card : playerA.getHand().getCards(currentGame)) { Assert.assertEquals(true, card.getColor(currentGame).isRed()); Assert.assertEquals(false, card.getColor(currentGame).isBlue()); } - for(Card card: playerB.getHand().getCards(currentGame)) { + for (Card card : playerB.getHand().getCards(currentGame)) { Assert.assertEquals(true, card.getColor(currentGame).isRed()); Assert.assertEquals(false, card.getColor(currentGame).isBlue()); } - for(Card card: playerA.getGraveyard().getCards(currentGame)) { - if(card.getName().equals("Silvercoat Lion")) { + for (Card card : playerA.getGraveyard().getCards(currentGame)) { + if (card.getName().equals("Silvercoat Lion")) { Assert.assertEquals(true, card.getColor(currentGame).isWhite()); Assert.assertEquals(false, card.getColor(currentGame).isBlue()); } } - for(Card card: playerB.getGraveyard().getCards(currentGame)) { - if(card.getName().equals("Silvercoat Lion")) { + for (Card card : playerB.getGraveyard().getCards(currentGame)) { + if (card.getName().equals("Silvercoat Lion")) { Assert.assertEquals(true, card.getColor(currentGame).isWhite()); Assert.assertEquals(false, card.getColor(currentGame).isBlue()); } @@ -152,42 +151,42 @@ public class PaintersServantTest extends CardTestPlayerBase { public void testColorOverwrite() { // As Painter's Servant enters the battlefield, choose a color. // All cards that aren't on the battlefield, spells, and permanents are the chosen color in addition to their other colors. - addCard(Zone.HAND, playerA, "Painter's Servant", 1); - addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.HAND, playerA, "Painter's Servant", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); // Target creature becomes blue until end of turn. Untap that creature. // Draw a card. addCard(Zone.HAND, playerB, "Cerulean Wisps", 1); // Instant {U} - addCard(Zone.BATTLEFIELD, playerB, "Island", 1); - + addCard(Zone.BATTLEFIELD, playerB, "Island", 1); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Painter's Servant"); setChoice(playerA, "Red"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cerulean Wisps", "Silvercoat Lion", "Painter's Servant", StackClause.WHILE_NOT_ON_STACK); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Painter's Servant", 1); - + Permanent silvercoatLion = getPermanent("Silvercoat Lion", playerA); Assert.assertEquals(false, silvercoatLion.getColor(currentGame).isWhite()); Assert.assertEquals(false, silvercoatLion.getColor(currentGame).isRed()); Assert.assertEquals(true, silvercoatLion.getColor(currentGame).isBlue()); } - - /** - * Check color of spells + + /** + * Check color of spells */ @Test public void testColorSpell() { // As Painter's Servant enters the battlefield, choose a color. // All cards that aren't on the battlefield, spells, and permanents are the chosen color in addition to their other colors. - addCard(Zone.HAND, playerA, "Painter's Servant", 1); + addCard(Zone.HAND, playerA, "Painter's Servant", 1); // Draw two cards. addCard(Zone.HAND, playerA, "Divination", 1); // {U}{2} - addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); // Whenever a player casts a red spell, you may gain 1 life. addCard(Zone.BATTLEFIELD, playerA, "Dragon's Claw"); addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); @@ -195,30 +194,30 @@ public class PaintersServantTest extends CardTestPlayerBase { // Target creature becomes blue until end of turn. Untap that creature. // Draw a card. addCard(Zone.HAND, playerB, "Cerulean Wisps", 1); // Instant {U} - addCard(Zone.BATTLEFIELD, playerB, "Island", 1); - + addCard(Zone.BATTLEFIELD, playerB, "Island", 1); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Painter's Servant"); setChoice(playerA, "Red"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cerulean Wisps", "Silvercoat Lion", "Painter's Servant", StackClause.WHILE_NOT_ON_STACK); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Divination", NO_TARGET, "Painter's Servant", StackClause.WHILE_NOT_ON_STACK); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Divination", TestPlayer.NO_TARGET, "Painter's Servant", StackClause.WHILE_NOT_ON_STACK); + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Painter's Servant", 1); - + assertGraveyardCount(playerA, "Divination", 1); assertGraveyardCount(playerB, "Cerulean Wisps", 1); assertLife(playerA, 22); // + 1 from Cerulean Wisps + 1 from Divination - + Permanent silvercoatLion = getPermanent("Silvercoat Lion", playerA); Assert.assertEquals(false, silvercoatLion.getColor(currentGame).isWhite()); Assert.assertEquals(false, silvercoatLion.getColor(currentGame).isRed()); Assert.assertEquals(true, silvercoatLion.getColor(currentGame).isBlue()); - - + + } - - + + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/UnboundFlourishingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/UnboundFlourishingTest.java index fdb5fd79498..517f665bdb8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/UnboundFlourishingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/UnboundFlourishingTest.java @@ -49,8 +49,8 @@ public class UnboundFlourishingTest extends CardTestPlayerBase { // cast with X=3, but double it castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Endless One"); - setChoice(playerA, "X=3"); setChoice(playerA, "Unbound Flourishing"); // choose replacement effects + setChoice(playerA, "X=3"); checkPermanentCounters("after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Endless One", CounterType.P1P1, 3 * 2 * 2); setStrictChooseMode(true); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java index 5d0b75df076..07c260e8add 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java @@ -36,11 +36,13 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { addTarget(playerA, playerB); setChoice(playerA, "Wear // Tear"); // select card setChoice(playerA, "Yes"); // confirm to cast - setChoice(playerA, "Tear"); // select tear side + setChoice(playerA, "Cast Tear"); // select tear side addTarget(playerA, "Sanguine Bond"); // target for tear + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Mindclaw Shaman", 1); assertGraveyardCount(playerB, "Wear // Tear", 1); @@ -67,11 +69,13 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { addTarget(playerA, playerB); setChoice(playerA, "Wear // Tear"); // select card setChoice(playerA, "Yes"); // confirm to cast - setChoice(playerA, "Wear"); // select wear side + setChoice(playerA, "Cast Wear"); // select wear side addTarget(playerA, "Icy Manipulator"); // target for wear + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Mindclaw Shaman", 1); assertGraveyardCount(playerB, "Wear // Tear", 1); @@ -98,12 +102,14 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { addTarget(playerA, playerB); setChoice(playerA, "Wear // Tear"); // select card setChoice(playerA, "Yes"); // confirm to cast - setChoice(playerA, "Wear // Tear"); // select fused + setChoice(playerA, "Cast fused Wear // Tear"); // select fused addTarget(playerA, "Icy Manipulator"); // target for wear addTarget(playerA, "Sanguine Bond"); // target for tear + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Mindclaw Shaman", 1); assertGraveyardCount(playerB, "Wear // Tear", 1); @@ -130,12 +136,15 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Etali, Primal Storm"); // Creature {4}{R} 6/6 attack(2, playerB, "Etali, Primal Storm"); - setChoice(playerB, "Yes"); - setChoice(playerB, "Fire"); - addTarget(playerB, "Silvercoat Lion"); + setChoice(playerB, "Yes"); // free cast + setChoice(playerB, "Fire // Ice"); // card to cast + setChoice(playerB, "Cast Fire"); // ability to cast + addTargetAmount(playerB, "Silvercoat Lion", 2); + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_COMBAT); execute(); + assertAllCommandsUsed(); assertLife(playerA, 14); assertGraveyardCount(playerA, "Silvercoat Lion", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SpreadingSeasTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SpreadingSeasTest.java index f1e04d3ffec..e60cec95c21 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SpreadingSeasTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SpreadingSeasTest.java @@ -1,14 +1,13 @@ - package org.mage.test.cards.enchantments; import mage.constants.PhaseStep; import mage.constants.SubType; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class SpreadingSeasTest extends CardTestPlayerBase { @@ -17,7 +16,7 @@ public class SpreadingSeasTest extends CardTestPlayerBase { * Played Spreading Seas on opps manland (e.g. Blinkmoth Nexus) . He * activated it on response, seas resolves but the manland loses creature * type what should not happened. - * + *

* 305.7. If an effect changes a land's subtype to one or more of the basic * land types, the land no longer has its old land type. It loses all * abilities generated from its rules text and its old land types, and it @@ -28,7 +27,6 @@ public class SpreadingSeasTest extends CardTestPlayerBase { * snow) the land may have. If a land gains one or more land types in * addition to its own, it keeps its land types and rules text, and it gains * the new land types and mana abilities. - * */ @Test public void testCreatureTypeStays() { @@ -46,7 +44,7 @@ public class SpreadingSeasTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spreading Seas", "Blinkmoth Nexus"); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}:", NO_TARGET, "Spreading Seas"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}:", TestPlayer.NO_TARGET, "Spreading Seas"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/VivienTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/VivienTest.java index 3c0d4d43b04..b8ffd2e2d12 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/VivienTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/VivienTest.java @@ -10,14 +10,14 @@ import mage.constants.PhaseStep; import mage.constants.Zone; import mage.counters.CounterType; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ -public class VivienTest extends CardTestPlayerBase { - +public class VivienTest extends CardTestPlayerBase { + @Test public void testVivienArkbowRangerAbility1NoTargets() { setStrictChooseMode(true); @@ -28,7 +28,8 @@ public class VivienTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vivien, Arkbow Ranger"); - + addTargetAmount(playerA, TestPlayer.TARGET_SKIP); // stop choosing (not targets) + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Distribute"); setStopAt(1, PhaseStep.BEGIN_COMBAT); @@ -38,9 +39,9 @@ public class VivienTest extends CardTestPlayerBase { assertCounterCount("Vivien, Arkbow Ranger", CounterType.LOYALTY, 5); } - + @Test - public void testVivienArkbowRangerAbility1OnePossibleTarget() { + public void testVivienArkbowRangerAbilityOnePossibleTargetWithOne() { setStrictChooseMode(true); // +1: Distribute two +1/+1 counters among up to two target creatures. They gain trample until end of turn. // −3: Target creature you control deals damage equal to its power to target creature or planeswalker. @@ -49,21 +50,47 @@ public class VivienTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vivien, Arkbow Ranger"); - + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Distribute"); - + addTargetAmount(playerA, "Silvercoat Lion", 1); + addTargetAmount(playerA, TestPlayer.TARGET_SKIP); // stop choosing (one target) + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Vivien, Arkbow Ranger", 1); assertCounterCount("Vivien, Arkbow Ranger", CounterType.LOYALTY, 5); - - assertPowerToughness(playerB, "Silvercoat Lion", 2, 2); + assertPowerToughness(playerB, "Silvercoat Lion", 2 + 1, 2 + 1); } - + + @Test + public void testVivienArkbowRangerAbilityOnePossibleTargetWithTwo() { + setStrictChooseMode(true); + // +1: Distribute two +1/+1 counters among up to two target creatures. They gain trample until end of turn. + // −3: Target creature you control deals damage equal to its power to target creature or planeswalker. + // −5: You may choose a creature card you own from outside the game, reveal it, and put it into your hand. + addCard(Zone.HAND, playerA, "Vivien, Arkbow Ranger"); // Planeswalker {1}{G}{G}{G} - starts with 4 Loyality counters + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vivien, Arkbow Ranger"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Distribute"); + addTargetAmount(playerA, "Silvercoat Lion", 2); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Vivien, Arkbow Ranger", 1); + assertCounterCount("Vivien, Arkbow Ranger", CounterType.LOYALTY, 5); + + assertPowerToughness(playerB, "Silvercoat Lion", 2 + 2, 2 + 2); + } + @Test public void testVivienArkbowRangerAbility1OneOwnPossibleTarget() { // +1: Distribute two +1/+1 counters among up to two target creatures. They gain trample until end of turn. @@ -73,22 +100,22 @@ public class VivienTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vivien, Arkbow Ranger"); - + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Distribute"); addTargetAmount(playerA, "Silvercoat Lion", 2); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Vivien, Arkbow Ranger", 1); assertCounterCount("Vivien, Arkbow Ranger", CounterType.LOYALTY, 5); - + assertPowerToughness(playerA, "Silvercoat Lion", 4, 4); - } - + } + @Test public void testVivienArkbowRangerAbility1TwoOwnPossibleTarget() { // +1: Distribute two +1/+1 counters among up to two target creatures. They gain trample until end of turn. @@ -99,24 +126,24 @@ public class VivienTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vivien, Arkbow Ranger"); - + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Distribute"); addTargetAmount(playerA, "Silvercoat Lion", 1); addTargetAmount(playerA, "Pillarfield Ox", 1); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Vivien, Arkbow Ranger", 1); assertCounterCount("Vivien, Arkbow Ranger", CounterType.LOYALTY, 5); - + assertPowerToughness(playerA, "Silvercoat Lion", 3, 3); assertPowerToughness(playerA, "Pillarfield Ox", 3, 5); assertAbility(playerA, "Silvercoat Lion", TrampleAbility.getInstance(), true); assertAbility(playerA, "Pillarfield Ox", TrampleAbility.getInstance(), true); - } - + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/HallowedMoonlightTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/HallowedMoonlightTest.java index 4073ad12b6e..1fbf85cc0ba 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/HallowedMoonlightTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/HallowedMoonlightTest.java @@ -1,13 +1,12 @@ - package org.mage.test.cards.replacement; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class HallowedMoonlightTest extends CardTestPlayerBase { @@ -72,7 +71,7 @@ public class HallowedMoonlightTest extends CardTestPlayerBase { castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Rally the Ancestors"); setChoice(playerB, "X=4"); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Hallowed Moonlight", NO_TARGET, "Rally the Ancestors"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Hallowed Moonlight", TestPlayer.NO_TARGET, "Rally the Ancestors"); setStopAt(2, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ChaliceOfTheVoidTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ChaliceOfTheVoidTest.java index 9440682efd5..ab2271c490b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/ChaliceOfTheVoidTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ChaliceOfTheVoidTest.java @@ -48,14 +48,17 @@ public class ChaliceOfTheVoidTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Chalice of the Void", 1); addCard(Zone.BATTLEFIELD, playerB, "Island", 1); + // Counter target spell with converted mana cost 1. addCard(Zone.HAND, playerB, "Mental Misstep", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Chalice of the Void"); setChoice(playerA, "X=1"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Mental Misstep", "Chalice of the Void", "Chalice of the Void"); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + // assertAllCommandsUsed(); // cast Mental Misstep must be ignored assertHandCount(playerB, "Mental Misstep", 1); // cannot be cast because no legal target exists assertPermanentCount(playerA, "Chalice of the Void", 1); // was not countered @@ -81,10 +84,13 @@ public class ChaliceOfTheVoidTest extends CardTestPlayerBase { activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Flashback {R}{R}"); setChoice(playerB, "X=1"); - addTarget(playerB, playerA); + addTargetAmount(playerB, playerA, 1); + setChoice(playerB, "Mountain"); // discard 1 card + setStrictChooseMode(true); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertExileCount(playerB, "Conflagrate", 1); //TODO: Apparently there are two mountains in the graveyard at the end of the test now. diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/BurrentonForgeTenderTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/BurrentonForgeTenderTest.java index ea3dc9bd8ef..92c52f2d6dd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/BurrentonForgeTenderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/BurrentonForgeTenderTest.java @@ -1,13 +1,12 @@ - package org.mage.test.cards.single.lrw; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author Kranken, LevelX2 */ @@ -23,12 +22,12 @@ public class BurrentonForgeTenderTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Soldier of the Pantheon"); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice {this}: Prevent all damage a red source of your choice would deal this turn.", NO_TARGET, "Cast Lightning Bolt"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice {this}: Prevent all damage a red source of your choice would deal this turn.", TestPlayer.NO_TARGET, "Cast Lightning Bolt"); playerA.addChoice("Lightning Bolt"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + assertGraveyardCount(playerB, "Lightning Bolt", 1); assertGraveyardCount(playerA, "Burrenton Forge-Tender", 1); @@ -46,15 +45,15 @@ public class BurrentonForgeTenderTest extends CardTestPlayerBase { castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Flametongue Kavu"); addTarget(playerB, "Soldier of the Pantheon"); - activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice {this}: Prevent all damage a red source of your choice would deal this turn.", - NO_TARGET, "When {this} enters the battlefield, {source} deals 4 damage to target creature."); + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice {this}: Prevent all damage a red source of your choice would deal this turn.", + TestPlayer.NO_TARGET, "When {this} enters the battlefield, {source} deals 4 damage to target creature."); playerA.addChoice("Flametongue Kavu"); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerB, "Flametongue Kavu", 1); - + assertGraveyardCount(playerA, "Burrenton Forge-Tender", 1); assertPermanentCount(playerA, "Soldier of the Pantheon", 1); } @@ -73,24 +72,24 @@ public class BurrentonForgeTenderTest extends CardTestPlayerBase { castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Flametongue Kavu"); addTarget(playerB, "Soldier of the Pantheon"); - activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice {this}: Prevent all damage a red source of your choice would deal this turn.", - NO_TARGET, "When {this} enters the battlefield, {source} deals 4 damage to target creature."); + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice {this}: Prevent all damage a red source of your choice would deal this turn.", + TestPlayer.NO_TARGET, "When {this} enters the battlefield, {source} deals 4 damage to target creature."); playerA.addChoice("Flametongue Kavu"); - + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Cloudshift", "Flametongue Kavu"); addTarget(playerB, "Soldier of the Pantheon"); // now the damage may not be prevented because it's a new object - + setStopAt(2, PhaseStep.END_TURN); execute(); assertPermanentCount(playerB, "Flametongue Kavu", 1); assertGraveyardCount(playerB, "Cloudshift", 1); - + assertGraveyardCount(playerA, "Burrenton Forge-Tender", 1); assertGraveyardCount(playerA, "Soldier of the Pantheon", 1); - } - - + } + + @Test public void testPreventDamageFromToken() { addCard(Zone.BATTLEFIELD, playerA, "Burrenton Forge-Tender"); @@ -111,26 +110,26 @@ public class BurrentonForgeTenderTest extends CardTestPlayerBase { castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Rite of Replication", "Mogg Fanatic"); setChoice(playerB, "No"); // no kicker - + castSpell(2, PhaseStep.BEGIN_COMBAT, playerA, "Orzhov Charm", "Mogg Fanatic"); setModeChoice(playerA, "1"); - + activateAbility(2, PhaseStep.END_COMBAT, playerA, "Sacrifice {this}: Prevent all damage a red source of your choice would deal this turn."); playerA.addChoice("Mogg Fanatic"); - activateAbility(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Sacrifice {this}: {source} deals 1 damage to ","Soldier of the Pantheon"); - + activateAbility(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Sacrifice {this}: {source} deals 1 damage to ", "Soldier of the Pantheon"); + setStopAt(2, PhaseStep.END_TURN); execute(); - + assertPermanentCount(playerB, "Mogg Fanatic", 0); assertGraveyardCount(playerA, "Orzhov Charm", 1); assertHandCount(playerA, "Mogg Fanatic", 1); assertGraveyardCount(playerB, "Rite of Replication", 1); - + assertGraveyardCount(playerA, "Burrenton Forge-Tender", 1); assertPermanentCount(playerA, "Soldier of the Pantheon", 1); - } - + } + } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/split/CastSplitCardsWithFuseTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/split/CastSplitCardsWithFuseTest.java index 5779fd61a85..034305cd91e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/split/CastSplitCardsWithFuseTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/split/CastSplitCardsWithFuseTest.java @@ -6,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class CastSplitCardsWithFuseTest extends CardTestPlayerBase { @@ -27,8 +26,10 @@ public class CastSplitCardsWithFuseTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wear", "Juggernaut"); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Wear // Tear", 1); @@ -52,8 +53,10 @@ public class CastSplitCardsWithFuseTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tear", "Absolute Grace"); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Wear // Tear", 1); @@ -62,8 +65,9 @@ public class CastSplitCardsWithFuseTest extends CardTestPlayerBase { @Test public void testCastingFusedSpell() { + // TODO: AI can't distribute mana for future (e.g. it consume W instead R and can't cast next split half that require W) addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); - addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1 + 1); // INSTANT // Wear {1}{R} // Destroy target artifact. @@ -76,12 +80,17 @@ public class CastSplitCardsWithFuseTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Absolute Grace"); // Enchantment addCard(Zone.BATTLEFIELD, playerB, "Juggernaut"); // Artifact + showAvaileableAbilities("abils", 1, PhaseStep.PRECOMBAT_MAIN, playerA); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "fused Wear // Tear"); - playerA.addTarget("Juggernaut"); - playerA.addTarget("Absolute Grace"); + addTarget(playerA, "Juggernaut"); + addTarget(playerA, "Absolute Grace"); + //playerA.addTarget("Absolute Grace"); + showBattlefield("after", 1, PhaseStep.BEGIN_COMBAT, playerB); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Wear // Tear", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java index f8294a5b418..e1086fcac97 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java @@ -1,13 +1,12 @@ - package org.mage.test.cards.triggers; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class ReturnToBattlefieldEffectsTest extends CardTestPlayerBase { @@ -149,7 +148,7 @@ public class ReturnToBattlefieldEffectsTest extends CardTestPlayerBase { attack(2, playerB, "Reassembling Skeleton"); block(2, playerA, "Necroskitter", "Reassembling Skeleton"); - activateAbility(2, PhaseStep.COMBAT_DAMAGE, playerB, "{1}{B}: Return", NO_TARGET, "Whenever a creature"); + activateAbility(2, PhaseStep.COMBAT_DAMAGE, playerB, "{1}{B}: Return", TestPlayer.NO_TARGET, "Whenever a creature"); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java index a00fce8d9d0..42633cee9bd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java @@ -251,13 +251,15 @@ public class SpellskiteTest extends CardTestPlayerBase { // Cast Fiery Justice castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); - addTarget(playerA, playerB); // 5 life to B - addTargetAmount(playerA, "Scute Mob" , 1); // target 1 + addTargetAmount(playerA, "Scute Mob", 1); // target 1 addTargetAmount(playerA, "Spellskite", 4); // target 2 + addTarget(playerA, playerB); // 5 life to B + // B activate Spellskite, but can't change any targets cause it's already targeted activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); setChoice(playerB, "Yes"); // pay 2 life + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertAllCommandsUsed(); @@ -319,9 +321,9 @@ public class SpellskiteTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Fiery Justice"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); // 5 damage distributed to any number of targets - addTargetAmount(playerA, "Royal Assassin",1); - addTargetAmount(playerA, "Blinking Spirit",2); - addTargetAmount(playerA, "Pearled Unicorn",2); + addTargetAmount(playerA, "Royal Assassin", 1); + addTargetAmount(playerA, "Blinking Spirit", 2); + addTargetAmount(playerA, "Pearled Unicorn", 2); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); setChoice(playerB, "Yes"); // pay 2 life diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java index 7e9d8b2cf14..b0ec4c7b39d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java @@ -42,7 +42,7 @@ public class TestComputerPlayer extends ComputerPlayer { if (!this.testPlayerLink.getChoices().isEmpty()) { MageObject object = game.getObject(ability.getSourceId()); if (object != null) { - LinkedHashMap useableAbilities = this.getSpellAbilities(object, game.getState().getZone(object.getId()), game); + LinkedHashMap useableAbilities = getSpellAbilities(playerId, object, game.getState().getZone(object.getId()), game); // left, right or fused cast for (String choose : this.testPlayerLink.getChoices()) { diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java index e647128bb6c..f8d9933eb4a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java @@ -42,7 +42,7 @@ public class TestComputerPlayer7 extends ComputerPlayer7 { if (!this.testPlayerLink.getChoices().isEmpty()) { MageObject object = game.getObject(ability.getSourceId()); if (object != null) { - LinkedHashMap useableAbilities = this.getSpellAbilities(object, game.getState().getZone(object.getId()), game); + LinkedHashMap useableAbilities = getSpellAbilities(playerId, object, game.getState().getZone(object.getId()), game); // left, right or fused cast for (String choose : this.testPlayerLink.getChoices()) { 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 651a8d0fab1..13831632210 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 @@ -1,11 +1,5 @@ package org.mage.test.player; -import java.io.Serializable; -import java.util.*; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; import mage.MageItem; import mage.MageObject; import mage.MageObjectReference; @@ -17,7 +11,6 @@ import mage.abilities.costs.Costs; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.abilities.mana.ManaOptions; import mage.cards.Card; @@ -55,6 +48,7 @@ import mage.player.ai.ComputerPlayer; import mage.players.Library; import mage.players.ManaPool; import mage.players.Player; +import mage.players.PlayerImpl; import mage.players.net.UserData; import mage.target.*; import mage.target.common.*; @@ -62,6 +56,13 @@ import mage.util.CardUtil; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Ignore; + +import java.io.Serializable; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*; /** @@ -74,9 +75,10 @@ public class TestPlayer implements Player { private static final Logger LOGGER = Logger.getLogger(TestPlayer.class); - public static final String TARGET_SKIP = "[target_skip]"; + public static final String TARGET_SKIP = "[target_skip]"; // stop/skip targeting public static final String BLOCK_SKIP = "[block_skip]"; public static final String ATTACK_SKIP = "[attack_skip]"; + public static final String NO_TARGET = "NO_TARGET"; // cast spell or activate ability without target defines private int maxCallsWithoutAction = 100; private int foundNoAction = 0; @@ -84,7 +86,6 @@ public class TestPlayer implements Player { private final List actions = new ArrayList<>(); private final List choices = new ArrayList<>(); // choices stack for choice private final List targets = new ArrayList<>(); // targets stack for choose (it's uses on empty direct target by cast command) - private final LinkedHashMap targetsAmount = new LinkedHashMap<>(); // targets and amounts for targets that also need to set an amount private final Map aliases = new HashMap<>(); // aliases for game objects/players (use it for cards with same name to save and use) private final List modesSet = new ArrayList<>(); @@ -156,16 +157,6 @@ public class TestPlayer implements Player { targets.add(target); } - /** - * Sets the data for TargetAmount classes that include also an amount beside the target like TargetPermanentAmount - * - * @param targetName - * @param amount - */ - public void addTargetAmount(String targetName, Integer amount) { - targetsAmount.put(targetName, amount); - } - public void addAlias(String name, UUID Id) { aliases.put(name, Id); } @@ -188,7 +179,7 @@ public class TestPlayer implements Player { /** * @param maxCallsWithoutAction max number of priority passes a player may - * have for this test (default = 100) + * have for this test (default = 100) */ public void setMaxCallsWithoutAction(int maxCallsWithoutAction) { this.maxCallsWithoutAction = maxCallsWithoutAction; @@ -518,7 +509,7 @@ public class TestPlayer implements Player { if (ability.toString().startsWith(groups[0])) { int bookmark = game.bookmarkState(); Ability newAbility = ability.copy(); - if (groups.length > 1 && !groups[1].equals("target=NO_TARGET")) { + if (groups.length > 1 && !groups[1].equals("target=" + NO_TARGET)) { groupsForTargetHandling = groups; } if (computerPlayer.activateAbility((ActivatedAbility) newAbility, game)) { @@ -909,12 +900,12 @@ public class TestPlayer implements Player { List data = cards.stream() .map(c -> (((c instanceof PermanentToken) ? "[T] " : "[C] ") - + c.getIdName() - + (c.isCopy() ? " [copy of " + c.getCopyFrom().getId().toString().substring(0, 3) + "]" : "") - + " - " + c.getPower().getValue() + "/" + c.getToughness().getValue() - + (c.isPlaneswalker() ? " - L" + c.getCounters(game).getCount(CounterType.LOYALTY) : "") - + ", " + (c.isTapped() ? "Tapped" : "Untapped") - + (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName()))) + + c.getIdName() + + (c.isCopy() ? " [copy of " + c.getCopyFrom().getId().toString().substring(0, 3) + "]" : "") + + " - " + c.getPower().getValue() + "/" + c.getToughness().getValue() + + (c.isPlaneswalker() ? " - L" + c.getCounters(game).getCount(CounterType.LOYALTY) : "") + + ", " + (c.isTapped() ? "Tapped" : "Untapped") + + (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName()))) .sorted() .collect(Collectors.toList()); @@ -938,11 +929,11 @@ public class TestPlayer implements Player { List data = abilities.stream() .map(a -> (a.getZone() + " -> " - + a.getSourceObject(game).getIdName() + " -> " - + (a.toString().length() > 0 - ? a.toString().substring(0, Math.min(20, a.toString().length()) - 1) - : a.getClass().getSimpleName()) - + "...")) + + a.getSourceObject(game).getIdName() + " -> " + + (a.toString().length() > 0 + ? a.toString().substring(0, Math.min(20, a.toString().length()) - 1) + : a.getClass().getSimpleName()) + + "...")) .sorted() .collect(Collectors.toList()); @@ -1296,7 +1287,7 @@ public class TestPlayer implements Player { UUID defenderId = null; boolean mustAttackByAction = false; boolean madeAttackByAction = false; - for (Iterator it = actions.iterator(); it.hasNext();) { + for (Iterator it = actions.iterator(); it.hasNext(); ) { PlayerAction action = it.next(); if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("attack:")) { mustAttackByAction = true; @@ -1357,7 +1348,7 @@ public class TestPlayer implements Player { } if (mustAttackByAction && !madeAttackByAction) { - this.chooseStrictModeFailed(game, "select attackers must use attack command but don't"); + this.chooseStrictModeFailed("attacker", game, "select attackers must use attack command but don't"); } // AI play if no actions available @@ -1472,9 +1463,9 @@ public class TestPlayer implements Player { return o != null ? o.getClass().getSimpleName() + ": " + o.getMessage() : "null"; } - private void chooseStrictModeFailed(Game game, String reason) { + private void chooseStrictModeFailed(String choiceType, Game game, String reason) { if (strictChooseMode) { - Assert.fail("Missing target/choice def for turn " + game.getTurnNum() + ", " + this.getName() + ", " + Assert.fail("Missing " + choiceType + " def for turn " + game.getTurnNum() + ", " + this.getName() + ", " + game.getStep().getType().name() + ": " + reason); } } @@ -1501,7 +1492,7 @@ public class TestPlayer implements Player { return null; } - this.chooseStrictModeFailed(game, getInfo(source)); + this.chooseStrictModeFailed("mode", game, getInfo(source)); return computerPlayer.chooseMode(modes, source, game); } @@ -1515,7 +1506,7 @@ public class TestPlayer implements Player { //Assert.fail("Wrong choice"); } - this.chooseStrictModeFailed(game, choice.getMessage()); + this.chooseStrictModeFailed("choice", game, choice.getMessage()); return computerPlayer.choose(outcome, choice, game); } @@ -1525,21 +1516,22 @@ public class TestPlayer implements Player { return 0; } if (!choices.isEmpty()) { - for (String choice : choices) { - int index = 0; - for (Map.Entry entry : rEffects.entrySet()) { - if (entry.getValue().startsWith(choice)) { - choices.remove(choice); - return index; - } - index++; + String choice = choices.get(0); + + int index = 0; + for (Map.Entry entry : rEffects.entrySet()) { + if (entry.getValue().startsWith(choice)) { + choices.remove(choice); + return index; } + index++; } + // TODO: enable fail checks and fix tests //Assert.fail("wrong choice"); } - this.chooseStrictModeFailed(game, String.join("; ", rEffects.values())); + this.chooseStrictModeFailed("choice", game, String.join("; ", rEffects.values())); return computerPlayer.chooseReplacementEffect(rEffects, game); } @@ -1737,7 +1729,7 @@ public class TestPlayer implements Player { // ignore player select if (!target.getMessage().equals("Select a starting player")) { - this.chooseStrictModeFailed(game, getInfo(game.getObject(sourceId)) + "; " + getInfo(target)); + this.chooseStrictModeFailed("choice", game, getInfo(game.getObject(sourceId)) + "; " + getInfo(target)); } return computerPlayer.choose(outcome, target, sourceId, game, options); } @@ -1774,9 +1766,11 @@ public class TestPlayer implements Player { if (!targets.isEmpty()) { - // do not select + // skip targets if (targets.get(0).equals(TARGET_SKIP)) { - Assert.assertEquals("found empty choice, but target is not support 0 choice", 0, target.getMinNumberOfTargets()); + Assert.assertTrue("found skip target, but it require more targets, needs " + + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", + target.getTargets().size() >= target.getMinNumberOfTargets()); targets.remove(0); return true; } @@ -2030,7 +2024,7 @@ public class TestPlayer implements Player { Assert.fail(message); } - this.chooseStrictModeFailed(game, getInfo(source) + "; " + getInfo(target)); + this.chooseStrictModeFailed("target", game, getInfo(source) + "; " + getInfo(target)); return computerPlayer.chooseTarget(outcome, target, source, game); } @@ -2059,7 +2053,7 @@ public class TestPlayer implements Player { //Assert.fail("Wrong target"); } - this.chooseStrictModeFailed(game, getInfo(source) + "; " + getInfo(target)); + this.chooseStrictModeFailed("target", game, getInfo(source) + "; " + getInfo(target)); return computerPlayer.chooseTarget(outcome, cards, target, source, game); } @@ -2076,7 +2070,7 @@ public class TestPlayer implements Player { //Assert.fail("Wrong choice"); } - this.chooseStrictModeFailed(game, abilities.stream().map(this::getInfo).collect(Collectors.joining("; "))); + this.chooseStrictModeFailed("choice", game, abilities.stream().map(this::getInfo).collect(Collectors.joining("; "))); return computerPlayer.chooseTriggeredAbility(abilities, game); } @@ -2103,7 +2097,8 @@ public class TestPlayer implements Player { //Assert.fail("Wrong choice"); } - this.chooseStrictModeFailed(game, getInfo(source) + "; " + message + ": " + trueText + " - " + falseText); + this.chooseStrictModeFailed("choice", game, getInfo(source) + "; " + message + ": " + + (trueText != null ? trueText : "Yes") + " - " + (falseText != null ? falseText : "No")); return computerPlayer.chooseUse(outcome, message, secondMessage, trueText, falseText, source, game); } @@ -2119,7 +2114,7 @@ public class TestPlayer implements Player { } } - this.chooseStrictModeFailed(game, getInfo(ability) + "; " + message); + this.chooseStrictModeFailed("choice", game, getInfo(ability) + "; " + message); return computerPlayer.announceXMana(min, max, multiplier, message, game, ability); } @@ -2133,7 +2128,7 @@ public class TestPlayer implements Player { } } - this.chooseStrictModeFailed(game, getInfo(ability) + "; " + message); + this.chooseStrictModeFailed("choice", game, getInfo(ability) + "; " + message); return computerPlayer.announceXCost(min, max, message, game, ability, null); } @@ -2147,7 +2142,7 @@ public class TestPlayer implements Player { } } - this.chooseStrictModeFailed(game, message); + this.chooseStrictModeFailed("choice", game, message); return computerPlayer.getAmount(min, max, message, game); } @@ -3248,7 +3243,7 @@ public class TestPlayer implements Player { @Override public boolean choose(Outcome outcome, Target target, - UUID sourceId, Game game + UUID sourceId, Game game ) { // needed to call here the TestPlayer because it's overwitten return choose(outcome, target, sourceId, game, null); @@ -3256,7 +3251,7 @@ public class TestPlayer implements Player { @Override public boolean choose(Outcome outcome, Cards cards, - TargetCard target, Game game + TargetCard target, Game game ) { if (!choices.isEmpty()) { for (String choose2 : choices) { @@ -3286,44 +3281,69 @@ public class TestPlayer implements Player { //Assert.fail("Wrong choice"); } - this.chooseStrictModeFailed(game, getInfo(target)); + this.chooseStrictModeFailed("choice", game, getInfo(target)); return computerPlayer.choose(outcome, cards, target, game); } - @Override + @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game ) { - if (!targetsAmount.isEmpty()) { - for (Iterator> iterator = targetsAmount.entrySet().iterator(); iterator.hasNext();) { - Entry targetRecord = iterator.next(); - if (target.getAmountRemaining() > 0) { - target.possibleTargets(source.getSourceId(), source.getControllerId(), game).forEach((possibleTarget) -> { - MageObject objectPermanent = game.getObject(possibleTarget); - Player objectPlayer = game.getPlayer(possibleTarget); - String objectName = objectPermanent != null ? objectPermanent.getName() : objectPlayer.getName(); - if (objectName.equals(targetRecord.getKey())) { - if (!target.getTargets().contains(possibleTarget) && target.canTarget(possibleTarget, source, game)) { - // can select - target.addTarget(possibleTarget, targetRecord.getValue(), source, game); - iterator.remove(); - } - } - }); + // chooseTargetAmount calls for EACH target cycle (e.g. one target per click, see TargetAmount) + // if use want to stop choosing then chooseTargetAmount must return false (example: up to xxx) + + Assert.assertNotEquals("chooseTargetAmount needs non zero amount remaining", 0, target.getAmountRemaining()); + + if (!targets.isEmpty()) { + + // skip targets + if (targets.get(0).equals(TARGET_SKIP)) { + Assert.assertTrue("found skip target, but it require more targets, needs " + + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", + target.getTargets().size() >= target.getMinNumberOfTargets()); + targets.remove(0); + return false; // false in chooseTargetAmount = stop to choose + } + + // only target amount needs + String[] choiceSettings = targets.get(0).split("\\^"); + if (choiceSettings.length != 2 + || !choiceSettings[1].startsWith("X=")) { + Assert.fail("Must be target amount, but found unknown target: " + targets.get(0)); + } + String targetName = choiceSettings[0]; + int targetAmount = Integer.parseInt(choiceSettings[1].substring("X=".length())); + + // player target support + if (targetName.startsWith("targetPlayer=")) { + targetName = targetName.substring(targetName.indexOf("targetPlayer=") + "targetPlayer=".length()); + } + + String targetInfo = "(" + targetName + " - " + targetAmount + ")"; + Assert.assertTrue("target amount must be non zero " + targetInfo, targetAmount > 0); + Assert.assertTrue("target amount must be <= remaining = " + target.getAmountRemaining() + " " + targetInfo, targetAmount <= target.getAmountRemaining()); + + if (target.getAmountRemaining() > 0) { + for (UUID possibleTarget : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + MageObject objectPermanent = game.getObject(possibleTarget); + Player objectPlayer = game.getPlayer(possibleTarget); + String objectName = objectPermanent != null ? objectPermanent.getName() : objectPlayer.getName(); + if (objectName.equals(targetName)) { + if (!target.getTargets().contains(possibleTarget) && target.canTarget(possibleTarget, source, game)) { + // can select + target.addTarget(possibleTarget, targetAmount, source, game); + targets.remove(0); + return true; // one target per choose call + } + } } - } - } - if (!target.isRequired() && target.getAmountRemaining() > 0) { - if (strictChooseMode) { - target.setAmountDefinition(StaticValue.get(0)); - target.setAmount(source, game); - return true; } } - this.chooseStrictModeFailed(game, getInfo(source) + "; " + getInfo(target)); + + this.chooseStrictModeFailed("target", game, getInfo(source) + "; " + getInfo(target)); return computerPlayer.chooseTargetAmount(outcome, target, source, game); } - + @Override public boolean chooseMulligan(Game game ) { @@ -3332,15 +3352,15 @@ public class TestPlayer implements Player { @Override public boolean choosePile(Outcome outcome, String message, - List pile1, List pile2, - Game game + List pile1, List pile2, + Game game ) { return computerPlayer.choosePile(outcome, message, pile1, pile2, game); } @Override public boolean playMana(Ability ability, ManaCost unpaid, - String promptText, Game game + String promptText, Game game ) { groupsForTargetHandling = null; return computerPlayer.playMana(ability, unpaid, promptText, game); @@ -3354,15 +3374,15 @@ public class TestPlayer implements Player { @Override public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, - List blockerOrder, Game game + List blockerOrder, Game game ) { return computerPlayer.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game); } @Override public void assignDamage(int damage, List targets, - String singleTargetName, UUID sourceId, - Game game + String singleTargetName, UUID sourceId, + Game game ) { computerPlayer.assignDamage(damage, targets, singleTargetName, sourceId, game); } @@ -3381,14 +3401,14 @@ public class TestPlayer implements Player { @Override public void pickCard(List cards, Deck deck, - Draft draft + Draft draft ) { computerPlayer.pickCard(cards, deck, draft); } @Override public boolean scry(int value, Ability source, - Game game + Game game ) { // Don't scry at the start of the game. if (game.getTurnNum() == 1 && game.getStep() == null) { @@ -3399,44 +3419,44 @@ public class TestPlayer implements Player { @Override public boolean surveil(int value, Ability source, - Game game + Game game ) { return computerPlayer.surveil(value, source, game); } @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return computerPlayer.moveCards(card, toZone, source, game); } @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); } @Override public boolean moveCards(Cards cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return computerPlayer.moveCards(cards, toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return computerPlayer.moveCards(cards, toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); } @@ -3524,6 +3544,23 @@ public class TestPlayer implements Player { @Override public SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana) { - return card.getSpellAbility(); + String allInfo = ""; + if (!choices.isEmpty()) { + Map useable = PlayerImpl.getSpellAbilities(this.getId(), card, game.getState().getZone(card.getId()), game); + for (ActivatedAbility ability : useable.values()) { + if (ability.toString().startsWith(choices.get(0))) { + choices.remove(0); + return (SpellAbility) ability; + } + } + + allInfo = useable.values().stream().map(Object::toString).collect(Collectors.joining("\n")); + + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong choice"); + } + + this.chooseStrictModeFailed("choice", game, getInfo(card) + " - can't select ability to cast.\n" + "Card's abilities:\n" + allInfo); + return computerPlayer.chooseAbilityForCast(card, game, noMana); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index c7f159a9526..e789aff52ef 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -46,9 +46,6 @@ import java.util.stream.Collectors; * @author ayratn */ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implements CardTestAPI { - - // Defines the constant if for activate ability is not target but a ability on the stack to define - public static final String NO_TARGET = "NO_TARGET"; // TODO: add target player param to commands public static final String CHECK_COMMAND_PT = "PT"; @@ -1395,7 +1392,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param player * @param cardName * @param targetName for modes you can add "mode=3" before target name, - * multiple targets can be seperated by ^ + * multiple targets can be seperated by ^, not target marks as TestPlayer.NO_TARGET */ public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName) { //Assert.assertNotEquals("", cardName); @@ -1604,11 +1601,29 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement player.addTarget("targetPlayer=" + targetPlayer.getName()); } + /** + * @param player + * @param target use TestPlayer.TARGET_SKIP to 0 targets selects or to stop "up two xxx" selection + * @param amount + */ public void addTargetAmount(TestPlayer player, String target, int amount) { - player.addTargetAmount(target, amount); + if (target.equals(TestPlayer.TARGET_SKIP)) { + player.addTarget(target); + } else { + player.addTarget(target + "^X=" + amount); + } } - - + + public void addTargetAmount(TestPlayer player, Player targetPlayer, int amount) { + addTargetAmount(player, "targetPlayer=" + targetPlayer.getName(), amount); + } + + + public void addTargetAmount(TestPlayer player, String target) { + Assert.assertTrue("Only skip command allows here", target.equals(TestPlayer.TARGET_SKIP)); + addTargetAmount(player, target, 0); + } + public void setDecknamePlayerA(String deckname) { deckNameA = deckname; } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 361f99c32e5..6a03dd58461 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1,9 +1,6 @@ package mage.players; import com.google.common.collect.ImmutableMap; -import java.io.Serializable; -import java.util.*; -import java.util.Map.Entry; import mage.ConditionalMana; import mage.MageObject; import mage.MageObjectReference; @@ -68,6 +65,10 @@ import mage.util.GameLog; import mage.util.RandomUtil; import org.apache.log4j.Logger; +import java.io.Serializable; +import java.util.*; +import java.util.Map.Entry; + public abstract class PlayerImpl implements Player, Serializable { private static final Logger logger = Logger.getLogger(PlayerImpl.class); @@ -613,7 +614,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (abilities.containsKey(HexproofAbility.getInstance().getId())) { if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game) && null == game.getContinuousEffects().asThough(this.getId(), - AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)) { + AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)) { return false; } } @@ -621,7 +622,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (abilities.containsKey(HexproofFromWhiteAbility.getInstance().getId())) { if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game) && null == game.getContinuousEffects().asThough(this.getId(), - AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) + AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) && source.getColor(game).isWhite()) { return false; } @@ -630,7 +631,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (abilities.containsKey(HexproofFromBlueAbility.getInstance().getId())) { if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game) && null == game.getContinuousEffects().asThough(this.getId(), - AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) + AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) && source.getColor(game).isBlue()) { return false; } @@ -639,7 +640,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (abilities.containsKey(HexproofFromBlackAbility.getInstance().getId())) { if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game) && null == game.getContinuousEffects().asThough(this.getId(), - AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) + AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) && source.getColor(game).isBlack()) { return false; } @@ -648,7 +649,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (abilities.containsKey(HexproofFromMonocoloredAbility.getInstance().getId())) { if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game) && null == game.getContinuousEffects().asThough(this.getId(), - AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) + AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) && !source.getColor(game).isColorless() && !source.getColor(game).isMulticolored()) { return false; @@ -691,7 +692,7 @@ public abstract class PlayerImpl implements Player, Serializable { game.informPlayers(getLogName() + " discards down to " + this.maxHandSize + (this.maxHandSize == 1 - ? " hand card" : " hand cards")); + ? " hand card" : " hand cards")); } discard(hand.size() - this.maxHandSize, false, null, game); } @@ -799,7 +800,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (card != null) { GameEvent gameEvent = GameEvent.getEvent(GameEvent.EventType.DISCARD_CARD, card.getId(), source == null - ? null : source.getSourceId(), playerId); + ? null : source.getSourceId(), playerId); gameEvent.setFlag(source != null); // event from effect or from cost (source == null) if (!game.replaceEvent(gameEvent, source)) { // write info to game log first so game log infos from triggered or replacement effects follow in the game log @@ -814,7 +815,7 @@ public abstract class PlayerImpl implements Player, Serializable { // So discard is also successful if card is moved to another zone by replacement effect! game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DISCARDED_CARD, card.getId(), source == null - ? null : source.getSourceId(), playerId)); + ? null : source.getSourceId(), playerId)); return true; } } @@ -1450,7 +1451,7 @@ public abstract class PlayerImpl implements Player, Serializable { return false; } - public LinkedHashMap getSpellAbilities(MageObject object, Zone zone, Game game) { + public static LinkedHashMap getSpellAbilities(UUID playerId, MageObject object, Zone zone, Game game) { LinkedHashMap useable = new LinkedHashMap<>(); for (Ability ability : object.getAbilities()) { if (ability instanceof SpellAbility) { @@ -1502,7 +1503,7 @@ public abstract class PlayerImpl implements Player, Serializable { // Also called on the whole split card but only passing the fuse ability and other whole-split-card shared abilities // as candidates. private void getUseableActivatedAbilitiesHalfImpl(MageObject object, Zone zone, Game game, Abilities candidateAbilites, - LinkedHashMap output) { + LinkedHashMap output) { boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game); ManaOptions availableMana = null; // ManaOptions availableMana = getManaAvailable(game); // can only be activated if mana calculation works flawless otherwise player can't play spells they could play if calculation would work correctly @@ -1554,10 +1555,10 @@ public abstract class PlayerImpl implements Player, Serializable { != null // if anyone sees an issue with this code, please report it. Worked in my testing. ! || game.getContinuousEffects().asThough(object.getId(), - AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, - ability, - this.getId(), - game) + AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, + ability, + this.getId(), + game) != null) { if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { @@ -1920,9 +1921,9 @@ public abstract class PlayerImpl implements Player, Serializable { } private List getPermanentsThatCanBeUntapped(Game game, - List canBeUntapped, - RestrictionUntapNotMoreThanEffect handledEffect, - Map>, Integer> notMoreThanEffectsUsage) { + List canBeUntapped, + RestrictionUntapNotMoreThanEffect handledEffect, + Map>, Integer> notMoreThanEffectsUsage) { List leftForUntap = new ArrayList<>(); // select permanents that can still be untapped for (Permanent permanent : canBeUntapped) { @@ -2630,7 +2631,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId, - boolean triggerEvents) { + boolean triggerEvents) { //20091005 - 701.14c Library searchedLibrary = null; String searchInfo = null; @@ -2834,7 +2835,7 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param game * @param appliedEffects - * @param numSides Number of sides the dice has + * @param numSides Number of sides the dice has * @return the number that the player rolled */ @Override @@ -2871,16 +2872,16 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param game * @param appliedEffects - * @param numberChaosSides The number of chaos sides the planar die - * currently has (normally 1 but can be 5) + * @param numberChaosSides The number of chaos sides the planar die + * currently has (normally 1 but can be 5) * @param numberPlanarSides The number of chaos sides the planar die - * currently has (normally 1) + * currently has (normally 1) * @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll * or NilRoll */ @Override public PlanarDieRoll rollPlanarDie(Game game, ArrayList appliedEffects, int numberChaosSides, - int numberPlanarSides) { + int numberPlanarSides) { int result = RandomUtil.nextInt(9) + 1; PlanarDieRoll roll = PlanarDieRoll.NIL_ROLL; if (numberChaosSides + numberPlanarSides > 9) { @@ -3037,7 +3038,7 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param ability - * @param available if null, it won't be checked if enough mana is available + * @param available if null, it won't be checked if enough mana is available * @param sourceObject * @param game * @return @@ -3358,8 +3359,8 @@ public abstract class PlayerImpl implements Player, Serializable { if (ability instanceof ActivatedAbility) { if (!(ability instanceof PlayLandAbility) || !game.getContinuousEffects().preventedByRuleModification( - GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), - ability.getSourceId(), playerId), ability, game, true)) { + GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), + ability.getSourceId(), playerId), ability, game, true)) { if (canPlay((ActivatedAbility) ability, availableMana, card, game)) { playable.add(ability); } @@ -3684,7 +3685,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, - UUID controllerId, Game game + UUID controllerId, Game game ) { return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game); } @@ -3837,8 +3838,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { Set cardList = new HashSet<>(); if (card != null) { @@ -3849,22 +3850,22 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Cards cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return moveCards(cards.getCards(game), toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return moveCards(cards, toZone, source, game, false, false, false, null); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { if (cards.isEmpty()) { return true; @@ -3966,8 +3967,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardsToExile(Card card, Ability source, - Game game, boolean withName, UUID exileId, - String exileZoneName + Game game, boolean withName, UUID exileId, + String exileZoneName ) { Set cards = new HashSet<>(); cards.add(card); @@ -3976,8 +3977,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardsToExile(Set cards, Ability source, - Game game, boolean withName, UUID exileId, - String exileZoneName + Game game, boolean withName, UUID exileId, + String exileZoneName ) { if (cards.isEmpty()) { return true; @@ -3993,14 +3994,14 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, - Game game + Game game ) { return this.moveCardToHandWithInfo(card, sourceId, game, true); } @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, - Game game, boolean withName + Game game, boolean withName ) { boolean result = false; Zone fromZone = game.getState().getZone(card.getId()); @@ -4025,7 +4026,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public Set moveCardsToGraveyardWithInfo(Set allCards, Ability source, - Game game, Zone fromZone + Game game, Zone fromZone ) { UUID sourceId = source == null ? null : source.getSourceId(); Set movedCards = new LinkedHashSet<>(); @@ -4033,7 +4034,7 @@ public abstract class PlayerImpl implements Player, Serializable { // identify cards from one owner Cards cards = new CardsImpl(); UUID ownerId = null; - for (Iterator it = allCards.iterator(); it.hasNext();) { + for (Iterator it = allCards.iterator(); it.hasNext(); ) { Card card = it.next(); if (cards.isEmpty()) { ownerId = card.getOwnerId(); @@ -4096,7 +4097,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, - Game game, Zone fromZone + Game game, Zone fromZone ) { if (card == null) { return false; @@ -4125,8 +4126,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, - Game game, Zone fromZone, - boolean toTop, boolean withName + Game game, Zone fromZone, + boolean toTop, boolean withName ) { if (card == null) { return false; @@ -4191,7 +4192,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, - Game game, Zone fromZone, boolean withName) { + Game game, Zone fromZone, boolean withName) { if (card == null) { return false; } @@ -4214,7 +4215,7 @@ public abstract class PlayerImpl implements Player, Serializable { game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() + (card.isCopy() ? " (Copy)" : "") : "a card face down") + ' ' + (fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH) - + ' ' : "") + "to the exile zone"); + + ' ' : "") + "to the exile zone"); } result = true; diff --git a/Mage/src/main/java/mage/target/TargetPermanent.java b/Mage/src/main/java/mage/target/TargetPermanent.java index 9114df0019b..65a8e26e33c 100644 --- a/Mage/src/main/java/mage/target/TargetPermanent.java +++ b/Mage/src/main/java/mage/target/TargetPermanent.java @@ -1,8 +1,5 @@ package mage.target; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.constants.Zone; @@ -11,8 +8,11 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class TargetPermanent extends TargetObject { @@ -85,11 +85,11 @@ public class TargetPermanent extends TargetObject { /** * Checks if there are enough {@link Permanent} that can be chosen. - * + *

* Takes into account notTarget parameter, in case it's true doesn't check * for protection, shroud etc. * - * @param sourceId the target event source + * @param sourceId the target event source * @param sourceControllerId controller of the target event source * @param game * @return true if enough valid {@link Permanent} exist @@ -146,6 +146,7 @@ public class TargetPermanent extends TargetObject { @Override public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + // TODO: check if possible targets works with setTargetController from some cards like Nicol Bolas, Dragon-God Set possibleTargets = new HashSet<>(); MageObject targetSource = game.getObject(sourceId); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) {