From ab03da16a0db4e85f366baceea545600ddfe4016 Mon Sep 17 00:00:00 2001 From: elcnesh Date: Sat, 23 May 2015 07:13:10 +0000 Subject: [PATCH] - Cleanup and fix PlayEffect, especially related to optionally playing multiple cards - Fix Jace, Architect of Thought's ultimate to search each player's library --- .../game/ability/effects/PlayEffect.java | 67 +++++++++++-------- .../j/jace_architect_of_thought.txt | 9 ++- 2 files changed, 44 insertions(+), 32 deletions(-) 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 8a60f5dc8c2..0fdd43b976e 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 @@ -30,7 +30,7 @@ import forge.util.Lang; public class PlayEffect extends SpellAbilityEffect { @Override - protected String getStackDescription(SpellAbility sa) { + protected String getStackDescription(final SpellAbility sa) { final StringBuilder sb = new StringBuilder(); sb.append("Play "); @@ -49,13 +49,12 @@ public class PlayEffect extends SpellAbilityEffect { } @Override - public void resolve(SpellAbility sa) { + public void resolve(final SpellAbility sa) { final Card source = sa.getHostCard(); Player activator = sa.getActivatingPlayer(); final Game game = activator.getGame(); - boolean optional = sa.hasParam("Optional"); + final boolean optional = sa.hasParam("Optional"); boolean remember = sa.hasParam("RememberPlayed"); - boolean wasFaceDown = false; boolean useEncoded = false; int amount = 1; if (sa.hasParam("Amount") && !sa.getParam("Amount").equals("All")) { @@ -84,26 +83,26 @@ public class PlayEffect extends SpellAbilityEffect { } else if (sa.hasParam("AnySupportedCard")) { List cards = Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards()); - String valid = sa.getParam("AnySupportedCard"); + final String valid = sa.getParam("AnySupportedCard"); if (StringUtils.containsIgnoreCase(valid, "sorcery")) { - Predicate cpp = Predicates.compose(CardRulesPredicates.Presets.IS_SORCERY, PaperCard.FN_GET_RULES); + final Predicate cpp = Predicates.compose(CardRulesPredicates.Presets.IS_SORCERY, PaperCard.FN_GET_RULES); cards = Lists.newArrayList(Iterables.filter(cards, cpp)); } if (StringUtils.containsIgnoreCase(valid, "instant")) { - Predicate cpp = Predicates.compose(CardRulesPredicates.Presets.IS_INSTANT, PaperCard.FN_GET_RULES); + final Predicate cpp = Predicates.compose(CardRulesPredicates.Presets.IS_INSTANT, PaperCard.FN_GET_RULES); cards = Lists.newArrayList(Iterables.filter(cards, cpp)); } if (sa.hasParam("RandomCopied")) { - List copysource = new ArrayList(cards); - CardCollection choice = new CardCollection(); + final List copysource = new ArrayList(cards); + final CardCollection choice = new CardCollection(); final String num = sa.hasParam("RandomNum") ? sa.getParam("RandomNum") : "1"; int ncopied = AbilityUtils.calculateAmount(source, num, sa); while(ncopied > 0) { final PaperCard cp = Aggregates.random(copysource); - Card possibleCard = Card.fromPaperCard(cp, null); + final Card possibleCard = Card.fromPaperCard(cp, null); // Need to temporarily set the Owner so the Game is set possibleCard.setOwner(sa.getActivatingPlayer()); - + if (possibleCard.isValid(valid, source.getController(), source)) { choice.add(possibleCard); copysource.remove(cp); @@ -134,31 +133,39 @@ public class PlayEffect extends SpellAbilityEffect { amount = tgtCards.size(); } - for (int i = 0; i < amount; i++) { + final CardCollection saidNoTo = new CardCollection(); + while (tgtCards.size() > saidNoTo.size() && amount > 0) { Card tgtCard = controller.getController().chooseSingleEntityForEffect(tgtCards, sa, "Select a card to play"); if (tgtCard == null) { return; } + final boolean wasFaceDown; if (tgtCard.isFaceDown()) { tgtCard.setState(CardStateName.Original, false); wasFaceDown = true; + } else { + wasFaceDown = false; } - - if (optional && !controller.getController().confirmAction(sa, null, "Do you want to play " + tgtCard + "?")) { - // i--; // This causes an infinite loop (ArsenalNut) + + if (optional && !controller.getController().confirmAction(sa, null, String.format("Do you want to play %s?", tgtCard))) { if (wasFaceDown) { tgtCard.setState(CardStateName.FaceDown, false); } + saidNoTo.add(tgtCard); continue; } + + tgtCards.remove(tgtCard); + if (wasFaceDown) { tgtCard.updateStateForView(); } if (sa.hasParam("ForgetRemembered")) { source.clearRemembered(); } - Card original = tgtCard; + + final Card original = tgtCard; if (sa.hasParam("CopyCard")) { final Zone zone = tgtCard.getZone(); tgtCard = Card.fromPaperCard(tgtCard.getPaperCard(), sa.getActivatingPlayer()); @@ -173,24 +180,30 @@ public class PlayEffect extends SpellAbilityEffect { tgtCard.setSVar("IsEncoded", "Number$1"); } } + if(sa.hasParam("SuspendCast")) { tgtCard.setSuspendCast(true); } + // lands will be played if (tgtCard.isLand()) { - if (controller.playLand(tgtCard, true) && remember) { - source.addRemembered(tgtCard); + if (controller.playLand(tgtCard, true)) { + amount--; + if (remember) { + source.addRemembered(tgtCard); + } + } else { + saidNoTo.add(tgtCard); } - tgtCards.remove(tgtCard); continue; } // get basic spells (no flashback, etc.) - List sas = AbilityUtils.getBasicSpellsFromPlayEffect(tgtCard, controller); + final List sas = AbilityUtils.getBasicSpellsFromPlayEffect(tgtCard, controller); if (sas.isEmpty()) { - return; + continue; } - tgtCards.remove(tgtCard); + // play copied cards with linked abilities, e.g. Elite Arcanist if (sa.hasParam("CopyOnce")) { tgtCards.remove(original); @@ -198,11 +211,11 @@ public class PlayEffect extends SpellAbilityEffect { // only one mode can be used SpellAbility tgtSA = sa.getActivatingPlayer().getController().getAbilityToPlay(tgtCard, sas); - boolean noManaCost = sa.hasParam("WithoutManaCost"); + final boolean noManaCost = sa.hasParam("WithoutManaCost"); if (noManaCost) { tgtSA = tgtSA.copyWithNoManaCost(); } else if (sa.hasParam("PlayMadness")) { - Cost abCost = new Cost(sa.getParam("PlayMadness"), false); + final Cost abCost = new Cost(sa.getParam("PlayMadness"), false); tgtSA = tgtSA.copyWithDefinedCost(abCost); tgtSA.getHostCard().setMadness(true); } @@ -210,13 +223,13 @@ public class PlayEffect extends SpellAbilityEffect { if (tgtSA.usesTargeting() && !optional) { tgtSA.getTargetRestrictions().setMandatory(true); } - - + remember &= controller.getController().playSaFromPlayEffect(tgtSA); if (remember) { source.addRemembered(tgtSA.getHostCard()); } - + + amount--; } } // end resolve diff --git a/forge-gui/res/cardsfolder/j/jace_architect_of_thought.txt b/forge-gui/res/cardsfolder/j/jace_architect_of_thought.txt index bc9230e214d..768d0eff385 100644 --- a/forge-gui/res/cardsfolder/j/jace_architect_of_thought.txt +++ b/forge-gui/res/cardsfolder/j/jace_architect_of_thought.txt @@ -9,10 +9,9 @@ A:AB$ Dig | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | DigNum$ 3 | Revea SVar:DBTwoPiles:DB$ TwoPiles | Defined$ You | DefinedCards$ Remembered | Separator$ Opponent | ChosenPile$ DBHand | UnchosenPile$ DBLibraryBottom SVar:DBHand:DB$ ChangeZone | Defined$ Remembered | Origin$ Library | Destination$ Hand SVar:DBLibraryBottom:DB$ ChangeZone | Defined$ Remembered | Origin$ Library | Destination$ Library | LibraryPosition$ -1 | SubAbility$ DBCleanup -A:AB$ ChangeZone | Cost$ SubCounter<8/LOYALTY> | Planeswalker$ True | Ultimate$ True | Origin$ Library | Destination$ Exile | DefinedPlayer$ Opponent | Chooser$ You | ChangeType$ Card.nonLand | ChangeNum$ 1 | RememberChanged$ True | Shuffle$ True | SubAbility$ JaceYourself | SpellDescription$ For each player, search that player's library for a nonland card and exile it, then that player shuffles his or her library. You may cast those cards without paying their mana costs. -SVar:JaceYourself:DB$ ChangeZone | Origin$ Library | Destination$ Exile | DefinedPlayer$ You | ChangeType$ Card.nonLand | ChangeNum$ 1 | RememberChanged$ True | Shuffle$ True | SubAbility$ DBPlayIT -SVar:DBPlayIT:DB$ Play | Defined$ Remembered | Amount$ Thoughts | References$ Thoughts | Controller$ You | WithoutManaCost$ True | Optional$ True | RememberPlayed$ True | SubAbility$ DBCleanup -SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:Thoughts:Remembered$Amount +A:AB$ RepeatEach | Cost$ SubCounter<8/LOYALTY> | Planeswalker$ True | Ultimate$ True | RepeatPlayers$ Each | RepeatSubAbility$ DBJaceExile | SubAbility$ DBPlayIt | SpellDescription$ For each player, search that player's library for a nonland card and exile it, then that player shuffles his or her library. You may cast those cards without paying their mana costs. +SVar:DBJaceExile:DB$ ChangeZone | Origin$ Library | Destination$ Exile | DefinedPlayer$ Remembered | Chooser$ You | ChangeType$ Card.nonLand | ChangeNum$ 1 | Imprint$ True | Shuffle$ True +SVar:DBPlayIt:DB$ Play | Defined$ Imprinted | Amount$ All | Controller$ You | WithoutManaCost$ True | Optional$ True | RememberPlayed$ True | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True SVar:Picture:http://www.wizards.com/global/images/magic/general/jace_architect_of_thought.jpg Oracle:[+1] Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn.\n[-2] Reveal the top three cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other on the bottom of your library in any order.\n[-8] For each player, search that player's library for a nonland card and exile it, then that player shuffles his or her library. You may cast those cards without paying their mana costs.