diff --git a/Mage.Sets/src/mage/cards/a/AjaniInspiringLeader.java b/Mage.Sets/src/mage/cards/a/AjaniInspiringLeader.java index 8f3d473b0e6..d7a4eb57c5d 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniInspiringLeader.java +++ b/Mage.Sets/src/mage/cards/a/AjaniInspiringLeader.java @@ -2,8 +2,9 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.GainLifeTargetControllerEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.DoubleStrikeAbility; @@ -13,9 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -39,8 +37,9 @@ public final class AjaniInspiringLeader extends CardImpl { this.addAbility(ability); // −3: Exile target creature. Its controller gains 2 life. - ability = new LoyaltyAbility(new AjaniInspiringLeaderEffect(), -3); + ability = new LoyaltyAbility(new ExileTargetEffect(), -3); ability.addTarget(new TargetCreaturePermanent()); + ability.addEffect(new GainLifeTargetControllerEffect(2)); this.addAbility(ability); // −10: Creatures you control gain flying and double strike until end of turn. @@ -64,34 +63,3 @@ public final class AjaniInspiringLeader extends CardImpl { return new AjaniInspiringLeader(this); } } - -class AjaniInspiringLeaderEffect extends OneShotEffect { - - AjaniInspiringLeaderEffect() { - super(Outcome.Benefit); - staticText = "Exile target creature. Its controller gains 2 life."; - } - - private AjaniInspiringLeaderEffect(final AjaniInspiringLeaderEffect effect) { - super(effect); - } - - @Override - public AjaniInspiringLeaderEffect copy() { - return new AjaniInspiringLeaderEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent == null) { - return false; - } - Player player = game.getPlayer(permanent.getControllerId()); - if (player == null) { - return false; - } - player.gainLife(2, game, source); - return player.moveCards(permanent, Zone.EXILED, source, game); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/l/LastBreath.java b/Mage.Sets/src/mage/cards/l/LastBreath.java index b82914366c8..b2ba30379ec 100644 --- a/Mage.Sets/src/mage/cards/l/LastBreath.java +++ b/Mage.Sets/src/mage/cards/l/LastBreath.java @@ -1,21 +1,17 @@ package mage.cards.l; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.GainLifeTargetControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Outcome; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; +import java.util.UUID; + /** * * @author LevelX2 @@ -33,7 +29,7 @@ public final class LastBreath extends CardImpl { // Exile target creature with power 2 or less. Its controller gains 4 life. this.getSpellAbility().addEffect(new ExileTargetEffect()); - this.getSpellAbility().addEffect(new LastBreathEffect()); + this.getSpellAbility().addEffect(new GainLifeTargetControllerEffect(4)); this.getSpellAbility().addTarget(new TargetPermanent(filter)); } @@ -47,34 +43,3 @@ public final class LastBreath extends CardImpl { return new LastBreath(this); } } - -class LastBreathEffect extends OneShotEffect { - - LastBreathEffect() { - super(Outcome.GainLife); - staticText = "Its controller gains 4 life"; - } - - private LastBreathEffect(final LastBreathEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent target = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); - if (target != null) { - Player player = game.getPlayer(target.getControllerId()); - if (player != null) { - player.gainLife(4, game, source); - return true; - } - } - return false; - } - - @Override - public LastBreathEffect copy() { - return new LastBreathEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/l/LayDownArms.java b/Mage.Sets/src/mage/cards/l/LayDownArms.java index 44475d4ab77..cf8a4eef33e 100644 --- a/Mage.Sets/src/mage/cards/l/LayDownArms.java +++ b/Mage.Sets/src/mage/cards/l/LayDownArms.java @@ -1,17 +1,15 @@ package mage.cards.l; -import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.GainLifeTargetControllerEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; 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.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; @@ -19,10 +17,8 @@ import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; -import java.util.Optional; import java.util.UUID; /** @@ -42,8 +38,9 @@ public final class LayDownArms extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}"); // Exile target creature with mana value less than or equal to the number of Plains you control. Its controller gains 3 life. - this.getSpellAbility().addEffect(new LayDownArmsEffect()); + this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addEffect(new GainLifeTargetControllerEffect(3)); this.getSpellAbility().addHint(LayDownArmsPredicate.getHint()); } @@ -72,34 +69,3 @@ enum LayDownArmsPredicate implements ObjectSourcePlayerPredicate { return hint; } } - -class LayDownArmsEffect extends OneShotEffect { - - LayDownArmsEffect() { - super(Outcome.Benefit); - staticText = "exile target creature with mana value less than or equal " + - "to the number of Plains you control. Its controller gains 3 life"; - } - - private LayDownArmsEffect(final LayDownArmsEffect effect) { - super(effect); - } - - @Override - public LayDownArmsEffect copy() { - return new LayDownArmsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (controller == null || permanent == null) { - return false; - } - controller.moveCards(permanent, Zone.EXILED, source, game); - Optional.ofNullable(game.getPlayer(permanent.getControllerId())) - .ifPresent(player -> player.gainLife(3, game, source)); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/n/NaturesClaim.java b/Mage.Sets/src/mage/cards/n/NaturesClaim.java index 2107c6aef26..1b281725d45 100644 --- a/Mage.Sets/src/mage/cards/n/NaturesClaim.java +++ b/Mage.Sets/src/mage/cards/n/NaturesClaim.java @@ -1,17 +1,11 @@ - package mage.cards.n; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.GainLifeTargetControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import java.util.UUID; @@ -27,7 +21,7 @@ public final class NaturesClaim extends CardImpl { // Destroy target artifact or enchantment. Its controller gains 4 life. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addEffect(new NaturesClaimEffect()); + this.getSpellAbility().addEffect(new GainLifeTargetControllerEffect(4)); this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); } @@ -40,33 +34,3 @@ public final class NaturesClaim extends CardImpl { return new NaturesClaim(this); } } - -class NaturesClaimEffect extends OneShotEffect { - - NaturesClaimEffect() { - super(Outcome.GainLife); - staticText = "Its controller gains 4 life"; - } - - private NaturesClaimEffect(final NaturesClaimEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent target = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); - if (target != null) { - Player player = game.getPlayer(target.getControllerId()); - if (player != null) { - player.gainLife(4, game, source); - return true; - } - } - return false; - } - - @Override - public NaturesClaimEffect copy() { - return new NaturesClaimEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/Oust.java b/Mage.Sets/src/mage/cards/o/Oust.java index 7b5e1fe9dc5..c094492e20b 100644 --- a/Mage.Sets/src/mage/cards/o/Oust.java +++ b/Mage.Sets/src/mage/cards/o/Oust.java @@ -1,17 +1,14 @@ package mage.cards.o; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeTargetControllerEffect; +import mage.abilities.effects.common.PutIntoLibraryNFromTopTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author North @@ -22,7 +19,8 @@ public final class Oust extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}"); // Put target creature into its owner's library second from the top. Its controller gains 3 life. - this.getSpellAbility().addEffect(new OustEffect()); + this.getSpellAbility().addEffect(new PutIntoLibraryNFromTopTargetEffect(2)); + this.getSpellAbility().addEffect(new GainLifeTargetControllerEffect(3)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } @@ -35,35 +33,3 @@ public final class Oust extends CardImpl { return new Oust(this); } } - -class OustEffect extends OneShotEffect { - - OustEffect() { - super(Outcome.Benefit); - this.staticText = "Put target creature into its owner's library second from the top. Its controller gains 3 life"; - } - - private OustEffect(final OustEffect effect) { - super(effect); - } - - @Override - public OustEffect copy() { - return new OustEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null) { - Player owner = game.getPlayer(permanent.getOwnerId()); - Player controller = game.getPlayer(permanent.getControllerId()); - if (owner == null || controller == null) { - return false; - } - owner.putCardOnTopXOfLibrary(permanent, game, source, 2, true); - controller.gainLife(3, game, source); - } - return true; - } -} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mmq/LastBreathTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mmq/LastBreathTest.java new file mode 100644 index 00000000000..9d570474ebd --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mmq/LastBreathTest.java @@ -0,0 +1,57 @@ +package org.mage.test.cards.single.mmq; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author xenohedron + */ +public class LastBreathTest extends CardTestPlayerBase { + + // Exile target creature with power 2 or less. Its controller gains 4 life. + private static final String lastBreath = "Last Breath"; // 1W Instant + private static final String drake = "Wind Drake"; + + @Test + public void testControllerGains() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, lastBreath); + addCard(Zone.BATTLEFIELD, playerB, drake); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lastBreath, drake); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, lastBreath, 1); + assertExileCount(playerB, drake, 1); + assertLife(playerA, 20); + assertLife(playerB, 24); + } + + @Test + public void testControllerChanged() { + String threaten = "Act of Treason"; + + addCard(Zone.HAND, playerA, lastBreath); + addCard(Zone.BATTLEFIELD, playerB, drake); + addCard(Zone.BATTLEFIELD, playerA, "Plateau", 5); + addCard(Zone.HAND, playerA, threaten); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, threaten, drake); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, lastBreath, drake); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, lastBreath, 1); + assertExileCount(playerB, drake, 1); + assertLife(playerA, 24); + assertLife(playerB, 20); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/GainLifeTargetControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/GainLifeTargetControllerEffect.java new file mode 100644 index 00000000000..7d91aa12e91 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/GainLifeTargetControllerEffect.java @@ -0,0 +1,59 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; + +/** + * @author xenohedron + */ +public class GainLifeTargetControllerEffect extends OneShotEffect { + + protected DynamicValue amount; + + public GainLifeTargetControllerEffect(int amount) { + this(StaticValue.get(amount)); + this.staticText = "its controller gains " + amount + " life"; + } + + public GainLifeTargetControllerEffect(DynamicValue amount) { + super(Outcome.GainLife); + this.amount = amount; + } + + protected GainLifeTargetControllerEffect(final GainLifeTargetControllerEffect effect) { + super(effect); + amount = effect.amount.copy(); + } + + @Override + public GainLifeTargetControllerEffect copy() { + return new GainLifeTargetControllerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetController = null; + Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); + if (permanent != null) { + targetController = game.getPlayer(permanent.getControllerId()); + } else { + Spell spell = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source)); + if (spell != null) { + targetController = game.getPlayer(spell.getControllerId()); + } + } + if (targetController != null) { + targetController.gainLife(amount.calculate(game, source, this), game, source); + return true; + } + return false; + } + +}