cleanup The Tomb of Aclazotz without breaking it (#11648)

* add test for Tarrian's Journal // The Tomb of Aclazotz

* re-apply cleanup without breaking this time
This commit is contained in:
xenohedron 2024-01-14 19:55:55 -05:00 committed by GitHub
parent ac53e5b518
commit f0043ee9d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 45 deletions

View file

@ -1,9 +1,5 @@
package mage.cards.t; package mage.cards.t;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import mage.MageIdentifier; import mage.MageIdentifier;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectReference; import mage.MageObjectReference;
@ -19,16 +15,7 @@ import mage.abilities.mana.BlackManaAbility;
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.AsThoughEffectType; import mage.constants.*;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
@ -39,6 +26,10 @@ import mage.util.CardUtil;
import mage.util.SubTypes; import mage.util.SubTypes;
import mage.watchers.Watcher; import mage.watchers.Watcher;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/** /**
* *
* @author jeffwadsworth * @author jeffwadsworth
@ -78,7 +69,7 @@ class TheTombOfAclazotzEffect extends AsThoughEffectImpl {
TheTombOfAclazotzEffect() { TheTombOfAclazotzEffect() {
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
staticText = "You may cast a creature spell from your graveyard this turn. If you do, it enters the battlefield with a finality counter on it and is a Vampire in addition to its other types. (If a creature with a finality counter on it would die, exile it instead.)"; staticText = "You may cast a creature spell from your graveyard this turn. If you do, it enters the battlefield with a finality counter on it and is a Vampire in addition to its other types. <i>(If a creature with a finality counter on it would die, exile it instead.)</i>";
} }
private TheTombOfAclazotzEffect(final TheTombOfAclazotzEffect effect) { private TheTombOfAclazotzEffect(final TheTombOfAclazotzEffect effect) {
@ -119,20 +110,16 @@ class TheTombOfAclazotzEffect extends AsThoughEffectImpl {
return false; return false;
} }
Card card = game.getCard(objectId); Card card = game.getCard(objectId);
if (card != null return card != null
&& affectedAbility instanceof SpellAbility && affectedAbility instanceof SpellAbility
&& card.getOwnerId().equals(playerId) && card.getOwnerId().equals(playerId)
&& card.isCreature(game)) { && card.isCreature(game);
return true;
}
return false;
} }
} }
class TheTombOfAclazotzWatcher extends Watcher { class TheTombOfAclazotzWatcher extends Watcher {
private final Map<MageObjectReference, Map<UUID, Integer>> morMap = new HashMap<>(); private final Map<MageObjectReference, Map<UUID, Integer>> morMap = new HashMap<>();
private MageObjectReference mor;
private UUID playFromAnywhereEffectId; private UUID playFromAnywhereEffectId;
TheTombOfAclazotzWatcher() { TheTombOfAclazotzWatcher() {
@ -146,19 +133,16 @@ class TheTombOfAclazotzWatcher extends Watcher {
Spell target = game.getSpell(event.getTargetId()); Spell target = game.getSpell(event.getTargetId());
Card card = target.getCard(); Card card = target.getCard();
if (card != null) { if (card != null) {
mor = new MageObjectReference(card.getId(), card.getZoneChangeCounter(game), game); game.getState().addEffect(new AddCounterEnteringCreatureEffect(new MageObjectReference(target.getCard(), game),
if (mor != null) { CounterType.FINALITY.createInstance(), Outcome.Neutral),
game.getState().addEffect(new AddCounterEnteringCreatureEffect(new MageObjectReference(target.getCard(), game), target.getSpellAbility());
CounterType.FINALITY.createInstance(), Outcome.Neutral), game.getState().addEffect(new AddSubtypeEnteringCreatureEffect(new MageObjectReference(target.getCard(), game), SubType.VAMPIRE, Outcome.Benefit), card.getSpellAbility());
target.getSpellAbility()); // Rule 728.2 we must insure the effect is used (creature is cast successfully) before discarding the play effect
game.getState().addEffect(new AddSubtypeEnteringCreatureEffect(new MageObjectReference(target.getCard(), game), SubType.VAMPIRE, Outcome.Benefit), card.getSpellAbility()); UUID playEffectId = this.getPlayFromAnywhereEffect();
// Rule 728.2 we must insure the effect is used (creature is cast successfully) before discarding the play effect if (playEffectId != null
UUID playEffectId = this.getPlayFromAnywhereEffect(); && game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, game).listIterator().next().getId().equals(playEffectId)) {
if (playEffectId != null // discard the play effect
&& game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, game).listIterator().next().getId().equals(playEffectId)) { game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, game).listIterator().next().discard();
// discard the play effect
game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, game).listIterator().next().discard();
}
} }
} }
} }
@ -203,7 +187,7 @@ class AddSubtypeEnteringCreatureEffect extends ReplacementEffectImpl {
private final MageObjectReference mor; private final MageObjectReference mor;
private final SubType subType; private final SubType subType;
public AddSubtypeEnteringCreatureEffect(MageObjectReference mor, SubType subType, Outcome outcome) { AddSubtypeEnteringCreatureEffect(MageObjectReference mor, SubType subType, Outcome outcome) {
super(Duration.WhileOnBattlefield, outcome); super(Duration.WhileOnBattlefield, outcome);
this.mor = mor; this.mor = mor;
this.subType = subType; this.subType = subType;
@ -223,11 +207,7 @@ class AddSubtypeEnteringCreatureEffect extends ReplacementEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
MageObject spell = game.getObject(event.getSourceId()); MageObject spell = game.getObject(event.getSourceId());
if (spell != null return spell != null && mor.refersTo(spell, game);
&& mor.refersTo(spell, game)) {
return true;
}
return false;
} }
@Override @Override
@ -237,7 +217,6 @@ class AddSubtypeEnteringCreatureEffect extends ReplacementEffectImpl {
AddCardSubTypeEnteringTargetEffect effect = new AddCardSubTypeEnteringTargetEffect(mor, subType, Duration.WhileOnBattlefield); AddCardSubTypeEnteringTargetEffect effect = new AddCardSubTypeEnteringTargetEffect(mor, subType, Duration.WhileOnBattlefield);
effect.setTargetPointer(new FixedTarget(target, game)); effect.setTargetPointer(new FixedTarget(target, game));
game.addEffect(effect, source); game.addEffect(effect, source);
} }
return false; return false;
} }
@ -251,10 +230,10 @@ class AddSubtypeEnteringCreatureEffect extends ReplacementEffectImpl {
class AddCardSubTypeEnteringTargetEffect extends ContinuousEffectImpl { class AddCardSubTypeEnteringTargetEffect extends ContinuousEffectImpl {
private final SubType addedSubType; private final SubType addedSubType;
private MageObjectReference mor; private final MageObjectReference mor;
private Card card; private Card card;
public AddCardSubTypeEnteringTargetEffect(MageObjectReference mor, SubType addedSubType, Duration duration) { AddCardSubTypeEnteringTargetEffect(MageObjectReference mor, SubType addedSubType, Duration duration) {
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
this.addedSubType = addedSubType; this.addedSubType = addedSubType;
this.mor = mor; this.mor = mor;
@ -264,6 +243,7 @@ class AddCardSubTypeEnteringTargetEffect extends ContinuousEffectImpl {
super(effect); super(effect);
this.addedSubType = effect.addedSubType; this.addedSubType = effect.addedSubType;
this.mor = effect.mor; this.mor = effect.mor;
this.card = effect.card;
} }
@Override @Override
@ -273,8 +253,7 @@ class AddCardSubTypeEnteringTargetEffect extends ContinuousEffectImpl {
if (spell != null) { if (spell != null) {
card = spell.getCard(); card = spell.getCard();
} }
for (Iterator<StackObject> iterator = game.getStack().iterator(); iterator.hasNext();) { for (StackObject stackObject : game.getStack()) {
StackObject stackObject = iterator.next();
if (stackObject instanceof Spell if (stackObject instanceof Spell
&& target != null && target != null
&& target.equals(stackObject) && target.equals(stackObject)

View file

@ -0,0 +1,49 @@
package org.mage.test.cards.single.lci;
import mage.constants.PhaseStep;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author xenohedron
*/
public class TarriansJournalTest extends CardTestPlayerBase {
private static final String tj = "Tarrian's Journal";
private static final String transformAbility = "{2}, {T}, Discard your hand: Transform";
private static final String mayCastAbility = "{T}: You may cast a creature spell from your graveyard this turn. ";
// If you do, it enters the battlefield with a finality counter on it and is a Vampire in addition to its other types.
private static final String edgarMarkov = "Edgar Markov";
// Whenever you cast another Vampire spell, if Edgar Markov is in the command zone or on the battlefield, create a 1/1 black Vampire creature token.
private static final String kraken = "Kraken Hatchling"; // not a vampire
@Test
public void testFunctionality() {
addCard(Zone.BATTLEFIELD, playerA, tj);
addCard(Zone.BATTLEFIELD, playerA, edgarMarkov);
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
addCard(Zone.HAND, playerA, kraken);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, transformAbility);
checkHandCount("Hand discarded", 1, PhaseStep.BEGIN_COMBAT, playerA, 0);
checkGraveyardCount("Kraken discarded", 1, PhaseStep.BEGIN_COMBAT, playerA, kraken, 1);
checkPermanentCount("transformed", 1, PhaseStep.BEGIN_COMBAT, playerA, "The Tomb of Aclazotz", 1);
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, mayCastAbility);
castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, kraken);
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, kraken, 1);
assertPermanentCount(playerA, "Vampire Token", 1);
assertSubtype(kraken, SubType.VAMPIRE);
assertCounterCount(kraken, CounterType.FINALITY, 1);
}
}