From 53532a7f60abb3fcaf5662e298dbd2d546d1663f Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 23 May 2025 08:33:50 -0400 Subject: [PATCH] [FIC] Implement Tidus, Yuna's Guardian (#13555) * [FIC] Implement Tidus, Yuna's Guardian * merge fix --- .../src/mage/cards/c/CombineGuildmage.java | 56 ++------- .../src/mage/cards/d/DaghatarTheAdamant.java | 70 +++-------- Mage.Sets/src/mage/cards/l/LeechBonder.java | 87 ++------------ .../src/mage/cards/n/NestingGrounds.java | 92 ++------------ Mage.Sets/src/mage/cards/r/RumorMonger.java | 24 +++- .../src/mage/cards/s/SimicGuildmage.java | 86 ++++---------- .../src/mage/cards/t/TidusYunasGuardian.java | 67 +++++++++++ .../src/mage/sets/FinalFantasyCommander.java | 5 + ...oreCombatDamagePlayerTriggeredAbility.java | 6 +- .../counter/MoveCounterTargetsEffect.java | 112 ++++++++++++++++++ .../counter/MoveCountersTargetsEffect.java | 77 ------------ 11 files changed, 280 insertions(+), 402 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/t/TidusYunasGuardian.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/counter/MoveCounterTargetsEffect.java delete mode 100644 Mage/src/main/java/mage/abilities/effects/common/counter/MoveCountersTargetsEffect.java diff --git a/Mage.Sets/src/mage/cards/c/CombineGuildmage.java b/Mage.Sets/src/mage/cards/c/CombineGuildmage.java index 9353935c98a..9bc468d89f6 100644 --- a/Mage.Sets/src/mage/cards/c/CombineGuildmage.java +++ b/Mage.Sets/src/mage/cards/c/CombineGuildmage.java @@ -5,21 +5,20 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.EntersWithCountersControlledEffect; +import mage.abilities.effects.common.counter.MoveCounterTargetsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.predicate.other.AnotherTargetPredicate; import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -28,10 +27,12 @@ import java.util.UUID; */ public final class CombineGuildmage extends CardImpl { - private static final FilterPermanent filter1 - = new FilterControlledCreaturePermanent("creature you control (to remove a counter from)"); - private static final FilterPermanent filter2 - = new FilterControlledCreaturePermanent("creature you control (to move a counter to)"); + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("another target creature you control"); + + static { + filter.add(new AnotherTargetPredicate(2)); + } public CombineGuildmage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}"); @@ -50,12 +51,10 @@ public final class CombineGuildmage extends CardImpl { this.addAbility(ability); // {1}{U}, {T}: Move a +1/+1 counter from target creature you control onto another target creature you control. - ability = new SimpleActivatedAbility( - new CombineGuildmageCounterEffect(), new ManaCostsImpl<>("{1}{U}") - ); + ability = new SimpleActivatedAbility(new MoveCounterTargetsEffect(CounterType.P1P1), new ManaCostsImpl<>("{1}{U}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetPermanent(filter1)); - ability.addTarget(new TargetPermanent(filter2)); + ability.addTarget(new TargetControlledCreaturePermanent().withChooseHint("to remove a counter from")); + ability.addTarget(new TargetPermanent(filter).withChooseHint("to move a counter to").setTargetTag(2)); this.addAbility(ability); } @@ -68,34 +67,3 @@ public final class CombineGuildmage extends CardImpl { return new CombineGuildmage(this); } } - -class CombineGuildmageCounterEffect extends OneShotEffect { - - CombineGuildmageCounterEffect() { - super(Outcome.Benefit); - staticText = "Move a +1/+1 counter from target creature you control onto another target creature you control."; - } - - private CombineGuildmageCounterEffect(final CombineGuildmageCounterEffect effect) { - super(effect); - } - - @Override - public CombineGuildmageCounterEffect copy() { - return new CombineGuildmageCounterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent fromPermanent = game.getPermanent(source.getFirstTarget()); - Permanent toPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (fromPermanent == null || toPermanent == null) { - return false; - } - if (fromPermanent.getCounters(game).getCount(CounterType.P1P1) > 0) { - fromPermanent.removeCounters(CounterType.P1P1.createInstance(), source, game); - toPermanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DaghatarTheAdamant.java b/Mage.Sets/src/mage/cards/d/DaghatarTheAdamant.java index 2d2d495ac2b..9c679a78189 100644 --- a/Mage.Sets/src/mage/cards/d/DaghatarTheAdamant.java +++ b/Mage.Sets/src/mage/cards/d/DaghatarTheAdamant.java @@ -1,38 +1,41 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.MoveCounterTargetsEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; import mage.constants.SuperType; -import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DaghatarTheAdamant extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("a second target creature"); + + static { + filter.add(new AnotherTargetPredicate(2)); + } + public DaghatarTheAdamant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); @@ -41,17 +44,18 @@ public final class DaghatarTheAdamant extends CardImpl { // Vigilance this.addAbility(VigilanceAbility.getInstance()); + // Daghatar the Adamant enters the battlefield with four +1/+1 counters on it. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)), "with four +1/+1 counters on it")); // {1}{B/G}{B/G}: Move a +1/+1 counter from target creature onto a second target creature. - Ability ability = new SimpleActivatedAbility(new MoveCounterFromTargetToTargetEffect(),new ManaCostsImpl<>("{1}{B/G}{B/G}")); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature the +1/+1 counter is moved from"))); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature the +1/+1 counter is moved to"))); + Ability ability = new SimpleActivatedAbility( + new MoveCounterTargetsEffect(CounterType.P1P1), new ManaCostsImpl<>("{1}{B/G}{B/G}") + ); + ability.addTarget(new TargetCreaturePermanent().withChooseHint("to remove a counter from")); + ability.addTarget(new TargetPermanent(filter).withChooseHint("to move a counter to").setTargetTag(2)); this.addAbility(ability); - - } private DaghatarTheAdamant(final DaghatarTheAdamant card) { @@ -63,39 +67,3 @@ public final class DaghatarTheAdamant extends CardImpl { return new DaghatarTheAdamant(this); } } - -class MoveCounterFromTargetToTargetEffect extends OneShotEffect { - - MoveCounterFromTargetToTargetEffect() { - super(Outcome.Detriment); - this.staticText = "Move a +1/+1 counter from target creature onto a second target creature"; - } - - private MoveCounterFromTargetToTargetEffect(final MoveCounterFromTargetToTargetEffect effect) { - super(effect); - } - - @Override - public MoveCounterFromTargetToTargetEffect copy() { - return new MoveCounterFromTargetToTargetEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source); - if (sourceObject != null && controller != null) { - Permanent fromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (fromPermanent != null && fromPermanent.getCounters(game).getCount(CounterType.P1P1) > 0) { - Permanent toPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (toPermanent != null) { - fromPermanent.removeCounters(CounterType.P1P1.createInstance(), source, game); - toPermanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); - game.informPlayers(sourceObject.getLogName() + ": Moved a +1/+1 counter from " + fromPermanent.getLogName() +" to " + toPermanent.getLogName()); - } - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LeechBonder.java b/Mage.Sets/src/mage/cards/l/LeechBonder.java index 07759436689..0bc52070d2b 100644 --- a/Mage.Sets/src/mage/cards/l/LeechBonder.java +++ b/Mage.Sets/src/mage/cards/l/LeechBonder.java @@ -6,28 +6,19 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.UntapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.MoveCounterTargetsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.counters.Counter; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; import java.util.UUID; /** @@ -35,6 +26,12 @@ import java.util.UUID; */ public final class LeechBonder extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("a second target creature"); + + static { + filter.add(new AnotherTargetPredicate(2)); + } + public LeechBonder(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.MERFOLK); @@ -47,21 +44,11 @@ public final class LeechBonder extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)), "with two -1/-1 counters on it")); // {U}, {untap}: Move a counter from target creature onto another target creature. - Ability ability = new SimpleActivatedAbility(new LeechBonderEffect(), new ManaCostsImpl<>("{U}")); + Ability ability = new SimpleActivatedAbility(new MoveCounterTargetsEffect(), new ManaCostsImpl<>("{U}")); ability.addCost(new UntapSourceCost()); - // target 1 - TargetCreaturePermanent target1 = new TargetCreaturePermanent(new FilterCreaturePermanent("creature to remove counter from")); - target1.setTargetTag(1); - ability.addTarget(target1); - // target 2 - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature to put counter on"); - filter.add(new AnotherTargetPredicate(2)); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); - target2.setTargetTag(2); - ability.addTarget(target2); - + ability.addTarget(new TargetCreaturePermanent().withChooseHint("to remove a counter from")); + ability.addTarget(new TargetPermanent(filter).withChooseHint("to move a counter to").setTargetTag(2)); this.addAbility(ability); - } private LeechBonder(final LeechBonder card) { @@ -73,53 +60,3 @@ public final class LeechBonder extends CardImpl { return new LeechBonder(this); } } - -class LeechBonderEffect extends OneShotEffect { - - LeechBonderEffect() { - super(Outcome.AIDontUseIt); - this.staticText = "Move a counter from target creature onto a second target creature"; - } - - private LeechBonderEffect(final LeechBonderEffect effect) { - super(effect); - } - - @Override - public LeechBonderEffect copy() { - return new LeechBonderEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent fromPermanent = game.getPermanent(source.getFirstTarget()); - Permanent toPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (fromPermanent == null - || toPermanent == null - || controller == null) { - return false; - } - - Set possibleChoices = new LinkedHashSet<>(fromPermanent.getCounters(game).keySet()); - if (possibleChoices.isEmpty()) { - return false; - } - - Choice choice = new ChoiceImpl(false); - choice.setChoices(possibleChoices); - if (controller.choose(outcome, choice, game)) { - String chosen = choice.getChoice(); - if (fromPermanent.getCounters(game).containsKey(chosen)) { - CounterType counterType = CounterType.findByName(chosen); - if (counterType != null) { - Counter counter = counterType.createInstance(); - fromPermanent.removeCounters(counterType.getName(), 1, source, game); - toPermanent.addCounters(counter, source.getControllerId(), source, game); - return true; - } - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/n/NestingGrounds.java b/Mage.Sets/src/mage/cards/n/NestingGrounds.java index 8fb8fcf5775..cc3cbe926ac 100644 --- a/Mage.Sets/src/mage/cards/n/NestingGrounds.java +++ b/Mage.Sets/src/mage/cards/n/NestingGrounds.java @@ -4,29 +4,16 @@ import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.MoveCounterTargetsEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.counters.Counter; -import mage.counters.CounterType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; import java.util.UUID; /** @@ -34,6 +21,12 @@ import java.util.UUID; */ public final class NestingGrounds extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("another target"); + + static { + filter.add(new AnotherTargetPredicate(2)); + } + public NestingGrounds(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); @@ -41,19 +34,10 @@ public final class NestingGrounds extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {1}, {T}: Move a counter from target permanent you control onto another target permanent. Activate this ability only any time you could cast a sorcery. - Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new NestingGroundsEffect(), new GenericManaCost(1)); + Ability ability = new ActivateAsSorceryActivatedAbility(new MoveCounterTargetsEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - // target 1 - TargetControlledPermanent target1 = new TargetControlledPermanent(new FilterControlledPermanent("permanent to remove counter from")); - target1.setTargetTag(1); - ability.addTarget(target1); - // target 2 - FilterPermanent filter = new FilterPermanent("permanent to put counter on"); - filter.add(new AnotherTargetPredicate(2)); - TargetPermanent target2 = new TargetPermanent(filter); - target2.setTargetTag(2); - ability.addTarget(target2); - + ability.addTarget(new TargetControlledPermanent().withChooseHint("to remove a counter from")); + ability.addTarget(new TargetPermanent(filter).withChooseHint("to move a counter to").setTargetTag(2)); this.addAbility(ability); } @@ -66,59 +50,3 @@ public final class NestingGrounds extends CardImpl { return new NestingGrounds(this); } } - -class NestingGroundsEffect extends OneShotEffect { - - NestingGroundsEffect() { - super(Outcome.AIDontUseIt); - this.staticText = "Move a counter from target permanent you control onto another target permanent"; - } - - private NestingGroundsEffect(final NestingGroundsEffect effect) { - super(effect); - } - - @Override - public NestingGroundsEffect copy() { - return new NestingGroundsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent fromPermanent = game.getPermanent(source.getFirstTarget()); - Permanent toPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (fromPermanent == null - || toPermanent == null - || controller == null - || fromPermanent.getCounters(game).size() == 0) { - return false; - } - - if (fromPermanent.getCounters(game).size() == 1) { - for (Counter counter : fromPermanent.getCounters(game).values()) { - fromPermanent.removeCounters(counter.getName(), 1, source, game); - toPermanent.addCounters(new Counter(counter.getName()), source.getControllerId(), source, game); - } - return true; - } - - Choice choice = new ChoiceImpl(false); - Set possibleChoices = new LinkedHashSet<>(fromPermanent.getCounters(game).keySet()); - choice.setChoices(possibleChoices); - choice.setMessage("Choose a counter"); - if (controller.choose(outcome, choice, game)) { - String chosen = choice.getChoice(); - if (fromPermanent.getCounters(game).containsKey(chosen)) { - CounterType counterType = CounterType.findByName(chosen); - if (counterType != null) { - Counter counter = counterType.createInstance(); - fromPermanent.removeCounters(counterType.getName(), 1, source, game); - toPermanent.addCounters(counter, source.getControllerId(), source, game); - return true; - } - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RumorMonger.java b/Mage.Sets/src/mage/cards/r/RumorMonger.java index 9e254e209d5..ac7d4fb79c7 100644 --- a/Mage.Sets/src/mage/cards/r/RumorMonger.java +++ b/Mage.Sets/src/mage/cards/r/RumorMonger.java @@ -1,28 +1,39 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.effects.common.counter.MoveCountersTargetsEffect; +import mage.abilities.effects.common.counter.MoveCounterTargetsEffect; import mage.abilities.keyword.BountyAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponentsCreaturePermanent; +import java.util.UUID; + /** - * * @author Styxo */ public final class RumorMonger extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("another target creature"); + + static { + filter.add(new AnotherTargetPredicate(2)); + } + public RumorMonger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}{G}"); this.subtype.add(SubType.ARCONA); this.subtype.add(SubType.HUNTER); this.power = new MageInt(3); @@ -34,8 +45,9 @@ public final class RumorMonger extends CardImpl { this.addAbility(ability); // Bounty — Whenever a creature an opponent controls with a bounty counter on it dies, you may move a bounty counter from one target creature to another target creatute. - ability = new BountyAbility(new MoveCountersTargetsEffect(CounterType.BOUNTY, 1), false); - ability.addTarget(new TargetOpponentsCreaturePermanent(2)); + ability = new BountyAbility(new MoveCounterTargetsEffect(CounterType.BOUNTY), true); + ability.addTarget(new TargetCreaturePermanent().withChooseHint("to remove a counter from")); + ability.addTarget(new TargetPermanent(filter).setTargetTag(2).withChooseHint("to move a counter to")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SimicGuildmage.java b/Mage.Sets/src/mage/cards/s/SimicGuildmage.java index 861474e5e91..2b74eee8691 100644 --- a/Mage.Sets/src/mage/cards/s/SimicGuildmage.java +++ b/Mage.Sets/src/mage/cards/s/SimicGuildmage.java @@ -6,14 +6,15 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.MoveCounterTargetsEffect; 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.counters.CounterType; import mage.filter.Filter; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterEnchantmentPermanent; import mage.filter.predicate.ObjectSourcePlayer; @@ -37,9 +38,12 @@ import java.util.UUID; */ public final class SimicGuildmage extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("another target creature with the same controller"); private static final FilterEnchantmentPermanent auraFilter = new FilterEnchantmentPermanent("Aura"); static { + filter.add(new AnotherTargetPredicate(2)); + filter.add(SameControllerPredicate.instance); auraFilter.add(SubType.AURA.getPredicate()); } @@ -51,26 +55,15 @@ public final class SimicGuildmage extends CardImpl { this.toughness = new MageInt(2); // {1}{G}: Move a +1/+1 counter from target creature onto another target creature with the same controller. - Ability countersAbility = new SimpleActivatedAbility(new MoveCounterFromTargetToTargetEffect(), new ManaCostsImpl<>("{1}{G}")); - TargetCreaturePermanent target = new TargetCreaturePermanent( - new FilterCreaturePermanent("creature (you take counter from)")); - target.setTargetTag(1); - countersAbility.addTarget(target); - - FilterCreaturePermanent filter = new FilterCreaturePermanent( - "another target creature with the same controller (counter goes to)"); - filter.add(new AnotherTargetPredicate(2)); - filter.add(new SameControllerPredicate()); - TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); - target2.setTargetTag(2); - countersAbility.addTarget(target2); + Ability countersAbility = new SimpleActivatedAbility(new MoveCounterTargetsEffect(CounterType.P1P1), new ManaCostsImpl<>("{1}{G}")); + countersAbility.addTarget(new TargetCreaturePermanent().withChooseHint("to remove a counter from")); + countersAbility.addTarget(new TargetPermanent(filter).withChooseHint("to move a counter to").setTargetTag(2)); this.addAbility(countersAbility); // {1}{U}: Attach target Aura enchanting a permanent to another permanent with the same controller. Ability auraAbility = new SimpleActivatedAbility(new MoveAuraEffect(), new ManaCostsImpl<>("{1}{U}")); auraAbility.addTarget(new TargetPermanent(auraFilter)); this.addAbility(auraAbility); - } private SimicGuildmage(final SimicGuildmage card) { @@ -83,68 +76,29 @@ public final class SimicGuildmage extends CardImpl { } } -class MoveCounterFromTargetToTargetEffect extends OneShotEffect { - - MoveCounterFromTargetToTargetEffect() { - super(Outcome.Detriment); - this.staticText = "Move a +1/+1 counter from target creature onto another target creature with the same controller"; - } - - private MoveCounterFromTargetToTargetEffect(final MoveCounterFromTargetToTargetEffect effect) { - super(effect); - } - - @Override - public MoveCounterFromTargetToTargetEffect copy() { - return new MoveCounterFromTargetToTargetEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent fromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - Permanent toPermanent = null; - if (source.getTargets().size() > 1) { - toPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - } - if (fromPermanent == null || toPermanent == null || !fromPermanent.isControlledBy(toPermanent.getControllerId())) { - return false; - } - fromPermanent.removeCounters(CounterType.P1P1.createInstance(1), source, game); - toPermanent.addCounters(CounterType.P1P1.createInstance(1), source.getControllerId(), source, game); - return true; - } - return false; - - } -} - -class SameControllerPredicate implements ObjectSourcePlayerPredicate { +enum SameControllerPredicate implements ObjectSourcePlayerPredicate { + instance; @Override public boolean apply(ObjectSourcePlayer input, Game game) { StackObject source = game.getStack().getStackObject(input.getSourceId()); - if (source != null) { - if (source.getStackAbility().getTargets().isEmpty() - || source.getStackAbility().getTargets().get(0).getTargets().isEmpty()) { - return true; - } - Permanent firstTarget = game.getPermanent( - source.getStackAbility().getTargets().get(0).getTargets().get(0)); - Permanent inputPermanent = game.getPermanent(input.getObject().getId()); - if (firstTarget != null && inputPermanent != null) { - return firstTarget.isControlledBy(inputPermanent.getControllerId()); - } + if (source == null + || source.getStackAbility().getTargets().isEmpty() + || source.getStackAbility().getTargets().get(0).getTargets().isEmpty()) { + return true; } - return true; + Permanent firstTarget = game.getPermanent(source.getStackAbility().getTargets().get(0).getTargets().get(0)); + Permanent inputPermanent = game.getPermanent(input.getObject().getId()); + if (firstTarget == null || inputPermanent == null) { + return true; + } + return firstTarget.isControlledBy(inputPermanent.getControllerId()); } @Override public String toString() { return "Target with the same controller"; } - } class MoveAuraEffect extends OneShotEffect { diff --git a/Mage.Sets/src/mage/cards/t/TidusYunasGuardian.java b/Mage.Sets/src/mage/cards/t/TidusYunasGuardian.java new file mode 100644 index 00000000000..5ee2f7358b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TidusYunasGuardian.java @@ -0,0 +1,67 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.MoveCounterTargetsEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TidusYunasGuardian extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("a second target creature you control"); + + static { + filter.add(new AnotherTargetPredicate(2)); + } + + public TidusYunasGuardian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // At the beginning of combat on your turn, you may move a counter from target creature you control onto a second target creature you control. + Ability ability = new BeginningOfCombatTriggeredAbility(new MoveCounterTargetsEffect(), true); + ability.addTarget(new TargetControlledCreaturePermanent().withChooseHint("to take a counter from").setTargetTag(1)); + ability.addTarget(new TargetPermanent(filter).withChooseHint("to move a counter to").setTargetTag(2)); + this.addAbility(ability); + + // Cheer - Whenever one or more creatures you control with counters on them deal combat damage to a player, you may draw a card and proliferate. Do this only once each turn. + ability = new OneOrMoreCombatDamagePlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), SetTargetPointer.NONE, true + ).setDoOnlyOnceEachTurn(true); + ability.addEffect(new ProliferateEffect(false).concatBy("and")); + this.addAbility(ability.withFlavorWord("Cheer")); + } + + private TidusYunasGuardian(final TidusYunasGuardian card) { + super(card); + } + + @Override + public TidusYunasGuardian copy() { + return new TidusYunasGuardian(this); + } +} diff --git a/Mage.Sets/src/mage/sets/FinalFantasyCommander.java b/Mage.Sets/src/mage/sets/FinalFantasyCommander.java index cf08a26764e..8c92e8b8bbd 100644 --- a/Mage.Sets/src/mage/sets/FinalFantasyCommander.java +++ b/Mage.Sets/src/mage/sets/FinalFantasyCommander.java @@ -366,6 +366,11 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("The Warring Triad", 99, Rarity.RARE, mage.cards.t.TheWarringTriad.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thought Vessel", 368, Rarity.COMMON, mage.cards.t.ThoughtVessel.class)); cards.add(new SetCardInfo("Three Visits", 315, Rarity.UNCOMMON, mage.cards.t.ThreeVisits.class)); + cards.add(new SetCardInfo("Tidus, Yuna's Guardian", 187, Rarity.MYTHIC, mage.cards.t.TidusYunasGuardian.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tidus, Yuna's Guardian", 205, Rarity.MYTHIC, mage.cards.t.TidusYunasGuardian.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tidus, Yuna's Guardian", 213, Rarity.MYTHIC, mage.cards.t.TidusYunasGuardian.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tidus, Yuna's Guardian", 224, Rarity.MYTHIC, mage.cards.t.TidusYunasGuardian.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tidus, Yuna's Guardian", 5, Rarity.MYTHIC, mage.cards.t.TidusYunasGuardian.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tifa, Martial Artist", 188, Rarity.MYTHIC, mage.cards.t.TifaMartialArtist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tifa, Martial Artist", 206, Rarity.MYTHIC, mage.cards.t.TifaMartialArtist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tifa, Martial Artist", 214, Rarity.MYTHIC, mage.cards.t.TifaMartialArtist.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage/src/main/java/mage/abilities/common/OneOrMoreCombatDamagePlayerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/OneOrMoreCombatDamagePlayerTriggeredAbility.java index f2aa652cfb2..ec79d7e82c2 100644 --- a/Mage/src/main/java/mage/abilities/common/OneOrMoreCombatDamagePlayerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/OneOrMoreCombatDamagePlayerTriggeredAbility.java @@ -20,7 +20,11 @@ public class OneOrMoreCombatDamagePlayerTriggeredAbility extends OneOrMoreDamage } public OneOrMoreCombatDamagePlayerTriggeredAbility(Effect effect, SetTargetPointer setTargetPointer) { - this(Zone.BATTLEFIELD, effect, StaticFilters.FILTER_PERMANENT_CREATURES, setTargetPointer, false); + this(effect, setTargetPointer, false); + } + + public OneOrMoreCombatDamagePlayerTriggeredAbility(Effect effect, SetTargetPointer setTargetPointer, boolean optional) { + this(Zone.BATTLEFIELD, effect, StaticFilters.FILTER_PERMANENT_CREATURES, setTargetPointer, optional); } public OneOrMoreCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect, FilterCreaturePermanent filter, diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/MoveCounterTargetsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/MoveCounterTargetsEffect.java new file mode 100644 index 00000000000..bda45285c45 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/MoveCounterTargetsEffect.java @@ -0,0 +1,112 @@ +package mage.abilities.effects.common.counter; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.EachTargetPointer; +import mage.util.RandomUtil; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Styxo + */ +public class MoveCounterTargetsEffect extends OneShotEffect { + + private final CounterType counterType; + + public MoveCounterTargetsEffect() { + this((CounterType) null); + } + + public MoveCounterTargetsEffect(CounterType counterType) { + super(Outcome.Detriment); + this.counterType = counterType; + this.setTargetPointer(new EachTargetPointer()); + } + + protected MoveCounterTargetsEffect(final MoveCounterTargetsEffect effect) { + super(effect); + this.counterType = effect.counterType; + } + + @Override + public MoveCounterTargetsEffect copy() { + return new MoveCounterTargetsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.size() < 2) { + return false; + } + Permanent fromPermanent = permanents.get(0); + if (counterType != null && !fromPermanent.getCounters(game).containsKey(counterType)) { + return false; + } + CounterType typeToRemove; + if (counterType == null) { + Set types = new HashSet<>(fromPermanent.getCounters(game).keySet()); + switch (types.size()) { + case 0: + return false; + case 1: + typeToRemove = CounterType.findByName(RandomUtil.randomFromCollection(types)); + break; + default: + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Choice choice = new ChoiceImpl(true); + choice.setChoices(types); + choice.setMessage("Choose a type of counter to move"); + player.choose(Outcome.BoostCreature, choice, game); + typeToRemove = CounterType.findByName(choice.getChoice()); + } + } else { + typeToRemove = counterType; + } + if (typeToRemove == null) { + return false; + } + Permanent toPermanent = permanents.get(1); + if (!toPermanent.addCounters(typeToRemove.createInstance(), source, game)) { + return false; + } + fromPermanent.removeCounters(typeToRemove.createInstance(), source, game); + return true; + } + + @Override + public String getText(Mode mode) { + if (!staticText.isEmpty()) { + return staticText; + } + StringBuilder sb = new StringBuilder("move "); + sb.append(Optional + .ofNullable(counterType) + .map(c -> counterType.getArticle() + ' ' + counterType.getName()) + .orElse("a")); + sb.append(" counter from target "); + sb.append(mode.getTargets().get(0).getDescription()); + sb.append(" onto "); + sb.append(mode.getTargets().get(1).getDescription()); + return sb.toString(); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/MoveCountersTargetsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/MoveCountersTargetsEffect.java deleted file mode 100644 index e797f82c7e2..00000000000 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/MoveCountersTargetsEffect.java +++ /dev/null @@ -1,77 +0,0 @@ - -package mage.abilities.effects.common.counter; - -import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.effects.OneShotEffect; -import mage.constants.Outcome; -import mage.counters.CounterType; -import mage.game.Game; -import mage.game.permanent.Permanent; - -/** - * @author Styxo - */ -public class MoveCountersTargetsEffect extends OneShotEffect { - - private final CounterType counterType; - private final int amount; - - public MoveCountersTargetsEffect(CounterType counterType, int amount) { - super(Outcome.Detriment); - this.counterType = counterType; - this.amount = amount; - - } - - protected MoveCountersTargetsEffect(final MoveCountersTargetsEffect effect) { - super(effect); - this.counterType = effect.counterType; - this.amount = effect.amount; - } - - @Override - public MoveCountersTargetsEffect copy() { - return new MoveCountersTargetsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent removeTargetCreature = game.getPermanent(getTargetPointer().getTargets(game, source).get(0)); - Permanent addTargetCreature = game.getPermanent(getTargetPointer().getTargets(game, source).get(1)); - if (removeTargetCreature != null && addTargetCreature != null && removeTargetCreature.getCounters(game).getCount(counterType) >= amount) { - removeTargetCreature.removeCounters(counterType.createInstance(amount), source, game); - addTargetCreature.addCounters(counterType.createInstance(amount), source.getControllerId(), source, game); - if (!game.isSimulation()) { - game.informPlayers("Moved " + amount + ' ' + counterType.getName() + " counter" + (amount > 1 ? "s" : "") + " from " + removeTargetCreature.getLogName() + " to " + addTargetCreature.getLogName()); - } - return true; - } - return false; - } - - @Override - public String getText(Mode mode) { - if (!staticText.isEmpty()) { - return staticText; - } - - StringBuilder sb = new StringBuilder("move "); - if (amount > 1) { - sb.append(amount); - } else { - sb.append('a'); - } - sb.append(' '); - sb.append(counterType.getName()); - sb.append(" counter"); - if (amount > 1) { - sb.append("s "); - } else { - sb.append(' '); - } - sb.append("from one target creature to another target creature"); - - return sb.toString(); - } -}