diff --git a/forge-game/src/main/java/forge/game/ability/AbilityKey.java b/forge-game/src/main/java/forge/game/ability/AbilityKey.java index fce9790c488..0db9ccaa4bc 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityKey.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityKey.java @@ -118,6 +118,7 @@ public enum AbilityKey { ScryBottom("ScryBottom"), ScryNum("ScryNum"), Sides("Sides"), + SimultaneousETB("SimultaneousETB"), Source("Source"), Sources("Sources"), SourceSA("SourceSA"), diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java index 473e80a7b22..6be096854f7 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java @@ -107,8 +107,6 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect { } } - cards = (CardCollection)AbilityUtils.filterListByType(cards, sa.getParam("ChangeType"), sa); - if (sa.hasParam("Optional")) { final String targets = Lang.joinHomogenous(cards); final String message; @@ -123,6 +121,12 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect { } } + cards = (CardCollection)AbilityUtils.filterListByType(cards, sa.getParam("ChangeType"), sa); + + if (sa.hasParam("TypeLimit")) { + cards = new CardCollection(Iterables.limit(cards, AbilityUtils.calculateAmount(source, sa.getParam("TypeLimit"), sa))); + } + if (sa.hasParam("ForgetOtherRemembered")) { source.clearRemembered(); } @@ -171,6 +175,7 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect { moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); if (destination == ZoneType.Battlefield) { + moveParams.put(AbilityKey.SimultaneousETB, cards); if (sa.hasAdditionalAbility("AnimateSubAbility")) { // need LKI before Animate does apply moveParams.put(AbilityKey.CardLKI, CardUtil.getLKICopy(c)); 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 f36dabc0e18..97b9d495bb8 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 @@ -573,195 +573,194 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } movedCard = game.getAction().moveToLibrary(gameCard, libraryPosition, sa); - } else { - if (destination.equals(ZoneType.Battlefield)) { - Map moveParams = AbilityKey.newMap(); - moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); - moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); - if (sa.isReplacementAbility()) { - ReplacementEffect re = sa.getReplacementEffect(); - moveParams.put(AbilityKey.ReplacementEffect, re); - if (ReplacementType.Moved.equals(re.getMode()) && sa.getReplacingObject(AbilityKey.CardLKI) != null) { - moveParams.put(AbilityKey.CardLKI, sa.getReplacingObject(AbilityKey.CardLKI)); - } + } else if (destination.equals(ZoneType.Battlefield)) { + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); + moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); + moveParams.put(AbilityKey.SimultaneousETB, tgtCards); + if (sa.isReplacementAbility()) { + ReplacementEffect re = sa.getReplacementEffect(); + moveParams.put(AbilityKey.ReplacementEffect, re); + if (ReplacementType.Moved.equals(re.getMode()) && sa.getReplacingObject(AbilityKey.CardLKI) != null) { + moveParams.put(AbilityKey.CardLKI, sa.getReplacingObject(AbilityKey.CardLKI)); } + } - if (sa.hasParam("Tapped") || sa.isNinjutsu()) { - gameCard.setTapped(true); - } - if (sa.hasParam("Transformed")) { - if (gameCard.isTransformable()) { - // need LKI before Animate does apply - if (!moveParams.containsKey(AbilityKey.CardLKI)) { - moveParams.put(AbilityKey.CardLKI, CardUtil.getLKICopy(gameCard)); - } - gameCard.changeCardState("Transform", null, sa); - } else { - // If it can't Transform, don't change zones. - continue; - } - } - if (sa.hasParam("WithCountersType")) { - CounterType cType = CounterType.getType(sa.getParam("WithCountersType")); - int cAmount = AbilityUtils.calculateAmount(hostCard, sa.getParamOrDefault("WithCountersAmount", "1"), sa); - gameCard.addEtbCounter(cType, cAmount, player); - } - if (sa.hasParam("GainControl")) { - final String g = sa.getParam("GainControl"); - Player newController = g.equals("True") ? player : - AbilityUtils.getDefinedPlayers(hostCard, g, sa).get(0); - if (newController != null) { - if (newController != gameCard.getController()) { - gameCard.runChangeControllerCommands(); - } - gameCard.setController(newController, game.getNextTimestamp()); - } - } - if (sa.hasParam("AttachedTo")) { - CardCollection list = AbilityUtils.getDefinedCards(hostCard, sa.getParam("AttachedTo"), sa); - if (list.isEmpty()) { - list = CardLists.getValidCards(lastStateBattlefield, sa.getParam("AttachedTo"), hostCard.getController(), hostCard, sa); - } - - // only valid choices are when they could be attached - // TODO for multiple Auras entering attached this way, need to use LKI info - if (!list.isEmpty()) { - list = CardLists.filter(list, CardPredicates.canBeAttached(gameCard, sa)); - } - if (!list.isEmpty()) { - Map params = Maps.newHashMap(); - params.put("Attach", gameCard); - Card attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", gameCard.toString()), params); - - // TODO can't attach later or moveToPlay would attach indirectly - // bypass canBeAttached to skip Protection checks when trying to attach multiple auras that would grant protection - gameCard.attachToEntity(game.getCardState(attachedTo), sa, true); - } else { // When it should enter the battlefield attached to an illegal permanent it fails - continue; - } - } - - if (sa.hasParam("AttachedToPlayer")) { - FCollectionView list = AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("AttachedToPlayer"), sa); - if (!list.isEmpty()) { - Map params = Maps.newHashMap(); - params.put("Attach", gameCard); - Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", gameCard.toString()), params); - gameCard.attachToEntity(attachedTo, sa); - } - else { // When it should enter the battlefield attached to an illegal player it fails - continue; - } - } - - if (sa.hasAdditionalAbility("AnimateSubAbility")) { + if (sa.hasParam("Tapped") || sa.isNinjutsu()) { + gameCard.setTapped(true); + } + if (sa.hasParam("Transformed")) { + if (gameCard.isTransformable()) { // need LKI before Animate does apply if (!moveParams.containsKey(AbilityKey.CardLKI)) { moveParams.put(AbilityKey.CardLKI, CardUtil.getLKICopy(gameCard)); } - - final SpellAbility animate = sa.getAdditionalAbility("AnimateSubAbility"); - hostCard.addRemembered(gameCard); - AbilityUtils.resolve(animate); - hostCard.removeRemembered(gameCard); - animate.setSVar("unanimateTimestamp", String.valueOf(game.getTimestamp())); - } - - // need to be facedown before it hits the battlefield in case of Replacement Effects or Trigger - if (sa.hasParam("FaceDown")) { - gameCard.turnFaceDown(true); - CardFactoryUtil.setFaceDownState(gameCard, sa); - } - - movedCard = game.getAction().moveTo(gameCard.getController().getZone(destination), gameCard, sa, moveParams); - // below stuff only if it changed zones - if (movedCard.getZone().equals(originZone)) { + gameCard.changeCardState("Transform", null, sa); + } else { + // If it can't Transform, don't change zones. continue; } - if (sa.hasParam("Unearth") && movedCard.isInPlay()) { - movedCard.setUnearthed(true); - movedCard.addChangedCardKeywords(Lists.newArrayList("Haste"), null, false, - game.getNextTimestamp(), 0, true); - registerDelayedTrigger(sa, "Exile", Lists.newArrayList(movedCard)); - addLeaveBattlefieldReplacement(movedCard, sa, "Exile"); - } - if (sa.hasParam("LeaveBattlefield")) { - addLeaveBattlefieldReplacement(movedCard, sa, sa.getParam("LeaveBattlefield")); - } - if (addToCombat(movedCard, movedCard.getController(), sa, "Attacking", "Blocking")) { - combatChanged = true; - } - if (sa.isNinjutsu()) { - // Ninjutsu need to get the Defender of the Returned Creature - final Card returned = sa.getPaidList("Returned", true).getFirst(); - final GameEntity defender = game.getCombat().getDefenderByAttacker(returned); - game.getCombat().addAttacker(movedCard, defender); - game.getCombat().getBandOfAttacker(movedCard).setBlocked(false); - combatChanged = true; - } - - if (sa.hasParam("AttachAfter") && movedCard.isAttachment()) { - CardCollection list = AbilityUtils.getDefinedCards(hostCard, sa.getParam("AttachAfter"), sa); - if (list.isEmpty()) { - list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("AttachAfter"), hostCard.getController(), hostCard, sa); - } - if (!list.isEmpty()) { - String title = Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(gameCard.getName())); - Map params = Maps.newHashMap(); - params.put("Attach", gameCard); - Card attachedTo = chooser.getController().chooseSingleEntityForEffect(list, sa, title, params); - movedCard.attachToEntity(attachedTo, sa); + } + if (sa.hasParam("WithCountersType")) { + CounterType cType = CounterType.getType(sa.getParam("WithCountersType")); + int cAmount = AbilityUtils.calculateAmount(hostCard, sa.getParamOrDefault("WithCountersAmount", "1"), sa); + gameCard.addEtbCounter(cType, cAmount, player); + } + if (sa.hasParam("GainControl")) { + final String g = sa.getParam("GainControl"); + Player newController = g.equals("True") ? player : + AbilityUtils.getDefinedPlayers(hostCard, g, sa).get(0); + if (newController != null) { + if (newController != gameCard.getController()) { + gameCard.runChangeControllerCommands(); } + gameCard.setController(newController, game.getNextTimestamp()); } - } else { - // might set before card is moved only for nontoken - if (destination.equals(ZoneType.Exile)) { - handleExiledWith(gameCard, sa); + } + if (sa.hasParam("AttachedTo")) { + CardCollection list = AbilityUtils.getDefinedCards(hostCard, sa.getParam("AttachedTo"), sa); + if (list.isEmpty()) { + list = CardLists.getValidCards(lastStateBattlefield, sa.getParam("AttachedTo"), hostCard.getController(), hostCard, sa); } - Map moveParams = AbilityKey.newMap(); - moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); - moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); - movedCard = game.getAction().moveTo(destination, gameCard, sa, moveParams); + // only valid choices are when they could be attached + // TODO for multiple Auras entering attached this way, need to use LKI info + if (!list.isEmpty()) { + list = CardLists.filter(list, CardPredicates.canBeAttached(gameCard, sa)); + } + if (!list.isEmpty()) { + Map params = Maps.newHashMap(); + params.put("Attach", gameCard); + Card attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", gameCard.toString()), params); - if (ZoneType.Hand.equals(destination) && ZoneType.Command.equals(originZone.getZoneType())) { - StringBuilder sb = new StringBuilder(); - sb.append(movedCard.getName()).append(" has moved from Command Zone to ").append(player).append("'s hand."); - game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString()); - commandCards.add(movedCard); //add to list to reveal the commandzone cards + // TODO can't attach later or moveToPlay would attach indirectly + // bypass canBeAttached to skip Protection checks when trying to attach multiple auras that would grant protection + gameCard.attachToEntity(game.getCardState(attachedTo), sa, true); + } else { // When it should enter the battlefield attached to an illegal permanent it fails + continue; + } + } + + if (sa.hasParam("AttachedToPlayer")) { + FCollectionView list = AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("AttachedToPlayer"), sa); + if (!list.isEmpty()) { + Map params = Maps.newHashMap(); + params.put("Attach", gameCard); + Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", gameCard.toString()), params); + gameCard.attachToEntity(attachedTo, sa); + } + else { // When it should enter the battlefield attached to an illegal player it fails + continue; + } + } + + if (sa.hasAdditionalAbility("AnimateSubAbility")) { + // need LKI before Animate does apply + if (!moveParams.containsKey(AbilityKey.CardLKI)) { + moveParams.put(AbilityKey.CardLKI, CardUtil.getLKICopy(gameCard)); } - // If a card is Exiled from the stack, remove its spells from the stack - if (sa.hasParam("Fizzle")) { - if (gameCard.isInZone(ZoneType.Exile) || gameCard.isInZone(ZoneType.Hand) - || gameCard.isInZone(ZoneType.Stack) || gameCard.isInZone(ZoneType.Command)) { - // This only fizzles spells, not anything else. - game.getStack().remove(gameCard); - } - } + final SpellAbility animate = sa.getAdditionalAbility("AnimateSubAbility"); + hostCard.addRemembered(gameCard); + AbilityUtils.resolve(animate); + hostCard.removeRemembered(gameCard); + animate.setSVar("unanimateTimestamp", String.valueOf(game.getTimestamp())); + } - if (sa.hasParam("WithCountersType")) { - CounterType cType = CounterType.getType(sa.getParam("WithCountersType")); - int cAmount = AbilityUtils.calculateAmount(hostCard, sa.getParamOrDefault("WithCountersAmount", "1"), sa); - movedCard.addCounter(cType, cAmount, player, counterTable); - } + // need to be facedown before it hits the battlefield in case of Replacement Effects or Trigger + if (sa.hasParam("FaceDown")) { + gameCard.turnFaceDown(true); + CardFactoryUtil.setFaceDownState(gameCard, sa); + } - if (sa.hasParam("ExileFaceDown") || sa.hasParam("FaceDown")) { - movedCard.turnFaceDown(true); - } - if (sa.hasParam("Foretold")) { - movedCard.setForetold(true); - movedCard.setForetoldThisTurn(true); - if (sa.hasParam("ForetoldCost")) { - movedCard.setForetoldCostByEffect(true); - } - // look at the exiled card - movedCard.addMayLookTemp(player); - } + movedCard = game.getAction().moveTo(gameCard.getController().getZone(destination), gameCard, sa, moveParams); + // below stuff only if it changed zones + if (movedCard.getZone().equals(originZone)) { + continue; + } + if (sa.hasParam("Unearth") && movedCard.isInPlay()) { + movedCard.setUnearthed(true); + movedCard.addChangedCardKeywords(Lists.newArrayList("Haste"), null, false, + game.getNextTimestamp(), 0, true); + registerDelayedTrigger(sa, "Exile", Lists.newArrayList(movedCard)); + addLeaveBattlefieldReplacement(movedCard, sa, "Exile"); + } + if (sa.hasParam("LeaveBattlefield")) { + addLeaveBattlefieldReplacement(movedCard, sa, sa.getParam("LeaveBattlefield")); + } + if (addToCombat(movedCard, movedCard.getController(), sa, "Attacking", "Blocking")) { + combatChanged = true; + } + if (sa.isNinjutsu()) { + // Ninjutsu need to get the Defender of the Returned Creature + final Card returned = sa.getPaidList("Returned", true).getFirst(); + final GameEntity defender = game.getCombat().getDefenderByAttacker(returned); + game.getCombat().addAttacker(movedCard, defender); + game.getCombat().getBandOfAttacker(movedCard).setBlocked(false); + combatChanged = true; + } - if (sa.hasParam("TrackDiscarded")) { - movedCard.setDiscarded(true); + if (sa.hasParam("AttachAfter") && movedCard.isAttachment()) { + CardCollection list = AbilityUtils.getDefinedCards(hostCard, sa.getParam("AttachAfter"), sa); + if (list.isEmpty()) { + list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("AttachAfter"), hostCard.getController(), hostCard, sa); } + if (!list.isEmpty()) { + String title = Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(gameCard.getName())); + Map params = Maps.newHashMap(); + params.put("Attach", gameCard); + Card attachedTo = chooser.getController().chooseSingleEntityForEffect(list, sa, title, params); + movedCard.attachToEntity(attachedTo, sa); + } + } + } else { + // might set before card is moved only for nontoken + if (destination.equals(ZoneType.Exile)) { + handleExiledWith(gameCard, sa); + } + + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); + moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); + movedCard = game.getAction().moveTo(destination, gameCard, sa, moveParams); + + if (ZoneType.Hand.equals(destination) && ZoneType.Command.equals(originZone.getZoneType())) { + StringBuilder sb = new StringBuilder(); + sb.append(movedCard.getName()).append(" has moved from Command Zone to ").append(player).append("'s hand."); + game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString()); + commandCards.add(movedCard); //add to list to reveal the commandzone cards + } + + // If a card is Exiled from the stack, remove its spells from the stack + if (sa.hasParam("Fizzle")) { + if (gameCard.isInZone(ZoneType.Exile) || gameCard.isInZone(ZoneType.Hand) + || gameCard.isInZone(ZoneType.Stack) || gameCard.isInZone(ZoneType.Command)) { + // This only fizzles spells, not anything else. + game.getStack().remove(gameCard); + } + } + + if (sa.hasParam("WithCountersType")) { + CounterType cType = CounterType.getType(sa.getParam("WithCountersType")); + int cAmount = AbilityUtils.calculateAmount(hostCard, sa.getParamOrDefault("WithCountersAmount", "1"), sa); + movedCard.addCounter(cType, cAmount, player, counterTable); + } + + if (sa.hasParam("ExileFaceDown") || sa.hasParam("FaceDown")) { + movedCard.turnFaceDown(true); + } + if (sa.hasParam("Foretold")) { + movedCard.setForetold(true); + movedCard.setForetoldThisTurn(true); + if (sa.hasParam("ForetoldCost")) { + movedCard.setForetoldCostByEffect(true); + } + // look at the exiled card + movedCard.addMayLookTemp(player); + } + + if (sa.hasParam("TrackDiscarded")) { + movedCard.setDiscarded(true); } } if (!movedCard.getZone().equals(originZone)) { @@ -1305,6 +1304,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { movedCard = game.getAction().moveToLibrary(c, libraryPos, sa, moveParams); } else if (destination.equals(ZoneType.Battlefield)) { + moveParams.put(AbilityKey.SimultaneousETB, chosenCards); if (sa.hasParam("Tapped")) { c.setTapped(true); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java index 442b52a6c4f..779c15da4d8 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java @@ -398,10 +398,13 @@ public class DigEffect extends SpellAbilityEffect { if (sa.hasParam("Tapped")) { c.setTapped(true); } - if (destZone1.equals(ZoneType.Battlefield) && sa.hasParam("WithCounter")) { - final int numCtr = AbilityUtils.calculateAmount(host, - sa.getParamOrDefault("WithCounterNum", "1"), sa); - c.addEtbCounter(CounterType.getType(sa.getParam("WithCounter")), numCtr, player); + if (destZone1.equals(ZoneType.Battlefield)) { + moveParams.put(AbilityKey.SimultaneousETB, movedCards); + if (sa.hasParam("WithCounter")) { + final int numCtr = AbilityUtils.calculateAmount(host, + sa.getParamOrDefault("WithCounterNum", "1"), sa); + c.addEtbCounter(CounterType.getType(sa.getParam("WithCounter")), numCtr, player); + } } if (sa.hasAdditionalAbility("AnimateSubAbility")) { // need LKI before Animate does apply @@ -477,8 +480,7 @@ public class DigEffect extends SpellAbilityEffect { } } else { // just move them randomly - for (int i = 0; i < rest.size(); i++) { - Card c = rest.get(i); + for (Card c : rest) { final ZoneType origin = c.getZone().getZoneType(); final PlayerZone toZone = c.getOwner().getZone(destZone2); c = game.getAction().moveTo(toZone, c, sa); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java index 35c51a6bb08..e31e6f9670c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java @@ -99,11 +99,6 @@ public class DigUntilEffect extends SpellAbilityEffect { final Card host = sa.getHostCard(); final Game game = host.getGame(); - String[] type = new String[]{"Card"}; - if (sa.hasParam("Valid")) { - type = sa.getParam("Valid").split(","); - } - int untilAmount = 1; if (sa.hasParam("Amount")) { untilAmount = AbilityUtils.calculateAmount(host, sa.getParam("Amount"), sa); @@ -115,6 +110,11 @@ public class DigUntilEffect extends SpellAbilityEffect { maxRevealed = AbilityUtils.calculateAmount(host, sa.getParam("MaxRevealed"), sa); } + String[] type = new String[]{"Card"}; + if (sa.hasParam("Valid")) { + type = sa.getParam("Valid").split(","); + } + final boolean remember = sa.hasParam("RememberFound"); final boolean imprint = sa.hasParam("ImprintFound"); @@ -210,6 +210,7 @@ public class DigUntilEffect extends SpellAbilityEffect { moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); Card m = null; if (foundDest.equals(ZoneType.Battlefield)) { + moveParams.put(AbilityKey.SimultaneousETB, new CardCollection(c)); if (sa.hasParam("GainControl")) { c.setController(sa.getActivatingPlayer(), game.getNextTimestamp()); } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java index 72b823a035d..d58eabb666e 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java @@ -312,6 +312,7 @@ public class ReplacementHandler { replacementEffect.setReplacingObjects(runParams, tailend); //set original Params to update them later tailend.setReplacingObject(AbilityKey.OriginalParams, runParams); + tailend.setReplacingObjectsFrom(runParams, AbilityKey.SimultaneousETB); tailend = tailend.getSubAbility(); } while(tailend != null); diff --git a/forge-gui/res/cardsfolder/upcoming/ashiok_wicked_manipulator.txt b/forge-gui/res/cardsfolder/upcoming/ashiok_wicked_manipulator.txt index 181c94d6b0e..601877baf74 100644 --- a/forge-gui/res/cardsfolder/upcoming/ashiok_wicked_manipulator.txt +++ b/forge-gui/res/cardsfolder/upcoming/ashiok_wicked_manipulator.txt @@ -3,12 +3,12 @@ ManaCost:3 B B Types:Legendary Planeswalker Ashiok Loyalty:5 R:Event$ PayLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ ExileTop | Amount$ LEY | Description$ If you would pay life while your library has at least that many cards in it, exile that many cards from the top of your library instead. -SVar:ExileTop:DB$ Dig | DigNum$ X | ChangeNum$ All | DestinationZone$ Exile +SVar:ExileTop:DB$ ChangeZoneAll | TypeLimit$ X | ChangeType$ Card.NotDefinedReplacedSimultaneousETB | Defined$ You | Origin$ Library | Destination$ Exile SVar:X:ReplaceCount$Amount -SVar:Y:Count$ValidLibrary Card +SVar:Y:Count$ValidLibrary Card.YouOwn A:AB$ Dig | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | DigNum$ 2 | ChangeNum$ 1 | DestinationZone2$ Exile | NoReveal$ True | SpellDescription$ Look at the top two cards of your library. Exile one of them and put the other into your hand. A:AB$ Token | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | TokenAmount$ 2 | TokenScript$ b_1_1_nightmare_exile_counter | TokenOwner$ You | SpellDescription$ Create two 1/1 black Nightmare creature tokens with "At the beginning of combat on your turn, if a card was put into exile this turn, put a +1/+1 counter on this creature." -A:AB$ Discard | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Player | NumCards$ Z | Mode$ TgtChoose | SpellDescription$ Target player exiles the top X cards of their library, where X is the total mana value of cards you own in exile. +A:AB$ Dig | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Player | DigNum$ Z | ChangeNum$ All | DestinationZone$ Exile | SpellDescription$ Target player exiles the top X cards of their library, where X is the total mana value of cards you own in exile. SVar:Z:Count$ValidExile Card.YouOwn$SumCMC AI:RemoveDeck:Random Oracle:If you would pay life while your library has at least that many cards in it, exile that many cards from the top of your library instead.\n+1: Look at the top two cards of your library. Exile one of them and put the other into your hand.\n−2: Create two 1/1 black Nightmare creature tokens with "At the beginning of combat on your turn, if a card was put into exile this turn, put a +1/+1 counter on this creature."\n−7: Target player exiles the top X cards of their library, where X is the total mana value of cards you own in exile.