mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
refactor: fixed dies events support in single cards (part 8, related to #13089, continue from #13088);
This commit is contained in:
parent
a970dc46c7
commit
b855434a24
7 changed files with 67 additions and 5 deletions
|
|
@ -64,6 +64,7 @@ class CuratorsWardTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
public CuratorsWardTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(2), false);
|
||||
setLeavesTheBattlefieldTrigger(true);
|
||||
}
|
||||
|
||||
private CuratorsWardTriggeredAbility(final CuratorsWardTriggeredAbility ability) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ public final class GracefulAntelope extends CardImpl {
|
|||
|
||||
// Plainswalk
|
||||
this.addAbility(new PlainswalkAbility());
|
||||
|
||||
// Whenever Graceful Antelope deals combat damage to a player, you may have target land become a Plains until Graceful Antelope leaves the battlefield.
|
||||
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new BecomesBasicLandTargetEffect(Duration.UntilSourceLeavesBattlefield, SubType.PLAINS), true);
|
||||
ability.addTarget(new TargetLandPermanent());
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ public final class Portcullis extends CardImpl {
|
|||
public Portcullis(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
|
||||
|
||||
// Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature.
|
||||
// Return that card to the battlefield under its owner's control when Portcullis leaves the battlefield.
|
||||
// Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature. Return that card to the battlefield under its owner's control when Portcullis leaves the battlefield.
|
||||
String rule = "Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature.";
|
||||
String rule2 = " Return that card to the battlefield under its owner's control when {this} leaves the battlefield.";
|
||||
TriggeredAbility ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new PortcullisExileEffect(),
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ class SludgeStriderTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public SludgeStriderTriggeredAbility() {
|
||||
// setting optional = false because DoIfCostPaid already asks the player
|
||||
super(Zone.BATTLEFIELD, new DoIfCostPaid(new SludgeStriderEffect(), new GenericManaCost(1)), false);
|
||||
setLeavesTheBattlefieldTrigger(true);
|
||||
}
|
||||
|
||||
private SludgeStriderTriggeredAbility(final SludgeStriderTriggeredAbility ability) {
|
||||
|
|
@ -69,7 +70,8 @@ class SludgeStriderTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD || event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD
|
||||
|| event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
package org.mage.test.cards.single.who;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class CrackInTimeTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void test_ExileUntilLeaves() {
|
||||
addCustomEffect_TargetDestroy(playerA);
|
||||
|
||||
// When Crack in Time enters the battlefield and at the beginning of your precombat main phase,
|
||||
// exile target creature an opponent controls until Crack in Time leaves the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Crack in Time"); // {3}{W}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1);
|
||||
|
||||
// exile
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crack in Time");
|
||||
addTarget(playerA, "Balduvian Bears"); // exile on etb
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkExileCount("on exile", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||
|
||||
// destroy and return
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "target destroy", "Crack in Time");
|
||||
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
checkExileCount("on return", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 0);
|
||||
checkPermanentCount("on return", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import mage.abilities.condition.Condition;
|
|||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.ExileUntilSourceLeavesEffect;
|
||||
import mage.abilities.effects.common.FightTargetsEffect;
|
||||
import mage.abilities.effects.common.counter.ProliferateEffect;
|
||||
import mage.abilities.effects.keyword.ScryEffect;
|
||||
|
|
@ -74,6 +75,7 @@ public class VerifyCardDataTest {
|
|||
|
||||
private static final String FULL_ABILITIES_CHECK_SET_CODES = "MH3;M3C"; // check ability text due mtgjson, can use multiple sets like MAT;CMD or * for all
|
||||
private static final boolean CHECK_ONLY_ABILITIES_TEXT = false; // use when checking text locally, suppresses unnecessary checks and output messages
|
||||
private static final boolean CHECK_COPYABLE_FIELDS = true; // disable for better verify test performance
|
||||
|
||||
private static final boolean AUTO_FIX_SAMPLE_DECKS = false; // debug only: auto-fix sample decks by test_checkSampleDecks test run
|
||||
|
||||
|
|
@ -1632,8 +1634,10 @@ public class VerifyCardDataTest {
|
|||
checkRarityAndBasicLands(card, ref);
|
||||
checkMissingAbilities(card, ref);
|
||||
checkWrongSymbolsInRules(card);
|
||||
if (CHECK_COPYABLE_FIELDS) {
|
||||
checkCardCanBeCopied(card);
|
||||
}
|
||||
}
|
||||
checkWrongAbilitiesText(card, ref, cardIndex);
|
||||
}
|
||||
|
||||
|
|
@ -1994,6 +1998,10 @@ public class VerifyCardDataTest {
|
|||
ignoredCards.add("Infested Thrinax");
|
||||
ignoredCards.add("Xira, the Golden Sting");
|
||||
ignoredCards.add("Mawloc");
|
||||
ignoredCards.add("Crack in Time");
|
||||
ignoredCards.add("Mysterious Limousine");
|
||||
ignoredCards.add("Graceful Antelope");
|
||||
ignoredCards.add("Portcullis");
|
||||
List<String> ignoredAbilities = new ArrayList<>();
|
||||
ignoredAbilities.add("roll"); // roll die effects
|
||||
ignoredAbilities.add("with \"When"); // token creating effects
|
||||
|
|
@ -2009,6 +2017,18 @@ public class VerifyCardDataTest {
|
|||
if (triggeredAbility == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// ignore exile effects
|
||||
// example 1: exile up to one other target nonland permanent until Constable of the Realm leaves the battlefield.
|
||||
if (ability.getAllEffects().stream().anyMatch(e -> e instanceof ExileUntilSourceLeavesEffect)) {
|
||||
continue;
|
||||
}
|
||||
// example 2: When Hostage Taker enters the battlefield, exile another target artifact or creature until Hostage Taker leaves the battlefield
|
||||
if (ability instanceof EntersBattlefieldTriggeredAbility) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// search and check dies related abilities
|
||||
String rules = triggeredAbility.getRule();
|
||||
if (ignoredAbilities.stream().anyMatch(rules::contains)) {
|
||||
|
|
@ -2022,7 +2042,6 @@ public class VerifyCardDataTest {
|
|||
&& rules.contains("graveyard")
|
||||
&& rules.contains("from the battlefield");
|
||||
boolean isLeavesBattlefield = rules.contains("leaves the battlefield");
|
||||
isLeavesBattlefield = false; // TODO: remove and fix all bad cards
|
||||
if (triggeredAbility.isLeavesTheBattlefieldTrigger()) {
|
||||
// TODO: add check for wrongly enabled settings too?
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public class OnLeaveReturnExiledAbility extends DelayedTriggeredAbility {
|
|||
super(new ReturnExiledPermanentsEffect(zone), Duration.OneUse);
|
||||
this.usesStack = false;
|
||||
this.setRuleVisible(false);
|
||||
setLeavesTheBattlefieldTrigger(true);
|
||||
}
|
||||
|
||||
protected OnLeaveReturnExiledAbility(final OnLeaveReturnExiledAbility ability) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue