From 831313bcb9807af86e97325318546586c5e244d3 Mon Sep 17 00:00:00 2001 From: PurpleCrowbar <26198472+PurpleCrowbar@users.noreply.github.com> Date: Mon, 29 Jul 2024 21:45:54 +0100 Subject: [PATCH] [BLB] Implement Vren, the Relentless (#12615) --- .../src/mage/cards/v/VrenTheRelentless.java | 120 ++++++++++++++++++ Mage.Sets/src/mage/sets/Bloomburrow.java | 2 + .../game/permanent/token/VrenRatToken.java | 49 +++++++ 3 files changed, 171 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/v/VrenTheRelentless.java create mode 100644 Mage/src/main/java/mage/game/permanent/token/VrenRatToken.java diff --git a/Mage.Sets/src/mage/cards/v/VrenTheRelentless.java b/Mage.Sets/src/mage/cards/v/VrenTheRelentless.java new file mode 100644 index 00000000000..0577b98e14c --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VrenTheRelentless.java @@ -0,0 +1,120 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.replacement.CreaturesAreExiledOnDeathReplacementEffect; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.WardAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.token.VrenRatToken; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author PurpleCrowbar + */ +public final class VrenTheRelentless extends CardImpl { + + public VrenTheRelentless(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}"); + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.RAT, SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Ward {2} + this.addAbility(new WardAbility(new GenericManaCost(2), false)); + + // If a creature an opponent controls would die, exile it instead. + this.addAbility(new SimpleStaticAbility( + new CreaturesAreExiledOnDeathReplacementEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE) + )); + + // At the beginning of each end step, create X 1/1 black Rat creature tokens with "This creature gets +1/+1 for each + // other Rat you control," where X is the number of creatures your opponents controlled that were exiled this turn. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new CreateTokenEffect(new VrenRatToken(), VrenTheRelentlessCount.instance) + .setText("create X 1/1 black Rat creature tokens with \"This creature gets +1/+1 for each other Rat you " + + "control,\" where X is the number of creatures your opponents controlled that were exiled this turn"), + TargetController.ANY, false + ).addHint(new ValueHint("Creatures exiled under opponents' control this turn", VrenTheRelentlessCount.instance)), new VrenTheRelentlessWatcher()); + } + + private VrenTheRelentless(final VrenTheRelentless card) { + super(card); + } + + @Override + public VrenTheRelentless copy() { + return new VrenTheRelentless(this); + } +} + +enum VrenTheRelentlessCount implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + VrenTheRelentlessWatcher watcher = game.getState().getWatcher(VrenTheRelentlessWatcher.class); + return watcher == null ? 0 : watcher.getCount(sourceAbility.getControllerId()); + } + + @Override + public VrenTheRelentlessCount copy() { + return instance; + } + + @Override + public String getMessage() { + return ""; + } +} + +class VrenTheRelentlessWatcher extends Watcher { + + private final Map playerMap = new HashMap<>(); + + VrenTheRelentlessWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.ZONE_CHANGE) { + return; + } + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if ((zEvent.getToZone() == Zone.EXILED && zEvent.getFromZone() == Zone.BATTLEFIELD) && zEvent.getTarget().isCreature(game)) { + playerMap.compute(zEvent.getTarget().getControllerId(), CardUtil::setOrIncrementValue); + } + } + + @Override + public void reset() { + playerMap.clear(); + super.reset(); + } + + int getCount(UUID playerId) { + return playerMap.entrySet().stream() + .filter(entry -> !entry.getKey().equals(playerId)) + .mapToInt(Map.Entry::getValue) + .sum(); + } +} diff --git a/Mage.Sets/src/mage/sets/Bloomburrow.java b/Mage.Sets/src/mage/sets/Bloomburrow.java index 66701a382b2..cdc534e4dce 100644 --- a/Mage.Sets/src/mage/sets/Bloomburrow.java +++ b/Mage.Sets/src/mage/sets/Bloomburrow.java @@ -248,6 +248,8 @@ public final class Bloomburrow extends ExpansionSet { cards.add(new SetCardInfo("Valley Rotcaller", 119, Rarity.RARE, mage.cards.v.ValleyRotcaller.class)); cards.add(new SetCardInfo("Veteran Guardmouse", 237, Rarity.COMMON, mage.cards.v.VeteranGuardmouse.class)); cards.add(new SetCardInfo("Vinereap Mentor", 238, Rarity.UNCOMMON, mage.cards.v.VinereapMentor.class)); + cards.add(new SetCardInfo("Vren, the Relentless", 239, Rarity.RARE, mage.cards.v.VrenTheRelentless.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vren, the Relentless", 354, Rarity.RARE, mage.cards.v.VrenTheRelentless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wandertale Mentor", 240, Rarity.UNCOMMON, mage.cards.w.WandertaleMentor.class)); cards.add(new SetCardInfo("War Squeak", 160, Rarity.COMMON, mage.cards.w.WarSqueak.class)); cards.add(new SetCardInfo("Warren Elder", 37, Rarity.COMMON, mage.cards.w.WarrenElder.class)); diff --git a/Mage/src/main/java/mage/game/permanent/token/VrenRatToken.java b/Mage/src/main/java/mage/game/permanent/token/VrenRatToken.java new file mode 100644 index 00000000000..5876cdc1430 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/VrenRatToken.java @@ -0,0 +1,49 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +/** + * @author PurpleCrowbar + */ +public final class VrenRatToken extends TokenImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("other Rat you control"); + + static { + filter.add(SubType.RAT.getPredicate()); + filter.add(AnotherPredicate.instance); + } + + public VrenRatToken() { + super("Rat Token", "1/1 black Rat creature tokens with \"This creature gets +1/+1 for each other Rat you control\""); + cardType.add(CardType.CREATURE); + color.setBlack(true); + subtype.add(SubType.RAT); + power = new MageInt(1); + toughness = new MageInt(1); + + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new BoostSourceEffect(new PermanentsOnBattlefieldCount(filter), + new PermanentsOnBattlefieldCount(filter), Duration.WhileOnBattlefield + ) + )); + } + + private VrenRatToken(final VrenRatToken token) { + super(token); + } + + @Override + public VrenRatToken copy() { + return new VrenRatToken(this); + } +}