From 9c2f1474ea85eb061c29903127333538170f205a Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Fri, 25 Nov 2022 21:22:56 +0100 Subject: [PATCH 1/5] Small updates --- .../ability/effects/BecomeMonarchEffect.java | 9 ++--- .../ability/effects/BecomesBlockedEffect.java | 20 +++++------ .../ability/effects/ChangeZoneEffect.java | 6 ++-- .../ability/effects/ChooseEvenOddEffect.java | 13 +++---- .../ability/effects/ControlPlayerEffect.java | 2 +- .../ability/effects/CopyPermanentEffect.java | 9 ++--- .../effects/CountersPutOrRemoveEffect.java | 18 +++++----- .../ability/effects/DamageDealEffect.java | 8 ++--- .../ability/effects/DamageEachEffect.java | 18 +++------- .../ability/effects/DamagePreventEffect.java | 13 +++---- .../game/ability/effects/DestroyEffect.java | 19 +++++----- .../forge/game/ability/effects/DigEffect.java | 9 ++--- .../ability/effects/DigMultipleEffect.java | 2 +- .../game/ability/effects/DiscardEffect.java | 13 +++---- .../game/ability/effects/DrainManaEffect.java | 13 +++---- .../game/ability/effects/DrawEffect.java | 3 +- .../effects/FlipOntoBattlefieldEffect.java | 1 - .../game/ability/effects/GoadEffect.java | 8 +---- .../game/ability/effects/LifeGainEffect.java | 13 +++---- .../game/ability/effects/LifeLoseEffect.java | 6 ++-- .../game/ability/effects/LifeSetEffect.java | 30 ++++++++-------- .../game/ability/effects/LookAtEffect.java | 16 ++------- .../game/ability/effects/ManaEffect.java | 3 +- .../game/ability/effects/MustBlockEffect.java | 12 +++---- .../game/ability/effects/PoisonEffect.java | 15 ++++---- .../game/ability/effects/ProtectEffect.java | 9 ++--- .../game/ability/effects/PumpEffect.java | 16 +++------ .../effects/RearrangeTopOfLibraryEffect.java | 15 +++----- .../ability/effects/ReorderZoneEffect.java | 20 +++++------ .../game/ability/effects/ScryEffect.java | 6 ++-- .../game/ability/effects/SetStateEffect.java | 4 --- .../game/ability/effects/ShuffleEffect.java | 16 ++++----- .../game/ability/effects/SurveilEffect.java | 13 +++---- .../game/ability/effects/TapAllEffect.java | 12 +------ .../forge/game/ability/effects/TapEffect.java | 3 -- .../ability/effects/TapOrUntapAllEffect.java | 35 ++++++++----------- .../ability/effects/TapOrUntapEffect.java | 29 +++++++-------- .../ability/effects/UnattachAllEffect.java | 18 +++------- .../game/ability/effects/UnattachEffect.java | 20 +++-------- .../game/ability/effects/UntapAllEffect.java | 11 +----- .../game/ability/effects/UntapEffect.java | 7 ++-- .../game/ability/effects/VentureEffect.java | 5 +-- .../src/main/java/forge/game/card/Card.java | 15 +++++--- 43 files changed, 212 insertions(+), 321 deletions(-) diff --git a/forge-game/src/main/java/forge/game/ability/effects/BecomeMonarchEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BecomeMonarchEffect.java index d8ba6c707f3..519b73f886b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/BecomeMonarchEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/BecomeMonarchEffect.java @@ -27,10 +27,11 @@ public class BecomeMonarchEffect extends SpellAbilityEffect { final String set = sa.getHostCard().getSetCode(); for (final Player p : getTargetPlayers(sa)) { - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - if (p.canBecomeMonarch()) { - p.getGame().getAction().becomeMonarch(p, set); - } + if (!p.isInGame()) { + continue; + } + if (p.canBecomeMonarch()) { + p.getGame().getAction().becomeMonarch(p, set); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/BecomesBlockedEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BecomesBlockedEffect.java index 3e31e6f37fa..8547d6bd190 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/BecomesBlockedEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/BecomesBlockedEffect.java @@ -34,17 +34,15 @@ public class BecomesBlockedEffect extends SpellAbilityEffect { final Game game = sa.getActivatingPlayer().getGame(); List blocked = Lists.newArrayList(); for (final Card c : getTargetCards(sa)) { - if ((!sa.usesTargeting()) || c.canBeTargetedBy(sa)) { - game.getCombat().setBlocked(c, true); - if (!c.getDamageHistory().getCreatureGotBlockedThisCombat()) { - blocked.add(c); - final Map runParams = AbilityKey.newMap(); - runParams.put(AbilityKey.Attacker, c); - runParams.put(AbilityKey.Blockers, Lists.newArrayList()); - runParams.put(AbilityKey.Defender, game.getCombat().getDefenderByAttacker(c)); - runParams.put(AbilityKey.DefendingPlayer, game.getCombat().getDefenderPlayerByAttacker(c)); - game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false); - } + game.getCombat().setBlocked(c, true); + if (!c.getDamageHistory().getCreatureGotBlockedThisCombat()) { + blocked.add(c); + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Attacker, c); + runParams.put(AbilityKey.Blockers, Lists.newArrayList()); + runParams.put(AbilityKey.Defender, game.getCombat().getDefenderByAttacker(c)); + runParams.put(AbilityKey.DefendingPlayer, game.getCombat().getDefenderPlayerByAttacker(c)); + game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false); } } 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 040e11893ae..5c7876e2dbe 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 @@ -537,15 +537,13 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard) || gameCard.isPhasedOut()) { continue; } - if (sa.usesTargeting() && !gameCard.canBeTargetedBy(sa)) { - continue; - } + if (sa.hasParam("RememberLKI")) { hostCard.addRemembered(CardUtil.getLKICopy(gameCard)); } final String prompt = TextUtil.concatWithSpace(Localizer.getInstance().getMessage("lblDoYouWantMoveTargetFromOriToDest", CardTranslation.getTranslatedName(gameCard.getName()), Lang.joinHomogenous(origin, ZoneType.Accessors.GET_TRANSLATED_NAME), destination.getTranslatedName())); - if (optional && !chooser.getController().confirmAction(sa, null, prompt, null) ) + if (optional && !chooser.getController().confirmAction(sa, null, prompt, null)) continue; final Zone originZone = game.getZoneOf(gameCard); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseEvenOddEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseEvenOddEffect.java index 01687bc9780..f61336dceae 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseEvenOddEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseEvenOddEffect.java @@ -30,12 +30,13 @@ public class ChooseEvenOddEffect extends SpellAbilityEffect { final Card card = sa.getHostCard(); for (final Player p : getTargetPlayers(sa)) { - if ((!sa.usesTargeting()) || p.canBeTargetedBy(sa)) { - EvenOdd chosen = p.getController().chooseBinary(sa, "odd or even", BinaryChoiceType.OddsOrEvens) ? EvenOdd.Odd : EvenOdd.Even; - card.setChosenEvenOdd(chosen); - if (sa.hasParam("Notify")) { - p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p); - } + if (!p.isInGame()) { + continue; + } + EvenOdd chosen = p.getController().chooseBinary(sa, "odd or even", BinaryChoiceType.OddsOrEvens) ? EvenOdd.Odd : EvenOdd.Even; + card.setChosenEvenOdd(chosen); + if (sa.hasParam("Notify")) { + p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p); } } card.updateStateForView(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ControlPlayerEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ControlPlayerEffect.java index 44131d15e8a..2490857f88f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ControlPlayerEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ControlPlayerEffect.java @@ -37,7 +37,7 @@ public class ControlPlayerEffect extends SpellAbilityEffect { @Override public void run() { // CR 800.4b - if (controller.hasLost()) { + if (!controller.isInGame()) { return; } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java index a13870820f3..f034c4312c7 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java @@ -135,6 +135,9 @@ public class CopyPermanentEffect extends TokenEffectBase { } for (final Player controller : controllers) { + if (!controller.isInGame()) { + continue; + } List tgtCards = Lists.newArrayList(); if (sa.hasParam("ValidSupportedCopy")) { @@ -231,10 +234,8 @@ public class CopyPermanentEffect extends TokenEffectBase { continue; } - // if it only targets player, it already got all needed cards from defined - if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !c.canBeTargetedBy(sa)) { - continue; - } + // because copy should be able to copy LKI values, don't handle target and timestamp there + if (sa.hasParam("ForEach")) { for (Player p : AbilityUtils.getDefinedPlayers(host, sa.getParam("ForEach"), sa)) { Card proto = getProtoType(sa, c, controller); diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java index a55b34a1bc6..c36f92001f4 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java @@ -79,18 +79,16 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect { CardTranslation.getTranslatedName(gameCard.getName())), null)) { continue; } - if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) { - if (gameCard.hasCounters()) { - if (eachExisting) { - for (CounterType listType : Lists.newArrayList(gameCard.getCounters().keySet())) { - addOrRemoveCounter(sa, gameCard, listType, counterAmount, table, pl); - } - } else { - addOrRemoveCounter(sa, gameCard, ctype, counterAmount, table, pl); + if (gameCard.hasCounters()) { + if (eachExisting) { + for (CounterType listType : Lists.newArrayList(gameCard.getCounters().keySet())) { + addOrRemoveCounter(sa, gameCard, listType, counterAmount, table, pl); } - } else if (!eachExisting && ctype != null) { - gameCard.addCounter(ctype, counterAmount, pl, table); + } else { + addOrRemoveCounter(sa, gameCard, ctype, counterAmount, table, pl); } + } else if (!eachExisting && ctype != null) { + gameCard.addCounter(ctype, counterAmount, pl, table); } } table.replaceCounterEffect(game, sa, true); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java index 6e3df066009..f74cc649e8d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java @@ -272,14 +272,10 @@ public class DamageDealEffect extends DamageBaseEffect { if (c.isPhasedOut()) { continue; } - if (!sa.usesTargeting() || gc.canBeTargetedBy(sa)) { - internalDamageDeal(sa, sourceLKI, gc, dmg, damageMap); - } + internalDamageDeal(sa, sourceLKI, gc, dmg, damageMap); } else if (o instanceof Player) { final Player p = (Player) o; - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - damageMap.put(sourceLKI, p, dmg); - } + damageMap.put(sourceLKI, p, dmg); } } for (final Card unTgtC : untargetedCards) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/DamageEachEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DamageEachEffect.java index c3faf6b5e08..26020eb59eb 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DamageEachEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DamageEachEffect.java @@ -1,10 +1,7 @@ package forge.game.ability.effects; -import java.util.List; - import forge.game.Game; import forge.game.GameEntityCounterTable; -import forge.game.GameObject; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardDamageMap; @@ -68,10 +65,6 @@ public class DamageEachEffect extends DamageBaseEffect { sources = CardLists.getValidCards(sources, sa.getParam("ValidCards"), sa.getActivatingPlayer(), card, sa); } - final List tgts = getTargets(sa, "DefinedPlayers"); - - final boolean targeted = sa.usesTargeting(); - boolean usedDamageMap = true; CardDamageMap damageMap = sa.getDamageMap(); CardDamageMap preventMap = sa.getPreventMap(); @@ -85,24 +78,21 @@ public class DamageEachEffect extends DamageBaseEffect { usedDamageMap = false; } - for (final Object o : tgts) { + for (final Object o : getTargetEntities(sa, "DefinedPlayers")) { for (final Card source : sources) { final Card sourceLKI = game.getChangeZoneLKIInfo(source); // TODO shouldn't that be using Num or something first? final int dmg = AbilityUtils.calculateAmount(source, "X", sa); - + if (o instanceof Card) { final Card c = (Card) o; - if (c.isInPlay() && (!targeted || c.canBeTargetedBy(sa))) { + if (c.isInPlay()) { damageMap.put(sourceLKI, c, dmg); } } else if (o instanceof Player) { - final Player p = (Player) o; - if (!targeted || p.canBeTargetedBy(sa)) { - damageMap.put(sourceLKI, p, dmg); - } + damageMap.put(sourceLKI, (Player) o, dmg); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffect.java index d06dab25e17..ac6eaa94b1f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffect.java @@ -93,20 +93,15 @@ public class DamagePreventEffect extends DamagePreventEffectBase { final CardCollection untargetedCards = CardUtil.getRadiance(sa); - final boolean targeted = sa.usesTargeting(); - for (final GameObject o : tgts) { - numDam = targeted && sa.isDividedAsYouChoose() ? sa.getDividedValue(o) : numDam; + numDam = sa.usesTargeting() && sa.isDividedAsYouChoose() ? sa.getDividedValue(o) : numDam; if (o instanceof Card) { final Card c = (Card) o; - if (c.isInPlay() && (!targeted || c.canBeTargetedBy(sa))) { + if (c.isInPlay()) { addPreventNextDamage(sa, o, numDam); } } else if (o instanceof Player) { - final Player p = (Player) o; - if (!targeted || p.canBeTargetedBy(sa)) { - addPreventNextDamage(sa, o, numDam); - } + addPreventNextDamage(sa, o, numDam); } } @@ -115,5 +110,5 @@ public class DamagePreventEffect extends DamagePreventEffectBase { addPreventNextDamage(sa, c, numDam); } } - } // preventDamageResolve + } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java index 470464d119f..257fd457768 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java @@ -64,16 +64,17 @@ public class DestroyEffect extends SpellAbilityEffect { CardZoneTable table = new CardZoneTable(); Map cachedMap = Maps.newHashMap(); for (final Card tgtC : tgtCards) { - if (tgtC.isInPlay() && (!sa.usesTargeting() || tgtC.canBeTargetedBy(sa))) { - Card gameCard = game.getCardState(tgtC, null); - // gameCard is LKI in that case, the card is not in game anymore - // or the timestamp did change - // this should check Self too - if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard)) { - continue; - } - internalDestroy(gameCard, sa, table, cachedMap, params); + if (!tgtC.isInPlay()) { + continue; } + Card gameCard = game.getCardState(tgtC, null); + // gameCard is LKI in that case, the card is not in game anymore + // or the timestamp did change + // this should check Self too + if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard)) { + continue; + } + internalDestroy(gameCard, sa, table, cachedMap, params); } if (untargetedCards.size() > 1) { 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 659b86dd55e..896d3ba928d 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 @@ -15,7 +15,6 @@ import forge.game.player.DelayedReveal; import forge.game.player.Player; import forge.game.player.PlayerView; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.PlayerZone; import forge.game.zone.ZoneType; import forge.util.CardTranslation; @@ -169,19 +168,17 @@ public class DigEffect extends SpellAbilityEffect { } } - final TargetRestrictions tgt = sa.getTargetRestrictions(); - final List tgtPlayers = getDefinedPlayersOrTargeted(sa); - CardZoneTable table = new CardZoneTable(); GameEntityCounterTable counterTable = new GameEntityCounterTable(); boolean combatChanged = false; CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield(); CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); - for (final Player p : tgtPlayers) { - if (tgt != null && !p.canBeTargetedBy(sa)) { + for (final Player p : getDefinedPlayersOrTargeted(sa)) { + if (!p.isInGame()) { continue; } + final CardCollection top = new CardCollection(); final CardCollection rest = new CardCollection(); CardCollection all = new CardCollection(p.getCardsIn(srcZone)); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DigMultipleEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DigMultipleEffect.java index d9b4ddf3e6b..e815b89f8a9 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DigMultipleEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DigMultipleEffect.java @@ -40,7 +40,7 @@ public class DigMultipleEffect extends SpellAbilityEffect { CardZoneTable table = new CardZoneTable(); for (final Player chooser : getDefinedPlayersOrTargeted(sa)) { - if (sa.usesTargeting() && !chooser.canBeTargetedBy(sa)) { + if (!chooser.isInGame()) { continue; } final CardCollection top = new CardCollection(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java index 5b3f5c479ac..aab3d4d44c7 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java @@ -134,9 +134,6 @@ public class DiscardEffect extends SpellAbilityEffect { // In this case the target need not be the discarding player discarders = getDefinedPlayersOrTargeted(sa); firstTarget = Iterables.getFirst(targets, null); - if (sa.usesTargeting() && !firstTarget.canBeTargetedBy(sa)) { - firstTarget = null; - } } else { discarders = targets; } @@ -144,6 +141,10 @@ public class DiscardEffect extends SpellAbilityEffect { final CardZoneTable table = new CardZoneTable(); Map discardedMap = Maps.newHashMap(); for (final Player p : discarders) { + if (!p.isInGame()) { + continue; + } + CardCollectionView toBeDiscarded = new CardCollection(); if ((mode.equals("RevealTgtChoose") && firstTarget != null) || !sa.usesTargeting() || p.canBeTargetedBy(sa)) { final int numCardsInHand = p.getCardsIn(ZoneType.Hand).size(); @@ -268,9 +269,6 @@ public class DiscardEffect extends SpellAbilityEffect { dPHand = p.getController().chooseCardsToRevealFromHand(amount, amount, dPHand); } - final String valid = sa.getParamOrDefault("DiscardValid", "Card"); - CardCollection validCards = CardLists.getValidCards(dPHand, valid, source.getController(), source, sa); - Player chooser = p; if (mode.endsWith("YouChoose")) { chooser = source.getController(); @@ -289,6 +287,9 @@ public class DiscardEffect extends SpellAbilityEffect { continue; } + final String valid = sa.getParamOrDefault("DiscardValid", "Card"); + CardCollection validCards = CardLists.getValidCards(dPHand, valid, source.getController(), source, sa); + int min = sa.hasParam("AnyNumber") || sa.hasParam("Optional") ? 0 : Math.min(validCards.size(), numCards); int max = sa.hasParam("AnyNumber") ? validCards.size() : Math.min(validCards.size(), numCards); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DrainManaEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DrainManaEffect.java index 1d1871b7b4c..1532eb72755 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DrainManaEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DrainManaEffect.java @@ -3,22 +3,19 @@ package forge.game.ability.effects; import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.StringUtils; - import forge.game.ability.SpellAbilityEffect; import forge.game.mana.Mana; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; +import forge.util.Lang; public class DrainManaEffect extends SpellAbilityEffect { @Override protected String getStackDescription(SpellAbility sa) { final StringBuilder sb = new StringBuilder(); - final List tgtPlayers = getTargetPlayers(sa); + sb.append(Lang.joinHomogenous(getTargetPlayers(sa))); - sb.append(StringUtils.join(tgtPlayers, ", ")); sb.append(" loses all unspent mana."); return sb.toString(); @@ -26,13 +23,13 @@ public class DrainManaEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { - final TargetRestrictions tgt = sa.getTargetRestrictions(); List drained = new ArrayList<>(); for (final Player p : getTargetPlayers(sa)) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - drained.addAll(p.getManaPool().clearPool(false)); + if (!p.isInGame()) { + continue; } + drained.addAll(p.getManaPool().clearPool(false)); } if (sa.hasParam("DrainMana")) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java index 5c90c773ed4..d67830d3895 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java @@ -62,8 +62,7 @@ public class DrawEffect extends SpellAbilityEffect { moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); for (final Player p : getDefinedPlayersOrTargeted(sa)) { - // TODO can this be removed? - if (sa.usesTargeting() && !p.canBeTargetedBy(sa)) { + if (!p.isInGame()) { continue; } diff --git a/forge-game/src/main/java/forge/game/ability/effects/FlipOntoBattlefieldEffect.java b/forge-game/src/main/java/forge/game/ability/effects/FlipOntoBattlefieldEffect.java index 9e73af3ba86..b2e2dfad95b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/FlipOntoBattlefieldEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/FlipOntoBattlefieldEffect.java @@ -86,7 +86,6 @@ public class FlipOntoBattlefieldEffect extends SpellAbilityEffect { protected String getStackDescription(SpellAbility sa) { final StringBuilder sb = new StringBuilder(); final Card host = sa.getHostCard(); - final Player p = sa.getActivatingPlayer(); sb.append("Flip "); sb.append(host.toString()); diff --git a/forge-game/src/main/java/forge/game/ability/effects/GoadEffect.java b/forge-game/src/main/java/forge/game/ability/effects/GoadEffect.java index ad5116f444e..6b441f4f756 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/GoadEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/GoadEffect.java @@ -6,7 +6,6 @@ import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.zone.ZoneType; import forge.util.Lang; import java.util.List; @@ -36,12 +35,7 @@ public class GoadEffect extends SpellAbilityEffect { for (final Card tgtC : getDefinedCardsOrTargeted(sa)) { // only goad things on the battlefield - if (!game.getCardsIn(ZoneType.Battlefield).contains(tgtC)) { - continue; - } - - // make sure we can still target now if using targeting - if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !tgtC.canBeTargetedBy(sa)) { + if (!tgtC.isInPlay()) { continue; } diff --git a/forge-game/src/main/java/forge/game/ability/effects/LifeGainEffect.java b/forge-game/src/main/java/forge/game/ability/effects/LifeGainEffect.java index 08a50416ce5..01952a587fd 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/LifeGainEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/LifeGainEffect.java @@ -58,13 +58,14 @@ public class LifeGainEffect extends SpellAbilityEffect { } for (final Player p : tgtPlayers) { - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - if (variableAmount) { - sa.setSVar("AFNotDrawnNum", sa.getSVar("AFNotDrawnNum_" + p.getId())); - lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), amount, sa); - } - p.gainLife(lifeAmount, sa.getHostCard(), sa); + if (!p.isInGame()) { + continue; } + if (variableAmount) { + sa.setSVar("AFNotDrawnNum", sa.getSVar("AFNotDrawnNum_" + p.getId())); + lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), amount, sa); + } + p.gainLife(lifeAmount, sa.getHostCard(), sa); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/LifeLoseEffect.java b/forge-game/src/main/java/forge/game/ability/effects/LifeLoseEffect.java index e8afee2a13e..a2afc3381ea 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/LifeLoseEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/LifeLoseEffect.java @@ -1,6 +1,5 @@ package forge.game.ability.effects; - import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.player.Player; @@ -43,9 +42,10 @@ public class LifeLoseEffect extends SpellAbilityEffect { final int lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("LifeAmount"), sa); for (final Player p : getTargetPlayers(sa)) { - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - lifeLost += p.loseLife(lifeAmount, false, false); + if (!p.isInGame()) { + continue; } + lifeLost += p.loseLife(lifeAmount, false, false); } sa.setSVar("AFLifeLost", "Number$" + lifeLost); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/LifeSetEffect.java b/forge-game/src/main/java/forge/game/ability/effects/LifeSetEffect.java index 6ec9b377ee9..82fbb2d2d44 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/LifeSetEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/LifeSetEffect.java @@ -10,7 +10,6 @@ import forge.game.ability.SpellAbilityEffect; import forge.game.player.Player; import forge.game.player.PlayerCollection; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.util.Localizer; public class LifeSetEffect extends SpellAbilityEffect { @@ -22,29 +21,30 @@ public class LifeSetEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final boolean redistribute = sa.hasParam("Redistribute"); final int lifeAmount = redistribute ? 0 : AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("LifeAmount"), sa); - final TargetRestrictions tgt = sa.getTargetRestrictions(); final List lifetotals = new ArrayList<>(); final PlayerCollection players = getTargetPlayers(sa); if (redistribute) { for (final Player p : players) { - if (tgt == null || p.canBeTargetedBy(sa)) { - lifetotals.add(p.getLife()); + if (!p.isInGame()) { + continue; } + lifetotals.add(p.getLife()); } } for (final Player p : players.threadSafeIterable()) { - if (tgt == null || p.canBeTargetedBy(sa)) { - if (!redistribute) { - p.setLife(lifeAmount, sa); - } else { - List validChoices = getDistribution(players, true, lifetotals); - int life = sa.getActivatingPlayer().getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblLifeTotal") + ": " + p, validChoices, p); - p.setLife(life, sa); - lifetotals.remove((Integer) life); - players.remove(p); - } + if (!p.isInGame()) { + continue; + } + if (!redistribute) { + p.setLife(lifeAmount, sa); + } else { + List validChoices = getDistribution(players, true, lifetotals); + int life = sa.getActivatingPlayer().getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblLifeTotal") + ": " + p, validChoices, p); + p.setLife(life, sa); + lifetotals.remove((Integer) life); + players.remove(p); } } } @@ -87,7 +87,7 @@ public class LifeSetEffect extends SpellAbilityEffect { return validChoices; } } - return new ArrayList(); + return new ArrayList<>(); } /* (non-Javadoc) diff --git a/forge-game/src/main/java/forge/game/ability/effects/LookAtEffect.java b/forge-game/src/main/java/forge/game/ability/effects/LookAtEffect.java index e2b27fa0e31..eb37cadfd91 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/LookAtEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/LookAtEffect.java @@ -2,30 +2,18 @@ package forge.game.ability.effects; import forge.game.Game; import forge.game.ability.SpellAbilityEffect; -import forge.game.card.Card; -import forge.game.card.CardCollection; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.util.Lang; public class LookAtEffect extends SpellAbilityEffect { @Override public void resolve(final SpellAbility sa) { - final Card host = sa.getHostCard(); - final Game game = host.getGame(); + final Game game = sa.getHostCard().getGame(); final Player activator = sa.getActivatingPlayer(); - final TargetRestrictions tgt = sa.getTargetRestrictions(); - final CardCollection targets = new CardCollection(); - for (final Card tgtCard : getTargetCards(sa)) { - if (tgt == null || tgtCard.canBeTargetedBy(sa)) { - targets.add(tgtCard); - } - } - - game.getAction().revealTo(targets, activator); + game.getAction().revealTo(getTargetCards(sa), activator); } @Override diff --git a/forge-game/src/main/java/forge/game/ability/effects/ManaEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ManaEffect.java index 05d62f0fd23..1a56a2150d8 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ManaEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ManaEffect.java @@ -48,8 +48,7 @@ public class ManaEffect extends SpellAbilityEffect { final StringBuilder producedMana = new StringBuilder(); for (Player p : tgtPlayers) { - if (sa.usesTargeting() && !p.canBeTargetedBy(sa)) { - // Illegal target. Skip. + if (!p.isInGame()) { continue; } diff --git a/forge-game/src/main/java/forge/game/ability/effects/MustBlockEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MustBlockEffect.java index 57e817ab00b..ecc54d41580 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/MustBlockEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/MustBlockEffect.java @@ -62,13 +62,11 @@ public class MustBlockEffect extends SpellAbilityEffect { long ts = game.getNextTimestamp(); for (final Card c : tgtCards) { - if ((!sa.usesTargeting()) || c.canBeTargetedBy(sa)) { - if (mustBlockAll) { - c.addMustBlockCards(ts, cards); - } else { - final Card attacker = cards.get(0); - c.addMustBlockCard(ts, attacker); - } + if (mustBlockAll) { + c.addMustBlockCards(ts, cards); + } else { + final Card attacker = cards.get(0); + c.addMustBlockCard(ts, attacker); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/PoisonEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PoisonEffect.java index ae42a9eb585..b406d699175 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PoisonEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PoisonEffect.java @@ -29,13 +29,16 @@ public class PoisonEffect extends SpellAbilityEffect { final int amount = AbilityUtils.calculateAmount(host, sa.getParam("Num"), sa); GameEntityCounterTable table = new GameEntityCounterTable(); + for (final Player p : getTargetPlayers(sa)) { - if ((!sa.usesTargeting()) || p.canBeTargetedBy(sa)) { - if (amount >= 0) { - p.addPoisonCounters(amount, sa.getActivatingPlayer(), table); - } else { - p.removePoisonCounters(-amount, sa.getActivatingPlayer()); - } + if (!p.isInGame()) { + continue; + } + + if (amount >= 0) { + p.addPoisonCounters(amount, sa.getActivatingPlayer(), table); + } else { + p.removePoisonCounters(-amount, sa.getActivatingPlayer()); } } table.replaceCounterEffect(game, sa, true); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java index 853f20f2aa9..9a39d627394 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java @@ -90,7 +90,7 @@ public class ProtectEffect extends SpellAbilityEffect { } return sb.toString(); - } // protectStackDescription() + } @Override public void resolve(SpellAbility sa) { @@ -140,11 +140,6 @@ public class ProtectEffect extends SpellAbilityEffect { continue; } - // if this is a target, make sure we can still target now - if (sa.usesTargeting() && !tgtC.canBeTargetedBy(sa)) { - continue; - } - tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, 0, true); if (!"Permanent".equals(sa.getParam("Duration"))) { @@ -186,7 +181,7 @@ public class ProtectEffect extends SpellAbilityEffect { addUntilCommand(sa, untilEOT); } } - } // protectResolve() + } public static List getProtectionList(final SpellAbility sa) { final List gains = new ArrayList<>(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java index be5e0074fe2..d310adce2d0 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java @@ -199,7 +199,7 @@ public class PumpEffect extends SpellAbilityEffect { sb.append(" "); } - if (sa instanceof AbilitySub & sa.getRootAbility().getTargets().containsAll(tgts)) { + if (sa instanceof AbilitySub && sa.getRootAbility().getTargets().containsAll(tgts)) { //try to avoid having the same long list of targets twice in a StackDescription sb.append(tgts.size() == 1 && tgts.get(0) instanceof Card ? "It " : "They "); } else { @@ -266,7 +266,7 @@ public class PumpEffect extends SpellAbilityEffect { } return sb.toString(); - } // pumpStackDescription() + } @Override public void resolve(final SpellAbility sa) { @@ -274,7 +274,6 @@ public class PumpEffect extends SpellAbilityEffect { final Game game = activator.getGame(); final Card host = sa.getHostCard(); final long timestamp = game.getNextTimestamp(); - List tgts = Lists.newArrayList(); List tgtCards = getCardsfromTargets(sa); List tgtPlayers = getTargetPlayers(sa); @@ -296,8 +295,6 @@ public class PumpEffect extends SpellAbilityEffect { keywords = CardFactoryUtil.sharedKeywords(keywords, restrictions, zones, host, sa); } - tgts.addAll(tgtCards); - tgts.addAll(tgtPlayers); final CardCollection untargetedCards = CardUtil.getRadiance(sa); if (sa.hasParam("DefinedKW")) { @@ -433,11 +430,6 @@ public class PumpEffect extends SpellAbilityEffect { continue; } - // if pump is a target, make sure we can still target now - if (sa.usesTargeting() && !tgtC.canBeTargetedBy(sa)) { - continue; - } - // substitute specific tgtC mana cost for keyword placeholder CardManaCost List affectedKeywords = Lists.newArrayList(keywords); @@ -486,7 +478,7 @@ public class PumpEffect extends SpellAbilityEffect { } for (Player p : tgtPlayers) { - if (!p.canBeTargetedBy(sa)) { + if (!p.isInGame()) { continue; } @@ -494,5 +486,5 @@ public class PumpEffect extends SpellAbilityEffect { } replaceDying(sa); - } // pumpResolve() + } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RearrangeTopOfLibraryEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RearrangeTopOfLibraryEffect.java index 3d6c7ab50bd..b2124e95ca9 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RearrangeTopOfLibraryEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RearrangeTopOfLibraryEffect.java @@ -11,7 +11,6 @@ import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; import forge.util.Lang; import forge.util.Localizer; @@ -70,19 +69,15 @@ public class RearrangeTopOfLibraryEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { - int numCards = 0; Card host = sa.getHostCard(); - boolean shuffle = false; - - final TargetRestrictions tgt = sa.getTargetRestrictions(); - - numCards = AbilityUtils.calculateAmount(host, sa.getParam("NumCards"), sa); - shuffle = sa.hasParam("MayShuffle"); + int numCards = AbilityUtils.calculateAmount(host, sa.getParam("NumCards"), sa); + boolean shuffle = sa.hasParam("MayShuffle"); for (final Player p : getTargetPlayers(sa)) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - rearrangeTopOfLibrary(host, p, numCards, shuffle, sa); + if (!p.isInGame()) { + continue; } + rearrangeTopOfLibrary(host, p, numCards, shuffle, sa); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReorderZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReorderZoneEffect.java index 1b2cb597848..ffd17743cdd 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ReorderZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ReorderZoneEffect.java @@ -7,7 +7,6 @@ import forge.game.ability.SpellAbilityEffect; import forge.game.card.CardCollection; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; import forge.util.Lang; import forge.util.MyRandom; @@ -26,17 +25,18 @@ public class ReorderZoneEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final ZoneType zone = ZoneType.smartValueOf(sa.getParam("Zone")); boolean shuffle = sa.hasParam("Random"); - final TargetRestrictions tgt = sa.getTargetRestrictions(); for (final Player p : getTargetPlayers(sa)) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - CardCollection list = new CardCollection(p.getCardsIn(zone)); - if (shuffle) { - Collections.shuffle(list, MyRandom.getRandom()); - p.getZone(zone).setCards(list); - } else { - p.getController().orderMoveToZoneList(list, zone, sa); - } + if (!p.isInGame()) { + continue; + } + + CardCollection list = new CardCollection(p.getCardsIn(zone)); + if (shuffle) { + Collections.shuffle(list, MyRandom.getRandom()); + p.getZone(zone).setCards(list); + } else { + p.getController().orderMoveToZoneList(list, zone, sa); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ScryEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ScryEffect.java index 5d77f6350b1..a2719abc4f3 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ScryEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ScryEffect.java @@ -43,8 +43,10 @@ public class ScryEffect extends SpellAbilityEffect { // Optional here for spells that have optional multi-player scrying for (final Player p : getTargetPlayers(sa)) { - if ( (!sa.usesTargeting() || p.canBeTargetedBy(sa)) && - (!isOptional || p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWanttoScry"), null)) ) { + if (!p.isInGame()) { + continue; + } + if (!isOptional || p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWanttoScry"), null)) { players.add(p); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java index da458252bbb..f0c5f9cb494 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java @@ -93,10 +93,6 @@ public class SetStateEffect extends SpellAbilityEffect { continue; } - if (sa.usesTargeting() && !gameCard.canBeTargetedBy(sa)) { - continue; - } - // Cards which are not on the battlefield should not be able to transform. // TurnFace should be allowed in other zones like Exile too // Specialize and Unspecialize are allowed in other zones diff --git a/forge-game/src/main/java/forge/game/ability/effects/ShuffleEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ShuffleEffect.java index 0832d421302..ecfc6e98e8f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ShuffleEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ShuffleEffect.java @@ -6,7 +6,6 @@ import java.util.List; import forge.game.ability.SpellAbilityEffect; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.util.Localizer; public class ShuffleEffect extends SpellAbilityEffect { @@ -15,16 +14,13 @@ public class ShuffleEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final boolean optional = sa.hasParam("Optional"); - final List tgtPlayers = getTargetPlayers(sa); - - final TargetRestrictions tgt = sa.getTargetRestrictions(); - - for (final Player p : tgtPlayers) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - boolean mustShuffle = !optional || sa.getActivatingPlayer().getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblHaveTargetShuffle", p.getName()), null); - if (mustShuffle) - p.shuffle(sa); + for (final Player p : getTargetPlayers(sa)) { + if (!p.isInGame()) { + continue; } + boolean mustShuffle = !optional || sa.getActivatingPlayer().getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblHaveTargetShuffle", p.getName()), null); + if (mustShuffle) + p.shuffle(sa); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/SurveilEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SurveilEffect.java index f79c5c9e43e..56c8492ad0c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SurveilEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SurveilEffect.java @@ -42,13 +42,14 @@ public class SurveilEffect extends SpellAbilityEffect { moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); for (final Player p : getTargetPlayers(sa)) { - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - if (isOptional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantSurveil"), null)) { - continue; - } - - p.surveil(num, sa, table, moveParams); + if (!p.isInGame()) { + continue; } + if (isOptional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantSurveil"), null)) { + continue; + } + + p.surveil(num, sa, table, moveParams); } table.triggerChangesZoneAll(sa.getHostCard().getGame(), sa); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/TapAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TapAllEffect.java index 873e3096b59..982bb6e2b8f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TapAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TapAllEffect.java @@ -1,12 +1,9 @@ package forge.game.ability.effects; -import java.util.List; - import forge.game.Game; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; -import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; import forge.game.player.Player; import forge.game.spellability.AbilitySub; @@ -34,17 +31,10 @@ public class TapAllEffect extends SpellAbilityEffect { } CardCollectionView cards; - - final List tgtPlayers = getTargetPlayers(sa); - if (!sa.usesTargeting() && !sa.hasParam("Defined")) { cards = game.getCardsIn(ZoneType.Battlefield); } else { - CardCollection cards2 = new CardCollection(); - for (final Player p : tgtPlayers) { - cards2.addAll(p.getCardsIn(ZoneType.Battlefield)); - } - cards = cards2; + cards = getTargetPlayers(sa).getCardsIn(ZoneType.Battlefield); } cards = AbilityUtils.filterListByType(cards, sa.getParam("ValidCards"), sa); diff --git a/forge-game/src/main/java/forge/game/ability/effects/TapEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TapEffect.java index 33b1402c859..656f9cde456 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TapEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TapEffect.java @@ -23,9 +23,6 @@ public class TapEffect extends SpellAbilityEffect { if (tgtC.isPhasedOut()) { continue; } - if (sa.usesTargeting() && !tgtC.canBeTargetedBy(sa)) { - continue; - } if (tgtC.isInPlay()) { if (tgtC.isUntapped() && remTapped || alwaysRem) { card.addRemembered(tgtC); diff --git a/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapAllEffect.java index a041728e6d1..ef60486fb0f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapAllEffect.java @@ -1,8 +1,5 @@ package forge.game.ability.effects; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; import forge.game.Game; import forge.game.ability.AbilityUtils; @@ -14,9 +11,8 @@ import forge.game.player.Player; import forge.game.player.PlayerController; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; +import forge.util.Lang; import forge.util.Localizer; -import forge.util.collect.FCollection; - public class TapOrUntapAllEffect extends SpellAbilityEffect { @@ -29,8 +25,7 @@ public class TapOrUntapAllEffect extends SpellAbilityEffect { if (sa.hasParam("ValidMessage")) { sb.append(sa.getParam("ValidMessage")); } else { - final List tgtCards = getTargetCards(sa); - sb.append(StringUtils.join(tgtCards, ", ")); + sb.append(Lang.joinHomogenous(getTargetCards(sa))); } sb.append("."); return sb.toString(); @@ -38,19 +33,18 @@ public class TapOrUntapAllEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { - CardCollectionView validCards = getTargetCards(sa); final Player activator = sa.getActivatingPlayer(); final Game game = activator.getGame(); - FCollection targetedPlayers = getTargetPlayers(sa); - + CardCollectionView validCards; if (sa.hasParam("ValidCards")) { - validCards = game.getCardsIn(ZoneType.Battlefield); - validCards = AbilityUtils.filterListByType(validCards, sa.getParam("ValidCards"), sa); + validCards = AbilityUtils.filterListByType(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidCards"), sa); + } else { + validCards = getTargetCards(sa); } if (sa.usesTargeting() || sa.hasParam("Defined")) { - validCards = CardLists.filterControlledBy(validCards, targetedPlayers); + validCards = CardLists.filterControlledBy(validCards, getTargetPlayers(sa)); } // Default to tapping for AI @@ -66,13 +60,14 @@ public class TapOrUntapAllEffect extends SpellAbilityEffect { toTap = sa.getActivatingPlayer().getController().chooseBinary(sa, sb.toString(), PlayerController.BinaryChoiceType.TapOrUntap); - for (final Card cad : validCards) { - if (cad.isInPlay()) { - if (toTap) { - cad.tap(true); - } else { - cad.untap(true); - } + for (final Card tgtC : validCards) { + if (!tgtC.isInPlay()) { + continue; + } + if (toTap) { + tgtC.tap(true); + } else { + tgtC.untap(true); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapEffect.java index eb911ac0b89..3c732f920e1 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapEffect.java @@ -2,14 +2,12 @@ package forge.game.ability.effects; import java.util.List; -import org.apache.commons.lang3.StringUtils; - import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.player.PlayerController; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.util.CardTranslation; +import forge.util.Lang; import forge.util.Localizer; public class TapOrUntapEffect extends SpellAbilityEffect { @@ -24,8 +22,7 @@ public class TapOrUntapEffect extends SpellAbilityEffect { sb.append("Tap or untap "); - final List tgtCards = getTargetCards(sa); - sb.append(StringUtils.join(tgtCards, ", ")); + sb.append(Lang.joinHomogenous(getTargetCards(sa))); sb.append("."); return sb.toString(); } @@ -33,24 +30,24 @@ public class TapOrUntapEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { final List tgtCards = getTargetCards(sa); - - final TargetRestrictions tgt = sa.getTargetRestrictions(); PlayerController pc = sa.getActivatingPlayer().getController(); for (final Card tgtC : tgtCards) { + if (!tgtC.isInPlay()) { + continue; + } if (tgtC.isPhasedOut()) { continue; } - if (tgtC.isInPlay() && ((tgt == null) || tgtC.canBeTargetedBy(sa))) { - // If the effected card is controlled by the same controller of the SA, default to untap. - boolean tap = pc.chooseBinary(sa, Localizer.getInstance().getMessage("lblTapOrUntapTarget", CardTranslation.getTranslatedName(tgtC.getName())), PlayerController.BinaryChoiceType.TapOrUntap, - !tgtC.getController().equals(sa.getActivatingPlayer()) ); - if (tap) { - tgtC.tap(true); - } else { - tgtC.untap(true); - } + // If the effected card is controlled by the same controller of the SA, default to untap. + boolean tap = pc.chooseBinary(sa, Localizer.getInstance().getMessage("lblTapOrUntapTarget", CardTranslation.getTranslatedName(tgtC.getName())), PlayerController.BinaryChoiceType.TapOrUntap, + !tgtC.getController().equals(sa.getActivatingPlayer()) ); + + if (tap) { + tgtC.tap(true); + } else { + tgtC.untap(true); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/UnattachAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/UnattachAllEffect.java index c25aae259d5..947920ec8ef 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/UnattachAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/UnattachAllEffect.java @@ -1,18 +1,14 @@ package forge.game.ability.effects; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - import forge.game.Game; import forge.game.GameEntity; -import forge.game.GameObject; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; +import forge.util.Lang; public class UnattachAllEffect extends SpellAbilityEffect { private static void handleUnattachment(final GameEntity o, final Card cardToUnattach) { @@ -121,8 +117,7 @@ public class UnattachAllEffect extends SpellAbilityEffect { protected String getStackDescription(final SpellAbility sa) { final StringBuilder sb = new StringBuilder(); sb.append("Unattach all valid Equipment and Auras from "); - final List targets = getTargets(sa); - sb.append(StringUtils.join(targets, " ")); + sb.append(Lang.joinHomogenous(getTargets(sa))); return sb.toString(); } @@ -130,19 +125,14 @@ public class UnattachAllEffect extends SpellAbilityEffect { public void resolve(final SpellAbility sa) { Card source = sa.getHostCard(); final Game game = sa.getActivatingPlayer().getGame(); - final List targets = getTargets(sa); // If Cast Targets will be checked on the Stack - for (final Object o : targets) { - if (!(o instanceof GameEntity)) { - continue; - } - + for (final GameEntity ge : getTargetEntities(sa)) { String valid = sa.getParam("UnattachValid"); CardCollectionView unattachList = game.getCardsIn(ZoneType.Battlefield); unattachList = CardLists.getValidCards(unattachList, valid, source.getController(), source, sa); for (final Card c : unattachList) { - handleUnattachment((GameEntity) o, c); + handleUnattachment(ge, c); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/UnattachEffect.java b/forge-game/src/main/java/forge/game/ability/effects/UnattachEffect.java index 65453f29391..5bdfc94b070 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/UnattachEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/UnattachEffect.java @@ -1,12 +1,9 @@ package forge.game.ability.effects; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Lang; public class UnattachEffect extends SpellAbilityEffect { /* (non-Javadoc) @@ -16,8 +13,7 @@ public class UnattachEffect extends SpellAbilityEffect { protected String getStackDescription(SpellAbility sa) { final StringBuilder sb = new StringBuilder(); sb.append("Unattach "); - final List targets = getTargetCards(sa); - sb.append(StringUtils.join(targets, " ")); + sb.append(Lang.joinHomogenous(getTargetCards(sa))); return sb.toString(); } @@ -26,15 +22,9 @@ public class UnattachEffect extends SpellAbilityEffect { */ @Override public void resolve(SpellAbility sa) { - final List unattachList = getTargetCards(sa); - for (final Card cardToUnattach : unattachList) { - if (cardToUnattach.isAura()) { - //final boolean gainControl = "GainControl".equals(af.parseParams().get("AILogic")); - //AbilityFactoryAttach.handleUnattachAura(cardToUnattach, c, gainControl); - } else if (cardToUnattach.isAttachment()) { - if (cardToUnattach.isAttachedToEntity()) { - cardToUnattach.unattachFromEntity(cardToUnattach.getEntityAttachedTo()); - } + for (final Card cardToUnattach : getTargetCards(sa)) { + if (cardToUnattach.isAttachment() && cardToUnattach.isAttachedToEntity()) { + cardToUnattach.unattachFromEntity(cardToUnattach.getEntityAttachedTo()); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/UntapAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/UntapAllEffect.java index c749602dcde..538117eb812 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/UntapAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/UntapAllEffect.java @@ -1,13 +1,9 @@ package forge.game.ability.effects; -import java.util.List; - import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; -import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; -import forge.game.player.Player; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; @@ -25,17 +21,12 @@ public class UntapAllEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final Card card = sa.getHostCard(); CardCollectionView list; - List tgtPlayers = getTargetPlayers(sa); final String valid = sa.getParamOrDefault("ValidCards", ""); if (!sa.usesTargeting() && !sa.hasParam("Defined")) { list = sa.getActivatingPlayer().getGame().getCardsIn(ZoneType.Battlefield); } else { - CardCollection list2 = new CardCollection(); - for (final Player p : tgtPlayers) { - list2.addAll(p.getCardsIn(ZoneType.Battlefield)); - } - list = list2; + list = getTargetPlayers(sa).getCardsIn(ZoneType.Battlefield); } list = CardLists.getValidCards(list, valid, sa.getActivatingPlayer(), card, sa); diff --git a/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java b/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java index 12f893c2870..9ac90333844 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java @@ -48,9 +48,6 @@ public class UntapEffect extends SpellAbilityEffect { if (tgtC.isPhasedOut()) { continue; } - if (sa.usesTargeting() && !tgtC.canBeTargetedBy(sa)) { - continue; - } if (tgtC.isInPlay()) { tgtC.untap(true); } @@ -86,6 +83,10 @@ public class UntapEffect extends SpellAbilityEffect { final String valid = sa.getParam("UntapType"); for (final Player p : AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Defined"), sa)) { + if (!p.isInGame()) { + continue; + } + CardCollectionView list = CardLists.getValidCards(p.getGame().getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), sa.getHostCard(), sa); list = CardLists.filter(list, Presets.TAPPED); diff --git a/forge-game/src/main/java/forge/game/ability/effects/VentureEffect.java b/forge-game/src/main/java/forge/game/ability/effects/VentureEffect.java index 239576a109c..e2fe177b61d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/VentureEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/VentureEffect.java @@ -132,9 +132,10 @@ public class VentureEffect extends SpellAbilityEffect { moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); for (final Player p : getTargetPlayers(sa)) { - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - ventureIntoDungeon(sa, p, moveParams); + if (!p.isInGame()) { + continue; } + ventureIntoDungeon(sa, p, moveParams); } } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 63904d99354..26bc01e348a 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -717,8 +717,6 @@ public class Card extends GameEntity implements Comparable, IHasSVars { if (!turnFaceDown(true) && !isFaceDown()) { return null; } - // Move to p's battlefield - Game game = p.getGame(); // Just in case you aren't the controller, now you are! setController(p, game.getNextTimestamp()); @@ -726,6 +724,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { // Mark this card as "manifested" setManifested(true); + // Move to p's battlefield Card c = game.getAction().moveToPlay(this, p, sa, params); if (c.isInPlay()) { c.setManifested(true); @@ -3656,7 +3655,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars { if (hasKeyword(Keyword.RECONFIGURE)) { // need extra time stamp so it doesn't collide with existing ones long ts = getGame().getNextTimestamp(); - // TODO make it use a Static Layer Effect instead + // 702.151b Attaching an Equipment with reconfigure to another creature causes the Equipment to stop being a creature until it becomes unattached from that creature. + // it is not a Static Ability addChangedCardTypes(null, CardType.parse("Creature", true), false, false, false, false, false, false, false, false, ts, 0, true, false); GameCommand unattach = new GameCommand() { @@ -5061,6 +5061,13 @@ public class Card extends GameEntity implements Comparable, IHasSVars { // when it doesn't exist the game will no longer see it as tapped runUntapCommands(); // TODO CR 702.26f need to run LeavesPlay + changeController commands but only when worded "for as long as" + + // these links also break + clearEncodedCards(); + if (isPaired()) { + getPairedWith().setPairedWith(null); + setPairedWith(null); + } } setPhasedOut(!phasedOut); @@ -6094,7 +6101,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { @Override public final boolean canBeTargetedBy(final SpellAbility sa) { - if (getOwner().hasLost()) { + if (!getOwner().isInGame()) { return false; } From 0146e0c72e4148ac78363595c95d53c9349d6b24 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Fri, 25 Nov 2022 21:25:58 +0100 Subject: [PATCH 2/5] Multiplayer support --- .../game/ability/SpellAbilityEffect.java | 11 +++ .../ability/effects/ChooseCardEffect.java | 83 +++++++++---------- .../ability/effects/ChooseColorEffect.java | 80 +++++++++--------- .../ability/effects/ChooseGenericEffect.java | 11 +-- 4 files changed, 94 insertions(+), 91 deletions(-) diff --git a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java index 1ce87661d78..fdf4a0f344f 100644 --- a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java +++ b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java @@ -818,4 +818,15 @@ public abstract class SpellAbilityEffect { game.getEndOfTurn().addUntil(until); } } + + public Player getNewChooser(final SpellAbility sa, final Player activator, final Player loser) { + // CR 800.4g + final PlayerCollection options; + if (loser.isOpponentOf(activator)) { + options = activator.getOpponents(); + } else { + options = activator.getAllOtherPlayers(); + } + return activator.getController().chooseSingleEntityForEffect(options, sa, Localizer.getInstance().getMessage("lblChoosePlayer") , null); + } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java index 8636ebe868e..fc7d378193b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java @@ -22,7 +22,6 @@ import forge.game.card.CardPredicates.Presets; import forge.game.player.Player; import forge.game.player.PlayerActionConfirmMode; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; import forge.util.Aggregates; import forge.util.Lang; @@ -61,7 +60,6 @@ public class ChooseCardEffect extends SpellAbilityEffect { final Game game = activator.getGame(); CardCollection chosen = new CardCollection(); - final TargetRestrictions tgt = sa.getTargetRestrictions(); final List tgtPlayers = getTargetPlayers(sa); List choiceZone = Lists.newArrayList(ZoneType.Battlefield); @@ -101,7 +99,10 @@ public class ChooseCardEffect extends SpellAbilityEffect { return; } - for (final Player p : tgtPlayers) { + for (Player p : tgtPlayers) { + if (!p.isInGame()) { + p = getNewChooser(sa, activator, p); + } boolean dontRevealToOwner = true; if (sa.hasParam("EachBasicType")) { // Get all lands, @@ -212,51 +213,49 @@ public class ChooseCardEffect extends SpellAbilityEffect { // Targeted player (p) chooses N creatures that belongs to them CardCollection tgtPlayerCtrl = CardLists.filterControlledBy(choices, p); chosen.addAll(p.getController().chooseCardsForEffect(tgtPlayerCtrl, sa, title + " " + "you control", minAmount, validAmount, - !sa.hasParam("Mandatory"), null)); + !sa.hasParam("Mandatory"), null)); // Targeted player (p) chooses N creatures that don't belong to them CardCollection notTgtPlayerCtrl = new CardCollection(choices); notTgtPlayerCtrl.removeAll(tgtPlayerCtrl); chosen.addAll(p.getController().chooseCardsForEffect(notTgtPlayerCtrl, sa, title + " " + "you don't control", minAmount, validAmount, - !sa.hasParam("Mandatory"), null)); + !sa.hasParam("Mandatory"), null)); - } else if ((tgt == null) || p.canBeTargetedBy(sa)) { - if (sa.hasParam("AtRandom") && !choices.isEmpty()) { - // don't pass FCollection for direct modification, the Set part would get messed up - chosen = new CardCollection(Aggregates.random(choices, validAmount)); - dontRevealToOwner = false; + } else if (sa.hasParam("AtRandom") && !choices.isEmpty()) { + // don't pass FCollection for direct modification, the Set part would get messed up + chosen = new CardCollection(Aggregates.random(choices, validAmount)); + dontRevealToOwner = false; + } else { + String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " "; + if (sa.hasParam ("ChoiceTitleAppend")) { + String tag = ""; + String value = sa.getParam("ChoiceTitleAppend"); + if (value.startsWith("Defined ")) { + tag = AbilityUtils.getDefinedPlayers(host, value.substring(8), sa).toString(); + } else if (value.equals("ChosenType")) { + tag = host.getChosenType(); + } + if (!tag.equals("")) { + title = title + " (" + tag +")"; + } + } + if (sa.hasParam("QuasiLibrarySearch")) { + final Player searched = AbilityUtils.getDefinedPlayers(host, + sa.getParam("QuasiLibrarySearch"), sa).get(0); + final int fetchNum = Math.min(searched.getCardsIn(ZoneType.Library).size(), 4); + CardCollectionView shown = !p.hasKeyword("LimitSearchLibrary") + ? searched.getCardsIn(ZoneType.Library) : searched.getCardsIn(ZoneType.Library, fetchNum); + DelayedReveal delayedReveal = new DelayedReveal(shown, ZoneType.Library, PlayerView.get(searched), + CardTranslation.getTranslatedName(host.getName()) + " - " + + Localizer.getInstance().getMessage("lblLookingCardIn") + " "); + Card choice = p.getController().chooseSingleEntityForEffect(choices, delayedReveal, sa, title, + !sa.hasParam("Mandatory"), p, null); + if (choice == null) { + return; + } + chosen.add(choice); } else { - String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " "; - if (sa.hasParam ("ChoiceTitleAppend")) { - String tag = ""; - String value = sa.getParam("ChoiceTitleAppend"); - if (value.startsWith("Defined ")) { - tag = AbilityUtils.getDefinedPlayers(host, value.substring(8), sa).toString(); - } else if (value.equals("ChosenType")) { - tag = host.getChosenType(); - } - if (!tag.equals("")) { - title = title + " (" + tag +")"; - } - } - if (sa.hasParam("QuasiLibrarySearch")) { - final Player searched = AbilityUtils.getDefinedPlayers(host, - sa.getParam("QuasiLibrarySearch"), sa).get(0); - final int fetchNum = Math.min(searched.getCardsIn(ZoneType.Library).size(), 4); - CardCollectionView shown = !p.hasKeyword("LimitSearchLibrary") - ? searched.getCardsIn(ZoneType.Library) : searched.getCardsIn(ZoneType.Library, fetchNum); - DelayedReveal delayedReveal = new DelayedReveal(shown, ZoneType.Library, PlayerView.get(searched), - CardTranslation.getTranslatedName(host.getName()) + " - " + - Localizer.getInstance().getMessage("lblLookingCardIn") + " "); - Card choice = p.getController().chooseSingleEntityForEffect(choices, delayedReveal, sa, title, - !sa.hasParam("Mandatory"), p, null); - if (choice == null) { - return; - } - chosen.add(choice); - } else { - chosen.addAll(p.getController().chooseCardsForEffect(choices, sa, title, minAmount, validAmount, - !sa.hasParam("Mandatory"), null)); - } + chosen.addAll(p.getController().chooseCardsForEffect(choices, sa, title, minAmount, validAmount, + !sa.hasParam("Mandatory"), null)); } } if (sa.hasParam("Reveal") && !sa.hasParam("SecretlyChoose")) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseColorEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseColorEffect.java index 75c5655960d..74154447d4f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseColorEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseColorEffect.java @@ -6,7 +6,6 @@ import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.util.Aggregates; import forge.util.Lang; import forge.util.Localizer; @@ -49,48 +48,45 @@ public class ChooseColorEffect extends SpellAbilityEffect { } } - final List tgtPlayers = getTargetPlayers(sa); - - final TargetRestrictions tgt = sa.getTargetRestrictions(); - - for (final Player p : tgtPlayers) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - List chosenColors = new ArrayList<>(); - int cntMin = sa.hasParam("TwoColors") ? 2 : 1; - int cntMax = sa.hasParam("TwoColors") ? 2 : sa.hasParam("OrColors") ? colorChoices.size() : 1; - String prompt = null; - if (cntMax == 1) { - prompt = Localizer.getInstance().getMessage("lblChooseAColor"); - } else { - if (cntMax > cntMin) { - if (cntMax >= MagicColor.NUMBER_OR_COLORS) { - prompt = Localizer.getInstance().getMessage("lblAtLastChooseNumColors", Lang.getNumeral(cntMin)); - } else { - prompt = Localizer.getInstance().getMessage("lblChooseSpecifiedRangeColors", Lang.getNumeral(cntMin), Lang.getNumeral(cntMax)); - } - } else { - prompt = Localizer.getInstance().getMessage("lblChooseNColors", Lang.getNumeral(cntMax)); - } - } - Player noNotify = p; - if (sa.hasParam("Random")) { - String choice; - for (int i=0; i chosenColors = new ArrayList<>(); + int cntMin = sa.hasParam("TwoColors") ? 2 : 1; + int cntMax = sa.hasParam("TwoColors") ? 2 : sa.hasParam("OrColors") ? colorChoices.size() : 1; + String prompt = null; + if (cntMax == 1) { + prompt = Localizer.getInstance().getMessage("lblChooseAColor"); + } else { + if (cntMax > cntMin) { + if (cntMax >= MagicColor.NUMBER_OR_COLORS) { + prompt = Localizer.getInstance().getMessage("lblAtLastChooseNumColors", Lang.getNumeral(cntMin)); + } else { + prompt = Localizer.getInstance().getMessage("lblChooseSpecifiedRangeColors", Lang.getNumeral(cntMin), Lang.getNumeral(cntMax)); + } + } else { + prompt = Localizer.getInstance().getMessage("lblChooseNColors", Lang.getNumeral(cntMax)); + } + } + Player noNotify = p; + if (sa.hasParam("Random")) { + String choice; + for (int i=0; i tgtPlayers = getDefinedPlayersOrTargeted(sa); - - for (final Player p : tgtPlayers) { + for (Player p : getDefinedPlayersOrTargeted(sa)) { + if (!p.isInGame()) { + p = getNewChooser(sa, sa.getActivatingPlayer(), p); + } // determine if any of the choices are not valid List saToRemove = Lists.newArrayList(); @@ -62,10 +63,6 @@ public class ChooseGenericEffect extends SpellAbilityEffect { } abilities.removeAll(saToRemove); - if (sa.usesTargeting() && sa.getTargets().contains(p) && !p.canBeTargetedBy(sa)) { - continue; - } - List chosenSAs = Lists.newArrayList(); String prompt = sa.getParamOrDefault("ChoicePrompt", "Choose"); boolean random = false; From 9fabf6086cc142b0eb000f86cc54c59c518b4655 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Fri, 25 Nov 2022 21:28:59 +0100 Subject: [PATCH 3/5] The bigger looking ones from more indentation --- .../effects/ActivateAbilityEffect.java | 30 +-- .../game/ability/effects/AddTurnEffect.java | 54 ++-- .../effects/ChangeCombatantsEffect.java | 55 ++-- .../ability/effects/ChooseCardNameEffect.java | 185 +++++++------- .../ability/effects/ChooseNumberEffect.java | 50 ++-- .../ability/effects/ChoosePlayerEffect.java | 84 +++---- .../ability/effects/ChooseSourceEffect.java | 35 +-- .../ability/effects/ChooseTypeEffect.java | 38 ++- .../ability/effects/CountersPutEffect.java | 222 ++++++++-------- .../ability/effects/CountersRemoveEffect.java | 95 ++++--- .../game/ability/effects/DebuffEffect.java | 126 +++++----- .../game/ability/effects/DigUntilEffect.java | 236 +++++++++--------- .../game/ability/effects/ManifestEffect.java | 58 +++-- .../game/ability/effects/MillEffect.java | 74 +++--- .../ability/effects/MultiplePilesEffect.java | 46 ++-- .../ability/effects/ProtectAllEffect.java | 38 ++- .../effects/RemoveFromCombatEffect.java | 48 ++-- .../game/ability/effects/RevealEffect.java | 125 +++++----- .../ability/effects/RevealHandEffect.java | 48 ++-- .../game/ability/effects/TwoPilesEffect.java | 206 ++++++++------- 20 files changed, 912 insertions(+), 941 deletions(-) diff --git a/forge-game/src/main/java/forge/game/ability/effects/ActivateAbilityEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ActivateAbilityEffect.java index a292825e681..cd4d91468bd 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ActivateAbilityEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ActivateAbilityEffect.java @@ -12,7 +12,6 @@ import forge.game.card.Card; import forge.game.card.CardLists; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; import forge.util.Lang; import forge.util.Localizer; @@ -36,25 +35,26 @@ public class ActivateAbilityEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { - final TargetRestrictions tgt = sa.getTargetRestrictions(); final boolean isManaAb = sa.hasParam("ManaAbility"); // TODO: improve ai and fix corner cases for (final Player p : getTargetPlayers(sa)) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - List list = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), sa.getParamOrDefault("Type", "Card")); - for (Card c : list) { - List possibleAb = Lists.newArrayList(c.getAllPossibleAbilities(p, true)); - if (isManaAb) { - possibleAb.retainAll((FCollection)c.getManaAbilities()); - } - if (possibleAb.isEmpty()) { - continue; - } - SpellAbility manaAb = p.getController().chooseSingleSpellForEffect( - possibleAb, sa, Localizer.getInstance().getMessage("lblChooseManaAbility"), ImmutableMap.of()); - p.getController().playChosenSpellAbility(manaAb); + if (!p.isInGame()) { + continue; + } + + List list = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), sa.getParamOrDefault("Type", "Card")); + for (Card c : list) { + List possibleAb = Lists.newArrayList(c.getAllPossibleAbilities(p, true)); + if (isManaAb) { + possibleAb.retainAll((FCollection)c.getManaAbilities()); } + if (possibleAb.isEmpty()) { + continue; + } + SpellAbility manaAb = p.getController().chooseSingleSpellForEffect( + possibleAb, sa, Localizer.getInstance().getMessage("lblChooseManaAbility"), ImmutableMap.of()); + p.getController().playChosenSpellAbility(manaAb); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/AddTurnEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AddTurnEffect.java index 45a6b70afa0..265f490143f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AddTurnEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AddTurnEffect.java @@ -1,7 +1,5 @@ package forge.game.ability.effects; -import java.util.List; - import forge.game.Game; import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityKey; @@ -15,6 +13,7 @@ import forge.game.trigger.Trigger; import forge.game.trigger.TriggerHandler; import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; +import forge.util.Lang; import forge.util.Localizer; public class AddTurnEffect extends SpellAbilityEffect { @@ -24,11 +23,7 @@ public class AddTurnEffect extends SpellAbilityEffect { final StringBuilder sb = new StringBuilder(); final int numTurns = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumTurns"), sa); - List tgtPlayers = getTargetPlayers(sa); - - for (final Player player : tgtPlayers) { - sb.append(player).append(" "); - } + sb.append(Lang.joinHomogenous(getTargetPlayers(sa))); sb.append("takes "); sb.append(numTurns > 1 ? numTurns : "an"); @@ -45,29 +40,28 @@ public class AddTurnEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final int numTurns = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumTurns"), sa); - List tgtPlayers = getTargetPlayers(sa); - - for (final Player p : tgtPlayers) { - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - for (int i = 0; i < numTurns; i++) { - ExtraTurn extra = p.getGame().getPhaseHandler().addExtraTurn(p); - if (sa.hasParam("ExtraTurnDelayedTrigger")) { - final Trigger delTrig = TriggerHandler.parseTrigger(sa.getSVar(sa.getParam("ExtraTurnDelayedTrigger")), sa.getHostCard(), true); - SpellAbility overridingSA = AbilityFactory.getAbility(sa.getSVar(sa.getParam("ExtraTurnDelayedTriggerExcute")), sa.getHostCard()); - overridingSA.setActivatingPlayer(sa.getActivatingPlayer()); - delTrig.setOverridingAbility(overridingSA); - delTrig.setSpawningAbility(sa.copy(sa.getHostCard(), sa.getActivatingPlayer(), true)); - extra.addTrigger(delTrig); - } - if (sa.hasParam("SkipUntap")) { - extra.setSkipUntapSA(sa); - } - if (sa.hasParam("NoSchemes")) { - extra.setCantSetSchemesInMotionSA(sa); - } - if (sa.hasParam("ShowMessage")) { - p.getGame().getAction().notifyOfValue(sa, p, Localizer.getInstance().getMessage("lblPlayerTakesExtraTurn", p.toString()), null); - } + for (final Player p : getTargetPlayers(sa)) { + if (!p.isInGame()) { + continue; + } + for (int i = 0; i < numTurns; i++) { + ExtraTurn extra = p.getGame().getPhaseHandler().addExtraTurn(p); + if (sa.hasParam("ExtraTurnDelayedTrigger")) { + final Trigger delTrig = TriggerHandler.parseTrigger(sa.getSVar(sa.getParam("ExtraTurnDelayedTrigger")), sa.getHostCard(), true); + SpellAbility overridingSA = AbilityFactory.getAbility(sa.getSVar(sa.getParam("ExtraTurnDelayedTriggerExcute")), sa.getHostCard()); + overridingSA.setActivatingPlayer(sa.getActivatingPlayer()); + delTrig.setOverridingAbility(overridingSA); + delTrig.setSpawningAbility(sa.copy(sa.getHostCard(), sa.getActivatingPlayer(), true)); + extra.addTrigger(delTrig); + } + if (sa.hasParam("SkipUntap")) { + extra.setSkipUntapSA(sa); + } + if (sa.hasParam("NoSchemes")) { + extra.setCantSetSchemesInMotionSA(sa); + } + if (sa.hasParam("ShowMessage")) { + p.getGame().getAction().notifyOfValue(sa, p, Localizer.getInstance().getMessage("lblPlayerTakesExtraTurn", p.toString()), null); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java index e09742febc0..4d138cad810 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java @@ -18,7 +18,6 @@ import forge.game.event.GameEventCombatChanged; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; -import forge.game.spellability.TargetRestrictions; import forge.util.CardTranslation; import forge.util.Localizer; import forge.util.collect.FCollection; @@ -42,7 +41,6 @@ public class ChangeCombatantsEffect extends SpellAbilityEffect { boolean isCombatChanged = false; final Player activator = sa.getActivatingPlayer(); final Game game = activator.getGame(); - final TargetRestrictions tgt = sa.getTargetRestrictions(); // TODO: may expand this effect for defined blocker (False Orders, General Jarkeld, Sorrow's Path, Ydwen Efreet) for (final Card c : getTargetCards(sa)) { String cardString = CardTranslation.getTranslatedName(c.getName()) + " (" + c.getId() + ")"; @@ -51,38 +49,37 @@ public class ChangeCombatantsEffect extends SpellAbilityEffect { Localizer.getInstance().getMessage("lblChangeCombatantOption", cardString), null)) { continue; } - if ((tgt == null) || c.canBeTargetedBy(sa)) { - final Combat combat = game.getCombat(); - final GameEntity originalDefender = combat.getDefenderByAttacker(c); - final FCollection defs = new FCollection<>(); - defs.addAll(sa.hasParam("PlayerOnly") ? combat.getDefendingPlayers() : combat.getDefenders()); - String title = Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", cardString); - Map params = Maps.newHashMap(); - params.put("Attacker", c); + final Combat combat = game.getCombat(); + final GameEntity originalDefender = combat.getDefenderByAttacker(c); + final FCollection defs = new FCollection<>(); + defs.addAll(sa.hasParam("PlayerOnly") ? combat.getDefendingPlayers() : combat.getDefenders()); - final GameEntity defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(defs, sa, title, false, params); - if (originalDefender != null && !originalDefender.equals(defender)) { - AttackingBand ab = combat.getBandOfAttacker(c); - if (ab != null) { - combat.unregisterAttacker(c, ab); - ab.removeAttacker(c); - } - combat.addAttacker(c, defender); - // retarget triggers to the new defender (e.g. Ulamog, Ceaseless Hunger + Portal Mage) - for (SpellAbilityStackInstance si : game.getStack()) { - if (si.isTrigger() && c.equals(si.getSourceCard()) - && si.getTriggeringObject(AbilityKey.Attacker) != null) { - si.addTriggeringObject(AbilityKey.OriginalDefender, originalDefender); - if (defender instanceof Player) { - si.updateTriggeringObject(AbilityKey.DefendingPlayer, defender); - } else if (defender instanceof Card) { - si.updateTriggeringObject(AbilityKey.DefendingPlayer, ((Card)defender).getController()); - } + String title = Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", cardString); + Map params = Maps.newHashMap(); + params.put("Attacker", c); + + final GameEntity defender = activator.getController().chooseSingleEntityForEffect(defs, sa, title, false, params); + if (originalDefender != null && !originalDefender.equals(defender)) { + AttackingBand ab = combat.getBandOfAttacker(c); + if (ab != null) { + combat.unregisterAttacker(c, ab); + ab.removeAttacker(c); + } + combat.addAttacker(c, defender); + // retarget triggers to the new defender (e.g. Ulamog, Ceaseless Hunger + Portal Mage) + for (SpellAbilityStackInstance si : game.getStack()) { + if (si.isTrigger() && c.equals(si.getSourceCard()) + && si.getTriggeringObject(AbilityKey.Attacker) != null) { + si.addTriggeringObject(AbilityKey.OriginalDefender, originalDefender); + if (defender instanceof Player) { + si.updateTriggeringObject(AbilityKey.DefendingPlayer, defender); + } else if (defender instanceof Card) { + si.updateTriggeringObject(AbilityKey.DefendingPlayer, ((Card)defender).getController()); } } - isCombatChanged = true; } + isCombatChanged = true; } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardNameEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardNameEffect.java index a435520bf40..44ade4d4d8d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardNameEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardNameEffect.java @@ -19,7 +19,6 @@ import forge.game.card.CardCollection; import forge.game.card.CardLists; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.util.Aggregates; import forge.util.Localizer; @@ -41,9 +40,6 @@ public class ChooseCardNameEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final Card host = sa.getHostCard(); - final TargetRestrictions tgt = sa.getTargetRestrictions(); - final List tgtPlayers = getTargetPlayers(sa); - String valid = "Card"; String validDesc = null; String message = null; @@ -68,102 +64,103 @@ public class ChooseCardNameEffect extends SpellAbilityEffect { } } - for (final Player p : tgtPlayers) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - String chosen = ""; - //This section was used for Momir Avatar, which no longer uses it - commented out 7/28/2021 - //if (randomChoice) { - //String numericAmount = "X"; - //final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) : - // AbilityUtils.calculateAmount(host, numericAmount, sa); - // Momir needs PaperCard - //Collection cards = StaticData.instance().getCommonCards().getUniqueCards(); - //Predicate cpp = Predicates.and( - // Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES), - // Predicates.compose(CardRulesPredicates.cmc(ComparableOp.EQUALS, validAmount), PaperCard.FN_GET_RULES)); - //cards = Lists.newArrayList(Iterables.filter(cards, cpp)); - //if (!cards.isEmpty()) { chosen = Aggregates.random(cards).getName(); - //} else { - // chosen = ""; - //} - if (chooseFromDefined) { - CardCollection choices = AbilityUtils.getDefinedCards(host, sa.getParam("ChooseFromDefinedCards"), sa); - choices = CardLists.getValidCards(choices, valid, host.getController(), host, sa); - List faces = new ArrayList<>(); - // get Card - for (final Card c : choices) { - final CardRules rules = c.getRules(); - if (faces.contains(rules.getMainPart())) - continue; - faces.add(rules.getMainPart()); - // Alhammarret only allows Split for other faces - if (rules.getSplitType() == CardSplitType.Split) { - faces.add(rules.getOtherPart()); - } + for (final Player p : getTargetPlayers(sa)) { + if (!p.isInGame()) { + continue; + } + String chosen = ""; + //This section was used for Momir Avatar, which no longer uses it - commented out 7/28/2021 + //if (randomChoice) { + //String numericAmount = "X"; + //final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) : + // AbilityUtils.calculateAmount(host, numericAmount, sa); + // Momir needs PaperCard + //Collection cards = StaticData.instance().getCommonCards().getUniqueCards(); + //Predicate cpp = Predicates.and( + // Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES), + // Predicates.compose(CardRulesPredicates.cmc(ComparableOp.EQUALS, validAmount), PaperCard.FN_GET_RULES)); + //cards = Lists.newArrayList(Iterables.filter(cards, cpp)); + //if (!cards.isEmpty()) { chosen = Aggregates.random(cards).getName(); + //} else { + // chosen = ""; + //} + if (chooseFromDefined) { + CardCollection choices = AbilityUtils.getDefinedCards(host, sa.getParam("ChooseFromDefinedCards"), sa); + choices = CardLists.getValidCards(choices, valid, host.getController(), host, sa); + List faces = new ArrayList<>(); + // get Card + for (final Card c : choices) { + final CardRules rules = c.getRules(); + if (faces.contains(rules.getMainPart())) + continue; + faces.add(rules.getMainPart()); + // Alhammarret only allows Split for other faces + if (rules.getSplitType() == CardSplitType.Split) { + faces.add(rules.getOtherPart()); } - Collections.sort(faces); - chosen = p.getController().chooseCardName(sa, faces, message); - } else if (chooseFromList) { - String [] names = sa.getParam("ChooseFromList").split(","); - List faces = new ArrayList<>(); - for (String name : names) { - // Cardnames that include "," must use ";" instead in ChooseFromList$ (i.e. Tovolar; Dire Overlord) - name = name.replace(";", ","); - faces.add(StaticData.instance().getCommonCards().getFaceByName(name)); - } - if (randomChoice) { - chosen = Aggregates.random(faces).getName(); - } else { - chosen = p.getController().chooseCardName(sa, faces, message); - } - } else if (chooseFromOneTimeList) { - String [] names = sa.getParam("ChooseFromOneTimeList").split(","); - List faces = new ArrayList<>(); - for (String name : names) { - faces.add(StaticData.instance().getCommonCards().getFaceByName(name)); - } - chosen = p.getController().chooseCardName(sa, faces, message); - - // Remove chosen Name from List - StringBuilder sb = new StringBuilder(); - for (String name : names) { - if (chosen.equals(name)) continue; - if (sb.length() > 0) sb.append(','); - sb.append(name); - } - sa.putParam("ChooseFromOneTimeList", sb.toString()); + } + Collections.sort(faces); + chosen = p.getController().chooseCardName(sa, faces, message); + } else if (chooseFromList) { + String [] names = sa.getParam("ChooseFromList").split(","); + List faces = new ArrayList<>(); + for (String name : names) { + // Cardnames that include "," must use ";" instead in ChooseFromList$ (i.e. Tovolar; Dire Overlord) + name = name.replace(";", ","); + faces.add(StaticData.instance().getCommonCards().getFaceByName(name)); + } + if (randomChoice) { + chosen = Aggregates.random(faces).getName(); } else { - // use CardFace because you might name a alternate names - Predicate cpp = Predicates.alwaysTrue(); - if (sa.hasParam("ValidCards")) { - //Calculating/replacing this must happen before running valid in CardFacePredicates - if (valid.contains("ManaCost=")) { - if (valid.contains("ManaCost=Equipped")) { - String s = host.getEquipping().getManaCost().getShortString(); - valid = valid.replace("=Equipped", s); - } else if (valid.contains("ManaCost=Imprinted")) { - String s = host.getImprintedCards().getFirst().getManaCost().getShortString(); - valid = valid.replace("=Imprinted", s); - } - } - cpp = CardFacePredicates.valid(valid); - } - if (randomChoice) { - final Iterable cardsFromDb = StaticData.instance().getCommonCards().getAllFaces(); - final List cards = Lists.newArrayList(Iterables.filter(cardsFromDb, cpp)); - chosen = Aggregates.random(cards).getName(); - } else { - chosen = p.getController().chooseCardName(sa, cpp, valid, message); - } + chosen = p.getController().chooseCardName(sa, faces, message); } + } else if (chooseFromOneTimeList) { + String [] names = sa.getParam("ChooseFromOneTimeList").split(","); + List faces = new ArrayList<>(); + for (String name : names) { + faces.add(StaticData.instance().getCommonCards().getFaceByName(name)); + } + chosen = p.getController().chooseCardName(sa, faces, message); - host.setNamedCard(chosen); - if (!randomChoice) { - p.setNamedCard(chosen); + // Remove chosen Name from List + StringBuilder sb = new StringBuilder(); + for (String name : names) { + if (chosen.equals(name)) continue; + if (sb.length() > 0) sb.append(','); + sb.append(name); } - if (sa.hasParam("NoteFor")) { - p.addNoteForName(sa.getParam("NoteFor"), "Name:" + chosen); + sa.putParam("ChooseFromOneTimeList", sb.toString()); + } else { + // use CardFace because you might name a alternate names + Predicate cpp = Predicates.alwaysTrue(); + if (sa.hasParam("ValidCards")) { + //Calculating/replacing this must happen before running valid in CardFacePredicates + if (valid.contains("ManaCost=")) { + if (valid.contains("ManaCost=Equipped")) { + String s = host.getEquipping().getManaCost().getShortString(); + valid = valid.replace("=Equipped", s); + } else if (valid.contains("ManaCost=Imprinted")) { + String s = host.getImprintedCards().getFirst().getManaCost().getShortString(); + valid = valid.replace("=Imprinted", s); + } + } + cpp = CardFacePredicates.valid(valid); } + if (randomChoice) { + final Iterable cardsFromDb = StaticData.instance().getCommonCards().getAllFaces(); + final List cards = Lists.newArrayList(Iterables.filter(cardsFromDb, cpp)); + chosen = Aggregates.random(cards).getName(); + } else { + chosen = p.getController().chooseCardName(sa, cpp, valid, message); + } + } + + host.setNamedCard(chosen); + if (!randomChoice) { + p.setNamedCard(chosen); + } + if (sa.hasParam("NoteFor")) { + p.addNoteForName(sa.getParam("NoteFor"), "Name:" + chosen); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseNumberEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseNumberEffect.java index 6ac1e42e252..f7734aad013 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseNumberEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseNumberEffect.java @@ -12,7 +12,6 @@ import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.util.Localizer; import forge.util.MyRandom; @@ -46,35 +45,34 @@ public class ChooseNumberEffect extends SpellAbilityEffect { final String sMax = sa.getParamOrDefault("Max", "99"); final int max = AbilityUtils.calculateAmount(card, sMax, sa); - final List tgtPlayers = getTargetPlayers(sa); - final TargetRestrictions tgt = sa.getTargetRestrictions(); final Map chooseMap = Maps.newHashMap(); - for (final Player p : tgtPlayers) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - int chosen; - if (random) { - chosen = MyRandom.getRandom().nextInt((max - min) + 1) + min; - //TODO more useful notify for RepeatEach -> ChooseNumber with random - p.getGame().getAction().notifyOfValue(sa, p, Integer.toString(chosen), null); + for (final Player p : getTargetPlayers(sa)) { + if (!p.isInGame()) { + continue; + } + int chosen; + if (random) { + chosen = MyRandom.getRandom().nextInt((max - min) + 1) + min; + //TODO more useful notify for RepeatEach -> ChooseNumber with random + p.getGame().getAction().notifyOfValue(sa, p, Integer.toString(chosen), null); + } else { + String title = sa.hasParam("ListTitle") ? sa.getParam("ListTitle") : Localizer.getInstance().getMessage("lblChooseNumber"); + if (anyNumber) { + Integer value = p.getController().announceRequirements(sa, title); + chosen = value == null ? 0 : value; } else { - String title = sa.hasParam("ListTitle") ? sa.getParam("ListTitle") : Localizer.getInstance().getMessage("lblChooseNumber"); - if (anyNumber) { - Integer value = p.getController().announceRequirements(sa, title); - chosen = value == null ? 0 : value; - } else { - chosen = p.getController().chooseNumber(sa, title, min, max); - } - // don't notify here, because most scripts I've seen don't store that number in a long term - } - if (secretlyChoose) { - chooseMap.put(p, chosen); - } else { - card.setChosenNumber(chosen); - } - if (sa.hasParam("Notify")) { - p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p); + chosen = p.getController().chooseNumber(sa, title, min, max); } + // don't notify here, because most scripts I've seen don't store that number in a long term + } + if (secretlyChoose) { + chooseMap.put(p, chosen); + } else { + card.setChosenNumber(chosen); + } + if (sa.hasParam("Notify")) { + p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p); } } if (secretlyChoose) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChoosePlayerEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChoosePlayerEffect.java index 62dba5b5b40..ae42272e447 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChoosePlayerEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChoosePlayerEffect.java @@ -1,14 +1,12 @@ package forge.game.ability.effects; -import java.util.List; - import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.util.Aggregates; +import forge.util.Lang; import forge.util.Localizer; import forge.util.collect.FCollectionView; @@ -18,9 +16,8 @@ public class ChoosePlayerEffect extends SpellAbilityEffect { protected String getStackDescription(SpellAbility sa) { final StringBuilder sb = new StringBuilder(); - for (final Player p : getTargetPlayers(sa)) { - sb.append(p).append(" "); - } + sb.append(Lang.joinHomogenous(getTargetPlayers(sa))); + sb.append("chooses a player."); return sb.toString(); @@ -30,56 +27,53 @@ public class ChoosePlayerEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final Card card = sa.getHostCard(); - final List tgtPlayers = getTargetPlayers(sa); - - final TargetRestrictions tgt = sa.getTargetRestrictions(); - final FCollectionView choices = sa.hasParam("Choices") ? AbilityUtils.getDefinedPlayers( card, sa.getParam("Choices"), sa) : sa.getActivatingPlayer().getGame().getPlayersInTurnOrder(); final String choiceDesc = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChoosePlayer"); final boolean random = sa.hasParam("Random"); - for (final Player p : tgtPlayers) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - Player chosen; - if (random) { - chosen = choices.isEmpty() ? null : Aggregates.random(choices); + for (final Player p : getTargetPlayers(sa)) { + if (!p.isInGame()) { + continue; + } + Player chosen; + if (random) { + chosen = choices.isEmpty() ? null : Aggregates.random(choices); + } else { + chosen = choices.isEmpty() ? null : p.getController().chooseSingleEntityForEffect(choices, sa, choiceDesc, null); + } + if (null != chosen) { + if (sa.hasParam("Secretly")) { + card.setSecretChosenPlayer(chosen); } else { - chosen = choices.isEmpty() ? null : p.getController().chooseSingleEntityForEffect(choices, sa, choiceDesc, null); + card.setChosenPlayer(chosen); + } + if (sa.hasParam("ForgetOtherRemembered")) { + card.clearRemembered(); + } + if (sa.hasParam("RememberChosen")) { + card.addRemembered(chosen); } - if (null != chosen) { - if (sa.hasParam("Secretly")) { - card.setSecretChosenPlayer(chosen); - } else { - card.setChosenPlayer(chosen); - } - if (sa.hasParam("ForgetOtherRemembered")) { - card.clearRemembered(); - } - if (sa.hasParam("RememberChosen")) { - card.addRemembered(chosen); - } - // SubAbility that only fires if a player is chosen - SpellAbility chosenSA = sa.getAdditionalAbility("ChooseSubAbility"); - if (chosenSA != null) { - if (!chosenSA.getHostCard().equals(sa.getHostCard())) { - System.out.println("Warning: ChooseSubAbility had the wrong host set (potentially after cloning the root SA), attempting to correct..."); - chosenSA.setHostCard(sa.getHostCard()); - } - AbilityUtils.resolve(chosenSA); + // SubAbility that only fires if a player is chosen + SpellAbility chosenSA = sa.getAdditionalAbility("ChooseSubAbility"); + if (chosenSA != null) { + if (!chosenSA.getHostCard().equals(sa.getHostCard())) { + System.out.println("Warning: ChooseSubAbility had the wrong host set (potentially after cloning the root SA), attempting to correct..."); + chosenSA.setHostCard(sa.getHostCard()); } - } else { - // SubAbility that only fires if a player is not chosen - SpellAbility notChosenSA = sa.getAdditionalAbility("CantChooseSubAbility"); - if (notChosenSA != null) { - if (!notChosenSA.getHostCard().equals(sa.getHostCard())) { - System.out.println("Warning: CantChooseSubAbility had the wrong host set (potentially after cloning the root SA), attempting to correct..."); - notChosenSA.setHostCard(sa.getHostCard()); - } - AbilityUtils.resolve(notChosenSA); + AbilityUtils.resolve(chosenSA); + } + } else { + // SubAbility that only fires if a player is not chosen + SpellAbility notChosenSA = sa.getAdditionalAbility("CantChooseSubAbility"); + if (notChosenSA != null) { + if (!notChosenSA.getHostCard().equals(sa.getHostCard())) { + System.out.println("Warning: CantChooseSubAbility had the wrong host set (potentially after cloning the root SA), attempting to correct..."); + notChosenSA.setHostCard(sa.getHostCard()); } + AbilityUtils.resolve(notChosenSA); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseSourceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseSourceEffect.java index 51a845748e4..5f3ea984730 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseSourceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseSourceEffect.java @@ -15,6 +15,7 @@ import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; import forge.game.zone.ZoneType; +import forge.util.Lang; import forge.util.Localizer; public class ChooseSourceEffect extends SpellAbilityEffect { @@ -22,9 +23,8 @@ public class ChooseSourceEffect extends SpellAbilityEffect { protected String getStackDescription(SpellAbility sa) { final StringBuilder sb = new StringBuilder(); - for (final Player p : getTargetPlayers(sa)) { - sb.append(p).append(" "); - } + sb.append(Lang.joinHomogenous(getTargetPlayers(sa))); + sb.append("chooses a source."); return sb.toString(); @@ -129,21 +129,22 @@ public class ChooseSourceEffect extends SpellAbilityEffect { final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) : AbilityUtils.calculateAmount(host, numericAmount, sa); for (final Player p : tgtPlayers) { + if (!p.isInGame()) { + continue; + } final CardCollection chosen = new CardCollection(); - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - for (int i = 0; i < validAmount; i++) { - final String choiceTitle = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseSource") + " "; - Card o = null; - do { - o = p.getController().chooseSingleEntityForEffect(sourcesToChooseFrom, sa, choiceTitle, null); - } while (o == null || o.getName().startsWith("--")); - chosen.add(o); - sourcesToChooseFrom.remove(o); - } - host.setChosenCards(chosen); - if (sa.hasParam("RememberChosen")) { - host.addRemembered(chosen); - } + for (int i = 0; i < validAmount; i++) { + final String choiceTitle = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseSource") + " "; + Card o = null; + do { + o = p.getController().chooseSingleEntityForEffect(sourcesToChooseFrom, sa, choiceTitle, null); + } while (o == null || o.getName().startsWith("--")); + chosen.add(o); + sourcesToChooseFrom.remove(o); + } + host.setChosenCards(chosen); + if (sa.hasParam("RememberChosen")) { + host.addRemembered(chosen); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseTypeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseTypeEffect.java index 1566dcbad69..27bbc775a35 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseTypeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseTypeEffect.java @@ -13,9 +13,9 @@ import forge.game.card.CardCollectionView; import forge.game.card.CardFactoryUtil; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; import forge.util.Aggregates; +import forge.util.Lang; public class ChooseTypeEffect extends SpellAbilityEffect { @@ -24,9 +24,7 @@ public class ChooseTypeEffect extends SpellAbilityEffect { final StringBuilder sb = new StringBuilder(); if (!sa.usesTargeting()) { - for (final Player p : getTargetPlayers(sa)) { - sb.append(p); - } + sb.append(Lang.joinHomogenous(getTargetPlayers(sa))); sb.append(" chooses a ").append(sa.getParam("Type").toLowerCase()).append(" type."); } else { sb.append("Please improve the stack description."); @@ -103,30 +101,26 @@ public class ChooseTypeEffect extends SpellAbilityEffect { } } - final TargetRestrictions tgt = sa.getTargetRestrictions(); - if (validTypes.isEmpty() && sa.hasParam("Note")) { // OK to end up with no choices/have nothing new to note } else if (!validTypes.isEmpty()) { for (final Player p : tgtPlayers) { String choice; - if ((tgt == null) || p.canBeTargetedBy(sa)) { - Player noNotify = p; - if (sa.hasParam("AtRandom")) { - choice = Aggregates.random(validTypes); - noNotify = null; - } else { - choice = p.getController().chooseSomeType(type, sa, validTypes, invalidTypes); - } - if (sa.hasParam("Note")) { - card.addNotedType(choice); - } else if (!sa.hasParam("ChooseType2")) { - card.setChosenType(choice); - } else { - card.setChosenType2(choice); - } - p.getGame().getAction().notifyOfValue(sa, p, choice, noNotify); + Player noNotify = p; + if (sa.hasParam("AtRandom")) { + choice = Aggregates.random(validTypes); + noNotify = null; + } else { + choice = p.getController().chooseSomeType(type, sa, validTypes, invalidTypes); } + if (sa.hasParam("Note")) { + card.addNotedType(choice); + } else if (!sa.hasParam("ChooseType2")) { + card.setChosenType(choice); + } else { + card.setChosenType2(choice); + } + p.getGame().getAction().notifyOfValue(sa, p, choice, noNotify); } } else { throw new InvalidParameterException(sa.getHostCard() + "'s ability resulted in no types to choose from"); diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersPutEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersPutEffect.java index 48854e8b6b3..31e0aa7f217 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CountersPutEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CountersPutEffect.java @@ -453,124 +453,122 @@ public class CountersPutEffect extends SpellAbilityEffect { } counterAmount = sa.usesTargeting() && sa.isDividedAsYouChoose() ? sa.getDividedValue(gameCard) : counterAmount; - if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) { - if (max != -1) { - counterAmount = Math.max(Math.min(max - gameCard.getCounters(counterType), counterAmount), - 0); - } - if (sa.hasParam("UpTo")) { - int min = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("UpToMin", "0"), sa); - Map params = Maps.newHashMap(); - params.put("Target", obj); - params.put("CounterType", counterType); - counterAmount = pc.chooseNumber(sa, - Localizer.getInstance().getMessage("lblHowManyCounters"), min, counterAmount, params); - } - if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) { - Map params = Maps.newHashMap(); - params.put("Target", obj); - params.put("CounterType", counterType); - divrem++; - if (divrem == tgtObjects.size() || counterRemain == 1) { - counterAmount = counterRemain; - } else { - counterAmount = pc.chooseNumber(sa, - Localizer.getInstance().getMessage("lblHowManyCountersThis", - CardTranslation.getTranslatedName(gameCard.getName())), - 1, counterRemain, params); - } - } - - // Adapt need extra logic - if (sa.hasParam("Adapt")) { - if (!(gameCard.getCounters(CounterEnumType.P1P1) == 0 - || StaticAbilityAdapt.anyWithAdapt(sa, gameCard))) { - continue; - } - } - - if (sa.hasParam("ReadAhead")) { - gameCard.setReadAhead(counterAmount); - } - - if (sa.hasParam("Tribute")) { - // make a copy to check if it would be on the battlefield - Card noTributeLKI = CardUtil.getLKICopy(gameCard); - // this check needs to check if this card would be on the battlefield - noTributeLKI.setLastKnownZone(activator.getZone(ZoneType.Battlefield)); - - // double freeze tracker, so it doesn't update view - game.getTracker().freeze(); - - CardCollection preList = new CardCollection(noTributeLKI); - game.getAction().checkStaticAbilities(false, Sets.newHashSet(noTributeLKI), preList); - - boolean abort = !noTributeLKI.canReceiveCounters(counterType); - - game.getAction().checkStaticAbilities(false); - // clear delayed changes, this check should not have updated the view - game.getTracker().clearDelayed(); - // need to unfreeze tracker - game.getTracker().unfreeze(); - - // check if it can receive the Tribute - if (abort) { - continue; - } - - Map params = Maps.newHashMap(); - params.put("CounterType", counterType); - params.put("Amount", counterAmount); - params.put("Target", gameCard); - - String message = Localizer.getInstance().getMessage( - "lblDoYouWantPutTargetP1P1CountersOnCard", String.valueOf(counterAmount), - CardTranslation.getTranslatedName(gameCard.getName())); - Player chooser = pc.chooseSingleEntityForEffect(activator.getOpponents(), sa, - Localizer.getInstance().getMessage("lblChooseAnOpponent"), params); - - if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.Tribute, message, null)) { - gameCard.setTributed(true); - } else { - continue; - } - } - - if (etbcounter) { - gameCard.addEtbCounter(counterType, counterAmount, placer); + if (max != -1) { + counterAmount = Math.max(Math.min(max - gameCard.getCounters(counterType), counterAmount), + 0); + } + if (sa.hasParam("UpTo")) { + int min = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("UpToMin", "0"), sa); + Map params = Maps.newHashMap(); + params.put("Target", obj); + params.put("CounterType", counterType); + counterAmount = pc.chooseNumber(sa, + Localizer.getInstance().getMessage("lblHowManyCounters"), min, counterAmount, params); + } + if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) { + Map params = Maps.newHashMap(); + params.put("Target", obj); + params.put("CounterType", counterType); + divrem++; + if (divrem == tgtObjects.size() || counterRemain == 1) { + counterAmount = counterRemain; } else { - gameCard.addCounter(counterType, counterAmount, placer, table); + counterAmount = pc.chooseNumber(sa, + Localizer.getInstance().getMessage("lblHowManyCountersThis", + CardTranslation.getTranslatedName(gameCard.getName())), + 1, counterRemain, params); + } + } + + // Adapt need extra logic + if (sa.hasParam("Adapt")) { + if (!(gameCard.getCounters(CounterEnumType.P1P1) == 0 + || StaticAbilityAdapt.anyWithAdapt(sa, gameCard))) { + continue; + } + } + + if (sa.hasParam("ReadAhead")) { + gameCard.setReadAhead(counterAmount); + } + + if (sa.hasParam("Tribute")) { + // make a copy to check if it would be on the battlefield + Card noTributeLKI = CardUtil.getLKICopy(gameCard); + // this check needs to check if this card would be on the battlefield + noTributeLKI.setLastKnownZone(activator.getZone(ZoneType.Battlefield)); + + // double freeze tracker, so it doesn't update view + game.getTracker().freeze(); + + CardCollection preList = new CardCollection(noTributeLKI); + game.getAction().checkStaticAbilities(false, Sets.newHashSet(noTributeLKI), preList); + + boolean abort = !noTributeLKI.canReceiveCounters(counterType); + + game.getAction().checkStaticAbilities(false); + // clear delayed changes, this check should not have updated the view + game.getTracker().clearDelayed(); + // need to unfreeze tracker + game.getTracker().unfreeze(); + + // check if it can receive the Tribute + if (abort) { + continue; } - if (sa.hasParam("Evolve")) { - game.getTriggerHandler().runTrigger(TriggerType.Evolved, AbilityKey.mapFromCard(gameCard), - false); - } - if (sa.hasParam("Monstrosity")) { - gameCard.setMonstrous(true); - final Map runParams = AbilityKey.mapFromCard(gameCard); - runParams.put(AbilityKey.MonstrosityAmount, counterAmount); - game.getTriggerHandler().runTrigger(TriggerType.BecomeMonstrous, runParams, false); - } - if (sa.hasParam("Renown")) { - gameCard.setRenowned(true); - game.getTriggerHandler().runTrigger(TriggerType.BecomeRenowned, - AbilityKey.mapFromCard(gameCard), false); - } - if (sa.hasParam("Adapt")) { - game.getTriggerHandler().runTrigger(TriggerType.Adapt, AbilityKey.mapFromCard(gameCard), - false); - } - if (sa.hasParam("Training")) { - game.getTriggerHandler().runTrigger(TriggerType.Trains, AbilityKey.mapFromCard(gameCard), - false); - } + Map params = Maps.newHashMap(); + params.put("CounterType", counterType); + params.put("Amount", counterAmount); + params.put("Target", gameCard); - game.updateLastStateForCard(gameCard); - if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) { - counterRemain = counterRemain - counterAmount; + String message = Localizer.getInstance().getMessage( + "lblDoYouWantPutTargetP1P1CountersOnCard", String.valueOf(counterAmount), + CardTranslation.getTranslatedName(gameCard.getName())); + Player chooser = pc.chooseSingleEntityForEffect(activator.getOpponents(), sa, + Localizer.getInstance().getMessage("lblChooseAnOpponent"), params); + + if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.Tribute, message, null)) { + gameCard.setTributed(true); + } else { + continue; } } + + if (etbcounter) { + gameCard.addEtbCounter(counterType, counterAmount, placer); + } else { + gameCard.addCounter(counterType, counterAmount, placer, table); + } + + if (sa.hasParam("Evolve")) { + game.getTriggerHandler().runTrigger(TriggerType.Evolved, AbilityKey.mapFromCard(gameCard), + false); + } + if (sa.hasParam("Monstrosity")) { + gameCard.setMonstrous(true); + final Map runParams = AbilityKey.mapFromCard(gameCard); + runParams.put(AbilityKey.MonstrosityAmount, counterAmount); + game.getTriggerHandler().runTrigger(TriggerType.BecomeMonstrous, runParams, false); + } + if (sa.hasParam("Renown")) { + gameCard.setRenowned(true); + game.getTriggerHandler().runTrigger(TriggerType.BecomeRenowned, + AbilityKey.mapFromCard(gameCard), false); + } + if (sa.hasParam("Adapt")) { + game.getTriggerHandler().runTrigger(TriggerType.Adapt, AbilityKey.mapFromCard(gameCard), + false); + } + if (sa.hasParam("Training")) { + game.getTriggerHandler().runTrigger(TriggerType.Trains, AbilityKey.mapFromCard(gameCard), + false); + } + + game.updateLastStateForCard(gameCard); + if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) { + counterRemain = counterRemain - counterAmount; + } } else if (obj instanceof Player) { // Add Counters to players! Player pl = (Player) obj; diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java index c3de8c42ad2..e17cd12cc04 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java @@ -103,21 +103,22 @@ public class CountersRemoveEffect extends SpellAbilityEffect { boolean rememberAmount = sa.hasParam("RememberAmount"); for (final Player tgtPlayer : getTargetPlayers(sa)) { + if (!tgtPlayer.isInGame()) { + continue; + } // Removing energy - if (!sa.usesTargeting() || tgtPlayer.canBeTargetedBy(sa)) { - if (type.equals("All")) { - for (Map.Entry e : Lists.newArrayList(tgtPlayer.getCounters().entrySet())) { - tgtPlayer.subtractCounter(e.getKey(), e.getValue()); - } + if (type.equals("All")) { + for (Map.Entry e : Lists.newArrayList(tgtPlayer.getCounters().entrySet())) { + tgtPlayer.subtractCounter(e.getKey(), e.getValue()); + } + } else { + if (num.equals("All")) { + cntToRemove = tgtPlayer.getCounters(counterType); + } + if (type.equals("Any")) { + removeAnyType(tgtPlayer, cntToRemove, sa); } else { - if (num.equals("All")) { - cntToRemove = tgtPlayer.getCounters(counterType); - } - if (type.equals("Any")) { - removeAnyType(tgtPlayer, cntToRemove, sa); - } else { - tgtPlayer.subtractCounter(counterType, cntToRemove); - } + tgtPlayer.subtractCounter(counterType, cntToRemove); } } } @@ -160,44 +161,42 @@ public class CountersRemoveEffect extends SpellAbilityEffect { if (gameCard == null || !tgtCard.equalsWithTimestamp(gameCard)) { continue; } - if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) { - final Zone zone = game.getZoneOf(gameCard); - if (type.equals("All")) { - for (Map.Entry e : Lists.newArrayList(gameCard.getCounters().entrySet())) { - gameCard.subtractCounter(e.getKey(), e.getValue()); + final Zone zone = game.getZoneOf(gameCard); + if (type.equals("All")) { + for (Map.Entry e : Lists.newArrayList(gameCard.getCounters().entrySet())) { + gameCard.subtractCounter(e.getKey(), e.getValue()); + } + game.updateLastStateForCard(gameCard); + continue; + } else if (num.equals("All") || num.equals("Any")) { + cntToRemove = gameCard.getCounters(counterType); + } + + if (type.equals("Any")) { + removeAnyType(gameCard, cntToRemove, sa); + } else { + cntToRemove = Math.min(cntToRemove, gameCard.getCounters(counterType)); + + if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) { + if (sa.hasParam("UpTo") || num.equals("Any")) { + Map params = Maps.newHashMap(); + params.put("Target", gameCard); + params.put("CounterType", counterType); + title = Localizer.getInstance().getMessage("lblSelectRemoveCountersNumberOfTarget", type); + cntToRemove = pc.chooseNumber(sa, title, 0, cntToRemove, params); + } + } + if (cntToRemove > 0) { + gameCard.subtractCounter(counterType, cntToRemove); + if (rememberRemoved) { + for (int i = 0; i < cntToRemove; i++) { + // TODO might need to be more specific + card.addRemembered(Pair.of(counterType, i)); + } } game.updateLastStateForCard(gameCard); - continue; - } else if (num.equals("All") || num.equals("Any")) { - cntToRemove = gameCard.getCounters(counterType); - } - if (type.equals("Any")) { - removeAnyType(gameCard, cntToRemove, sa); - } else { - cntToRemove = Math.min(cntToRemove, gameCard.getCounters(counterType)); - - if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) { - if (sa.hasParam("UpTo") || num.equals("Any")) { - Map params = Maps.newHashMap(); - params.put("Target", gameCard); - params.put("CounterType", counterType); - title = Localizer.getInstance().getMessage("lblSelectRemoveCountersNumberOfTarget", type); - cntToRemove = pc.chooseNumber(sa, title, 0, cntToRemove, params); - } - } - if (cntToRemove > 0) { - gameCard.subtractCounter(counterType, cntToRemove); - if (rememberRemoved) { - for (int i = 0; i < cntToRemove; i++) { - // TODO might need to be more specific - card.addRemembered(Pair.of(counterType, i)); - } - } - game.updateLastStateForCard(gameCard); - - totalRemoved += cntToRemove; - } + totalRemoved += cntToRemove; } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/DebuffEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DebuffEffect.java index 4da99ed62ea..5f2597531fc 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DebuffEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DebuffEffect.java @@ -69,80 +69,92 @@ public class DebuffEffect extends SpellAbilityEffect { final long timestamp = game.getNextTimestamp(); for (final Card tgtC : getTargetCards(sa)) { + if (!tgtC.isInPlay()) { + continue; + } if (tgtC.isPhasedOut()) { continue; } + // check if the object is still in game or if it was moved + Card gameCard = game.getCardState(tgtC, null); + // gameCard is LKI in that case, the card is not in game anymore + // or the timestamp did change + // this should check Self too + if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard)) { + continue; + } + final List addedKW = Lists.newArrayList(); final List removedKW = Lists.newArrayList(); - if (tgtC.isInPlay() && (!sa.usesTargeting() || tgtC.canBeTargetedBy(sa))) { - if (sa.hasParam("AllSuffixKeywords")) { - // this only for walk abilities, may to try better - if (sa.getParam("AllSuffixKeywords").equals("walk")) { - for (final KeywordInterface kw : tgtC.getKeywords(Keyword.LANDWALK)) { - removedKW.add(kw.getOriginal()); - } + + if (sa.hasParam("AllSuffixKeywords")) { + // this only for walk abilities, may to try better + if (sa.getParam("AllSuffixKeywords").equals("walk")) { + for (final KeywordInterface kw : tgtC.getKeywords(Keyword.LANDWALK)) { + removedKW.add(kw.getOriginal()); } } + } - // special for Protection:Card.:Protection from :* - for (final KeywordInterface inst : tgtC.getUnhiddenKeywords()) { - String keyword = inst.getOriginal(); - if (keyword.startsWith("Protection:")) { - for (final String kw : kws) { - if (keyword.matches("(?i).*:" + kw)) - removedKW.add(keyword); - } + // special for Protection:Card.:Protection from :* + for (final KeywordInterface inst : tgtC.getUnhiddenKeywords()) { + String keyword = inst.getOriginal(); + if (keyword.startsWith("Protection:")) { + for (final String kw : kws) { + if (keyword.matches("(?i).*:" + kw)) + removedKW.add(keyword); } } + } - boolean ProtectionFromColor = false; - for (final String kw : kws) { - // Check if some of the Keywords are Protection from - if (!ProtectionFromColor && kw.startsWith("Protection from ")) { - for (byte col : MagicColor.WUBRG) { - final String colString = MagicColor.toLongString(col); - if (kw.endsWith(colString.toLowerCase())) { - ProtectionFromColor = true; - } - } - } - } - - // Split "Protection from all colors" into extra Protection from - String allColors = "Protection from all colors"; - if (ProtectionFromColor && tgtC.hasKeyword(allColors)) { - final List allColorsProtect = Lists.newArrayList(); - - for (byte col : MagicColor.WUBRG) { - allColorsProtect.add("Protection from " + MagicColor.toLongString(col).toLowerCase()); - } - allColorsProtect.removeAll(kws); - addedKW.addAll(allColorsProtect); - removedKW.add(allColors); - } - - // Extra for Spectra Ward - allColors = "Protection:Card.nonColorless:Protection from all colors:Aura"; - if (ProtectionFromColor && tgtC.hasKeyword(allColors)) { - final List allColorsProtect = Lists.newArrayList(); - + boolean ProtectionFromColor = false; + for (final String kw : kws) { + // Check if some of the Keywords are Protection from + if (!ProtectionFromColor && kw.startsWith("Protection from ")) { for (byte col : MagicColor.WUBRG) { final String colString = MagicColor.toLongString(col); - if (!kws.contains("Protection from " + colString)) { - allColorsProtect.add( - "Protection:Card." + StringUtils.capitalize(colString) + - ":Protection from " + colString + ":Aura" - ); + if (kw.endsWith(colString.toLowerCase())) { + ProtectionFromColor = true; } } - addedKW.addAll(allColorsProtect); - removedKW.add(allColors); } - - removedKW.addAll(kws); - tgtC.addChangedCardKeywords(addedKW, removedKW, false, timestamp, 0); } + + // Split "Protection from all colors" into extra Protection from + String allColors = "Protection from all colors"; + if (ProtectionFromColor && tgtC.hasKeyword(allColors)) { + final List allColorsProtect = Lists.newArrayList(); + + for (byte col : MagicColor.WUBRG) { + allColorsProtect.add("Protection from " + MagicColor.toLongString(col).toLowerCase()); + } + allColorsProtect.removeAll(kws); + addedKW.addAll(allColorsProtect); + removedKW.add(allColors); + } + + // Extra for Spectra Ward + allColors = "Protection:Card.nonColorless:Protection from all colors:Aura"; + if (ProtectionFromColor && tgtC.hasKeyword(allColors)) { + final List allColorsProtect = Lists.newArrayList(); + + for (byte col : MagicColor.WUBRG) { + final String colString = MagicColor.toLongString(col); + if (!kws.contains("Protection from " + colString)) { + allColorsProtect.add( + "Protection:Card." + StringUtils.capitalize(colString) + + ":Protection from " + colString + ":Aura" + ); + } + } + addedKW.addAll(allColorsProtect); + removedKW.add(allColors); + } + + removedKW.addAll(kws); + tgtC.addChangedCardKeywords(addedKW, removedKW, false, timestamp, 0); + if (!"Permanent".equals(sa.getParam("Duration"))) { final GameCommand until = new GameCommand() { private static final long serialVersionUID = 5387486776282932314L; @@ -155,6 +167,6 @@ public class DebuffEffect extends SpellAbilityEffect { addUntilCommand(sa, until); } } - } // debuffResolve + } } 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 35a846ef8f2..5f10f698d1c 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 @@ -122,146 +122,144 @@ public class DigUntilEffect extends SpellAbilityEffect { CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); for (final Player p : getTargetPlayers(sa)) { - if (p == null) { + if (p == null || !p.isInGame()) { continue; } - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - if (optional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantDigYourLibrary"), null)) { - continue; + if (optional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantDigYourLibrary"), null)) { + continue; + } + CardCollection found = new CardCollection(); + CardCollection revealed = new CardCollection(); + + final PlayerZone library = p.getZone(digSite); + + final int maxToDig = maxRevealed != null ? maxRevealed : library.size(); + + for (int i = 0; i < maxToDig; i++) { + final Card c = library.get(i); + revealed.add(c); + if (c.isValid(type, sa.getActivatingPlayer(), host, sa)) { + found.add(c); + if (sa.hasParam("ForgetOtherRemembered")) { + host.clearRemembered(); + } + if (remember) { + host.addRemembered(c); + } + if (imprint) { + host.addImprintedCard(c); + } + if (found.size() == untilAmount) { + break; + } } - CardCollection found = new CardCollection(); - CardCollection revealed = new CardCollection(); + } - final PlayerZone library = p.getZone(digSite); + if (shuffle && sa.hasParam("ShuffleCondition")) { + if (sa.getParam("ShuffleCondition").equals("NoneFound")) { + shuffle = found.isEmpty(); + } + } - final int maxToDig = maxRevealed != null ? maxRevealed : library.size(); + if (revealed.size() > 0) { + game.getAction().reveal(revealed, p, false); + } - for (int i = 0; i < maxToDig; i++) { - final Card c = library.get(i); - revealed.add(c); - if (c.isValid(type, sa.getActivatingPlayer(), host, sa)) { - found.add(c); - if (sa.hasParam("ForgetOtherRemembered")) { - host.clearRemembered(); + if (foundDest != null) { + // Allow ordering of found cards + if (foundDest.isKnown() && found.size() >= 2 && !foundDest.equals(ZoneType.Exile)) { + found = (CardCollection)p.getController().orderMoveToZoneList(found, foundDest, sa); + } + + final Iterator itr = found.iterator(); + while (itr.hasNext()) { + final Card c = itr.next(); + final ZoneType origin = c.getZone().getZoneType(); + if (optionalFound && !p.getController().confirmAction(sa, null, + Localizer.getInstance().getMessage("lblDoYouWantPutCardToZone", foundDest.getTranslatedName()), null)) { + continue; + } + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); + moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); + Card m = null; + if (sa.hasParam("GainControl") && foundDest.equals(ZoneType.Battlefield)) { + c.setController(sa.getActivatingPlayer(), game.getNextTimestamp()); + if (sa.hasParam("Tapped")) { + c.setTapped(true); } - if (remember) { - host.addRemembered(c); - } - if (imprint) { - host.addImprintedCard(c); - } - if (found.size() == untilAmount) { - break; + m = game.getAction().moveTo(c.getController().getZone(foundDest), c, sa, moveParams); + if (addToCombat(c, c.getController(), sa, "Attacking", "Blocking")) { + combatChanged = true; } + } else if (sa.hasParam("NoMoveFound") && foundDest.equals(ZoneType.Library)) { + //Don't do anything + } else { + m = game.getAction().moveTo(foundDest, c, foundLibPos, sa, moveParams); + } + revealed.remove(c); + if (m != null && !origin.equals(m.getZone().getZoneType())) { + table.put(origin, m.getZone().getZoneType(), m); } } + } - if (shuffle && sa.hasParam("ShuffleCondition")) { - if (sa.getParam("ShuffleCondition").equals("NoneFound")) { - shuffle = found.isEmpty(); - } + if (sa.hasParam("RememberRevealed")) { + host.addRemembered(revealed); + } + if (sa.hasParam("ImprintRevealed")) { + host.addImprintedCards(revealed); + } + if (sa.hasParam("RevealRandomOrder")) { + Collections.shuffle(revealed, MyRandom.getRandom()); + } + + if (sa.hasParam("NoMoveRevealed")) { + //don't do anything + } else if (sa.hasParam("NoneFoundDestination") && found.size() < untilAmount) { + // Allow ordering the revealed cards + if (noneFoundDest.isKnown() && revealed.size() >= 2) { + revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa); + } + if (noneFoundDest == ZoneType.Library && !shuffle + && !sa.hasParam("RevealRandomOrder") && revealed.size() >= 2) { + revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa); } - if (revealed.size() > 0) { - game.getAction().reveal(revealed, p, false); - } - - if (foundDest != null) { - // Allow ordering of found cards - if (foundDest.isKnown() && found.size() >= 2 && !foundDest.equals(ZoneType.Exile)) { - found = (CardCollection)p.getController().orderMoveToZoneList(found, foundDest, sa); - } - - final Iterator itr = found.iterator(); - while (itr.hasNext()) { - final Card c = itr.next(); - final ZoneType origin = c.getZone().getZoneType(); - if (optionalFound && !p.getController().confirmAction(sa, null, - Localizer.getInstance().getMessage("lblDoYouWantPutCardToZone", foundDest.getTranslatedName()), null)) { - continue; - } - Map moveParams = AbilityKey.newMap(); - moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); - moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); - Card m = null; - if (sa.hasParam("GainControl") && foundDest.equals(ZoneType.Battlefield)) { - c.setController(sa.getActivatingPlayer(), game.getNextTimestamp()); - if (sa.hasParam("Tapped")) { - c.setTapped(true); - } - m = game.getAction().moveTo(c.getController().getZone(foundDest), c, sa, moveParams); - if (addToCombat(c, c.getController(), sa, "Attacking", "Blocking")) { - combatChanged = true; - } - } else if (sa.hasParam("NoMoveFound") && foundDest.equals(ZoneType.Library)) { - //Don't do anything - } else { - m = game.getAction().moveTo(foundDest, c, foundLibPos, sa, moveParams); - } - revealed.remove(c); - if (m != null && !origin.equals(m.getZone().getZoneType())) { - table.put(origin, m.getZone().getZoneType(), m); - } + final Iterator itr = revealed.iterator(); + while (itr.hasNext()) { + final Card c = itr.next(); + final ZoneType origin = c.getZone().getZoneType(); + final Card m = game.getAction().moveTo(noneFoundDest, c, noneFoundLibPos, sa); + if (m != null && !origin.equals(m.getZone().getZoneType())) { + table.put(origin, m.getZone().getZoneType(), m); } } - - if (sa.hasParam("RememberRevealed")) { - host.addRemembered(revealed); + } else { + // Allow ordering the rest of the revealed cards + if (revealedDest.isKnown() && revealed.size() >= 2 && !sa.hasParam("SkipReorder")) { + revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest, sa); } - if (sa.hasParam("ImprintRevealed")) { - host.addImprintedCards(revealed); - } - if (sa.hasParam("RevealRandomOrder")) { - Collections.shuffle(revealed, MyRandom.getRandom()); + if (revealedDest == ZoneType.Library && !shuffle + && !sa.hasParam("RevealRandomOrder") && revealed.size() >= 2) { + revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest, sa); } - if (sa.hasParam("NoMoveRevealed")) { - //don't do anything - } else if (sa.hasParam("NoneFoundDestination") && found.size() < untilAmount) { - // Allow ordering the revealed cards - if (noneFoundDest.isKnown() && revealed.size() >= 2) { - revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa); - } - if (noneFoundDest == ZoneType.Library && !shuffle - && !sa.hasParam("RevealRandomOrder") && revealed.size() >= 2) { - revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa); - } - - final Iterator itr = revealed.iterator(); - while (itr.hasNext()) { - final Card c = itr.next(); - final ZoneType origin = c.getZone().getZoneType(); - final Card m = game.getAction().moveTo(noneFoundDest, c, noneFoundLibPos, sa); - if (m != null && !origin.equals(m.getZone().getZoneType())) { - table.put(origin, m.getZone().getZoneType(), m); - } - } - } else { - // Allow ordering the rest of the revealed cards - if (revealedDest.isKnown() && revealed.size() >= 2 && !sa.hasParam("SkipReorder")) { - revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest, sa); - } - if (revealedDest == ZoneType.Library && !shuffle - && !sa.hasParam("RevealRandomOrder") && revealed.size() >= 2) { - revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest, sa); - } - - final Iterator itr = revealed.iterator(); - while (itr.hasNext()) { - final Card c = itr.next(); - final ZoneType origin = c.getZone().getZoneType(); - final Card m = game.getAction().moveTo(revealedDest, c, revealedLibPos, sa); - if (m != null && !origin.equals(m.getZone().getZoneType())) { - table.put(origin, m.getZone().getZoneType(), m); - } + final Iterator itr = revealed.iterator(); + while (itr.hasNext()) { + final Card c = itr.next(); + final ZoneType origin = c.getZone().getZoneType(); + final Card m = game.getAction().moveTo(revealedDest, c, revealedLibPos, sa); + if (m != null && !origin.equals(m.getZone().getZoneType())) { + table.put(origin, m.getZone().getZoneType(), m); } } + } - if (shuffle) { - p.shuffle(sa); - } - } // end foreach player - } + if (shuffle) { + p.shuffle(sa); + } + } // end foreach player if (combatChanged) { game.updateCombatForView(); game.fireEvent(new GameEventCombatChanged()); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java index 5c84eb8d5d7..a6b8da19bd4 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java @@ -37,39 +37,37 @@ public class ManifestEffect extends SpellAbilityEffect { moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); for (final Player p : getTargetPlayers(sa, "DefinedPlayer")) { - if (sa.usesTargeting() || p.canBeTargetedBy(sa)) { - CardCollection tgtCards; - if (sa.hasParam("Choices") || sa.hasParam("ChoiceZone")) { - ZoneType choiceZone = ZoneType.Hand; - if (sa.hasParam("ChoiceZone")) { - choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone")); - } - CardCollection choices = new CardCollection(game.getCardsIn(choiceZone)); - if (sa.hasParam("Choices")) { - choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, source, sa); - } - if (choices.isEmpty()) { - continue; - } - - String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseCardToManifest") + " "; - - tgtCards = new CardCollection(activator.getController().chooseCardsForEffect(choices, sa, title, amount, amount, false, null)); - } else if ("TopOfLibrary".equals(defined)) { - tgtCards = p.getTopXCardsFromLibrary(amount); - } else { - tgtCards = getTargetCards(sa); + CardCollection tgtCards; + if (sa.hasParam("Choices") || sa.hasParam("ChoiceZone")) { + ZoneType choiceZone = ZoneType.Hand; + if (sa.hasParam("ChoiceZone")) { + choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone")); + } + CardCollection choices = new CardCollection(game.getCardsIn(choiceZone)); + if (sa.hasParam("Choices")) { + choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, source, sa); + } + if (choices.isEmpty()) { + continue; } - if (sa.hasParam("Shuffle")) { - CardLists.shuffle(tgtCards); - } + String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseCardToManifest") + " "; - for (Card c : tgtCards) { - Card rem = c.manifest(p, sa, moveParams); - if (sa.hasParam("RememberManifested") && rem != null && rem.isManifested()) { - source.addRemembered(rem); - } + tgtCards = new CardCollection(activator.getController().chooseCardsForEffect(choices, sa, title, amount, amount, false, null)); + } else if ("TopOfLibrary".equals(defined)) { + tgtCards = p.getTopXCardsFromLibrary(amount); + } else { + tgtCards = getTargetCards(sa); + } + + if (sa.hasParam("Shuffle")) { + CardLists.shuffle(tgtCards); + } + + for (Card c : tgtCards) { + Card rem = c.manifest(p, sa, moveParams); + if (sa.hasParam("RememberManifested") && rem != null && rem.isManifested()) { + source.addRemembered(rem); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/MillEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MillEffect.java index fc8ae802494..1c10c907809 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/MillEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/MillEffect.java @@ -44,44 +44,46 @@ public class MillEffect extends SpellAbilityEffect { moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); for (final Player p : getTargetPlayers(sa)) { - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - if (sa.hasParam("Optional")) { - final String prompt = TextUtil.concatWithSpace(Localizer.getInstance().getMessage("lblDoYouWantPutLibraryCardsTo", destination.getTranslatedName())); - // CR 701.13b - if (numCards > p.getZone(ZoneType.Library).size() || !p.getController().confirmAction(sa, null, prompt, null)) { - continue; + if (!p.isInGame()) { + continue; + } + + if (sa.hasParam("Optional")) { + final String prompt = TextUtil.concatWithSpace(Localizer.getInstance().getMessage("lblDoYouWantPutLibraryCardsTo", destination.getTranslatedName())); + // CR 701.13b + if (numCards > p.getZone(ZoneType.Library).size() || !p.getController().confirmAction(sa, null, prompt, null)) { + continue; + } + } + final CardCollectionView milled = p.mill(numCards, destination, bottom, sa, table, moveParams); + // Reveal the milled cards, so players don't have to manually inspect the + // graveyard to figure out which ones were milled. + if (!facedown && reveal) { // do not reveal when exiling face down + if (showRevealDialog) { + game.getAction().reveal(milled, p, false); + } + StringBuilder sb = new StringBuilder(); + sb.append(p).append(" milled ").append(milled).append(" to ").append(destination); + p.getGame().getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString()); + } + if (destination.equals(ZoneType.Exile)) { + Card host = sa.getOriginalHost(); + if (host == null) { + host = sa.getHostCard(); + } + for (final Card c : milled) { + host.addExiledCard(c); + c.setExiledWith(host); + if (facedown) { + c.turnFaceDown(true); } } - final CardCollectionView milled = p.mill(numCards, destination, bottom, sa, table, moveParams); - // Reveal the milled cards, so players don't have to manually inspect the - // graveyard to figure out which ones were milled. - if (!facedown && reveal) { // do not reveal when exiling face down - if (showRevealDialog) { - game.getAction().reveal(milled, p, false); - } - StringBuilder sb = new StringBuilder(); - sb.append(p).append(" milled ").append(milled).append(" to ").append(destination); - p.getGame().getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString()); - } - if (destination.equals(ZoneType.Exile)) { - Card host = sa.getOriginalHost(); - if (host == null) { - host = sa.getHostCard(); - } - for (final Card c : milled) { - host.addExiledCard(c); - c.setExiledWith(host); - if (facedown) { - c.turnFaceDown(true); - } - } - } - if (sa.hasParam("RememberMilled")) { - source.addRemembered(milled); - } - if (sa.hasParam("Imprint")) { - source.addImprintedCards(milled); - } + } + if (sa.hasParam("RememberMilled")) { + source.addRemembered(milled); + } + if (sa.hasParam("Imprint")) { + source.addImprintedCards(milled); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/MultiplePilesEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MultiplePilesEffect.java index 4337646f372..bc5f14882ea 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/MultiplePilesEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/MultiplePilesEffect.java @@ -16,7 +16,6 @@ import forge.game.card.CardCollectionView; import forge.game.card.CardLists; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; import forge.util.Aggregates; import forge.util.Localizer; @@ -56,7 +55,6 @@ public class MultiplePilesEffect extends SpellAbilityEffect { final String valid = sa.getParamOrDefault("ValidCards", ""); - final TargetRestrictions tgt = sa.getTargetRestrictions(); final List tgtPlayers = getTargetPlayers(sa); // starting with the activator int pSize = tgtPlayers.size(); @@ -66,28 +64,30 @@ public class MultiplePilesEffect extends SpellAbilityEffect { } for (final Player p : tgtPlayers) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - CardCollection pool; - if (sa.hasParam("DefinedCards")) { - pool = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa); - } else { - pool = new CardCollection(p.getCardsIn(zone)); - } - pool = CardLists.getValidCards(pool, valid, source.getController(), source, sa); - - List pileList = Lists.newArrayList(); - - for (int i = 1; i < piles; i++) { - int size = pool.size(); - CardCollectionView pile = p.getController().chooseCardsForEffect(pool, sa, Localizer.getInstance().getMessage("lblChooseCardsInTargetPile", String.valueOf(i)), 0, size, false, null); - pileList.add(pile); - pool.removeAll(pile); - } - - pileList.add(pool); - p.getGame().getAction().notifyOfValue(sa, p, pileList.toString(), p); - record.put(p, pileList); + if (!p.isInGame()) { + continue; } + + CardCollection pool; + if (sa.hasParam("DefinedCards")) { + pool = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa); + } else { + pool = new CardCollection(p.getCardsIn(zone)); + } + pool = CardLists.getValidCards(pool, valid, source.getController(), source, sa); + + List pileList = Lists.newArrayList(); + + for (int i = 1; i < piles; i++) { + int size = pool.size(); + CardCollectionView pile = p.getController().chooseCardsForEffect(pool, sa, Localizer.getInstance().getMessage("lblChooseCardsInTargetPile", String.valueOf(i)), 0, size, false, null); + pileList.add(pile); + pool.removeAll(pile); + } + + pileList.add(pool); + p.getGame().getAction().notifyOfValue(sa, p, pileList.toString(), p); + record.put(p, pileList); } if (randomChosen) { for (Entry> ev : record.entrySet()) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java index d157cde5960..635602b0dfd 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java @@ -39,7 +39,7 @@ public class ProtectAllEffect extends SpellAbilityEffect { } return sb.toString(); - } // protectStackDescription() + } @Override public void resolve(SpellAbility sa) { @@ -83,27 +83,24 @@ public class ProtectAllEffect extends SpellAbilityEffect { // Deal with permanents final String valid = sa.getParamOrDefault("ValidCards", ""); if (!valid.equals("")) { - CardCollectionView list = game.getCardsIn(ZoneType.Battlefield); - list = CardLists.getValidCards(list, valid, sa.getActivatingPlayer(), host, sa); + CardCollectionView list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), host, sa); for (final Card tgtC : list) { - if (tgtC.isInPlay()) { - tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, 0, true); + tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, 0, true); - if (!"Permanent".equals(sa.getParam("Duration"))) { - // If not Permanent, remove protection at EOT - final GameCommand untilEOT = new GameCommand() { - private static final long serialVersionUID = -6573962672873853565L; + if (!"Permanent".equals(sa.getParam("Duration"))) { + // If not Permanent, remove protection at EOT + final GameCommand untilEOT = new GameCommand() { + private static final long serialVersionUID = -6573962672873853565L; - @Override - public void run() { - if (tgtC.isInPlay()) { - tgtC.removeChangedCardKeywords(timestamp, 0, true); - } + @Override + public void run() { + if (tgtC.isInPlay()) { + tgtC.removeChangedCardKeywords(timestamp, 0, true); } - }; - addUntilCommand(sa, untilEOT); - } + } + }; + addUntilCommand(sa, untilEOT); } } } @@ -111,11 +108,8 @@ public class ProtectAllEffect extends SpellAbilityEffect { // Deal with Players final String players = sa.getParamOrDefault("ValidPlayers", ""); if (!players.equals("")) { - final List playerList = AbilityUtils.getDefinedPlayers(host, players, sa); - for (final Player player : playerList) { - for (final String gain : gains) { - player.addChangedKeywords(ImmutableList.of("Protection from " + gain), ImmutableList.of(), timestamp, 0); - } + for (final Player player : AbilityUtils.getDefinedPlayers(host, players, sa)) { + player.addChangedKeywords(gainsKWList, ImmutableList.of(), timestamp, 0); if (!"Permanent".equals(sa.getParam("Duration"))) { // If not Permanent, remove protection at EOT diff --git a/forge-game/src/main/java/forge/game/ability/effects/RemoveFromCombatEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RemoveFromCombatEffect.java index 82a377a84f6..dba17adcc12 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RemoveFromCombatEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RemoveFromCombatEffect.java @@ -12,7 +12,6 @@ import forge.game.card.CardCollection; import forge.game.combat.Combat; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; public class RemoveFromCombatEffect extends SpellAbilityEffect { @@ -34,37 +33,38 @@ public class RemoveFromCombatEffect extends SpellAbilityEffect { final Player activator = sa.getActivatingPlayer(); final Game game = activator.getGame(); final boolean rem = sa.hasParam("RememberRemovedFromCombat"); + final Combat combat = game.getPhaseHandler().getCombat(); - final TargetRestrictions tgt = sa.getTargetRestrictions(); for (final Card c : getTargetCards(sa)) { - final Combat combat = game.getPhaseHandler().getCombat(); - if (combat != null && (tgt == null || c.canBeTargetedBy(sa))) { - // Unblock creatures that were blocked only by this card (e.g. Ydwen Efreet) - if (sa.hasParam("UnblockCreaturesBlockedOnlyBy")) { - CardCollection attackers = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("UnblockCreaturesBlockedOnlyBy"), sa); - if (!attackers.isEmpty()) { - CardCollection blockedByCard = combat.getAttackersBlockedBy(attackers.getFirst()); - for (Card atk : blockedByCard) { - boolean blockedOnlyByCard = true; - for (Card blocker : combat.getBlockers(atk)) { - if (!blocker.equals(attackers.getFirst())) { - blockedOnlyByCard = false; - break; - } - } - if (blockedOnlyByCard) { - combat.setBlocked(atk, false); + if (combat == null || !c.isInPlay()) { + continue; + } + + // Unblock creatures that were blocked only by this card (e.g. Ydwen Efreet) + if (sa.hasParam("UnblockCreaturesBlockedOnlyBy")) { + CardCollection attackers = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("UnblockCreaturesBlockedOnlyBy"), sa); + if (!attackers.isEmpty()) { + CardCollection blockedByCard = combat.getAttackersBlockedBy(attackers.getFirst()); + for (Card atk : blockedByCard) { + boolean blockedOnlyByCard = true; + for (Card blocker : combat.getBlockers(atk)) { + if (!blocker.equals(attackers.getFirst())) { + blockedOnlyByCard = false; + break; } } + if (blockedOnlyByCard) { + combat.setBlocked(atk, false); + } } } + } - game.getCombat().saveLKI(c); - combat.removeFromCombat(c); + game.getCombat().saveLKI(c); + combat.removeFromCombat(c); - if (rem) { - sa.getHostCard().addRemembered(c); - } + if (rem) { + sa.getHostCard().addRemembered(c); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RevealEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RevealEffect.java index 87e53bb36d6..f29d2dcc9f9 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RevealEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RevealEffect.java @@ -29,76 +29,77 @@ public class RevealEffect extends SpellAbilityEffect { int cnt = sa.hasParam("NumCards") ? AbilityUtils.calculateAmount(host, sa.getParam("NumCards"), sa) : 1; for (final Player p : getTargetPlayers(sa)) { - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - final CardCollectionView cardsInHand = p.getZone(ZoneType.Hand).getCards(); - if (cardsInHand.isEmpty()) { + if (!p.isInGame()) { + continue; + } + final CardCollectionView cardsInHand = p.getZone(ZoneType.Hand).getCards(); + if (cardsInHand.isEmpty()) { + continue; + } + final CardCollection revealed = new CardCollection(); + if (sa.hasParam("Random")) { + CardCollection valid = new CardCollection(cardsInHand); + + if (sa.hasParam("RevealValid")) { + valid = CardLists.getValidCards(valid, sa.getParam("RevealValid"), p, host, sa); + } + + if (valid.isEmpty()) continue; - } - final CardCollection revealed = new CardCollection(); - if (sa.hasParam("Random")) { - CardCollection valid = new CardCollection(cardsInHand); - if (sa.hasParam("RevealValid")) { - valid = CardLists.getValidCards(valid, sa.getParam("RevealValid"), p, host, sa); + if (sa.hasParam("NumCards")) { + final int revealnum = Math.min(cardsInHand.size(), cnt); + for (int i = 0; i < revealnum; i++) { + final Card random = Aggregates.random(valid); + revealed.add(random); + valid.remove(random); } - - if (valid.isEmpty()) - continue; - - if (sa.hasParam("NumCards")) { - final int revealnum = Math.min(cardsInHand.size(), cnt); - for (int i = 0; i < revealnum; i++) { - final Card random = Aggregates.random(valid); - revealed.add(random); - valid.remove(random); - } - } else { - revealed.add(Aggregates.random(valid)); - } - - } else if (sa.hasParam("RevealDefined")) { - revealed.addAll(AbilityUtils.getDefinedCards(host, sa.getParam("RevealDefined"), sa)); - } else if (sa.hasParam("RevealAllValid")) { - revealed.addAll(CardLists.getValidCards(cardsInHand, sa.getParam("RevealAllValid"), p, host, sa)); } else { - CardCollection valid = new CardCollection(cardsInHand); - - if (sa.hasParam("RevealValid")) { - valid = CardLists.getValidCards(valid, sa.getParam("RevealValid"), p, host, sa); - } - - if (valid.isEmpty()) - continue; - - if (sa.hasParam("RevealAll")) { //for when cards to reveal are not in hand - revealed.addAll(valid); - } else { - if (cnt > valid.size()) - cnt = valid.size(); - - int min = cnt; - if (anyNumber) { - cnt = valid.size(); - min = 0; - } else if (optional) { - min = 0; - } - - revealed.addAll(p.getController().chooseCardsToRevealFromHand(min, cnt, valid)); - } + revealed.add(Aggregates.random(valid)); } - if (sa.hasParam("RevealToAll") || sa.hasParam("Random")) { - game.getAction().reveal(revealed, p, false, - sa.getParamOrDefault("RevealTitle", "")); + } else if (sa.hasParam("RevealDefined")) { + revealed.addAll(AbilityUtils.getDefinedCards(host, sa.getParam("RevealDefined"), sa)); + } else if (sa.hasParam("RevealAllValid")) { + revealed.addAll(CardLists.getValidCards(cardsInHand, sa.getParam("RevealAllValid"), p, host, sa)); + } else { + CardCollection valid = new CardCollection(cardsInHand); + + if (sa.hasParam("RevealValid")) { + valid = CardLists.getValidCards(valid, sa.getParam("RevealValid"), p, host, sa); + } + + if (valid.isEmpty()) + continue; + + if (sa.hasParam("RevealAll")) { //for when cards to reveal are not in hand + revealed.addAll(valid); } else { - game.getAction().reveal(revealed, p); - } - for (final Card c : revealed) { - game.getTriggerHandler().runTrigger(TriggerType.Revealed, AbilityKey.mapFromCard(c), false); - if (sa.hasParam("RememberRevealed")) { - host.addRemembered(c); + if (cnt > valid.size()) + cnt = valid.size(); + + int min = cnt; + if (anyNumber) { + cnt = valid.size(); + min = 0; + } else if (optional) { + min = 0; } + + revealed.addAll(p.getController().chooseCardsToRevealFromHand(min, cnt, valid)); + } + } + + if (sa.hasParam("RevealToAll") || sa.hasParam("Random")) { + game.getAction().reveal(revealed, p, false, + sa.getParamOrDefault("RevealTitle", "")); + } else { + game.getAction().reveal(revealed, p); + } + for (final Card c : revealed) { + game.getTriggerHandler().runTrigger(TriggerType.Revealed, AbilityKey.mapFromCard(c), false); + if (sa.hasParam("RememberRevealed")) { + host.addRemembered(c); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RevealHandEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RevealHandEffect.java index d5b0687ed8c..c83fc00bc6b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RevealHandEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RevealHandEffect.java @@ -6,7 +6,6 @@ import forge.game.ability.SpellAbilityEffect; import forge.game.card.*; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; import forge.util.Lang; import forge.util.Localizer; @@ -36,33 +35,32 @@ public class RevealHandEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { final Card host = sa.getHostCard(); - - final TargetRestrictions tgt = sa.getTargetRestrictions(); final boolean optional = sa.hasParam("Optional"); for (final Player p : getTargetPlayers(sa)) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - if (optional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantRevealYourHand"), null)) { - continue; - } - CardCollectionView hand = p.getCardsIn(ZoneType.Hand); - if (sa.hasParam("RevealType")) { - hand = CardLists.getType(hand, sa.getParam("RevealType")); - } - if (sa.hasParam("Look")) { - sa.getActivatingPlayer().getController().reveal(hand, ZoneType.Hand, p); - } else { - host.getGame().getAction().reveal(hand, p); - } - if (sa.hasParam("RememberRevealed")) { - host.addRemembered(hand); - } - if (sa.hasParam("ImprintRevealed")) { - host.addImprintedCards(hand); - } - if (sa.hasParam("RememberRevealedPlayer")) { - host.addRemembered(p); - } + if (!p.isInGame()) { + continue; + } + if (optional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantRevealYourHand"), null)) { + continue; + } + CardCollectionView hand = p.getCardsIn(ZoneType.Hand); + if (sa.hasParam("RevealType")) { + hand = CardLists.getType(hand, sa.getParam("RevealType")); + } + if (sa.hasParam("Look")) { + sa.getActivatingPlayer().getController().reveal(hand, ZoneType.Hand, p); + } else { + host.getGame().getAction().reveal(hand, p); + } + if (sa.hasParam("RememberRevealed")) { + host.addRemembered(hand); + } + if (sa.hasParam("ImprintRevealed")) { + host.addImprintedCards(hand); + } + if (sa.hasParam("RememberRevealedPlayer")) { + host.addRemembered(p); } } } 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 96cb9afbcea..6df53cd59e9 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 @@ -11,7 +11,6 @@ import forge.game.card.CardCollectionView; import forge.game.card.CardLists; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; import forge.util.Lang; import forge.util.Localizer; @@ -26,15 +25,11 @@ public class TwoPilesEffect extends SpellAbilityEffect { protected String getStackDescription(SpellAbility sa) { final StringBuilder sb = new StringBuilder(); - final List tgtPlayers = getTargetPlayers(sa); - final String valid = sa.getParamOrDefault("ValidCards", ""); sb.append("Separate all ").append(valid).append(" cards "); - for (final Player p : tgtPlayers) { - sb.append(p).append(" "); - } + sb.append(Lang.joinHomogenous(getTargetPlayers(sa))); sb.append("controls into two piles."); return sb.toString(); } @@ -55,7 +50,6 @@ public class TwoPilesEffect extends SpellAbilityEffect { final String valid = sa.getParamOrDefault("ValidCards", "Card"); - final TargetRestrictions tgt = sa.getTargetRestrictions(); final List tgtPlayers = getTargetPlayers(sa); Player separator = card.getController(); @@ -75,116 +69,118 @@ public class TwoPilesEffect extends SpellAbilityEffect { } for (final Player p : tgtPlayers) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - CardCollectionView pool0; - if (sa.hasParam("DefinedCards")) { - pool0 = AbilityUtils.getDefinedCards(card, sa.getParam("DefinedCards"), sa); - } else { - pool0 = p.getCardsIn(zone); - } - CardCollection pool = CardLists.getValidCards(pool0, valid, card.getController(), card, sa); - int size = pool.size(); - if (size == 0) { - return; - } + if (!p.isInGame()) { + continue; + } + + CardCollectionView pool0; + if (sa.hasParam("DefinedCards")) { + pool0 = AbilityUtils.getDefinedCards(card, sa.getParam("DefinedCards"), sa); + } else { + pool0 = p.getCardsIn(zone); + } + CardCollection pool = CardLists.getValidCards(pool0, valid, card.getController(), card, sa); + int size = pool.size(); + if (size == 0) { + return; + } - 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"); - } + 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"); + } - // first, separate the cards into piles - final CardCollectionView pile1; - final CardCollection pile2; - if (sa.hasParam("DefinedPiles")) { - final String[] def = sa.getParam("DefinedPiles").split(",", 2); - pile1 = AbilityUtils.getDefinedCards(card, def[0], sa); - pile2 = AbilityUtils.getDefinedCards(card, def[1], sa); - } else { - pile1 = separator.getController().chooseCardsForEffect(pool, sa, title, 0, size, false, null); - pile2 = new CardCollection(pool); - pile2.removeAll(pile1); - } + // first, separate the cards into piles + final CardCollectionView pile1; + final CardCollection pile2; + if (sa.hasParam("DefinedPiles")) { + final String[] def = sa.getParam("DefinedPiles").split(",", 2); + pile1 = AbilityUtils.getDefinedCards(card, def[0], sa); + pile2 = AbilityUtils.getDefinedCards(card, def[1], sa); + } else { + pile1 = separator.getController().chooseCardsForEffect(pool, sa, title, 0, size, false, null); + pile2 = new CardCollection(pool); + pile2.removeAll(pile1); + } - 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(); - 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"); + 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(); + 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"); } - 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(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") + ")"); + 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"); } - p.getGame().getAction().notifyOfValue(sa, chooser, notification.toString(), chooser); + } else { + notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")\n"); } - - - if (sa.hasParam("RememberChosen")) { - card.addRemembered(chosenPile); - } - - // take action on the chosen pile - if (sa.hasParam("ChosenPile")) { - List tempRemembered = Lists.newArrayList(card.getRemembered()); - card.removeRemembered(tempRemembered); - card.addRemembered(chosenPile); - - SpellAbility sub = sa.getAdditionalAbility("ChosenPile"); - if (sub != null) { - AbilityUtils.resolve(sub); + p.getGame().getAction().notifyOfValue(sa, separator, notification.toString(), separator); + } else { + notification.append(chooser + " " + Localizer.getInstance().getMessage("lblChoosesPile") + " " + (pile1WasChosen ? "1" : "2") + ":\n"); + if (!chosenPile.isEmpty()) { + for (Card c : chosenPile) { + notification.append(c.getName()).append("\n"); } - card.removeRemembered(chosenPile); - card.addRemembered(tempRemembered); + } else { + notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")"); } + p.getGame().getAction().notifyOfValue(sa, chooser, notification.toString(), chooser); + } - // take action on the unchosen pile - if (sa.hasParam("UnchosenPile")) { - List tempRemembered = Lists.newArrayList(card.getRemembered()); - card.removeRemembered(tempRemembered); - card.addRemembered(unchosenPile); - SpellAbility sub = sa.getAdditionalAbility("UnchosenPile"); - if (sub != null) { - AbilityUtils.resolve(sub); - } - card.removeRemembered(unchosenPile); - card.addRemembered(tempRemembered); + if (sa.hasParam("RememberChosen")) { + card.addRemembered(chosenPile); + } + + // take action on the chosen pile + if (sa.hasParam("ChosenPile")) { + List tempRemembered = Lists.newArrayList(card.getRemembered()); + card.removeRemembered(tempRemembered); + card.addRemembered(chosenPile); + + SpellAbility sub = sa.getAdditionalAbility("ChosenPile"); + if (sub != null) { + AbilityUtils.resolve(sub); } + card.removeRemembered(chosenPile); + card.addRemembered(tempRemembered); + } + + // take action on the unchosen pile + if (sa.hasParam("UnchosenPile")) { + List tempRemembered = Lists.newArrayList(card.getRemembered()); + card.removeRemembered(tempRemembered); + card.addRemembered(unchosenPile); + + SpellAbility sub = sa.getAdditionalAbility("UnchosenPile"); + if (sub != null) { + AbilityUtils.resolve(sub); + } + card.removeRemembered(unchosenPile); + card.addRemembered(tempRemembered); } } if (!sa.hasParam("KeepRemembered")) { From 0b907db6ee978b2ab1c2a11631979c2b4ad78db0 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Fri, 25 Nov 2022 21:35:19 +0100 Subject: [PATCH 4/5] A few independent card fixes --- forge-gui/res/cardsfolder/d/dhalsim_pliable_pacifist.txt | 8 ++++---- forge-gui/res/cardsfolder/f/fog_patch.txt | 3 +-- forge-gui/res/cardsfolder/m/mist_of_stagnation.txt | 6 ++---- forge-gui/res/cardsfolder/t/triumphant_adventurer.txt | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/forge-gui/res/cardsfolder/d/dhalsim_pliable_pacifist.txt b/forge-gui/res/cardsfolder/d/dhalsim_pliable_pacifist.txt index 26484bd1b2c..566dbc3a41b 100644 --- a/forge-gui/res/cardsfolder/d/dhalsim_pliable_pacifist.txt +++ b/forge-gui/res/cardsfolder/d/dhalsim_pliable_pacifist.txt @@ -5,10 +5,10 @@ PT:1/3 K:Reach S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Hexproof | IsPresent$ Card.Self+notattacking | Description$ Teleport — CARDNAME has hexproof unless he's attacking. T:Mode$ Attacks | ValidCard$ Creature.YouCtrl+withReach | TriggerZones$ Battlefield | Execute$ TrigUntap | TriggerDescription$ Whenever a creature you control with reach attacks, untap it and it can't be blocked by creatures with greater power this combat. -SVar:TrigUntap:DB$ Untap | Defined$ TriggeredAttackerLKICopy | SubAbility$ DBAnimate -SVar:DBAnimate:DB$ Animate | Defined$ TriggeredAttackerLKICopy | staticAbilities$ CantBeBlockedPow | Duration$ UntilEndOfCombat -SVar:CantBeBlockedPow:Mode$ CantBlockBy | ValidAttacker$ Card.Self | ValidBlocker$ Creature.powerGTX | Description$ CARDNAME can't be blocked by creatures with greater power this combat. -SVar:X:Count$CardPower +SVar:TrigUntap:DB$ Untap | Defined$ TriggeredAttackerLKICopy | SubAbility$ DBEffect +SVar:DBEffect:DB$ Effect | RememberObjects$ TriggeredAttacker | StaticAbilities$ CantBeBlockedPow | ForgetOnMoved$ Battlefield | Duration$ UntilEndOfCombat +SVar:CantBeBlockedPow:Mode$ CantBlockBy | ValidAttacker$ Card.IsRemembered | ValidBlocker$ Creature.powerGTX | Description$ CARDNAME can't be blocked by creatures with greater power this combat. +SVar:X:Remembered$CardPower T:Mode$ DamageDoneOnce | CombatDamage$ True | ValidSource$ Creature.YouCtrl | TriggerZones$ Battlefield | ValidTarget$ Player | Execute$ TrigDraw | TriggerDescription$ Fierce Punch — Whenever one or more creatures you control deal combat damage to a player, draw a card. SVar:TrigDraw:DB$ Draw DeckHints:Keyword$Reach diff --git a/forge-gui/res/cardsfolder/f/fog_patch.txt b/forge-gui/res/cardsfolder/f/fog_patch.txt index 79f682c5f9c..d3977f3a37f 100644 --- a/forge-gui/res/cardsfolder/f/fog_patch.txt +++ b/forge-gui/res/cardsfolder/f/fog_patch.txt @@ -2,7 +2,6 @@ Name:Fog Patch ManaCost:1 G Types:Instant Text:Cast this spell only during the declare blockers step. -A:SP$ RepeatEach | Cost$ 1 G | ActivationPhases$ Declare Blockers | RepeatSubAbility$ DBBecomeBlocked | RepeatCards$ Creature.attacking | SpellDescription$ Attacking creatures become blocked. (This spell works on creatures that can't be blocked.) -SVar:DBBecomeBlocked:DB$ BecomesBlocked | Defined$ Remembered +A:SP$ BecomesBlocked | Cost$ 1 G | Defined$ Valid Creature.attacking | ActivationPhases$ Declare Blockers | SpellDescription$ Attacking creatures become blocked. (This spell works on creatures that can't be blocked.) AI:RemoveDeck:All Oracle:Cast this spell only during the declare blockers step.\nAttacking creatures become blocked. (This spell works on creatures that can't be blocked.) diff --git a/forge-gui/res/cardsfolder/m/mist_of_stagnation.txt b/forge-gui/res/cardsfolder/m/mist_of_stagnation.txt index 20c68b65047..cfefc77f823 100644 --- a/forge-gui/res/cardsfolder/m/mist_of_stagnation.txt +++ b/forge-gui/res/cardsfolder/m/mist_of_stagnation.txt @@ -2,10 +2,8 @@ Name:Mist of Stagnation ManaCost:3 U U Types:Enchantment S:Mode$ Continuous | Affected$ Permanent | AddHiddenKeyword$ CARDNAME doesn't untap during your untap step. | Description$ Permanents don't untap during their controllers' untap steps. -T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of each player's upkeep, that player chooses a permanent for each card in their graveyard, then untaps those permanents. -SVar:TrigChoose:DB$ ChooseCard | Defined$ TriggeredPlayer | Amount$ X | Mandatory$ True | Choices$ Permanent.ActivePlayerCtrl | ChoiceTitle$ Choose a permanent to untap | AILogic$ Untap | SubAbility$ DBUntap -SVar:DBUntap:DB$ UntapAll | ValidCards$ Permanent.ChosenCard | SubAbility$ DBCleanup -SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True +T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player | Execute$ DBUntap | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of each player's upkeep, that player chooses a permanent for each card in their graveyard, then untaps those permanents. +SVar:DBUntap:DB$ Untap | UntapExactly$ True | Defined$ TriggeredPlayer | Amount$ X | UntapType$ Card SVar:X:Count$ValidGraveyard Card.ActivePlayerCtrl AI:RemoveDeck:Random SVar:NonStackingEffect:True diff --git a/forge-gui/res/cardsfolder/t/triumphant_adventurer.txt b/forge-gui/res/cardsfolder/t/triumphant_adventurer.txt index 253cd65fa7b..f82bd4a284d 100644 --- a/forge-gui/res/cardsfolder/t/triumphant_adventurer.txt +++ b/forge-gui/res/cardsfolder/t/triumphant_adventurer.txt @@ -4,7 +4,7 @@ Types:Creature Human Knight PT:1/1 K:Deathtouch S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ First Strike | Condition$ PlayerTurn | Description$ As long as it's your turn, CARDNAME has first strike. -T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBVenture | Secondary$ True | TriggerDescription$ Whenever CARDNAME attacks, venture into the dungeon. (Enter the first room or advance to the next room.) +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBVenture | TriggerDescription$ Whenever CARDNAME attacks, venture into the dungeon. (Enter the first room or advance to the next room.) SVar:DBVenture:DB$ Venture | Defined$ You SVar:HasAttackEffect:TRUE Oracle:Deathtouch\nAs long as it's your turn, Triumphant Adventurer has first strike.\nWhenever Triumphant Adventurer attacks, venture into the dungeon. (Enter the first room or advance to the next room.) From 157f99f87f49c1d978e8e1fad1802d33ff92e074 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Fri, 25 Nov 2022 21:50:19 +0100 Subject: [PATCH 5/5] Update new one --- .../forge/game/ability/effects/TakeInitiativeEffect.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/forge-game/src/main/java/forge/game/ability/effects/TakeInitiativeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TakeInitiativeEffect.java index 9fa95a288a5..c8fcaa5dba2 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TakeInitiativeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TakeInitiativeEffect.java @@ -27,9 +27,11 @@ public class TakeInitiativeEffect extends SpellAbilityEffect { final String set = sa.getHostCard().getSetCode(); for (final Player p : getTargetPlayers(sa)) { - if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - p.getGame().getAction().takeInitiative(p, set); + if (!p.isInGame()) { + continue; } + + p.getGame().getAction().takeInitiative(p, set); } } }