[UNF] Implement Comet, Stellar Pup (#10925)

This commit is contained in:
Susucre 2023-09-15 23:55:11 +02:00 committed by GitHub
parent 410eeda709
commit f4b0b83612
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 441 additions and 2 deletions

View file

@ -0,0 +1,189 @@
package mage.cards.c;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.SquirrelToken;
import mage.game.permanent.token.Token;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.common.TargetCreatureOrPlayer;
import mage.target.targetpointer.FixedTarget;
import mage.target.targetpointer.FixedTargets;
import java.util.UUID;
/**
* @author Susucr
*/
public final class CometStellarPup extends CardImpl {
public CometStellarPup(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.COMET);
this.setStartingLoyalty(5);
// 0: Roll a six-sided die.
// 1 or 2 -- [+2] , then create two 1/1 green Squirrel creature tokens. They gain haste until end of turn.
// 3 -- [-1], then return a card with mana value 2 or less from your graveyard to your hand.
// 4 or 5 -- Comet, Stellar Pup deals damage equal to the number of loyalty counters on him to a creature or player, then [-2].
// 6 -- [+1], and you may activate Comet, Stellar Pup's loyalty ability two more times this turn.
this.addAbility(new LoyaltyAbility(new CometStellarPupAbility(), 0));
}
private CometStellarPup(final CometStellarPup card) {
super(card);
}
@Override
public CometStellarPup copy() {
return new CometStellarPup(this);
}
}
class CometStellarPupAbility extends OneShotEffect {
private static final FilterCard filterCard =
new FilterCard("card with mana value 2 or less from your graveyard");
static {
filterCard.add(new ManaValuePredicate(ComparisonType.OR_LESS, 2));
}
CometStellarPupAbility() {
super(Outcome.Benefit);
staticText = "Roll a six-sided die.<br>"
+ "1 or 2 &mdash; [+2] , then create two 1/1 green Squirrel creature tokens. They gain haste until end of turn.<br>"
+ "3 &mdash; [-1], then return a card with mana value 2 or less from your graveyard to your hand.<br>"
+ "4 or 5 &mdash; {this} deals damage equal to the number of loyalty counters on him to a creature or player, then [-2].<br>"
+ "6 &mdash; [+1], and you may activate Comet, Stellar Pup's loyalty ability two more times this turn.";
}
private CometStellarPupAbility(final CometStellarPupAbility effect) {
super(effect);
}
@Override
public CometStellarPupAbility copy() {
return new CometStellarPupAbility(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
int result = player.rollDice(outcome, source, game, 6);
if (result == 1 || result == 2) {
// [+2]
new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(2))
.apply(game, source);
// Create two 1/1 green Squirrel creature tokens.
Token token = new SquirrelToken();
token.putOntoBattlefield(2, game, source);
// They gain haste until end of turn.
game.addEffect(new GainAbilityTargetEffect(
HasteAbility.getInstance(), Duration.EndOfTurn
).setTargetPointer(new FixedTargets(token, game)), source);
} else if (result == 3) {
// [-1]
new RemoveCounterSourceEffect(CounterType.LOYALTY.createInstance(1))
.apply(game, source);
// return a card with mana value 2 or less from your graveyard to your hand.
TargetCard target = new TargetCardInYourGraveyard(filterCard);
target.withNotTarget(true);
if (!target.canChoose(source.getControllerId(), source, game)) {
return true;
}
player.choose(outcome, target, source, game);
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
player.moveCards(card, Zone.HAND, source, game);
}
} else if (result == 4 || result == 5) {
// Comet, Stellar Pup deals damage equal to the number of loyalty counters on him to a creature or player
TargetCreatureOrPlayer target = new TargetCreatureOrPlayer();
target.withNotTarget(true);
if (!target.canChoose(source.getControllerId(), source, game)) {
return true;
}
player.choose(Outcome.Damage, target, source, game);
new DamageTargetEffect(new CountersSourceCount(CounterType.LOYALTY))
.setTargetPointer(new FixedTarget(target.getFirstTarget()))
.apply(game, source);
// [2]
new RemoveCounterSourceEffect(CounterType.LOYALTY.createInstance(2))
.apply(game, source);
} else if (result == 6) {
//[+1]
new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(1))
.apply(game, source);
// You may activate Comet, Stellar Pups loyalty ability two more times this turn.
Permanent comet = source.getSourcePermanentIfItStillExists(game);
if (comet != null) {
game.addEffect(
new CometStellarPupContinuousEffect(new MageObjectReference(comet, game)),
source
);
}
}
return true;
}
}
class CometStellarPupContinuousEffect extends ContinuousEffectImpl {
private final MageObjectReference cometMOR;
CometStellarPupContinuousEffect(MageObjectReference cometMOR) {
super(Duration.EndOfTurn, Layer.RulesEffects, SubLayer.NA, Outcome.Benefit);
this.cometMOR = cometMOR;
}
private CometStellarPupContinuousEffect(final CometStellarPupContinuousEffect effect) {
super(effect);
this.cometMOR = effect.cometMOR;
}
@Override
public CometStellarPupContinuousEffect copy() {
return new CometStellarPupContinuousEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent comet = cometMOR.getPermanent(game);
if (comet != null) {
comet.incrementLoyaltyActivationsAvailable();
comet.incrementLoyaltyActivationsAvailable();
return true;
}
return false;
}
}

View file

@ -29,6 +29,7 @@ public final class Unfinity extends ExpansionSet {
cards.add(new SetCardInfo("Circuits Act", 103, Rarity.COMMON, mage.cards.c.CircuitsAct.class));
cards.add(new SetCardInfo("Clown Car", 186, Rarity.RARE, mage.cards.c.ClownCar.class));
cards.add(new SetCardInfo("Clowning Around", 6, Rarity.COMMON, mage.cards.c.ClowningAround.class));
cards.add(new SetCardInfo("Comet, Stellar Pup", 166, Rarity.MYTHIC, mage.cards.c.CometStellarPup.class));
cards.add(new SetCardInfo("Dissatisfied Customer", 72, Rarity.COMMON, mage.cards.d.DissatisfiedCustomer.class));
cards.add(new SetCardInfo("Embiggen", 137, Rarity.COMMON, mage.cards.e.Embiggen.class));
cards.add(new SetCardInfo("Forest", 239, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.UST_FULL_ART_BASIC, true)));//there are multipiles so use the true boolean here for useVariousArt

View file

@ -0,0 +1,240 @@
package org.mage.test.cards.single.unf;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Susucr
*/
public class CometStellarPupTest extends CardTestPlayerBase {
/**
* Comet, Stellar Pup
* {2}{R}{W}
* Legendary Planeswalker Comet
*
* 0: Roll a six-sided die.
* 1 or 2 [+2], then create two 1/1 green Squirrel creature tokens. They gain haste until end of turn.
* 3 [1], then return a card with mana value 2 or less from your graveyard to your hand.
* 4 or 5 Comet, Stellar Pup deals damage equal to the number of loyalty counters on him to a creature or player, then [2].
* 6 [+1], and you may activate Comet, Stellar Pups loyalty ability two more times this turn.
*
* Loyalty: 5
*/
private final static String comet = "Comet, Stellar Pup";
private final static String cometAbility = "0: Roll a six-sided die."
+ "<br>1 or 2 &mdash; [+2] , then create two 1/1 green Squirrel creature tokens. They gain haste until end of turn."
+ "<br>3 &mdash; [-1], then return a card with mana value 2 or less from your graveyard to your hand."
+ "<br>4 or 5 &mdash; {this} deals damage equal to the number of loyalty counters on him to a creature or player, then [-2]."
+ "<br>6 &mdash; [+1], and you may activate Comet, Stellar Pup's loyalty ability two more times this turn.";
@Test
public void testRoll1() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, comet);
setDieRollResult(playerA, 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
checkPlayableAbility("can't activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, false);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Squirrel Token", 2);
assertCounterCount(playerA, comet, CounterType.LOYALTY, 5 + 2);
}
@Test
public void testRoll2() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, comet);
setDieRollResult(playerA, 2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
checkPlayableAbility("can't activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, false);
attack(1, playerA, "Squirrel Token", playerB);
attack(1, playerA, "Squirrel Token", playerB);
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertPermanentCount(playerA, "Squirrel Token", 2);
assertLife(playerB, 20 - 2);
assertCounterCount(playerA, comet, CounterType.LOYALTY, 5 + 2);
}
@Test
public void testRoll3() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, comet);
addCard(Zone.GRAVEYARD, playerA, "Memnite");
setDieRollResult(playerA, 3);
setChoice(playerA, "Memnite");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
checkPlayableAbility("can't activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, false);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Squirrel Token", 0);
assertHandCount(playerA, "Memnite", 1);
assertLife(playerB, 20);
assertCounterCount(playerA, comet, CounterType.LOYALTY, 5 - 1);
}
// TODO: Currently it is not possible to choose a player of a TargetCreatureOrPlayer
// the 4 roll is tested in testRoll6 on a permanent.
//@Test
public void testRoll4() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, comet);
setDieRollResult(playerA, 4);
setChoice(playerA, "PlayerB");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
checkPlayableAbility("can't activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, false);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Squirrel Token", 0);
assertLife(playerB, 20 - 5);
assertCounterCount(playerA, comet, CounterType.LOYALTY, 5 - 2);
}
@Test
public void testRoll5() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, comet);
addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon"); // 9/9
setDieRollResult(playerA, 5);
setChoice(playerA, "Ancient Brontodon");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
checkPlayableAbility("can't activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, false);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Squirrel Token", 0);
assertLife(playerB, 20);
assertDamageReceived(playerB, "Ancient Brontodon", 5);
assertCounterCount(playerA, comet, CounterType.LOYALTY, 5 - 2);
}
@Test
public void testRoll6() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, comet);
addCard(Zone.BATTLEFIELD, playerB, "Ghalta, Primal Hunger"); // 12/12
setDieRollResult(playerA, 6);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("can activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, true);
checkPermanentCounters("6 loyalty", 1, PhaseStep.PRECOMBAT_MAIN, playerA, comet, CounterType.LOYALTY, 6);
setDieRollResult(playerA, 6);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("can activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, true);
checkPermanentCounters("7 loyalty", 1, PhaseStep.PRECOMBAT_MAIN, playerA, comet, CounterType.LOYALTY, 7);
setDieRollResult(playerA, 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("can activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, true);
checkPermanentCounters("9 loyalty", 1, PhaseStep.PRECOMBAT_MAIN, playerA, comet, CounterType.LOYALTY, 9);
setDieRollResult(playerA, 2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("can activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, true);
checkPermanentCounters("9 loyalty", 1, PhaseStep.PRECOMBAT_MAIN, playerA, comet, CounterType.LOYALTY, 11);
setDieRollResult(playerA, 4);
setChoice(playerA, "Ghalta, Primal Hunger");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("can't activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, false);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Squirrel Token", 4);
assertDamageReceived(playerB, "Ghalta, Primal Hunger", 11);
assertCounterCount(playerA, comet, CounterType.LOYALTY, 9);
}
@Test
public void testRoll6WithCarthTheLion() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, comet);
// Planeswalkers' loyalty abilities you activate cost an additional [+1] to activate.
addCard(Zone.BATTLEFIELD, playerA, "Carth the Lion");
setDieRollResult(playerA, 6);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("can activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, true);
checkPermanentCounters("7 loyalty", 1, PhaseStep.PRECOMBAT_MAIN, playerA, comet, CounterType.LOYALTY, 7);
setDieRollResult(playerA, 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("can activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, true);
checkPermanentCounters("10 loyalty", 1, PhaseStep.PRECOMBAT_MAIN, playerA, comet, CounterType.LOYALTY, 10);
setDieRollResult(playerA, 2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("can activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, false);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Squirrel Token", 4);
assertCounterCount(playerA, comet, CounterType.LOYALTY, 13);
}
@Test
public void testRoll6AgainstEidolonOfObstruction() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, comet);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
// Loyalty abilities of planeswalkers your opponents control cost {1} more to activate.
addCard(Zone.BATTLEFIELD, playerB, "Eidolon of Obstruction");
setDieRollResult(playerA, 6);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("can activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, true);
checkPermanentCounters("7 loyalty", 1, PhaseStep.PRECOMBAT_MAIN, playerA, comet, CounterType.LOYALTY, 6);
setDieRollResult(playerA, 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("can activate more", 1, PhaseStep.PRECOMBAT_MAIN, playerA, cometAbility, false); // no mana to pay the tax one more time.
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Squirrel Token", 2);
assertTappedCount("Plains", true, 2);
assertCounterCount(playerA, comet, CounterType.LOYALTY, 8);
}
}

View file

@ -2196,11 +2196,15 @@ public class TestPlayer implements Player {
List<UUID> usedTargets = new ArrayList<>();
// TODO: Allow to choose a player with TargetPermanentOrPlayer
if ((target.getOriginalTarget() instanceof TargetPermanent)
|| (target.getOriginalTarget() instanceof TargetPermanentOrPlayer)) { // player target not implemted yet
|| (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) // player target not implemented yet
|| (target.getOriginalTarget() instanceof TargetPermanentOrPlayer)) { // player target not implemented yet
FilterPermanent filterPermanent;
if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) {
filterPermanent = ((TargetPermanentOrPlayer) target.getOriginalTarget()).getFilterPermanent();
} else if (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) {
filterPermanent = ((TargetCreatureOrPlayer) target.getOriginalTarget()).getFilterCreature();
} else {
filterPermanent = ((TargetPermanent) target.getOriginalTarget()).getFilter();
}
@ -2379,7 +2383,7 @@ public class TestPlayer implements Player {
}
private void checkTargetDefinitionMarksSupport(Target needTarget, String targetDefinition, String canSupportChars) {
// fail on wrong chars in definition ` ` ` ` ` ` ` ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````
// fail on wrong chars in definition
// ^ - multiple targets
// [] - special option like [no copy]
// = - target type like targetPlayer=PlayerA

View file

@ -437,6 +437,7 @@ public enum SubType {
BOLAS("Bolas", SubTypeSet.PlaneswalkerType),
CALIX("Calix", SubTypeSet.PlaneswalkerType),
CHANDRA("Chandra", SubTypeSet.PlaneswalkerType),
COMET("Comet", SubTypeSet.PlaneswalkerType),
DACK("Dack", SubTypeSet.PlaneswalkerType),
DAKKON("Dakkon", SubTypeSet.PlaneswalkerType),
DARETTI("Daretti", SubTypeSet.PlaneswalkerType),

View file

@ -5,6 +5,7 @@ import mage.abilities.Ability;
import mage.constants.Zone;
import mage.filter.Filter;
import mage.filter.common.FilterCreatureOrPlayer;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
@ -217,4 +218,7 @@ public class TargetCreatureOrPlayer extends TargetImpl {
return new TargetCreatureOrPlayer(this);
}
public FilterCreaturePermanent getFilterCreature() {
return filter.getCreatureFilter().copy();
}
}