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);
|
cardsList.add(newCard);
|
||||||
game.loadCards(cardsList, controllerId);
|
game.loadCards(cardsList, controllerId);
|
||||||
|
|
||||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
Card permCard = CardUtil.getDefaultCardSideForBattlefield(game, newCard);
|
||||||
if (extraAbilities != null) {
|
if (extraAbilities != null) {
|
||||||
extraAbilities.forEach(ability -> permCard.addAbility(ability));
|
extraAbilities.forEach(ability -> permCard.addAbility(ability));
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ public class TestCardRenderDialog extends MageDialog {
|
||||||
cardsList.add(newCard);
|
cardsList.add(newCard);
|
||||||
game.loadCards(cardsList, controllerId);
|
game.loadCards(cardsList, controllerId);
|
||||||
|
|
||||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
Card permCard = CardUtil.getDefaultCardSideForBattlefield(game, newCard);
|
||||||
|
|
||||||
PermanentCard perm = new PermanentCard(permCard, controllerId, game);
|
PermanentCard perm = new PermanentCard(permCard, controllerId, game);
|
||||||
perm.setFaceDown(true, game);
|
perm.setFaceDown(true, game);
|
||||||
|
|
|
@ -30,7 +30,8 @@ public final class ZamWesell extends CardImpl {
|
||||||
this.power = new MageInt(2);
|
this.power = new MageInt(2);
|
||||||
this.toughness = 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 ability = new CastSourceTriggeredAbility(new RevealHandTargetEffect());
|
||||||
ability.addEffect(new ZamWesselEffect());
|
ability.addEffect(new ZamWesselEffect());
|
||||||
ability.addTarget(new TargetOpponent());
|
ability.addTarget(new TargetOpponent());
|
||||||
|
|
|
@ -9,6 +9,7 @@ import mage.game.permanent.PermanentCard;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
import mage.util.ManaUtil;
|
import mage.util.ManaUtil;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.player.TestPlayer;
|
import org.mage.test.player.TestPlayer;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
@ -863,4 +864,110 @@ public class ModalDoubleFacesCardsTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
assertPermanentCount(playerA, "The Omenkeel", 1);
|
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;
|
Card newCard = cardInfo != null ? cardInfo.getCard() : null;
|
||||||
if (newCard != null) {
|
if (newCard != null) {
|
||||||
if (gameZone == Zone.BATTLEFIELD) {
|
if (gameZone == Zone.BATTLEFIELD) {
|
||||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||||
PermanentCard p = new PermanentCard(permCard, null, currentGame);
|
PermanentCard p = new PermanentCard(permCard, null, currentGame);
|
||||||
p.setTapped(tapped);
|
p.setTapped(tapped);
|
||||||
perms.add(p);
|
perms.add(p);
|
||||||
|
|
|
@ -269,7 +269,7 @@ public abstract class MageTestPlayerBase {
|
||||||
Card newCard = cardInfo != null ? cardInfo.getCard() : null;
|
Card newCard = cardInfo != null ? cardInfo.getCard() : null;
|
||||||
if (newCard != null) {
|
if (newCard != null) {
|
||||||
if (gameZone == Zone.BATTLEFIELD) {
|
if (gameZone == Zone.BATTLEFIELD) {
|
||||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||||
PermanentCard p = new PermanentCard(permCard, null, currentGame);
|
PermanentCard p = new PermanentCard(permCard, null, currentGame);
|
||||||
p.setTapped(tapped);
|
p.setTapped(tapped);
|
||||||
perms.add(p);
|
perms.add(p);
|
||||||
|
@ -422,7 +422,7 @@ public abstract class MageTestPlayerBase {
|
||||||
|
|
||||||
CardSetInfo testSet = new CardSetInfo(customName, "custom", "123", Rarity.COMMON);
|
CardSetInfo testSet = new CardSetInfo(customName, "custom", "123", Rarity.COMMON);
|
||||||
Card newCard = new CustomTestCard(controllerPlayer.getId(), testSet, cardType, spellCost);
|
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);
|
PermanentCard permanent = new PermanentCard(permCard, controllerPlayer.getId(), currentGame);
|
||||||
|
|
||||||
switch (putAtZone) {
|
switch (putAtZone) {
|
||||||
|
|
|
@ -685,7 +685,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
||||||
if (gameZone == Zone.BATTLEFIELD) {
|
if (gameZone == Zone.BATTLEFIELD) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
Card newCard = cardInfo.getCard();
|
Card newCard = cardInfo.getCard();
|
||||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||||
|
|
||||||
PermanentCard p = new PermanentCard(permCard, player.getId(), currentGame);
|
PermanentCard p = new PermanentCard(permCard, player.getId(), currentGame);
|
||||||
p.setTapped(tapped);
|
p.setTapped(tapped);
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class SerializationTest extends CardTestPlayerBase {
|
||||||
public void test_PermanentImpl_Simple() {
|
public void test_PermanentImpl_Simple() {
|
||||||
CardInfo cardInfo = CardRepository.instance.findCard("Balduvian Bears");
|
CardInfo cardInfo = CardRepository.instance.findCard("Balduvian Bears");
|
||||||
Card newCard = cardInfo.getCard();
|
Card newCard = cardInfo.getCard();
|
||||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||||
PermanentImpl permanent = new PermanentCard(permCard, playerA.getId(), currentGame);
|
PermanentImpl permanent = new PermanentCard(permCard, playerA.getId(), currentGame);
|
||||||
currentGame.addPermanent(permanent, 0);
|
currentGame.addPermanent(permanent, 0);
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ public class SerializationTest extends CardTestPlayerBase {
|
||||||
public void test_PermanentImpl_MarkedDamageInfo() {
|
public void test_PermanentImpl_MarkedDamageInfo() {
|
||||||
CardInfo cardInfo = CardRepository.instance.findCard("Balduvian Bears");
|
CardInfo cardInfo = CardRepository.instance.findCard("Balduvian Bears");
|
||||||
Card newCard = cardInfo.getCard();
|
Card newCard = cardInfo.getCard();
|
||||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||||
PermanentImpl permanent = new PermanentCard(permCard, playerA.getId(), currentGame);
|
PermanentImpl permanent = new PermanentCard(permCard, playerA.getId(), currentGame);
|
||||||
currentGame.addPermanent(permanent, 0);
|
currentGame.addPermanent(permanent, 0);
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ public class SerializationTest extends CardTestPlayerBase {
|
||||||
CardUtil.getObjectPartsAsObjects(newCard).stream()
|
CardUtil.getObjectPartsAsObjects(newCard).stream()
|
||||||
.map(Card.class::cast)
|
.map(Card.class::cast)
|
||||||
.forEach(card -> {
|
.forEach(card -> {
|
||||||
Card testCard = CardUtil.getDefaultCardSideForBattlefield(newCard);
|
Card testCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||||
Card testPermanent = null;
|
Card testPermanent = null;
|
||||||
if (!testCard.isInstantOrSorcery()) {
|
if (!testCard.isInstantOrSorcery()) {
|
||||||
testPermanent = new PermanentCard(testCard, playerA.getId(), currentGame);
|
testPermanent = new PermanentCard(testCard, playerA.getId(), currentGame);
|
||||||
|
|
|
@ -10,20 +10,20 @@ import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.PermanentCard;
|
import mage.game.permanent.PermanentCard;
|
||||||
import mage.game.permanent.PermanentToken;
|
import mage.game.permanent.PermanentToken;
|
||||||
|
import mage.util.CardUtil;
|
||||||
import mage.util.functions.CopyApplier;
|
import mage.util.functions.CopyApplier;
|
||||||
|
|
||||||
import java.util.UUID;
|
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
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
public class CopyEffect extends ContinuousEffectImpl {
|
public class CopyEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
/**
|
|
||||||
* Object we copy from
|
|
||||||
*/
|
|
||||||
protected MageObject copyFromObject;
|
protected MageObject copyFromObject;
|
||||||
|
|
||||||
protected UUID copyToObjectId;
|
protected UUID copyToObjectId;
|
||||||
protected CopyApplier applier;
|
protected CopyApplier applier;
|
||||||
|
|
||||||
|
@ -47,9 +47,13 @@ public class CopyEffect extends ContinuousEffectImpl {
|
||||||
@Override
|
@Override
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
super.init(source, 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)) {
|
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);
|
Permanent permanent = game.getPermanent(copyToObjectId);
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
affectedObjectList.add(new MageObjectReference(permanent, game));
|
affectedObjectList.add(new MageObjectReference(permanent, game));
|
||||||
|
|
|
@ -997,7 +997,7 @@ public final class CardUtil {
|
||||||
// same logic as ZonesHandler->maybeRemoveFromSourceZone
|
// same logic as ZonesHandler->maybeRemoveFromSourceZone
|
||||||
|
|
||||||
// workaround to put real permanent from one side (example: you call mdf card by cheats)
|
// 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
|
// prepare card and permanent
|
||||||
permCard.setZone(Zone.BATTLEFIELD, game);
|
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)
|
* 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
|
* @param card
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static Card getDefaultCardSideForBattlefield(Card card) {
|
public static Card getDefaultCardSideForBattlefield(Game game, Card card) {
|
||||||
// chose left side all time
|
if (card instanceof PermanentCard) {
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
// must choose left side all time
|
||||||
Card permCard;
|
Card permCard;
|
||||||
if (card instanceof SplitCard) {
|
if (card instanceof SplitCard) {
|
||||||
permCard = card;
|
permCard = card;
|
||||||
|
@ -1051,6 +1056,12 @@ public final class CardUtil {
|
||||||
} else {
|
} else {
|
||||||
permCard = card;
|
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;
|
return permCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue