From a1318663d6731e80f89e046575cf8c7a4c5d9f8d Mon Sep 17 00:00:00 2001 From: Daniel Bomar Date: Tue, 22 Dec 2020 18:04:43 -0600 Subject: [PATCH 1/2] [KHM] Implemented Kaya the Inexorable --- .../src/mage/cards/k/KayaTheInexorable.java | 170 ++++++++++++++++++ Mage.Sets/src/mage/sets/Kaldheim.java | 1 + .../main/java/mage/counters/CounterType.java | 1 + .../emblems/KayaTheInexorableEmblem.java | 104 +++++++++++ 4 files changed, 276 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/k/KayaTheInexorable.java create mode 100644 Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java diff --git a/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java b/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java new file mode 100644 index 0000000000..0f00bd2c62 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java @@ -0,0 +1,170 @@ +package mage.cards.k; + +import mage.MageObject; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.command.emblems.KayaTheInexorableEmblem; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.SpiritWhiteToken; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * + * @author weirddan455 + */ +public final class KayaTheInexorable extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); + static { + filter.add(Predicates.not(TokenPredicate.instance)); + } + + public KayaTheInexorable(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{W}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.KAYA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // +1: Put a ghostform counter on up to one target nontoken creature. It gains "When this creature dies or is put into exile, return it to its owner's hand and create a 1/1 white Spirit creature token with flying." + LoyaltyAbility ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.GHOSTFORM.createInstance()), 1); + ability.addEffect(new GainAbilityTargetEffect(new KayaTheInexorableTriggeredAbility(), Duration.WhileOnBattlefield, + "It gains \"When this creature dies or is put into exile, return it to its owner's hand and create a 1/1 white Spirit creature token with flying.\"")); + ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + this.addAbility(ability); + + // −3: Exile target nonland permanent. + ability = new LoyaltyAbility(new ExileTargetEffect(), -3); + ability.addTarget(new TargetNonlandPermanent()); + this.addAbility(ability); + + // −7: You get an emblem with "At the beginning of your upkeep, you may cast a legendary spell from your hand, from your graveyard, or from among cards you own in exile without paying its mana cost." + this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new KayaTheInexorableEmblem()), -7)); + } + + private KayaTheInexorable(final KayaTheInexorable card) { + super(card); + } + + @Override + public KayaTheInexorable copy() { + return new KayaTheInexorable(this); + } +} + +class KayaTheInexorableTriggeredAbility extends TriggeredAbilityImpl { + + public KayaTheInexorableTriggeredAbility() { + super(Zone.ALL, null, false); + } + + private KayaTheInexorableTriggeredAbility(KayaTheInexorableTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.getFromZone() == Zone.BATTLEFIELD + && (zEvent.getToZone() == Zone.GRAVEYARD + || zEvent.getToZone() == Zone.EXILED); + } + return false; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getTargetId().equals(this.getSourceId())) { + this.getEffects().clear(); + this.addEffect(new KayaTheInexorableEffect(new MageObjectReference(zEvent.getTarget(), game))); + this.addEffect(new CreateTokenEffect(new SpiritWhiteToken())); + return true; + } + return false; + } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + Permanent sourcePermanent = null; + if (game.getState().getZone(getSourceId()) == Zone.BATTLEFIELD) { + sourcePermanent = game.getPermanent(getSourceId()); + } else { + if (game.getShortLivingLKI(getSourceId(), Zone.BATTLEFIELD)) { + sourcePermanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD); + } + } + if (sourcePermanent == null) { + return false; + } + return hasSourceObjectAbility(game, sourcePermanent, event); + } + + @Override + public KayaTheInexorableTriggeredAbility copy() { + return new KayaTheInexorableTriggeredAbility(this); + } + + @Override + public String getRule() { + return "When {this} dies or is put into exile, return it to its owner's hand and create a 1/1 white Spirit creature token with flying."; + } +} + +class KayaTheInexorableEffect extends OneShotEffect { + + private final MageObjectReference mor; + + KayaTheInexorableEffect(MageObjectReference mor) { + super(Outcome.Benefit); + this.mor = mor; + } + + private KayaTheInexorableEffect(KayaTheInexorableEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public KayaTheInexorableEffect copy() { + return new KayaTheInexorableEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = game.getCard(mor.getSourceId()); + if (card == null || card.getZoneChangeCounter(game) - 1 != mor.getZoneChangeCounter()) { + return false; + } + return player.moveCards(card, Zone.HAND, source, game); + } +} diff --git a/Mage.Sets/src/mage/sets/Kaldheim.java b/Mage.Sets/src/mage/sets/Kaldheim.java index 795bec6ce6..8d4f97e3ae 100644 --- a/Mage.Sets/src/mage/sets/Kaldheim.java +++ b/Mage.Sets/src/mage/sets/Kaldheim.java @@ -42,6 +42,7 @@ public final class Kaldheim extends ExpansionSet { cards.add(new SetCardInfo("Gilded Assault Cart", 390, Rarity.UNCOMMON, mage.cards.g.GildedAssaultCart.class)); cards.add(new SetCardInfo("Gladewalker Ritualist", 392, Rarity.UNCOMMON, mage.cards.g.GladewalkerRitualist.class)); cards.add(new SetCardInfo("Hengegate Pathway", 260, Rarity.RARE, mage.cards.h.HengegatePathway.class)); + cards.add(new SetCardInfo("Kaya the Inexorable", 218, Rarity.MYTHIC, mage.cards.k.KayaTheInexorable.class)); cards.add(new SetCardInfo("Rampage of the Valkyries", 393, Rarity.UNCOMMON, mage.cards.r.RampageOfTheValkyries.class)); cards.add(new SetCardInfo("Renegade Reaper", 386, Rarity.UNCOMMON, mage.cards.r.RenegadeReaper.class)); cards.add(new SetCardInfo("Showdown of the Skalds", 229, Rarity.RARE, mage.cards.s.ShowdownOfTheSkalds.class)); diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index 93c9c57164..ea08814b73 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -64,6 +64,7 @@ public enum CounterType { FUNGUS("fungus"), FUSE("fuse"), GEM("gem"), + GHOSTFORM("ghostform"), GLOBE("globe"), GLYPH("glyph"), GOLD("gold"), diff --git a/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java b/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java new file mode 100644 index 0000000000..b7dcb9a9b6 --- /dev/null +++ b/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java @@ -0,0 +1,104 @@ +package mage.game.command.emblems; + +import mage.ApprovingObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.*; +import mage.filter.common.FilterOwnedCard; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.command.Emblem; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInExile; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * + * @author weirddan455 + */ +public class KayaTheInexorableEmblem extends Emblem { + + // −7: You get an emblem with "At the beginning of your upkeep, you may cast a legendary spell from your hand, from your graveyard, or from among cards you own in exile without paying its mana cost." + public KayaTheInexorableEmblem() { + + this.setName("Emblem Kaya"); + this.setExpansionSetCodeForImage("KHM"); + this.getAbilities().add(new BeginningOfUpkeepTriggeredAbility(Zone.COMMAND, new KayaTheInexorableEmblemEffect(), TargetController.YOU, true, false)); + } +} + +class KayaTheInexorableEmblemEffect extends OneShotEffect { + + private static final FilterOwnedCard filter = new FilterOwnedCard(); + static { + filter.add(SuperType.LEGENDARY.getPredicate()); + filter.add(Predicates.not(CardType.LAND.getPredicate())); + } + + public KayaTheInexorableEmblemEffect() { + super(Outcome.PlayForFree); + this.staticText = "cast a legendary spell from your hand, from your graveyard, or from among cards you own in exile without paying its mana cost"; + } + + private KayaTheInexorableEmblemEffect(final KayaTheInexorableEmblemEffect effect) { + super(effect); + } + + @Override + public KayaTheInexorableEmblemEffect copy() { + return new KayaTheInexorableEmblemEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + Set choices = new LinkedHashSet<>(); + choices.add("Hand"); + choices.add("Graveyard"); + choices.add("Exile"); + Choice zoneChoice = new ChoiceImpl(true); + zoneChoice.setMessage("Cast a legendary spell from hand, graveyard, or exile"); + zoneChoice.setChoices(choices); + zoneChoice.clearChoice(); + if (player.choose(Outcome.PlayForFree, zoneChoice, game)) { + TargetCard target = null; + switch (zoneChoice.getChoice()) { + case "Hand": + target = new TargetCardInHand(0, 1, filter); + target.setTargetName("legendary spell from your hand"); + break; + case "Graveyard": + target = new TargetCardInYourGraveyard(0, 1, filter, true); + target.setTargetName("legendary spell from your graveyard"); + break; + case "Exile": + target = new TargetCardInExile(0, 1, filter, null, true); + target.setNotTarget(true); + target.setTargetName("legendary spell you own in exile"); + break; + } + if (target != null && player.chooseTarget(Outcome.PlayForFree, target, source, game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); + boolean cardWasCast = player.cast(player.chooseAbilityForCast(card, game, true), + game, true, new ApprovingObject(source, game)); + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); + return cardWasCast; + } + } + } + } + return false; + } +} From 0a28963aa3f003fcc9c1d3c5dce397d98355ad18 Mon Sep 17 00:00:00 2001 From: Daniel Bomar Date: Wed, 23 Dec 2020 14:29:03 -0600 Subject: [PATCH 2/2] [KHM] KayaTheInexorableEmblem - Move choices to static --- .../game/command/emblems/KayaTheInexorableEmblem.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java b/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java index b7dcb9a9b6..96b753831d 100644 --- a/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java @@ -39,9 +39,13 @@ public class KayaTheInexorableEmblem extends Emblem { class KayaTheInexorableEmblemEffect extends OneShotEffect { private static final FilterOwnedCard filter = new FilterOwnedCard(); + private static final Set choices = new LinkedHashSet<>(); static { filter.add(SuperType.LEGENDARY.getPredicate()); filter.add(Predicates.not(CardType.LAND.getPredicate())); + choices.add("Hand"); + choices.add("Graveyard"); + choices.add("Exile"); } public KayaTheInexorableEmblemEffect() { @@ -62,10 +66,6 @@ class KayaTheInexorableEmblemEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - Set choices = new LinkedHashSet<>(); - choices.add("Hand"); - choices.add("Graveyard"); - choices.add("Exile"); Choice zoneChoice = new ChoiceImpl(true); zoneChoice.setMessage("Cast a legendary spell from hand, graveyard, or exile"); zoneChoice.setChoices(choices);