From f7fd335b1055bd98ed888d0ecce5af635e2b4a03 Mon Sep 17 00:00:00 2001 From: TRT <> Date: Tue, 29 Nov 2022 20:12:30 +0100 Subject: [PATCH] Fix phasing in attached when entity stopped existing --- .../main/java/forge/ai/ability/AnimateAi.java | 4 ++-- .../java/forge/ai/ability/ChooseSourceAi.java | 6 ++++-- .../java/forge/ai/ability/CountersRemoveAi.java | 3 +-- .../src/main/java/forge/ai/ability/EffectAi.java | 1 + .../src/main/java/forge/game/card/Card.java | 16 +++++++++++++++- .../src/main/java/forge/game/phase/Untap.java | 2 +- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java b/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java index 849f4eec2d8..66a5ddee8ae 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java @@ -261,10 +261,10 @@ public class AnimateAi extends SpellAbilityAi { // something is used for animate into creature if (types.isCreature()) { final Game game = ai.getGame(); - CardCollectionView list = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa); + CardCollection list = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa); // Filter AI-specific targets if provided - list = ComputerUtil.filterAITgts(sa, ai, (CardCollection)list, false); + list = ComputerUtil.filterAITgts(sa, ai, list, false); // list is empty, no possible targets if (list.isEmpty() && !alwaysActivatePWAbility) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java index 78848367229..aec92fc142c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java @@ -74,9 +74,11 @@ public class ChooseSourceAi extends SpellAbilityAi { } final Card threatSource = topStack.getHostCard(); - List objects = getTargets(topStack); + List objects; if (!topStack.usesTargeting() && topStack.hasParam("ValidPlayers") && !topStack.hasParam("Defined")) { objects = AbilityUtils.getDefinedPlayers(threatSource, topStack.getParam("ValidPlayers"), topStack); + } else { + objects = getTargets(topStack); } if (!objects.contains(ai) || topStack.hasParam("NoPrevention")) { @@ -201,7 +203,7 @@ public class ChooseSourceAi extends SpellAbilityAi { private static List getTargets(final SpellAbility sa) { return sa.usesTargeting() && (!sa.hasParam("Defined")) - ? Lists.newArrayList(sa.getTargets()) + ? sa.getTargets() : AbilityUtils.getDefinedObjects(sa.getHostCard(), sa.getParam("Defined"), sa); } } diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java index d5df83a1a60..885bb8d5f22 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java @@ -107,9 +107,8 @@ public class CountersRemoveAi extends SpellAbilityAi { // remove counter with Time might use Exile Zone too final TargetRestrictions tgt = sa.getTargetRestrictions(); - CardCollection list = new CardCollection(game.getCardsIn(tgt.getZone())); // need to targetable - list = CardLists.getTargetableCards(list, sa); + CardCollection list = CardLists.getTargetableCards(game.getCardsIn(tgt.getZone()), sa); if (list.isEmpty()) { return false; diff --git a/forge-ai/src/main/java/forge/ai/ability/EffectAi.java b/forge-ai/src/main/java/forge/ai/ability/EffectAi.java index b84cea69c80..0d6452f4975 100644 --- a/forge-ai/src/main/java/forge/ai/ability/EffectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/EffectAi.java @@ -218,6 +218,7 @@ public class EffectAi extends SpellAbilityAi { return FightAi.canFightAi(ai, sa, 0, 0); } else if (logic.equals("Pump")) { List options = CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa); + options = CardLists.filterControlledBy(options, ai); if (sa.getPayCosts().hasTapCost()) { options.remove(sa.getHostCard()); } 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 a1d0489d59f..92acdf57724 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -5027,7 +5027,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { setDirectlyPhasedOut(direct); } - // CR 702.25g + // CR 702.26g if (!getAllAttachedCards().isEmpty()) { for (final Card eq : getAllAttachedCards()) { if (eq.isPhasedOut() == phasingIn) { @@ -5084,6 +5084,20 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } if (!isPhasedOut()) { + // CR 702.26g phases in unattached if that object is still in the same zone or that player is still in the game + if (isAttachedToEntity()) { + final GameEntity ge = getEntityAttachedTo(); + boolean unattach = false; + if (ge instanceof Player) { + unattach = !((Player) ge).isInGame(); + } else { + unattach = !((Card) ge).isInPlay(); + } + if (unattach) { + unattachFromEntity(ge); + } + } + // Just phased in, time to run the phased in trigger getGame().getTriggerHandler().registerActiveTrigger(this, false); getGame().getTriggerHandler().runTrigger(TriggerType.PhaseIn, runParams, false); diff --git a/forge-game/src/main/java/forge/game/phase/Untap.java b/forge-game/src/main/java/forge/game/phase/Untap.java index dcdd3861e09..7c9720fccce 100644 --- a/forge-game/src/main/java/forge/game/phase/Untap.java +++ b/forge-game/src/main/java/forge/game/phase/Untap.java @@ -269,7 +269,7 @@ public class Untap extends Phase { if (c.isPhasedOut()) { c.phase(true); } else if (c.hasKeyword(Keyword.PHASING)) { - // 702.23g If an object would simultaneously phase out directly + // CR 702.26h If an object would simultaneously phase out directly // and indirectly, it just phases out indirectly. if (c.isAttachment()) { final Card ent = c.getAttachedTo();