forked from External/mage
[WOC] Implement Unfinished Business (#11144)
* [WOC] Implement Unfinished Business * Added assertIsNotAttachedTo * Added unittests for [WOC] Unfinished Business * Remove unused import * Refactored assertIsAttachedTo & assertIsNotAttachedTo into assertIsAttached. * Added processAction after return of creature * Added comments and minor changes --------- Co-authored-by: Codermann63 <zoiazous@gmail.com>
This commit is contained in:
parent
4a53ca5ad8
commit
e92031a3bb
8 changed files with 281 additions and 13 deletions
126
Mage.Sets/src/mage/cards/u/UnfinishedBusiness.java
Normal file
126
Mage.Sets/src/mage/cards/u/UnfinishedBusiness.java
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
package mage.cards.u;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Codermann63
|
||||
*/
|
||||
public final class UnfinishedBusiness extends CardImpl {
|
||||
|
||||
private static final FilterCard auraOrEquipmentFilter = new FilterCard("Aura or Equipment card");
|
||||
|
||||
static {
|
||||
auraOrEquipmentFilter.add(Predicates.or(
|
||||
SubType.EQUIPMENT.getPredicate(),
|
||||
SubType.AURA.getPredicate()
|
||||
));
|
||||
}
|
||||
|
||||
public UnfinishedBusiness(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{W}");
|
||||
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(1,1, StaticFilters.FILTER_CARD_CREATURE));
|
||||
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 2, auraOrEquipmentFilter));
|
||||
// Return target creature card from your graveyard to the battlefield,
|
||||
// then return up to two target Aura and/or Equipment cards from your graveyard to the battlefield attached to that creature.
|
||||
this.getSpellAbility().addEffect(new UnfinishedBusinessEffect());
|
||||
}
|
||||
|
||||
private UnfinishedBusiness(final UnfinishedBusiness card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnfinishedBusiness copy() {
|
||||
return new UnfinishedBusiness(this);
|
||||
}
|
||||
}
|
||||
|
||||
class UnfinishedBusinessEffect extends OneShotEffect{
|
||||
|
||||
UnfinishedBusinessEffect() {
|
||||
super(Outcome.PutCreatureInPlay);
|
||||
staticText = "Return target creature card from your graveyard to the battlefield, then return up to two target Aura and/or Equipment cards from your graveyard to the battlefield attached to that creature. <i>(If the Auras can not enchant that creature, they remain in your graveyard.)</i>";
|
||||
}
|
||||
|
||||
private UnfinishedBusinessEffect(final UnfinishedBusinessEffect effect) {super(effect);}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer((source.getControllerId()));
|
||||
if (controller == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return target creature from the graveyard to the battlefield
|
||||
Card targetCreature = game.getCard(source.getTargets().getFirstTarget());
|
||||
|
||||
if (targetCreature != null){
|
||||
controller.moveCards(targetCreature, Zone.BATTLEFIELD, source, game);
|
||||
game.getState().processAction(game);
|
||||
}
|
||||
Permanent permanentCreature = targetCreature == null ? null : game.getPermanent(targetCreature.getId());
|
||||
|
||||
// Target auras and/or equipment in your graveyard.
|
||||
Cards cardsInitial = new CardsImpl(source.getTargets().get(1).getTargets());
|
||||
if (cardsInitial.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Auras that cannot be attached to the creature stay in the graveyard
|
||||
// Create a list of legal cards to return
|
||||
Cards cards = new CardsImpl();
|
||||
for(UUID c: cardsInitial){
|
||||
if (game.getCard(c).hasSubtype(SubType.EQUIPMENT,game)){
|
||||
// always add equipment cards
|
||||
cards.add(c);
|
||||
}
|
||||
else if (permanentCreature != null &&
|
||||
!permanentCreature.cantBeAttachedBy(game.getCard(c),source, game, false) &&
|
||||
game.getCard(c).hasSubtype(SubType.AURA, game)){
|
||||
// only add auras if the creature has returned
|
||||
// only add auras that can be attached to creature
|
||||
cards.add(c);
|
||||
}
|
||||
}
|
||||
if (cards.isEmpty()){
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle return of legal auras and equipment
|
||||
if (permanentCreature != null){
|
||||
cards.getCards(game)
|
||||
.forEach(card -> game.getState().setValue("attachTo:" + card.getId(), permanentCreature));
|
||||
}
|
||||
controller.moveCards(cards, Zone.BATTLEFIELD, source, game);
|
||||
if (permanentCreature != null){
|
||||
for(UUID id: cards){
|
||||
if (!permanentCreature.cantBeAttachedBy(game.getCard(id), source, game, true)){
|
||||
permanentCreature.addAttachment(id, source, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnfinishedBusinessEffect copy() {
|
||||
return new UnfinishedBusinessEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -148,6 +148,7 @@ public final class WildsOfEldraineCommander extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Tithe Taker", 80, Rarity.RARE, mage.cards.t.TitheTaker.class));
|
||||
cards.add(new SetCardInfo("Transcendent Envoy", 81, Rarity.COMMON, mage.cards.t.TranscendentEnvoy.class));
|
||||
cards.add(new SetCardInfo("Umbra Mystic", 82, Rarity.RARE, mage.cards.u.UmbraMystic.class));
|
||||
cards.add(new SetCardInfo("Unfinished Business", 8, Rarity.RARE, mage.cards.u.UnfinishedBusiness.class));
|
||||
cards.add(new SetCardInfo("Utopia Sprawl", 135, Rarity.COMMON, mage.cards.u.UtopiaSprawl.class));
|
||||
cards.add(new SetCardInfo("Verdant Embrace", 136, Rarity.RARE, mage.cards.v.VerdantEmbrace.class));
|
||||
cards.add(new SetCardInfo("Vitu-Ghazi, the City-Tree", 173, Rarity.UNCOMMON, mage.cards.v.VituGhaziTheCityTree.class));
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class ReconfigureTest extends CardTestPlayerBase {
|
|||
|
||||
assertType(boar, CardType.CREATURE, false);
|
||||
assertSubtype(boar, SubType.EQUIPMENT);
|
||||
assertIsAttachedTo(playerA, boar, lion);
|
||||
assertAttachedTo(playerA, boar, lion, true);
|
||||
assertPowerToughness(playerA, lion, 2 + 3, 2 + 2);
|
||||
assertAbility(playerA, lion, TrampleAbility.getInstance(), true);
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ public class ReconfigureTest extends CardTestPlayerBase {
|
|||
|
||||
assertType(boar, CardType.CREATURE, false);
|
||||
assertSubtype(boar, SubType.EQUIPMENT);
|
||||
assertIsAttachedTo(playerA, boar, lion);
|
||||
assertAttachedTo(playerA, boar, lion, true);
|
||||
assertPowerToughness(playerA, lion, 2 + 3, 2 + 2);
|
||||
assertAbility(playerA, lion, TrampleAbility.getInstance(), true);
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ public class ReconfigureTest extends CardTestPlayerBase {
|
|||
|
||||
assertType(boar, CardType.CREATURE, false);
|
||||
assertSubtype(boar, SubType.EQUIPMENT);
|
||||
assertIsAttachedTo(playerA, boar, lion);
|
||||
assertAttachedTo(playerA, boar, lion, true);
|
||||
assertPowerToughness(playerA, lion, 2 + 3, 2 + 2);
|
||||
assertAbility(playerA, lion, TrampleAbility.getInstance(), true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public class BronzehideLionTest extends CardTestPlayerBase {
|
|||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
assertGraveyardCount(playerA, lion, 0);
|
||||
assertIsAttachedTo(playerA, lion, "Grizzly Bears");
|
||||
assertAttachedTo(playerA, lion, "Grizzly Bears", true);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class BeltOfGiantStrengthTest extends CardTestPlayerBase {
|
|||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertIsAttachedTo(playerA, belt, gigantosauras);
|
||||
assertAttachedTo(playerA, belt, gigantosauras, true);
|
||||
Assert.assertTrue(
|
||||
"All Forests should be untapped",
|
||||
currentGame
|
||||
|
|
@ -51,6 +51,6 @@ public class BeltOfGiantStrengthTest extends CardTestPlayerBase {
|
|||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertIsAttachedTo(playerA, belt, gigantosauras);
|
||||
assertAttachedTo(playerA, belt, gigantosauras, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,6 @@ public class ForgeAnewTest extends CardTestPlayerBase {
|
|||
execute();
|
||||
|
||||
// Make sure it is attached
|
||||
assertIsAttachedTo(playerA, EQUIPMENT, CREATURE);
|
||||
assertAttachedTo(playerA, EQUIPMENT, CREATURE, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
package org.mage.test.cards.single.woc;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author Codermann63
|
||||
*/
|
||||
|
||||
public class UnfinishedBusinessTest extends CardTestPlayerBase {
|
||||
/*
|
||||
* Unfinished Business
|
||||
* {3}{W}{W} - Sorcery
|
||||
* Return target creature card from your graveyard to the battlefield,
|
||||
* then return up to two target Aura and/or Equipment cards from your graveyard to the battlefield attached to that creature.
|
||||
* (If the Auras can’t enchant that creature, they remain in your graveyard.)
|
||||
*/
|
||||
private static final String UNFINISHEDBUSINESS = "Unfinished Business";
|
||||
// Deadly insect - 6/1 creature with Shroud
|
||||
private static final String SHROUDCREATURE = "Deadly Insect";
|
||||
// Apostle of Purifying Light - white creature with protection from black & activated ability to exile target card from a graveyard.
|
||||
private static final String APOSTLE = "Apostle of Purifying Light";
|
||||
private static final String BEAR = "Grizzly Bears";
|
||||
// Blanchwood Armor - green aura - enchanted creature gets +1/+1 for each forest you control
|
||||
private static final String AURA = "Blanchwood Armor";
|
||||
// Ghoulflesh - black aura - enchanted creature get -1/-1 and is a black Zombie in addition to its other colors and types.
|
||||
private static final String GHOULFLESH = "Ghoulflesh";
|
||||
// Shuko - colorless Equipment - Equipped creature gets +1/+0.
|
||||
private static final String EQUIPMENT = "Shuko";
|
||||
// Enormous Energy Blade - black equipment - Equipped creature gets +4/+0. Whenever Enormous Energy Blade becomes attached to a creature, tap that creature.
|
||||
private static final String EEB = "Enormous Energy Blade";
|
||||
|
||||
|
||||
// Return a creature with shroud, and return an Aura and an Equipment checking that both attach.
|
||||
@Test
|
||||
public void testShroud() {
|
||||
addCard(Zone.HAND, playerA, UNFINISHEDBUSINESS);
|
||||
addCard(Zone.GRAVEYARD, playerA, SHROUDCREATURE, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
|
||||
addCard(Zone.GRAVEYARD, playerA, AURA);
|
||||
addCard(Zone.GRAVEYARD, playerA, EQUIPMENT);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
castSpell(1,PhaseStep.PRECOMBAT_MAIN,playerA,UNFINISHEDBUSINESS,SHROUDCREATURE);
|
||||
addTarget(playerA, AURA+"^"+EQUIPMENT);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
execute();
|
||||
|
||||
// Check that all returned to the battlefield
|
||||
assertPermanentCount(playerA, SHROUDCREATURE, 1);
|
||||
assertPermanentCount(playerA, AURA, 1);
|
||||
assertPermanentCount(playerA, EQUIPMENT, 1);
|
||||
|
||||
// Check aura and equipment is attached
|
||||
assertAttachedTo(playerA, AURA, SHROUDCREATURE, true);
|
||||
assertAttachedTo(playerA, EQUIPMENT, SHROUDCREATURE, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Return Apostle of purifying light (creature with protection from black),
|
||||
// and try to return a Ghoulflesh(black aura) and Enormous energy blade(black equipment).
|
||||
// The aura should remain in graveyard and the equipment should return but not attach.
|
||||
@Test
|
||||
public void testProtection(){
|
||||
addCard(Zone.HAND, playerA, UNFINISHEDBUSINESS);
|
||||
// Nexus wardens gain life if an enchantment entered the battlefield
|
||||
// This is to test if ghoulflesh enters the battlefield
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Nexus Wardens");
|
||||
addCard(Zone.GRAVEYARD, playerA, APOSTLE);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
|
||||
addCard(Zone.GRAVEYARD, playerA, GHOULFLESH);
|
||||
addCard(Zone.GRAVEYARD, playerA, EEB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
castSpell(1,PhaseStep.PRECOMBAT_MAIN,playerA,UNFINISHEDBUSINESS,APOSTLE);
|
||||
addTarget(playerA, GHOULFLESH+"^"+EEB);
|
||||
waitStackResolved(1, PhaseStep.END_TURN);
|
||||
|
||||
execute();
|
||||
|
||||
// Check boardstate
|
||||
assertPermanentCount(playerA, APOSTLE, 1);
|
||||
assertPermanentCount(playerA, GHOULFLESH, 0);
|
||||
assertPermanentCount(playerA, EEB, 1);
|
||||
|
||||
// EEB should never have been attached and therefore the White knight should be untapped
|
||||
assertTapped(APOSTLE,false);
|
||||
assertAttachedTo(playerA, EEB, APOSTLE,false);
|
||||
|
||||
// Check that Ghoulflesh never entered the battlefield
|
||||
assertLife(playerA, 20);
|
||||
assertGraveyardCount(playerA,GHOULFLESH, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Test equipment return if creature is exiled from graveyard before spell resolution
|
||||
@Test
|
||||
public void testExileCreatureBeforeResolution(){
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
|
||||
addCard(Zone.HAND,playerA,UNFINISHEDBUSINESS);
|
||||
addCard(Zone.GRAVEYARD, playerA, EQUIPMENT);
|
||||
addCard(Zone.GRAVEYARD, playerA, AURA);
|
||||
addCard(Zone.GRAVEYARD, playerA, BEAR);
|
||||
// Apostle of Purifying Light has an activated ability to exile card from graveyard
|
||||
addCard(Zone.BATTLEFIELD, playerB, APOSTLE);
|
||||
// Nexus wardens gain life if an enchantment entered the battlefield
|
||||
// This is to test if the aura enters the battlefield
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Nexus Wardens");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
// Cast Unfinished Business targeting GrizzlyBears, and aura and an equipment
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, UNFINISHEDBUSINESS);
|
||||
addTarget(playerA, BEAR);
|
||||
addTarget(playerA, EQUIPMENT+"^"+AURA);
|
||||
// Exile Grizzly Bears from graveyard before spell resolution
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB,"{2}: ",BEAR,UNFINISHEDBUSINESS);
|
||||
waitStackResolved(1, PhaseStep.END_TURN);
|
||||
|
||||
execute();
|
||||
|
||||
// Grizzly Bears should be exiled
|
||||
assertExileCount(playerA, BEAR, 1);
|
||||
// The aura should still be in the graveyard and should never have entered
|
||||
assertGraveyardCount(playerA, AURA, 1);
|
||||
assertLife(playerA, 20);
|
||||
// The equipment should have returned to the battlefield
|
||||
assertPermanentCount(playerA,EQUIPMENT, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -1556,24 +1556,27 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
public void assertTopCardRevealed(TestPlayer player, boolean isRevealed) {
|
||||
Assert.assertEquals(isRevealed, player.isTopCardRevealed());
|
||||
}
|
||||
|
||||
public void assertIsAttachedTo(TestPlayer thePlayer, String theAttachment, String thePermanent) {
|
||||
|
||||
/**
|
||||
* Asserts if, or if not, theAttachment is attached to thePermanent.
|
||||
*
|
||||
* @param isAttached true => assertIsAttachedTo, false => assertIsNotAttachedTo
|
||||
*/
|
||||
public void assertAttachedTo(TestPlayer thePlayer, String theAttachment, String thePermanent, boolean isAttached) {
|
||||
List<Permanent> permanents = currentGame.getBattlefield().getAllActivePermanents().stream()
|
||||
.filter(permanent -> permanent.isControlledBy(thePlayer.getId()))
|
||||
.filter(permanent -> permanent.getName().equals(thePermanent))
|
||||
.collect(Collectors.toList());
|
||||
assertTrue(theAttachment + " was not attached to " + thePermanent,
|
||||
assertTrue(theAttachment + " was "+ (!isAttached ? "":"not") +" attached to " + thePermanent,
|
||||
!isAttached ^
|
||||
permanents.stream()
|
||||
.anyMatch(permanent -> permanent.getAttachments()
|
||||
.stream()
|
||||
.map(id -> currentGame.getCard(id))
|
||||
.map(MageObject::getName)
|
||||
.collect(Collectors.toList()).contains(theAttachment)));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public Permanent getPermanent(String cardName, UUID controller) {
|
||||
assertAliaseSupportInActivateCommand(cardName, false);
|
||||
Permanent found = null;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue