From 0b50f15923befcb4c22775f129b66497ca1c8c80 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 22 Apr 2022 09:17:09 -0400 Subject: [PATCH] [SNC] Implemented Riveteers Ascendancy --- .../src/mage/cards/d/DonalHeraldOfWings.java | 90 ++++++--------- .../src/mage/cards/n/NykthosParagon.java | 105 +++++------------- .../src/mage/cards/r/RiveteersAscendancy.java | 74 ++++++++++++ .../src/mage/sets/StreetsOfNewCapenna.java | 1 + .../mage/abilities/TriggeredAbilities.java | 2 +- .../java/mage/abilities/TriggeredAbility.java | 2 + .../mage/abilities/TriggeredAbilityImpl.java | 46 ++++++-- .../GainLifeControllerTriggeredAbility.java | 8 +- 8 files changed, 179 insertions(+), 149 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java diff --git a/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java b/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java index 2df6161f99f..a72bc6b9d80 100644 --- a/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java +++ b/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java @@ -7,17 +7,18 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterSpell; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.MageObjectReferencePredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; import mage.util.functions.StackObjectCopyApplier; import java.util.UUID; @@ -27,6 +28,13 @@ import java.util.UUID; */ public class DonalHeraldOfWings extends CardImpl { + private static final FilterSpell filterSpell = new FilterSpell("a nonlegendary creature spell with flying"); + + static { + filterSpell.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); + filterSpell.add(CardType.CREATURE.getPredicate()); + } + public DonalHeraldOfWings(UUID ownderId, CardSetInfo setInfo) { super(ownderId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); @@ -40,57 +48,18 @@ public class DonalHeraldOfWings extends CardImpl { // Whenever you cast a nonlegendary creature spell with flying, you may copy it, // except the copy is a 1/1 Spirit in addition to its other types. // Do this only once each turn. (The copy becomes a token.) - // TODO: This still triggers and asks if you wanna use it, even if you've used it once this turn. - this.addAbility(new DonalHeraldOfWingsTriggeredAbility()); + this.addAbility(new SpellCastControllerTriggeredAbility( + new DonalHeraldOfWingsEffect(), filterSpell, true, true + ).setDoOnlyOnce(true)); } - private DonalHeraldOfWings(final DonalHeraldOfWings card) { super(card); } - - @Override - public DonalHeraldOfWings copy() { return new DonalHeraldOfWings(this); } -} - -class DonalHeraldOfWingsTriggeredAbility extends SpellCastControllerTriggeredAbility { - - private static final FilterSpell filterSpell = new FilterSpell("a nonlegendary creature spell with flying"); - static { - filterSpell.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); - filterSpell.add(CardType.CREATURE.getPredicate()); - } - - DonalHeraldOfWingsTriggeredAbility() { - super(new DonalHeraldOfWingsEffect(), filterSpell, true, true); - } - - private DonalHeraldOfWingsTriggeredAbility(final DonalHeraldOfWingsTriggeredAbility ability) { super(ability); } - - @Override - public DonalHeraldOfWingsTriggeredAbility copy() { - return new DonalHeraldOfWingsTriggeredAbility(this); + private DonalHeraldOfWings(final DonalHeraldOfWings card) { + super(card); } @Override - public boolean checkTrigger(GameEvent event, Game game) { - return abilityAvailableThisTurn(game) && super.checkTrigger(event, game); - } - - @Override - public boolean resolve(Game game) { - if (!(abilityAvailableThisTurn(game) && super.resolve(game))) { return false; } - game.getState().setValue( - CardUtil.getCardZoneString("lastTurnResolved" + originalId, sourceId, game), - game.getTurnNum() - ); - - return true; - } - - private boolean abilityAvailableThisTurn(Game game) { - Integer lastTurnResolved = (Integer) game.getState().getValue( - CardUtil.getCardZoneString("lastTurnResolved" + originalId, sourceId, game) - ); - // A null result is assumed to mean the this ability has not been used yet. - return lastTurnResolved == null || lastTurnResolved != game.getTurnNum(); + public DonalHeraldOfWings copy() { + return new DonalHeraldOfWings(this); } } @@ -98,19 +67,24 @@ class DonalHeraldOfWingsEffect extends OneShotEffect { DonalHeraldOfWingsEffect() { super(Outcome.Copy); - staticText = "you may copy it, except the copy is a 1/1 Spirit in addition to its other types. " + - "Do this only once each turn. (The copy becomes a token.)"; + staticText = "you may copy it, except the copy is a 1/1 Spirit in addition to its other types"; } - private DonalHeraldOfWingsEffect(final DonalHeraldOfWingsEffect effect) { super(effect); } + private DonalHeraldOfWingsEffect(final DonalHeraldOfWingsEffect effect) { + super(effect); + } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { return false; } + if (controller == null) { + return false; + } // Get the card that was cast - if (this.getTargetPointer() == null) { return false; } + if (this.getTargetPointer() == null) { + return false; + } Spell originalSpell = game.getStack().getSpell(((FixedTarget) this.getTargetPointer()).getTarget()); // Create a token copy @@ -120,7 +94,9 @@ class DonalHeraldOfWingsEffect extends OneShotEffect { } @Override - public Effect copy() { return new DonalHeraldOfWingsEffect(this); } + public Effect copy() { + return new DonalHeraldOfWingsEffect(this); + } } enum DonalHeraldOfWingsApplier implements StackObjectCopyApplier { @@ -134,5 +110,7 @@ enum DonalHeraldOfWingsApplier implements StackObjectCopyApplier { } @Override - public MageObjectReferencePredicate getNextNewTargetType(int copyNumber) { return null; } + public MageObjectReferencePredicate getNextNewTargetType(int copyNumber) { + return null; + } } diff --git a/Mage.Sets/src/mage/cards/n/NykthosParagon.java b/Mage.Sets/src/mage/cards/n/NykthosParagon.java index e2cae10701c..39160b8e5d6 100644 --- a/Mage.Sets/src/mage/cards/n/NykthosParagon.java +++ b/Mage.Sets/src/mage/cards/n/NykthosParagon.java @@ -1,27 +1,24 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; +import mage.abilities.common.GainLifeControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.constants.Outcome; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class NykthosParagon extends CardImpl { @@ -35,7 +32,7 @@ public final class NykthosParagon extends CardImpl { this.toughness = new MageInt(6); // Whenever you gain life, you may put that many +1/+1 counters on each creature you control. Do this only once each turn. - this.addAbility(new NykthosParagonTriggeredAbility()); + this.addAbility(new GainLifeControllerTriggeredAbility(new NykthosParagonEffect()).setDoOnlyOnce(true)); } private NykthosParagon(final NykthosParagon card) { @@ -48,65 +45,11 @@ public final class NykthosParagon extends CardImpl { } } -class NykthosParagonTriggeredAbility extends TriggeredAbilityImpl { - - public NykthosParagonTriggeredAbility() { - super(Zone.BATTLEFIELD, new NykthosParagonEffect(), true); - } - - private NykthosParagonTriggeredAbility(final NykthosParagonTriggeredAbility ability) { - super(ability); - } - - @Override - public NykthosParagonTriggeredAbility copy() { - return new NykthosParagonTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.GAINED_LIFE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (abilityAvailableThisTurn(game) && event.getPlayerId().equals(this.getControllerId())) { - for (Effect effect : this.getEffects()) { - effect.setValue("gainedLife", event.getAmount()); - } - return true; - } - return false; - } - - @Override - public boolean resolve(Game game) { - if (abilityAvailableThisTurn(game) && super.resolve(game)) { - game.getState().setValue(CardUtil.getCardZoneString( - "lastTurnResolved" + originalId, sourceId, game - ), game.getTurnNum()); - return true; - } - return false; - } - - private boolean abilityAvailableThisTurn(Game game) { - Integer lastTurnResolved = (Integer) game.getState().getValue( - CardUtil.getCardZoneString("lastTurnResolved" + originalId, sourceId, game) - ); - return lastTurnResolved == null || lastTurnResolved != game.getTurnNum(); - } - - @Override - public String getRule() { - return "Whenever you gain life, you may put that many +1/+1 counters on each creature you control. Do this only once each turn."; - } -} - class NykthosParagonEffect extends OneShotEffect { public NykthosParagonEffect() { super(Outcome.BoostCreature); + staticText = "put that many +1/+1 counters on each creature you control"; } private NykthosParagonEffect(final NykthosParagonEffect effect) { @@ -119,22 +62,26 @@ class NykthosParagonEffect extends OneShotEffect { } @Override - public boolean apply (Game game, Ability source) { + public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source); Integer life = (Integer) this.getValue("gainedLife"); - if (controller != null && sourceObject != null && life != null) { - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (permanent != null && permanent.isCreature(game)) { - permanent.addCounters(CounterType.P1P1.createInstance(life), source.getControllerId(), source, game); - if (!game.isSimulation()) { - game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " puts " + life - + " +1/+1 counters on " + permanent.getLogName()); - } - } - } - return true; + if (controller == null || life == null || life < 1) { + return false; } - return false; + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURES, + source.getControllerId(), source, game + )) { + permanent.addCounters( + CounterType.P1P1.createInstance(life), + source.getControllerId(), source, game + ); + game.informPlayers( + CardUtil.getSourceLogName(game, source) + ": " + + controller.getLogName() + " puts " + life + + " +1/+1 counters on " + permanent.getLogName() + ); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java b/Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java new file mode 100644 index 00000000000..64d31061e6d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java @@ -0,0 +1,74 @@ +package mage.cards.r; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiveteersAscendancy extends CardImpl { + + private static final FilterCard filter + = new FilterCreatureCard("creature card with lesser mana value from your graveyard "); + + static { + filter.add(RiveteersAscendancyPredicate.instance); + } + + public RiveteersAscendancy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{R}{G}"); + + // Whenever you sacrifice a creature, you may return target creature card with lesser mana value from your graveyard to the battlefield tapped. Do this only once each turn. + Ability ability = new SacrificePermanentTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(true) + ).setDoOnlyOnce(true); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + private RiveteersAscendancy(final RiveteersAscendancy card) { + super(card); + } + + @Override + public RiveteersAscendancy copy() { + return new RiveteersAscendancy(this); + } +} + +enum RiveteersAscendancyPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input + .getObject() + .getManaValue() + < input + .getSource() + .getEffects() + .stream() + .map(effect -> effect.getValue("sacrificedPermanent")) + .filter(Objects::nonNull) + .map(Permanent.class::cast) + .mapToInt(MageObject::getManaValue) + .max() + .orElse(0); + } +} diff --git a/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java b/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java index 630f56f2210..42e728cc529 100644 --- a/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java +++ b/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java @@ -210,6 +210,7 @@ public final class StreetsOfNewCapenna extends ExpansionSet { cards.add(new SetCardInfo("Revelation of Power", 28, Rarity.COMMON, mage.cards.r.RevelationOfPower.class)); cards.add(new SetCardInfo("Rhox Pummeler", 155, Rarity.COMMON, mage.cards.r.RhoxPummeler.class)); cards.add(new SetCardInfo("Rigo, Streetwise Mentor", 215, Rarity.RARE, mage.cards.r.RigoStreetwiseMentor.class)); + cards.add(new SetCardInfo("Riveteers Ascendancy", 216, Rarity.RARE, mage.cards.r.RiveteersAscendancy.class)); cards.add(new SetCardInfo("Riveteers Charm", 217, Rarity.UNCOMMON, mage.cards.r.RiveteersCharm.class)); cards.add(new SetCardInfo("Riveteers Decoy", 156, Rarity.UNCOMMON, mage.cards.r.RiveteersDecoy.class)); cards.add(new SetCardInfo("Riveteers Initiate", 120, Rarity.COMMON, mage.cards.r.RiveteersInitiate.class)); diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java index 644313f542d..199da56edc5 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java @@ -91,7 +91,7 @@ public class TriggeredAbilities extends ConcurrentHashMap