From 3c5eb2248b8094b82acc3bea9e62a07b776cbbd3 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Fri, 18 Nov 2016 19:55:05 +0000 Subject: [PATCH] CardFactoryUtil: Miracle is a Trigger now, and make PlayAi a bit better to check if it can play it --- .../src/main/java/forge/ai/AiController.java | 35 ----- .../java/forge/ai/PlayerControllerAi.java | 25 ++-- .../main/java/forge/ai/ability/PlayAi.java | 69 ++++------ .../game/ability/effects/PlayEffect.java | 8 +- .../src/main/java/forge/game/card/Card.java | 8 -- .../java/forge/game/card/CardFactoryUtil.java | 124 ++++++++++-------- .../java/forge/game/trigger/TriggerDrawn.java | 9 ++ .../util/PlayerControllerForTests.java | 5 - .../forge/player/PlayerControllerHuman.java | 8 -- 9 files changed, 119 insertions(+), 172 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 7a46af43486..b4b14a18aa0 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -18,7 +18,6 @@ package forge.ai; import java.security.InvalidParameterException; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -974,40 +973,6 @@ public class AiController { return Boolean.parseBoolean(prop); } - /** Returns the spell ability which has already been played - use it for reference only */ - public SpellAbility chooseAndPlaySa(boolean mandatory, boolean withoutPayingManaCost, final SpellAbility... list) { - return chooseAndPlaySa(Arrays.asList(list), mandatory, withoutPayingManaCost); - } - /** Returns the spell ability which has already been played - use it for reference only */ - public SpellAbility chooseAndPlaySa(final List choices, boolean mandatory, boolean withoutPayingManaCost) { - for (final SpellAbility sa : choices) { - sa.setActivatingPlayer(player); - //Spells - if (sa instanceof Spell) { - if (AiPlayDecision.WillPlay != canPlayFromEffectAI((Spell) sa, mandatory, withoutPayingManaCost)) { - continue; - } - } - else { - if (AiPlayDecision.WillPlay == canPlaySa(sa)) { - continue; - } - } - - if (withoutPayingManaCost) { - ComputerUtil.playSpellAbilityWithoutPayingManaCost(player, sa, game); - } - else if (!ComputerUtilCost.canPayCost(sa, player)) { - continue; - } - else { - ComputerUtil.playStack(sa, player, game); - } - return sa; - } - return null; - } - public AiPlayDecision canPlayFromEffectAI(Spell spell, boolean mandatory, boolean withoutPayingManaCost) { final Card card = spell.getHostCard(); diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index afb8cd8d93d..14fec123ce3 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -1,5 +1,12 @@ package forge.ai; +import java.security.InvalidParameterException; +import java.util.*; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + import com.esotericsoftware.minlog.Log; import com.google.common.base.Predicate; import com.google.common.base.Predicates; @@ -44,17 +51,10 @@ import forge.game.trigger.WrappedAbility; import forge.game.zone.ZoneType; import forge.item.PaperCard; import forge.util.Aggregates; -import forge.util.collect.FCollection; -import forge.util.collect.FCollectionView; import forge.util.ITriggerEvent; import forge.util.MyRandom; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; - -import java.security.InvalidParameterException; -import java.util.*; +import forge.util.collect.FCollection; +import forge.util.collect.FCollectionView; /** @@ -79,6 +79,7 @@ public class PlayerControllerAi extends PlayerController { brains.setUseSimulation(value); } + @Override public SpellAbility getAbilityToPlay(Card hostCard, List abilities, ITriggerEvent triggerEvent) { if (abilities.size() == 0) { return null; @@ -314,11 +315,6 @@ public class PlayerControllerAi extends PlayerController { ComputerUtil.playNoStack(player, effectSA, game); } - @Override - public void playMiracle(SpellAbility miracle, Card card) { - getAi().chooseAndPlaySa(false, false, miracle); - } - @Override public CardCollectionView chooseCardsToDelve(int genericAmount, CardCollection grave) { return getAi().chooseCardsToDelve(genericAmount, grave); @@ -436,6 +432,7 @@ public class PlayerControllerAi extends PlayerController { return brains.chooseNumber(sa, title, min, max); } + @Override public int chooseNumber(SpellAbility sa, String title, List options, Player relatedPlayer) { return brains.chooseNumber(sa, title, options, relatedPlayer); } diff --git a/forge-ai/src/main/java/forge/ai/ability/PlayAi.java b/forge-ai/src/main/java/forge/ai/ability/PlayAi.java index 1de32e16c52..c1720aeb61c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PlayAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PlayAi.java @@ -1,14 +1,18 @@ package forge.ai.ability; +import java.util.List; + import com.google.common.base.Predicate; import forge.ai.AiPlayDecision; +import forge.ai.ComputerUtil; import forge.ai.ComputerUtilCard; -import forge.ai.ComputerUtilCost; import forge.ai.PlayerControllerAi; import forge.ai.SpellAbilityAi; +import forge.game.Game; import forge.game.ability.AbilityUtils; import forge.game.card.Card; +import forge.game.card.CardCollection; import forge.game.card.CardLists; import forge.game.cost.Cost; import forge.game.player.Player; @@ -17,64 +21,38 @@ import forge.game.spellability.Spell; import forge.game.spellability.SpellAbility; import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; -import forge.util.MyRandom; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; public class PlayAi extends SpellAbilityAi { @Override - protected boolean canPlayAI(Player ai, SpellAbility sa) { - final Cost abCost = sa.getPayCosts(); + protected boolean checkApiLogic(final Player ai, final SpellAbility sa) { + final Game game = ai.getGame(); final Card source = sa.getHostCard(); - - final Random r = MyRandom.getRandom(); - - if (abCost != null) { - // AI currently disabled for these costs - if (!ComputerUtilCost.checkSacrificeCost(ai, abCost, source)) { - return false; - } - - if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, null)) { - return false; - } - - if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) { - return false; - } - - if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source)) { - return false; - } - } - // don't use this as a response - if (!ai.getGame().getStack().isEmpty()) { + if (!game.getStack().isEmpty()) { return false; } - // prevent run-away activations - first time will always return true - boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getRestrictions().getNumberTurnActivations()); + if (ComputerUtil.preventRunAwayActivations(sa)) { + return false; // prevent infinite loop + } - List cards; + CardCollection cards; final TargetRestrictions tgt = sa.getTargetRestrictions(); if (tgt != null) { ZoneType zone = tgt.getZone().get(0); - cards = CardLists.getValidCards(ai.getGame().getCardsIn(zone), tgt.getValidTgts(), ai, source, sa); + cards = CardLists.getValidCards(game.getCardsIn(zone), tgt.getValidTgts(), ai, source, sa); if (cards.isEmpty()) { return false; } sa.getTargets().add(ComputerUtilCard.getBestAI(cards)); } else if (!sa.hasParam("Valid")) { - cards = new ArrayList(AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa)); + cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa); if (cards.isEmpty()) { return false; } } - return chance; + return true; } /** @@ -90,9 +68,7 @@ public class PlayAi extends SpellAbilityAi { */ @Override protected boolean doTriggerAINoCost(final Player ai, final SpellAbility sa, final boolean mandatory) { - - final TargetRestrictions tgt = sa.getTargetRestrictions(); - if (tgt != null) { + if (sa.usesTargeting()) { return false; } @@ -112,7 +88,8 @@ public class PlayAi extends SpellAbilityAi { * @see forge.card.ability.SpellAbilityAi#chooseSingleCard(forge.game.player.Player, forge.card.spellability.SpellAbility, java.util.List, boolean) */ @Override - public Card chooseSingleCard(final Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) { + public Card chooseSingleCard(final Player ai, final SpellAbility sa, Iterable options, boolean isOptional, + Player targetedPlayer) { List tgtCards = CardLists.filter(options, new Predicate() { @Override public boolean apply(final Card c) { @@ -122,6 +99,16 @@ public class PlayAi extends SpellAbilityAi { // timing restrictions still apply if (!s.getRestrictions().checkTimingRestrictions(c, s)) continue; + if (sa.hasParam("PlayCost")) { + Cost abCost; + if ("ManaCost".equals(sa.getParam("PlayCost"))) { + abCost = new Cost(c.getManaCost(), false); + } else { + abCost = new Cost(sa.getParam("PlayCost"), false); + } + + spell = (Spell) spell.copyWithDefinedCost(abCost); + } if( AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlayFromEffectAI(spell, false, true)) { return true; } diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java index d23a4a6ec76..5a1b8aafc46 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java @@ -213,15 +213,17 @@ public class PlayEffect extends SpellAbilityEffect { final boolean noManaCost = sa.hasParam("WithoutManaCost"); if (noManaCost) { tgtSA = tgtSA.copyWithNoManaCost(); - } else if (sa.hasParam("PlayMadness")) { + } else if (sa.hasParam("PlayCost")) { Cost abCost; - if ("ManaCost".equals(sa.getParam("PlayMadness"))) { + if ("ManaCost".equals(sa.getParam("PlayCost"))) { abCost = new Cost(source.getManaCost(), false); } else { - abCost = new Cost(sa.getParam("PlayMadness"), false); + abCost = new Cost(sa.getParam("PlayCost"), false); } tgtSA = tgtSA.copyWithDefinedCost(abCost); + } + if (sa.hasParam("Madness")) { tgtSA.getHostCard().setMadness(true); } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index e76adf44fed..f50d9446a0e 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -211,7 +211,6 @@ public class Card extends GameEntity implements Comparable { private NavigableMap tempControllers = Maps.newTreeMap(); private String originalText = "", text = ""; - private Cost miracleCost = null; private String chosenType = ""; private List chosenColors; private String namedCard = ""; @@ -3471,13 +3470,6 @@ public class Card extends GameEntity implements Comparable { unearthed = b; } - public final Cost getMiracleCost() { - return miracleCost; - } - public final void setMiracleCost(final Cost cost) { - miracleCost = cost; - } - public final boolean hasSuspend() { return suspend; } diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 7cf2e3836ba..ebabd93774a 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -901,7 +901,7 @@ public class CardFactoryUtil { } if (l[0].startsWith("CommanderCastFromCommandZone")) { - // TODO fix it for multiple commanders + // TODO fix it for multiple commanders // Read SVar CommanderCostRaise from Commander Effect Card commeff = CardLists.filter(cc.getCardsIn(ZoneType.Command), CardPredicates.nameEquals("Commander Effect")).get(0); @@ -994,14 +994,14 @@ public class CardFactoryUtil { return doXMath(cc.getOpponentsGreatestLifeTotal(), m, c); } if (sq[0].contains("OppsAtLifeTotal")) { - final int lifeTotal = xCount(c, sq[1]); - int number = 0; - for (final Player opp : cc.getOpponents()) { - if (opp.getLife() == lifeTotal) { - number++; - } - } - return doXMath(number, m, c); + final int lifeTotal = xCount(c, sq[1]); + int number = 0; + for (final Player opp : cc.getOpponents()) { + if (opp.getLife() == lifeTotal) { + number++; + } + } + return doXMath(number, m, c); } // Count$TargetedLifeTotal (targeted player's life total) @@ -1157,13 +1157,13 @@ public class CardFactoryUtil { } if (sq[0].contains("ColorsCtrl")) { - final CardCollectionView list = cc.getCardsIn(ZoneType.Battlefield); - int n = 0; - for (final byte col : MagicColor.WUBRG) { - if (!CardLists.getColor(list, col).isEmpty()) { - n++; - } - } + final CardCollectionView list = cc.getCardsIn(ZoneType.Battlefield); + int n = 0; + for (final byte col : MagicColor.WUBRG) { + if (!CardLists.getColor(list, col).isEmpty()) { + n++; + } + } return doXMath(n, m, c); } @@ -1473,7 +1473,7 @@ public class CardFactoryUtil { } private static CardCollectionView getCardListForXCount(final Card c, final Player cc, final String[] sq) { - final List opps = cc.getOpponents(); + final List opps = cc.getOpponents(); CardCollection someCards = new CardCollection(); final Game game = c.getGame(); @@ -1503,41 +1503,41 @@ public class CardFactoryUtil { } if (sq[0].contains("OppCtrl")) { - for (final Player p : opps) { - someCards.addAll(p.getZone(ZoneType.Battlefield).getCards()); - } + for (final Player p : opps) { + someCards.addAll(p.getZone(ZoneType.Battlefield).getCards()); + } } if (sq[0].contains("InOppYard")) { - for (final Player p : opps) { - someCards.addAll(p.getCardsIn(ZoneType.Graveyard)); - } + for (final Player p : opps) { + someCards.addAll(p.getCardsIn(ZoneType.Graveyard)); + } } if (sq[0].contains("InOppHand")) { - for (final Player p : opps) { - someCards.addAll(p.getCardsIn(ZoneType.Hand)); - } + for (final Player p : opps) { + someCards.addAll(p.getCardsIn(ZoneType.Hand)); + } } if (sq[0].contains("InChosenHand")) { - if (c.getChosenPlayer() != null) { - someCards.addAll(c.getChosenPlayer().getCardsIn(ZoneType.Hand)); - } + if (c.getChosenPlayer() != null) { + someCards.addAll(c.getChosenPlayer().getCardsIn(ZoneType.Hand)); + } } if (sq[0].contains("InChosenYard")) { - if (c.getChosenPlayer() != null) { - someCards.addAll(c.getChosenPlayer().getCardsIn(ZoneType.Graveyard)); - } + if (c.getChosenPlayer() != null) { + someCards.addAll(c.getChosenPlayer().getCardsIn(ZoneType.Graveyard)); + } } if (sq[0].contains("OnBattlefield")) { - someCards.addAll(game.getCardsIn(ZoneType.Battlefield)); + someCards.addAll(game.getCardsIn(ZoneType.Battlefield)); } if (sq[0].contains("InAllYards")) { - someCards.addAll(game.getCardsIn(ZoneType.Graveyard)); + someCards.addAll(game.getCardsIn(ZoneType.Graveyard)); } if (sq[0].contains("SpellsOnStack")) { @@ -1545,7 +1545,7 @@ public class CardFactoryUtil { } if (sq[0].contains("InAllHands")) { - someCards.addAll(game.getCardsIn(ZoneType.Hand)); + someCards.addAll(game.getCardsIn(ZoneType.Hand)); } // Count$InTargetedHand (targeted player's cards in hand) @@ -2240,7 +2240,7 @@ public class CardFactoryUtil { addTriggerAbility(keyword, card, null); } else if (keyword.equals("Epic")) { - addSpellAbility(keyword, card, null); + addSpellAbility(keyword, card, null); } else if (keyword.equals("Soulbond")) { // Setup ETB trigger for card with Soulbond keyword @@ -2282,6 +2282,9 @@ public class CardFactoryUtil { else if (keyword.equals("Ingest")) { addTriggerAbility(keyword, card, null); } + else if (keyword.startsWith("Miracle")) { + addTriggerAbility(keyword, card, null); + } else if (keyword.equals("Persist")) { addTriggerAbility(keyword, card, null); } @@ -2981,9 +2984,9 @@ public class CardFactoryUtil { "Execute$ " + trigPlay + " | Secondary$ True | TriggerDescription$ " + "Play Madness " + ManaCostParser.parse(manacost) + " - " + card.getName(); - final String playMadness = "AB$ Play | Cost$ 0 | Defined$ Self | PlayMadness$ " + manacost + + final String playMadness = "AB$ Play | Cost$ 0 | Defined$ Self | PlayCost$ " + manacost + " | ConditionDefined$ Self | ConditionPresent$ Card.StrictlySelf+inZoneExile" + - " | Optional$ True | SubAbility$ DBWasNotPlayMadness | RememberPlayed$ True"; + " | Optional$ True | SubAbility$ DBWasNotPlayMadness | RememberPlayed$ True | Madness$ True"; final String moveToYard = "DB$ ChangeZone | Defined$ Self.StrictlySelf | Origin$ Exile | " + "Destination$ Graveyard | ConditionDefined$ Remembered | ConditionPresent$" + " Card | ConditionCompare$ EQ0 | SubAbility$ DBMadnessCleanup"; @@ -3006,6 +3009,22 @@ public class CardFactoryUtil { card.setSVar("MeleePump", effect); card.setSVar("MeleeX", "TriggeredPlayersDefenders$Amount"); final Trigger trigger = TriggerHandler.parseTrigger(trigStr.toString(), card, intrinsic); + final Trigger cardTrigger = card.addTrigger(trigger); + if (!intrinsic) { + kws.addTrigger(cardTrigger); + } + } else if (keyword.startsWith("Miracle")) { + final String[] k = keyword.split(":"); + final String manacost = k[1]; + final String abStr = "DB$ Play | Defined$ Self | PlayCost$ " + manacost; + + final String trigStr = "Mode$ Drawn | ValidCard$ Card.Self | Miracle$ True | Secondary$ True " + + "| Static$ True | TriggerDescription$ CARDNAME - Miracle"; + + final Trigger trigger = TriggerHandler.parseTrigger(trigStr, card, intrinsic); + + trigger.setOverridingAbility(AbilityFactory.getAbility(abStr, card)); + final Trigger cardTrigger = card.addTrigger(trigger); if (!intrinsic) { kws.addTrigger(cardTrigger); @@ -4082,17 +4101,6 @@ public class CardFactoryUtil { addTriggerAbility(parse, card, null); } // madness - if (hasKeyword(card, "Miracle") != -1) { - final int n = hasKeyword(card, "Miracle"); - if (n != -1) { - final String parse = card.getKeywords().get(n).toString(); - // card.removeIntrinsicKeyword(parse); - - final String[] k = parse.split(":"); - card.setMiracleCost(new Cost(k[1], false)); - } - } // miracle - if (hasKeyword(card, "Devour") != -1) { final int n = hasKeyword(card, "Devour"); addReplacementEffect(card.getKeywords().get(n), card, null); @@ -4129,22 +4137,22 @@ public class CardFactoryUtil { if (hasKeyword(card, "Recover") != -1) { final String recoverCost = card.getKeywords().get(card.getKeywordPosition("Recover")).split(":")[1]; final String abStr = "AB$ ChangeZone | Cost$ 0 | Defined$ Self" - + " | Origin$ Graveyard | Destination$ Hand | UnlessCost$ " + + " | Origin$ Graveyard | Destination$ Hand | UnlessCost$ " + recoverCost + " | UnlessPayer$ You | UnlessSwitched$ True" + " | UnlessResolveSubs$ WhenNotPaid | SubAbility$ RecoverExile"; card.setSVar("RecoverTrig", abStr); card.setSVar("RecoverExile", "DB$ ChangeZone | Defined$ Self" - + " | Origin$ Graveyard | Destination$ Exile"); + + " | Origin$ Graveyard | Destination$ Exile"); String trigObject = card.isCreature() ? "Creature.Other+YouOwn" : "Creature.YouOwn"; String trigArticle = card.isCreature() ? "another" : "a"; String trigStr = "Mode$ ChangesZone | ValidCard$ " + trigObject - + " | Origin$ Battlefield | Destination$ Graveyard | " - + "TriggerZones$ Graveyard | Execute$ RecoverTrig | " - + "TriggerDescription$ When " + trigArticle + " creature is " - + "put into your graveyard from the battlefield, you " - + "may pay " + recoverCost + ". If you do, return " - + "CARDNAME from your graveyard to your hand. Otherwise," - + " exile CARDNAME. | Secondary$ True"; + + " | Origin$ Battlefield | Destination$ Graveyard | " + + "TriggerZones$ Graveyard | Execute$ RecoverTrig | " + + "TriggerDescription$ When " + trigArticle + " creature is " + + "put into your graveyard from the battlefield, you " + + "may pay " + recoverCost + ". If you do, return " + + "CARDNAME from your graveyard to your hand. Otherwise," + + " exile CARDNAME. | Secondary$ True"; final Trigger myTrigger = TriggerHandler.parseTrigger(trigStr, card, true); card.addTrigger(myTrigger); } // Recover diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDrawn.java b/forge-game/src/main/java/forge/game/trigger/TriggerDrawn.java index a03cc760acd..12f8b494718 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDrawn.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDrawn.java @@ -17,6 +17,8 @@ */ package forge.game.trigger; +import forge.game.Game; +import forge.game.GameStage; import forge.game.card.Card; import forge.game.spellability.SpellAbility; @@ -64,6 +66,13 @@ public class TriggerDrawn extends Trigger { return false; } } + + if (this.mapParams.containsKey("Miracle")) { + final Game game = this.getHostCard().getGame(); + if (number != 1 || game.getAge() == GameStage.Mulligan) { + return false; + } + } return true; } diff --git a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java index 1d0f4bccbb0..b9541ea4bbd 100644 --- a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java +++ b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java @@ -268,11 +268,6 @@ public class PlayerControllerForTests extends PlayerController { return chooseItems(validCards, min); } - @Override - public void playMiracle(SpellAbility miracle, Card card) { - throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!"); - } - @Override public CardCollectionView chooseCardsToDelve(int genericAmount, CardCollection grave) { return CardCollection.EMPTY; diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 9ad3e85449d..a2ea7e2c226 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -694,14 +694,6 @@ public class PlayerControllerHuman return new CardCollection(inp.getSelected()); } - @Override - public void playMiracle(final SpellAbility miracle, final Card card) { - final CardView view = CardView.get(card); - if (getGui().confirm(view, view + " - Drawn. Play for Miracle Cost?")) { - HumanPlay.playSpellAbility(this, player, miracle); - } - } - @Override public CardCollectionView chooseCardsToDelve(final int genericAmount, final CardCollection grave) { final int cardsInGrave = Math.min(genericAmount, grave.size());