[MKM] Implement Case of the Gorgon's Kiss (#11720)

* [MKM] Implement Case of the Gorgon's Kiss

---------

Co-authored-by: Matthew Wilson <matthew_w@vaadin.com>
This commit is contained in:
Matthew Wilson 2024-01-30 08:53:20 +02:00 committed by GitHub
parent e344edcba8
commit 99fa058742
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 192 additions and 1 deletions

View file

@ -0,0 +1,149 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.CaseAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SolvedSourceCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect;
import mage.abilities.hint.common.CaseSolvedHint;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.WasDealtDamageThisTurnPredicate;
import mage.game.Game;
import mage.game.permanent.token.TokenImpl;
import mage.target.TargetPermanent;
import mage.watchers.common.CardsPutIntoGraveyardWatcher;
/**
* Case of the Gorgon's Kiss {B}
* Enchantment - Case
* When this Case enters the battlefield, destroy up to one target creature that was dealt damage this turn.
* To solve -- Three or more creature cards were put into graveyards from anywhere this turn.
* Solved -- This Case is a 4/4 Gorgon creature with deathtouch and lifelink in addition to its other types.
*
* @author DominionSpy
*/
public final class CaseOfTheGorgonsKiss extends CardImpl {
private static final FilterPermanent filter
= new FilterCreaturePermanent("creature that was dealt damage this turn");
static {
filter.add(WasDealtDamageThisTurnPredicate.instance);
}
public CaseOfTheGorgonsKiss(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}");
this.subtype.add(SubType.CASE);
// When this Case enters the battlefield, destroy up to one target creature that was dealt damage this turn.
Ability initialAbility = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect())
.setTriggerPhrase("When this Case enters the battlefield, ");
initialAbility.addTarget(new TargetPermanent(0, 1, filter));
// To solve -- Three or more creature cards were put into graveyards from anywhere this turn.
Condition toSolveCondition = new CaseOfTheGorgonsKissCondition();
// Solved -- This Case is a 4/4 Gorgon creature with deathtouch and lifelink in addition to its other types.
Ability solvedAbility = new SimpleStaticAbility(new ConditionalContinuousEffect(
new BecomesCreatureSourceEffect(new CaseOfTheGorgonsKissToken(),
CardType.ENCHANTMENT, Duration.WhileOnBattlefield),
SolvedSourceCondition.SOLVED, "")
.setText("This Case is a 4/4 Gorgon creature with deathtouch and lifelink in addition to its other types."));
this.addAbility(new CaseAbility(initialAbility, toSolveCondition, solvedAbility)
.addHint(new CaseOfTheGorgonsKissHint(toSolveCondition)),
new CardsPutIntoGraveyardWatcher());
}
private CaseOfTheGorgonsKiss(final CaseOfTheGorgonsKiss card) {
super(card);
}
@Override
public CaseOfTheGorgonsKiss copy() {
return new CaseOfTheGorgonsKiss(this);
}
}
class CaseOfTheGorgonsKissCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class);
return watcher != null &&
watcher.getCardsPutIntoGraveyardFromAnywhere(game)
.stream()
.filter(MageObject::isCreature)
.count() >= 3;
}
@Override
public String toString() {
return "Three or more creature cards were put into graveyards from anywhere this turn";
}
}
class CaseOfTheGorgonsKissHint extends CaseSolvedHint {
CaseOfTheGorgonsKissHint(Condition condition) {
super(condition);
}
private CaseOfTheGorgonsKissHint(final CaseOfTheGorgonsKissHint hint) {
super(hint);
}
@Override
public CaseOfTheGorgonsKissHint copy() {
return new CaseOfTheGorgonsKissHint(this);
}
@Override
public String getConditionText(Game game, Ability ability) {
int creatures = (int)game.getState()
.getWatcher(CardsPutIntoGraveyardWatcher.class)
.getCardsPutIntoGraveyardFromAnywhere(game)
.stream()
.filter(MageObject::isCreature)
.count();
return "Creatures put into graveyards: " + creatures + " (need 3).";
}
}
class CaseOfTheGorgonsKissToken extends TokenImpl {
CaseOfTheGorgonsKissToken() {
super("", "4/4 Gorgon creature with deathtouch and lifelink");
this.cardType.add(CardType.CREATURE);
this.subtype.add(SubType.GORGON);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
this.addAbility(DeathtouchAbility.getInstance());
this.addAbility(LifelinkAbility.getInstance());
}
private CaseOfTheGorgonsKissToken(final CaseOfTheGorgonsKissToken token) {
super(token);
}
@Override
public CaseOfTheGorgonsKissToken copy() {
return new CaseOfTheGorgonsKissToken(this);
}
}

View file

@ -50,6 +50,7 @@ public final class MurdersAtKarlovManor extends ExpansionSet {
cards.add(new SetCardInfo("Case of the Burning Masks", 113, Rarity.UNCOMMON, mage.cards.c.CaseOfTheBurningMasks.class)); cards.add(new SetCardInfo("Case of the Burning Masks", 113, Rarity.UNCOMMON, mage.cards.c.CaseOfTheBurningMasks.class));
cards.add(new SetCardInfo("Case of the Crimson Pulse", 114, Rarity.RARE, mage.cards.c.CaseOfTheCrimsonPulse.class)); cards.add(new SetCardInfo("Case of the Crimson Pulse", 114, Rarity.RARE, mage.cards.c.CaseOfTheCrimsonPulse.class));
cards.add(new SetCardInfo("Case of the Filched Falcon", 44, Rarity.UNCOMMON, mage.cards.c.CaseOfTheFilchedFalcon.class)); cards.add(new SetCardInfo("Case of the Filched Falcon", 44, Rarity.UNCOMMON, mage.cards.c.CaseOfTheFilchedFalcon.class));
cards.add(new SetCardInfo("Case of the Gorgon's Kiss", 79, Rarity.UNCOMMON, mage.cards.c.CaseOfTheGorgonsKiss.class));
cards.add(new SetCardInfo("Case of the Locked Hothouse", 155, Rarity.RARE, mage.cards.c.CaseOfTheLockedHothouse.class)); cards.add(new SetCardInfo("Case of the Locked Hothouse", 155, Rarity.RARE, mage.cards.c.CaseOfTheLockedHothouse.class));
cards.add(new SetCardInfo("Caught Red-Handed", 115, Rarity.UNCOMMON, mage.cards.c.CaughtRedHanded.class)); cards.add(new SetCardInfo("Caught Red-Handed", 115, Rarity.UNCOMMON, mage.cards.c.CaughtRedHanded.class));
cards.add(new SetCardInfo("Cease // Desist", 246, Rarity.UNCOMMON, mage.cards.c.CeaseDesist.class)); cards.add(new SetCardInfo("Cease // Desist", 246, Rarity.UNCOMMON, mage.cards.c.CeaseDesist.class));

View file

@ -1,6 +1,8 @@
package org.mage.test.cards.enchantments; package org.mage.test.cards.enchantments;
import mage.constants.CardType;
import mage.constants.PhaseStep; import mage.constants.PhaseStep;
import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import org.junit.Test; import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase; import org.mage.test.serverside.base.CardTestPlayerBase;
@ -75,6 +77,45 @@ public class CaseTest extends CardTestPlayerBase {
assertHandCount(playerA, 2); assertHandCount(playerA, 2);
} }
// CardsPutIntoGraveyardWatcher was updated to work correctly with cards
// going to the graveyard from other zones than the battlefield. This test
// checks this by cycling a card from the hand.
@Test
public void test_CaseOfTheGorgonsKiss() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2 + 1 + 2);
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears");
addCard(Zone.HAND, playerA, "Walking Ballista");
addCard(Zone.HAND, playerA, "Case of the Gorgon's Kiss");
addCard(Zone.HAND, playerA, "Angel of the God-Pharaoh");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Walking Ballista");
setChoice(playerA, "X=1");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
// Walking Ballista goes to the graveyard from the battlefield
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Remove", "Grizzly Bears");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Case of the Gorgon's Kiss");
// Grizzly Bears goes to the graveyard from the battlefield
addTarget(playerA, "Grizzly Bears"); // Case of the Gorgon's Kiss ETB target
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
// Angel of the God-Pharaoh goes to the graveyard from playerA's hand
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling");
checkStackObject("case is solved", 1, PhaseStep.END_TURN, playerA, "<i>To solve", 1);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Case of the Gorgon's Kiss", 1);
assertType("Case of the Gorgon's Kiss", CardType.CREATURE, true);
assertSubtype("Case of the Gorgon's Kiss", SubType.GORGON);
assertBasePowerToughness(playerA, "Case of the Gorgon's Kiss", 4, 4);
}
@Test @Test
public void test_CaseOfTheLockedHothouse() { public void test_CaseOfTheLockedHothouse() {
addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);

View file

@ -49,7 +49,7 @@ public class CardsPutIntoGraveyardWatcher extends Watcher {
if (((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) { if (((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) {
cardsPutIntoGraveyardFromBattlefield.add(new MageObjectReference(((ZoneChangeEvent) event).getTarget(), game, 1)); cardsPutIntoGraveyardFromBattlefield.add(new MageObjectReference(((ZoneChangeEvent) event).getTarget(), game, 1));
} else { } else {
cardsPutIntoGraveyardFromEverywhereElse.add(new MageObjectReference(((ZoneChangeEvent) event).getTarget(), game, 1)); cardsPutIntoGraveyardFromEverywhereElse.add(new MageObjectReference(game.getCard(event.getTargetId()), game, 0));
} }
} }