diff --git a/src/main/java/forge/ComputerAIGeneral.java b/src/main/java/forge/ComputerAIGeneral.java index d022dba44da..ec08391f547 100644 --- a/src/main/java/forge/ComputerAIGeneral.java +++ b/src/main/java/forge/ComputerAIGeneral.java @@ -89,9 +89,9 @@ public class ComputerAIGeneral implements Computer { * a {@link java.lang.String} object. */ private void playCards(final String phase) { - final SpellAbility[] sp = phase.equals(Constant.Phase.MAIN1) ? this.getMain1() : this.getMain2(); + final CardList list = phase.equals(Constant.Phase.MAIN1) ? this.getMain1() : this.getMain2(); - final boolean nextPhase = ComputerUtil.playSpellAbilities(sp); + final boolean nextPhase = ComputerUtil.playSpellAbilities(getSpellAbilities(list)); if (nextPhase) { AllZone.getPhaseHandler().passPriority(); @@ -105,14 +105,16 @@ public class ComputerAIGeneral implements Computer { * * @return an array of {@link forge.card.spellability.SpellAbility} objects. */ - private SpellAbility[] getMain1() { + private CardList getMain1() { + final Player computer = AllZone.getComputerPlayer(); + final Player human = AllZone.getHumanPlayer(); // Card list of all cards to consider - CardList hand = AllZone.getComputerPlayer().getCardsIn(Zone.Hand); + CardList hand = computer.getCardsIn(Zone.Hand); final boolean hasACardGivingHaste = this.hasACardGivingHaste(); // If mana pool is not empty try to play anything - if (AllZone.getComputerPlayer().getManaPool().isEmpty()) { + if (computer.getManaPool().isEmpty()) { hand = hand.filter(new CardListFilter() { @Override public boolean addCard(final Card c) { @@ -131,7 +133,7 @@ public class ComputerAIGeneral implements Computer { } // get all cards the computer controls with BuffedBy - final CardList buffed = AllZone.getComputerPlayer().getCardsIn(Zone.Battlefield); + final CardList buffed = computer.getCardsIn(Zone.Battlefield); for (int j = 0; j < buffed.size(); j++) { final Card buffedcard = buffed.get(j); if (buffedcard.getSVar("BuffedBy").length() > 0) { @@ -144,7 +146,7 @@ public class ComputerAIGeneral implements Computer { } // BuffedBy // get all cards the human controls with AntiBuffedBy - final CardList antibuffed = AllZone.getHumanPlayer().getCardsIn(Zone.Battlefield); + final CardList antibuffed = human.getCardsIn(Zone.Battlefield); for (int k = 0; k < antibuffed.size(); k++) { final Card buffedcard = antibuffed.get(k); if (buffedcard.getSVar("AntiBuffedBy").length() > 0) { @@ -160,9 +162,9 @@ public class ComputerAIGeneral implements Computer { return false; } - final CardList vengevines = AllZone.getComputerPlayer().getCardsIn(Zone.Graveyard, "Vengevine"); + final CardList vengevines = computer.getCardsIn(Zone.Graveyard, "Vengevine"); if (vengevines.size() > 0) { - final CardList creatures = AllZone.getComputerPlayer().getCardsIn(Zone.Hand); + final CardList creatures = computer.getCardsIn(Zone.Hand); final CardList creatures2 = new CardList(); for (int i = 0; i < creatures.size(); i++) { if (creatures.get(i).isCreature() @@ -182,21 +184,17 @@ public class ComputerAIGeneral implements Computer { } }); } - final CardList all = AllZone.getComputerPlayer().getCardsIn(Zone.Battlefield); - all.addAll(CardFactoryUtil.getExternalZoneActivationCards(AllZone.getComputerPlayer())); + final CardList all = computer.getCardsIn(Zone.Battlefield); + all.addAll(computer.getCardsIn(Zone.Exile)); + all.addAll(computer.getCardsIn(Zone.Graveyard)); + if (!computer.getCardsIn(Zone.Library).isEmpty()) { + all.add(computer.getCardsIn(Zone.Library).get(0)); + } + all.addAll(human.getCardsIn(Zone.Battlefield)); + all.addAll(human.getCardsIn(Zone.Exile)); all.addAll(hand); - CardList humanPlayable = AllZone.getHumanPlayer().getCardsIn(Zone.Battlefield); - humanPlayable = humanPlayable.filter(new CardListFilter() { - @Override - public boolean addCard(final Card c) { - return (c.canAnyPlayerActivate()); - } - }); - - all.addAll(humanPlayable); - - return this.getPlayable(all); + return all; } // getMain1() /** @@ -240,49 +238,39 @@ public class ComputerAIGeneral implements Computer { * * @return an array of {@link forge.card.spellability.SpellAbility} objects. */ - private SpellAbility[] getMain2() { + private CardList getMain2() { + final Player computer = AllZone.getComputerPlayer(); + final Player human = AllZone.getHumanPlayer(); // Card list of all cards to consider - CardList all = AllZone.getComputerPlayer().getCardsIn(Zone.Hand); + CardList all = computer.getCardsIn(Zone.Hand); // Don't play permanents with Flash before humans declare attackers step all = all.filter(new CardListFilter() { @Override public boolean addCard(final Card c) { if (c.isPermanent() && c.hasKeyword("Flash") - && (AllZone.getPhaseHandler().isPlayerTurn(AllZone.getComputerPlayer()) || AllZone.getPhaseHandler() + && (AllZone.getPhaseHandler().isPlayerTurn(computer) || AllZone.getPhaseHandler() .isBefore(Constant.Phase.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY))) { return false; } return true; } }); - all.addAll(AllZone.getComputerPlayer().getCardsIn(Zone.Battlefield)); - all.addAll(CardFactoryUtil.getExternalZoneActivationCards(AllZone.getComputerPlayer())); + all.addAll(computer.getCardsIn(Zone.Exile)); + all.addAll(computer.getCardsIn(Zone.Graveyard)); + if (!computer.getCardsIn(Zone.Library).isEmpty()) { + all.add(computer.getCardsIn(Zone.Library).get(0)); + } + all.addAll(human.getCardsIn(Zone.Exile)); // Prevent the computer from summoning Ball Lightning type creatures // during main phase 2 all = all.getNotKeyword("At the beginning of the end step, sacrifice CARDNAME."); - all = all.filter(new CardListFilter() { - @Override - public boolean addCard(final Card c) { - if (c.isLand()) { - return false; - } - return true; - } - }); + all.addAll(computer.getCardsIn(Zone.Battlefield)); + all.addAll(human.getCardsIn(Zone.Battlefield)); - CardList humanPlayable = AllZone.getHumanPlayer().getCardsIn(Zone.Battlefield); - humanPlayable = humanPlayable.filter(new CardListFilter() { - @Override - public boolean addCard(final Card c) { - return (c.canAnyPlayerActivate()); - } - }); - all.addAll(humanPlayable); - - return this.getPlayable(all); + return all; } // getMain2() /** @@ -293,7 +281,9 @@ public class ComputerAIGeneral implements Computer { * @return a {@link forge.CardList} object. */ private CardList getAvailableSpellAbilities() { - CardList all = AllZone.getComputerPlayer().getCardsIn(Zone.Hand); + final Player computer = AllZone.getComputerPlayer(); + final Player human = AllZone.getHumanPlayer(); + CardList all = computer.getCardsIn(Zone.Hand); // Don't play permanents with Flash before humans declare attackers step all = all.filter(new CardListFilter() { @Override @@ -301,24 +291,21 @@ public class ComputerAIGeneral implements Computer { if (c.isPermanent() && c.hasKeyword("Flash") && !hasETBTrigger(c) - && (AllZone.getPhaseHandler().isPlayerTurn(AllZone.getComputerPlayer()) || AllZone.getPhaseHandler() + && (AllZone.getPhaseHandler().isPlayerTurn(computer) || AllZone.getPhaseHandler() .isBefore(Constant.Phase.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY))) { return false; } return true; } }); - all.addAll(AllZone.getComputerPlayer().getCardsIn(Zone.Battlefield)); - all.addAll(CardFactoryUtil.getExternalZoneActivationCards(AllZone.getComputerPlayer())); - - CardList humanPlayable = AllZone.getHumanPlayer().getCardsIn(Zone.Battlefield); - humanPlayable = humanPlayable.filter(new CardListFilter() { - @Override - public boolean addCard(final Card c) { - return (c.canAnyPlayerActivate()); - } - }); - all.addAll(humanPlayable); + all.addAll(computer.getCardsIn(Zone.Battlefield)); + all.addAll(computer.getCardsIn(Zone.Exile)); + all.addAll(computer.getCardsIn(Zone.Graveyard)); + if (!computer.getCardsIn(Zone.Library).isEmpty()) { + all.add(computer.getCardsIn(Zone.Library).get(0)); + } + all.addAll(human.getCardsIn(Zone.Exile)); + all.addAll(human.getCardsIn(Zone.Battlefield)); return all; } @@ -351,17 +338,6 @@ public class ComputerAIGeneral implements Computer { return false; } - /** - *

- * getOtherPhases. - *

- * - * @return an array of {@link forge.card.spellability.SpellAbility} objects. - */ - private SpellAbility[] getOtherPhases() { - return this.getPlayable(this.getAvailableSpellAbilities()); - } - /** *

* getPossibleCounters. @@ -381,25 +357,44 @@ public class ComputerAIGeneral implements Computer { * @return a {@link java.util.ArrayList} object. */ private ArrayList getPossibleETBCounters() { - return this.getETBCounters(this.getAvailableSpellAbilities()); + final Player computer = AllZone.getComputerPlayer(); + final Player human = AllZone.getHumanPlayer(); + CardList all = computer.getCardsIn(Zone.Hand); + all.addAll(computer.getCardsIn(Zone.Exile)); + all.addAll(computer.getCardsIn(Zone.Graveyard)); + if (!computer.getCardsIn(Zone.Library).isEmpty()) { + all.add(computer.getCardsIn(Zone.Library).get(0)); + } + all.addAll(human.getCardsIn(Zone.Exile)); + + final ArrayList spellAbilities = new ArrayList(); + for (final Card c : all) { + for (final SpellAbility sa : c.getSpellAbility()) { + if (sa instanceof SpellPermanent) { + if (SpellPermanent.checkETBEffects(c, sa, "Counter")) { + spellAbilities.add(sa); + } + } + } + } + return spellAbilities; } /** - * Returns the spellAbilities from the card list that the computer is able - * to play. + * Returns the spellAbilities from the card list * * @param l * a {@link forge.CardList} object. * @return an array of {@link forge.card.spellability.SpellAbility} objects. */ - private SpellAbility[] getPlayable(final CardList l) { - final ArrayList spellAbility = new ArrayList(); + private ArrayList getSpellAbilities(final CardList l) { + final ArrayList spellAbilities = new ArrayList(); for (final Card c : l) { for (final SpellAbility sa : c.getSpellAbility()) { - spellAbility.add(sa); + spellAbilities.add(sa); } } - return spellAbility.toArray(new SpellAbility[spellAbility.size()]); + return spellAbilities; } /** @@ -425,31 +420,6 @@ public class ComputerAIGeneral implements Computer { return spellAbility; } - /** - *

- * getETBCounters. - *

- * - * @param l - * a {@link forge.CardList} object. - * @return a {@link java.util.ArrayList} object. - */ - private ArrayList getETBCounters(final CardList l) { - final ArrayList spellAbility = new ArrayList(); - for (final Card c : l) { - for (final SpellAbility sa : c.getSpellAbility()) { - // Or if this Permanent has an ETB ability with Counter - if (sa instanceof SpellPermanent) { - if (SpellPermanent.checkETBEffects(c, sa, "Counter")) { - spellAbility.add(sa); - } - } - } - } - - return spellAbility; - } - /** *

* begin_combat. @@ -562,10 +532,10 @@ public class ComputerAIGeneral implements Computer { */ public final void stackResponse() { // if top of stack is empty - final SpellAbility[] sas = this.getOtherPhases(); + final ArrayList sas = this.getSpellAbilities(this.getAvailableSpellAbilities()); if (AllZone.getStack().size() == 0) { - boolean pass = (sas.length == 0) + boolean pass = (sas.size() == 0) || AllZone.getPhaseHandler().is(Constant.Phase.END_OF_TURN, AllZone.getComputerPlayer()); if (!pass) { // Each AF should check the phase individually pass = ComputerUtil.playSpellAbilities(sas); @@ -597,13 +567,13 @@ public class ComputerAIGeneral implements Computer { possibleCounters.clear(); possibleCounters = this.getPossibleETBCounters(); - if ((possibleCounters.size() > 0) && !ComputerUtil.playAbilities(possibleCounters)) { + if ((possibleCounters.size() > 0) && !ComputerUtil.playSpellAbilities(possibleCounters)) { // Responding Permanent w/ ETB Counter is on the Stack // AllZone.getPhaseHandler().passPriority(); return; } - if (sas.length > 0) { + if (sas.size() > 0) { // Spell not Countered if (!ComputerUtil.playSpellAbilities(sas)) { return; diff --git a/src/main/java/forge/ComputerUtil.java b/src/main/java/forge/ComputerUtil.java index 503c4f559b8..9c8832f4de7 100644 --- a/src/main/java/forge/ComputerUtil.java +++ b/src/main/java/forge/ComputerUtil.java @@ -63,10 +63,9 @@ public class ComputerUtil { public static boolean playSpellAbilities(final SpellAbility[] all) { // not sure "playing biggest spell" matters? ComputerUtil.sortSpellAbilityByCost(all); - // MyRandom.shuffle(all); for (final SpellAbility sa : all) { - // Don't add Counterspells to the "normal" playcard lookupss + // Don't add Counterspells to the "normal" playcard lookups final AbilityFactory af = sa.getAbilityFactory(); if ((af != null) && af.getAPI().equals("Counter")) { continue; @@ -141,7 +140,7 @@ public class ComputerUtil { * a {@link java.util.ArrayList} object. * @return a boolean. */ - public static boolean playAbilities(final ArrayList all) { + public static boolean playSpellAbilities(final ArrayList all) { final SpellAbility[] sas = new SpellAbility[all.size()]; for (int i = 0; i < sas.length; i++) { sas[i] = all.get(i); diff --git a/src/main/java/forge/card/staticability/StaticAbility.java b/src/main/java/forge/card/staticability/StaticAbility.java index 2a9f7e29325..5fe7b151524 100644 --- a/src/main/java/forge/card/staticability/StaticAbility.java +++ b/src/main/java/forge/card/staticability/StaticAbility.java @@ -439,6 +439,9 @@ public class StaticAbility { } if (this.mapParams.containsKey("TopCardOfLibraryIs")) { + if (controller.getCardsIn(Zone.Library).isEmpty()) { + return false; + } final Card topCard = controller.getCardsIn(Zone.Library).get(0); if (!topCard.isValid(this.mapParams.get("TopCardOfLibraryIs").split(","), controller, this.hostCard)) { return false;