implement [PIP] Craig Boone, Novac Guard

This commit is contained in:
Susucre 2024-05-01 16:26:23 +02:00
parent eb8e2fa5b9
commit 24dbba7b43
3 changed files with 260 additions and 0 deletions

View file

@ -0,0 +1,114 @@
package mage.cards.c;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
import mage.abilities.costs.common.PutCountersSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.DoWhenCostPaid;
import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.keyword.ReachAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
* @author Susucr
*/
public final class CraigBooneNovacGuard extends CardImpl {
public CraigBooneNovacGuard(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SOLDIER);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// Reach
this.addAbility(ReachAbility.getInstance());
// Lifelink
this.addAbility(LifelinkAbility.getInstance());
// One for My Baby -- Whenever you attack with two or more creatures, put two quest counters on Craig Boone, Novac Guard. When you do, Craig Boone deals damage equal to the number of quest counters on it to up to one target creature unless that creature's controller has Craig Boone deal that much damage to them.
ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility(new CraigBooneNovacGuardEffect(), false);
reflexive.addTarget(new TargetCreaturePermanent(0, 1));
this.addAbility(new AttacksWithCreaturesTriggeredAbility(
new DoWhenCostPaid(
reflexive,
new PutCountersSourceCost(CounterType.QUEST.createInstance(2)),
"", false
), 2
).withFlavorWord("One for my Baby"));
}
private CraigBooneNovacGuard(final CraigBooneNovacGuard card) {
super(card);
}
@Override
public CraigBooneNovacGuard copy() {
return new CraigBooneNovacGuard(this);
}
}
class CraigBooneNovacGuardEffect extends OneShotEffect {
CraigBooneNovacGuardEffect() {
super(Outcome.Damage);
staticText = "{this} deals damage equal to the number of quest counters on it "
+ "to up to one target creature unless that creature's controller "
+ "has {this} deal that much damage to them";
}
private CraigBooneNovacGuardEffect(final CraigBooneNovacGuardEffect effect) {
super(effect);
}
@Override
public CraigBooneNovacGuardEffect copy() {
return new CraigBooneNovacGuardEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
Permanent sourcePermanent = source.getSourcePermanentOrLKI(game);
if (sourcePermanent == null || targetPermanent == null) {
return false;
}
int amount = sourcePermanent.getCounters(game).getCount(CounterType.QUEST);
Player playerChoosing = game.getPlayer(targetPermanent.getControllerId());
if (playerChoosing != null && playerChoosing.chooseUse(
Outcome.Neutral,
"have " + amount + " damage be dealt to you instead of " + targetPermanent.getLogName() + "?",
source,
game)
) {
new DamageTargetEffect(amount)
.setTargetPointer(new FixedTarget(playerChoosing.getId()))
.apply(game, source);
return true;
}
new DamageTargetEffect(amount)
.setTargetPointer(getTargetPointer().copy())
.apply(game, source);
return true;
}
}

View file

@ -92,6 +92,7 @@ public final class Fallout extends ExpansionSet {
cards.add(new SetCardInfo("Contagion Clasp", 229, Rarity.UNCOMMON, mage.cards.c.ContagionClasp.class));
cards.add(new SetCardInfo("Contaminated Drink", 99, Rarity.UNCOMMON, mage.cards.c.ContaminatedDrink.class));
cards.add(new SetCardInfo("Corpsejack Menace", 214, Rarity.UNCOMMON, mage.cards.c.CorpsejackMenace.class));
cards.add(new SetCardInfo("Craig Boone, Novac Guard", 100, Rarity.UNCOMMON, mage.cards.c.CraigBooneNovacGuard.class));
cards.add(new SetCardInfo("Crimson Caravaneer", 56, Rarity.UNCOMMON, mage.cards.c.CrimsonCaravaneer.class));
cards.add(new SetCardInfo("Crucible of Worlds", 357, Rarity.MYTHIC, mage.cards.c.CrucibleOfWorlds.class));
cards.add(new SetCardInfo("Crush Contraband", 158, Rarity.UNCOMMON, mage.cards.c.CrushContraband.class));

View file

@ -0,0 +1,145 @@
package org.mage.test.cards.single.pip;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.player.TestPlayer;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Susucr
*/
public class CraigBooneNovacGuardTest extends CardTestPlayerBase {
/**
* {@link mage.cards.c.CraigBooneNovacGuard Craig Boone, Novac Guard} {1}{R}{W}
* Legendary Creature Human Soldier
* Reach, lifelink
* One for My Baby Whenever you attack with two or more creatures, put two quest counters on Craig Boone, Novac Guard. When you do, Craig Boone deals damage equal to the number of quest counters on it to up to one target creature unless that creatures controller has Craig Boone deal that much damage to them.
* 3/3
*/
private static final String craig = "Craig Boone, Novac Guard";
@Test
public void test_Trigger_Simple_DamageCreature() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, craig);
addCard(Zone.BATTLEFIELD, playerA, "Memnite");
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard");
addCard(Zone.BATTLEFIELD, playerB, "Indomitable Ancients");
attack(1, playerA, "Memnite", playerB);
attack(1, playerA, "Elite Vanguard", playerB);
addTarget(playerA, "Indomitable Ancients");
setChoice(playerB, false); // choose to not have damage dealt to them
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertDamageReceived(playerB, "Indomitable Ancients", 2);
assertLife(playerA, 20 + 2);
assertLife(playerB, 20 - 3);
}
@Test
public void test_Trigger_Simple_DamagePlayer() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, craig);
addCard(Zone.BATTLEFIELD, playerA, "Memnite");
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard");
addCard(Zone.BATTLEFIELD, playerB, "Indomitable Ancients");
attack(1, playerA, "Memnite", playerB);
attack(1, playerA, "Elite Vanguard", playerB);
addTarget(playerA, "Indomitable Ancients");
setChoice(playerB, true); // choose to not have damage dealt to them
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertDamageReceived(playerB, "Indomitable Ancients", 0);
assertLife(playerA, 20 + 2);
assertLife(playerB, 20 - 3 - 2);
}
@Test
public void test_Trigger_Simple_NoTarget_NoDamage() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, craig);
addCard(Zone.BATTLEFIELD, playerA, "Memnite");
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard");
addCard(Zone.BATTLEFIELD, playerB, "Indomitable Ancients");
attack(1, playerA, "Memnite", playerB);
attack(1, playerA, "Elite Vanguard", playerB);
addTarget(playerA, TestPlayer.TARGET_SKIP);
// No one has a choice to make
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertDamageReceived(playerB, "Indomitable Ancients", 0);
assertLife(playerA, 20);
assertLife(playerB, 20 - 3);
}
@Test
public void test_Trigger_DiesBeforeResolve() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, craig);
addCard(Zone.BATTLEFIELD, playerA, "Memnite");
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard");
addCard(Zone.BATTLEFIELD, playerB, "Indomitable Ancients");
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
addCard(Zone.HAND, playerB, "Doom Blade");
attack(1, playerA, "Memnite", playerB);
attack(1, playerA, "Elite Vanguard", playerB);
castSpell(1, PhaseStep.DECLARE_ATTACKERS, playerB, "Doom Blade", craig);
// The attack trigger is there, but since counters can not be put on Craig, no Reflexive Trigger
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertDamageReceived(playerB, "Indomitable Ancients", 0);
assertLife(playerA, 20);
assertLife(playerB, 20 - 3);
assertGraveyardCount(playerA, craig, 1);
}
@Test
public void test_Trigger_DiesBeforeReflexiveResolve() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, craig);
addCard(Zone.BATTLEFIELD, playerA, "Memnite");
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard");
addCard(Zone.BATTLEFIELD, playerB, "Indomitable Ancients");
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
addCard(Zone.HAND, playerB, "Doom Blade");
attack(1, playerA, "Memnite", playerB);
attack(1, playerA, "Elite Vanguard", playerB);
waitStackResolved(1, PhaseStep.DECLARE_ATTACKERS, playerB, true);
addTarget(playerA, "Indomitable Ancients");
setChoice(playerB, true); // choose to not have damage dealt to them
castSpell(1, PhaseStep.DECLARE_ATTACKERS, playerB, "Doom Blade", craig);
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertDamageReceived(playerB, "Indomitable Ancients", 0);
assertLife(playerA, 20 + 2);
assertLife(playerB, 20 - 3 - 2); // Still took 2 Damage when the reflexive trigger
assertGraveyardCount(playerA, craig, 1);
}
}