From 488b9842815b63b3cb875a6c4188f70eabbbf843 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 24 Oct 2023 20:10:29 -0400 Subject: [PATCH] [LCI] Implement Hidden Courtyard --- .../src/mage/cards/h/HiddenCourtyard.java | 51 ++++++++++++ .../src/mage/sets/TheLostCavernsOfIxalan.java | 1 + .../effects/keyword/DiscoverEffect.java | 78 +++++++++++++++++++ .../src/main/java/mage/constants/SubType.java | 1 + 4 files changed, 131 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/h/HiddenCourtyard.java create mode 100644 Mage/src/main/java/mage/abilities/effects/keyword/DiscoverEffect.java diff --git a/Mage.Sets/src/mage/cards/h/HiddenCourtyard.java b/Mage.Sets/src/mage/cards/h/HiddenCourtyard.java new file mode 100644 index 00000000000..71910f897e2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HiddenCourtyard.java @@ -0,0 +1,51 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.keyword.DiscoverEffect; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HiddenCourtyard extends CardImpl { + + public HiddenCourtyard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.CAVE); + + // Hidden Courtyard enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {W}. + this.addAbility(new WhiteManaAbility()); + + // {4}{W}, {T}, Sacrifice Hidden Courtyard: Discover 4. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + new DiscoverEffect(4), new ManaCostsImpl<>("{4}{W}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private HiddenCourtyard(final HiddenCourtyard card) { + super(card); + } + + @Override + public HiddenCourtyard copy() { + return new HiddenCourtyard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java index 714d7b2d14e..6549c868c89 100644 --- a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java @@ -28,6 +28,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Ghalta, Stampede Tyrant", 185, Rarity.MYTHIC, mage.cards.g.GhaltaStampedeTyrant.class)); cards.add(new SetCardInfo("Gishath, Sun's Avatar", 330, Rarity.MYTHIC, mage.cards.g.GishathSunsAvatar.class)); cards.add(new SetCardInfo("Growing Rites of Itlimoc", 188, Rarity.RARE, mage.cards.g.GrowingRitesOfItlimoc.class)); + cards.add(new SetCardInfo("Hidden Courtyard", 274, Rarity.COMMON, mage.cards.h.HiddenCourtyard.class)); cards.add(new SetCardInfo("Huatli, Poet of Unity", 189, Rarity.MYTHIC, mage.cards.h.HuatliPoetOfUnity.class)); cards.add(new SetCardInfo("Island", 288, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Itlimoc, Cradle of the Sun", 188, Rarity.RARE, mage.cards.i.ItlimocCradleOfTheSun.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/DiscoverEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/DiscoverEffect.java new file mode 100644 index 00000000000..57fe408b2a1 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/keyword/DiscoverEffect.java @@ -0,0 +1,78 @@ +package mage.abilities.effects.keyword; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * @author TheElk801 + */ +public class DiscoverEffect extends OneShotEffect { + + private final int amount; + private final FilterCard filter; + + public DiscoverEffect(int amount) { + super(Outcome.Benefit); + this.amount = amount; + this.filter = new FilterNonlandCard(); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, amount + 1)); + staticText = "Discover " + amount + " (Exile cards from the top of your library " + + "until you exile a nonland card with mana value " + amount + " or less. " + + "Cast it without paying its mana cost or put it into your hand. " + + "Put the rest on the bottom in a random order.)"; + } + + private DiscoverEffect(final DiscoverEffect effect) { + super(effect); + this.amount = effect.amount; + this.filter = effect.filter.copy(); + } + + @Override + public DiscoverEffect copy() { + return new DiscoverEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + Card card = getCard(player, cards, game, source); + if (card != null) { + CardUtil.castSpellWithAttributesForFree(player, source, game, card, filter); + if (game.getState().getZone(card.getId()) == Zone.EXILED) { + player.moveCards(card, Zone.HAND, source, game); + } + } + cards.retainZone(Zone.EXILED, game); + player.putCardsOnBottomOfLibrary(cards, game, source, false); + return true; + } + + private Card getCard(Player player, Cards cards, Game game, Ability source) { + for (Card card : player.getLibrary().getCards(game)) { + cards.add(card); + player.moveCards(card, Zone.EXILED, source, game); + game.getState().processAction(game); + if (filter.match(card, game)) { + return card; + } + } + return null; + } +} diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index 92c7d91ae4c..131cbcea9ec 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -25,6 +25,7 @@ public enum SubType { MOUNTAIN("Mountain", SubTypeSet.BasicLandType), PLAINS("Plains", SubTypeSet.BasicLandType), SWAMP("Swamp", SubTypeSet.BasicLandType), + CAVE("Cave", SubTypeSet.NonBasicLandType), DESERT("Desert", SubTypeSet.NonBasicLandType), GATE("Gate", SubTypeSet.NonBasicLandType), LAIR("Lair", SubTypeSet.NonBasicLandType),