diff --git a/forge-ai/src/main/java/forge/ai/ability/AmassAi.java b/forge-ai/src/main/java/forge/ai/ability/AmassAi.java index d49341d1552..2f0e909fe34 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AmassAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AmassAi.java @@ -29,7 +29,7 @@ public class AmassAi extends SpellAbilityAi { final Game game = ai.getGame(); if (!aiArmies.isEmpty()) { - return CardLists.count(aiArmies, CardPredicates.canReceiveCounters(CounterEnumType.P1P1)) > 0; + return Iterables.any(aiArmies, CardPredicates.canReceiveCounters(CounterEnumType.P1P1)); } final String tokenScript = "b_0_0_zombie_army"; final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa); diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index 5e4804bafa4..4cd58a3d69f 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -932,7 +932,9 @@ public final class GameActionUtil { // add back to where it came from, hopefully old state // skip GameAction oldCard.getZone().remove(oldCard); - fromZone.add(oldCard, zonePosition >= 0 ? Integer.valueOf(zonePosition) : null); + // in some rare cases the old position no longer exists (Panglacial Wurm + Selvala) + Integer newPosition = zonePosition >= 0 ? Math.min(Integer.valueOf(zonePosition), fromZone.size()) : null; + fromZone.add(oldCard, newPosition); ability.setHostCard(oldCard); ability.setXManaCostPaid(null); ability.setSpendPhyrexianMana(false); diff --git a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java index b0ee9fd71e1..46f4ba65f2f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java @@ -4,6 +4,7 @@ import java.util.Map; import org.apache.commons.lang3.mutable.MutableBoolean; +import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import forge.game.Game; @@ -53,7 +54,7 @@ public class AmassEffect extends TokenEffectBase { final boolean remember = sa.hasParam("RememberAmass"); // create army token if needed - if (CardLists.count(activator.getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Army")) == 0) { + if (!Iterables.any(activator.getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Army"))) { CardZoneTable triggerList = new CardZoneTable(); MutableBoolean combatChanged = new MutableBoolean(false); diff --git a/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java index a4d62e9f2a5..727c782a689 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java @@ -61,7 +61,7 @@ public class BalanceEffect extends SpellAbilityEffect { if (zone.equals(ZoneType.Hand)) { discardedMap.put(p, p.getController().chooseCardsToDiscardFrom(p, sa, validCards.get(i), numToBalance, numToBalance)); } else { // Battlefield - for (Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) { + for (Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) { if ( null == card ) continue; game.getAction().sacrifice(card, sa, true, table, params); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java index ff3a7c64fc5..12ad3e3d16a 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java @@ -8,7 +8,6 @@ import com.google.common.collect.Lists; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; -import forge.game.card.CardUtil; import forge.game.cost.Cost; import forge.game.event.GameEventCardModeChosen; import forge.game.player.Player; @@ -66,24 +65,24 @@ public class ChooseGenericEffect extends SpellAbilityEffect { List chosenSAs = Lists.newArrayList(); String prompt = sa.getParamOrDefault("ChoicePrompt", "Choose"); boolean random = false; + if (sa.hasParam("AtRandom")) { random = true; - Aggregates.random(abilities, amount, chosenSAs); - } else if (!abilities.isEmpty()) { - chosenSAs = p.getController().chooseSpellAbilitiesForEffect(abilities, sa, prompt, amount, ImmutableMap.of()); - } + chosenSAs = Aggregates.random(abilities, amount); - for (SpellAbility chosenSA : chosenSAs) { - if (random && sa.getParam("AtRandom").equals("Urza") && chosenSA.usesTargeting()) { - List validTargets = CardUtil.getValidCardsToTarget(chosenSA.getTargetRestrictions(), sa); - if (validTargets.isEmpty()) { - List newChosenSAs = Lists.newArrayList(); - Aggregates.random(abilities, amount, newChosenSAs); - chosenSAs = newChosenSAs; + int i = 0; + while (sa.getParam("AtRandom").equals("Urza") && i < chosenSAs.size()) { + if (!chosenSAs.get(i).usesTargeting()) { + i++; + } else if (sa.getTargetRestrictions().hasCandidates(chosenSAs.get(i))) { + p.getController().chooseTargetsFor(chosenSAs.get(i)); + i++; } else { - p.getController().chooseTargetsFor(chosenSA); + chosenSAs.set(i, Aggregates.random(abilities)); } } + } else if (!abilities.isEmpty()) { + chosenSAs = p.getController().chooseSpellAbilitiesForEffect(abilities, sa, prompt, amount, ImmutableMap.of()); } if (!chosenSAs.isEmpty()) { diff --git a/forge-gui/res/cardsfolder/b/bishop_of_binding.txt b/forge-gui/res/cardsfolder/b/bishop_of_binding.txt index 7f33e19a2f6..006c776f927 100644 --- a/forge-gui/res/cardsfolder/b/bishop_of_binding.txt +++ b/forge-gui/res/cardsfolder/b/bishop_of_binding.txt @@ -3,10 +3,10 @@ ManaCost:3 W Types:Creature Vampire Cleric PT:1/1 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile target creature an opponent controls until CARDNAME leaves the battlefield. -SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | ConditionPresent$ Card.Self | Duration$ UntilHostLeavesPlay | RememberChanged$ True +SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | Duration$ UntilHostLeavesPlay | RememberChanged$ True T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, target Vampire gets +X/+X until end of turn, where X is the power of the exiled card. SVar:TrigPump:DB$ Pump | ValidTgts$ Permanent.Vampire | TgtPrompt$ Select target Vampire | NumAtt$ X | NumDef$ X -SVar:X:Remembered$CardPower +SVar:X:Count$ValidExile Card.IsRemembered+ExiledWithSource$CardPower // Release notes indicate that this effect should work with Vehicle cards. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True diff --git a/forge-gui/res/cardsfolder/upcoming/the_temporal_anchor.txt b/forge-gui/res/cardsfolder/upcoming/the_temporal_anchor.txt index 9d75974dfec..db112f95dab 100644 --- a/forge-gui/res/cardsfolder/upcoming/the_temporal_anchor.txt +++ b/forge-gui/res/cardsfolder/upcoming/the_temporal_anchor.txt @@ -3,7 +3,7 @@ ManaCost:3 U U U Types:Legendary Artifact T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigScry | TriggerDescription$ At the beginning of your upkeep, scry 2. SVar:TrigScry:DB$ Scry | ScryNum$ 2 -T:Mode$ Scry | ValidPlayer$ You | ToBottom$ True | Execute$ TrigExile | TriggerDescription$ Whenever you choose to put one or more cards on the bottom of your library while scrying, exile that many cards from the bottom of your library. +T:Mode$ Scry | ValidPlayer$ You | ToBottom$ True | TriggerZones$ Battlefield | Execute$ TrigExile | TriggerDescription$ Whenever you choose to put one or more cards on the bottom of your library while scrying, exile that many cards from the bottom of your library. SVar:TrigExile:DB$ Dig | DigNum$ X | ChangeNum$ All | FromBottom$ True | DestinationZone$ Exile | RememberChanged$ True SVar:X:TriggerCount$ScryBottom S:Mode$ Continuous | Condition$ PlayerTurn | MayPlay$ True | Affected$ Card.ExiledWithSource+IsRemembered | AffectedZone$ Exile | Description$ During your turn, you may play cards exiled with CARDNAME.