diff --git a/forge-game/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-game/src/main/java/forge/ai/ability/ChangeZoneAi.java index fa37f98f7d8..db890f1503d 100644 --- a/forge-game/src/main/java/forge/ai/ability/ChangeZoneAi.java +++ b/forge-game/src/main/java/forge/ai/ability/ChangeZoneAi.java @@ -1101,65 +1101,18 @@ public class ChangeZoneAi extends SpellAbilityAi { * a {@link forge.game.player.Player} object. * @param changeNum2 * @param destination + * @param fetchList * @param libraryPos2 * @param origin2 + * @return */ - public static void hiddenOriginResolveAI(final Player ai, final SpellAbility sa, Player player, int changeNum, List origin, ZoneType destination, int libraryPos2) { + public static List hiddenOriginResolveAI(final Player decider, final SpellAbility sa, Player player, int changeNum, List origin, ZoneType destination, List fetchList, int libraryPos) { final Card source = sa.getSourceCard(); final boolean defined = sa.hasParam("Defined"); - final Game game = ai.getGame(); + final Game game = decider.getGame(); - - String type = sa.getParam("ChangeType"); - if (type == null) { - type = "Card"; - } - - - List fetchList; - boolean shuffleMandatory = true; - boolean searchedLibrary = false; - if (defined) { - fetchList = new ArrayList(AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa)); - if (!sa.hasParam("ChangeNum")) { - changeNum = fetchList.size(); - } - } else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand) - && !sa.hasParam("DefinedPlayer")) { - fetchList = game.getCardsIn(origin); - fetchList = AbilityUtils.filterListByType(fetchList, type, sa); - } else { - fetchList = player.getCardsIn(origin); - if (origin.contains(ZoneType.Library) && !sa.hasParam("NoLooking")) { - searchedLibrary = true; - if (ai.hasKeyword("LimitSearchLibrary")) { - // Aven Mindcensor - fetchList.removeAll(player.getCardsIn(ZoneType.Library)); - final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4); - fetchList.addAll(player.getCardsIn(ZoneType.Library, fetchNum)); - if (fetchNum == 0) { - searchedLibrary = false; - } - } - if (ai.hasKeyword("CantSearchLibrary")) { - fetchList.removeAll(player.getCardsIn(ZoneType.Library)); - // "if you do/sb does, shuffle" is not mandatory, should has this param. - // "then shuffle" is mandatory - shuffleMandatory = !sa.hasParam("ShuffleNonMandatory"); - searchedLibrary = false; - } - } - fetchList = AbilityUtils.filterListByType(fetchList, type, sa); - } - if (searchedLibrary && ai.equals(player)) { - ai.incLibrarySearched(); - } - if (sa.hasParam("NoShuffle")) { - shuffleMandatory = false; - } - - final List fetched = new ArrayList(); + final List movedCards = new ArrayList(); final boolean remember = sa.hasParam("RememberChanged"); final boolean forget = sa.hasParam("ForgetChanged"); final boolean champion = sa.hasParam("Champion"); @@ -1167,19 +1120,15 @@ public class ChangeZoneAi extends SpellAbilityAi { final String totalcmc = sa.getParam("WithTotalCMC"); int totcmc = AbilityUtils.calculateAmount(source, totalcmc, sa); - if (sa.hasParam("Unimprint")) { - source.clearImprinted(); - } - for (int i = 0; i < changeNum; i++) { if (sa.hasParam("DifferentNames")) { - for (Card c : fetched) { + for (Card c : movedCards) { fetchList = CardLists.filter(fetchList, Predicates.not(CardPredicates.nameEquals(c.getName()))); } } if (totalcmc != null) { if (totcmc >= 0) { - fetchList = CardLists.getValidCards(fetchList, "Card.cmcLE" + Integer.toString(totcmc), ai, source); + fetchList = CardLists.getValidCards(fetchList, "Card.cmcLE" + Integer.toString(totcmc), decider, source); } } if ((fetchList.size() == 0) || (destination == null)) { @@ -1193,129 +1142,30 @@ public class ChangeZoneAi extends SpellAbilityAi { } else if (defined) { c = fetchList.get(0); } else { - final Player activator = sa.getActivatingPlayer(); - - CardLists.shuffle(fetchList); - // Save a card as a default, in case we can't find anything suitable. - Card first = fetchList.get(0); - if (ZoneType.Battlefield.equals(destination)) { - fetchList = CardLists.filter(fetchList, new Predicate() { - @Override - public boolean apply(final Card c) { - if (c.isType("Legendary")) { - if (!ai.getCardsIn(ZoneType.Battlefield, c.getName()).isEmpty()) { - return false; - } - } - return true; - } - }); - if (player.isOpponentOf(ai) && sa.hasParam("GainControl") && activator.equals(ai)) { - fetchList = CardLists.filter(fetchList, new Predicate() { - @Override - public boolean apply(final Card c) { - if (c.hasSVar("RemAIDeck") || c.hasSVar("RemRandomDeck")) { - return false; - } - return true; - } - }); - } - } - if (ZoneType.Exile.equals(destination) || origin.contains(ZoneType.Battlefield) - || (ZoneType.Library.equals(destination) && origin.contains(ZoneType.Hand))) { - // Exiling or bouncing stuff - if (player.isOpponentOf(ai)) { - c = ComputerUtilCard.getBestAI(fetchList); - } else { - c = ComputerUtilCard.getWorstAI(fetchList); - } - } else if (origin.contains(ZoneType.Library) - && (type.contains("Basic") || areAllBasics(type))) { - c = basicManaFixing(ai, fetchList); - } else if (ZoneType.Hand.equals(destination) && CardLists.getNotType(fetchList, "Creature").isEmpty()) { - c = chooseCreature(ai, fetchList); - } else if (ZoneType.Battlefield.equals(destination) || ZoneType.Graveyard.equals(destination)) { - if (!activator.equals(ai) && sa.hasParam("GainControl")) { - c = ComputerUtilCard.getWorstAI(fetchList); - } else { - c = ComputerUtilCard.getBestAI(fetchList); - } - } else { - // Don't fetch another tutor with the same name - List sameNamed = CardLists.filter(fetchList, Predicates.not(CardPredicates.nameEquals(source.getName()))); - if (origin.contains(ZoneType.Library) && !sameNamed.isEmpty()) { - fetchList = sameNamed; - } - - // Does AI need a land? - List hand = ai.getCardsIn(ZoneType.Hand); - if (CardLists.filter(hand, Presets.LANDS).isEmpty() && CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), Presets.LANDS).size() < 4) { - boolean canCastSomething = false; - for (Card cardInHand : hand) { - canCastSomething |= ComputerUtilMana.hasEnoughManaSourcesToCast(cardInHand.getFirstSpellAbility(), ai); - } - if (!canCastSomething) { - System.out.println("Pulling a land as there are none in hand, less than 4 on the board, and nothing in hand is castable."); - c = basicManaFixing(ai, fetchList); - } - } - if (c == null) { - System.out.println("Don't need a land or none available; trying for a creature."); - fetchList = CardLists.getNotType(fetchList, "Land"); - // Prefer to pull a creature, generally more useful for AI. - c = chooseCreature(ai, CardLists.filter(fetchList, CardPredicates.Presets.CREATURES)); - } - if (c == null) { // Could not find a creature. - if (ai.getLife() <= 5) { // Desperate? - // Get something AI can cast soon. - System.out.println("5 Life or less, trying to find something castable."); - CardLists.sortByCmcDesc(fetchList); - for (Card potentialCard : fetchList) { - if (ComputerUtilMana.hasEnoughManaSourcesToCast(potentialCard.getFirstSpellAbility(), ai)) { - c = potentialCard; - break; - } - } - } else { - // Get the best card in there. - System.out.println("No creature and lots of life, finding something good."); - c = ComputerUtilCard.getBestAI(fetchList); - } - } - } - if (c == null) { - c = first; - } + c = chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player, decider); } - fetched.add(c); + movedCards.add(c); fetchList.remove(c); if (totalcmc != null) { totcmc -= c.getCMC(); } } - if (origin.contains(ZoneType.Library) && !defined && !"False".equals(sa.getParam("Shuffle")) && shuffleMandatory) { - player.shuffle(sa); - } - - for (final Card c : fetched) { + for (final Card c : movedCards) { Card movedCard = null; if (ZoneType.Library.equals(destination)) { - final int libraryPos = sa.hasParam("LibraryPosition") ? AbilityUtils.calculateAmount(source, sa.getParam("LibraryPosition"), sa) : 0; movedCard = game.getAction().moveToLibrary(c, libraryPos); } else if (ZoneType.Battlefield.equals(destination)) { if (sa.hasParam("Tapped")) { c.setTapped(true); } if (sa.hasParam("GainControl")) { + Player newController = sa.getActivatingPlayer(); if (sa.hasParam("NewController")) { - final Player p = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("DefinedPlayer"), sa).get(0); - c.setController(p, game.getNextTimestamp()); - } else { - c.setController(sa.getActivatingPlayer(), game.getNextTimestamp()); - } + newController = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("NewController"), sa).get(0); + } + c.setController(newController, game.getNextTimestamp()); } if (sa.hasParam("AttachedTo")) { @@ -1399,19 +1249,114 @@ public class ChangeZoneAi extends SpellAbilityAi { source.addImprinted(movedCard); } } - - if ("True".equals(sa.getParam("Shuffle"))) { - player.shuffle(sa); - } - - if (((!ZoneType.Battlefield.equals(destination) && !"Card".equals(type) && !defined) - || (sa.hasParam("Reveal") && !fetched.isEmpty())) - && !sa.hasParam("NoReveal")) { - - game.getAction().reveal(fetched, player); - } + + return movedCards; } // end changeHiddenOriginResolveAI + private static Card chooseCardToHiddenOriginChangeZone(ZoneType destination, List origin, SpellAbility sa, List fetchList, Player player, final Player decider) { + + String type = sa.getParam("ChangeType"); + if (type == null) { + type = "Card"; + } + + Card c = null; + final Player activator = sa.getActivatingPlayer(); + + CardLists.shuffle(fetchList); + // Save a card as a default, in case we can't find anything suitable. + Card first = fetchList.get(0); + if (ZoneType.Battlefield.equals(destination)) { + fetchList = CardLists.filter(fetchList, new Predicate() { + @Override + public boolean apply(final Card c) { + if (c.isType("Legendary")) { + if (!decider.getCardsIn(ZoneType.Battlefield, c.getName()).isEmpty()) { + return false; + } + } + return true; + } + }); + if (player.isOpponentOf(decider) && sa.hasParam("GainControl") && activator.equals(decider)) { + fetchList = CardLists.filter(fetchList, new Predicate() { + @Override + public boolean apply(final Card c) { + if (c.hasSVar("RemAIDeck") || c.hasSVar("RemRandomDeck")) { + return false; + } + return true; + } + }); + } + } + if (ZoneType.Exile.equals(destination) || origin.contains(ZoneType.Battlefield) + || (ZoneType.Library.equals(destination) && origin.contains(ZoneType.Hand))) { + // Exiling or bouncing stuff + if (player.isOpponentOf(decider)) { + c = ComputerUtilCard.getBestAI(fetchList); + } else { + c = ComputerUtilCard.getWorstAI(fetchList); + } + } else if (origin.contains(ZoneType.Library) && (type.contains("Basic") || areAllBasics(type))) { + c = basicManaFixing(decider, fetchList); + } else if (ZoneType.Hand.equals(destination) && CardLists.getNotType(fetchList, "Creature").isEmpty()) { + c = chooseCreature(decider, fetchList); + } else if (ZoneType.Battlefield.equals(destination) || ZoneType.Graveyard.equals(destination)) { + if (!activator.equals(decider) && sa.hasParam("GainControl")) { + c = ComputerUtilCard.getWorstAI(fetchList); + } else { + c = ComputerUtilCard.getBestAI(fetchList); + } + } else { + // Don't fetch another tutor with the same name + List sameNamed = CardLists.filter(fetchList, Predicates.not(CardPredicates.nameEquals(sa.getSourceCard().getName()))); + if (origin.contains(ZoneType.Library) && !sameNamed.isEmpty()) { + fetchList = sameNamed; + } + + // Does AI need a land? + List hand = decider.getCardsIn(ZoneType.Hand); + if (CardLists.filter(hand, Presets.LANDS).isEmpty() && CardLists.filter(decider.getCardsIn(ZoneType.Battlefield), Presets.LANDS).size() < 4) { + boolean canCastSomething = false; + for (Card cardInHand : hand) { + canCastSomething |= ComputerUtilMana.hasEnoughManaSourcesToCast(cardInHand.getFirstSpellAbility(), decider); + } + if (!canCastSomething) { + System.out.println("Pulling a land as there are none in hand, less than 4 on the board, and nothing in hand is castable."); + c = basicManaFixing(decider, fetchList); + } + } + if (c == null) { + System.out.println("Don't need a land or none available; trying for a creature."); + fetchList = CardLists.getNotType(fetchList, "Land"); + // Prefer to pull a creature, generally more useful for AI. + c = chooseCreature(decider, CardLists.filter(fetchList, CardPredicates.Presets.CREATURES)); + } + if (c == null) { // Could not find a creature. + if (decider.getLife() <= 5) { // Desperate? + // Get something AI can cast soon. + System.out.println("5 Life or less, trying to find something castable."); + CardLists.sortByCmcDesc(fetchList); + for (Card potentialCard : fetchList) { + if (ComputerUtilMana.hasEnoughManaSourcesToCast(potentialCard.getFirstSpellAbility(), decider)) { + c = potentialCard; + break; + } + } + } else { + // Get the best card in there. + System.out.println("No creature and lots of life, finding something good."); + c = ComputerUtilCard.getBestAI(fetchList); + } + } + } + if (c == null) { + c = first; + } + return c; + } + /* (non-Javadoc) * @see forge.card.ability.SpellAbilityAi#confirmAction(forge.game.player.Player, forge.card.spellability.SpellAbility, forge.game.player.PlayerActionConfirmMode, java.lang.String) */ diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index 895be4a71ea..c560dc4318b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -644,19 +644,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if( optional && !decider.getController().confirmAction(sa, PlayerActionConfirmMode.ChangeZoneGeneral, defined ? "Put that card from " + origin + "to " + destination : "Search " + origin + "?")) return; - if (decider.isHuman()) { - changeHiddenOriginResolveHuman(decider, sa, player, changeNum, origin, destination, libraryPos); - } else { - ChangeZoneAi.hiddenOriginResolveAI(decider, sa, player, changeNum, origin, destination, libraryPos); - } - } - - private static void changeHiddenOriginResolveHuman(final Player decider, final SpellAbility sa, Player player, int changeNum, List origin, ZoneType destination, int libraryPos) { - final Card source = sa.getSourceCard(); - final boolean defined = sa.hasParam("Defined"); - final Game game = player.getGame(); - - final List movedCards = new ArrayList(); + String changeType = sa.getParam("ChangeType"); List fetchList; boolean shuffleMandatory = true; @@ -668,7 +656,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } } else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand) && !sa.hasParam("DefinedPlayer")) { - fetchList = game.getCardsIn(origin); + fetchList = player.getGame().getCardsIn(origin); } else { fetchList = player.getCardsIn(origin); if (origin.contains(ZoneType.Library) && !sa.hasParam("NoLooking")) { @@ -676,10 +664,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (decider.hasKeyword("LimitSearchLibrary")) { // Aven Mindcensor fetchList.removeAll(player.getCardsIn(ZoneType.Library)); final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4); - if (fetchNum == 0) { + if (fetchNum == 0) searchedLibrary = false; - } - fetchList.addAll(player.getCardsIn(ZoneType.Library, fetchNum)); + else + fetchList.addAll(player.getCardsIn(ZoneType.Library, fetchNum)); } if (decider.hasKeyword("CantSearchLibrary")) { fetchList.removeAll(player.getCardsIn(ZoneType.Library)); @@ -690,15 +678,14 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } } } + + if (!defined && changeType != null) + fetchList = AbilityUtils.filterListByType(fetchList, sa.getParam("ChangeType"), sa); if (searchedLibrary && decider.equals(player)) { // should only count the number of searching player's own library decider.incLibrarySearched(); } - if (sa.hasParam("NoShuffle")) { - shuffleMandatory = false; - } - if (!defined) { if (origin.contains(ZoneType.Library) && !defined && !sa.hasParam("NoLooking") && !decider.hasKeyword("CantSearchLibrary")) { final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4); @@ -711,9 +698,40 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (origin.contains(ZoneType.Hand) && player.isOpponentOf(decider)) { decider.getController().reveal(player.getCardsIn(ZoneType.Hand), ZoneType.Hand, player, source.getName() + " - Looking at cards in "); } - fetchList = AbilityUtils.filterListByType(fetchList, sa.getParam("ChangeType"), sa); + } + if (sa.hasParam("NoShuffle")) { + shuffleMandatory = false; + } + + final Game game = player.getGame(); + if (sa.hasParam("Unimprint")) { + source.clearImprinted(); + } + + List movedCards; + if (decider.isHuman()) { + movedCards = changeHiddenOriginResolveHuman(decider, sa, player, changeNum, origin, destination, fetchList, libraryPos); + } else { + movedCards = ChangeZoneAi.hiddenOriginResolveAI(decider, sa, player, changeNum, origin, destination, fetchList, libraryPos); + } + + if (((!ZoneType.Battlefield.equals(destination) && changeType != null && !defined) + || (sa.hasParam("Reveal") && !movedCards.isEmpty())) && !sa.hasParam("NoReveal")) { + game.getAction().reveal(movedCards, player); + } + + if ((origin.contains(ZoneType.Library) && !destination.equals(ZoneType.Library) && !defined && shuffleMandatory) + || (sa.hasParam("Shuffle") && "True".equals(sa.getParam("Shuffle")))) { + player.shuffle(sa); + } + } + + private static List changeHiddenOriginResolveHuman(final Player decider, final SpellAbility sa, Player player, int changeNum, List origin, ZoneType destination, List fetchList, int libraryPos) { + final Card source = sa.getSourceCard(); + final Game game = player.getGame(); + final boolean remember = sa.hasParam("RememberChanged"); final boolean champion = sa.hasParam("Champion"); final boolean forget = sa.hasParam("ForgetChanged"); @@ -722,9 +740,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { final String totalcmc = sa.getParam("WithTotalCMC"); int totcmc = AbilityUtils.calculateAmount(source, totalcmc, sa); - if (sa.hasParam("Unimprint")) { - source.clearImprinted(); - } + final List movedCards = new ArrayList(); for (int i = 0; i < changeNum && destination != null; i++) { if (sa.hasParam("DifferentNames")) { @@ -773,12 +789,11 @@ public class ChangeZoneEffect extends SpellAbilityEffect { c.setTapped(true); } if (sa.hasParam("GainControl")) { + Player newController = sa.getActivatingPlayer(); if (sa.hasParam("NewController")) { - final Player p = AbilityUtils.getDefinedPlayers(source, sa.getParam("NewController"), sa).get(0); - c.setController(p, game.getNextTimestamp()); - } else { - c.setController(sa.getActivatingPlayer(), game.getNextTimestamp()); - } + newController = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("NewController"), sa).get(0); + } + c.setController(newController, game.getNextTimestamp()); } if (sa.hasParam("AttachedTo")) { @@ -896,18 +911,8 @@ public class ChangeZoneEffect extends SpellAbilityEffect { totcmc -= movedCard.getCMC(); } } - if (sa.hasParam("Reveal") && !movedCards.isEmpty()) { - ZoneType zt = null; - if (!origin.isEmpty()) { - zt = origin.get(0); - } - decider.getController().reveal(movedCards, zt, player, source + " - Revealed card" + (movedCards.size() > 1 ? "s" : "") + " from "); - } - - if ((origin.contains(ZoneType.Library) && !destination.equals(ZoneType.Library) && !defined && shuffleMandatory) - || (sa.hasParam("Shuffle") && "True".equals(sa.getParam("Shuffle")))) { - player.shuffle(sa); - } + + return movedCards; } /**