From b316a32ab77a99058da4aef82d25a0b0a7f8fe39 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 14 Jul 2021 17:45:46 -0400 Subject: [PATCH] [AFR] Implemented The Tarrasque --- Mage.Sets/src/mage/cards/t/TheTarrasque.java | 122 ++++++++++++++++++ .../sets/AdventuresInTheForgottenRealms.java | 1 + .../cards/single/afr/TheTarrasqueTest.java | 118 +++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TheTarrasque.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/afr/TheTarrasqueTest.java diff --git a/Mage.Sets/src/mage/cards/t/TheTarrasque.java b/Mage.Sets/src/mage/cards/t/TheTarrasque.java new file mode 100644 index 0000000000..affb969578 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheTarrasque.java @@ -0,0 +1,122 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.FightTargetSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.WardAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.target.TargetPermanent; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheTarrasque extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature defending player controls"); + + static { + filter.add(DefendingPlayerControlsPredicate.instance); + } + + public TheTarrasque(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{G}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DINOSAUR); + this.power = new MageInt(10); + this.toughness = new MageInt(10); + + // The Tarrasque has haste and ward {10} as long as it was cast. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield + ), TheTarrasqueCondition.instance, "{this} has haste" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + new WardAbility(new GenericManaCost(10)), Duration.WhileOnBattlefield + ), TheTarrasqueCondition.instance, "and ward {10} as long as it was cast" + )); + this.addAbility(ability, new TheTarrasqueWatcher()); + + // Whenever The Tarrasque attacks, it fights target creature defending player controls. + ability = new AttacksTriggeredAbility(new FightTargetSourceEffect() + .setText("it fights target creature defending player controls")); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private TheTarrasque(final TheTarrasque card) { + super(card); + } + + @Override + public TheTarrasque copy() { + return new TheTarrasque(this); + } +} + +enum TheTarrasqueCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return TheTarrasqueWatcher.checkSource(game, source); + } +} + +class TheTarrasqueWatcher extends Watcher { + + private final Set cast = new HashSet<>(); + + TheTarrasqueWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + switch (event.getType()) { + case SPELL_CAST: + Spell spell = game.getSpell(event.getTargetId()); + if (spell != null) { + cast.add(new MageObjectReference(spell.getCard(), game, 1)); + } + return; + case BEGINNING_PHASE_PRE: + if (game.getTurnNum() == 1) { + cast.clear(); + } + } + } + + static boolean checkSource(Game game, Ability source) { + TheTarrasqueWatcher watcher = game.getState().getWatcher(TheTarrasqueWatcher.class); + return watcher != null + && watcher + .cast + .stream() + .anyMatch(mor -> mor.refersTo(source.getSourcePermanentIfItStillExists(game), game)); + } +} diff --git a/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java b/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java index ebbd558bec..1ca62b09d2 100644 --- a/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java +++ b/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java @@ -225,6 +225,7 @@ public final class AdventuresInTheForgottenRealms extends ExpansionSet { cards.add(new SetCardInfo("The Book of Exalted Deeds", 4, Rarity.MYTHIC, mage.cards.t.TheBookOfExaltedDeeds.class)); cards.add(new SetCardInfo("The Book of Vile Darkness", 91, Rarity.MYTHIC, mage.cards.t.TheBookOfVileDarkness.class)); cards.add(new SetCardInfo("The Deck of Many Things", 241, Rarity.MYTHIC, mage.cards.t.TheDeckOfManyThings.class)); + cards.add(new SetCardInfo("The Tarrasque", 207, Rarity.MYTHIC, mage.cards.t.TheTarrasque.class)); cards.add(new SetCardInfo("Thieves' Tools", 122, Rarity.COMMON, mage.cards.t.ThievesTools.class)); cards.add(new SetCardInfo("Tiamat", 235, Rarity.MYTHIC, mage.cards.t.Tiamat.class)); cards.add(new SetCardInfo("Tiger-Tribe Hunter", 163, Rarity.UNCOMMON, mage.cards.t.TigerTribeHunter.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/afr/TheTarrasqueTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/afr/TheTarrasqueTest.java new file mode 100644 index 0000000000..d681d8c690 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/afr/TheTarrasqueTest.java @@ -0,0 +1,118 @@ +package org.mage.test.cards.single.afr; + +import mage.abilities.keyword.HasteAbility; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class TheTarrasqueTest extends CardTestPlayerBase { + + private static final String tarrasque = "The Tarrasque"; + private static final String sakashima = "Sakashima the Impostor"; + + @Test + public void testCast() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 9); + addCard(Zone.HAND, playerA, tarrasque); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, tarrasque); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), true); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), true); + + setStopAt(3, PhaseStep.END_TURN); + execute(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), true); + + setStopAt(4, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), true); + } + + @Test + public void testNotCast() { + addCard(Zone.BATTLEFIELD, playerA, "Forest"); + addCard(Zone.BATTLEFIELD, playerA, "Elvish Piper"); + addCard(Zone.HAND, playerA, tarrasque); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{G},"); + setChoice(playerA, "Yes"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), false); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), false); + + setStopAt(3, PhaseStep.END_TURN); + execute(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), false); + + setStopAt(4, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), false); + } + + @Test + public void testSakashima() { + addCard(Zone.BATTLEFIELD, playerA, "Forest"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + addCard(Zone.BATTLEFIELD, playerA, "Elvish Piper"); + addCard(Zone.HAND, playerA, tarrasque); + addCard(Zone.HAND, playerA, sakashima); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{G},"); + setChoice(playerA, "Yes"); + setChoice(playerA, tarrasque); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sakashima); + setChoice(playerA, "Yes"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPowerToughness(playerA, sakashima, 10, 10); + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), false); + assertAbility(playerA, sakashima, HasteAbility.getInstance(), true); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), false); + assertAbility(playerA, sakashima, HasteAbility.getInstance(), true); + + setStopAt(3, PhaseStep.END_TURN); + execute(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), false); + assertAbility(playerA, sakashima, HasteAbility.getInstance(), true); + + setStopAt(4, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertAbility(playerA, tarrasque, HasteAbility.getInstance(), false); + assertAbility(playerA, sakashima, HasteAbility.getInstance(), true); + } +}