diff --git a/Mage.Sets/src/mage/cards/b/BlatantThievery.java b/Mage.Sets/src/mage/cards/b/BlatantThievery.java index 39bfb83a74c..376b88aa446 100644 --- a/Mage.Sets/src/mage/cards/b/BlatantThievery.java +++ b/Mage.Sets/src/mage/cards/b/BlatantThievery.java @@ -1,9 +1,7 @@ - package mage.cards.b; import java.util.*; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; @@ -18,6 +16,7 @@ import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; /** @@ -31,34 +30,37 @@ public final class BlatantThievery extends CardImpl { // For each opponent, gain control of target permanent that player controls. this.getSpellAbility().addEffect(new BlatantThieveryEffect()); + this.getSpellAbility().setTargetAdjuster(BlatantThieveryEffect.class); } public BlatantThievery(final BlatantThievery card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - for (UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterPermanent filter = new FilterPermanent("Permanent of player " + opponent.getName()); - filter.add(new ControllerIdPredicate(opponentId)); - TargetPermanent targetPermanent = new TargetPermanent(filter); - ability.addTarget(targetPermanent); - } - } - } - } - @Override public BlatantThievery copy() { return new BlatantThievery(this); } } +enum BlatantThieveryAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + FilterPermanent filter = new FilterPermanent("Permanent of player " + opponent.getName()); + filter.add(new ControllerIdPredicate(opponentId)); + TargetPermanent targetPermanent = new TargetPermanent(filter); + ability.addTarget(targetPermanent); + } + } + } +} + class BlatantThieveryEffect extends OneShotEffect { BlatantThieveryEffect() { diff --git a/Mage.Sets/src/mage/cards/d/DwarvenLandslide.java b/Mage.Sets/src/mage/cards/d/DwarvenLandslide.java index 1b7f92f62a9..056980f8959 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenLandslide.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenLandslide.java @@ -1,9 +1,7 @@ - package mage.cards.d; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; @@ -19,6 +17,7 @@ import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetLandPermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -27,34 +26,38 @@ import mage.target.common.TargetLandPermanent; public final class DwarvenLandslide extends CardImpl { public DwarvenLandslide(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Kicker-{2}{R}, Sacrifice a land. Costs kickerCosts = new CostsImpl<>(); kickerCosts.add(new ManaCostsImpl<>("{2}{R}")); kickerCosts.add(new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent("a land")))); this.addAbility(new KickerAbility(kickerCosts)); + // Destroy target land. If Dwarven Landslide was kicked, destroy another target land. getSpellAbility().addEffect(new DestroyTargetEffect("Destroy target land. if this spell was kicked, destroy another target land")); getSpellAbility().addTarget(new TargetLandPermanent()); + getSpellAbility().setTargetAdjuster(DwarvenLandslideAdjuster.instance); } public DwarvenLandslide(final DwarvenLandslide card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - if (KickedCondition.instance.apply(game, ability)) { - ability.getTargets().clear(); - getSpellAbility().addTarget(new TargetLandPermanent(2)); - } - } - } - @Override public DwarvenLandslide copy() { return new DwarvenLandslide(this); } } + +enum DwarvenLandslideAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + if (KickedCondition.instance.apply(game, ability)) { + ability.getTargets().clear(); + ability.addTarget(new TargetLandPermanent(2)); + } + } +} diff --git a/Mage.Sets/src/mage/cards/e/EliminateTheCompetition.java b/Mage.Sets/src/mage/cards/e/EliminateTheCompetition.java index 9b6b3c855a4..03ad3ea31bb 100644 --- a/Mage.Sets/src/mage/cards/e/EliminateTheCompetition.java +++ b/Mage.Sets/src/mage/cards/e/EliminateTheCompetition.java @@ -1,4 +1,3 @@ - package mage.cards.e; import java.util.UUID; @@ -9,11 +8,11 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityType; import mage.constants.CardType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -22,7 +21,7 @@ import mage.target.common.TargetCreaturePermanent; public final class EliminateTheCompetition extends CardImpl { public EliminateTheCompetition(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); // As an additional cost to cast Eliminate the Competition, sacrifice X creatures. this.getSpellAbility().addCost(new SacrificeXTargetCost(new FilterControlledCreaturePermanent("creatures"), true)); @@ -32,23 +31,26 @@ public final class EliminateTheCompetition extends CardImpl { effect.setText("Destroy X target creatures"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().setTargetAdjuster(EliminateTheCompetitionAdjuster.instance); } public EliminateTheCompetition(final EliminateTheCompetition card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getAbilityType() == AbilityType.SPELL) { - ability.getTargets().clear(); - int sac = new GetXValue().calculate(game, ability, null); - ability.addTarget(new TargetCreaturePermanent(sac, sac)); - } - } - @Override public EliminateTheCompetition copy() { return new EliminateTheCompetition(this); } } + +enum EliminateTheCompetitionAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int sac = new GetXValue().calculate(game, ability, null); + ability.addTarget(new TargetCreaturePermanent(sac, sac)); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FallingTimber.java b/Mage.Sets/src/mage/cards/f/FallingTimber.java index 90a39c76143..492c7e6f343 100644 --- a/Mage.Sets/src/mage/cards/f/FallingTimber.java +++ b/Mage.Sets/src/mage/cards/f/FallingTimber.java @@ -1,4 +1,3 @@ - package mage.cards.f; import java.util.UUID; @@ -16,38 +15,30 @@ import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * * @author LoneFox - + * */ public final class FallingTimber extends CardImpl { - private final UUID originalId; - public FallingTimber(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); // Kicker-Sacrifice a land. this.addAbility(new KickerAbility(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, new FilterControlledLandPermanent("a land"), true)))); + // Prevent all combat damage target creature would deal this turn. If Falling Timber was kicked, prevent all combat damage another target creature would deal this turn. Effect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn, true); effect.setText("Prevent all combat damage target creature would deal this turn. if this spell was kicked, prevent all combat damage another target creature would deal this turn."); this.getSpellAbility().addEffect(effect); - originalId = this.getSpellAbility().getOriginalId(); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if(ability.getOriginalId().equals(originalId)) { - ability.addTarget(new TargetCreaturePermanent(KickedCondition.instance.apply(game, ability) ? 2 : 1)); - } + this.getSpellAbility().setTargetAdjuster(FallingTimberAdjuster.instance); } public FallingTimber(final FallingTimber card) { super(card); - this.originalId = card.originalId; } @Override @@ -55,3 +46,13 @@ public final class FallingTimber extends CardImpl { return new FallingTimber(this); } } + +enum FallingTimberAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(KickedCondition.instance.apply(game, ability) ? 2 : 1)); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FightWithFire.java b/Mage.Sets/src/mage/cards/f/FightWithFire.java index ebad07ad966..67b7b683a84 100644 --- a/Mage.Sets/src/mage/cards/f/FightWithFire.java +++ b/Mage.Sets/src/mage/cards/f/FightWithFire.java @@ -1,9 +1,7 @@ - package mage.cards.f; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DamageMultiEffect; @@ -16,6 +14,7 @@ import mage.game.Game; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAnyTargetAmount; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -39,26 +38,29 @@ public final class FightWithFire extends CardImpl { + " (Those targets can include players and planeswalkers.)" )); this.getSpellAbility().addTarget(new TargetAnyTarget()); + this.getSpellAbility().setTargetAdjuster(FightWithFireAdjuster.instance); } public FightWithFire(final FightWithFire card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - ability.getTargets().clear(); - if (ability instanceof SpellAbility) { - if (KickedCondition.instance.apply(game, ability)) { - ability.addTarget(new TargetAnyTargetAmount(10)); - } else { - ability.addTarget(new TargetCreaturePermanent()); - } - } - } - @Override public FightWithFire copy() { return new FightWithFire(this); } } + +enum FightWithFireAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + if (KickedCondition.instance.apply(game, ability)) { + ability.addTarget(new TargetAnyTargetAmount(10)); + } else { + ability.addTarget(new TargetCreaturePermanent()); + } + } +} diff --git a/Mage.Sets/src/mage/cards/f/Firestorm.java b/Mage.Sets/src/mage/cards/f/Firestorm.java index 584afbec575..ba503d37905 100644 --- a/Mage.Sets/src/mage/cards/f/Firestorm.java +++ b/Mage.Sets/src/mage/cards/f/Firestorm.java @@ -1,4 +1,3 @@ - package mage.cards.f; import java.util.UUID; @@ -16,6 +15,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetAnyTarget; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -24,19 +24,28 @@ import mage.target.common.TargetAnyTarget; public final class Firestorm extends CardImpl { public Firestorm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // As an additional cost to cast Firestorm, discard X cards. this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("cards"), true)); // Firestorm deals X damage to each of X target creatures and/or players. this.getSpellAbility().addEffect(new FirestormEffect()); + this.getSpellAbility().setTargetAdjuster(FirestormAdjuster.instance); } public Firestorm(final Firestorm card) { super(card); } + @Override + public Firestorm copy() { + return new Firestorm(this); + } +} + +enum FirestormAdjuster implements TargetAdjuster { + instance; + @Override public void adjustTargets(Ability ability, Game game) { int xValue = new GetXValue().calculate(game, ability, null); @@ -45,11 +54,6 @@ public final class Firestorm extends CardImpl { ability.addTarget(target); } } - - @Override - public Firestorm copy() { - return new Firestorm(this); - } } class FirestormEffect extends OneShotEffect { @@ -85,9 +89,6 @@ class FirestormEffect extends OneShotEffect { } return false; } - - - @Override public FirestormEffect copy() { diff --git a/Mage.Sets/src/mage/cards/j/Jilt.java b/Mage.Sets/src/mage/cards/j/Jilt.java index f1ab8a2f697..a66b94bdde7 100644 --- a/Mage.Sets/src/mage/cards/j/Jilt.java +++ b/Mage.Sets/src/mage/cards/j/Jilt.java @@ -1,9 +1,7 @@ - package mage.cards.j; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.Effect; @@ -18,6 +16,7 @@ import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.target.Target; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.SecondTargetPointer; /** @@ -43,18 +42,7 @@ public final class Jilt extends CardImpl { Target target = new TargetCreaturePermanent(); target.setTargetTag(1); this.getSpellAbility().addTarget(target); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility && KickedCondition.instance.apply(game, ability)) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("Another creature: Damaged"); - filter.add(new AnotherTargetPredicate(2)); - Target target = new TargetCreaturePermanent(filter); - target.setTargetTag(2); - ability.addTarget(target); - } - + this.getSpellAbility().setTargetAdjuster(JiltAdjuster.instance); } public Jilt(final Jilt card) { @@ -66,3 +54,20 @@ public final class Jilt extends CardImpl { return new Jilt(this); } } + +enum JiltAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + if (!KickedCondition.instance.apply(game, ability)) { + return; + } + FilterCreaturePermanent filter = new FilterCreaturePermanent("Another creature: Damaged"); + filter.add(new AnotherTargetPredicate(2)); + Target target = new TargetCreaturePermanent(filter); + target.setTargetTag(2); + ability.addTarget(target); + } + +} diff --git a/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java b/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java index b27e8ce73d4..ab33978e771 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java +++ b/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java @@ -1,4 +1,3 @@ - package mage.cards.l; import java.util.UUID; @@ -21,6 +20,7 @@ import mage.filter.predicate.mageobject.SupertypePredicate; import mage.game.Game; import mage.game.command.emblems.LilianaDefiantNecromancerEmblem; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -28,14 +28,12 @@ import mage.target.common.TargetCardInYourGraveyard; */ public final class LilianaDefiantNecromancer extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("nonlegendary creature with converted mana cost X from your graveyard"); + protected static final FilterCreatureCard filter = new FilterCreatureCard("nonlegendary creature with converted mana cost X from your graveyard"); static { filter.add(Predicates.not(new SupertypePredicate(SuperType.LEGENDARY))); } - UUID ability2Id; - public LilianaDefiantNecromancer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); this.addSuperType(SuperType.LEGENDARY); @@ -49,36 +47,18 @@ public final class LilianaDefiantNecromancer extends CardImpl { // +2: Each player discards a card. this.addAbility(new LoyaltyAbility(new DiscardEachPlayerEffect(1, false), 2)); - //TODO: Make ability properly copiable // -X: Return target nonlegendary creature with converted mana cost X from your graveyard to the battlefield. Ability ability = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()); - ability2Id = ability.getOriginalId(); ability.addTarget(new TargetCardInYourGraveyard(filter)); + ability.setTargetAdjuster(LilianaDefiantNecromancerAdjuster.instance); this.addAbility(ability); //-8: You get an emblem with "Whenever a creature dies, return it to the battlefield under your control at the beginning of the next end step."; this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new LilianaDefiantNecromancerEmblem()), -8)); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(ability2Id)) { - int cmc = 0; - for (Cost cost : ability.getCosts()) { - if (cost instanceof PayVariableLoyaltyCost) { - cmc = ((PayVariableLoyaltyCost) cost).getAmount(); - } - } - FilterCard newFilter = filter.copy(); - newFilter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); - ability.getTargets().clear(); - ability.addTarget(new TargetCardInYourGraveyard(newFilter)); - } - } - public LilianaDefiantNecromancer(final LilianaDefiantNecromancer card) { super(card); - this.ability2Id = card.ability2Id; } @Override @@ -86,3 +66,21 @@ public final class LilianaDefiantNecromancer extends CardImpl { return new LilianaDefiantNecromancer(this); } } + +enum LilianaDefiantNecromancerAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int cmc = 0; + for (Cost cost : ability.getCosts()) { + if (cost instanceof PayVariableLoyaltyCost) { + cmc = ((PayVariableLoyaltyCost) cost).getAmount(); + } + } + FilterCard newFilter = LilianaDefiantNecromancer.filter.copy(); + newFilter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(newFilter)); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MeteorBlast.java b/Mage.Sets/src/mage/cards/m/MeteorBlast.java index fb57f84cce0..9331bce50dc 100644 --- a/Mage.Sets/src/mage/cards/m/MeteorBlast.java +++ b/Mage.Sets/src/mage/cards/m/MeteorBlast.java @@ -1,4 +1,3 @@ - package mage.cards.m; import java.util.UUID; @@ -13,6 +12,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetAnyTarget; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -21,7 +21,7 @@ import mage.target.common.TargetAnyTarget; public final class MeteorBlast extends CardImpl { public MeteorBlast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{R}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}{R}{R}"); // Meteor Blast deals 4 damage to each of X target creatures and/or players. this.getSpellAbility().addEffect(new MeteorBlastEffect()); @@ -31,6 +31,15 @@ public final class MeteorBlast extends CardImpl { super(card); } + @Override + public MeteorBlast copy() { + return new MeteorBlast(this); + } +} + +enum MeteorBlastAdjuster implements TargetAdjuster { + instance; + @Override public void adjustTargets(Ability ability, Game game) { int xValue = ability.getManaCostsToPay().getX(); @@ -39,11 +48,6 @@ public final class MeteorBlast extends CardImpl { ability.addTarget(target); } } - - @Override - public MeteorBlast copy() { - return new MeteorBlast(this); - } } class MeteorBlastEffect extends OneShotEffect { diff --git a/Mage.Sets/src/mage/cards/p/PollenRemedy.java b/Mage.Sets/src/mage/cards/p/PollenRemedy.java index 65d52569733..b13dadd098c 100644 --- a/Mage.Sets/src/mage/cards/p/PollenRemedy.java +++ b/Mage.Sets/src/mage/cards/p/PollenRemedy.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -17,39 +16,30 @@ import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetAnyTargetAmount; +import mage.target.targetadjustment.TargetAdjuster; /** * * @author LoneFox - + * */ public final class PollenRemedy extends CardImpl { - private final UUID originalId; - public PollenRemedy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); // Kicker-Sacrifice a land. this.addAbility(new KickerAbility(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, new FilterControlledLandPermanent("a land"), true)))); // Prevent the next 3 damage that would be dealt this turn to any number of target creatures and/or players, divided as you choose. If Pollen Remedy was kicked, prevent the next 6 damage this way instead. Effect effect = new ConditionalReplacementEffect(new PreventDamageToTargetMultiAmountEffect(Duration.EndOfTurn, 6), - KickedCondition.instance, new PreventDamageToTargetMultiAmountEffect(Duration.EndOfTurn, 3)); + KickedCondition.instance, new PreventDamageToTargetMultiAmountEffect(Duration.EndOfTurn, 3)); effect.setText("Prevent the next 3 damage that would be dealt this turn to any number of targets, divided as you choose. if this spell was kicked, prevent the next 6 damage this way instead."); this.getSpellAbility().addEffect(effect); - originalId = this.getSpellAbility().getOriginalId(); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if(ability.getOriginalId().equals(originalId)) { - ability.addTarget(new TargetAnyTargetAmount(KickedCondition.instance.apply(game, ability) ? 6 : 3)); - } + this.getSpellAbility().setTargetAdjuster(PollenRemedyAdjuster.instance); } public PollenRemedy(final PollenRemedy card) { super(card); - this.originalId = card.originalId; } @Override @@ -57,3 +47,12 @@ public final class PollenRemedy extends CardImpl { return new PollenRemedy(this); } } + +enum PollenRemedyAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.addTarget(new TargetAnyTargetAmount(KickedCondition.instance.apply(game, ability) ? 6 : 3)); + } +} diff --git a/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java b/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java index 418f839664b..5782524f16e 100644 --- a/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java +++ b/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java @@ -1,6 +1,6 @@ - package mage.cards.q; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -12,19 +12,24 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.DependencyType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; - -import java.util.UUID; -import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.common.TargetLandPermanent; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.FixedTarget; /** * @@ -32,42 +37,22 @@ import mage.target.common.TargetLandPermanent; */ public final class QuicksilverFountain extends CardImpl { - public final UUID originalId; - public QuicksilverFountain(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // At the beginning of each player's upkeep, that player puts a flood counter on target non-Island land he or she controls of their choice. That land is an Island for as long as it has a flood counter on it. Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new QuicksilverFountainEffect(), TargetController.ANY, false, true); ability.addTarget(new TargetLandPermanent()); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(QuicksilverFountainAdjuster.instance); this.addAbility(ability); // At the beginning of each end step, if all lands on the battlefield are Islands, remove all flood counters from them. Condition condition = new AllLandsAreSubtypeCondition(SubType.ISLAND); this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new QuicksilverFountainEffect2(), TargetController.ANY, condition, false)); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - if (activePlayer != null) { - ability.getTargets().clear(); - FilterLandPermanent filter = new FilterLandPermanent(); - filter.add(Predicates.not(new SubtypePredicate(SubType.ISLAND))); - filter.add(new ControllerPredicate(TargetController.ACTIVE)); - TargetLandPermanent target = new TargetLandPermanent(1, 1, filter, false); - target.setTargetController(activePlayer.getId()); - ability.getTargets().add(target); - } - } } public QuicksilverFountain(final QuicksilverFountain card) { super(card); - this.originalId = card.originalId; } @Override @@ -76,11 +61,29 @@ public final class QuicksilverFountain extends CardImpl { } } +enum QuicksilverFountainAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if (activePlayer != null) { + ability.getTargets().clear(); + FilterLandPermanent filter = new FilterLandPermanent(); + filter.add(Predicates.not(new SubtypePredicate(SubType.ISLAND))); + filter.add(new ControllerPredicate(TargetController.ACTIVE)); + TargetLandPermanent target = new TargetLandPermanent(1, 1, filter, false); + target.setTargetController(activePlayer.getId()); + ability.getTargets().add(target); + } + } +} + class QuicksilverFountainEffect extends OneShotEffect { public QuicksilverFountainEffect() { super(Outcome.Neutral); - staticText = "that player puts a flood counter on target non-Island land he or she controls of their choice. That land is an Island for as long as it has a flood counter on it"; + staticText = "that player puts a flood counter on target non-Island land they control of their choice. That land is an Island for as long as it has a flood counter on it"; } public QuicksilverFountainEffect(final QuicksilverFountainEffect effect) { diff --git a/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java b/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java index e98d72f8038..5aa3ab80996 100644 --- a/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java +++ b/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java @@ -1,4 +1,3 @@ - package mage.cards.q; import java.util.UUID; @@ -27,16 +26,15 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @author LevelX2 */ public final class QuillmaneBaku extends CardImpl { - private final UUID originalId; - public QuillmaneBaku(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(3); @@ -45,70 +43,70 @@ public final class QuillmaneBaku extends CardImpl { // Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Skullmane Baku. this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.SPIRIT_OR_ARCANE_CARD, true)); - //TODO: Make ability properly copiable // {1}, Tap, Remove X ki counters from Quillmane Baku: Return target creature with converted mana cost X or less to its owner's hand. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new QuillmaneBakuReturnEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance(1))); ability.addTarget(new TargetCreaturePermanent()); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(QuillmaneBakuAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - int maxConvManaCost = 0; - for (Cost cost : ability.getCosts()) { - if (cost instanceof RemoveVariableCountersSourceCost) { - maxConvManaCost = ((RemoveVariableCountersSourceCost) cost).getAmount(); - } - } - ability.getTargets().clear(); - FilterCreaturePermanent newFilter = new FilterCreaturePermanent("creature with converted mana cost " + maxConvManaCost + " or less"); - newFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, maxConvManaCost + 1)); - TargetCreaturePermanent target = new TargetCreaturePermanent(newFilter); - ability.getTargets().add(target); - } - } - public QuillmaneBaku(final QuillmaneBaku card) { super(card); - this.originalId = card.originalId; } @Override public QuillmaneBaku copy() { return new QuillmaneBaku(this); } +} - static class QuillmaneBakuReturnEffect extends OneShotEffect { +enum QuillmaneBakuAdjuster implements TargetAdjuster { + instance; - public QuillmaneBakuReturnEffect() { - super(Outcome.ReturnToHand); - this.staticText = "Return target creature with converted mana cost X or less to its owner's hand"; - } - - public QuillmaneBakuReturnEffect(final QuillmaneBakuReturnEffect effect) { - super(effect); - } - - @Override - public QuillmaneBakuReturnEffect copy() { - return new QuillmaneBakuReturnEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; + @Override + public void adjustTargets(Ability ability, Game game) { + int maxConvManaCost = 0; + for (Cost cost : ability.getCosts()) { + if (cost instanceof RemoveVariableCountersSourceCost) { + maxConvManaCost = ((RemoveVariableCountersSourceCost) cost).getAmount(); } - Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (permanent != null) { - controller.moveCards(permanent, Zone.HAND, source, game); - } - return true; } + ability.getTargets().clear(); + FilterCreaturePermanent newFilter = new FilterCreaturePermanent("creature with converted mana cost " + maxConvManaCost + " or less"); + newFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, maxConvManaCost + 1)); + TargetCreaturePermanent target = new TargetCreaturePermanent(newFilter); + ability.getTargets().add(target); + } +} + +class QuillmaneBakuReturnEffect extends OneShotEffect { + + public QuillmaneBakuReturnEffect() { + super(Outcome.ReturnToHand); + this.staticText = "Return target creature with converted mana cost X or less to its owner's hand"; + } + + public QuillmaneBakuReturnEffect(final QuillmaneBakuReturnEffect effect) { + super(effect); + } + + @Override + public QuillmaneBakuReturnEffect copy() { + return new QuillmaneBakuReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (permanent != null) { + controller.moveCards(permanent, Zone.HAND, source, game); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/r/Repeal.java b/Mage.Sets/src/mage/cards/r/Repeal.java index 9738ab88b24..34851fedcad 100644 --- a/Mage.Sets/src/mage/cards/r/Repeal.java +++ b/Mage.Sets/src/mage/cards/r/Repeal.java @@ -1,9 +1,7 @@ - package mage.cards.r; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; @@ -15,6 +13,7 @@ import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.target.TargetPermanent; import mage.target.common.TargetNonlandPermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -23,29 +22,17 @@ import mage.target.common.TargetNonlandPermanent; public final class Repeal extends CardImpl { public Repeal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}"); // Return target nonland permanent with converted mana cost X to its owner's hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(new FilterNonlandPermanent("nonland permanent with converted mana cost X"))); - + this.getSpellAbility().setTargetAdjuster(RepealAdjuster.instance); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterNonlandPermanent filter = new FilterNonlandPermanent(new StringBuilder("nonland permanent with converted mana cost ").append(xValue).toString()); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); - ability.addTarget(new TargetNonlandPermanent(filter)); - } - } - public Repeal(final Repeal card) { super(card); } @@ -55,3 +42,16 @@ public final class Repeal extends CardImpl { return new Repeal(this); } } + +enum RepealAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanent with converted mana cost " + xValue); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.addTarget(new TargetNonlandPermanent(filter)); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkyfireKirin.java b/Mage.Sets/src/mage/cards/s/SkyfireKirin.java index ab3981c926c..899b0aa5aab 100644 --- a/Mage.Sets/src/mage/cards/s/SkyfireKirin.java +++ b/Mage.Sets/src/mage/cards/s/SkyfireKirin.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -22,6 +21,7 @@ import mage.game.stack.Spell; import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; /** @@ -29,8 +29,6 @@ import mage.target.targetpointer.FixedTarget; */ public final class SkyfireKirin extends CardImpl { - private final UUID originalId; - public SkyfireKirin(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); addSuperType(SuperType.LEGENDARY); @@ -43,30 +41,17 @@ public final class SkyfireKirin extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Whenever you cast a Spirit or Arcane spell, you may gain control of target creature with that spell's converted mana cost until end of turn. - Ability ability = new SpellCastControllerTriggeredAbility(Zone.BATTLEFIELD, new SkyfireKirinEffect(), StaticFilters.SPIRIT_OR_ARCANE_CARD, true, true); + Ability ability = new SpellCastControllerTriggeredAbility( + Zone.BATTLEFIELD, new SkyfireKirinEffect(), + StaticFilters.SPIRIT_OR_ARCANE_CARD, true, true + ); ability.addTarget(new TargetCreaturePermanent()); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(SkyfireKirinAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Spell spell = game.getStack().getSpell(ability.getEffects().get(0).getTargetPointer().getFirst(game, ability)); - if (spell != null) { - int cmc = spell.getConvertedManaCost(); - ability.getTargets().clear(); - FilterPermanent filter = new FilterCreaturePermanent(new StringBuilder("creature with converted mana costs of ").append(cmc).toString()); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); - Target target = new TargetPermanent(filter); - ability.addTarget(target); - } - } - } - public SkyfireKirin(final SkyfireKirin card) { super(card); - this.originalId = card.originalId; } @Override @@ -75,6 +60,22 @@ public final class SkyfireKirin extends CardImpl { } } +enum SkyfireKirinAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Spell spell = game.getStack().getSpell(ability.getEffects().get(0).getTargetPointer().getFirst(game, ability)); + if (spell != null) { + int cmc = spell.getConvertedManaCost(); + ability.getTargets().clear(); + FilterPermanent filter = new FilterCreaturePermanent("creature with converted mana cost " + cmc); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); + ability.addTarget(new TargetPermanent(filter)); + } + } +} + class SkyfireKirinEffect extends OneShotEffect { public SkyfireKirinEffect() { diff --git a/Mage.Sets/src/mage/cards/s/StrengthOfTheTajuru.java b/Mage.Sets/src/mage/cards/s/StrengthOfTheTajuru.java index 93d7d0d141b..48f0586a2bc 100644 --- a/Mage.Sets/src/mage/cards/s/StrengthOfTheTajuru.java +++ b/Mage.Sets/src/mage/cards/s/StrengthOfTheTajuru.java @@ -1,9 +1,7 @@ - package mage.cards.s; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.dynamicvalue.common.MultikickerCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.MultikickerAbility; @@ -16,7 +14,7 @@ import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; - +import mage.target.targetadjustment.TargetAdjuster; /** * @author noxx @@ -24,7 +22,7 @@ import mage.target.common.TargetCreaturePermanent; public final class StrengthOfTheTajuru extends CardImpl { public StrengthOfTheTajuru(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}{G}"); // Multikicker (You may pay an additional {1} any number of times as you cast this spell.) this.addAbility(new MultikickerAbility("{1}")); @@ -32,15 +30,7 @@ public final class StrengthOfTheTajuru extends CardImpl { // Choose target creature, then choose another target creature for each time Strength of the Tajuru was kicked. Put X +1/+1 counters on each of them. this.getSpellAbility().addEffect(new StrengthOfTheTajuruAddCountersTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE)); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int numbTargets = new MultikickerCount().calculate(game, ability, null) + 1; - ability.addTarget(new TargetCreaturePermanent(0, numbTargets)); - } + this.getSpellAbility().setTargetAdjuster(StrengthOfTheTajuruAdjuster.instance); } public StrengthOfTheTajuru(final StrengthOfTheTajuru card) { @@ -53,6 +43,17 @@ public final class StrengthOfTheTajuru extends CardImpl { } } +enum StrengthOfTheTajuruAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int numbTargets = new MultikickerCount().calculate(game, ability, null) + 1; + ability.addTarget(new TargetCreaturePermanent(0, numbTargets)); + } +} + class StrengthOfTheTajuruAddCountersTargetEffect extends OneShotEffect { public StrengthOfTheTajuruAddCountersTargetEffect() { @@ -73,7 +74,7 @@ class StrengthOfTheTajuruAddCountersTargetEffect extends OneShotEffect { Permanent permanent = game.getPermanent(uuid); if (permanent != null) { permanent.addCounters(counter.copy(), source, game); - affectedTargets ++; + affectedTargets++; } } return affectedTargets > 0; @@ -84,5 +85,4 @@ class StrengthOfTheTajuruAddCountersTargetEffect extends OneShotEffect { return new StrengthOfTheTajuruAddCountersTargetEffect(this); } - } diff --git a/Mage.Sets/src/mage/cards/t/TimeToReflect.java b/Mage.Sets/src/mage/cards/t/TimeToReflect.java index 3ac0599ba4d..5a59975512f 100644 --- a/Mage.Sets/src/mage/cards/t/TimeToReflect.java +++ b/Mage.Sets/src/mage/cards/t/TimeToReflect.java @@ -1,9 +1,7 @@ - package mage.cards.t; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -19,8 +17,8 @@ import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.Watcher; - import java.util.*; +import mage.target.targetadjustment.TargetAdjuster; /** * @author jeffwadsworth @@ -34,27 +32,7 @@ public final class TimeToReflect extends CardImpl { this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(new FilterCreaturePermanent("creature that blocked or was blocked by a Zombie this turn."))); this.getSpellAbility().addWatcher(new BlockedOrWasBlockedByAZombieWatcher()); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - List creaturesThatBlockedOrWereBlockedByAZombie = new ArrayList<>(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that blocked or was blocked by a Zombie this turn.").copy(); - BlockedOrWasBlockedByAZombieWatcher watcher = (BlockedOrWasBlockedByAZombieWatcher) game.getState().getWatchers().get(BlockedOrWasBlockedByAZombieWatcher.class.getSimpleName()); - if (watcher != null) { - for (MageObjectReference mor : watcher.getBlockedThisTurnCreatures()) { - Permanent permanent = mor.getPermanent(game); - if (permanent != null) { - creaturesThatBlockedOrWereBlockedByAZombie.add(new PermanentIdPredicate(permanent.getId())); - } - } - } - filter.add(Predicates.or(creaturesThatBlockedOrWereBlockedByAZombie)); - ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanent(filter)); - } + this.getSpellAbility().setTargetAdjuster(TimeToReflectAdjuster.instance); } public TimeToReflect(final TimeToReflect card) { @@ -67,6 +45,28 @@ public final class TimeToReflect extends CardImpl { } } +enum TimeToReflectAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + List creaturesThatBlockedOrWereBlockedByAZombie = new ArrayList<>(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that blocked or was blocked by a Zombie this turn.").copy(); + BlockedOrWasBlockedByAZombieWatcher watcher = (BlockedOrWasBlockedByAZombieWatcher) game.getState().getWatchers().get(BlockedOrWasBlockedByAZombieWatcher.class.getSimpleName()); + if (watcher != null) { + for (MageObjectReference mor : watcher.getBlockedThisTurnCreatures()) { + Permanent permanent = mor.getPermanent(game); + if (permanent != null) { + creaturesThatBlockedOrWereBlockedByAZombie.add(new PermanentIdPredicate(permanent.getId())); + } + } + } + filter.add(Predicates.or(creaturesThatBlockedOrWereBlockedByAZombie)); + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(filter)); + } +} + class BlockedOrWasBlockedByAZombieWatcher extends Watcher { private final Set blockedOrWasBlockedByAZombieWatcher;