From c65956e5f2542ffc7e953fdae81ceda6f346a080 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 17 Apr 2023 17:50:00 -0400 Subject: [PATCH] [MOM] Implement Invasion of Gobakhan / Lightshield Array --- .../src/mage/cards/i/InvasionOfGobakhan.java | 167 ++++++++++++++++++ .../src/mage/cards/l/LightshieldArray.java | 93 ++++++++++ .../src/mage/sets/MarchOfTheMachine.java | 2 + 3 files changed, 262 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/i/InvasionOfGobakhan.java create mode 100644 Mage.Sets/src/mage/cards/l/LightshieldArray.java diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfGobakhan.java b/Mage.Sets/src/mage/cards/i/InvasionOfGobakhan.java new file mode 100644 index 00000000000..cb5e65bd964 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvasionOfGobakhan.java @@ -0,0 +1,167 @@ +package mage.cards.i; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SiegeAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetOpponent; +import mage.util.CardUtil; +import mage.watchers.common.AttackedThisTurnWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InvasionOfGobakhan extends CardImpl { + + public InvasionOfGobakhan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{1}{W}"); + + this.subtype.add(SubType.SIEGE); + this.setStartingDefense(3); + this.secondSideCardClazz = mage.cards.l.LightshieldArray.class; + + // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) + this.addAbility(new SiegeAbility()); + + // When Invasion of Gobakhan enters the battlefield, look at target opponent's hand. You may exile a nonland card from it. For as long as that card remains exiled, its owner may play it. A spell cast this way costs {2} more to cast. + Ability ability = new EntersBattlefieldTriggeredAbility(new InvasionOfGobakhanEffect()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability, new AttackedThisTurnWatcher()); + } + + private InvasionOfGobakhan(final InvasionOfGobakhan card) { + super(card); + } + + @Override + public InvasionOfGobakhan copy() { + return new InvasionOfGobakhan(this); + } +} + +class InvasionOfGobakhanEffect extends OneShotEffect { + + InvasionOfGobakhanEffect() { + super(Outcome.Benefit); + staticText = "look at target opponent's hand. You may exile a nonland card from it. " + + "For as long as that card remains exiled, its owner may play it. " + + "A spell cast this way costs {2} more to cast"; + } + + private InvasionOfGobakhanEffect(final InvasionOfGobakhanEffect effect) { + super(effect); + } + + @Override + public InvasionOfGobakhanEffect copy() { + return new InvasionOfGobakhanEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller == null || opponent == null || opponent.getHand().isEmpty()) { + return false; + } + TargetCard target = new TargetCardInHand( + 0, 1, StaticFilters.FILTER_CARD_A_NON_LAND + ); + controller.choose(outcome, opponent.getHand(), target, game); + Card card = opponent.getHand().get(target.getFirstTarget(), game); + if (card == null) { + return false; + } + controller.moveCards(card, Zone.EXILED, source, game); + game.addEffect(new InvasionOfGobakhanCastEffect(card, game), source); + game.addEffect(new InvasionOfGobakhanCostEffect(card, game), source); + return true; + } +} + +class InvasionOfGobakhanCastEffect extends AsThoughEffectImpl { + + private final MageObjectReference mor; + + public InvasionOfGobakhanCastEffect(Card card, Game game) { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); + this.mor = new MageObjectReference(card, game); + } + + private InvasionOfGobakhanCastEffect(final InvasionOfGobakhanCastEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public InvasionOfGobakhanCastEffect copy() { + return new InvasionOfGobakhanCastEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + Card card = mor.getCard(game); + if (card == null) { + discard(); + return false; + } + return mor.refersTo(CardUtil.getMainCardId(game, sourceId), game) + && card.isOwnedBy(affectedControllerId); + } +} + +class InvasionOfGobakhanCostEffect extends CostModificationEffectImpl { + + private final MageObjectReference mor; + + InvasionOfGobakhanCostEffect(Card card, Game game) { + super(Duration.Custom, Outcome.Benefit, CostModificationType.INCREASE_COST); + mor = new MageObjectReference(card, game, 1); + } + + private InvasionOfGobakhanCostEffect(InvasionOfGobakhanCostEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + CardUtil.increaseCost(abilityToModify, 2); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if (game.inCheckPlayableState()) { // during playable check, the card is still in exile zone, the zcc is one less + UUID cardtoCheckId = CardUtil.getMainCardId(game, abilityToModify.getSourceId()); + return mor.getSourceId().equals(cardtoCheckId) + && mor.getZoneChangeCounter() == game.getState().getZoneChangeCounter(cardtoCheckId) + 1; + } else { + return mor.refersTo(CardUtil.getMainCardId(game, abilityToModify.getSourceId()), game); + } + } + + @Override + public InvasionOfGobakhanCostEffect copy() { + return new InvasionOfGobakhanCostEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LightshieldArray.java b/Mage.Sets/src/mage/cards/l/LightshieldArray.java new file mode 100644 index 00000000000..6a62ec837d9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LightshieldArray.java @@ -0,0 +1,93 @@ +package mage.cards.l; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.watchers.common.AttackedThisTurnWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LightshieldArray extends CardImpl { + + public LightshieldArray(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); + + this.color.setWhite(true); + this.nightCard = true; + + // At the beginning of your end step, put a +1/+1 counter on each creature that attacked this turn. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new LightshieldArrayEffect(), TargetController.YOU, false + )); + + // Sacrifice Lightshield Array: Creatures you control gain hexproof and indestructible until end of turn. + Ability ability = new SimpleActivatedAbility(new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("creatures you control gain hexproof"), new SacrificeSourceCost()); + ability.addEffect(new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("and indestructible until end of turn")); + this.addAbility(ability); + } + + private LightshieldArray(final LightshieldArray card) { + super(card); + } + + @Override + public LightshieldArray copy() { + return new LightshieldArray(this); + } +} + +class LightshieldArrayEffect extends OneShotEffect { + + LightshieldArrayEffect() { + super(Outcome.Benefit); + staticText = "put a +1/+1 counter on each creature that attacked this turn"; + } + + private LightshieldArrayEffect(final LightshieldArrayEffect effect) { + super(effect); + } + + @Override + public LightshieldArrayEffect copy() { + return new LightshieldArrayEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (MageObjectReference mor : game + .getState() + .getWatcher(AttackedThisTurnWatcher.class) + .getAttackedThisTurnCreatures()) { + Permanent permanent = mor.getPermanent(game); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/MarchOfTheMachine.java b/Mage.Sets/src/mage/sets/MarchOfTheMachine.java index 4d24493faca..d8e4bffe6b9 100644 --- a/Mage.Sets/src/mage/sets/MarchOfTheMachine.java +++ b/Mage.Sets/src/mage/sets/MarchOfTheMachine.java @@ -168,6 +168,7 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Invasion of Eldraine", 113, Rarity.UNCOMMON, mage.cards.i.InvasionOfEldraine.class)); cards.add(new SetCardInfo("Invasion of Ergamon", 233, Rarity.UNCOMMON, mage.cards.i.InvasionOfErgamon.class)); cards.add(new SetCardInfo("Invasion of Fiora", 114, Rarity.RARE, mage.cards.i.InvasionOfFiora.class)); + cards.add(new SetCardInfo("Invasion of Gobakhan", 22, Rarity.RARE, mage.cards.i.InvasionOfGobakhan.class)); cards.add(new SetCardInfo("Invasion of Innistrad", 115, Rarity.MYTHIC, mage.cards.i.InvasionOfInnistrad.class)); cards.add(new SetCardInfo("Invasion of Ixalan", 191, Rarity.RARE, mage.cards.i.InvasionOfIxalan.class)); cards.add(new SetCardInfo("Invasion of Kaladesh", 234, Rarity.UNCOMMON, mage.cards.i.InvasionOfKaladesh.class)); @@ -210,6 +211,7 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Kyren Flamewright", 147, Rarity.UNCOMMON, mage.cards.k.KyrenFlamewright.class)); cards.add(new SetCardInfo("Lazotep Convert", 231, Rarity.UNCOMMON, mage.cards.l.LazotepConvert.class)); cards.add(new SetCardInfo("Leyline Surge", 193, Rarity.MYTHIC, mage.cards.l.LeylineSurge.class)); + cards.add(new SetCardInfo("Lightshield Array", 22, Rarity.RARE, mage.cards.l.LightshieldArray.class)); cards.add(new SetCardInfo("Lithomantic Barrage", 152, Rarity.UNCOMMON, mage.cards.l.LithomanticBarrage.class)); cards.add(new SetCardInfo("Malady Invoker", 189, Rarity.UNCOMMON, mage.cards.m.MaladyInvoker.class)); cards.add(new SetCardInfo("Marauding Dreadship", 153, Rarity.COMMON, mage.cards.m.MaraudingDreadship.class));