diff --git a/Mage.Sets/src/mage/cards/o/OcelotPride.java b/Mage.Sets/src/mage/cards/o/OcelotPride.java new file mode 100644 index 00000000000..8a9e11ba00f --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OcelotPride.java @@ -0,0 +1,128 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CitysBlessingCondition; +import mage.abilities.condition.common.YouGainedLifeCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.keyword.AscendAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.permanent.EnteredThisTurnPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.CatToken3; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.common.PlayerGainedLifeWatcher; + +import java.util.List; +import java.util.UUID; + +/** + * @author Susucr"é"é + */ +public final class OcelotPride extends CardImpl { + + private static final Condition condition = new YouGainedLifeCondition(ComparisonType.MORE_THAN, 0); + private static final Hint hint = new ConditionHint(condition, "You gained life this turn"); + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("other creature you control named Charmed Stray"); + + static { + filter.add(new NamePredicate("Charmed Stray")); + filter.add(AnotherPredicate.instance); + } + + public OcelotPride(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Ascend + this.addAbility(new AscendAbility()); + + // At the beginning of your end step, if you gained life this turn, create a 1/1 white Cat creature token. Then if you have the city's blessing, for each token you control that entered the battlefield this turn, create a token that's a copy of it. + Ability ability = new BeginningOfEndStepTriggeredAbility( + new CreateTokenEffect(new CatToken3()), + TargetController.YOU, condition, false + ); + ability.addEffect(new ConditionalOneShotEffect( + new OcelotPrideEffect(), + CitysBlessingCondition.instance + ).concatBy("Then")); + ability.addHint(hint); + this.addAbility(ability, new PlayerGainedLifeWatcher()); + } + + private OcelotPride(final OcelotPride card) { + super(card); + } + + @Override + public OcelotPride copy() { + return new OcelotPride(this); + } +} + +class OcelotPrideEffect extends OneShotEffect { + + private static final FilterControlledPermanent filter = + new FilterControlledPermanent("token you control that entered the battlefield this turn"); + + static { + filter.add(TokenPredicate.TRUE); + filter.add(EnteredThisTurnPredicate.instance); + } + + OcelotPrideEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "for each token you control that entered the battlefield this turn, create a token that's a copy of it"; + } + + private OcelotPrideEffect(final OcelotPrideEffect effect) { + super(effect); + } + + @Override + public OcelotPrideEffect copy() { + return new OcelotPrideEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + boolean result = false; + List tokensToCopy = + game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); + for (Permanent toCopy : tokensToCopy) { + result |= new CreateTokenCopyTargetEffect() + .setTargetPointer(new FixedTarget(toCopy, game)) + .apply(game, source); + } + return result; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/ModernHorizons3.java b/Mage.Sets/src/mage/sets/ModernHorizons3.java index b6934a19c56..0a385ba376c 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons3.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons3.java @@ -111,6 +111,7 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Null Elemental Blast", 12, Rarity.UNCOMMON, mage.cards.n.NullElementalBlast.class)); cards.add(new SetCardInfo("Nulldrifter", 13, Rarity.RARE, mage.cards.n.Nulldrifter.class)); cards.add(new SetCardInfo("Nyxborn Hydra", 164, Rarity.COMMON, mage.cards.n.NyxbornHydra.class)); + cards.add(new SetCardInfo("Ocelot Pride", 38, Rarity.MYTHIC, mage.cards.o.OcelotPride.class)); cards.add(new SetCardInfo("Ophiomancer", 276, Rarity.RARE, mage.cards.o.Ophiomancer.class)); cards.add(new SetCardInfo("Orim's Chant", 265, Rarity.RARE, mage.cards.o.OrimsChant.class)); cards.add(new SetCardInfo("Path of Annihilation", 165, Rarity.UNCOMMON, mage.cards.p.PathOfAnnihilation.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/OcelotPrideTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/OcelotPrideTest.java new file mode 100644 index 00000000000..42a91af5252 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/OcelotPrideTest.java @@ -0,0 +1,95 @@ +package org.mage.test.cards.single.mh3; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author Susucr + */ +public class OcelotPrideTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.o.OcelotPride Ocelot Pride} {W} + * Creature — Cat + * First strike, lifelink + * Ascend + * At the beginning of your end step, if you gained life this turn, create a 1/1 white Cat creature token. Then if you have the city's blessing, for each token you control that entered the battlefield this turn, create a token that's a copy of it. + */ + private static final String ocelot = "Ocelot Pride"; + + @Test + public void test_No_Trigger() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, ocelot); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, 1); + } + + @Test + public void test_Trigger_NoCitysBlessing() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, ocelot); + addCard(Zone.HAND, playerA, "Hard Evidence"); + addCard(Zone.BATTLEFIELD, playerA, "Island"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hard Evidence"); + + attack(1, playerA, ocelot, playerB); + + checkPermanentCount("1: before trigger, 1 Crab", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Crab Token", 1); + checkPermanentCount("1: before trigger, 0 Cat", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cat Token", 0); + checkPermanentCount("1: before trigger, 1 Clue", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Clue Token", 1); + + attack(3, playerA, ocelot, playerB); + + checkPermanentCount("3: before trigger, 1 Crab", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Crab Token", 1); + checkPermanentCount("3: before trigger, 1 Cat", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cat Token", 1); + checkPermanentCount("3: before trigger, 1 Clue", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Clue Token", 1); + + setStopAt(4, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, 4 + 1 + 1); + assertPermanentCount(playerA, "Crab Token", 1); + assertPermanentCount(playerA, "Cat Token", 2); // 1 per trigger + assertPermanentCount(playerA, "Clue Token", 1); + } + + @Test + public void test_Trigger_CitysBlessing() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, ocelot); + addCard(Zone.HAND, playerA, "Hard Evidence"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hard Evidence"); + + attack(1, playerA, ocelot, playerB); + + checkPermanentCount("1: before trigger, 1 Crab", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Crab Token", 1); + checkPermanentCount("1: before trigger, 0 Cat", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cat Token", 0); + checkPermanentCount("1: before trigger, 1 Clue", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Clue Token", 1); + + attack(3, playerA, ocelot, playerB); + + checkPermanentCount("3: before trigger, 2 Crab", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Crab Token", 2); + checkPermanentCount("3: before trigger, 2 Cat", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cat Token", 2); + checkPermanentCount("3: before trigger, 2 Clue", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Clue Token", 2); + + setStopAt(4, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, (6 + 1) + 2 + 4 + 2); + assertPermanentCount(playerA, "Crab Token", 1 + 1); // 1 by Hard Evidence, 1 on trigger + assertPermanentCount(playerA, "Cat Token", 4); // 2 per trigger + assertPermanentCount(playerA, "Clue Token", 1 + 1); // 1 by Hard Evidence, 1 on trigger + } +}