diff --git a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java index 22242466b7b..8897d2d29ed 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java @@ -12,10 +12,13 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect.FaceDownType; +import mage.cards.Card; import mage.constants.CardType; import mage.constants.Rarity; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.game.permanent.token.EmptyToken; +import mage.game.permanent.token.Token; import mage.game.stack.Spell; import mage.util.CardUtil; @@ -134,24 +137,40 @@ public class MorphAbility extends AlternativeSourceCostsImpl { morphCosts.getText() + (isMana ? ' ' : ". ") + alternativeCost.getReminderText(); } - public static void setPermanentToFaceDownCreature(MageObject mageObject, Game game) { - mageObject.getPower().setModifiedBaseValue(2); - mageObject.getToughness().setModifiedBaseValue(2); - mageObject.getAbilities().clear(); - mageObject.getColor(game).setColor(new ObjectColor()); - mageObject.setName(""); - mageObject.removeAllCardTypes(game); - mageObject.addCardType(game, CardType.CREATURE); - mageObject.removeAllSubTypes(game); - mageObject.getSuperType().clear(); - mageObject.getManaCost().clear(); + /** + * Hide all info and make it a 2/2 creature + * + * @param targetObject + * @param sourcePermanent source of the face down status + * @param game + */ + public static void setPermanentToFaceDownCreature(MageObject targetObject, Permanent sourcePermanent, Game game) { + targetObject.getPower().setModifiedBaseValue(2); + targetObject.getToughness().setModifiedBaseValue(2); + targetObject.getAbilities().clear(); + targetObject.getColor(game).setColor(new ObjectColor()); + targetObject.setName(""); + targetObject.removeAllCardTypes(game); + targetObject.addCardType(game, CardType.CREATURE); + targetObject.removeAllSubTypes(game); + targetObject.getSuperType().clear(); + targetObject.getManaCost().clear(); + + Token emptyImage = new EmptyToken(); + emptyImage.setOriginalExpansionSetCode(""); + emptyImage.setExpansionSetCodeForImage(""); + emptyImage.setOriginalCardNumber(""); // TODO: add morph image here? - if (mageObject instanceof Permanent) { + if (targetObject instanceof Permanent) { // hide image info - CardUtil.copySetAndCardNumber((Permanent) mageObject, "", "", 0); + CardUtil.copySetAndCardNumber(targetObject, emptyImage); // hide rarity info - ((Permanent) mageObject).setRarity(Rarity.SPECIAL); + ((Permanent) targetObject).setRarity(Rarity.SPECIAL); + } else if (targetObject instanceof Token) { + CardUtil.copySetAndCardNumber(targetObject, emptyImage); + } else { + throw new IllegalArgumentException("Wrong code usage: un-supported targetObject in face down method: " + targetObject.getClass().getSimpleName()); } } } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 27fe58c4675..e019922f512 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1912,9 +1912,10 @@ public abstract class GameImpl implements Game { newBluePrint.reset(this); //getState().addCard(permanent); - if (copyFromPermanent.isMorphed() || copyFromPermanent.isManifested() + if (copyFromPermanent.isMorphed() + || copyFromPermanent.isManifested() || copyFromPermanent.isFaceDown(this)) { - MorphAbility.setPermanentToFaceDownCreature(newBluePrint, this); + MorphAbility.setPermanentToFaceDownCreature(newBluePrint, copyFromPermanent, this); } newBluePrint.assignNewId(); if (copyFromPermanent.isTransformed()) { diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 01d3db2a287..9f8785fcd65 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1185,9 +1185,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean entersBattlefield(Ability source, Game game, Zone fromZone, boolean fireEvent) { controlledFromStartOfControllerTurn = false; - if (this.isFaceDown(game)) { + if (this.isFaceDown(game)) { // ?? add morphed/manifested here ?? // remove some attributes here, because first apply effects comes later otherwise abilities (e.g. color related) will unintended trigger - MorphAbility.setPermanentToFaceDownCreature(this, game); + MorphAbility.setPermanentToFaceDownCreature(this, this, game); } if (game.replaceEvent(new EntersTheBattlefieldEvent(this, source, getControllerId(), fromZone, EnterEventType.SELF))) { diff --git a/Mage/src/main/java/mage/game/permanent/PermanentToken.java b/Mage/src/main/java/mage/game/permanent/PermanentToken.java index e0295c686a7..b1f0ea19b53 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentToken.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentToken.java @@ -19,6 +19,8 @@ import java.util.UUID; */ public class PermanentToken extends PermanentImpl { + // non-modifyable container with token characteristics + // this PermanentToken resets to it on each game cycle protected Token token; public PermanentToken(Token token, UUID controllerId, Game game) { diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index fa2451f07b2..27907202f23 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -1789,7 +1789,7 @@ public final class CardUtil { * Copy image related data from one object to another (card number, set code, token type) * Use it in copy/transform effects */ - public static void copySetAndCardNumber(Permanent permanent, MageObject copyFromObject) { + public static void copySetAndCardNumber(MageObject targetObject, MageObject copyFromObject) { String needSetCode; String needCardNumber; int needTokenType; @@ -1810,23 +1810,37 @@ public final class CardUtil { needCardNumber = ((Card) copyFromObject).getCardNumber(); needTokenType = 0; } else if (copyFromObject instanceof Token) { - // TODO: make this work - return; + needSetCode = ((Token) copyFromObject).getOriginalExpansionSetCode(); + needCardNumber = ((Token) copyFromObject).getOriginalCardNumber(); + needTokenType = ((Token) copyFromObject).getTokenType(); } else { throw new IllegalStateException("Unsupported copyFromObject class: " + copyFromObject.getClass().getSimpleName()); } - copySetAndCardNumber(permanent, needSetCode, needCardNumber, needTokenType); - } - - public static void copySetAndCardNumber(Permanent permanent, String newSetCode, String newCardNumber, Integer newTokenType) { - if (permanent instanceof PermanentToken) { - ((PermanentToken) permanent).getToken().setOriginalExpansionSetCode(newSetCode); - ((PermanentToken) permanent).getToken().setExpansionSetCodeForImage(newCardNumber); - ((PermanentToken) permanent).getToken().setTokenType(newTokenType); + if (targetObject instanceof Permanent) { + copySetAndCardNumber((Permanent) targetObject, needSetCode, needCardNumber, needTokenType); + } else if (targetObject instanceof Token) { + copySetAndCardNumber((Token) targetObject, needSetCode, needCardNumber, needTokenType); } else { - permanent.setExpansionSetCode(newSetCode); - permanent.setCardNumber(newCardNumber); + throw new IllegalStateException("Unsupported target object class: " + targetObject.getClass().getSimpleName()); } } + + private static void copySetAndCardNumber(Permanent targetPermanent, String newSetCode, String newCardNumber, Integer newTokenType) { + if (targetPermanent instanceof PermanentToken) { + copySetAndCardNumber(((PermanentToken) targetPermanent).getToken(), newSetCode, newCardNumber, newTokenType); + } else if (targetPermanent instanceof PermanentCard) { + targetPermanent.setExpansionSetCode(newSetCode); + targetPermanent.setCardNumber(newCardNumber); + } else { + throw new IllegalArgumentException("Wrong code usage: un-supported target permanent type: " + targetPermanent.getClass().getSimpleName()); + } + } + + private static void copySetAndCardNumber(Token targetToken, String newSetCode, String newCardNumber, Integer newTokenType) { + targetToken.setOriginalExpansionSetCode(newSetCode); + targetToken.setExpansionSetCodeForImage(newSetCode); + targetToken.setOriginalCardNumber(newCardNumber); + targetToken.setTokenType(newTokenType); + } } diff --git a/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java b/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java index ae7e41ed58e..f208902ae66 100644 --- a/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java +++ b/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java @@ -13,6 +13,7 @@ import mage.game.permanent.PermanentToken; import mage.game.permanent.token.EmptyToken; import mage.game.permanent.token.Token; import mage.game.stack.Spell; +import mage.util.CardUtil; /** * @author nantuko @@ -44,59 +45,68 @@ public class CopyTokenFunction { // else gained abililies would be copied too. target.setEntersTransformed(source instanceof Permanent && ((Permanent) source).isTransformed()); MageObject sourceObj; + + // from another token if (source instanceof PermanentToken) { // create token from another token Token sourceToken = ((PermanentToken) source).getToken(); sourceObj = sourceToken; - copyToToken(target, sourceObj, game); - if (sourceToken.getBackFace() != null) { - target.getBackFace().setOriginalExpansionSetCode(sourceToken.getOriginalExpansionSetCode()); - target.getBackFace().setOriginalCardNumber(sourceToken.getOriginalCardNumber()); - target.getBackFace().setCopySourceCard(sourceToken.getBackFace().getCopySourceCard()); - copyToToken(target.getBackFace(), sourceToken.getBackFace(), game); - } - // to show the source image, the original values have to be used - target.setOriginalExpansionSetCode(sourceToken.getOriginalExpansionSetCode()); - target.setOriginalCardNumber(sourceToken.getOriginalCardNumber()); target.setCopySourceCard(((PermanentToken) source).getToken().getCopySourceCard()); + + copyToToken(target, sourceObj, game); + CardUtil.copySetAndCardNumber(target, source); + if (sourceToken.getBackFace() != null) { + copyToToken(target.getBackFace(), sourceToken.getBackFace(), game); + CardUtil.copySetAndCardNumber(target.getBackFace(), sourceToken.getBackFace()); + } return; } + + // from a permanent if (source instanceof PermanentCard) { // create token from non-token permanent - if (((PermanentCard) source).isMorphed() || ((PermanentCard) source).isManifested()) { - MorphAbility.setPermanentToFaceDownCreature(target, game); + + // morph/manifest must hide all info + if (((PermanentCard) source).isMorphed() + || ((PermanentCard) source).isManifested() + || source.isFaceDown(game)) { + MorphAbility.setPermanentToFaceDownCreature(target, (PermanentCard) source, game); return; } - sourceObj = ((PermanentCard) source).getMainCard(); - copyToToken(target, sourceObj, game); - if (((Card) sourceObj).isTransformable()) { - target.getBackFace().setOriginalExpansionSetCode(source.getExpansionSetCode()); - target.getBackFace().setOriginalCardNumber(source.getCardNumber()); - target.getBackFace().setCopySourceCard(((Card) sourceObj).getSecondCardFace()); - copyToToken(target.getBackFace(), ((Card) sourceObj).getSecondCardFace(), game); - } - target.setOriginalExpansionSetCode(source.getExpansionSetCode()); - target.setOriginalCardNumber(source.getCardNumber()); + sourceObj = source.getMainCard(); target.setCopySourceCard((Card) sourceObj); + + copyToToken(target, sourceObj, game); + CardUtil.copySetAndCardNumber(target, sourceObj); + if (((Card) sourceObj).isTransformable()) { + copyToToken(target.getBackFace(), ((Card) sourceObj).getSecondCardFace(), game); + CardUtil.copySetAndCardNumber(target.getBackFace(), ((Card) sourceObj).getSecondCardFace()); + } return; } + + // from another object like card (example: Embalm ability) sourceObj = source; - copyToToken(target, sourceObj, game); - if (source.isTransformable()) { - target.getBackFace().setOriginalExpansionSetCode(source.getExpansionSetCode()); - target.getBackFace().setOriginalCardNumber(source.getCardNumber()); - target.getBackFace().setCopySourceCard(source.getSecondCardFace()); - copyToToken(target.getBackFace(), source.getSecondCardFace(), game); - } - // create token from non-permanent object like card (example: Embalm ability) - target.setOriginalExpansionSetCode(source.getExpansionSetCode()); - target.setOriginalCardNumber(source.getCardNumber()); target.setCopySourceCard(source); + + copyToToken(target, sourceObj, game); + CardUtil.copySetAndCardNumber(target, sourceObj); + if (source.isTransformable()) { + if (target.getBackFace() == null) { + // if you catch this then a weird use case here: card with single face copy another token with double face?? + // must create back face?? + throw new IllegalStateException("Wrong code usage: back face must be non null: " + target.getName() + " - " + target.getClass().getSimpleName()); + } + copyToToken(target.getBackFace(), source.getSecondCardFace(), game); + CardUtil.copySetAndCardNumber(target.getBackFace(), source.getSecondCardFace()); + } } - private static Token copyToToken(Token target, MageObject sourceObj, Game game) { + private static void copyToToken(Token target, MageObject sourceObj, Game game) { // modify all attributes permanently (without game usage) + // ignore images settings here, it will be setup later due needs in face down + // (after copy or after put to battlefield) target.setName(sourceObj.getName()); target.getColor().setColor(sourceObj.getColor()); target.getManaCost().clear(); @@ -128,8 +138,6 @@ public class CopyTokenFunction { target.setToughness(sourceObj.getToughness().getBaseValue()); target.setStartingLoyalty(sourceObj.getStartingLoyalty()); target.setStartingDefense(sourceObj.getStartingDefense()); - - return target; } private Token from(Card source, Game game, Spell spell) {