Update Laelia, the Blade Reforged to use ZONE_CHANGE_BATCH (#12010)

* Fix #11747

* Fix #12008
This commit is contained in:
Matthew Wilson 2024-03-28 05:28:30 +02:00 committed by GitHub
parent e465eab1bc
commit d08b71642b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 153 additions and 39 deletions

View file

@ -1,7 +1,6 @@
package mage.cards.c;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.common.ChooseACardNameEffect;
import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect;
import mage.cards.CardImpl;
@ -53,11 +52,12 @@ class CranialExtractionEffect extends SearchTargetGraveyardHandLibraryForCardNam
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source));
if (player == null) {
if (controller == null || player == null) {
return true;
}
String cardName = ChooseACardNameEffect.TypeOfName.NON_LAND_NAME.getChoice(player, game, source, false);
String cardName = ChooseACardNameEffect.TypeOfName.NON_LAND_NAME.getChoice(controller, game, source, false);
if (cardName == null) {
return false;
}

View file

@ -13,12 +13,18 @@ import mage.constants.*;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeGroupEvent;
import mage.game.events.ZoneChangeBatchEvent;
import mage.game.events.ZoneChangeEvent;
import java.util.Objects;
import java.util.UUID;
/**
* Rules update: 6/18/2021
* Laelia, the Blade Reforged has received an update to its Oracle text.
* Specifically, its last triggered ability doesn't care which player is exiling cards from the library or graveyard.
* Cards put into exile from your library or graveyard for any reason, such as the delve ability, cause the ability to trigger.
*
* @author jmharmon
*/
public final class LaeliaTheBladeReforged extends CardImpl {
@ -38,7 +44,7 @@ public final class LaeliaTheBladeReforged extends CardImpl {
// Whenever Laelia, the Blade Reforged attacks, exile the top card of your library. You may play that card this turn.
this.addAbility(new AttacksTriggeredAbility(new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn), false));
// Whenever a spell or ability you control exiles one or more cards from your library and/or your graveyard, put a +1/+1 counter on Laelia.
// Whenever one or more cards are put into exile from your library and/or your graveyard, put a +1/+1 counter on Laelia.
this.addAbility(new LaeliaTheBladeReforgedAddCountersTriggeredAbility());
}
@ -69,44 +75,21 @@ class LaeliaTheBladeReforgedAddCountersTriggeredAbility extends TriggeredAbility
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE_GROUP;
return event.getType() == GameEvent.EventType.ZONE_CHANGE_BATCH;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeGroupEvent zEvent = (ZoneChangeGroupEvent) event;
final int numberExiled = zEvent.getCards().size();
if (zEvent.getToZone() != Zone.EXILED
|| numberExiled == 0) {
return false;
}
switch (zEvent.getFromZone()) {
case LIBRARY:
if (zEvent
.getCards()
.stream()
.filter(Objects::nonNull)
.map(Card::getOwnerId)
.anyMatch(this::isControlledBy)
&& numberExiled > 0) {
this.getEffects().clear();
this.getEffects().add(new AddCountersSourceEffect(CounterType.P1P1.createInstance()));
return true;
}
case GRAVEYARD:
if (zEvent
.getCards()
.stream()
.filter(Objects::nonNull)
.map(Card::getOwnerId)
.anyMatch(this::isControlledBy)
&& numberExiled > 0) {
this.getEffects().clear();
this.getEffects().add(new AddCountersSourceEffect(CounterType.P1P1.createInstance()));
return true;
}
}
return false;
ZoneChangeBatchEvent zEvent = (ZoneChangeBatchEvent) event;
return zEvent.getEvents()
.stream()
.filter(e -> e.getFromZone() == Zone.LIBRARY || e.getFromZone() == Zone.GRAVEYARD)
.filter(e -> e.getToZone() == Zone.EXILED)
.map(ZoneChangeEvent::getTargetId)
.map(game::getCard)
.filter(Objects::nonNull)
.map(Card::getOwnerId)
.anyMatch(this::isControlledBy);
}
@Override

View file

@ -0,0 +1,131 @@
package org.mage.test.cards.single.c21;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* {@link mage.cards.l.LaeliaTheBladeReforged Laelia, the Blade Reforged}
* {2}{R}
* Legendary Creature - Spirit Warrior
* Haste
* Whenever Laelia, the Blade Reforged attacks, exile the top card of your library. You may play that card this turn.
* Whenever one or more cards are put into exile from your library and/or your graveyard, put a +1/+1 counter on Laelia.
*
* @author DominionSpy
*/
public class LaeliaTheBladeReforgedTest extends CardTestPlayerBase {
private static final String laelia = "Laelia, the Blade Reforged";
private static final String cranialExtraction = "Cranial Extraction";
private static final String llanowarElves = "Llanowar Elves";
@Test
public void controllerExilesOwnCards() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
addCard(Zone.BATTLEFIELD, playerA, laelia);
addCard(Zone.HAND, playerA, cranialExtraction);
addCard(Zone.HAND, playerA, llanowarElves);
addCard(Zone.GRAVEYARD, playerA, llanowarElves);
addCard(Zone.LIBRARY, playerA, llanowarElves);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cranialExtraction, playerA);
// Choose a nonland card name (Llanowar Elves)
setChoice(playerA, llanowarElves);
// Graveyard
setChoice(playerA, llanowarElves);
// Hand
setChoice(playerA, llanowarElves);
// Library
setChoice(playerA, llanowarElves);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertCounterCount(playerA, laelia, CounterType.P1P1, 1);
}
@Test
public void opponentExilesControllersCards() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
addCard(Zone.HAND, playerA, cranialExtraction);
addCard(Zone.BATTLEFIELD, playerB, laelia);
addCard(Zone.HAND, playerB, llanowarElves);
addCard(Zone.GRAVEYARD, playerB, llanowarElves);
addCard(Zone.LIBRARY, playerB, llanowarElves);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cranialExtraction, playerB);
// Choose a nonland card name (Llanowar Elves)
setChoice(playerA, llanowarElves);
// Graveyard
setChoice(playerA, llanowarElves);
// Hand
setChoice(playerA, llanowarElves);
// Library
setChoice(playerA, llanowarElves);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertCounterCount(playerB, laelia, CounterType.P1P1, 1);
}
@Test
public void controllerExilesOpponentsCards() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
addCard(Zone.BATTLEFIELD, playerA, laelia);
addCard(Zone.HAND, playerA, cranialExtraction);
addCard(Zone.HAND, playerB, llanowarElves);
addCard(Zone.GRAVEYARD, playerB, llanowarElves);
addCard(Zone.LIBRARY, playerB, llanowarElves);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cranialExtraction, playerB);
// Choose a nonland card name (Llanowar Elves)
setChoice(playerA, llanowarElves);
// Graveyard
setChoice(playerA, llanowarElves);
// Hand
setChoice(playerA, llanowarElves);
// Library
setChoice(playerA, llanowarElves);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertCounterCount(playerA, laelia, CounterType.P1P1, 0);
}
@Test
public void opponentExilesOwnCards() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
addCard(Zone.HAND, playerA, cranialExtraction);
addCard(Zone.HAND, playerA, llanowarElves);
addCard(Zone.GRAVEYARD, playerA, llanowarElves);
addCard(Zone.LIBRARY, playerA, llanowarElves);
addCard(Zone.BATTLEFIELD, playerB, laelia);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cranialExtraction, playerA);
// Choose a nonland card name (Llanowar Elves)
setChoice(playerA, llanowarElves);
// Graveyard
setChoice(playerA, llanowarElves);
// Hand
setChoice(playerA, llanowarElves);
// Library
setChoice(playerA, llanowarElves);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertCounterCount(playerB, laelia, CounterType.P1P1, 0);
}
}