diff --git a/src/main/java/forge/card/ability/effects/DiscardEffect.java b/src/main/java/forge/card/ability/effects/DiscardEffect.java index 5be0911714e..3f2502fe574 100644 --- a/src/main/java/forge/card/ability/effects/DiscardEffect.java +++ b/src/main/java/forge/card/ability/effects/DiscardEffect.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.List; import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; import com.google.common.base.Predicate; @@ -18,7 +19,6 @@ import forge.game.player.AIPlayer; import forge.game.player.Player; import forge.game.zone.ZoneType; import forge.gui.GuiChoose; -import forge.gui.GuiDialog; import forge.util.Aggregates; public class DiscardEffect extends RevealEffectBase { @@ -86,34 +86,6 @@ public class DiscardEffect extends RevealEffectBase { return sb.toString(); } // discardStackDescription() - private List discardComputerChooses(SpellAbility sa, Player victim, Player chooser, int numCards, String[] dValid, boolean isReveal) { - final Card source = sa.getSourceCard(); - List dPChHand = new ArrayList(victim.getCardsIn(ZoneType.Hand)); - dPChHand = CardLists.getValidCards(dPChHand, dValid, source.getController(), source); - final List toDiscard = new ArrayList(); - - int max = Math.min(dPChHand.size(), numCards); - List list = new ArrayList(); - - if (!victim.isOpponentOf(chooser) && victim instanceof AIPlayer) { // discard AI cards - list = ((AIPlayer) victim).getAi().getCardsToDiscard(max, dValid, sa); - } else { - // discard hostile or human opponent - for (int i = 0; i < max; i++) { - Card dC = chooseCardToDiscardFromOpponent(sa, dPChHand); - dPChHand.remove(dC); - list.add(dC); - } - } - - if (isReveal) { - GuiChoose.oneOrNone("Computer has chosen", list); - } - - return toDiscard; - - } - /** * TODO: Write javadoc for this method. * @param sa @@ -207,19 +179,9 @@ public class DiscardEffect extends RevealEffectBase { } if (mode.equals("Random")) { - boolean runDiscard = true; - if (sa.hasParam("Optional")) { - if (p.isHuman()) { - // TODO Ask if Human would like to discard a card at Random - StringBuilder sb = new StringBuilder("Would you like to discard "); - sb.append(numCards).append(" random card(s)?"); - runDiscard = GuiDialog.confirm(source, sb.toString()); - } - else { - // TODO For now AI will always discard Random used currently with: - // Balduvian Horde and similar cards - } - } + String message = "Would you like to discard " + numCards + " random card(s)?"; + boolean runDiscard = !sa.hasParam("Optional") || p.getController().confirmAction(sa, mode, message); + if (runDiscard) { final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card"; @@ -253,68 +215,88 @@ public class DiscardEffect extends RevealEffectBase { // Is Reveal you choose right? I think the wrong player is // being used? List dPHand = new ArrayList(p.getCardsIn(ZoneType.Hand)); - if (dPHand.size() != 0) { - if (sa.hasParam("RevealNumber")) { - String amountString = sa.getParam("RevealNumber"); - int amount = amountString.matches("[0-9][0-9]?") ? Integer.parseInt(amountString) - : CardFactoryUtil.xCount(source, source.getSVar(amountString)); - dPHand = getRevealedList(p, dPHand, amount, false); - } - List dPChHand = new ArrayList(dPHand); - final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card"; - String[] dValid = ArrayUtils.EMPTY_STRING_ARRAY; - dValid = valid.split(","); - dPChHand = CardLists.getValidCards(dPHand, dValid, source.getController(), source); + if (dPHand.isEmpty()) + continue; // for loop over players - Player chooser = p; - if (mode.equals("RevealYouChoose")) { - chooser = source.getController(); - } else if (mode.equals("RevealOppChoose")) { - chooser = source.getController().getOpponent(); - } + if (sa.hasParam("RevealNumber")) { + String amountString = sa.getParam("RevealNumber"); + int amount = StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString) : CardFactoryUtil.xCount(source, source.getSVar(amountString)); + dPHand = getRevealedList(p, dPHand, amount, false); + } + List dPChHand = new ArrayList(dPHand); + final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card"; + String[] dValid = ArrayUtils.EMPTY_STRING_ARRAY; + dValid = valid.split(","); + dPChHand = CardLists.getValidCards(dPHand, dValid, source.getController(), source); - List toBeDiscarded = new ArrayList(); - if (chooser.isComputer()) { - toBeDiscarded = discardComputerChooses(sa, p, chooser, numCards, dValid, mode.startsWith("Reveal")); + Player chooser = p; + if (mode.equals("RevealYouChoose")) { + chooser = source.getController(); + } else if (mode.equals("RevealOppChoose")) { + chooser = source.getController().getOpponent(); + } + + List toBeDiscarded = new ArrayList(); + if (chooser.isComputer()) { + List dPChHand1 = new ArrayList(p.getCardsIn(ZoneType.Hand)); + dPChHand1 = CardLists.getValidCards(dPChHand1, dValid, source.getController(), source); + + int max = Math.min(dPChHand1.size(), numCards); + List list = new ArrayList(); + + if (!p.isOpponentOf(chooser) && p instanceof AIPlayer) { // discard AI cards + toBeDiscarded = ((AIPlayer) p).getAi().getCardsToDiscard(max, dValid, sa); } else { - // human - if (mode.startsWith("Reveal")) { - GuiChoose.oneOrNone("Revealed " + p + " hand", dPHand); - } - - if (sa.hasParam("AnyNumber")) { - List chosen = getDiscardedList(p, dPChHand, dPChHand.size(), true); - - for (Card c : chosen) { - dPChHand.remove(chosen); - toBeDiscarded.add(c); - } - } else - for (int i = 0; i < numCards; i++) { - if (dPChHand.isEmpty()) { - break; - } - Card dC = null; - if (sa.hasParam("Optional")) { - dC = GuiChoose.oneOrNone("Choose a card to be discarded", dPChHand); - } else { - dC = GuiChoose.one("Choose a card to be discarded", dPChHand); - } - - if (dC != null) { - dPChHand.remove(dC); - toBeDiscarded.add(dC); - } - else break; + // discard hostile or human opponent + for (int i = 0; i < max; i++) { + Card dC = chooseCardToDiscardFromOpponent(sa, dPChHand1); + dPChHand1.remove(dC); + toBeDiscarded.add(dC); } } + + if (mode.startsWith("Reveal")) { + GuiChoose.oneOrNone("Computer has chosen", list); + } - if (toBeDiscarded != null) { - for (Card card : toBeDiscarded) { - if ( null == card ) continue; - p.discard(card, sa); - discarded.add(card); + } else { + // human + if (mode.startsWith("Reveal")) { + GuiChoose.oneOrNone("Revealed " + p + " hand", dPHand); + } + + if (sa.hasParam("AnyNumber")) { + List chosen = getDiscardedList(p, dPChHand); + + for (Card c : chosen) { + dPChHand.remove(chosen); + toBeDiscarded.add(c); } + } else + for (int i = 0; i < numCards; i++) { + if (dPChHand.isEmpty()) { + break; + } + Card dC = null; + if (sa.hasParam("Optional")) { + dC = GuiChoose.oneOrNone("Choose a card to be discarded", dPChHand); + } else { + dC = GuiChoose.one("Choose a card to be discarded", dPChHand); + } + + if (dC != null) { + dPChHand.remove(dC); + toBeDiscarded.add(dC); + } + else break; + } + } + + if (toBeDiscarded != null) { + for (Card card : toBeDiscarded) { + if ( null == card ) continue; + p.discard(card, sa); + discarded.add(card); } } } @@ -329,11 +311,11 @@ public class DiscardEffect extends RevealEffectBase { } // discardResolve() - public static List getDiscardedList(final Player player, final List valid, final int max, boolean anyNumber) { + public static List getDiscardedList(final Player player, final List valid) { final List chosen = new ArrayList(); - final int validamount = Math.min(valid.size(), max); + final int validamount = Math.min(valid.size(), valid.size()); - if (anyNumber && player.isHuman() && validamount > 0) { + if (player.isHuman() && validamount > 0) { final List selection = GuiChoose.order("Choose Which Cards to Discard", "Discarded", -1, valid, null, null); for (final Object o : selection) { if (o != null && o instanceof Card) { diff --git a/src/main/java/forge/game/ai/AiController.java b/src/main/java/forge/game/ai/AiController.java index 19d89c99ec1..df943f0a37e 100644 --- a/src/main/java/forge/game/ai/AiController.java +++ b/src/main/java/forge/game/ai/AiController.java @@ -17,6 +17,7 @@ */ package forge.game.ai; +import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -545,7 +546,7 @@ public class AiController { // look for good discards while (count < numDiscard) { Card prefCard = null; - if (sa != null && sa.getActivatingPlayer() != null && sa.getActivatingPlayer().isHuman()) { + if (sa != null && sa.getActivatingPlayer() != null && sa.getActivatingPlayer().isOpponentOf(player)) { for (Card c : hand) { if (c.hasKeyword("If a spell or ability an opponent controls causes you to discard CARDNAME," + " put it onto the battlefield instead of putting it into your graveyard.")) { @@ -604,5 +605,38 @@ public class AiController { return discardList; } + + public Card chooseSingleCardForEffect(List options, SpellAbility sa, String title, boolean isOptional) { + ApiType api = sa.getApi(); + if ( null == api ) { + throw new InvalidParameterException("SA is not api-based, this is not supported yet"); + } + + switch(api) { + case Bond: return CardFactoryUtil.getBestCreatureAI(options); + default: throw new InvalidParameterException("AI chooseSingleCard does not know how to choose card for " + api); + } + } + + + public boolean confirmAction(SpellAbility sa, String mode, String message) { + ApiType api = sa.getApi(); + if ( null == api ) { + throw new InvalidParameterException("SA is not api-based, this is not supported yet"); + } + + switch(api) { + case Discard: + if ( mode.equals("Random") ) { // + // TODO For now AI will always discard Random used currently with: Balduvian Horde and similar cards + return true; + } + break; + + default: + } + String exMsg = String.format("AI confirmAction does not know what to decide about %s with %s mode.", api, mode); + throw new InvalidParameterException(exMsg); + } } diff --git a/src/main/java/forge/game/player/PlayerController.java b/src/main/java/forge/game/player/PlayerController.java index f35b3761484..16df31315a9 100644 --- a/src/main/java/forge/game/player/PlayerController.java +++ b/src/main/java/forge/game/player/PlayerController.java @@ -94,4 +94,5 @@ public abstract class PlayerController { public Card chooseSingleCardForEffect(List sourceList, SpellAbility sa, String title) { return chooseSingleCardForEffect(sourceList, sa, title); } public abstract Card chooseSingleCardForEffect(List sourceList, SpellAbility sa, String title, boolean isOptional); + public abstract boolean confirmAction(SpellAbility sa, String mode, String message); } diff --git a/src/main/java/forge/game/player/PlayerControllerAi.java b/src/main/java/forge/game/player/PlayerControllerAi.java index 1e07e43bd0d..2ac34cd911f 100644 --- a/src/main/java/forge/game/player/PlayerControllerAi.java +++ b/src/main/java/forge/game/player/PlayerControllerAi.java @@ -1,13 +1,10 @@ package forge.game.player; -import java.security.InvalidParameterException; import java.util.List; import java.util.Map; import forge.Card; import forge.GameEntity; -import forge.card.ability.ApiType; -import forge.card.cardfactory.CardFactoryUtil; import forge.card.spellability.Spell; import forge.card.spellability.SpellAbility; import forge.control.input.Input; @@ -193,15 +190,12 @@ public class PlayerControllerAi extends PlayerController { @Override public Card chooseSingleCardForEffect(List options, SpellAbility sa, String title, boolean isOptional) { - ApiType api = sa.getApi(); - if ( null == api ) { - throw new InvalidParameterException("SA is not api-based, this is not supported yet"); - } - - switch(api) { - case Bond: return CardFactoryUtil.getBestCreatureAI(options); - default: throw new InvalidParameterException("AI chooseSingleCard does not know how to choose card for " + api); - } + return brains.chooseSingleCardForEffect(options, sa, title, isOptional); + } + + @Override + public boolean confirmAction(SpellAbility sa, String mode, String message) { + return brains.confirmAction(sa, mode, message); } } diff --git a/src/main/java/forge/game/player/PlayerControllerHuman.java b/src/main/java/forge/game/player/PlayerControllerHuman.java index 4d255c51a82..5e73ee21f8f 100644 --- a/src/main/java/forge/game/player/PlayerControllerHuman.java +++ b/src/main/java/forge/game/player/PlayerControllerHuman.java @@ -237,5 +237,13 @@ public class PlayerControllerHuman extends PlayerController { return GuiChoose.one(title, options); } + /* (non-Javadoc) + * @see forge.game.player.PlayerController#confirmAction(forge.card.spellability.SpellAbility, java.lang.String, java.lang.String) + */ + @Override + public boolean confirmAction(SpellAbility sa, String mode, String message) { + return GuiDialog.confirm(sa.getSourceCard(), message); + } + }