Fix phasing in attached when entity stopped existing

This commit is contained in:
TRT
2022-11-29 20:12:30 +01:00
parent 56963e6d07
commit f7fd335b10
6 changed files with 24 additions and 8 deletions

View File

@@ -261,10 +261,10 @@ public class AnimateAi extends SpellAbilityAi {
// something is used for animate into creature // something is used for animate into creature
if (types.isCreature()) { if (types.isCreature()) {
final Game game = ai.getGame(); 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 // 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 // list is empty, no possible targets
if (list.isEmpty() && !alwaysActivatePWAbility) { if (list.isEmpty() && !alwaysActivatePWAbility) {

View File

@@ -74,9 +74,11 @@ public class ChooseSourceAi extends SpellAbilityAi {
} }
final Card threatSource = topStack.getHostCard(); final Card threatSource = topStack.getHostCard();
List<? extends GameObject> objects = getTargets(topStack); List<? extends GameObject> objects;
if (!topStack.usesTargeting() && topStack.hasParam("ValidPlayers") && !topStack.hasParam("Defined")) { if (!topStack.usesTargeting() && topStack.hasParam("ValidPlayers") && !topStack.hasParam("Defined")) {
objects = AbilityUtils.getDefinedPlayers(threatSource, topStack.getParam("ValidPlayers"), topStack); objects = AbilityUtils.getDefinedPlayers(threatSource, topStack.getParam("ValidPlayers"), topStack);
} else {
objects = getTargets(topStack);
} }
if (!objects.contains(ai) || topStack.hasParam("NoPrevention")) { if (!objects.contains(ai) || topStack.hasParam("NoPrevention")) {
@@ -201,7 +203,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
private static List<GameObject> getTargets(final SpellAbility sa) { private static List<GameObject> getTargets(final SpellAbility sa) {
return sa.usesTargeting() && (!sa.hasParam("Defined")) return sa.usesTargeting() && (!sa.hasParam("Defined"))
? Lists.newArrayList(sa.getTargets()) ? sa.getTargets()
: AbilityUtils.getDefinedObjects(sa.getHostCard(), sa.getParam("Defined"), sa); : AbilityUtils.getDefinedObjects(sa.getHostCard(), sa.getParam("Defined"), sa);
} }
} }

View File

@@ -107,9 +107,8 @@ public class CountersRemoveAi extends SpellAbilityAi {
// remove counter with Time might use Exile Zone too // remove counter with Time might use Exile Zone too
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
CardCollection list = new CardCollection(game.getCardsIn(tgt.getZone()));
// need to targetable // need to targetable
list = CardLists.getTargetableCards(list, sa); CardCollection list = CardLists.getTargetableCards(game.getCardsIn(tgt.getZone()), sa);
if (list.isEmpty()) { if (list.isEmpty()) {
return false; return false;

View File

@@ -218,6 +218,7 @@ public class EffectAi extends SpellAbilityAi {
return FightAi.canFightAi(ai, sa, 0, 0); return FightAi.canFightAi(ai, sa, 0, 0);
} else if (logic.equals("Pump")) { } else if (logic.equals("Pump")) {
List<Card> options = CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa); List<Card> options = CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa);
options = CardLists.filterControlledBy(options, ai);
if (sa.getPayCosts().hasTapCost()) { if (sa.getPayCosts().hasTapCost()) {
options.remove(sa.getHostCard()); options.remove(sa.getHostCard());
} }

View File

@@ -5027,7 +5027,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
setDirectlyPhasedOut(direct); setDirectlyPhasedOut(direct);
} }
// CR 702.25g // CR 702.26g
if (!getAllAttachedCards().isEmpty()) { if (!getAllAttachedCards().isEmpty()) {
for (final Card eq : getAllAttachedCards()) { for (final Card eq : getAllAttachedCards()) {
if (eq.isPhasedOut() == phasingIn) { if (eq.isPhasedOut() == phasingIn) {
@@ -5084,6 +5084,20 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
if (!isPhasedOut()) { 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 // Just phased in, time to run the phased in trigger
getGame().getTriggerHandler().registerActiveTrigger(this, false); getGame().getTriggerHandler().registerActiveTrigger(this, false);
getGame().getTriggerHandler().runTrigger(TriggerType.PhaseIn, runParams, false); getGame().getTriggerHandler().runTrigger(TriggerType.PhaseIn, runParams, false);

View File

@@ -269,7 +269,7 @@ public class Untap extends Phase {
if (c.isPhasedOut()) { if (c.isPhasedOut()) {
c.phase(true); c.phase(true);
} else if (c.hasKeyword(Keyword.PHASING)) { } 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. // and indirectly, it just phases out indirectly.
if (c.isAttachment()) { if (c.isAttachment()) {
final Card ent = c.getAttachedTo(); final Card ent = c.getAttachedTo();