From 5e67314c961d186b6b2da0f987cfe035c9923064 Mon Sep 17 00:00:00 2001 From: Daniel Bomar Date: Thu, 21 Oct 2021 15:26:01 -0500 Subject: [PATCH 1/2] [AFC] Implemented Death Tyrant --- Mage.Sets/src/mage/cards/d/DeathTyrant.java | 104 ++++++++++++++++++ .../mage/sets/ForgottenRealmsCommander.java | 1 + .../mage/game/permanent/PermanentImpl.java | 2 +- 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/cards/d/DeathTyrant.java diff --git a/Mage.Sets/src/mage/cards/d/DeathTyrant.java b/Mage.Sets/src/mage/cards/d/DeathTyrant.java new file mode 100644 index 0000000000..779d7d3ae4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeathTyrant.java @@ -0,0 +1,104 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; +import mage.constants.SubType; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ZombieToken; + +/** + * + * @author weirddan455 + */ +public final class DeathTyrant extends CardImpl { + + public DeathTyrant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.BEHOLDER); + this.subtype.add(SubType.SKELETON); + this.power = new MageInt(4); + this.toughness = new MageInt(6); + + // Menace + this.addAbility(new MenaceAbility()); + + // Negative Energy Cone — Whenever an attacking creature you control or a blocking creature an opponent controls dies, create a 2/2 black Zombie creature token. + this.addAbility(new DeathTyrantTriggeredAbility().withFlavorWord("Negative Energy Cone")); + + // {5}{B}: Return Death Tyrant from your graveyard to the battlefield tapped. + this.addAbility(new SimpleActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true), + new ManaCostsImpl<>("{5}{B}") + )); + } + + private DeathTyrant(final DeathTyrant card) { + super(card); + } + + @Override + public DeathTyrant copy() { + return new DeathTyrant(this); + } +} + +class DeathTyrantTriggeredAbility extends TriggeredAbilityImpl { + + public DeathTyrantTriggeredAbility() { + super(Zone.ALL, new CreateTokenEffect(new ZombieToken())); + } + + private DeathTyrantTriggeredAbility(final DeathTyrantTriggeredAbility ability) { + super(ability); + } + + @Override + public DeathTyrantTriggeredAbility copy() { + return new DeathTyrantTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.isDiesEvent()) { + Permanent permanent = zEvent.getTarget(); + if (permanent != null && permanent.isCreature(game)) { + if (permanent.isControlledBy(controllerId) && permanent.isAttacking()) { + return true; + } + return game.getOpponents(controllerId).contains(permanent.getControllerId()) && permanent.getBlocking() > 0; + } + } + return false; + } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game); + } + + @Override + public String getTriggerPhrase() { + return "Whenever an attacking creature you control or a blocking creature an opponent controls dies, "; + } +} diff --git a/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java b/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java index df24b0f0bb..37b5b0b584 100644 --- a/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java +++ b/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java @@ -79,6 +79,7 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Dark-Dweller Oracle", 119, Rarity.RARE, mage.cards.d.DarkDwellerOracle.class)); cards.add(new SetCardInfo("Darkwater Catacombs", 232, Rarity.RARE, mage.cards.d.DarkwaterCatacombs.class)); cards.add(new SetCardInfo("Dead Man's Chest", 97, Rarity.RARE, mage.cards.d.DeadMansChest.class)); + cards.add(new SetCardInfo("Death Tyrant", 23, Rarity.RARE, mage.cards.d.DeathTyrant.class)); cards.add(new SetCardInfo("Decree of Savagery", 156, Rarity.RARE, mage.cards.d.DecreeOfSavagery.class)); cards.add(new SetCardInfo("Demanding Dragon", 120, Rarity.RARE, mage.cards.d.DemandingDragon.class)); cards.add(new SetCardInfo("Desert", 233, Rarity.UNCOMMON, mage.cards.d.Desert.class)); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 78dcabfa8b..c3ab738341 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1723,7 +1723,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { Zone fromZone = game.getState().getZone(objectId); Player controller = game.getPlayer(controllerId); if (controller != null) { - ZoneChangeEvent event = new ZoneChangeEvent(this, source, controllerId, fromZone, toZone, appliedEffects); + ZoneChangeEvent event = new ZoneChangeEvent(this.copy(), source, controllerId, fromZone, toZone, appliedEffects); ZoneChangeInfo zoneChangeInfo; if (toZone == Zone.LIBRARY) { zoneChangeInfo = new ZoneChangeInfo.Library(event, flag /* put on top */); From 27d4fb13c3c5b0c5523eac9ee297cce8c978c35a Mon Sep 17 00:00:00 2001 From: Daniel Bomar Date: Thu, 21 Oct 2021 20:24:51 -0500 Subject: [PATCH 2/2] Fixed combat information not being preserved in LKI and added unit test --- Mage.Sets/src/mage/cards/d/DeathTyrant.java | 2 +- .../cards/single/afc/DeathTyrantTest.java | 45 +++++++++++++++++++ .../src/main/java/mage/game/ZonesHandler.java | 4 +- .../mage/game/permanent/PermanentImpl.java | 2 +- 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/afc/DeathTyrantTest.java diff --git a/Mage.Sets/src/mage/cards/d/DeathTyrant.java b/Mage.Sets/src/mage/cards/d/DeathTyrant.java index 779d7d3ae4..f9d4210b7f 100644 --- a/Mage.Sets/src/mage/cards/d/DeathTyrant.java +++ b/Mage.Sets/src/mage/cards/d/DeathTyrant.java @@ -81,7 +81,7 @@ class DeathTyrantTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; if (zEvent.isDiesEvent()) { - Permanent permanent = zEvent.getTarget(); + Permanent permanent = game.getPermanentOrLKIBattlefield(zEvent.getTargetId()); if (permanent != null && permanent.isCreature(game)) { if (permanent.isControlledBy(controllerId) && permanent.isAttacking()) { return true; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/DeathTyrantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/DeathTyrantTest.java new file mode 100644 index 0000000000..fb5528f602 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/DeathTyrantTest.java @@ -0,0 +1,45 @@ +package org.mage.test.cards.single.afc; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class DeathTyrantTest extends CardTestPlayerBase { + + @Test + public void attackerDies() { + addCard(Zone.BATTLEFIELD, playerA, "Death Tyrant", 1); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerB, "Hill Giant", 1); + + attack(1, playerA, "Grizzly Bears"); + block(1, playerB, "Hill Giant", "Grizzly Bears"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Grizzly Bears", 1); + assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Death Tyrant", 1); + assertPermanentCount(playerB, "Hill Giant", 1); + } + + @Test + public void blockerDies() { + addCard(Zone.BATTLEFIELD, playerA, "Death Tyrant", 1); + addCard(Zone.BATTLEFIELD, playerA, "Hill Giant", 1); + addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 1); + + attack(1, playerA, "Hill Giant"); + block(1, playerB, "Grizzly Bears", "Hill Giant"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerB, "Grizzly Bears", 1); + assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Death Tyrant", 1); + assertPermanentCount(playerA, "Hill Giant", 1); + } +} diff --git a/Mage/src/main/java/mage/game/ZonesHandler.java b/Mage/src/main/java/mage/game/ZonesHandler.java index 9f10fcdbcb..3620372800 100644 --- a/Mage/src/main/java/mage/game/ZonesHandler.java +++ b/Mage/src/main/java/mage/game/ZonesHandler.java @@ -382,8 +382,8 @@ public final class ZonesHandler { } else if (event.getTarget() != null) { card.setFaceDown(info.faceDown, game); Permanent target = event.getTarget(); - success = game.getPlayer(target.getControllerId()).removeFromBattlefield(target, source, game) - && target.removeFromZone(game, fromZone, source); + success = target.removeFromZone(game, fromZone, source) + && game.getPlayer(target.getControllerId()).removeFromBattlefield(target, source, game); } else { card.setFaceDown(info.faceDown, game); success = card.removeFromZone(game, fromZone, source); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index c3ab738341..78dcabfa8b 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1723,7 +1723,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { Zone fromZone = game.getState().getZone(objectId); Player controller = game.getPlayer(controllerId); if (controller != null) { - ZoneChangeEvent event = new ZoneChangeEvent(this.copy(), source, controllerId, fromZone, toZone, appliedEffects); + ZoneChangeEvent event = new ZoneChangeEvent(this, source, controllerId, fromZone, toZone, appliedEffects); ZoneChangeInfo zoneChangeInfo; if (toZone == Zone.LIBRARY) { zoneChangeInfo = new ZoneChangeInfo.Library(event, flag /* put on top */);