diff --git a/Mage.Sets/src/mage/cards/a/ActOfAuthority.java b/Mage.Sets/src/mage/cards/a/ActOfAuthority.java index 913dc43fbba..38dcd6ca161 100644 --- a/Mage.Sets/src/mage/cards/a/ActOfAuthority.java +++ b/Mage.Sets/src/mage/cards/a/ActOfAuthority.java @@ -94,9 +94,12 @@ class ActOfAuthorityEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent targetPermanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); if (targetPermanent != null && new ExileTargetEffect().apply(game, source)) { - ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId()); - effect.setTargetPointer(new FixedTarget(source.getSourceId())); - game.addEffect(effect, source); + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + if (sourcePermanent != null) { + ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId()); + effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); + game.addEffect(effect, source); + } return true; } return false; diff --git a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java index ae3abfebab8..0fccaadd0dd 100644 --- a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java +++ b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java @@ -109,7 +109,7 @@ class AdarkarValkyrieEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new FixedTarget(this.getTargetPointer().getFirst(game, source))); + DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(getTargetPointer().getFixedTarget(game, source)); game.addDelayedTriggeredAbility(delayedAbility, source); return false; } diff --git a/Mage.Sets/src/mage/cards/a/AnkhOfMishra.java b/Mage.Sets/src/mage/cards/a/AnkhOfMishra.java index 38272e1e8ef..a31aa9dbf4c 100644 --- a/Mage.Sets/src/mage/cards/a/AnkhOfMishra.java +++ b/Mage.Sets/src/mage/cards/a/AnkhOfMishra.java @@ -45,16 +45,16 @@ import mage.target.targetpointer.FixedTarget; /** * * @author KholdFuzion - + * */ public class AnkhOfMishra extends CardImpl { - + public AnkhOfMishra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land's controller. this.addAbility(new AnkhOfMishraAbility()); - + } public AnkhOfMishra(final AnkhOfMishra card) { @@ -70,16 +70,16 @@ public class AnkhOfMishra extends CardImpl { class AnkhOfMishraAbility extends TriggeredAbilityImpl { public AnkhOfMishraAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2)); } AnkhOfMishraAbility(final AnkhOfMishraAbility ability) { - super(ability); + super(ability); } @Override public AnkhOfMishraAbility copy() { - return new AnkhOfMishraAbility(this); + return new AnkhOfMishraAbility(this); } @Override @@ -104,6 +104,6 @@ class AnkhOfMishraAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land's controller."; + return "Whenever a land enters the battlefield, {this} deals 2 damage to that land's controller."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java b/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java index 31453ff15bf..de172fddb18 100644 --- a/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java +++ b/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java @@ -29,6 +29,7 @@ package mage.cards.a; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; @@ -53,7 +54,7 @@ import mage.target.targetpointer.FixedTarget; public class ArbiterOfTheIdeal extends CardImpl { public ArbiterOfTheIdeal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); this.subtype.add(SubType.SPHINX); this.power = new MageInt(4); @@ -79,6 +80,7 @@ public class ArbiterOfTheIdeal extends CardImpl { class ArbiterOfTheIdealEffect extends OneShotEffect { private static final FilterCard filter = new FilterCard(); + static { filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), @@ -102,32 +104,25 @@ class ArbiterOfTheIdealEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller == null || sourceObject == null) { return false; } - - if (player.getLibrary().hasCards()) { - Card card = player.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); - cards.add(card); - player.revealCards("Arbiter of the Ideal", cards, game); - - if (card != null) { - if (filter.match(card, game) && player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append("onto battlefield?").toString(), source, game)) { - card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - permanent.addCounters(new Counter("Manifestation"), source, game); - ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ENCHANTMENT); - effect.setTargetPointer(new FixedTarget(permanent.getId())); - game.addEffect(effect, source); - } + Card card = controller.getLibrary().getFromTop(game); + if (card != null) { + controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); + if (filter.match(card, game) && controller.chooseUse(outcome, "Put " + card.getName() + "onto battlefield?", source, game)) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + permanent.addCounters(new Counter("Manifestation"), source, game); + ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ENCHANTMENT); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } } - return true; } - - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/ArchonOfRedemption.java b/Mage.Sets/src/mage/cards/a/ArchonOfRedemption.java index 6b3507d3487..50342b73b40 100644 --- a/Mage.Sets/src/mage/cards/a/ArchonOfRedemption.java +++ b/Mage.Sets/src/mage/cards/a/ArchonOfRedemption.java @@ -29,23 +29,18 @@ package mage.cards.a; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.targetpointer.FixedTarget; /** * @author Loki @@ -53,7 +48,7 @@ import mage.target.targetpointer.FixedTarget; public class ArchonOfRedemption extends CardImpl { public ArchonOfRedemption(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.ARCHON); this.power = new MageInt(3); @@ -75,8 +70,9 @@ public class ArchonOfRedemption extends CardImpl { } class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl { + ArchonOfRedemptionTriggeredAbility() { - super(Zone.BATTLEFIELD, new ArchonOfRedemptionEffect(), true); + super(Zone.BATTLEFIELD, null, true); } ArchonOfRedemptionTriggeredAbility(final ArchonOfRedemptionTriggeredAbility ability) { @@ -95,15 +91,13 @@ class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - UUID targetId = event.getTargetId(); - Permanent permanent = game.getPermanent(targetId); - if (permanent.getControllerId().equals(this.controllerId) + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent.getControllerId().equals(getControllerId()) && permanent.isCreature() - && (targetId.equals(this.getSourceId()) - || (permanent.getAbilities().contains(FlyingAbility.getInstance()) && !targetId.equals(this.getSourceId())))) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - } + && (permanent.getId().equals(getSourceId()) + || (permanent.getAbilities().contains(FlyingAbility.getInstance())))) { + this.getEffects().clear(); + this.addEffect(new GainLifeEffect(permanent.getPower().getValue())); return true; } return false; @@ -111,35 +105,6 @@ class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever {this} or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power"; + return "Whenever {this} or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power."; } } - -class ArchonOfRedemptionEffect extends OneShotEffect { - ArchonOfRedemptionEffect() { - super(Outcome.GainLife); - } - - ArchonOfRedemptionEffect(final ArchonOfRedemptionEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent p = game.getPermanent(targetPointer.getFirst(game, source)); - Player player = game.getPlayer(source.getControllerId()); - if (p == null) { - p = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); - } - if (p != null && player != null) { - player.gainLife(p.getPower().getValue(), game); - return true; - } - return false; - } - - @Override - public ArchonOfRedemptionEffect copy() { - return new ArchonOfRedemptionEffect(this); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/ArrogantBloodlord.java b/Mage.Sets/src/mage/cards/a/ArrogantBloodlord.java index e6c11100593..0aa16e9cfe5 100644 --- a/Mage.Sets/src/mage/cards/a/ArrogantBloodlord.java +++ b/Mage.Sets/src/mage/cards/a/ArrogantBloodlord.java @@ -53,7 +53,7 @@ import mage.target.targetpointer.FixedTarget; public class ArrogantBloodlord extends CardImpl { public ArrogantBloodlord(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); this.subtype.add(SubType.VAMPIRE); this.subtype.add(SubType.KNIGHT); @@ -104,11 +104,8 @@ class ArrogantBloodlordTriggeredAbility extends TriggeredAbilityImpl { && Objects.equals(blocked, arrogantBloodlord)) { return true; } - if (blocker != null && Objects.equals(blocker, arrogantBloodlord) - && game.getPermanent(event.getTargetId()).getPower().getValue() < 2) { - return true; - } - return false; + return blocker != null && Objects.equals(blocker, arrogantBloodlord) + && game.getPermanent(event.getTargetId()).getPower().getValue() < 2; } @Override @@ -133,7 +130,7 @@ class ArrogantBloodlordEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new DestroyTargetEffect()); - delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(source.getSourceId())); + delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(permanent, game)); game.addDelayedTriggeredAbility(delayedAbility, source); return true; } diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java index d6baff95d43..d0a8f783aa9 100644 --- a/Mage/src/main/java/mage/abilities/Ability.java +++ b/Mage/src/main/java/mage/abilities/Ability.java @@ -45,6 +45,7 @@ import mage.constants.Zone; import mage.game.Controllable; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.Targets; @@ -535,6 +536,17 @@ public interface Ability extends Controllable, Serializable { */ MageObject getSourceObjectIfItStillExists(Game game); + /** + * Returns the permanent that actually existed while the ability triggerd or + * an ability was activated only if it has not changed zone meanwhile. If + * not set yet, the current permanent if one exists will be retrieved from + * the game and returned. + * + * @param game + * @return + */ + Permanent getSourcePermanentIfItStillExists(Game game); + String getTargetDescription(Targets targets, Game game); void setCanFizzle(boolean canFizzle); diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 23f81762129..25528d242b6 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -1211,6 +1211,19 @@ public abstract class AbilityImpl implements Ability { return null; } + @Override + public Permanent getSourcePermanentIfItStillExists(Game game) { + if (sourceObject == null) { + setSourceObject(game.getObject(getSourceId()), game); + } + if (sourceObject instanceof Permanent) { + if (game.getState().getZoneChangeCounter(getSourceId()) == getSourceObjectZoneChangeCounter()) { + return (Permanent) sourceObject; + } + } + return null; + } + @Override public int getSourceObjectZoneChangeCounter() { return sourceObjectZoneChangeCounter; diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index 07509f57863..00eabb629a5 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -50,6 +50,7 @@ import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.Targets; @@ -529,12 +530,17 @@ public class StackAbility extends StackObjImpl implements Ability { @Override public MageObject getSourceObject(Game game) { - return game.getBaseObject(getSourceId()); + return this.ability.getSourceObject(game); } @Override public MageObject getSourceObjectIfItStillExists(Game game) { - throw new UnsupportedOperationException("Not supported."); + return this.ability.getSourceObjectIfItStillExists(game); + } + + @Override + public Permanent getSourcePermanentIfItStillExists(Game game) { + return this.ability.getSourcePermanentIfItStillExists(game); } @Override diff --git a/Mage/src/main/java/mage/target/targetpointer/FirstTargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/FirstTargetPointer.java index 01d2b3c7db8..82241949ebf 100644 --- a/Mage/src/main/java/mage/target/targetpointer/FirstTargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/FirstTargetPointer.java @@ -35,7 +35,7 @@ public class FirstTargetPointer implements TargetPointer { Card card = game.getCard(target); if (card != null) { this.zoneChangeCounter.put(target, card.getZoneChangeCounter(game)); - } + } } } } @@ -66,9 +66,9 @@ public class FirstTargetPointer implements TargetPointer { if (zoneChangeCounter.containsKey(targetId)) { Card card = game.getCard(targetId); if (card != null && zoneChangeCounter.containsKey(targetId) - && card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) { - // because if dies trigger has to trigger as permanent has already moved zone, we have to check if target was on the battlefield immed. before - // but no longer if new permanent is already on the battlefield + && card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) { + // because if dies trigger has to trigger as permanent has already moved zone, we have to check if target was on the battlefield immed. before + // but no longer if new permanent is already on the battlefield Permanent permanent = game.getPermanentOrLKIBattlefield(targetId); if (permanent == null || permanent.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) { return null; @@ -82,4 +82,16 @@ public class FirstTargetPointer implements TargetPointer { public TargetPointer copy() { return new FirstTargetPointer(this); } + + @Override + public FixedTarget getFixedTarget(Game game, Ability source) { + this.init(game, source); + UUID firstId = getFirst(game, source); + if (firstId != null) { + return new FixedTarget(firstId, game.getState().getZoneChangeCounter(firstId)); + } + return null; + + } + } diff --git a/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java b/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java index 397e4e7de3d..c931962322d 100644 --- a/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java +++ b/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java @@ -1,15 +1,14 @@ package mage.target.targetpointer; -import mage.abilities.Ability; -import mage.cards.Card; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; +import mage.abilities.Ability; +import mage.cards.Card; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; public class FixedTarget implements TargetPointer { @@ -65,10 +64,7 @@ public class FixedTarget implements TargetPointer { public void init(Game game, Ability source) { if (!initialized) { initialized = true; - Card card = game.getCard(targetId); - if (card != null) { - this.zoneChangeCounter = card.getZoneChangeCounter(game); - } + this.zoneChangeCounter = game.getState().getZoneChangeCounter(targetId); } } @@ -121,4 +117,10 @@ public class FixedTarget implements TargetPointer { return permanent; } + @Override + public FixedTarget getFixedTarget(Game game, Ability source) { + init(game, source); + return this; + } + } diff --git a/Mage/src/main/java/mage/target/targetpointer/SecondTargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/SecondTargetPointer.java index db301a70553..4917726dfa6 100644 --- a/Mage/src/main/java/mage/target/targetpointer/SecondTargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/SecondTargetPointer.java @@ -1,11 +1,10 @@ package mage.target.targetpointer; +import java.util.*; import mage.abilities.Ability; import mage.cards.Card; import mage.game.Game; -import java.util.*; - public class SecondTargetPointer implements TargetPointer { private Map zoneChangeCounter = new HashMap<>(); @@ -59,7 +58,7 @@ public class SecondTargetPointer implements TargetPointer { if (zoneChangeCounter.containsKey(targetId)) { Card card = game.getCard(targetId); if (card != null && zoneChangeCounter.containsKey(targetId) - && card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) { + && card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) { return null; } } @@ -72,4 +71,15 @@ public class SecondTargetPointer implements TargetPointer { public TargetPointer copy() { return new SecondTargetPointer(this); } + + @Override + public FixedTarget getFixedTarget(Game game, Ability source) { + this.init(game, source); + UUID firstId = getFirst(game, source); + if (firstId != null) { + return new FixedTarget(firstId, game.getState().getZoneChangeCounter(firstId)); + } + return null; + + } } diff --git a/Mage/src/main/java/mage/target/targetpointer/TargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/TargetPointer.java index 0b77cd2bf67..6dd021c9ac5 100644 --- a/Mage/src/main/java/mage/target/targetpointer/TargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/TargetPointer.java @@ -7,8 +7,14 @@ import mage.abilities.Ability; import mage.game.Game; public interface TargetPointer extends Serializable { + void init(Game game, Ability source); + List getTargets(Game game, Ability source); + UUID getFirst(Game game, Ability source); + TargetPointer copy(); + + FixedTarget getFixedTarget(Game game, Ability source); } diff --git a/Mage/src/main/java/mage/target/targetpointer/ThirdTargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/ThirdTargetPointer.java index 2fdbf05037f..206bfe2eb9e 100644 --- a/Mage/src/main/java/mage/target/targetpointer/ThirdTargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/ThirdTargetPointer.java @@ -84,4 +84,15 @@ public class ThirdTargetPointer implements TargetPointer { public TargetPointer copy() { return new ThirdTargetPointer(this); } + + @Override + public FixedTarget getFixedTarget(Game game, Ability source) { + this.init(game, source); + UUID firstId = getFirst(game, source); + if (firstId != null) { + return new FixedTarget(firstId, game.getState().getZoneChangeCounter(firstId)); + } + return null; + + } }