From 43e95fd0cfe4e1f4fd564cc546afb9d787c81c64 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 10 Jul 2024 22:57:22 -0400 Subject: [PATCH] [BLB] Implement forage mechanic (#12569) * [BLB] Implement Corpseberry Cultivator * [BLB] Implement Thornvault Forager * fix verify failure --- .../mage/cards/c/CorpseberryCultivator.java | 49 ++++++++++++++ .../src/mage/cards/t/ThornvaultForager.java | 67 +++++++++++++++++++ Mage.Sets/src/mage/sets/Bloomburrow.java | 2 + .../common/ForageTriggeredAbility.java | 41 ++++++++++++ .../abilities/costs/common/ForageCost.java | 43 ++++++++++++ .../main/java/mage/game/events/GameEvent.java | 6 ++ 6 files changed, 208 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CorpseberryCultivator.java create mode 100644 Mage.Sets/src/mage/cards/t/ThornvaultForager.java create mode 100644 Mage/src/main/java/mage/abilities/common/ForageTriggeredAbility.java create mode 100644 Mage/src/main/java/mage/abilities/costs/common/ForageCost.java diff --git a/Mage.Sets/src/mage/cards/c/CorpseberryCultivator.java b/Mage.Sets/src/mage/cards/c/CorpseberryCultivator.java new file mode 100644 index 00000000000..9c0eca8e65e --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CorpseberryCultivator.java @@ -0,0 +1,49 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.ForageTriggeredAbility; +import mage.abilities.costs.common.ForageCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CorpseberryCultivator extends CardImpl { + + public CorpseberryCultivator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B/G}{B/G}"); + + this.subtype.add(SubType.SQUIRREL); + this.subtype.add(SubType.WARLOCK); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // At the beginning of combat on your turn, you may forage. + this.addAbility(new BeginningOfCombatTriggeredAbility( + new DoIfCostPaid(null, new ForageCost()), + TargetController.YOU, false + )); + + // Whenever you forage, put a +1/+1 counter on Corpseberry Cultivator. + this.addAbility(new ForageTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); + } + + private CorpseberryCultivator(final CorpseberryCultivator card) { + super(card); + } + + @Override + public CorpseberryCultivator copy() { + return new CorpseberryCultivator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThornvaultForager.java b/Mage.Sets/src/mage/cards/t/ThornvaultForager.java new file mode 100644 index 00000000000..ed4655a327b --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThornvaultForager.java @@ -0,0 +1,67 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.ForageCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.effects.mana.AddManaInAnyCombinationEffect; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThornvaultForager extends CardImpl { + + private static final FilterCard filter = new FilterCard("a Squirrel card"); + + static { + filter.add(SubType.SQUIRREL.getPredicate()); + } + + public ThornvaultForager(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.SQUIRREL); + this.subtype.add(SubType.RANGER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {T}: Add {G}. + this.addAbility(new GreenManaAbility()); + + // {T}, Forage: Add two mana in any combination of colors. + Ability ability = new SimpleManaAbility(new AddManaInAnyCombinationEffect(5), new TapSourceCost()); + ability.addCost(new ForageCost()); + this.addAbility(ability); + + // {3}{G}, {T}: Search your library for a Squirrel card, reveal it, put it into your hand, then shuffle. + ability = new SimpleActivatedAbility( + new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(filter), true + ), new ManaCostsImpl<>("{3}{G}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private ThornvaultForager(final ThornvaultForager card) { + super(card); + } + + @Override + public ThornvaultForager copy() { + return new ThornvaultForager(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Bloomburrow.java b/Mage.Sets/src/mage/sets/Bloomburrow.java index c137252db51..c4d60b92431 100644 --- a/Mage.Sets/src/mage/sets/Bloomburrow.java +++ b/Mage.Sets/src/mage/sets/Bloomburrow.java @@ -30,6 +30,7 @@ public final class Bloomburrow extends ExpansionSet { cards.add(new SetCardInfo("Byrke, Long Ear of the Law", 380, Rarity.MYTHIC, mage.cards.b.ByrkeLongEarOfTheLaw.class)); cards.add(new SetCardInfo("Cache Grab", 167, Rarity.COMMON, mage.cards.c.CacheGrab.class)); cards.add(new SetCardInfo("Carrot Cake", 7, Rarity.COMMON, mage.cards.c.CarrotCake.class)); + cards.add(new SetCardInfo("Corpseberry Cultivator", 210, Rarity.COMMON, mage.cards.c.CorpseberryCultivator.class)); cards.add(new SetCardInfo("Early Winter", 93, Rarity.COMMON, mage.cards.e.EarlyWinter.class)); cards.add(new SetCardInfo("Fell", 95, Rarity.UNCOMMON, mage.cards.f.Fell.class)); cards.add(new SetCardInfo("Flowerfoot Swordmaster", 14, Rarity.UNCOMMON, mage.cards.f.FlowerfootSwordmaster.class)); @@ -67,6 +68,7 @@ public final class Bloomburrow extends ExpansionSet { cards.add(new SetCardInfo("Swamp", 270, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Tempest Angler", 235, Rarity.COMMON, mage.cards.t.TempestAngler.class)); cards.add(new SetCardInfo("Tender Wildguide", 196, Rarity.RARE, mage.cards.t.TenderWildguide.class)); + cards.add(new SetCardInfo("Thornvault Forager", 197, Rarity.RARE, mage.cards.t.ThornvaultForager.class)); cards.add(new SetCardInfo("Thundertrap Trainer", 78, Rarity.RARE, mage.cards.t.ThundertrapTrainer.class)); cards.add(new SetCardInfo("Veteran Guardmouse", 237, Rarity.COMMON, mage.cards.v.VeteranGuardmouse.class)); cards.add(new SetCardInfo("Warren Warleader", 38, Rarity.MYTHIC, mage.cards.w.WarrenWarleader.class)); diff --git a/Mage/src/main/java/mage/abilities/common/ForageTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/ForageTriggeredAbility.java new file mode 100644 index 00000000000..ff10a0d5952 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/ForageTriggeredAbility.java @@ -0,0 +1,41 @@ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * @author TheElk801 + */ +public class ForageTriggeredAbility extends TriggeredAbilityImpl { + + public ForageTriggeredAbility(Effect effect) { + this(Zone.BATTLEFIELD, effect, false); + } + + public ForageTriggeredAbility(Zone zone, Effect effect, boolean optional) { + super(zone, effect, optional); + setTriggerPhrase("Whenever you forage, "); + } + + private ForageTriggeredAbility(final ForageTriggeredAbility ability) { + super(ability); + } + + @Override + public ForageTriggeredAbility copy() { + return new ForageTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.FORAGED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return isControlledBy(event.getPlayerId()); + } +} diff --git a/Mage/src/main/java/mage/abilities/costs/common/ForageCost.java b/Mage/src/main/java/mage/abilities/costs/common/ForageCost.java new file mode 100644 index 00000000000..e5e07d7187f --- /dev/null +++ b/Mage/src/main/java/mage/abilities/costs/common/ForageCost.java @@ -0,0 +1,43 @@ +package mage.abilities.costs.common; + +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.OrCost; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class ForageCost extends OrCost { + + public ForageCost() { + super( + "forage", + new ExileFromGraveCost(new TargetCardInYourGraveyard(3)), + new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_FOOD) + ); + } + + private ForageCost(final ForageCost cost) { + super(cost); + } + + @Override + public ForageCost copy() { + return new ForageCost(this); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + if (!super.pay(ability, game, source, controllerId, noMana, costToPay)) { + return false; + } + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.FORAGED, source.getSourceId(), source, controllerId)); + return true; + } +} diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index 24ed059b6b2..a02af598411 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -662,6 +662,12 @@ public class GameEvent implements Serializable { playerId owner of the plotted card (the one able to cast the card) */ BECOME_PLOTTED, + /* the player foraged + targetId same as sourceId + sourceId of the ability + playerId player who foraged + */ + FORAGED, //custom events CUSTOM_EVENT }