implement [PIP] White Glove Gourmand

This commit is contained in:
Susucre 2024-05-01 14:33:08 +02:00
parent 3c609904e2
commit 2e7c2dbaae
3 changed files with 230 additions and 0 deletions

View file

@ -0,0 +1,119 @@
package mage.cards.w;
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.Hint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.FoodToken;
import mage.game.permanent.token.HumanSoldierToken;
import mage.watchers.Watcher;
import java.util.*;
/**
* @author Susucr
*/
public final class WhiteGloveGourmand extends CardImpl {
public WhiteGloveGourmand(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.NOBLE);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// When White Glove Gourmand enters the battlefield, create two 1/1 white Human Soldier creature tokens.
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new HumanSoldierToken(), 2)));
// At the beginning of your end step, if another Human died under your control this turn, create a Food token.
this.addAbility(new ConditionalInterveningIfTriggeredAbility(
new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new FoodToken()), TargetController.YOU, false),
WhiteGloveGourmandCondition.instance,
"At the beginning of your end step, if another Human died under your control this turn, create a Food token."
).addHint(WhiteGloveGourmandCondition.hint), new WhiteGloveGourmandWatcher());
}
private WhiteGloveGourmand(final WhiteGloveGourmand card) {
super(card);
}
@Override
public WhiteGloveGourmand copy() {
return new WhiteGloveGourmand(this);
}
}
enum WhiteGloveGourmandCondition implements Condition {
instance;
static final Hint hint = new ConditionHint(instance);
@Override
public boolean apply(Game game, Ability source) {
MageObjectReference mor = new MageObjectReference(source.getSourceObject(game), game);
return WhiteGloveGourmandWatcher.checkCondition(source.getControllerId(), mor, game);
}
@Override
public String toString() {
return "another Human died under your control this turn";
}
}
class WhiteGloveGourmandWatcher extends Watcher {
// player -> set of Human mor that dies under you control this turn.
private final Map<UUID, Set<MageObjectReference>> diedThisTurn = new HashMap<>();
WhiteGloveGourmandWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.ZONE_CHANGE) {
return;
}
ZoneChangeEvent zce = (ZoneChangeEvent) event;
if (!zce.isDiesEvent()) {
return;
}
Permanent permanent = zce.getTarget();
if (permanent != null && permanent.hasSubtype(SubType.HUMAN, game)) {
diedThisTurn.computeIfAbsent(event.getPlayerId(), k -> new HashSet<>());
diedThisTurn.get(event.getPlayerId()).add(new MageObjectReference(permanent, game));
}
}
@Override
public void reset() {
super.reset();
diedThisTurn.clear();
}
static boolean checkCondition(UUID playerId, MageObjectReference morSource, Game game) {
WhiteGloveGourmandWatcher watcher = game.getState().getWatcher(WhiteGloveGourmandWatcher.class);
return watcher != null && watcher
.diedThisTurn
.getOrDefault(playerId, Collections.emptySet())
.stream()
.anyMatch(mor -> !mor.equals(morSource));
}
}

View file

@ -362,6 +362,7 @@ public final class Fallout extends ExpansionSet {
cards.add(new SetCardInfo("Well Rested", 88, Rarity.UNCOMMON, mage.cards.w.WellRested.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Well Rested", 88, Rarity.UNCOMMON, mage.cards.w.WellRested.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Well Rested", 616, Rarity.UNCOMMON, mage.cards.w.WellRested.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Well Rested", 616, Rarity.UNCOMMON, mage.cards.w.WellRested.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Whirler Rogue", 181, Rarity.UNCOMMON, mage.cards.w.WhirlerRogue.class)); cards.add(new SetCardInfo("Whirler Rogue", 181, Rarity.UNCOMMON, mage.cards.w.WhirlerRogue.class));
cards.add(new SetCardInfo("White Glove Gourmand", 124, Rarity.UNCOMMON, mage.cards.w.WhiteGloveGourmand.class));
cards.add(new SetCardInfo("Wild Growth", 208, Rarity.COMMON, mage.cards.w.WildGrowth.class)); cards.add(new SetCardInfo("Wild Growth", 208, Rarity.COMMON, mage.cards.w.WildGrowth.class));
cards.add(new SetCardInfo("Windbrisk Heights", 315, Rarity.RARE, mage.cards.w.WindbriskHeights.class)); cards.add(new SetCardInfo("Windbrisk Heights", 315, Rarity.RARE, mage.cards.w.WindbriskHeights.class));
cards.add(new SetCardInfo("Winding Constrictor", 223, Rarity.UNCOMMON, mage.cards.w.WindingConstrictor.class)); cards.add(new SetCardInfo("Winding Constrictor", 223, Rarity.UNCOMMON, mage.cards.w.WindingConstrictor.class));

View file

@ -0,0 +1,110 @@
package org.mage.test.cards.single.pip;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Susucr
*/
public class WhiteGloveGourmandTest extends CardTestPlayerBase {
/**
* {@link mage.cards.w.WhiteGloveGourmand White Glove Gourmand} {2}{W}{B}
* Creature Human Noble
* When White Glove Gourmand enters the battlefield, create two 1/1 white Human Soldier creature tokens.
* At the beginning of your end step, if another Human died under your control this turn, create a Food token.
* 2/2
*/
private static final String gourmand = "White Glove Gourmand";
@Test
public void test_Trigger_Simple() {
setStrictChooseMode(true);
addCard(Zone.HAND, playerA, gourmand);
addCard(Zone.HAND, playerA, "Shrivel"); // All creatures get -1/-1 until end of turn.
addCard(Zone.BATTLEFIELD, playerA, "Scrubland", 6);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, gourmand, true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shrivel");
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, "Food Token", 1);
}
@Test
public void test_Trigger_Changeling() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Avian Changeling");
addCard(Zone.BATTLEFIELD, playerA, "Scrubland", 6);
addCard(Zone.HAND, playerA, gourmand);
addCard(Zone.HAND, playerA, "Doom Blade");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Doom Blade", "Avian Changeling", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, gourmand);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, "Food Token", 1);
}
@Test
public void test_NoTrigger_OpponentHuman_Die() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerB, "Avian Changeling");
addCard(Zone.BATTLEFIELD, playerA, "Scrubland", 6);
addCard(Zone.HAND, playerA, gourmand);
addCard(Zone.HAND, playerA, "Doom Blade");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Doom Blade", "Avian Changeling", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, gourmand);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, "Food Token", 0);
}
@Test
public void test_NoTrigger_NonHuman() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Goblin Piker");
addCard(Zone.BATTLEFIELD, playerA, "Scrubland", 6);
addCard(Zone.HAND, playerA, gourmand);
addCard(Zone.HAND, playerA, "Doom Blade");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Doom Blade", "Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, gourmand);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, "Food Token", 0);
}
@Test
public void test_SelfDie_And_Reanimate() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
addCard(Zone.BATTLEFIELD, playerA, gourmand);
addCard(Zone.HAND, playerA, "Go for the Throat");
addCard(Zone.HAND, playerA, "Reanimate");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Go for the Throat", gourmand, true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", gourmand);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, "Food Token", 1);
}
}