diff --git a/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java b/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java index 60ad4f593b5..1a3b700eb15 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java @@ -112,7 +112,7 @@ class ArcaneArtisanCreateTokenEffect extends OneShotEffect { } else { tokensCreated = new HashSet<>(); } - for (Permanent perm : effect.getAddedPermanent()) { + for (Permanent perm : effect.getAddedPermanents()) { if (perm != null) { tokensCreated.add(perm.getId()); } diff --git a/Mage.Sets/src/mage/cards/c/CogworkAssembler.java b/Mage.Sets/src/mage/cards/c/CogworkAssembler.java index 89bd2f958eb..bac94ec4957 100644 --- a/Mage.Sets/src/mage/cards/c/CogworkAssembler.java +++ b/Mage.Sets/src/mage/cards/c/CogworkAssembler.java @@ -73,7 +73,7 @@ class CogworkAssemblerCreateTokenEffect extends OneShotEffect { if (copiedPermanent != null) { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, CardType.ARTIFACT, true); if (effect.apply(game, source)) { - for (Permanent copyPermanent : effect.getAddedPermanent()) { + for (Permanent copyPermanent : effect.getAddedPermanents()) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(copyPermanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); diff --git a/Mage.Sets/src/mage/cards/d/DanceOfMany.java b/Mage.Sets/src/mage/cards/d/DanceOfMany.java index 549c4c05b11..a6c2cf634e1 100644 --- a/Mage.Sets/src/mage/cards/d/DanceOfMany.java +++ b/Mage.Sets/src/mage/cards/d/DanceOfMany.java @@ -93,8 +93,8 @@ class DanceOfManyCreateTokenCopyEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); effect.setTargetPointer(new FixedTarget(permanent, game)); effect.apply(game, source); - game.getState().setValue(source.getSourceId() + "_token", effect.getAddedPermanent()); - for (Permanent addedToken : effect.getAddedPermanent()) { + game.getState().setValue(source.getSourceId() + "_token", effect.getAddedPermanents()); + for (Permanent addedToken : effect.getAddedPermanents()) { Effect sacrificeEffect = new SacrificeTargetEffect("sacrifice Dance of Many"); sacrificeEffect.setTargetPointer(new FixedTarget(sourceObject, game)); LeavesBattlefieldTriggeredAbility triggerAbility = new LeavesBattlefieldTriggeredAbility(sacrificeEffect, false); diff --git a/Mage.Sets/src/mage/cards/d/DollhouseOfHorrors.java b/Mage.Sets/src/mage/cards/d/DollhouseOfHorrors.java index feaa4101e93..01d92282866 100644 --- a/Mage.Sets/src/mage/cards/d/DollhouseOfHorrors.java +++ b/Mage.Sets/src/mage/cards/d/DollhouseOfHorrors.java @@ -94,7 +94,7 @@ class DollhouseOfHorrorsEffect extends OneShotEffect { effect.apply(game, source); game.addEffect(new GainAbilityTargetEffect( HasteAbility.getInstance(), Duration.EndOfTurn - ).setTargetPointer(new FixedTargets(effect.getAddedPermanent(), game)), source); + ).setTargetPointer(new FixedTargets(effect.getAddedPermanents(), game)), source); return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DualNature.java b/Mage.Sets/src/mage/cards/d/DualNature.java index 8da8ffbb1df..fa69caff5f9 100644 --- a/Mage.Sets/src/mage/cards/d/DualNature.java +++ b/Mage.Sets/src/mage/cards/d/DualNature.java @@ -97,7 +97,7 @@ class DualNatureCreateTokenEffect extends OneShotEffect { } else { tokensCreated = new HashSet<>(); } - for (Permanent perm : effect.getAddedPermanent()) { + for (Permanent perm : effect.getAddedPermanents()) { if (perm != null) { tokensCreated.add(perm.getId()); } diff --git a/Mage.Sets/src/mage/cards/e/EchoChamber.java b/Mage.Sets/src/mage/cards/e/EchoChamber.java index 18d24b34143..a06208c4b42 100644 --- a/Mage.Sets/src/mage/cards/e/EchoChamber.java +++ b/Mage.Sets/src/mage/cards/e/EchoChamber.java @@ -71,7 +71,7 @@ class EchoChamberCreateTokenEffect extends OneShotEffect { if (copiedPermanent != null) { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, CardType.CREATURE, true); if (effect.apply(game, source)) { - for (Permanent copyPermanent : effect.getAddedPermanent()) { + for (Permanent copyPermanent : effect.getAddedPermanents()) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(copyPermanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); diff --git a/Mage.Sets/src/mage/cards/f/FaerieArtisans.java b/Mage.Sets/src/mage/cards/f/FaerieArtisans.java index 7c7be3b9774..eff8adc812c 100644 --- a/Mage.Sets/src/mage/cards/f/FaerieArtisans.java +++ b/Mage.Sets/src/mage/cards/f/FaerieArtisans.java @@ -86,7 +86,7 @@ class FaerieArtisansEffect extends OneShotEffect { if (effect.apply(game, source)) { String oldTokens = (String) game.getState().getValue(source.getSourceId().toString() + source.getSourceObjectZoneChangeCounter()); StringBuilder sb = new StringBuilder(); - for (Permanent permanent : effect.getAddedPermanent()) { + for (Permanent permanent : effect.getAddedPermanents()) { if (sb.length() > 0) { sb.append(';'); } diff --git a/Mage.Sets/src/mage/cards/f/FeldonOfTheThirdPath.java b/Mage.Sets/src/mage/cards/f/FeldonOfTheThirdPath.java index 7d5ee1e97da..71c460928f0 100644 --- a/Mage.Sets/src/mage/cards/f/FeldonOfTheThirdPath.java +++ b/Mage.Sets/src/mage/cards/f/FeldonOfTheThirdPath.java @@ -81,7 +81,7 @@ class FeldonOfTheThirdPathEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), CardType.ARTIFACT, true); effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId()))); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("Sacrifice the token at the beginning of the next end step", source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(addedToken, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); diff --git a/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java b/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java index cfa673999e6..2d3263c107e 100644 --- a/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java +++ b/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java @@ -83,7 +83,7 @@ class FelhideSpiritbinderEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, CardType.ENCHANTMENT, true); effect.setTargetPointer(getTargetPointer()); if (effect.apply(game, source)) { - for (Permanent tokenPermanent : effect.getAddedPermanent()) { + for (Permanent tokenPermanent : effect.getAddedPermanents()) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); diff --git a/Mage.Sets/src/mage/cards/f/FlamerushRider.java b/Mage.Sets/src/mage/cards/f/FlamerushRider.java index 2e8e079c937..a7d0b8c60a1 100644 --- a/Mage.Sets/src/mage/cards/f/FlamerushRider.java +++ b/Mage.Sets/src/mage/cards/f/FlamerushRider.java @@ -89,7 +89,7 @@ class FlamerushRiderEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true, 1, true, true); effect.setTargetPointer(new FixedTarget(permanent, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { Effect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), false).apply(game, source); diff --git a/Mage.Sets/src/mage/cards/f/FlameshadowConjuring.java b/Mage.Sets/src/mage/cards/f/FlameshadowConjuring.java index 5f23c18d36d..fb7eca29d64 100644 --- a/Mage.Sets/src/mage/cards/f/FlameshadowConjuring.java +++ b/Mage.Sets/src/mage/cards/f/FlameshadowConjuring.java @@ -81,7 +81,7 @@ class FlameshadowConjuringEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, null, true); effect.setTargetPointer(getTargetPointer()); if (effect.apply(game, source)) { - for (Permanent tokenPermanent : effect.getAddedPermanent()) { + for (Permanent tokenPermanent : effect.getAddedPermanents()) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); diff --git a/Mage.Sets/src/mage/cards/f/ForceProjection.java b/Mage.Sets/src/mage/cards/f/ForceProjection.java index e185fe46d15..45bef91531c 100644 --- a/Mage.Sets/src/mage/cards/f/ForceProjection.java +++ b/Mage.Sets/src/mage/cards/f/ForceProjection.java @@ -80,7 +80,7 @@ class ForceProjectionEffect extends OneShotEffect { // and gains "When this creature becomes the target of a spell, sacrifice it." Effect sacrificeEffect = new SacrificeSourceEffect(); - sacrificeEffect.setTargetPointer(new FixedTarget(effect.getAddedPermanent().get(0), game)); + sacrificeEffect.setTargetPointer(new FixedTarget(effect.getAddedPermanents().get(0), game)); TriggeredAbility ability = new BecomesTargetTriggeredAbility(sacrificeEffect, new FilterSpell()); game.addTriggeredAbility(ability, null); diff --git a/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java b/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java index 28f936bdeb6..88f599718fc 100644 --- a/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java +++ b/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java @@ -96,7 +96,7 @@ class GyrusWakerOfCorpsesEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true, 1, true, true); effect.setTargetPointer(new FixedTarget(card, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { Effect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), false).apply(game, source); diff --git a/Mage.Sets/src/mage/cards/h/HeatShimmer.java b/Mage.Sets/src/mage/cards/h/HeatShimmer.java index 73f6a4fb7e3..cae0d6aed43 100644 --- a/Mage.Sets/src/mage/cards/h/HeatShimmer.java +++ b/Mage.Sets/src/mage/cards/h/HeatShimmer.java @@ -68,7 +68,7 @@ class HeatShimmerEffect extends OneShotEffect { effect.setTargetPointer(new FixedTarget(permanent, game)); effect.apply(game, source); ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(effect.getAddedPermanent().get(0), game)); + exileEffect.setTargetPointer(new FixedTarget(effect.getAddedPermanents().get(0), game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); game.addDelayedTriggeredAbility(delayedAbility, source); return true; diff --git a/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java b/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java index 05aca9f23ea..b162446354b 100644 --- a/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java +++ b/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java @@ -114,7 +114,7 @@ class InallaArchmageRitualistEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, null, true); effect.setTargetPointer(getTargetPointer()); if (effect.apply(game, source)) { - for (Permanent tokenPermanent : effect.getAddedPermanent()) { + for (Permanent tokenPermanent : effect.getAddedPermanents()) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); diff --git a/Mage.Sets/src/mage/cards/k/KikiJikiMirrorBreaker.java b/Mage.Sets/src/mage/cards/k/KikiJikiMirrorBreaker.java index 3ecfa7660ff..ba97b5e26e5 100644 --- a/Mage.Sets/src/mage/cards/k/KikiJikiMirrorBreaker.java +++ b/Mage.Sets/src/mage/cards/k/KikiJikiMirrorBreaker.java @@ -88,7 +88,7 @@ class KikiJikiMirrorBreakerEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true); effect.setTargetPointer(new FixedTarget(permanent, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("Sacrifice the token at the beginning of the next end step", source.getControllerId()); sacrificeEffect.setTargetPointer(new FixedTarget(addedToken.getId())); game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect), source); diff --git a/Mage.Sets/src/mage/cards/k/KindredCharge.java b/Mage.Sets/src/mage/cards/k/KindredCharge.java index 548e9f4eb96..82318a30d42 100644 --- a/Mage.Sets/src/mage/cards/k/KindredCharge.java +++ b/Mage.Sets/src/mage/cards/k/KindredCharge.java @@ -77,7 +77,7 @@ class KindredChargeEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true); effect.setTargetPointer(new FixedTarget(permanent, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { Effect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); diff --git a/Mage.Sets/src/mage/cards/l/LittjaraMirrorlake.java b/Mage.Sets/src/mage/cards/l/LittjaraMirrorlake.java index cbe54ff2ab5..c42e0218b97 100644 --- a/Mage.Sets/src/mage/cards/l/LittjaraMirrorlake.java +++ b/Mage.Sets/src/mage/cards/l/LittjaraMirrorlake.java @@ -77,7 +77,7 @@ class LittjaraMirrorlakeEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); effect.apply(game, source); - for (Permanent permanent : effect.getAddedPermanent()) { + for (Permanent permanent : effect.getAddedPermanents()) { if (permanent == null) { continue; } diff --git a/Mage.Sets/src/mage/cards/m/MimicVat.java b/Mage.Sets/src/mage/cards/m/MimicVat.java index a951e44e4b6..07d791714c8 100644 --- a/Mage.Sets/src/mage/cards/m/MimicVat.java +++ b/Mage.Sets/src/mage/cards/m/MimicVat.java @@ -182,7 +182,7 @@ class MimicVatCreateTokenEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true); effect.setTargetPointer(new FixedTarget(card, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); diff --git a/Mage.Sets/src/mage/cards/m/MinionReflector.java b/Mage.Sets/src/mage/cards/m/MinionReflector.java index a438b6e2000..8afbacbcc1d 100644 --- a/Mage.Sets/src/mage/cards/m/MinionReflector.java +++ b/Mage.Sets/src/mage/cards/m/MinionReflector.java @@ -83,7 +83,7 @@ class MinionReflectorEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true); effect.setTargetPointer(new FixedTarget(permanent, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { ContinuousEffect continuousEffect = new GainAbilityTargetEffect(new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect(), TargetController.ANY, false), Duration.Custom); continuousEffect.setTargetPointer(new FixedTarget(addedToken.getId())); game.addEffect(continuousEffect, source); diff --git a/Mage.Sets/src/mage/cards/m/MiragePhalanx.java b/Mage.Sets/src/mage/cards/m/MiragePhalanx.java new file mode 100644 index 00000000000..f7391909b6c --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MiragePhalanx.java @@ -0,0 +1,91 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityPairedEffect; +import mage.abilities.keyword.SoulbondAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author Alex-Vasile + */ +public class MiragePhalanx extends CardImpl { + + private static final String ruleText = + "As long as {this} is paired with another creature, each of those creatures has " + + "\"At the beginning of combat on your turn, create a token that's a copy of this creature, " + + "except it has haste and loses soulbond. " + + "Exile it at end of combat.\""; + + public MiragePhalanx(UUID ownderId, CardSetInfo setInfo) { + super(ownderId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); + + this.addSubType(SubType.HUMAN); + this.addSubType(SubType.SOLDIER); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Soulbond + this.addAbility(new SoulbondAbility()); + + // As long as Mirage Phalanx is paired with another creature, each of those creatures has + // “At the beginning of combat on your turn, create a token that's a copy of this creature, + // except it has haste and loses soulbond. + // Exile it at end of combat.” + Ability ability = new BeginningOfCombatTriggeredAbility(new MiragePhalanxEffect(), TargetController.YOU, false); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(ability, ruleText))); + } + + private MiragePhalanx(final MiragePhalanx card) { + super(card); + } + + @Override + public MiragePhalanx copy() { + return new MiragePhalanx(this); + } +} + +class MiragePhalanxEffect extends OneShotEffect { + MiragePhalanxEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "create a token that's a copy of this creature, " + + "except it has haste and loses soulbond. " + + "Exile it at end of combat."; + } + + private MiragePhalanxEffect(final MiragePhalanxEffect effect) { super(effect); } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentOrLKI(game); + if (permanent == null) { return false; } + + // It has haste + CreateTokenCopyTargetEffect tokenCopyEffect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true); + tokenCopyEffect.setTargetPointer(new FixedTarget(permanent, game)); + // It loses soulbond + tokenCopyEffect.addAbilityClassesToRemoveFromTokens(SoulbondAbility.class); + // Create the token(s) + tokenCopyEffect.apply(game, source); + // Exile it at the end of combat + tokenCopyEffect.exileTokensCreatedAtEndOfCombat(game, source); + + return !tokenCopyEffect.getAddedPermanents().isEmpty(); + } + + @Override + public Effect copy() { return new MiragePhalanxEffect(this); } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MirrorMatch.java b/Mage.Sets/src/mage/cards/m/MirrorMatch.java index 33688df5163..7bc8fbc81d3 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorMatch.java +++ b/Mage.Sets/src/mage/cards/m/MirrorMatch.java @@ -77,14 +77,14 @@ class MirrorMatchEffect extends OneShotEffect { CombatGroup group = game.getCombat().findGroup(attacker.getId()); boolean isCreature = false; if (group != null) { - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { if (addedToken.isCreature(game)) { group.addBlockerToGroup(addedToken.getId(), attackerId, game); isCreature = true; } } ExileTargetEffect exileEffect = new ExileTargetEffect("Exile those tokens at end of combat"); - exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanent(), game)); + exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanents(), game)); game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), source); if (isCreature) { group.pickBlockerOrder(attacker.getControllerId(), game); diff --git a/Mage.Sets/src/mage/cards/m/MirrorMockery.java b/Mage.Sets/src/mage/cards/m/MirrorMockery.java index 9a31aabb6b5..c8fb636afbd 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorMockery.java +++ b/Mage.Sets/src/mage/cards/m/MirrorMockery.java @@ -85,7 +85,7 @@ class MirrorMockeryEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); effect.setTargetPointer(new FixedTarget(enchanted, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { if (addedToken != null) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); diff --git a/Mage.Sets/src/mage/cards/m/MoltenEchoes.java b/Mage.Sets/src/mage/cards/m/MoltenEchoes.java index 6125a7f4c79..46f9a9a048f 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenEchoes.java +++ b/Mage.Sets/src/mage/cards/m/MoltenEchoes.java @@ -82,7 +82,7 @@ class MoltenEchoesEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, null, true); effect.setTargetPointer(getTargetPointer()); if (effect.apply(game, source)) { - for (Permanent tokenPermanent : effect.getAddedPermanent()) { + for (Permanent tokenPermanent : effect.getAddedPermanents()) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); diff --git a/Mage.Sets/src/mage/cards/n/NacatlWarPride.java b/Mage.Sets/src/mage/cards/n/NacatlWarPride.java index 0d7cd8adde7..1248fb27cb9 100644 --- a/Mage.Sets/src/mage/cards/n/NacatlWarPride.java +++ b/Mage.Sets/src/mage/cards/n/NacatlWarPride.java @@ -105,7 +105,7 @@ class NacatlWarPrideEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(controller.getId(), null, false, count, true, true); effect.setTargetPointer(new FixedTarget(origNactalWarPride, game)); effect.apply(game, source); - copies.addAll(effect.getAddedPermanent()); + copies.addAll(effect.getAddedPermanents()); if (!copies.isEmpty()) { FixedTargets fixedTargets = new FixedTargets(copies, game); diff --git a/Mage.Sets/src/mage/cards/n/NemesisTrap.java b/Mage.Sets/src/mage/cards/n/NemesisTrap.java index 96ffeac5a85..512f96f5b54 100644 --- a/Mage.Sets/src/mage/cards/n/NemesisTrap.java +++ b/Mage.Sets/src/mage/cards/n/NemesisTrap.java @@ -88,7 +88,7 @@ class NemesisTrapEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); effect.setTargetPointer(new FixedTarget(targetedCreature, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { Effect exileEffect = new ExileTargetEffect("Exile " + addedToken.getName() + " at the beginning of the next end step"); exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); diff --git a/Mage.Sets/src/mage/cards/o/OffspringsRevenge.java b/Mage.Sets/src/mage/cards/o/OffspringsRevenge.java index 43aad22f053..ef8a130fc80 100644 --- a/Mage.Sets/src/mage/cards/o/OffspringsRevenge.java +++ b/Mage.Sets/src/mage/cards/o/OffspringsRevenge.java @@ -91,7 +91,7 @@ class OffspringsRevengeEffect extends OneShotEffect { effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game) + 1)); player.moveCards(card, Zone.EXILED, source, game); effect.apply(game, source); - effect.getAddedPermanent().stream().forEach(permanent -> { + effect.getAddedPermanents().stream().forEach(permanent -> { ContinuousEffect continuousEffect = new GainAbilityTargetEffect( HasteAbility.getInstance(), Duration.UntilYourNextTurn ); diff --git a/Mage.Sets/src/mage/cards/s/SaheeliRai.java b/Mage.Sets/src/mage/cards/s/SaheeliRai.java index 5e3b82340f7..904f5891f45 100644 --- a/Mage.Sets/src/mage/cards/s/SaheeliRai.java +++ b/Mage.Sets/src/mage/cards/s/SaheeliRai.java @@ -87,7 +87,7 @@ class SaheeliRaiCreateTokenEffect extends OneShotEffect { if (copiedPermanent != null) { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, CardType.ARTIFACT, true); if (effect.apply(game, source)) { - for (Permanent copyPermanent : effect.getAddedPermanent()) { + for (Permanent copyPermanent : effect.getAddedPermanents()) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(copyPermanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); diff --git a/Mage.Sets/src/mage/cards/s/Seance.java b/Mage.Sets/src/mage/cards/s/Seance.java index 5795c7722ec..e40245e171d 100644 --- a/Mage.Sets/src/mage/cards/s/Seance.java +++ b/Mage.Sets/src/mage/cards/s/Seance.java @@ -75,7 +75,7 @@ class SeanceEffect extends OneShotEffect { effect.setAdditionalSubType(SubType.SPIRIT); effect.apply(game, source); ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanent(), game)); + exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanents(), game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); game.addDelayedTriggeredAbility(delayedAbility, source); return true; diff --git a/Mage.Sets/src/mage/cards/s/SplinterTwin.java b/Mage.Sets/src/mage/cards/s/SplinterTwin.java index 2ed704d7408..584ff927417 100644 --- a/Mage.Sets/src/mage/cards/s/SplinterTwin.java +++ b/Mage.Sets/src/mage/cards/s/SplinterTwin.java @@ -81,7 +81,7 @@ class SplinterTwinEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true); effect.setTargetPointer(new FixedTarget(permanent, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { + for (Permanent addedToken : effect.getAddedPermanents()) { ExileTargetEffect exileEffect = new ExileTargetEffect(); exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); diff --git a/Mage.Sets/src/mage/cards/t/Twinflame.java b/Mage.Sets/src/mage/cards/t/Twinflame.java index 7487d457628..748b833d0f0 100644 --- a/Mage.Sets/src/mage/cards/t/Twinflame.java +++ b/Mage.Sets/src/mage/cards/t/Twinflame.java @@ -77,7 +77,7 @@ class TwinflameCopyEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true); effect.setTargetPointer(new FixedTarget(creature, game)); effect.apply(game, source); - toExile.addAll(effect.getAddedPermanent()); + toExile.addAll(effect.getAddedPermanents()); } } ExileTargetEffect exileEffect = new ExileTargetEffect(); diff --git a/Mage.Sets/src/mage/sets/CrimsonVowCommander.java b/Mage.Sets/src/mage/sets/CrimsonVowCommander.java index 4ae6c908ed9..b12fde7584c 100644 --- a/Mage.Sets/src/mage/sets/CrimsonVowCommander.java +++ b/Mage.Sets/src/mage/sets/CrimsonVowCommander.java @@ -99,6 +99,7 @@ public final class CrimsonVowCommander extends ExpansionSet { cards.add(new SetCardInfo("Midnight Arsonist", 27, Rarity.RARE, mage.cards.m.MidnightArsonist.class)); cards.add(new SetCardInfo("Midnight Clock", 108, Rarity.RARE, mage.cards.m.MidnightClock.class)); cards.add(new SetCardInfo("Millicent, Restless Revenant", 1, Rarity.MYTHIC, mage.cards.m.MillicentRestlessRevenant.class)); + cards.add(new SetCardInfo("Mirage Phalanx", 35, Rarity.RARE, mage.cards.m.MiragePhalanx.class)); cards.add(new SetCardInfo("Mirror Entity", 94, Rarity.RARE, mage.cards.m.MirrorEntity.class)); cards.add(new SetCardInfo("Mob Rule", 147, Rarity.RARE, mage.cards.m.MobRule.class)); cards.add(new SetCardInfo("Molten Echoes", 148, Rarity.RARE, mage.cards.m.MoltenEchoes.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java index 03bd54c43cb..92746ff3728 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java @@ -3,10 +3,14 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; import mage.abilities.Mode; +import mage.abilities.TriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.EffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; @@ -16,43 +20,44 @@ import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.EmptyToken; +import mage.game.turn.Step; import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; import mage.util.CardUtil; import mage.util.functions.CopyApplier; import mage.util.functions.EmptyCopyApplier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; +import java.util.*; /** * @author LevelX2 */ public class CreateTokenCopyTargetEffect extends OneShotEffect { - private final UUID playerId; - private final CardType additionalCardType; - private boolean hasHaste; - private int number; + private final Set> abilityClazzesToRemove; private final List addedTokenPermanents; + private final List additionalAbilities; + private final CardType additionalCardType; private SubType additionalSubType; - private SubType onlySubType; - private final boolean tapped; - private final boolean attacking; private final UUID attackedPlayer; - private final int tokenPower; - private final int tokenToughness; - private final boolean gainsFlying; + private final boolean attacking; private boolean becomesArtifact; private ObjectColor color; - private boolean useLKI = false; - private boolean isntLegendary = false; - private int startingLoyalty = -1; - private final List additionalAbilities = new ArrayList(); - private Permanent savedPermanent = null; private CounterType counter; + private final boolean gainsFlying; + private boolean hasHaste; + private boolean isntLegendary = false; + private int number; private int numberOfCounters; + private SubType onlySubType; + private final UUID playerId; + private final boolean tapped; + private Permanent savedPermanent = null; + private int startingLoyalty = -1; + private final int tokenPower; + private final int tokenToughness; + private boolean useLKI = false; + public CreateTokenCopyTargetEffect(boolean useLKI) { this(); @@ -111,27 +116,37 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { this.tokenPower = power; this.tokenToughness = toughness; this.gainsFlying = gainsFlying; + + this.abilityClazzesToRemove = new HashSet<>(); + this.additionalAbilities = new ArrayList<>(); } public CreateTokenCopyTargetEffect(final CreateTokenCopyTargetEffect effect) { super(effect); - this.playerId = effect.playerId; - this.additionalCardType = effect.additionalCardType; - this.hasHaste = effect.hasHaste; + + this.abilityClazzesToRemove = new HashSet<>(effect.abilityClazzesToRemove); this.addedTokenPermanents = new ArrayList<>(effect.addedTokenPermanents); - this.number = effect.number; + this.additionalAbilities = new ArrayList<>(effect.additionalAbilities); + this.additionalCardType = effect.additionalCardType; this.additionalSubType = effect.additionalSubType; - this.onlySubType = effect.onlySubType; - this.tapped = effect.tapped; - this.attacking = effect.attacking; this.attackedPlayer = effect.attackedPlayer; - this.tokenPower = effect.tokenPower; - this.tokenToughness = effect.tokenToughness; - this.gainsFlying = effect.gainsFlying; + this.attacking = effect.attacking; this.becomesArtifact = effect.becomesArtifact; this.color = effect.color; - this.useLKI = effect.useLKI; + this.counter = effect.counter; + this.gainsFlying = effect.gainsFlying; + this.hasHaste = effect.hasHaste; this.isntLegendary = effect.isntLegendary; + this.number = effect.number; + this.numberOfCounters = effect.numberOfCounters; + this.onlySubType = effect.onlySubType; + this.playerId = effect.playerId; + this.savedPermanent = effect.savedPermanent; + this.startingLoyalty = effect.startingLoyalty; + this.tapped = effect.tapped; + this.tokenPower = effect.tokenPower; + this.tokenToughness = effect.tokenToughness; + this.useLKI = effect.useLKI; } @Override @@ -224,6 +239,25 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { } additionalAbilities.stream().forEach(token::addAbility); + if (!this.abilityClazzesToRemove.isEmpty()) { + List abilitiesToRemoveTmp = new ArrayList<>(); + + // Find the ones to remove + for (Ability ability : token.getAbilities()) { + if (this.abilityClazzesToRemove.contains(ability.getClass())) { + abilitiesToRemoveTmp.add(ability); + } + } + + // Remove them + for (Ability ability : abilitiesToRemoveTmp) { + // Remove subabilities + token.removeAbilities(ability.getSubAbilities()); + // Remove the ability + token.removeAbility(ability); + } + } + token.putOntoBattlefield(number, game, source, playerId == null ? source.getControllerId() : playerId, tapped, attacking, attackedPlayer); for (UUID tokenId : token.getLastAddedTokenIds()) { // by cards like Doubling Season multiple tokens can be added to the battlefield Permanent tokenPermanent = game.getPermanent(tokenId); @@ -280,7 +314,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { return sb.toString(); } - public List getAddedPermanent() { + public List getAddedPermanents() { return addedTokenPermanents; } @@ -321,26 +355,43 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { } public void exileTokensCreatedAtNextEndStep(Game game, Ability source) { - for (Permanent tokenPermanent : addedTokenPermanents) { - ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD); - exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); - } + this.exileTokensCreatedAtEndOf(game, source, PhaseStep.END_TURN); } public void exileTokensCreatedAtEndOfCombat(Game game, Ability source) { - for (Permanent tokenPermanent : addedTokenPermanents) { + this.exileTokensCreatedAtEndOf(game, source, PhaseStep.END_COMBAT); + } - ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD); - exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); - game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), source); + private void exileTokensCreatedAtEndOf(Game game, Ability source, PhaseStep phaseStepToExileCards) { + ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD); + exileEffect.setText("exile the token copies"); + exileEffect.setTargetPointer(new FixedTargets(addedTokenPermanents, game)); + + DelayedTriggeredAbility exileAbility; + + switch (phaseStepToExileCards) { + case END_TURN: + exileAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + break; + case END_COMBAT: + exileAbility = new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect); + break; + default: + return; } + + game.addDelayedTriggeredAbility(exileAbility, source); + } + + public void addAbilityClassesToRemoveFromTokens(Class clazz) { + this.abilityClazzesToRemove.add(clazz); } public void addAdditionalAbilities(Ability... abilities) { - Arrays.stream(abilities).forEach(this.additionalAbilities::add); + this.additionalAbilities.addAll(Arrays.asList(abilities)); } + public CreateTokenCopyTargetEffect setSavedPermanent(Permanent savedPermanent) { this.savedPermanent = savedPermanent; return this; diff --git a/Mage/src/main/java/mage/abilities/keyword/MyriadAbility.java b/Mage/src/main/java/mage/abilities/keyword/MyriadAbility.java index ae1ad7f3d94..0aaa7018e28 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MyriadAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MyriadAbility.java @@ -79,7 +79,7 @@ class MyriadEffect extends OneShotEffect { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(controller.getId(), null, false, 1, true, true, playerId); effect.setTargetPointer(new FixedTarget(sourceObject, game)); effect.apply(game, source); - tokens.addAll(effect.getAddedPermanent()); + tokens.addAll(effect.getAddedPermanents()); } } } diff --git a/Mage/src/main/java/mage/game/permanent/token/Token.java b/Mage/src/main/java/mage/game/permanent/token/Token.java index f072d1cf88c..02c5b36bc51 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Token.java @@ -27,6 +27,10 @@ public interface Token extends MageObject { void addAbility(Ability ability); + void removeAbility(Ability abilityToRemove); + + void removeAbilities(List abilitiesToRemove); + boolean putOntoBattlefield(int amount, Game game, Ability source); boolean putOntoBattlefield(int amount, Game game, Ability source, UUID controllerId); diff --git a/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java b/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java index 43864b47d06..a323b1af453 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java +++ b/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java @@ -130,6 +130,35 @@ public abstract class TokenImpl extends MageObjectImpl implements Token { abilities.addAll(ability.getSubAbilities()); } + // Directly from PermanentImpl + @Override + public void removeAbility(Ability abilityToRemove) { + if (abilityToRemove == null) { + return; + } + + // 112.10b Effects that remove an ability remove all instances of it. + List toRemove = new ArrayList<>(); + abilities.forEach(a -> { + if (a.isSameInstance(abilityToRemove)) { + toRemove.add(a); + } + }); + + // TODO: what about triggered abilities? See addAbility above -- triggers adds to GameState + toRemove.forEach(r -> abilities.remove(r)); + } + + // Directly from PermanentImpl + @Override + public void removeAbilities(List abilitiesToRemove) { + if (abilitiesToRemove == null) { + return; + } + + abilitiesToRemove.forEach(a -> removeAbility(a)); + } + @Override public boolean putOntoBattlefield(int amount, Game game, Ability source) { return this.putOntoBattlefield(amount, game, source, source.getControllerId());