diff --git a/forge-game/src/main/java/forge/game/ForgeScript.java b/forge-game/src/main/java/forge/game/ForgeScript.java index 1bf735a42d4..f21d1155fbd 100644 --- a/forge-game/src/main/java/forge/game/ForgeScript.java +++ b/forge-game/src/main/java/forge/game/ForgeScript.java @@ -168,6 +168,8 @@ public class ForgeScript { return found; } else if (property.equals("YouCtrl")) { return sa.getActivatingPlayer().equals(sourceController); + } else if (property.equals("OppCtrl")) { + return sa.getActivatingPlayer().isOpponentOf(sourceController); } else if (sa.getHostCard() != null) { return sa.getHostCard().hasProperty(property, sourceController, source, spellAbility); } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 7a304c73418..6cdb3d3992c 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -1279,6 +1279,8 @@ public class AbilityUtils { if (o instanceof Card) { final Card rem = (Card) o; sas.addAll(game.getCardState(rem).getSpellAbilities()); + } else if (o instanceof SpellAbility) { + sas.add((SpellAbility) o); } } } @@ -1836,6 +1838,11 @@ public class AbilityUtils { } else if (def.endsWith("Owner")) { players.add(c.getOwner()); } + } else if (o instanceof SpellAbility) { + final SpellAbility c = (SpellAbility) o; + if (def.endsWith("Controller")) { + players.add(c.getHostCard().getController()); + } } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java index fa834da87b2..e7ed46e2b1e 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java @@ -11,6 +11,7 @@ import forge.game.card.*; import forge.game.player.Player; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; +import forge.game.spellability.SpellAbilityStackInstance; import forge.game.zone.ZoneType; import forge.util.Aggregates; import forge.util.collect.FCollection; @@ -47,6 +48,7 @@ public class RepeatEachEffect extends SpellAbilityEffect { boolean loopOverCards = false; boolean recordChoice = sa.hasParam("RecordChoice"); CardCollectionView repeatCards = null; + List repeatSas = null; if (sa.hasParam("RepeatCards")) { List zone = Lists.newArrayList(); @@ -59,6 +61,16 @@ public class RepeatEachEffect extends SpellAbilityEffect { sa.getParam("RepeatCards"), source.getController(), source); loopOverCards = !recordChoice; } + else if (sa.hasParam(("RepeatSpellAbilities"))) { + repeatSas = Lists.newArrayList(); + String[] restrictions = sa.getParam("RepeatSpellAbilities").split((",")); + for (SpellAbilityStackInstance stackInstance : game.getStack()) { + if (stackInstance.getSpellAbility(false).isValid(restrictions, source.getController(), source, sa)) { + repeatSas.add(stackInstance.getSpellAbility(false)); + } + } + + } else if (sa.hasParam("DefinedCards")) { repeatCards = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa); if (sa.hasParam("AdditionalRestriction")) { // lki cards might not be in game @@ -110,6 +122,13 @@ public class RepeatEachEffect extends SpellAbilityEffect { } } } + if (repeatSas != null) { + for (SpellAbility card : repeatSas) { + source.addRemembered(card); + AbilityUtils.resolve(repeat); + source.removeRemembered(card); + } + } if (sa.hasParam("RepeatPlayers")) { final FCollection repeatPlayers = AbilityUtils.getDefinedPlayers(source, sa.getParam("RepeatPlayers"), sa); diff --git a/forge-gui/res/cardsfolder/upcoming/whirlwind_denial.txt b/forge-gui/res/cardsfolder/upcoming/whirlwind_denial.txt new file mode 100644 index 00000000000..1bceaf63af6 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/whirlwind_denial.txt @@ -0,0 +1,7 @@ +Name:Whirlwind Denial +ManaCost:2 U +Types:Instant +A:SP$ RepeatEach | Cost$ 2 U | RepeatSpellAbilities$ Card.OppCtrl,Spell.OppCtrl,Activated.OppCtrl,Triggered.OppCtrl | Zone$ Stack | RepeatSubAbility$ DBCounterUnless | SpellDescription$ For each spell and ability your opponents control, counter it unless its controller pays {4}. +SVar:DBCounterUnless:DB$ Counter | Defined$ Remembered | UnlessCost$ 4 | UnlessPayer$ RememberedController | StackDescription$ Counter {c:Remembered} +SVar:Picture:https://img.scryfall.com/cards/png/front/9/e/9e127856-bedd-40a9-9e8e-d1f9fbefe07d.png?1578326880 +Oracle:For each spell and ability your opponents control, counter it unless its controller pays {4}.