mirror of
https://github.com/correl/mage.git
synced 2024-11-25 03:00:11 +00:00
* Becomes a copy abilities: improved support with MDF cards (#8335);
This commit is contained in:
parent
35b257bd8f
commit
afdae939c3
9 changed files with 141 additions and 18 deletions
|
@ -121,7 +121,7 @@ public class TestCardRenderDialog extends MageDialog {
|
|||
cardsList.add(newCard);
|
||||
game.loadCards(cardsList, controllerId);
|
||||
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(game, newCard);
|
||||
if (extraAbilities != null) {
|
||||
extraAbilities.forEach(ability -> permCard.addAbility(ability));
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ public class TestCardRenderDialog extends MageDialog {
|
|||
cardsList.add(newCard);
|
||||
game.loadCards(cardsList, controllerId);
|
||||
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(game, newCard);
|
||||
|
||||
PermanentCard perm = new PermanentCard(permCard, controllerId, game);
|
||||
perm.setFaceDown(true, game);
|
||||
|
|
|
@ -30,7 +30,8 @@ public final class ZamWesell extends CardImpl {
|
|||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// When you cast Zam Wessel, target opponent reveals their hand. You may choose a creature card from it and have Zam Wessel enter the battlefield as a copy of that creature card.
|
||||
// When you cast Zam Wesell, target opponent reveals their hand. You may choose a creature card from it and have Zam Wesell enter the battlefield as a copy of that creature card.
|
||||
// TODO: Zam Wesell must be reworked to use on cast + etb abilities
|
||||
Ability ability = new CastSourceTriggeredAbility(new RevealHandTargetEffect());
|
||||
ability.addEffect(new ZamWesselEffect());
|
||||
ability.addTarget(new TargetOpponent());
|
||||
|
|
|
@ -9,6 +9,7 @@ import mage.game.permanent.PermanentCard;
|
|||
import mage.util.CardUtil;
|
||||
import mage.util.ManaUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.player.TestPlayer;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
@ -863,4 +864,110 @@ public class ModalDoubleFacesCardsTest extends CardTestPlayerBase {
|
|||
|
||||
assertPermanentCount(playerA, "The Omenkeel", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Copy_AsSpell() {
|
||||
addCard(Zone.HAND, playerA, "Akoum Warrior", 1); // {5}{R}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6);
|
||||
//
|
||||
// Copy target creature spell you control, except it isn't legendary if the spell is legendary.
|
||||
addCard(Zone.HAND, playerA, "Double Major", 1); // {G}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
|
||||
// cast mdf card
|
||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", 6);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior");
|
||||
// prepare copy of spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major", "Akoum Warrior", "Akoum Warrior");
|
||||
checkStackSize("before copy spell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true);
|
||||
checkStackSize("after copy spell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 2);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Copy_AsCloneFromPermanent() {
|
||||
addCard(Zone.HAND, playerA, "Akoum Warrior", 1); // {5}{R}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6);
|
||||
//
|
||||
// You may have Clone enter the battlefield as a copy of any creature on the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Clone", 1); // {3}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
|
||||
// cast mdf card
|
||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", 6);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
// copy permanent
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clone");
|
||||
setChoice(playerA, true); // use copy
|
||||
setChoice(playerA, "Akoum Warrior"); // copy source
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 2);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // TODO: Zam Wesell must be reworked to use on cast + etb abilities
|
||||
public void test_Copy_AsCloneFromCard_ZamWesell() {
|
||||
// When you cast Zam Wesell, target opponent reveals their hand. You may choose a creature card from it
|
||||
// and have Zam Wesell enter the battlefield as a copy of that creature card.
|
||||
addCard(Zone.HAND, playerA, "Zam Wesell"); // {2}{U}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
//
|
||||
addCard(Zone.HAND, playerB, "Akoum Warrior", 1);
|
||||
|
||||
// cast as copy of mdf card
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Zam Wesell");
|
||||
addTarget(playerA, playerB); // target opponent
|
||||
setChoice(playerA, "Akoum Warrior"); // creature card to copy
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 2);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Copy_AsCloneFromCard_ValkiGodOfLies() {
|
||||
// When Valki enters the battlefield, each opponent reveals their hand. For each opponent,
|
||||
// exile a creature card they revealed this way until Valki leaves the battlefield.
|
||||
// X: Choose a creature card exiled with Valki with converted mana cost X. Valki becomes a copy of that card.
|
||||
addCard(Zone.HAND, playerA, "Valki, God of Lies"); // {1}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2 + 3); // 3 for X
|
||||
//
|
||||
addCard(Zone.HAND, playerB, "Birgi, God of Storytelling", 1); // {2}{R}
|
||||
|
||||
// prepare valki
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Valki, God of Lies");
|
||||
setChoice(playerA, "Birgi, God of Storytelling"); // exile
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
// copy exiled card
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{X}:");
|
||||
setChoice(playerA, "X=3");
|
||||
setChoice(playerA, "Birgi, God of Storytelling");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Valki, God of Lies", 0);
|
||||
assertPermanentCount(playerA, "Birgi, God of Storytelling", 1);
|
||||
}
|
||||
}
|
|
@ -255,7 +255,7 @@ public abstract class MageTestBase {
|
|||
Card newCard = cardInfo != null ? cardInfo.getCard() : null;
|
||||
if (newCard != null) {
|
||||
if (gameZone == Zone.BATTLEFIELD) {
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
PermanentCard p = new PermanentCard(permCard, null, currentGame);
|
||||
p.setTapped(tapped);
|
||||
perms.add(p);
|
||||
|
|
|
@ -269,7 +269,7 @@ public abstract class MageTestPlayerBase {
|
|||
Card newCard = cardInfo != null ? cardInfo.getCard() : null;
|
||||
if (newCard != null) {
|
||||
if (gameZone == Zone.BATTLEFIELD) {
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
PermanentCard p = new PermanentCard(permCard, null, currentGame);
|
||||
p.setTapped(tapped);
|
||||
perms.add(p);
|
||||
|
@ -422,7 +422,7 @@ public abstract class MageTestPlayerBase {
|
|||
|
||||
CardSetInfo testSet = new CardSetInfo(customName, "custom", "123", Rarity.COMMON);
|
||||
Card newCard = new CustomTestCard(controllerPlayer.getId(), testSet, cardType, spellCost);
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
PermanentCard permanent = new PermanentCard(permCard, controllerPlayer.getId(), currentGame);
|
||||
|
||||
switch (putAtZone) {
|
||||
|
|
|
@ -685,7 +685,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
if (gameZone == Zone.BATTLEFIELD) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
Card newCard = cardInfo.getCard();
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
|
||||
PermanentCard p = new PermanentCard(permCard, player.getId(), currentGame);
|
||||
p.setTapped(tapped);
|
||||
|
|
|
@ -34,7 +34,7 @@ public class SerializationTest extends CardTestPlayerBase {
|
|||
public void test_PermanentImpl_Simple() {
|
||||
CardInfo cardInfo = CardRepository.instance.findCard("Balduvian Bears");
|
||||
Card newCard = cardInfo.getCard();
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
PermanentImpl permanent = new PermanentCard(permCard, playerA.getId(), currentGame);
|
||||
currentGame.addPermanent(permanent, 0);
|
||||
|
||||
|
@ -48,7 +48,7 @@ public class SerializationTest extends CardTestPlayerBase {
|
|||
public void test_PermanentImpl_MarkedDamageInfo() {
|
||||
CardInfo cardInfo = CardRepository.instance.findCard("Balduvian Bears");
|
||||
Card newCard = cardInfo.getCard();
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
PermanentImpl permanent = new PermanentCard(permCard, playerA.getId(), currentGame);
|
||||
currentGame.addPermanent(permanent, 0);
|
||||
|
||||
|
@ -73,7 +73,7 @@ public class SerializationTest extends CardTestPlayerBase {
|
|||
CardUtil.getObjectPartsAsObjects(newCard).stream()
|
||||
.map(Card.class::cast)
|
||||
.forEach(card -> {
|
||||
Card testCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
||||
Card testCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
Card testPermanent = null;
|
||||
if (!testCard.isInstantOrSorcery()) {
|
||||
testPermanent = new PermanentCard(testCard, playerA.getId(), currentGame);
|
||||
|
|
|
@ -10,20 +10,20 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyApplier;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Make battlefield's permanent as a copy of the source object
|
||||
* (source can be a card or another permanent)
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class CopyEffect extends ContinuousEffectImpl {
|
||||
|
||||
/**
|
||||
* Object we copy from
|
||||
*/
|
||||
protected MageObject copyFromObject;
|
||||
|
||||
protected UUID copyToObjectId;
|
||||
protected CopyApplier applier;
|
||||
|
||||
|
@ -47,9 +47,13 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
|
||||
// must copy the default side of the card (example: clone with mdf card)
|
||||
if (!(copyFromObject instanceof Permanent) && (copyFromObject instanceof Card)) {
|
||||
this.copyFromObject = new PermanentCard((Card) copyFromObject, source.getControllerId(), game);
|
||||
Card newBluePrint = CardUtil.getDefaultCardSideForBattlefield(game, (Card) copyFromObject);
|
||||
this.copyFromObject = new PermanentCard(newBluePrint, source.getControllerId(), game);
|
||||
}
|
||||
|
||||
Permanent permanent = game.getPermanent(copyToObjectId);
|
||||
if (permanent != null) {
|
||||
affectedObjectList.add(new MageObjectReference(permanent, game));
|
||||
|
|
|
@ -997,7 +997,7 @@ public final class CardUtil {
|
|||
// same logic as ZonesHandler->maybeRemoveFromSourceZone
|
||||
|
||||
// workaround to put real permanent from one side (example: you call mdf card by cheats)
|
||||
Card permCard = getDefaultCardSideForBattlefield(newCard);
|
||||
Card permCard = getDefaultCardSideForBattlefield(game, newCard);
|
||||
|
||||
// prepare card and permanent
|
||||
permCard.setZone(Zone.BATTLEFIELD, game);
|
||||
|
@ -1035,12 +1035,17 @@ public final class CardUtil {
|
|||
|
||||
/**
|
||||
* Choose default card's part to put on battlefield (for cheats and tests only)
|
||||
* or to find a default card side (for copy effect)
|
||||
*
|
||||
* @param card
|
||||
* @return
|
||||
*/
|
||||
public static Card getDefaultCardSideForBattlefield(Card card) {
|
||||
// chose left side all time
|
||||
public static Card getDefaultCardSideForBattlefield(Game game, Card card) {
|
||||
if (card instanceof PermanentCard) {
|
||||
return card;
|
||||
}
|
||||
|
||||
// must choose left side all time
|
||||
Card permCard;
|
||||
if (card instanceof SplitCard) {
|
||||
permCard = card;
|
||||
|
@ -1051,6 +1056,12 @@ public final class CardUtil {
|
|||
} else {
|
||||
permCard = card;
|
||||
}
|
||||
|
||||
// must be creature/planeswalker (if you catch this error then check targeting/copying code)
|
||||
if (permCard.isInstantOrSorcery(game)) {
|
||||
throw new IllegalArgumentException("Card side can't be put to battlefield: " + permCard.getName());
|
||||
}
|
||||
|
||||
return permCard;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue