diff --git a/Mage.Client/release/sample-decks/Commander/Tasigur BGU.dck b/Mage.Client/release/sample-decks/Commander/Tasigur BGU.dck new file mode 100644 index 0000000000..5c185ee126 --- /dev/null +++ b/Mage.Client/release/sample-decks/Commander/Tasigur BGU.dck @@ -0,0 +1,97 @@ +1 [MMQ:316] Dust Bowl +1 [MBS:43] Go for the Throat +1 [ALL:42] Force of Will +1 [ZEN:220] Misty Rainforest +1 [10E:361] Treetop Village +1 [10E:362] Underground River +1 [ROE:115] Inquisition of Kozilek +1 [STH:137] Volrath's Stronghold +1 [PLC:85] Damnation +1 [FUT:173] Tolaria West +1 [ISD:78] Snapcaster Mage +1 [ZEN:67] Spell Pierce +1 [ZEN:229] Verdant Catacombs +1 [M11:70] Preordain +1 [C13:177] Baleful Strix +1 [ZEN:223] Scalding Tarn +1 [MBS:138] Sword of Feast and Famine +1 [NPH:57] Dismember +1 [TMP:58] Dismiss +1 [INV:57] Fact or Fiction +1 [DGM:93] Putrefy +1 [ONS:320] Lonely Sandbar +1 [GTC:240] Breeding Pool +1 [DTK:262] Forest +1 [ISD:105] Liliana of the Veil +1 [TMP:340] Wasteland +1 [JUD:46] Mental Note +1 [ULG:36] Miscalculation +2 [CSP:152] Snow-Covered Island +1 [RAV:63] Remand +1 [LRW:56] Cryptic Command +1 [3ED:283] Bayou +1 [5ED:191] Sylvan Library +1 [CMD:269] Command Tower +1 [EXO:35] Forbid +1 [DDO:36] AEtherize +1 [KTK:36] Dig Through Time +1 [RTR:141] Abrupt Decay +1 [SHM:280] Sunken Ruins +1 [DIS:33] Spell Snare +1 [ARB:92] Maelstrom Pulse +1 [KTK:81] Murderous Cut +1 [TSP:48] Ancestral Vision +1 [TMP:22] Diabolic Edict +1 [10E:319] Crucible of Worlds +1 [M12:63] Mana Leak +1 [FUT:52] Logic Knot +1 [CHK:268] Sensei's Divining Top +1 [THS:225] Temple of Deceit +1 [ODY:317] Cephalid Coliseum +1 [WWK:145] Tectonic Edge +1 [EVE:41] Raven's Crime +1 [C13:96] Toxic Deluge +1 [9ED:152] Phyrexian Arena +1 [KTK:248] Windswept Heath +1 [KTK:204] Sultai Charm +1 [KTK:249] Wooded Foothills +1 [M13:223] Drowned Catacomb +1 [RAV:172] Life from the Loam +1 [THS:107] Thoughtseize +1 [MMQ:61] Brainstorm +1 [M15:244] Llanowar Wastes +1 [ISD:55] Forbidden Alchemy +1 [APC:114] Pernicious Deed +1 [RTR:243] Overgrown Tomb +1 [7ED:76] Force Spike +1 [TMP:70] Intuition +1 [3ED:305] Underground Sea +1 [M15:248] Urborg, Tomb of Yawgmoth +1 [AVR:226] Cavern of Souls +1 [ISD:241] Hinterland Harbor +1 [DKA:52] Thought Scour +1 [3ED:303] Tropical Island +1 [3ED:13] Demonic Tutor +1 [ISD:249] Woodland Cemetery +1 [M12:73] Ponder +1 [DTK:65] Negate +1 [RAV:82] Darkblast +1 [WWK:134] Creeping Tar Pit +1 [GTC:249] Watery Grave +1 [WWK:132] Bojuka Bog +1 [KTK:239] Polluted Delta +1 [KTK:233] Flooded Strand +1 [KTK:59] Treasure Cruise +1 [TSP:202] Krosan Grip +1 [7ED:67] Counterspell +1 [MIR:80] Mystical Tutor +1 [MOR:55] Vendilion Clique +1 [TSP:69] Mystical Teachings +1 [KTK:230] Bloodstained Mire +1 [ZEN:219] Marsh Flats +1 [DTK:256] Swamp +1 [THS:90] Hero's Downfall +3 [DTK:253] Island +1 [WWK:31] Jace, the Mind Sculptor +1 [DTK:98] Duress +SB: 1 [FRF:87] Tasigur, the Golden Fang diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java index 6c28193b77..22037b2ad5 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java @@ -84,6 +84,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { public ComputerPlayer7(final ComputerPlayer7 player) { super(player); + this.allowBadMoves = player.allowBadMoves; } @Override 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 8b8d0febd6..6e7e2e4122 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 @@ -1595,7 +1595,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } @Override - protected List getAvailableManaProducers(Game game) { + public List getAvailableManaProducers(Game game) { return super.getAvailableManaProducers(game); } 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 26308d7616..77bb838f1d 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 @@ -1038,6 +1038,12 @@ public class HumanPlayer extends PlayerImpl { } } + @Override + public boolean activateAbility(ActivatedAbility ability, Game game) { + getManaPool().setStock(); // needed for the "mana already in the pool has to be used manually" option + return super.activateAbility(ability, game); + } + protected void activateAbility(LinkedHashMap abilities, MageObject object, Game game) { updateGameStatePriority("activateAbility", game); if (abilities.size() == 1 && suppressAbilityPicker(abilities.values().iterator().next())) { diff --git a/Mage.Sets/src/mage/sets/avacynrestored/DevoutChaplain.java b/Mage.Sets/src/mage/sets/avacynrestored/DevoutChaplain.java index a1a951f810..3b79a31ed8 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/DevoutChaplain.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/DevoutChaplain.java @@ -78,7 +78,7 @@ public class DevoutChaplain extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - // {tap}, Tap two untapped Humans you control: Exile target artifact or enchantment. + // {T}, Tap two untapped Humans you control: Exile target artifact or enchantment. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new TapSourceCost()); ability.addCost(new TapTargetCost(new TargetControlledPermanent(2, 2, humanFilter, false))); ability.addTarget(new TargetPermanent(filter)); diff --git a/Mage.Sets/src/mage/sets/commander/SewerNemesis.java b/Mage.Sets/src/mage/sets/commander/SewerNemesis.java index 5942953b0c..ee6da4ab79 100644 --- a/Mage.Sets/src/mage/sets/commander/SewerNemesis.java +++ b/Mage.Sets/src/mage/sets/commander/SewerNemesis.java @@ -102,11 +102,11 @@ class SewerNemesisChoosePlayerEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (player != null && permanent != null) { - TargetPlayer target = new TargetPlayer(); + TargetPlayer target = new TargetPlayer(1,1,true); if (player.choose(this.outcome, target, source.getSourceId(), game)) { Player chosenPlayer = game.getPlayer(target.getFirstTarget()); if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); + game.informPlayers(permanent.getLogName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); return true; } diff --git a/Mage.Sets/src/mage/sets/newphyrexia/SheoldredWhisperingOne.java b/Mage.Sets/src/mage/sets/newphyrexia/SheoldredWhisperingOne.java index cc7e64b893..fa84cf9d8d 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/SheoldredWhisperingOne.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/SheoldredWhisperingOne.java @@ -58,10 +58,16 @@ public class SheoldredWhisperingOne extends CardImpl { this.power = new MageInt(6); this.toughness = new MageInt(6); + + // Swampwalk this.addAbility(new SwampwalkAbility()); + + // At the beginning of your upkeep, return target creature card from your graveyard to the battlefield. Ability ability = new BeginningOfUpkeepTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(false), TargetController.YOU, false); ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); this.addAbility(ability); + + // At the beginning of each opponent's upkeep, that player sacrifices a creature. ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeEffect(new FilterCreaturePermanent(), 1, "that player "), TargetController.OPPONENT, false); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/tempest/DiabolicEdict.java b/Mage.Sets/src/mage/sets/tempest/DiabolicEdict.java index 638f4e0b47..a6ad0c8a3c 100644 --- a/Mage.Sets/src/mage/sets/tempest/DiabolicEdict.java +++ b/Mage.Sets/src/mage/sets/tempest/DiabolicEdict.java @@ -45,6 +45,7 @@ public class DiabolicEdict extends CardImpl { super(ownerId, 22, "Diabolic Edict", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{B}"); this.expansionSetCode = "TMP"; + // Target player sacrifices a creature. this.getSpellAbility().addEffect(new SacrificeEffect(new FilterCreaturePermanent(), 1, "Target player")); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java new file mode 100644 index 0000000000..f7b3649f42 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.AI.basic; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBaseAI; + +/** + * + * @author LevelX2 + */ +public class CastCreaturesTest extends CardTestPlayerBaseAI { + + /** + * Tests that the creature is cast if enough mana is available + */ + @Test + public void testSimpleCast() { + addCard(Zone.HAND, playerA, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FadingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FadingTest.java index 77cee8a774..078942e082 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FadingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FadingTest.java @@ -91,7 +91,7 @@ public class FadingTest extends CardTestPlayerBase { public void testFadesAway() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); addCard(Zone.HAND, playerA, "Blastoderm"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blastoderm"); setStopAt(9, PhaseStep.BEGIN_COMBAT); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SewerNemesisTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SewerNemesisTest.java index 37abc2148e..6ca2b46617 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SewerNemesisTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SewerNemesisTest.java @@ -41,12 +41,16 @@ public class SewerNemesisTest extends CardTestPlayerBase { /** - * Sewer Nemesis count's all cards in each player's graveyard to determine it's * / *, not just the cosen player's graveyard. + * BUG: Sewer Nemesis count's all cards in each player's graveyard to determine it's * / *, not just the chosen player's graveyard. * */ @Test public void test1() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + + // As Sewer Nemesis enters the battlefield, choose a player. + // Sewer Nemesis's power and toughness are each equal to the number of cards in the chosen player's graveyard. + // Whenever the chosen player casts a spell, that player puts the top card of his or her library into his or her graveyard. addCard(Zone.HAND, playerA, "Sewer Nemesis"); addCard(Zone.GRAVEYARD, playerA, "Raging Goblin",4); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/SigardaHostOfHeronsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/SigardaHostOfHeronsTest.java index e02c0c7ed9..3148f858b2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/SigardaHostOfHeronsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/SigardaHostOfHeronsTest.java @@ -18,18 +18,25 @@ public class SigardaHostOfHeronsTest extends CardTestPlayerBase { */ @Test public void testCard() { + // Spells and abilities your opponents control can't cause you to sacrifice permanents. addCard(Zone.BATTLEFIELD, playerA, "Sigarda, Host of Herons"); + // {T}, Tap two untapped Humans you control: Exile target artifact or enchantment. addCard(Zone.BATTLEFIELD, playerA, "Devout Chaplain"); + // {2}{B}, Sacrifice a creature: Target opponent reveals his or her hand. You choose a card from it. That player discards that card. Activate this ability only any time you could cast a sorcery. addCard(Zone.BATTLEFIELD, playerA, "Corpse Traders"); + // Target player sacrifices a creature. addCard(Zone.HAND, playerA, "Diabolic Edict"); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); - + addCard(Zone.HAND, playerB, "Diabolic Edict"); addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + + // At the beginning of your upkeep, return target creature card from your graveyard to the battlefield. + // At the beginning of each opponent's upkeep, that player sacrifices a creature. addCard(Zone.BATTLEFIELD, playerB, "Sheoldred, Whispering One"); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Diabolic Edict", playerA); - castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Diabolic Edict", playerB); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Diabolic Edict", playerA); // sacrificing for player A prevented by Sigarda + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Diabolic Edict", playerB); // playerB has to sacrifice Sheldred setStopAt(3, PhaseStep.END_TURN); execute(); @@ -40,9 +47,13 @@ public class SigardaHostOfHeronsTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Sigarda, Host of Herons", 1); assertPermanentCount(playerA, "Devout Chaplain", 1); assertPermanentCount(playerA, "Corpse Traders", 1); + assertGraveyardCount(playerA, "Diabolic Edict", 1); assertGraveyardCount(playerA, 1); assertPermanentCount(playerB, "Sheoldred, Whispering One", 0); + assertHandCount(playerB, "Diabolic Edict", 0); + assertGraveyardCount(playerB, "Sheoldred, Whispering One", 1); + assertGraveyardCount(playerB, "Diabolic Edict", 1); assertGraveyardCount(playerB, 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java index 435c57719d..148c3c3497 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java @@ -102,16 +102,18 @@ public class RandomPlayer extends ComputerPlayer { List playables = getPlayableAbilities(game); Ability ability; while (true) { - if (playables.size() == 1) + if (playables.size() == 1) { ability = playables.get(0); - else + } else { ability = playables.get(rnd.nextInt(playables.size())); + } List options = getPlayableOptions(ability, game); if (!options.isEmpty()) { - if (options.size() == 1) + if (options.size() == 1) { ability = options.get(0); - else + } else { ability = options.get(rnd.nextInt(options.size())); + } } if (ability.getManaCosts().getVariableCosts().size() > 0) { int amount = getAvailableManaProducers(game).size() - ability.getManaCosts().convertedManaCost(); @@ -154,10 +156,11 @@ public class RandomPlayer extends ComputerPlayer { ability = source; } else { - if (options.size() == 1) + if (options.size() == 1) { ability = options.get(0); - else + } else { ability = options.get(rnd.nextInt(options.size())); + } } if (ability.isUsesStack()) { game.getStack().push(new StackAbility(ability, playerId)); @@ -203,15 +206,18 @@ public class RandomPlayer extends ComputerPlayer { @Override public void selectBlockers(Game game, UUID defendingPlayerId) { int numGroups = game.getCombat().getGroups().size(); - if (numGroups == 0) return; + if (numGroups == 0) { + return; + } List blockers = getAvailableBlockers(game); for (Permanent blocker: blockers) { int check = rnd.nextInt(numGroups + 1); if (check < numGroups) { CombatGroup group = game.getCombat().getGroups().get(check); - if (group.getAttackers().size() > 0) + if (group.getAttackers().size() > 0) { this.declareBlocker(this.getId(), blocker.getId(), group.getAttackers().get(0), game); + } } } actionCount++; @@ -243,8 +249,9 @@ public class RandomPlayer extends ComputerPlayer { protected boolean chooseRandomTarget(Target target, Ability source, Game game) { Set possibleTargets = target.possibleTargets(source==null?null:source.getSourceId(), playerId, game); - if (possibleTargets.isEmpty()) + if (possibleTargets.isEmpty()) { return false; + } if (!target.isRequired(source)) { if (rnd.nextInt(possibleTargets.size() + 1) == 0) { return false; @@ -300,8 +307,9 @@ public class RandomPlayer extends ComputerPlayer { @Override public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { - if (cards.isEmpty()) + if (cards.isEmpty()) { return !target.isRequired(source); + } Card card = cards.getRandom(game); target.addTarget(card.getId(), source, game); return true; @@ -373,8 +381,9 @@ public class RandomPlayer extends ComputerPlayer { public Mode chooseMode(Modes modes, Ability source, Game game) { Iterator it = modes.values().iterator(); Mode mode = it.next(); - if (modes.size() == 1) + if (modes.size() == 1) { return mode; + } int modeNum = rnd.nextInt(modes.values().size()); for (int i = 0; i < modeNum; i++) { mode = it.next(); 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 60bc095e14..4c7c0e855e 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,42 +1,65 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package org.mage.test.player; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import mage.MageObject; -import mage.abilities.*; +import mage.abilities.Abilities; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.Mode; +import mage.abilities.Modes; +import mage.abilities.SpellAbility; +import mage.abilities.TriggeredAbility; +import mage.abilities.costs.AlternativeSourceCosts; import mage.abilities.costs.VariableCost; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.mana.ManaAbility; +import mage.abilities.mana.ManaOptions; +import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.decks.Deck; import mage.choices.Choice; +import mage.constants.ManaType; import mage.constants.Outcome; import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; import mage.constants.SpellAbilityType; +import mage.constants.Zone; import mage.counters.Counter; +import mage.counters.Counters; import mage.filter.FilterPermanent; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterCreatureForCombat; @@ -47,59 +70,65 @@ import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.BlockingPredicate; import mage.game.Game; +import mage.game.Graveyard; +import mage.game.Table; +import mage.game.combat.CombatGroup; +import mage.game.draft.Draft; +import mage.game.match.Match; +import mage.game.match.MatchPlayer; import mage.game.permanent.Permanent; import mage.game.stack.StackObject; +import mage.game.tournament.Tournament; import mage.player.ai.ComputerPlayer; +import mage.players.Library; +import mage.players.ManaPool; import mage.players.Player; +import mage.players.net.UserData; import mage.target.Target; +import mage.target.TargetAmount; +import mage.target.TargetCard; import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import mage.target.common.TargetCreaturePermanentAmount; -import org.junit.Ignore; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import mage.abilities.mana.ManaAbility; -import mage.abilities.mana.ManaOptions; -import mage.cards.Card; -import mage.constants.Zone; import mage.target.TargetSource; import mage.target.TargetSpell; import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCreaturePermanentAmount; import mage.target.common.TargetPermanentOrPlayer; +import org.junit.Ignore; + + /** * * @author BetaSteward_at_googlemail.com */ @Ignore -public class TestPlayer extends ComputerPlayer { +public class TestPlayer implements Player { + + private int maxCallsWithoutAction = 100; + private int foundNoAction = 0; private final List actions = new ArrayList<>(); private final List choices = new ArrayList<>(); private final List targets = new ArrayList<>(); private final List modesSet = new ArrayList<>(); - public TestPlayer(String name, RangeOfInfluence range) { - super(name, range); - human = false; + private final ComputerPlayer computerPlayer; + + + public TestPlayer(ComputerPlayer computerPlayer) { + this.computerPlayer = computerPlayer; } - public TestPlayer(final TestPlayer player) { - super(player); - } + public TestPlayer(final TestPlayer testPlayer) { + this.actions.addAll(testPlayer.actions); + this.choices.addAll(testPlayer.choices); + this.targets.addAll(testPlayer.targets); + this.modesSet.addAll(testPlayer.modesSet); + this.computerPlayer = testPlayer.computerPlayer.copy(); + this.foundNoAction = testPlayer.foundNoAction; - public void addAction(int turnNum, PhaseStep step, String action) { - actions.add(new PlayerAction(turnNum, step, action)); - } - - @Override - public int getActionCount() { - return actions.size(); } public void addChoice(String choice) { @@ -114,6 +143,205 @@ public class TestPlayer extends ComputerPlayer { targets.add(target); } + public ManaOptions getAvailableManaTest(Game game) { + return computerPlayer.getManaAvailable(game); + } + + public void addAction(int turnNum, PhaseStep step, String action) { + actions.add(new PlayerAction(turnNum, step, action)); + } + + /** + * + * @param maxCallsWithoutAction max number of priority passes a player may have for this test (default = 100) + */ + public void setMaxCallsWithoutAction(int maxCallsWithoutAction) { + this.maxCallsWithoutAction = maxCallsWithoutAction; + } + + protected Permanent findPermanent(FilterPermanent filter, UUID controllerId, Game game) { + List permanents = game.getBattlefield().getAllActivePermanents(filter, controllerId, game); + if (permanents.size() > 0) { + return permanents.get(0); + } + return null; + } + + private boolean checkExecuteCondition(String[] groups, Game game) { + if (groups[2].startsWith("spellOnStack=")) { + String spellOnStack = groups[2].substring(13); + for (StackObject stackObject : game.getStack()) { + if (stackObject.getStackAbility().toString().contains(spellOnStack)) { + return true; + } + } + return false; + } else if (groups[2].startsWith("!spellOnStack=")) { + String spellNotOnStack = groups[2].substring(14); + for (StackObject stackObject : game.getStack()) { + if (stackObject.getStackAbility().toString().contains(spellNotOnStack)) { + return false; + } + } + return true; + } else if (groups[2].startsWith("spellOnTopOfStack=")) { + String spellOnTopOFStack = groups[2].substring(18); + if (game.getStack().size() > 0) { + StackObject stackObject = game.getStack().getFirst(); + if (stackObject != null && stackObject.getStackAbility().toString().contains(spellOnTopOFStack)) { + return true; + } + } + return false; + } else if (groups[2].startsWith("manaInPool=")) { + String manaInPool = groups[2].substring(11); + int amountOfMana = Integer.parseInt(manaInPool); + return computerPlayer.getManaPool().getMana().count() >= amountOfMana; + } + return true; + } + +// private boolean checkSpellOnTopOfStackCondition(String[] groups, Game game) { +// if (groups.length > 2 && groups[2].startsWith("spellOnTopOfStack=")) { +// String spellOnTopOFStack = groups[2].substring(18); +// if (game.getStack().size() > 0) { +// StackObject stackObject = game.getStack().getFirst(); +// if (stackObject != null && stackObject.getStackAbility().toString().contains(spellOnTopOFStack)) { +// return true; +// } +// } +// return false; +// } +// return true; +// } + private boolean addTargets(Ability ability, String[] groups, Game game) { + boolean result = true; + for (int i = 1; i < groups.length; i++) { + String group = groups[i]; + if (group.startsWith("spellOnStack") || group.startsWith("spellOnTopOfStack") || group.startsWith("!spellOnStack") || group.startsWith("target=null") || group.startsWith("manaInPool=")) { + break; + } + if (ability instanceof SpellAbility && ((SpellAbility) ability).getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) { + if (group.contains("FuseLeft-")) { + result = handleTargetString(group.substring(group.indexOf("FuseLeft-") + 9), ability, game); + } else if (group.startsWith("FuseRight-")) { + result = handleTargetString(group.substring(group.indexOf("FuseRight-") + 10), ability, game); + } else { + result = false; + } + } else { + result = handleTargetString(group, ability, game); + } + } + return result; + } + + private boolean handleTargetString(String target, Ability ability, Game game) { + boolean result = false; + if (target.startsWith("targetPlayer=")) { + result = handlePlayerTarget(target.substring(target.indexOf("targetPlayer=") + 13), ability, game); + } else if (target.startsWith("target=")) { + result = handleNonPlayerTargetTarget(target.substring(target.indexOf("target=") + 7), ability, game); + } + return result; + } + + private boolean handlePlayerTarget(String target, Ability ability, Game game) { + boolean result = true; + int targetsSet = 0; + for (Player player : game.getPlayers().values()) { + if (player.getName().equals(target)) { + ability.getTargets().get(0).addTarget(player.getId(), ability, game); + targetsSet++; + break; + } + } + if (targetsSet < 1) { + result = false; + } + return result; + } + + private boolean handleNonPlayerTargetTarget(String target, Ability ability, Game game) { + boolean result = true; + if (target == null) { + return true; // needed if spell has no target but waits until spell is on the stack + } + String[] targetList = target.split("\\^"); + int index = 0; + int targetsSet = 0; + for (String targetName : targetList) { + if (targetName.startsWith("mode=")) { + int modeNr = Integer.parseInt(targetName.substring(5, 6)); + if (modeNr == 0 || modeNr > ability.getModes().size()) { + throw new UnsupportedOperationException("Given mode number (" + modeNr + ") not available for " + ability.toString()); + } + int modeCounter = 1; + for (Mode mode : ability.getModes().values()) { + if (modeCounter == modeNr) { + ability.getModes().setMode(mode); + index = 0; // reset target index if mode changes + break; + } + modeCounter++; + } + targetName = targetName.substring(6); + } + if (ability.getTargets().size() == 0) { + throw new AssertionError("Ability has no targets. " + ability.toString()); + } + if (index >= ability.getTargets().size()) { + break; // this can happen if targets should be set but can't be used because of hexproof e.g. + } + Target currentTarget = ability.getTargets().get(index); + if (targetName.startsWith("targetPlayer=")) { + target = targetName.substring(targetName.indexOf("targetPlayer=") + 13); + for (Player player : game.getPlayers().values()) { + if (player.getName().equals(target)) { + currentTarget.addTarget(player.getId(), ability, game); + index++; + targetsSet++; + break; + } + } + } else { + for (UUID id : currentTarget.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) { + MageObject object = game.getObject(id); + if (object != null + && ((!targetName.isEmpty() && object.getName().startsWith(targetName)) || (targetName.isEmpty() && object.getName().isEmpty()))) { + if (currentTarget.getNumberOfTargets() == 1) { + currentTarget.clearChosen(); + } + if (currentTarget instanceof TargetCreaturePermanentAmount) { + // supports only to set the complete amount to one target + TargetCreaturePermanentAmount targetAmount = (TargetCreaturePermanentAmount) currentTarget; + targetAmount.setAmount(ability, game); + int amount = targetAmount.getAmountRemaining(); + targetAmount.addTarget(id, amount, ability, game); + targetsSet++; + } else { + currentTarget.addTarget(id, ability, game); + targetsSet++; + } + if (currentTarget.getTargets().size() == currentTarget.getMaxNumberOfTargets()) { + index++; + } + break; + } + } + } + } + if (targetsSet != targetList.length) { + result = false; + } + return result; + } + + @Override + public int getActionCount() { + return actions.size(); + } + @Override public TestPlayer copy() { return new TestPlayer(this); @@ -121,7 +349,8 @@ public class TestPlayer extends ComputerPlayer { @Override public boolean priority(Game game) { - for (PlayerAction action: actions) { + int numberOfActions = actions.size(); + for (PlayerAction action : actions) { if (action.getTurnNum() == game.getTurnNum() && action.getStep() == game.getStep().getType()) { if (action.getAction().startsWith("activate:")) { @@ -131,51 +360,47 @@ public class TestPlayer extends ComputerPlayer { if (groups.length > 2 && !checkExecuteCondition(groups, game)) { break; } - for (Ability ability: this.getPlayable(game, true)) { + for (Ability ability : computerPlayer.getPlayable(game, true)) { if (ability.toString().startsWith(groups[0])) { Ability newAbility = ability.copy(); if (groups.length > 1 && !groups[1].equals("target=NO_TARGET")) { - if (!addTargets(newAbility, groups, game)) { + if (!addTargets(newAbility, groups, game)) { // targets could not be set -> try next priority break; } } - this.activateAbility((ActivatedAbility)newAbility, game); + computerPlayer.activateAbility((ActivatedAbility) newAbility, game); actions.remove(action); return true; } - } - } else - - if (action.getAction().startsWith("manaActivate:")) { + } + } else if (action.getAction().startsWith("manaActivate:")) { String command = action.getAction(); command = command.substring(command.indexOf("manaActivate:") + 13); String[] groups = command.split("\\$"); - List manaPerms = this.getAvailableManaProducers(game); - for (Permanent perm: manaPerms) { - for (Ability manaAbility: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { - if (manaAbility.toString().startsWith(groups[0])) { - Ability newManaAbility = manaAbility.copy(); - this.activateAbility((ActivatedAbility)newManaAbility, game); + List manaPerms = computerPlayer.getAvailableManaProducers(game); + for (Permanent perm : manaPerms) { + for (Ability manaAbility : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { + if (manaAbility.toString().startsWith(groups[0])) { + Ability newManaAbility = manaAbility.copy(); + computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game); actions.remove(action); return true; - } - } + } + } } - List manaPermsWithCost = this.getAvailableManaProducersWithCost(game); - for (Permanent perm: manaPermsWithCost) { - for (ManaAbility manaAbility: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { - if (manaAbility.toString().startsWith(groups[0]) && manaAbility.canActivate(playerId, game)) { - Ability newManaAbility = manaAbility.copy(); - this.activateAbility((ActivatedAbility)newManaAbility, game); + List manaPermsWithCost = computerPlayer.getAvailableManaProducersWithCost(game); + for (Permanent perm : manaPermsWithCost) { + for (ManaAbility manaAbility : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { + if (manaAbility.toString().startsWith(groups[0]) && manaAbility.canActivate(computerPlayer.getId(), game)) { + Ability newManaAbility = manaAbility.copy(); + computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game); actions.remove(action); return true; - } - } + } + } } - } else - - if (action.getAction().startsWith("addCounters:")) { + } else if (action.getAction().startsWith("addCounters:")) { String command = action.getAction(); command = command.substring(command.indexOf("addCounters:") + 12); String[] groups = command.split("\\$"); @@ -189,16 +414,25 @@ public class TestPlayer extends ComputerPlayer { } } } - pass(game); + computerPlayer.pass(game); + // check to prevent endless loops + if (numberOfActions == actions.size()) { + foundNoAction++; + if (foundNoAction > maxCallsWithoutAction) { + throw new AssertionError("More priority calls to " +getName() + " and doing no action than allowed (" + maxCallsWithoutAction +")"); + } + } else { + foundNoAction = 0; + } return false; } @Override public void selectAttackers(Game game, UUID attackingPlayerId) { UUID defenderId = null; - for (PlayerAction action: actions) { + for (PlayerAction action : actions) { if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("attack:")) { - + String command = action.getAction(); command = command.substring(command.indexOf("attack:") + 7); String[] groups = command.split("\\$"); @@ -206,36 +440,36 @@ public class TestPlayer extends ComputerPlayer { String group = groups[i]; if (group.startsWith("planeswalker=")) { String planeswalkerName = group.substring(group.indexOf("planeswalker=") + 13); - for (Permanent permanent :game.getBattlefield().getAllActivePermanents(new FilterPlaneswalkerPermanent(), game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterPlaneswalkerPermanent(), game)) { if (permanent.getName().equals(planeswalkerName)) { - defenderId = permanent.getId(); + defenderId = permanent.getId(); } } } if (group.startsWith("defendingPlayer=")) { String defendingPlayerName = group.substring(group.indexOf("defendingPlayer=") + 16); - for (Player defendingPlayer :game.getPlayers().values()) { + for (Player defendingPlayer : game.getPlayers().values()) { if (defendingPlayer.getName().equals(defendingPlayerName)) { - defenderId = defendingPlayer.getId(); + defenderId = defendingPlayer.getId(); break; } } } } if (defenderId == null) { - for (UUID uuid: game.getCombat().getDefenders()) { + for (UUID uuid : game.getCombat().getDefenders()) { Player defender = game.getPlayer(uuid); if (defender != null) { defenderId = uuid; } } - } + } FilterCreatureForCombat filter = new FilterCreatureForCombat(); filter.add(new NamePredicate(groups[0])); filter.add(Predicates.not(new AttackingPredicate())); - Permanent attacker = findPermanent(filter, playerId, game); + Permanent attacker = findPermanent(filter, computerPlayer.getId(), game); if (attacker != null && attacker.canAttack(defenderId, game)) { - this.declareAttacker(attacker.getId(), defenderId, game, false); + computerPlayer.declareAttacker(attacker.getId(), defenderId, game, false); } } } @@ -243,8 +477,8 @@ public class TestPlayer extends ComputerPlayer { @Override public void selectBlockers(Game game, UUID defendingPlayerId) { - UUID opponentId = game.getOpponents(playerId).iterator().next(); - for (PlayerAction action: actions) { + UUID opponentId = game.getOpponents(computerPlayer.getId()).iterator().next(); + for (PlayerAction action : actions) { if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("block:")) { String command = action.getAction(); command = command.substring(command.indexOf("block:") + 6); @@ -252,13 +486,13 @@ public class TestPlayer extends ComputerPlayer { FilterCreatureForCombatBlock filterBlocker = new FilterCreatureForCombatBlock(); filterBlocker.add(new NamePredicate(groups[0])); filterBlocker.add(Predicates.not(new BlockingPredicate())); - Permanent blocker = findPermanent(filterBlocker, playerId, game); + Permanent blocker = findPermanent(filterBlocker, computerPlayer.getId(), game); if (blocker != null) { FilterAttackingCreature filterAttacker = new FilterAttackingCreature(); filterAttacker.add(new NamePredicate(groups[1])); Permanent attacker = findPermanent(filterAttacker, opponentId, game); if (attacker != null) { - this.declareBlocker(defendingPlayerId, blocker.getId(), attacker.getId(), game); + computerPlayer.declareBlocker(defendingPlayerId, blocker.getId(), attacker.getId(), game); } } } @@ -268,9 +502,9 @@ public class TestPlayer extends ComputerPlayer { @Override public Mode chooseMode(Modes modes, Ability source, Game game) { if (!modesSet.isEmpty() && modes.getMaxModes() > modes.getSelectedModes().size()) { - int selectedMode = Integer.parseInt(modesSet.get(0)); + int selectedMode = Integer.parseInt(modesSet.get(0)); int i = 1; - for (Mode mode: modes.values()) { + for (Mode mode : modes.values()) { if (i == selectedMode) { modesSet.remove(0); return mode; @@ -278,14 +512,14 @@ public class TestPlayer extends ComputerPlayer { i++; } } - return super.chooseMode(modes, source, game); //To change body of generated methods, choose Tools | Templates. + return computerPlayer.chooseMode(modes, source, game); //To change body of generated methods, choose Tools | Templates. } @Override public boolean choose(Outcome outcome, Choice choice, Game game) { if (!choices.isEmpty()) { - for (String choose2: choices) { - for (String choose1: choice.getChoices()) { + for (String choose2 : choices) { + for (String choose1 : choice.getChoices()) { if (choose1.equals(choose2)) { choice.setChoice(choose2); choices.remove(choose2); @@ -294,13 +528,13 @@ public class TestPlayer extends ComputerPlayer { } } } - return super.choose(outcome, choice, game); + return computerPlayer.choose(outcome, choice, game); } @Override public int chooseReplacementEffect(Map rEffects, Game game) { if (!choices.isEmpty()) { - for (String choice: choices) { + for (String choice : choices) { for (int index = 0; index < rEffects.size(); index++) { if (choice.equals(rEffects.get(index))) { choices.remove(choice); @@ -309,7 +543,7 @@ public class TestPlayer extends ComputerPlayer { } } } - return super.chooseReplacementEffect(rEffects, game); + return computerPlayer.chooseReplacementEffect(rEffects, game); } @Override @@ -322,22 +556,22 @@ public class TestPlayer extends ComputerPlayer { } else { filterPermanent = ((TargetPermanent) target).getFilter(); } - for (String choose2: choices) { + for (String choose2 : choices) { String[] targetList = choose2.split("\\^"); boolean targetFound = false; - for (String targetName: targetList) { + for (String targetName : targetList) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filterPermanent, game)) { if (target.getTargets().contains(permanent.getId())) { continue; } if (permanent.getName().equals(targetName)) { - if (target.isNotTarget() || ((TargetPermanent)target).canTarget(playerId, permanent.getId(), null, game)) { + if (target.isNotTarget() || ((TargetPermanent) target).canTarget(computerPlayer.getId(), permanent.getId(), null, game)) { target.add(permanent.getId(), game); targetFound = true; break; } - } else if ((permanent.getName()+"-"+permanent.getExpansionSetCode()).equals(targetName)) { - if (target.isNotTarget() || ((TargetPermanent)target).canTarget(playerId, permanent.getId(), null, game)) { + } else if ((permanent.getName() + "-" + permanent.getExpansionSetCode()).equals(targetName)) { + if (target.isNotTarget() || ((TargetPermanent) target).canTarget(computerPlayer.getId(), permanent.getId(), null, game)) { target.add(permanent.getId(), game); targetFound = true; break; @@ -352,13 +586,13 @@ public class TestPlayer extends ComputerPlayer { } } if (target instanceof TargetPlayer) { - for (Player player :game.getPlayers().values()) { - for (String choose2: choices) { + for (Player player : game.getPlayers().values()) { + for (String choose2 : choices) { if (player.getName().equals(choose2)) { - if (((TargetPlayer)target).canTarget(playerId, player.getId(), null, game) && !target.getTargets().contains(player.getId())) { + if (((TargetPlayer) target).canTarget(computerPlayer.getId(), player.getId(), null, game) && !target.getTargets().contains(player.getId())) { target.add(player.getId(), game); choices.remove(choose2); - return true; + return true; } } } @@ -367,14 +601,14 @@ public class TestPlayer extends ComputerPlayer { if (target instanceof TargetSource) { Set possibleTargets; TargetSource t = ((TargetSource) target); - possibleTargets = t.possibleTargets(sourceId, playerId, game); + possibleTargets = t.possibleTargets(sourceId, computerPlayer.getId(), game); for (UUID targetId : possibleTargets) { MageObject targetObject = game.getObject(targetId); if (targetObject != null) { - for (String choose2: choices) { + for (String choose2 : choices) { String[] targetList = choose2.split("\\^"); boolean targetFound = false; - for (String targetName: targetList) { + for (String targetName : targetList) { if (targetObject.getName().equals(targetName)) { List alreadyTargetted = target.getTargets(); if (t.canTarget(targetObject.getId(), game)) { @@ -389,43 +623,43 @@ public class TestPlayer extends ComputerPlayer { if (targetFound) { choices.remove(choose2); return true; - } + } } } } } } - return super.choose(outcome, target, sourceId, game, options); + return computerPlayer.choose(outcome, target, sourceId, game, options); } @Override public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { if (!targets.isEmpty()) { - UUID abilityControllerId = playerId; + UUID abilityControllerId = computerPlayer.getId(); if (target.getTargetController() != null && target.getAbilityController() != null) { abilityControllerId = target.getAbilityController(); } if ((target instanceof TargetPermanent) || (target instanceof TargetPermanentOrPlayer)) { - for (String targetDefinition: targets) { + for (String targetDefinition : targets) { String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; - for (String targetName: targetList) { + for (String targetName : targetList) { boolean originOnly = false; boolean copyOnly = false; if (targetName.endsWith("]")) { if (targetName.endsWith("[no copy]")) { originOnly = true; - targetName = targetName.substring(0, targetName.length()-9); + targetName = targetName.substring(0, targetName.length() - 9); } if (targetName.endsWith("[only copy]")) { copyOnly = true; - targetName = targetName.substring(0, targetName.length()-11); + targetName = targetName.substring(0, targetName.length() - 11); } } - for (Permanent permanent : game.getBattlefield().getAllActivePermanents((FilterPermanent)target.getFilter(), game)) { - if (permanent.getName().equals(targetName) || (permanent.getName()+"-"+permanent.getExpansionSetCode()).equals(targetName)) { - if (((TargetPermanent)target).canTarget(abilityControllerId, permanent.getId(), source, game) && !target.getTargets().contains(permanent.getId())) { - if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly )) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents((FilterPermanent) target.getFilter(), game)) { + if (permanent.getName().equals(targetName) || (permanent.getName() + "-" + permanent.getExpansionSetCode()).equals(targetName)) { + if (((TargetPermanent) target).canTarget(abilityControllerId, permanent.getId(), source, game) && !target.getTargets().contains(permanent.getId())) { + if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) { target.add(permanent.getId(), game); targetFound = true; break; @@ -441,28 +675,28 @@ public class TestPlayer extends ComputerPlayer { } } if (target instanceof TargetPlayer) { - for (String targetDefinition: targets) { + for (String targetDefinition : targets) { if (targetDefinition.startsWith("targetPlayer=")) { String playerName = targetDefinition.substring(targetDefinition.indexOf("targetPlayer=") + 13); - for (Player player: game.getPlayers().values()) { + for (Player player : game.getPlayers().values()) { if (player.getName().equals(playerName) - && ((TargetPlayer) target).canTarget(playerId, player.getId(), source, game)) { + && ((TargetPlayer) target).canTarget(computerPlayer.getId(), player.getId(), source, game)) { target.add(player.getId(), game); return true; } } } } - + } if (target instanceof TargetCardInHand) { - for (String targetDefinition: targets) { + for (String targetDefinition : targets) { String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; - for (String targetName: targetList) { - for (Card card: this.getHand().getCards(((TargetCardInHand)target).getFilter(), game)) { - if (card.getName().equals(targetName) || (card.getName()+"-"+card.getExpansionSetCode()).equals(targetName)) { - if (((TargetCardInHand)target).canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) { + for (String targetName : targetList) { + for (Card card : computerPlayer.getHand().getCards(((TargetCardInHand) target).getFilter(), game)) { + if (card.getName().equals(targetName) || (card.getName() + "-" + card.getExpansionSetCode()).equals(targetName)) { + if (((TargetCardInHand) target).canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) { target.add(card.getId(), game); targetFound = true; break; @@ -478,41 +712,40 @@ public class TestPlayer extends ComputerPlayer { } if (target instanceof TargetSpell) { - for (String targetDefinition: targets) { + for (String targetDefinition : targets) { String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; - for (String targetName: targetList) { - for(StackObject stackObject: game.getStack()) { + for (String targetName : targetList) { + for (StackObject stackObject : game.getStack()) { if (stackObject.getName().equals(targetName)) { target.add(stackObject.getId(), game); targetFound = true; - break; - } + break; + } } - } + } if (targetFound) { targets.remove(targetDefinition); return true; - } - } + } + } } - } - return super.chooseTarget(outcome, target, source, game); + return computerPlayer.chooseTarget(outcome, target, source, game); } @Override public TriggeredAbility chooseTriggeredAbility(List abilities, Game game) { if (!choices.isEmpty()) { - for(TriggeredAbility ability :abilities) { + for (TriggeredAbility ability : abilities) { if (ability.toString().startsWith(choices.get(0))) { choices.remove(0); return ability; } } } - return super.chooseTriggeredAbility(abilities, game); + return computerPlayer.chooseTriggeredAbility(abilities, game); } @Override @@ -539,7 +772,7 @@ public class TestPlayer extends ComputerPlayer { return xValue; } } - return super.announceXMana(min, max, message, game, ability); + return computerPlayer.announceXMana(min, max, message, game, ability); } @Override @@ -551,7 +784,7 @@ public class TestPlayer extends ComputerPlayer { return xValue; } } - return super.announceXCost(min, max, message, game, ability, null); + return computerPlayer.announceXCost(min, max, message, game, ability, null); } @Override @@ -563,190 +796,1017 @@ public class TestPlayer extends ComputerPlayer { return xValue; } } - return super.getAmount(min, max, message, game); + return computerPlayer.getAmount(min, max, message, game); } - protected Permanent findPermanent(FilterPermanent filter, UUID controllerId, Game game) { - List permanents = game.getBattlefield().getAllActivePermanents(filter, controllerId, game); - if (permanents.size() > 0) { - return permanents.get(0); - } - return null; + @Override + public void addAbility(Ability ability) { + computerPlayer.addAbility(ability); } - private boolean checkExecuteCondition(String[] groups, Game game) { - if (groups[2].startsWith("spellOnStack=")) { - String spellOnStack = groups[2].substring(13); - for (StackObject stackObject: game.getStack()) { - if (stackObject.getStackAbility().toString().contains(spellOnStack)) { - return true; - } - } - return false; - } else if (groups[2].startsWith("!spellOnStack=")) { - String spellNotOnStack = groups[2].substring(14); - for (StackObject stackObject: game.getStack()) { - if (stackObject.getStackAbility().toString().contains(spellNotOnStack)) { - return false; - } - } - return true; - } else if (groups[2].startsWith("spellOnTopOfStack=")) { - String spellOnTopOFStack = groups[2].substring(18); - if (game.getStack().size() > 0) { - StackObject stackObject = game.getStack().getFirst(); - if (stackObject != null && stackObject.getStackAbility().toString().contains(spellOnTopOFStack)) { - return true; - } - } - return false; - } else if (groups[2].startsWith("manaInPool=")) { - String manaInPool = groups[2].substring(11); - int amountOfMana = Integer.parseInt(manaInPool); - return this.getManaPool().getMana().count() >= amountOfMana; - } - return true; + @Override + public boolean activateAbility(ActivatedAbility ability, Game game) { + return computerPlayer.activateAbility(ability, game); } -// private boolean checkSpellOnTopOfStackCondition(String[] groups, Game game) { -// if (groups.length > 2 && groups[2].startsWith("spellOnTopOfStack=")) { -// String spellOnTopOFStack = groups[2].substring(18); -// if (game.getStack().size() > 0) { -// StackObject stackObject = game.getStack().getFirst(); -// if (stackObject != null && stackObject.getStackAbility().toString().contains(spellOnTopOFStack)) { -// return true; -// } -// } -// return false; -// } -// return true; -// } - - private boolean addTargets(Ability ability, String[] groups, Game game) { - boolean result = true; - for (int i = 1; i < groups.length; i++) { - String group = groups[i]; - if (group.startsWith("spellOnStack") || group.startsWith("spellOnTopOfStack") || group.startsWith("!spellOnStack") || group.startsWith("target=null") || group.startsWith("manaInPool=")) { - break; - } - if (ability instanceof SpellAbility && ((SpellAbility) ability).getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) { - if (group.contains("FuseLeft-")) { - result = handleTargetString(group.substring(group.indexOf("FuseLeft-") + 9), ability, game); - } else if(group.startsWith("FuseRight-")) { - result = handleTargetString(group.substring(group.indexOf("FuseRight-") + 10), ability, game); - } else { - result = false; - } - } else { - result = handleTargetString(group, ability, game); - } - } - return result; + @Override + public void abort() { + computerPlayer.abort(); } - private boolean handleTargetString(String target, Ability ability, Game game){ - boolean result = false; - if (target.startsWith("targetPlayer=")) { - result = handlePlayerTarget(target.substring(target.indexOf("targetPlayer=") + 13), ability, game); - } else if (target.startsWith("target=")) { - result = handleNonPlayerTargetTarget(target.substring(target.indexOf("target=") + 7), ability, game); - } - return result; - } - - private boolean handlePlayerTarget(String target, Ability ability, Game game) { - boolean result = true; - int targetsSet = 0; - for (Player player: game.getPlayers().values()) { - if (player.getName().equals(target)) { - ability.getTargets().get(0).addTarget(player.getId(), ability, game); - targetsSet++; - break; - } - } - if (targetsSet < 1) { - result = false; - } - return result; - } - - private boolean handleNonPlayerTargetTarget(String target, Ability ability, Game game) { - boolean result = true; - if (target == null) { - return true; // needed if spell has no target but waits until spell is on the stack - } - String[] targetList = target.split("\\^"); - int index = 0; - int targetsSet = 0; - for (String targetName: targetList) { - if (targetName.startsWith("mode=")) { - int modeNr = Integer.parseInt(targetName.substring(5, 6)); - if (modeNr == 0 || modeNr > ability.getModes().size()) { - throw new UnsupportedOperationException("Given mode number (" + modeNr + ") not available for " + ability.toString()); - } - int modeCounter = 1; - for (Mode mode :ability.getModes().values()) { - if (modeCounter == modeNr) { - ability.getModes().setMode(mode); - index=0; // reset target index if mode changes - break; - } - modeCounter++; - } - targetName = targetName.substring(6); - } - if (ability.getTargets().size() == 0) { - throw new AssertionError("Ability has no targets. " + ability.toString()); - } - if (index >= ability.getTargets().size()) { - break; // this can happen if targets should be set but can't be used because of hexproof e.g. - } - Target currentTarget = ability.getTargets().get(index); - if (targetName.startsWith("targetPlayer=")) { - target = targetName.substring(targetName.indexOf("targetPlayer=") + 13); - for (Player player: game.getPlayers().values()) { - if (player.getName().equals(target)) { - currentTarget.addTarget(player.getId(), ability, game); - index++; - targetsSet++; - break; - } - } - } else { - for (UUID id: currentTarget.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) { - MageObject object = game.getObject(id); - if (object != null && - ((!targetName.isEmpty() && object.getName().startsWith(targetName)) || (targetName.isEmpty() && object.getName().isEmpty()))) { - if (currentTarget.getNumberOfTargets() == 1) { - currentTarget.clearChosen(); - } - if (currentTarget instanceof TargetCreaturePermanentAmount) { - // supports only to set the complete amount to one target - TargetCreaturePermanentAmount targetAmount = (TargetCreaturePermanentAmount) currentTarget; - targetAmount.setAmount(ability, game); - int amount = targetAmount.getAmountRemaining(); - targetAmount.addTarget(id, amount,ability, game); - targetsSet++; - } else { - currentTarget.addTarget(id, ability, game); - targetsSet++; - } - if (currentTarget.getTargets().size() == currentTarget.getMaxNumberOfTargets()) { - index++; - } - break; - } - } - } - } - if (targetsSet != targetList.length) { - result = false; - } - return result; + @Override + public void abortReset() { + computerPlayer.abortReset(); } - public ManaOptions getAvailableManaTest(Game game) { - return getManaAvailable(game); + @Override + public void won(Game game) { + computerPlayer.won(game); } + + @Override + public void restore(Player player) { + computerPlayer.restore(player); + } + + @Override + public void useDeck(Deck deck, Game game) { + computerPlayer.useDeck(deck, game); + } + + @Override + public void init(Game game) { + computerPlayer.init(game); + } + + @Override + public void init(Game game, boolean testMode) { + computerPlayer.init(game, testMode); + } + + @Override + public void reset() { + computerPlayer.reset(); + } + + @Override + public Counters getCounters() { + return computerPlayer.getCounters(); + } + + @Override + public void otherPlayerLeftGame(Game game) { + computerPlayer.otherPlayerLeftGame(game); + } + + @Override + public void beginTurn(Game game) { + computerPlayer.beginTurn(game); + } + + @Override + public RangeOfInfluence getRange() { + return computerPlayer.getRange(); + } + + @Override + public Set getInRange() { + return computerPlayer.getInRange(); + } + + @Override + public Set getPlayersUnderYourControl() { + return computerPlayer.getPlayersUnderYourControl(); + } + + @Override + public void controlPlayersTurn(Game game, UUID playerId) { + computerPlayer.controlPlayersTurn(game, playerId); + } + + @Override + public void setTurnControlledBy(UUID playerId) { + computerPlayer.setTurnControlledBy(playerId); + } + + @Override + public UUID getTurnControlledBy() { + return computerPlayer.getTurnControlledBy(); + } + + @Override + public void resetOtherTurnsControlled() { + computerPlayer.resetOtherTurnsControlled(); + } + + @Override + public boolean isGameUnderControl() { + return computerPlayer.isGameUnderControl(); + } + + @Override + public void setGameUnderYourControl(boolean value) { + computerPlayer.setGameUnderYourControl(value); + } + + @Override + public void endOfTurn(Game game) { + computerPlayer.endOfTurn(game); + } + + @Override + public boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game) { + return computerPlayer.canBeTargetedBy(source, sourceControllerId, game); + } + + @Override + public boolean hasProtectionFrom(MageObject source, Game game) { + return computerPlayer.hasProtectionFrom(source, game); + } + + @Override + public int drawCards(int num, Game game) { + return computerPlayer.drawCards(num, game); + } + + @Override + public int drawCards(int num, Game game, ArrayList appliedEffects) { + return computerPlayer.drawCards(num, game, appliedEffects); + } + + @Override + public void discardToMax(Game game) { + computerPlayer.discardToMax(game); + } + + @Override + public boolean putInHand(Card card, Game game) { + return computerPlayer.putInHand(card, game); + } + + @Override + public boolean removeFromHand(Card card, Game game) { + return computerPlayer.removeFromHand(card, game); + } + + @Override + public boolean removeFromLibrary(Card card, Game game) { + return computerPlayer.removeFromLibrary(card, game); + } + + @Override + public void discard(int amount, Ability source, Game game) { + computerPlayer.discard(amount, source, game); + } + + @Override + public Card discardOne(boolean random, Ability source, Game game) { + return computerPlayer.discardOne(random, source, game); + } + + @Override + public Cards discard(int amount, boolean random, Ability source, Game game) { + return computerPlayer.discard(amount, random, source, game); + } + + @Override + public boolean discard(Card card, Ability source, Game game) { + return computerPlayer.discard(card, source, game); + } + + @Override + public List getAttachments() { + return computerPlayer.getAttachments(); + } + + @Override + public boolean addAttachment(UUID permanentId, Game game) { + return computerPlayer.addAttachment(permanentId, game); + } + + @Override + public boolean removeAttachment(Permanent attachment, Game game) { + return computerPlayer.removeAttachment(attachment, game); + } + + @Override + public boolean removeFromBattlefield(Permanent permanent, Game game) { + return computerPlayer.removeFromBattlefield(permanent, game); + } + + @Override + public boolean putInGraveyard(Card card, Game game, boolean fromBattlefield) { + return computerPlayer.putInGraveyard(card, game, fromBattlefield); + } + + @Override + public boolean removeFromGraveyard(Card card, Game game) { + return computerPlayer.removeFromGraveyard(card, game); + } + + @Override + public boolean putCardsOnBottomOfLibrary(Cards cards, Game game, Ability source, boolean anyOrder) { + return computerPlayer.putCardsOnBottomOfLibrary(cards, game, source, anyOrder); + } + + @Override + public boolean putCardsOnTopOfLibrary(Cards cards, Game game, Ability source, boolean anyOrder) { + return computerPlayer.putCardsOnTopOfLibrary(cards, game, source, anyOrder); + } + + @Override + public void setCastSourceIdWithAlternateMana(UUID sourceId, ManaCosts manaCosts) { + computerPlayer.setCastSourceIdWithAlternateMana(sourceId, manaCosts); + } + + @Override + public UUID getCastSourceIdWithAlternateMana() { + return computerPlayer.getCastSourceIdWithAlternateMana(); + } + + @Override + public ManaCosts getCastSourceIdManaCosts() { + return computerPlayer.getCastSourceIdManaCosts(); + } + + @Override + public boolean isInPayManaMode() { + return computerPlayer.isInPayManaMode(); + } + + @Override + public boolean cast(SpellAbility ability, Game game, boolean noMana) { + return computerPlayer.cast(ability, game, noMana); + } + + @Override + public boolean playLand(Card card, Game game) { + return computerPlayer.playLand(card, game); + } + + @Override + public boolean triggerAbility(TriggeredAbility source, Game game) { + return computerPlayer.triggerAbility(source, game); + } + + @Override + public LinkedHashMap getUseableActivatedAbilities(MageObject object, Zone zone, Game game) { + return computerPlayer.getUseableActivatedAbilities(object, zone, game); + } + + @Override + public int getLandsPlayed() { + return computerPlayer.getLandsPlayed(); + } + + @Override + public boolean canPlayLand() { + return computerPlayer.canPlayLand(); + } + + @Override + public void shuffleLibrary(Game game) { + computerPlayer.shuffleLibrary(game); + } + + @Override + public void revealCards(String name, Cards cards, Game game) { + computerPlayer.revealCards(name, cards, game); + } + + @Override + public void revealCards(String name, Cards cards, Game game, boolean postToLog) { + computerPlayer.revealCards(name, cards, game, postToLog); + } + + @Override + public void lookAtCards(String name, Cards cards, Game game) { + computerPlayer.lookAtCards(name, cards, game); + } + + @Override + public void phasing(Game game) { + computerPlayer.phasing(game); + } + + @Override + public void untap(Game game) { + computerPlayer.untap(game); + } + + @Override + public UUID getId() { + return computerPlayer.getId(); + } + + @Override + public Cards getHand() { + return computerPlayer.getHand(); + } + + @Override + public Graveyard getGraveyard() { + return computerPlayer.getGraveyard(); + } + + @Override + public ManaPool getManaPool() { + return computerPlayer.getManaPool(); + } + + @Override + public String getName() { + return computerPlayer.getName(); + } + + @Override + public String getLogName() { + return computerPlayer.getLogName(); + } + + @Override + public boolean isHuman() { + return computerPlayer.isHuman(); + } + + @Override + public Library getLibrary() { + return computerPlayer.getLibrary(); + } + + @Override + public Cards getSideboard() { + return computerPlayer.getSideboard(); + } + + @Override + public int getLife() { + return computerPlayer.getLife(); + } + + @Override + public void initLife(int life) { + computerPlayer.initLife(life); + } + + @Override + public void setLife(int life, Game game) { + computerPlayer.setLife(life, game); + } + + @Override + public void setLifeTotalCanChange(boolean lifeTotalCanChange) { + computerPlayer.setLifeTotalCanChange(lifeTotalCanChange); + } + + @Override + public boolean isLifeTotalCanChange() { + return computerPlayer.isLifeTotalCanChange(); + } + + @Override + public List getAlternativeSourceCosts() { + return computerPlayer.getAlternativeSourceCosts(); + } + + @Override + public boolean isCanLoseLife() { + return computerPlayer.isCanLoseLife(); + } + + @Override + public void setCanLoseLife(boolean canLoseLife) { + computerPlayer.setCanLoseLife(canLoseLife); + } + + @Override + public int loseLife(int amount, Game game) { + return computerPlayer.loseLife(amount, game); + } + + @Override + public boolean isCanGainLife() { + return computerPlayer.isCanGainLife(); + } + + @Override + public void setCanGainLife(boolean canGainLife) { + computerPlayer.setCanGainLife(canGainLife); + } + + @Override + public int gainLife(int amount, Game game) { + return computerPlayer.gainLife(amount, game); + } + + @Override + public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable) { + return computerPlayer.damage(damage, sourceId, game, combatDamage, preventable); + } + + @Override + public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, ArrayList appliedEffects) { + return computerPlayer.damage(damage, sourceId, game, combatDamage, preventable, appliedEffects); + } + + @Override + public void addCounters(Counter counter, Game game) { + computerPlayer.addCounters(counter, game); + } + + @Override + public Abilities getAbilities() { + return computerPlayer.getAbilities(); + } + + @Override + public int getLandsPerTurn() { + return computerPlayer.getLandsPerTurn(); + } + + @Override + public void setLandsPerTurn(int landsPerTurn) { + computerPlayer.setLandsPerTurn(landsPerTurn); + } + + @Override + public int getLoyaltyUsePerTurn() { + return computerPlayer.getLoyaltyUsePerTurn(); + } + + @Override + public void setLoyaltyUsePerTurn(int loyaltyUsePerTurn) { + computerPlayer.setLoyaltyUsePerTurn(loyaltyUsePerTurn); + } + + @Override + public int getMaxHandSize() { + return computerPlayer.getMaxHandSize(); + } + + @Override + public void setMaxHandSize(int maxHandSize) { + computerPlayer.setMaxHandSize(maxHandSize); + } + + @Override + public void setMaxAttackedBy(int maxAttackedBy) { + computerPlayer.setMaxAttackedBy(maxAttackedBy); + } + + @Override + public int getMaxAttackedBy() { + return computerPlayer.getMaxAttackedBy(); + } + + @Override + public void setResponseString(String responseString) { + computerPlayer.setResponseString(responseString); + } + + @Override + public void setResponseManaType(UUID manaTypePlayerId, ManaType responseManaType) { + computerPlayer.setResponseManaType(manaTypePlayerId, responseManaType); + } + + @Override + public void setResponseUUID(UUID responseUUID) { + computerPlayer.setResponseUUID(responseUUID); + } + + @Override + public void setResponseBoolean(Boolean responseBoolean) { + computerPlayer.setResponseBoolean(responseBoolean); + } + + @Override + public void setResponseInteger(Integer responseInteger) { + computerPlayer.setResponseInteger(responseInteger); + } + + @Override + public boolean isPassed() { + return computerPlayer.isPassed(); + } + + @Override + public void pass(Game game) { + computerPlayer.pass(game); + } + + @Override + public boolean isEmptyDraw() { + return computerPlayer.isEmptyDraw(); + } + + @Override + public void resetPassed() { + computerPlayer.resetPassed(); + } + + @Override + public void quit(Game game) { + computerPlayer.quit(game); + } + + @Override + public void timerTimeout(Game game) { + computerPlayer.timerTimeout(game); + } + + @Override + public void idleTimeout(Game game) { + computerPlayer.idleTimeout(game); + } + + @Override + public void concede(Game game) { + computerPlayer.concede(game); + } + + @Override + public void sendPlayerAction(mage.constants.PlayerAction playerAction, Game game) { + computerPlayer.sendPlayerAction(playerAction, game); + } + + @Override + public void leave() { + computerPlayer.leave(); + } + + @Override + public boolean hasLeft() { + return computerPlayer.hasLeft(); + } + + @Override + public void lost(Game game) { + computerPlayer.lost(game); + } + + @Override + public void lostForced(Game game) { + computerPlayer.lostForced(game); + } + + @Override + public boolean canLose(Game game) { + return computerPlayer.canLose(game); + } + + @Override + public boolean hasLost() { + return computerPlayer.hasLost(); + } + + @Override + public boolean isInGame() { + return computerPlayer.isInGame(); + } + + @Override + public boolean hasWon() { + return computerPlayer.hasWon(); + } + + @Override + public void declareAttacker(UUID attackerId, UUID defenderId, Game game, boolean allowUndo) { + computerPlayer.declareAttacker(attackerId, defenderId, game, allowUndo); + } + + @Override + public void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game) { + computerPlayer.declareBlocker(defenderId, blockerId, attackerId, game); + } + + @Override + public boolean searchLibrary(TargetCardInLibrary target, Game game) { + return computerPlayer.searchLibrary(target, game); + } + + @Override + public boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId) { + return computerPlayer.searchLibrary(target, game, targetPlayerId); + } + + @Override + public boolean flipCoin(Game game) { + return computerPlayer.flipCoin(game); + } + + @Override + public boolean flipCoin(Game game, ArrayList appliedEffects) { + return computerPlayer.flipCoin(game, appliedEffects); + } + + @Override + public List getAvailableAttackers(Game game) { + return computerPlayer.getAvailableAttackers(game); + } + + @Override + public List getAvailableAttackers(UUID defenderId, Game game) { + return computerPlayer.getAvailableAttackers(defenderId, game); + } + + @Override + public List getAvailableBlockers(Game game) { + return computerPlayer.getAvailableBlockers(game); + } + + @Override + public ManaOptions getManaAvailable(Game game) { + return computerPlayer.getManaAvailable(game); + } + + public List getAvailableManaProducersWithCost(Game game) { + return computerPlayer.getAvailableManaProducersWithCost(game); + } + + @Override + public List getPlayable(Game game, boolean hidden) { + return computerPlayer.getPlayable(game, hidden); + } + + @Override + public Set getPlayableInHand(Game game) { + return computerPlayer.getPlayableInHand(game); + } + + @Override + public List getPlayableOptions(Ability ability, Game game) { + return computerPlayer.getPlayableOptions(ability, game); + } + + @Override + public boolean isTestMode() { + return computerPlayer.isTestMode(); + } + + @Override + public void setTestMode(boolean value) { + computerPlayer.setTestMode(value); + } + + @Override + public boolean isTopCardRevealed() { + return computerPlayer.isTopCardRevealed(); + } + + @Override + public void setTopCardRevealed(boolean topCardRevealed) { + computerPlayer.setTopCardRevealed(topCardRevealed); + } + + @Override + public UserData getUserData() { + return computerPlayer.getUserData(); + } + + @Override + public void setUserData(UserData userData) { + computerPlayer.setUserData(userData); + } + + @Override + public void addAction(String action) { + computerPlayer.addAction(action); + } + + @Override + public void setAllowBadMoves(boolean allowBadMoves) { + computerPlayer.setAllowBadMoves(allowBadMoves); + } + + @Override + public boolean canPayLifeCost() { + return computerPlayer.canPayLifeCost(); + } + + @Override + public void setCanPayLifeCost(boolean canPayLifeCost) { + computerPlayer.setCanPayLifeCost(canPayLifeCost); + } + + @Override + public boolean canPaySacrificeCost() { + return computerPlayer.canPaySacrificeCost(); + } + + @Override + public void setCanPaySacrificeCost(boolean canPaySacrificeCost) { + computerPlayer.setCanPaySacrificeCost(canPaySacrificeCost); + } + + @Override + public boolean canLoseByZeroOrLessLife() { + return computerPlayer.canLoseByZeroOrLessLife(); + } + + @Override + public void setLoseByZeroOrLessLife(boolean loseByZeroOrLessLife) { + computerPlayer.setLoseByZeroOrLessLife(loseByZeroOrLessLife); + } + + @Override + public boolean canPlayCardsFromGraveyard() { + return computerPlayer.canPlayCardsFromGraveyard(); + } + + @Override + public void setPlayCardsFromGraveyard(boolean playCardsFromGraveyard) { + computerPlayer.setPlayCardsFromGraveyard(playCardsFromGraveyard); + } + + @Override + public boolean autoLoseGame() { + return computerPlayer.autoLoseGame(); + } + + @Override + public void becomesActivePlayer() { + computerPlayer.becomesActivePlayer(); + } + + @Override + public int getTurns() { + return computerPlayer.getTurns(); + } + + @Override + public int getStoredBookmark() { + return computerPlayer.getStoredBookmark(); + } + + @Override + public void setStoredBookmark(int storedBookmark) { + computerPlayer.setStoredBookmark(storedBookmark); + } + + @Override + public synchronized void resetStoredBookmark(Game game) { + computerPlayer.resetStoredBookmark(game); + } + + @Override + public void revealFaceDownCard(Card card, Game game) { + computerPlayer.revealFaceDownCard(card, game); + } + + @Override + public void setPriorityTimeLeft(int timeLeft) { + computerPlayer.setPriorityTimeLeft(timeLeft); + } + + @Override + public int getPriorityTimeLeft() { + return computerPlayer.getPriorityTimeLeft(); + } + + @Override + public boolean hasQuit() { + return computerPlayer.hasQuit(); + } + + @Override + public boolean hasTimerTimeout() { + return computerPlayer.hasTimerTimeout(); + } + + @Override + public boolean hasIdleTimeout() { + return computerPlayer.hasIdleTimeout(); + } + + @Override + public void setReachedNextTurnAfterLeaving(boolean reachedNextTurnAfterLeaving) { + computerPlayer.setReachedNextTurnAfterLeaving(reachedNextTurnAfterLeaving); + } + + @Override + public boolean hasReachedNextTurnAfterLeaving() { + return computerPlayer.hasReachedNextTurnAfterLeaving(); + } + + @Override + public boolean canJoinTable(Table table) { + return computerPlayer.canJoinTable(table); + } + + @Override + public void setCommanderId(UUID commanderId) { + computerPlayer.setCommanderId(commanderId); + } + + @Override + public UUID getCommanderId() { + return computerPlayer.getCommanderId(); + } + + @Override + public boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game) { + return computerPlayer.moveCards(cards, fromZone, toZone, source, game); + } + + @Override + public boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game) { + return computerPlayer.moveCards(card, fromZone, toZone, source, game); + } + + @Override + public boolean moveCards(List cards, Zone fromZone, Zone toZone, Ability source, Game game) { + return computerPlayer.moveCards(cards, fromZone, toZone, source, game); + } + + @Override + public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) { + return computerPlayer.moveCardToHandWithInfo(card, sourceId, game, fromZone); + } + + @Override + public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean withName) { + return computerPlayer.moveCardToHandWithInfo(card, sourceId, game, fromZone, withName); + } + + @Override + public boolean moveCardsToGraveyardWithInfo(List allCards, Ability source, Game game, Zone fromZone) { + return computerPlayer.moveCardsToGraveyardWithInfo(allCards, source, game, fromZone); + } + + @Override + public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) { + return computerPlayer.moveCardToGraveyardWithInfo(card, sourceId, game, fromZone); + } + + @Override + public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop, boolean withName) { + return computerPlayer.moveCardToLibraryWithInfo(card, sourceId, game, fromZone, toTop, withName); + } + + @Override + public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, Game game, Zone fromZone, boolean withName) { + return computerPlayer.moveCardToExileWithInfo(card, exileId, exileName, sourceId, game, fromZone, withName); + } + + @Override + public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId) { + return computerPlayer.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId); + } + + @Override + public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped) { + return computerPlayer.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, tapped); + } + + @Override + public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped, boolean facedown) { + return computerPlayer.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, tapped, facedown); + } + + @Override + public boolean hasOpponent(UUID playerToCheckId, Game game) { + return computerPlayer.hasOpponent(playerToCheckId, game); + } + + @Override + public boolean getPassedAllTurns() { + return computerPlayer.getPassedAllTurns(); + } + + @Override + public boolean getPassedUntilNextMain() { + return computerPlayer.getPassedUntilNextMain(); + } + + @Override + public boolean getPassedUntilEndOfTurn() { + return computerPlayer.getPassedUntilEndOfTurn(); + } + + @Override + public boolean getPassedTurn() { + return computerPlayer.getPassedTurn(); + } + + @Override + public boolean getPassedUntilStackResolved() { + return computerPlayer.getPassedUntilStackResolved(); + } + + @Override + public void revokePermissionToSeeHandCards() { + computerPlayer.revokePermissionToSeeHandCards(); + } + + @Override + public void addPermissionToShowHandCards(UUID watcherUserId) { + computerPlayer.addPermissionToShowHandCards(watcherUserId); + } + + @Override + public boolean isRequestToShowHandCardsAllowed() { + return computerPlayer.isRequestToShowHandCardsAllowed(); + } + + @Override + public boolean hasUserPermissionToSeeHand(UUID userId) { + return computerPlayer.hasUserPermissionToSeeHand(userId); + } + + @Override + public Set getUsersAllowedToSeeHandCards() { + return computerPlayer.getUsersAllowedToSeeHandCards(); + } + + @Override + public void setMatchPlayer(MatchPlayer matchPlayer) { + computerPlayer.setMatchPlayer(matchPlayer); + } + + @Override + public MatchPlayer getMatchPlayer() { + return computerPlayer.getMatchPlayer(); + } + + @Override + public void cleanUpOnMatchEnd() { + computerPlayer.cleanUpOnMatchEnd(); + } + + @Override + public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { + return computerPlayer.chooseSpellAbilityForCast(ability, game, noMana); + } + + @Override + public void skip() { + computerPlayer.skip(); + } + + @Override + public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + // needed to call here the TestPlayer because it's overwitten + return choose(outcome, target, sourceId, game, null); + } + + @Override + public boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) { + return computerPlayer.choose(outcome, cards, target, game); + } + + @Override + public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { + return computerPlayer.chooseTarget(outcome, cards, target, source, game); + } + + @Override + public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { + return computerPlayer.chooseTargetAmount(outcome, target, source, game); + } + + @Override + public boolean chooseMulligan(Game game) { + return computerPlayer.chooseMulligan(game); + } + + @Override + public boolean choosePile(Outcome outcome, String message, List pile1, List pile2, Game game) { + return computerPlayer.choosePile(outcome, message, pile1, pile2, game); + } + + @Override + public boolean playMana(ManaCost unpaid, String promptText, Game game) { + return computerPlayer.playMana(unpaid, promptText, game); + } + + @Override + public UUID chooseAttackerOrder(List attacker, Game game) { + return computerPlayer.chooseAttackerOrder(attacker, game); + } + + @Override + public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, 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) { + computerPlayer.assignDamage(damage, targets, singleTargetName, sourceId, game); + } + + @Override + public void sideboard(Match match, Deck deck) { + computerPlayer.sideboard(match, deck); + } + + @Override + public void construct(Tournament tournament, Deck deck) { + computerPlayer.construct(tournament, deck); + } + + @Override + public void pickCard(List cards, Deck deck, Draft draft) { + computerPlayer.pickCard(cards, deck, draft); + } + } - diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestAPI.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestAPI.java index 6369627bbc..67cf6484b5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestAPI.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestAPI.java @@ -1,13 +1,14 @@ package org.mage.test.serverside.base; -import mage.constants.PhaseStep; +import java.util.List; import mage.abilities.Ability; +import mage.constants.PhaseStep; import mage.constants.Zone; import mage.filter.Filter; import mage.players.Player; import org.mage.test.player.TestPlayer; -import java.util.List; + /** * Interface for all test initialization and assertion operations. @@ -81,11 +82,14 @@ public interface CardTestAPI { /** * Define turn number to stop the game on. + * @param turn */ void setStopOnTurn(int turn); /** * Define the turn number and step to stop the game on. + * @param turn + * @param step */ void setStopAt(int turn, PhaseStep step); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java new file mode 100644 index 0000000000..2fa9998510 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.serverside.base; + +import java.io.FileNotFoundException; +import mage.constants.MultiplayerAttackOption; +import mage.constants.RangeOfInfluence; +import mage.game.Game; +import mage.game.GameException; +import mage.game.TwoPlayerDuel; +import mage.player.ai.ComputerPlayer7; +import org.mage.test.player.TestPlayer; +import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl; + +/** + * + * @author LevelX2 + */ + +public abstract class CardTestPlayerBaseAI extends CardTestPlayerAPIImpl { + + int skill = 9; + + @Override + protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { + Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0, 20); + + playerA = createPlayer(game, playerA, "PlayerA"); + playerB = createPlayer(game, playerB, "PlayerB"); + return game; + } + + @Override + protected TestPlayer createPlayer(String name) { + if (name.equals("PlayerA")) { + return new TestPlayer(new ComputerPlayer7("PlayerA", RangeOfInfluence.ONE, skill)); + } + return super.createPlayer(name); + } + + public void setAISkill(int skill) { + this.skill = skill; + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java index d1864fbf4a..bcfa18d0f5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java @@ -31,7 +31,6 @@ import java.io.FilenameFilter; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static org.mage.test.serverside.base.MageTestPlayerBase.currentGame; /** * Base class for all tests. diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java index ace998ed9b..32805289ed 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java @@ -28,6 +28,7 @@ import java.io.FilenameFilter; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import mage.player.ai.ComputerPlayer; /** * Base class for all tests. @@ -260,14 +261,15 @@ public abstract class MageTestPlayerBase { } private TestPlayer getPlayer(String name) { - if (name.equals("ComputerA")) { - return playerA; - } else if (name.equals("ComputerB")) { - return playerB; - } else if (name.equals("ComputerC")) { - return playerC; - } else if (name.equals("ComputerD")) { - return playerD; + switch (name) { + case "ComputerA": + return playerA; + case "ComputerB": + return playerB; + case "ComputerC": + return playerC; + case "ComputerD": + return playerD; } throw new IllegalArgumentException("Couldn't find player for name=" + name); } @@ -339,6 +341,7 @@ public abstract class MageTestPlayerBase { } protected TestPlayer createPlayer(String name) { - return new TestPlayer(name, RangeOfInfluence.ONE); + return new TestPlayer(new ComputerPlayer(name, RangeOfInfluence.ONE)); } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestAPIImpl.java index 817d7fe6c2..66423135b0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestAPIImpl.java @@ -28,6 +28,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP /** * Default game initialization params for red player (that plays with Mountains) */ + @Override public void useRedDefault() { // *** ComputerA *** // battlefield:ComputerA:Mountain:5 @@ -88,6 +89,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP * @param player {@link Player} to add cards for. Use either playerA or playerB. * @param cardName Card name in string format. */ + @Override public void addCard(Zone gameZone, TestPlayer player, String cardName) { addCard(gameZone, player, cardName, 1, false); } @@ -100,6 +102,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP * @param cardName Card name in string format. * @param count Amount of cards to be added. */ + @Override public void addCard(Zone gameZone, TestPlayer player, String cardName, int count) { addCard(gameZone, player, cardName, count, false); } @@ -114,6 +117,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP * @param tapped In case gameZone is Battlefield, determines whether permanent should be tapped. * In case gameZone is other than Battlefield, {@link IllegalArgumentException} is thrown */ + @Override public void addCard(Zone gameZone, TestPlayer player, String cardName, int count, boolean tapped) { @@ -179,6 +183,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP * @param player {@link Player} to set life count for. * @param life Life count to set. */ + @Override public void setLife(TestPlayer player, int life) { if (player.equals(playerA)) { commandsA.put(Zone.OUTSIDE, "life:" + String.valueOf(life)); @@ -190,16 +195,18 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP /** * Define turn number to stop the game on. */ + @Override public void setStopOnTurn(int turn) { - stopOnTurn = turn == -1 ? null : Integer.valueOf(turn); + stopOnTurn = turn == -1 ? null : turn; stopAtStep = PhaseStep.UNTAP; } /** * Define turn number and step to stop the game on. */ + @Override public void setStopAt(int turn, PhaseStep step) { - stopOnTurn = turn == -1 ? null : Integer.valueOf(turn); + stopOnTurn = turn == -1 ? null : turn; stopAtStep = step; } @@ -208,6 +215,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP * * @param turn Expected turn number to compare with. 1-based. */ + @Override public void assertTurn(int turn) throws AssertionError { Assert.assertEquals("Turn numbers are not equal", turn, currentGame.getTurnNum()); } @@ -217,21 +225,28 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP * * @param result Expected {@link GameResult} to compare with. */ + @Override public void assertResult(Player player, GameResult result) throws AssertionError { if (player.equals(playerA)) { GameResult actual = CardTestAPI.GameResult.DRAW; - if (currentGame.getWinner().equals("Player PlayerA is the winner")) { - actual = CardTestAPI.GameResult.WON; - } else if (currentGame.getWinner().equals("Player PlayerB is the winner")) { - actual = CardTestAPI.GameResult.LOST; + switch (currentGame.getWinner()) { + case "Player PlayerA is the winner": + actual = CardTestAPI.GameResult.WON; + break; + case "Player PlayerB is the winner": + actual = CardTestAPI.GameResult.LOST; + break; } Assert.assertEquals("Game results are not equal", result, actual); } else if (player.equals(playerB)) { GameResult actual = CardTestAPI.GameResult.DRAW; - if (currentGame.getWinner().equals("Player PlayerB is the winner")) { - actual = CardTestAPI.GameResult.WON; - } else if (currentGame.getWinner().equals("Player PlayerA is the winner")) { - actual = CardTestAPI.GameResult.LOST; + switch (currentGame.getWinner()) { + case "Player PlayerB is the winner": + actual = CardTestAPI.GameResult.WON; + break; + case "Player PlayerA is the winner": + actual = CardTestAPI.GameResult.LOST; + break; } Assert.assertEquals("Game results are not equal", result, actual); } @@ -243,6 +258,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP * @param player {@link Player} to get life for comparison. * @param life Expected player's life to compare with. */ + @Override public void assertLife(Player player, int life) throws AssertionError { int actual = currentGame.getPlayer(player.getId()).getLife(); Assert.assertEquals("Life amounts are not equal", life, actual); @@ -265,6 +281,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP * @param scope {@link mage.filter.Filter.ComparisonScope} Use ANY, if you want "at least one creature with given name should have specified p\t" * Use ALL, if you want "all creature with gived name should have specified p\t" */ + @Override public void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope) throws AssertionError { int count = 0; @@ -298,6 +315,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP /** * {@inheritDoc} */ + @Override public void assertAbilities(Player player, String cardName, List abilities) throws AssertionError { int count = 0; @@ -326,6 +344,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP * @param player {@link Player} which permanents should be counted. * @param count Expected count. */ + @Override public void assertPermanentCount(Player player, int count) throws AssertionError { int actualCount = 0; for (Permanent permanent : currentGame.getBattlefield().getAllPermanents()) { @@ -343,6 +362,7 @@ public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAP * @param cardName Name of the cards that should be counted. * @param count Expected count. */ + @Override public void assertPermanentCount(Player player, String cardName, int count) throws AssertionError { int actualCount = 0; for (Permanent permanent : currentGame.getBattlefield().getAllPermanents()) { 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 c46ae3fa20..dc059ca7cf 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 @@ -1,6 +1,8 @@ package org.mage.test.serverside.base.impl; import java.io.FileNotFoundException; +import java.util.List; +import java.util.UUID; import mage.abilities.Ability; import mage.cards.Card; import mage.cards.decks.Deck; @@ -18,20 +20,18 @@ import mage.filter.predicate.mageobject.NamePredicate; import mage.game.ExileZone; import mage.game.Game; import mage.game.GameException; +import mage.game.GameOptions; import mage.game.command.CommandObject; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; import mage.players.Player; import org.junit.Assert; +import org.junit.Before; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestAPI; +import org.mage.test.serverside.base.CardTestAPI.GameResult; import org.mage.test.serverside.base.MageTestPlayerBase; -import java.util.List; -import java.util.UUID; -import mage.game.GameOptions; -import org.junit.Before; - /** * API for test initialization and asserting the test results. * @@ -213,7 +213,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * * @param player {@link Player} to remove all library cards from. */ - @Override public void removeAllCardsFromLibrary(TestPlayer player) { getCommands(player).put(Zone.LIBRARY, "clear"); } @@ -235,7 +234,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param player {@link Player} to add cards for. Use either playerA or playerB. * @param cardName Card name in string format. */ - @Override public void addCard(Zone gameZone, TestPlayer player, String cardName) { addCard(gameZone, player, cardName, 1, false); } @@ -248,7 +246,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param cardName Card name in string format. * @param count Amount of cards to be added. */ - @Override public void addCard(Zone gameZone, TestPlayer player, String cardName, int count) { addCard(gameZone, player, cardName, count, false); } @@ -263,7 +260,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param tapped In case gameZone is Battlefield, determines whether permanent should be tapped. * In case gameZone is other than Battlefield, {@link IllegalArgumentException} is thrown */ - @Override public void addCard(Zone gameZone, TestPlayer player, String cardName, int count, boolean tapped) { if (gameZone.equals(Zone.BATTLEFIELD)) { @@ -318,7 +314,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param player {@link Player} to set life count for. * @param life Life count to set. */ - @Override public void setLife(TestPlayer player, int life) { getCommands(player).put(Zone.OUTSIDE, "life:" + String.valueOf(life)); } diff --git a/Mage/src/mage/abilities/effects/common/SacrificeEffect.java b/Mage/src/mage/abilities/effects/common/SacrificeEffect.java index e03acac332..ad24e45819 100644 --- a/Mage/src/mage/abilities/effects/common/SacrificeEffect.java +++ b/Mage/src/mage/abilities/effects/common/SacrificeEffect.java @@ -90,7 +90,6 @@ public class SacrificeEffect extends OneShotEffect{ // A spell or ability could have removed the only legal target this player // had, if thats the case this ability should fizzle. if (amount > 0 && target.canChoose(source.getSourceId(), player.getId(), game)) { - boolean abilityApplied = false; while (!target.isChosen() && target.canChoose(player.getId(), game) && player.isInGame()) { player.chooseTarget(Outcome.Sacrifice, target, source, game); } @@ -99,11 +98,11 @@ public class SacrificeEffect extends OneShotEffect{ Permanent permanent = game.getPermanent(target.getTargets().get(idx)); if ( permanent != null ) { - abilityApplied |= permanent.sacrifice(source.getSourceId(), game); + permanent.sacrifice(source.getSourceId(), game); } } - return abilityApplied; + return true; } return false; } diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 8a108c50aa..23561b3425 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -2625,7 +2625,7 @@ public abstract class GameImpl implements Game, Serializable { playerObject.abort(); } } - state.restore(restore); + state.restoreForRollBack(restore); // because restore uses the objects without copy each copy the state again gameStatesRollBack.put(getTurnNum(), state.copy()); executingRollback = true; diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java index a29a353ee6..7d6d7eb7f8 100644 --- a/Mage/src/mage/game/GameState.java +++ b/Mage/src/mage/game/GameState.java @@ -175,11 +175,14 @@ public class GameState implements Serializable, Copyable { this.permanentOrderNumber = state.permanentOrderNumber; } + public void restoreForRollBack(GameState state) { + restore(state); + this.turn = state.turn; + } + public void restore(GameState state) { this.activePlayerId = state.activePlayerId; this.priorityPlayerId = state.priorityPlayerId; - this.turn = state.turn; - this.stack = state.stack; this.command = state.command; this.exile = state.exile; diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index 603744d065..c2f4a016ac 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -49,6 +49,7 @@ import mage.abilities.costs.AlternativeSourceCosts; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.mana.ManaOptions; import mage.cards.Card; import mage.cards.Cards; import mage.cards.decks.Deck; @@ -377,8 +378,10 @@ public interface Player extends MageItem, Copyable { void phasing(Game game); void untap(Game game); + ManaOptions getManaAvailable(Game game); List getPlayable(Game game, boolean hidden); List getPlayableOptions(Ability ability, Game game); + Set getPlayableInHand(Game game); LinkedHashMap getUseableActivatedAbilities(MageObject object, Zone zone, Game game); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index e0864e3627..a9fb708017 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -1089,7 +1089,6 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean activateAbility(ActivatedAbility ability, Game game) { - getManaPool().setStock(); // needed for the "mana already in the pool has to be used manually" option boolean result; if (ability instanceof PassAbility) { pass(game); @@ -1156,7 +1155,7 @@ public abstract class PlayerImpl implements Player, Serializable { return true; } } - game.restoreState(bookmark, source.getRule()); + game.restoreState(bookmark, source.getRule()); // why restore is needed here? return false; } @@ -2149,7 +2148,8 @@ public abstract class PlayerImpl implements Player, Serializable { return blockers; } - protected ManaOptions getManaAvailable(Game game) { + @Override + public ManaOptions getManaAvailable(Game game) { ManaOptions available = new ManaOptions(); List> sourceWithoutCosts = new ArrayList<>(); @@ -2207,7 +2207,7 @@ public abstract class PlayerImpl implements Player, Serializable { } // returns only mana producers that require mana payment - protected List getAvailableManaProducersWithCost(Game game) { + public List getAvailableManaProducersWithCost(Game game) { List result = new ArrayList<>(); for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { for (ManaAbility ability : permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {