diff --git a/Mage.Sets/src/mage/cards/e/EtchingOfKumano.java b/Mage.Sets/src/mage/cards/e/EtchingOfKumano.java new file mode 100644 index 00000000000..55da585e7cf --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EtchingOfKumano.java @@ -0,0 +1,88 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.constants.*; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.watchers.common.DamagedByControlledWatcher; + +/** + * + * @author weirddan455 + */ +public final class EtchingOfKumano extends CardImpl { + + public EtchingOfKumano(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + this.color.setRed(true); + this.nightCard = true; + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // If a creature dealt damage this turn by a source you controlled would die, exile it instead. + this.addAbility(new SimpleStaticAbility(new EtchingOfKumanoReplacementEffect()), new DamagedByControlledWatcher()); + } + + private EtchingOfKumano(final EtchingOfKumano card) { + super(card); + } + + @Override + public EtchingOfKumano copy() { + return new EtchingOfKumano(this); + } +} + +class EtchingOfKumanoReplacementEffect extends ReplacementEffectImpl { + + public EtchingOfKumanoReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Exile); + this.staticText = "If a creature dealt damage this turn by a source you controlled would die, exile it instead"; + } + + private EtchingOfKumanoReplacementEffect(final EtchingOfKumanoReplacementEffect effect) { + super(effect); + } + + @Override + public EtchingOfKumanoReplacementEffect copy() { + return new EtchingOfKumanoReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + ((ZoneChangeEvent) event).setToZone(Zone.EXILED); + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zce = (ZoneChangeEvent) event; + if (zce.isDiesEvent()) { + DamagedByControlledWatcher watcher = game.getState().getWatcher(DamagedByControlledWatcher.class, source.getControllerId()); + if (watcher != null) { + return watcher.wasDamaged(zce.getTarget(), game); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KumanoFacesKakkazan.java b/Mage.Sets/src/mage/cards/k/KumanoFacesKakkazan.java new file mode 100644 index 00000000000..80ea9b04903 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KumanoFacesKakkazan.java @@ -0,0 +1,176 @@ +package mage.cards.k; + +import java.util.Set; +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.keyword.TransformAbility; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; + +/** + * + * @author weirddan455 + */ +public final class KumanoFacesKakkazan extends CardImpl { + + public KumanoFacesKakkazan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + + this.subtype.add(SubType.SAGA); + this.secondSideCardClazz = mage.cards.e.EtchingOfKumano.class; + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I — Kumano Faces Kakkazan deals 1 damage to each opponent and each planeswalker they control. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new KumanoFacesKakkazanDamageEffect()); + + // II — When you cast your next creature spell this turn, that creature enters the battlefield with an additional +1/+1 counter on it. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new CreateDelayedTriggeredAbilityEffect(new KumanoFacesKakkazanTriggeredAbility())); + + // III — Exile this Saga, then return it to the battlefield transformed under your control. + this.addAbility(new TransformAbility()); + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + + this.addAbility(sagaAbility); + } + + private KumanoFacesKakkazan(final KumanoFacesKakkazan card) { + super(card); + } + + @Override + public KumanoFacesKakkazan copy() { + return new KumanoFacesKakkazan(this); + } +} + +class KumanoFacesKakkazanDamageEffect extends OneShotEffect { + + public KumanoFacesKakkazanDamageEffect() { + super(Outcome.Damage); + this.staticText = "{this} deals 1 damage to each opponent and each planeswalker they control"; + } + + private KumanoFacesKakkazanDamageEffect(final KumanoFacesKakkazanDamageEffect effect) { + super(effect); + } + + @Override + public KumanoFacesKakkazanDamageEffect copy() { + return new KumanoFacesKakkazanDamageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Set opponents = game.getOpponents(source.getControllerId()); + if (opponents.isEmpty()) { + return false; + } + for (UUID opponentId : opponents) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + opponent.damage(1, source, game); + } + } + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(CardType.PLANESWALKER, game)) { + if (opponents.contains(permanent.getControllerId())) { + permanent.damage(1, source, game); + } + } + return true; + } +} + +class KumanoFacesKakkazanTriggeredAbility extends DelayedTriggeredAbility { + + public KumanoFacesKakkazanTriggeredAbility() { + super(null, Duration.EndOfTurn); + } + + private KumanoFacesKakkazanTriggeredAbility(final KumanoFacesKakkazanTriggeredAbility ability) { + super(ability); + } + + @Override + public KumanoFacesKakkazanTriggeredAbility copy() { + return new KumanoFacesKakkazanTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (this.isControlledBy(event.getPlayerId())) { + Spell spell = game.getSpell(event.getTargetId()); + if (spell != null && spell.isCreature(game)) { + this.getEffects().clear(); + this.getEffects().add(new KumanoFacesKakkazanCounterEffect(spell.getSourceId())); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "When you cast your next creature spell this turn, that creature enters the battlefield with an additional +1/+1 counter on it."; + } +} + +class KumanoFacesKakkazanCounterEffect extends ReplacementEffectImpl { + + private final UUID spellCastId; + + public KumanoFacesKakkazanCounterEffect(UUID spellCastId) { + super(Duration.EndOfTurn, Outcome.BoostCreature); + this.spellCastId = spellCastId; + } + + private KumanoFacesKakkazanCounterEffect(final KumanoFacesKakkazanCounterEffect effect) { + super(effect); + this.spellCastId = effect.spellCastId; + } + + @Override + public KumanoFacesKakkazanCounterEffect copy() { + return new KumanoFacesKakkazanCounterEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return spellCastId.equals(event.getTargetId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game, event.getAppliedEffects()); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java index d9cb4e13713..f34b6d11f22 100644 --- a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java +++ b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java @@ -89,6 +89,7 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Enthusiastic Mechanaut", 218, Rarity.UNCOMMON, mage.cards.e.EnthusiasticMechanaut.class)); cards.add(new SetCardInfo("Era of Enlightenment", 11, Rarity.COMMON, mage.cards.e.EraOfEnlightenment.class)); cards.add(new SetCardInfo("Essence Capture", 52, Rarity.UNCOMMON, mage.cards.e.EssenceCapture.class)); + cards.add(new SetCardInfo("Etching of Kumano", 152, Rarity.UNCOMMON, mage.cards.e.EtchingOfKumano.class)); cards.add(new SetCardInfo("Experimental Synthesizer", 138, Rarity.COMMON, mage.cards.e.ExperimentalSynthesizer.class)); cards.add(new SetCardInfo("Explosive Entry", 139, Rarity.COMMON, mage.cards.e.ExplosiveEntry.class)); cards.add(new SetCardInfo("Explosive Singularity", 140, Rarity.MYTHIC, mage.cards.e.ExplosiveSingularity.class)); @@ -165,6 +166,7 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Kitsune Ace", 22, Rarity.COMMON, mage.cards.k.KitsuneAce.class)); cards.add(new SetCardInfo("Kodama of the West Tree", 199, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class)); cards.add(new SetCardInfo("Kotose, the Silent Spider", 351, Rarity.RARE, mage.cards.k.KotoseTheSilentSpider.class)); + cards.add(new SetCardInfo("Kumano Faces Kakkazan", 152, Rarity.UNCOMMON, mage.cards.k.KumanoFacesKakkazan.class)); cards.add(new SetCardInfo("Kura, the Boundless Sky", 200, Rarity.MYTHIC, mage.cards.k.KuraTheBoundlessSky.class)); cards.add(new SetCardInfo("Kyodai, Soul of Kamigawa", 23, Rarity.RARE, mage.cards.k.KyodaiSoulOfKamigawa.class)); cards.add(new SetCardInfo("Leech Gauntlet", 106, Rarity.UNCOMMON, mage.cards.l.LeechGauntlet.class)); diff --git a/Mage/src/main/java/mage/watchers/common/DamagedByControlledWatcher.java b/Mage/src/main/java/mage/watchers/common/DamagedByControlledWatcher.java new file mode 100644 index 00000000000..cfc8b28461b --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/DamagedByControlledWatcher.java @@ -0,0 +1,45 @@ +package mage.watchers.common; + +import mage.MageObjectReference; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; + +import java.util.HashSet; + +/** + * + * @author weirddan455 + */ +public class DamagedByControlledWatcher extends Watcher { + + private final HashSet damagedPermanents = new HashSet<>(); + + public DamagedByControlledWatcher() { + super(WatcherScope.PLAYER); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGED_PERMANENT) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null && permanent.isCreature(game)) { + if (controllerId != null && controllerId.equals(game.getControllerId(event.getSourceId()))) { + damagedPermanents.add(new MageObjectReference(event.getTargetId(), game)); + } + } + } + } + + @Override + public void reset() { + super.reset(); + damagedPermanents.clear(); + } + + public boolean wasDamaged(Permanent permanent, Game game) { + return damagedPermanents.contains(new MageObjectReference(permanent, game)); + } +}