mirror of
https://github.com/correl/mage.git
synced 2024-11-14 19:19:32 +00:00
Fixed Yixlid Jailer interaction with cards moving to graveyard (#8402)
* Fixed Yixlid Jailer interaction with cards moving to graveyard (fixes #8311) * Yixlid Jailer - Revert previous workaround and add rules modifying effect
This commit is contained in:
parent
b63623b40f
commit
83d37a7f35
2 changed files with 239 additions and 35 deletions
|
@ -4,12 +4,15 @@ import java.util.UUID;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.common.ZoneChangeTriggeredAbility;
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
|
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,6 +31,7 @@ public final class YixlidJailer extends CardImpl {
|
||||||
|
|
||||||
// Cards in graveyards lose all abilities.
|
// Cards in graveyards lose all abilities.
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new YixlidJailerEffect()));
|
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new YixlidJailerEffect()));
|
||||||
|
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new YixlidJailerRulesEffect()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private YixlidJailer(final YixlidJailer card) {
|
private YixlidJailer(final YixlidJailer card) {
|
||||||
|
@ -38,54 +42,85 @@ public final class YixlidJailer extends CardImpl {
|
||||||
public YixlidJailer copy() {
|
public YixlidJailer copy() {
|
||||||
return new YixlidJailer(this);
|
return new YixlidJailer(this);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class YixlidJailerEffect extends ContinuousEffectImpl {
|
class YixlidJailerEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
YixlidJailerEffect() {
|
public YixlidJailerEffect() {
|
||||||
super(Duration.WhileOnBattlefield, Outcome.LoseAbility);
|
super(Duration.WhileOnBattlefield, Outcome.LoseAbility);
|
||||||
staticText = "Cards in graveyards lose all abilities.";
|
staticText = "Cards in graveyards lose all abilities.";
|
||||||
|
|
||||||
this.dependencyTypes.add(DependencyType.AddingAbility); // Necrotic Ooze
|
this.dependencyTypes.add(DependencyType.AddingAbility); // Necrotic Ooze
|
||||||
}
|
}
|
||||||
|
|
||||||
YixlidJailerEffect(final YixlidJailerEffect effect) {
|
private YixlidJailerEffect(final YixlidJailerEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public YixlidJailerEffect copy() {
|
public YixlidJailerEffect copy() {
|
||||||
return new YixlidJailerEffect(this);
|
return new YixlidJailerEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
||||||
if (layer == Layer.AbilityAddingRemovingEffects_6) {
|
if (layer == Layer.AbilityAddingRemovingEffects_6) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
|
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
|
||||||
Player player = game.getPlayer(playerId);
|
Player player = game.getPlayer(playerId);
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
for (Card card : player.getGraveyard().getCards(game)) {
|
for (Card card : player.getGraveyard().getCards(game)) {
|
||||||
if (card != null) {
|
if (card != null) {
|
||||||
card.looseAllAbilities(game);
|
card.looseAllAbilities(game);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasLayer(Layer layer) {
|
public boolean hasLayer(Layer layer) {
|
||||||
return layer == Layer.AbilityAddingRemovingEffects_6;
|
return layer == Layer.AbilityAddingRemovingEffects_6;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class YixlidJailerRulesEffect extends ContinuousRuleModifyingEffectImpl {
|
||||||
|
|
||||||
|
public YixlidJailerRulesEffect() {
|
||||||
|
super(Duration.WhileOnBattlefield, Outcome.Detriment, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private YixlidJailerRulesEffect(final YixlidJailerRulesEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public YixlidJailerRulesEffect copy() {
|
||||||
|
return new YixlidJailerRulesEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checksEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
|
Object targetAbility = getValue("targetAbility");
|
||||||
|
if (targetAbility instanceof ZoneChangeTriggeredAbility) {
|
||||||
|
ZoneChangeTriggeredAbility zoneAbility = (ZoneChangeTriggeredAbility) targetAbility;
|
||||||
|
return zoneAbility.getFromZone() != Zone.BATTLEFIELD && zoneAbility.getToZone() == Zone.GRAVEYARD;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
package org.mage.test.cards.single.fut;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
public class YixlidJailerTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
// Rulings on Yixlid Jailer
|
||||||
|
// 1. If an ability triggers when the object that has it is put into a graveyard from the battlefield, that ability triggers from the battlefield and isn’t affected by Yixlid Jailer. (2021-03-19)
|
||||||
|
// 2. If an ability triggers when the object that has it is put into a graveyard from anywhere other than the battlefield, such as Krosan Tusker or Narcomoeba, that ability triggers from the graveyard.
|
||||||
|
// Yixlid Jailer stops those abilities from triggering at all. This includes abilities that trigger when a card is put into a graveyard “from anywhere,” even if that card was on the battlefield. (2021-03-19)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void narcomoebaBaseCase() {
|
||||||
|
skipInitShuffling();
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Narcomoeba", 1);
|
||||||
|
addCard(Zone.HAND, playerA, "Thought Scour", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thought Scour");
|
||||||
|
addTarget(playerA, playerA);
|
||||||
|
setChoice(playerA, true); // Use Narcomoeba's ability
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertPermanentCount(playerA, "Narcomoeba", 1);
|
||||||
|
assertGraveyardCount(playerA, "Thought Scour", 1);
|
||||||
|
assertGraveyardCount(playerA, "Narcomoeba", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emrakulBaseCase() {
|
||||||
|
skipInitShuffling();
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Emrakul, the Aeons Torn", 1);
|
||||||
|
addCard(Zone.HAND, playerA, "Thought Scour", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thought Scour");
|
||||||
|
addTarget(playerA, playerA);
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertGraveyardCount(playerA, 0); // Emrakul should shuffle graveyard into library
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emrakulWrathBaseCase() {
|
||||||
|
skipInitShuffling();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Emrakul, the Aeons Torn", 1);
|
||||||
|
addCard(Zone.HAND, playerA, "Wrath of God", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wrath of God");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertGraveyardCount(playerA, 0); // Emrakul should shuffle graveyard into library
|
||||||
|
assertPermanentCount(playerA, "Emrakul, the Aeons Torn", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void narcomoebaWithJailer() {
|
||||||
|
skipInitShuffling();
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Narcomoeba", 1);
|
||||||
|
addCard(Zone.HAND, playerA, "Thought Scour", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Yixlid Jailer", 1);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thought Scour");
|
||||||
|
addTarget(playerA, playerA);
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertPermanentCount(playerA, "Narcomoeba", 0);
|
||||||
|
assertGraveyardCount(playerA, "Thought Scour", 1);
|
||||||
|
assertGraveyardCount(playerA, "Narcomoeba", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emrakulWithJailer() {
|
||||||
|
skipInitShuffling();
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Emrakul, the Aeons Torn", 1);
|
||||||
|
addCard(Zone.HAND, playerA, "Thought Scour", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Yixlid Jailer", 1);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thought Scour");
|
||||||
|
addTarget(playerA, playerA);
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertGraveyardCount(playerA, "Emrakul, the Aeons Torn", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emrakulWrathWithJailer() {
|
||||||
|
skipInitShuffling();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Emrakul, the Aeons Torn", 1);
|
||||||
|
addCard(Zone.HAND, playerA, "Wrath of God", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Yixlid Jailer", 1);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wrath of God");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertGraveyardCount(playerA, "Emrakul, the Aeons Torn", 1); // Emrakul should not trigger even if removed from the battlefield
|
||||||
|
assertPermanentCount(playerA, "Emrakul, the Aeons Torn", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void midnightReaperWithJailer() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Midnight Reaper", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Yixlid Jailer", 1);
|
||||||
|
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt");
|
||||||
|
addTarget(playerA, "Midnight Reaper");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertGraveyardCount(playerA, "Midnight Reaper", 1);
|
||||||
|
assertPermanentCount(playerB, "Yixlid Jailer", 1);
|
||||||
|
assertLife(playerA, 19); // Midnight Reaper should still trigger
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void midnightReaperWrathWithJailer() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Midnight Reaper", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Yixlid Jailer", 1);
|
||||||
|
addCard(Zone.HAND, playerA, "Wrath of God", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wrath of God");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertGraveyardCount(playerA, "Midnight Reaper", 1);
|
||||||
|
assertGraveyardCount(playerB, "Yixlid Jailer", 1);
|
||||||
|
assertLife(playerA, 19); // Midnight Reaper should still trigger
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue