diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java index cfbf00d4232..9bf9d3eb09d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java @@ -24,6 +24,7 @@ public class AnimateEffect extends AnimateEffectBase { final Card source = sa.getHostCard(); String animateRemembered = null; + String animateImprinted = null; //if host is not on the battlefield don't apply if ((sa.hasParam("UntilHostLeavesPlay") || sa.hasParam("UntilLoseControlOfHost")) @@ -35,6 +36,10 @@ public class AnimateEffect extends AnimateEffectBase { if (sa.hasParam("RememberObjects")) { animateRemembered = sa.getParam("RememberObjects"); } + // Imprint Cards + if (sa.hasParam("ImprintCards")) { + animateImprinted = sa.getParam("ImprintCards"); + } // AF specific sa Integer power = null; @@ -162,6 +167,18 @@ public class AnimateEffect extends AnimateEffectBase { } } + // give Imprinted + if (animateImprinted != null) { + for (final Card imprintedCard : AbilityUtils.getDefinedCards(source, animateImprinted, sa)) { + c.addImprintedCard(imprintedCard); + } + } + + // Restore immutable to effect + if (sa.hasParam("Immutable")) { + c.setImmutable(true); + } + game.fireEvent(new GameEventCardStatsChanged(c)); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java b/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java index 308971adf7a..1df70724937 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java @@ -140,6 +140,10 @@ public class EffectEffect extends SpellAbilityEffect { final Card eff = createEffect(sa, controller, name, image); eff.setSetCode(sa.getHostCard().getSetCode()); eff.setRarity(sa.getHostCard().getRarity()); + // For Raging River effect to add attacker "left" or "right" pile later + if (sa.hasParam("Mutable")) { + eff.setImmutable(false); + } // Abilities and triggers work the same as they do for Token // Grant abilities diff --git a/forge-game/src/main/java/forge/game/ability/effects/TwoPilesEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TwoPilesEffect.java index ddf0fe0f741..1bcd140cd0b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TwoPilesEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TwoPilesEffect.java @@ -13,6 +13,7 @@ import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; +import forge.util.Lang; import forge.util.Localizer; public class TwoPilesEffect extends SpellAbilityEffect { @@ -52,6 +53,7 @@ public class TwoPilesEffect extends SpellAbilityEffect { final Card card = sa.getHostCard(); ZoneType zone = null; boolean pile1WasChosen = true; + boolean isLeftRightPile = sa.hasParam("LeftRightPile"); if (sa.hasParam("Zone")) { zone = ZoneType.smartValueOf(sa.getParam("Zone")); @@ -89,8 +91,14 @@ public class TwoPilesEffect extends SpellAbilityEffect { return; } - String title = "One".equals(sa.getParamOrDefault("FaceDown", "False")) ? Localizer.getInstance().getMessage("lblSelectCardForFaceDownPile") : - Localizer.getInstance().getMessage("lblDivideCardIntoTwoPiles"); + String title; + if("One".equals(sa.getParamOrDefault("FaceDown", "False"))) { + title = Localizer.getInstance().getMessage("lblSelectCardForFaceDownPile"); + } else if (isLeftRightPile) { + title = Localizer.getInstance().getMessage("lblSelectCardForLeftPile"); + } else { + title = Localizer.getInstance().getMessage("lblDivideCardIntoTwoPiles"); + } card.clearRemembered(); @@ -103,20 +111,49 @@ public class TwoPilesEffect extends SpellAbilityEffect { //System.out.println("Pile 2:" + pile2); - pile1WasChosen = chooser.getController().chooseCardsPile(sa, pile1, pile2, sa.getParamOrDefault("FaceDown", "False")); + if (isLeftRightPile) { + pile1WasChosen = true; + } else { + pile1WasChosen = chooser.getController().chooseCardsPile(sa, pile1, pile2, sa.getParamOrDefault("FaceDown", "False")); + } CardCollectionView chosenPile = pile1WasChosen ? pile1 : pile2; CardCollectionView unchosenPile = !pile1WasChosen ? pile1 : pile2; - StringBuilder notification = new StringBuilder(chooser + " " + Localizer.getInstance().getMessage("lblChoosesPile") + " " + (pile1WasChosen ? "1" : "2") + ":\n"); - if (!chosenPile.isEmpty()) { - for (Card c : chosenPile) { - notification.append(c.getName()).append("\n"); + StringBuilder notification = new StringBuilder(); + if (isLeftRightPile) { + notification.append("\n"); + notification.append(Lang.getInstance().getPossessedObject(separator.getName(), Localizer.getInstance().getMessage("lblLeftPile"))); + notification.append("\n--------------------\n"); + if (!chosenPile.isEmpty()) { + for (Card c : chosenPile) { + notification.append(c.getName()).append("\n"); + } + } else { + notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")\n"); } + notification.append("\n"); + notification.append(Lang.getInstance().getPossessedObject(separator.getName(), Localizer.getInstance().getMessage("lblRightPile"))); + notification.append("\n--------------------\n"); + if (!unchosenPile.isEmpty()) { + for (Card c : unchosenPile) { + notification.append(c.getName()).append("\n"); + } + } else { + notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")\n"); + } + p.getGame().getAction().notifyOfValue(sa, separator, notification.toString(), separator); } else { - notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")"); + notification.append(chooser + " " + Localizer.getInstance().getMessage("lblChoosesPile") + " " + (pile1WasChosen ? "1" : "2") + ":\n"); + if (!chosenPile.isEmpty()) { + for (Card c : chosenPile) { + notification.append(c.getName()).append("\n"); + } + } else { + notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")"); + } + p.getGame().getAction().notifyOfValue(sa, chooser, notification.toString(), chooser); } - p.getGame().getAction().notifyOfValue(sa, chooser, notification.toString(), chooser); // take action on the chosen pile if (sa.hasParam("ChosenPile")) { diff --git a/forge-gui/res/cardsfolder/r/raging_river.txt b/forge-gui/res/cardsfolder/r/raging_river.txt new file mode 100644 index 00000000000..17d4c626219 --- /dev/null +++ b/forge-gui/res/cardsfolder/r/raging_river.txt @@ -0,0 +1,20 @@ +Name:Raging River +ManaCost:R R +Types:Enchantment +T:Mode$ AttackersDeclared | AttackingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRepeatDefender | TriggerDescription$ Whenever one or more creatures you control attack, each defending player divides all creatures without flying they control into a "left" pile and a "right" pile. Then, for each attacking creature you control, choose "left" or "right." That creature can't be blocked this combat except by creatures with flying and creatures in a pile with the chosen label. +SVar:TrigRepeatDefender:DB$ RepeatEach | RepeatPlayers$ TriggeredAttackedTarget | RepeatSubAbility$ DBDefLeftEffect | SubAbility$ DBAtkLeftRight +SVar:DBDefLeftEffect:DB$ Effect | EffectOwner$ Remembered | Name$ Raging River Left | StaticAbilities$ DBCantBlock | ImprintOnHost$ True | Mutable$ True | Duration$ UntilEndOfCombat | SubAbility$ DBDefRightEffect +SVar:DBDefRightEffect:DB$ Effect | EffectOwner$ Remembered | Name$ Raging River Right | StaticAbilities$ DBCantBlock | ImprintOnHost$ True | Mutable$ True | Duration$ UntilEndOfCombat | SubAbility$ DBDefLeftRight +SVar:DBCantBlock:Mode$ CantBlockBy | ValidAttacker$ Creature.IsRemembered | ValidBlocker$ Creature.withoutFlying+IsNotImprinted+YouCtrl | EffectZone$ Command +SVar:DBDefLeftRight:DB$ TwoPiles | Defined$ Remembered | Separator$ Remembered | ValidCards$ Creature.withoutFlying+RememberedPlayerCtrl | Zone$ Battlefield | LeftRightPile$ True | ChosenPile$ DBDefLeftPile | UnchosenPile$ DBDefRightPile | AILogic$ Random | SubAbility$ DBClearImprinted +SVar:DBDefLeftPile:DB$ Animate | Defined$ Imprinted.namedRaging River Left | ImprintCards$ Remembered | Permanent$ True | SubAbility$ DBLeftPump +SVar:DBDefRightPile:DB$ Animate | Defined$ Imprinted.namedRaging River Right | ImprintCards$ Remembered | Permanent$ True | SubAbility$ DBRightPump +SVar:DBClearImprinted:DB$ Cleanup | ClearImprinted$ True +SVar:DBAtkLeftRight:DB$ TwoPiles | Defined$ You | Separator$ You | ValidCards$ Creature.attacking+YouCtrl | Zone$ Battlefield | LeftRightPile$ True | ChosenPile$ DBAtkLeftPile | UnchosenPile$ DBAtkRightPile | AILogic$ Random | SubAbility$ DBCleanup +SVar:DBAtkLeftPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Left | RememberObjects$ RememberedCard | Permanent$ True | Immutable$ True | SubAbility$ DBLeftPump +SVar:DBAtkRightPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Right | RememberObjects$ RememberedCard | Permanent$ True | Immutable$ True | SubAbility$ DBRightPump +SVar:DBLeftPump:DB$ Pump | Defined$ Remembered | KW$ "Left" pile | UntilEndOfCombat$ True +SVar:DBRightPump:DB$ Pump | Defined$ Remembered | KW$ "Right" pile | UntilEndOfCombat$ True +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:PlayMain1:TRUE +Oracle:Whenever one or more creatures you control attack, each defending player divides all creatures without flying they control into a "left" pile and a "right" pile. Then, for each attacking creature you control, choose "left" or "right." That creature can't be blocked this combat except by creatures with flying and creatures in a pile with the chosen label. diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index a0fd0565be7..ccad7624aec 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -1933,6 +1933,9 @@ lblTapOrUntapTarget=Tappe oder enttappe {0}? #TwoPilesEffect.java lblSelectCardForFaceDownPile=Wähle Karten für einen verdeckten Stapel lblDivideCardIntoTwoPiles=Teile die Karten in zwei Stapel auf +lblSelectCardForLeftPile=Select cards for the left pile +lblLeftPile=Left pile +lblRightPile=Right pile lblChoosesPile=wähle Stapel lblEmptyPile=Leerer Stapel #UntapEffect.java diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index d200212c677..a49a1f47510 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -1933,6 +1933,9 @@ lblTapOrUntapTarget=Tap or Untap {0}? #TwoPilesEffect.java lblSelectCardForFaceDownPile=Select cards for a face down pile lblDivideCardIntoTwoPiles=Divide cards into two piles +lblSelectCardForLeftPile=Select cards for the left pile +lblLeftPile=Left pile +lblRightPile=Right pile lblChoosesPile=chooses Pile lblEmptyPile=Empty pile #UntapEffect.java diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index 5eb0f851eee..226f28075fd 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -1933,6 +1933,9 @@ lblTapOrUntapTarget=¿Girar o Enderezar {0}? #TwoPilesEffect.java lblSelectCardForFaceDownPile=Selecciona las cartas para un montón boca abajo lblDivideCardIntoTwoPiles=Dividir las cartas en dos montones +lblSelectCardForLeftPile=Select cards for the left pile +lblLeftPile=Left pile +lblRightPile=Right pile lblChoosesPile=elige Montón lblEmptyPile=Montón vacío #UntapEffect.java diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index 80ca528835b..c40b513a2ed 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -1933,6 +1933,9 @@ lblTapOrUntapTarget=Tap or Untap {0}? #TwoPilesEffect.java lblSelectCardForFaceDownPile=Select cards for a face down pile lblDivideCardIntoTwoPiles=Divide cards into two piles +lblSelectCardForLeftPile=Select cards for the left pile +lblLeftPile=Left pile +lblRightPile=Right pile lblChoosesPile=chooses Pile lblEmptyPile=Empty pile #UntapEffect.java diff --git a/forge-gui/res/languages/ja-JP.properties b/forge-gui/res/languages/ja-JP.properties index 3f57b93ab2c..219998afa3b 100644 --- a/forge-gui/res/languages/ja-JP.properties +++ b/forge-gui/res/languages/ja-JP.properties @@ -1933,6 +1933,9 @@ lblTapOrUntapTarget={0}をタップまたはアンタップしますか? #TwoPilesEffect.java lblSelectCardForFaceDownPile=裏向き束のカードを選ぶ lblDivideCardIntoTwoPiles=カードを 2つの束に分ける +lblSelectCardForLeftPile=「左」の束のカードを選ぶ +lblLeftPile=「左」の束 +lblRightPile=「右」の束 lblChoosesPile=束を選んだ lblEmptyPile=空っぽの束 #UntapEffect.java diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index aacd3e9de26..1bb03642e6b 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -1933,6 +1933,9 @@ lblTapOrUntapTarget=横置还是重置{0}? #TwoPilesEffect.java lblSelectCardForFaceDownPile=选择一个面朝下的堆 lblDivideCardIntoTwoPiles=将牌分为两堆 +lblSelectCardForLeftPile=Select cards for the left pile +lblLeftPile=Left pile +lblRightPile=Right pile lblChoosesPile=选择堆 lblEmptyPile=空堆 #UntapEffect.java diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index a05031c9f0c..39729c64e77 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -492,7 +492,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont // Otherwise, use the order dialog to be able to grab multiple cards in // one shot - if (max == 1) { + if (min == 1 && max == 1) { final Card singleChosen = chooseSingleEntityForEffect(sourceList, sa, title, isOptional, params); return singleChosen == null ? CardCollection.EMPTY : new CardCollection(singleChosen); }