From ab280ad2ba67b148a5d7e29d7ca1228ae2c9784b Mon Sep 17 00:00:00 2001 From: Susucre <34709007+Susucre@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:47:07 +0200 Subject: [PATCH] implement [MKM] Cryptic Coat (#12164) and Cloak ability --- .../main/java/mage/view/PermanentView.java | 7 ++ Mage.Sets/src/mage/cards/c/CrypticCoat.java | 97 +++++++++++++++++++ .../src/mage/cards/o/OrochiSoulReaver.java | 2 +- Mage.Sets/src/mage/cards/s/ScrollOfFate.java | 2 +- .../src/mage/cards/t/ThievingAmalgam.java | 2 +- .../src/mage/cards/v/VesuvanShapeshifter.java | 1 + .../src/mage/sets/MurdersAtKarlovManor.java | 1 + .../cards/single/mkm/CrypticCoatTest.java | 50 ++++++++++ .../BecomesFaceDownCreatureEffect.java | 43 ++++---- .../effects/keyword/ManifestEffect.java | 35 +++++-- .../keyword/ManifestTargetPlayerEffect.java | 2 +- .../cards/repository/TokenRepository.java | 5 + .../java/mage/game/permanent/Permanent.java | 4 + .../mage/game/permanent/PermanentCard.java | 1 + .../mage/game/permanent/PermanentImpl.java | 12 +++ 15 files changed, 235 insertions(+), 29 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/c/CrypticCoat.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/mkm/CrypticCoatTest.java diff --git a/Mage.Common/src/main/java/mage/view/PermanentView.java b/Mage.Common/src/main/java/mage/view/PermanentView.java index ee61d369c69..6d3ef741d93 100644 --- a/Mage.Common/src/main/java/mage/view/PermanentView.java +++ b/Mage.Common/src/main/java/mage/view/PermanentView.java @@ -33,6 +33,7 @@ public class PermanentView extends CardView { private final boolean morphed; private final boolean disguised; private final boolean manifested; + private final boolean cloaked; private final boolean attachedToPermanent; // If this card is attached to a permanent which is controlled by a player other than the one which controls this permanent private final boolean attachedControllerDiffers; @@ -47,6 +48,7 @@ public class PermanentView extends CardView { this.morphed = permanent.isMorphed(); this.disguised = permanent.isDisguised(); this.manifested = permanent.isManifested(); + this.cloaked = permanent.isCloaked(); this.damage = permanent.getDamage(); this.attachments = new ArrayList<>(permanent.getAttachments()); this.attachedTo = permanent.getAttachedTo(); @@ -143,6 +145,7 @@ public class PermanentView extends CardView { this.morphed = permanentView.morphed; this.disguised = permanentView.disguised; this.manifested = permanentView.manifested; + this.cloaked = permanentView.cloaked; this.attachedToPermanent = permanentView.attachedToPermanent; this.attachedControllerDiffers = permanentView.attachedControllerDiffers; } @@ -222,4 +225,8 @@ public class PermanentView extends CardView { public boolean isManifested() { return manifested; } + + public boolean isCloaked() { + return cloaked; + } } diff --git a/Mage.Sets/src/mage/cards/c/CrypticCoat.java b/Mage.Sets/src/mage/cards/c/CrypticCoat.java new file mode 100644 index 00000000000..a8fa0c3bf9b --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrypticCoat.java @@ -0,0 +1,97 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.combat.CantBeBlockedAttachedEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.keyword.ManifestEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +import java.util.List; +import java.util.UUID; + +/** + * @author Susucr + */ +public final class CrypticCoat extends CardImpl { + + public CrypticCoat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When Cryptic Coat enters the battlefield, cloak the top card of your library, then attach Cryptic Coat to it. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CrypticCoatEffect())); + + // Equipped creature gets +1/+0 and can't be blocked. + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 0)); + ability.addEffect(new CantBeBlockedAttachedEffect(AttachmentType.EQUIPMENT) + .setText("and can't be blocked") + ); + this.addAbility(ability); + + // {1}{U}: Return Cryptic Coat to its owner's hand. + this.addAbility(new SimpleActivatedAbility(new ReturnToHandSourceEffect(), new ManaCostsImpl<>("{1}{U}"))); + } + + private CrypticCoat(final CrypticCoat card) { + super(card); + } + + @Override + public CrypticCoat copy() { + return new CrypticCoat(this); + } +} + +class CrypticCoatEffect extends OneShotEffect { + + CrypticCoatEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "cloak the top card of your library, then attach {this} to it"; + } + + private CrypticCoatEffect(final CrypticCoatEffect effect) { + super(effect); + } + + @Override + public CrypticCoatEffect copy() { + return new CrypticCoatEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + List cloakedList = ManifestEffect.doManifestCards( + game, source, controller, + controller.getLibrary().getTopCards(game, 1), true + ); + if (cloakedList.isEmpty()) { + return false; + } + Permanent cloaked = cloakedList.get(0); + new AttachEffect(Outcome.BoostCreature, "attach {this} to it") + .setTargetPointer(new FixedTarget(cloaked, game)) + .apply(game, source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/o/OrochiSoulReaver.java b/Mage.Sets/src/mage/cards/o/OrochiSoulReaver.java index acf938c8c6f..7601199ad9f 100644 --- a/Mage.Sets/src/mage/cards/o/OrochiSoulReaver.java +++ b/Mage.Sets/src/mage/cards/o/OrochiSoulReaver.java @@ -79,6 +79,6 @@ class OrochiSoulReaverManifestEffect extends OneShotEffect { return false; } - return ManifestEffect.doManifestCards(game, source, controller, targetPlayer.getLibrary().getTopCards(game, 1)); + return !ManifestEffect.doManifestCards(game, source, controller, targetPlayer.getLibrary().getTopCards(game, 1)).isEmpty(); } } diff --git a/Mage.Sets/src/mage/cards/s/ScrollOfFate.java b/Mage.Sets/src/mage/cards/s/ScrollOfFate.java index 0f42f901154..d60d6859ccb 100644 --- a/Mage.Sets/src/mage/cards/s/ScrollOfFate.java +++ b/Mage.Sets/src/mage/cards/s/ScrollOfFate.java @@ -67,6 +67,6 @@ class ScrollOfFateEffect extends OneShotEffect { return false; } - return ManifestEffect.doManifestCards(game, source, controller, new CardsImpl(targetCard.getTargets()).getCards(game)); + return !ManifestEffect.doManifestCards(game, source, controller, new CardsImpl(targetCard.getTargets()).getCards(game)).isEmpty(); } } diff --git a/Mage.Sets/src/mage/cards/t/ThievingAmalgam.java b/Mage.Sets/src/mage/cards/t/ThievingAmalgam.java index cdce1ba8ef1..17ed4d3a68e 100644 --- a/Mage.Sets/src/mage/cards/t/ThievingAmalgam.java +++ b/Mage.Sets/src/mage/cards/t/ThievingAmalgam.java @@ -86,7 +86,7 @@ class ThievingAmalgamManifestEffect extends OneShotEffect { return false; } - return ManifestEffect.doManifestCards(game, source, controller, targetPlayer.getLibrary().getTopCards(game, 1)); + return !ManifestEffect.doManifestCards(game, source, controller, targetPlayer.getLibrary().getTopCards(game, 1)).isEmpty(); } } diff --git a/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java b/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java index 685b33c6f5a..5a02be89f39 100644 --- a/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java +++ b/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java @@ -162,6 +162,7 @@ class VesuvanShapeshifterFaceDownEffect extends OneShotEffect { permanent.turnFaceDown(source, game, source.getControllerId()); permanent.setManifested(false); permanent.setDisguised(false); + permanent.setCloaked(false); permanent.setMorphed(true); // cause it morph card TODO: smells bad return permanent.isFaceDown(game); diff --git a/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java b/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java index b7f173949ae..93c2ee6da25 100644 --- a/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java +++ b/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java @@ -92,6 +92,7 @@ public final class MurdersAtKarlovManor extends ExpansionSet { cards.add(new SetCardInfo("Crimestopper Sprite", 49, Rarity.COMMON, mage.cards.c.CrimestopperSprite.class)); cards.add(new SetCardInfo("Crowd-Control Warden", 193, Rarity.COMMON, mage.cards.c.CrowdControlWarden.class)); cards.add(new SetCardInfo("Cryptex", 251, Rarity.RARE, mage.cards.c.Cryptex.class)); + cards.add(new SetCardInfo("Cryptic Coat", 50, Rarity.RARE, mage.cards.c.CrypticCoat.class)); cards.add(new SetCardInfo("Culvert Ambusher", 158, Rarity.UNCOMMON, mage.cards.c.CulvertAmbusher.class)); cards.add(new SetCardInfo("Curious Cadaver", 194, Rarity.UNCOMMON, mage.cards.c.CuriousCadaver.class)); cards.add(new SetCardInfo("Curious Inquiry", 51, Rarity.UNCOMMON, mage.cards.c.CuriousInquiry.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mkm/CrypticCoatTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mkm/CrypticCoatTest.java new file mode 100644 index 00000000000..3a0bfcac749 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mkm/CrypticCoatTest.java @@ -0,0 +1,50 @@ +package org.mage.test.cards.single.mkm; + +import mage.constants.EmptyNames; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author Susucr + */ +public class CrypticCoatTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.c.CrypticCoat Cryptic Coat} {2}{U} + * Artifact — Equipment + * When Cryptic Coat enters the battlefield, cloak the top card of your library, then attach Cryptic Coat to it. (To cloak a card, put it onto the battlefield face down as a 2/2 creature with ward {2}. Turn it face up any time for its mana cost if it’s a creature card.) + * Equipped creature gets +1/+0 and can’t be blocked. + * {1}{U}: Return Cryptic Coat to its owner’s hand. + */ + private static final String coat = "Cryptic Coat"; + + @Test + public void test_CloakCreature() { + skipInitShuffling(); + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + addCard(Zone.HAND, playerA, coat); + addCard(Zone.LIBRARY, playerA, "Ancient Crab"); + addCard(Zone.HAND, playerB, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, coat); + + checkPT("Cloaked is 3/2", 1, PhaseStep.BEGIN_COMBAT, playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 3, 2); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", EmptyNames.FACE_DOWN_CREATURE.toString()); + setChoice(playerB, true); // pay for ward + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{U}{U}: Turn this face-down permanent face up."); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Ancient Crab", 1 + 1, 5); + assertDamageReceived(playerA, "Ancient Crab", 3); + assertTappedCount("Mountain", true, 3); + assertTappedCount("Island", true, 6); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java index eb60dcb5d8a..24ec41ea6f7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java @@ -111,32 +111,36 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl { new TurnFaceUpAbility(turnFaceUpCosts, faceDownType == FaceDownType.MEGAMORPHED) .setCostAdjuster(costAdjuster) ); + } - switch (faceDownType) { - case MORPHED: - case MEGAMORPHED: + switch (faceDownType) { + case MORPHED: + case MEGAMORPHED: + if (turnFaceUpCosts != null) { // face up rules replace for cost hide this.additionalAbilities.add(new SimpleStaticAbility(Zone.ALL, new InfoEffect( "Turn it face up any time for its morph cost." ))); - break; - case DISGUISED: - case CLOAKED: - // ward - this.additionalAbilities.add(new WardAbility(new ManaCostsImpl<>("{2}"))); + } + break; + case DISGUISED: + case CLOAKED: + // Ward {2} -- should not be dependent on turnFaceUpCosts. + this.additionalAbilities.add(new WardAbility(new ManaCostsImpl<>("{2}"))); + if (turnFaceUpCosts != null) { // face up rules replace for cost hide this.additionalAbilities.add(new SimpleStaticAbility(Zone.ALL, new InfoEffect( "Turn it face up any time for its disguise/cloaked cost." ))); - break; - case MANUAL: - case MANIFESTED: - // no face up abilities - break; - default: - throw new IllegalArgumentException("Un-supported face down type: " + faceDownType); - } + } + break; + case MANUAL: + case MANIFESTED: + // no face up abilities + break; + default: + throw new IllegalArgumentException("Un-supported face down type: " + faceDownType); } staticText = "{this} becomes a 2/2 face-down creature, with no text, no name, no subtypes, and no mana cost"; @@ -209,6 +213,9 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl { case DISGUISED: permanent.setDisguised(true); break; + case CLOAKED: + permanent.setCloaked(true); + break; default: throw new UnsupportedOperationException("FaceDownType not yet supported: " + faceDownType); } @@ -228,6 +235,8 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl { return BecomesFaceDownCreatureEffect.FaceDownType.DISGUISED; } else if (permanent.isManifested()) { return BecomesFaceDownCreatureEffect.FaceDownType.MANIFESTED; + } else if (permanent.isCloaked()) { + return BecomesFaceDownCreatureEffect.FaceDownType.CLOAKED; } else if (permanent.isFaceDown(game)) { return BecomesFaceDownCreatureEffect.FaceDownType.MANUAL; } else { @@ -326,7 +335,7 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl { tokenName = TokenRepository.XMAGE_IMAGE_NAME_FACE_DOWN_MANIFEST; break; case CLOAKED: - tokenName = "TODO-CLOAKED"; + tokenName = TokenRepository.XMAGE_IMAGE_NAME_FACE_DOWN_CLOAK; break; case MANUAL: tokenName = TokenRepository.XMAGE_IMAGE_NAME_FACE_DOWN_MANUAL; diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ManifestEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ManifestEffect.java index 52c9b8d86b3..1d1b9954d18 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/ManifestEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ManifestEffect.java @@ -18,7 +18,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; -import java.util.Set; +import java.util.*; /** * Manifest @@ -65,6 +65,7 @@ public class ManifestEffect extends OneShotEffect { private final DynamicValue amount; private final boolean isPlural; + private final boolean cloakNotManifest; public ManifestEffect(int amount) { this(StaticValue.get(amount), amount > 1); @@ -75,9 +76,14 @@ public class ManifestEffect extends OneShotEffect { } private ManifestEffect(DynamicValue amount, boolean isPlural) { + this(amount, isPlural, false); + } + + private ManifestEffect(DynamicValue amount, boolean isPlural, boolean cloakNotManifest) { super(Outcome.PutCreatureInPlay); this.amount = amount; this.isPlural = isPlural; + this.cloakNotManifest = cloakNotManifest; this.staticText = setText(); } @@ -85,6 +91,7 @@ public class ManifestEffect extends OneShotEffect { super(effect); this.amount = effect.amount; this.isPlural = effect.isPlural; + this.cloakNotManifest = effect.cloakNotManifest; } @Override @@ -100,12 +107,16 @@ public class ManifestEffect extends OneShotEffect { } int manifestAmount = amount.calculate(game, source, this); - return doManifestCards(game, source, controller, controller.getLibrary().getTopCards(game, manifestAmount)); + return !doManifestCards(game, source, controller, controller.getLibrary().getTopCards(game, manifestAmount), cloakNotManifest).isEmpty(); } - public static boolean doManifestCards(Game game, Ability source, Player manifestPlayer, Set cardsToManifest) { + public static List doManifestCards(Game game, Ability source, Player manifestPlayer, Set cardsToManifest) { + return doManifestCards(game, source, manifestPlayer, cardsToManifest, false); + } + + public static List doManifestCards(Game game, Ability source, Player manifestPlayer, Set cardsToManifest, boolean cloakNotManifest) { if (cardsToManifest.isEmpty()) { - return false; + return Collections.emptyList(); } // prepare source ability @@ -132,9 +143,10 @@ public class ManifestEffect extends OneShotEffect { // zcc + 1 for use case with Rally the Ancestors (see related test) MageObjectReference objectReference = new MageObjectReference(battlefieldCard.getId(), battlefieldCard.getZoneChangeCounter(game) + 1, game); - game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, FaceDownType.MANIFESTED), newSource); + game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, cloakNotManifest ? FaceDownType.CLOAKED : FaceDownType.MANIFESTED), newSource); } + List manifested = new ArrayList<>(); // move cards to battlefield as face down // TODO: possible buggy for multiple cards, see rule 701.34e - it require manifest one by one (card to check: Omarthis, Ghostfire Initiate) manifestPlayer.moveCards(cardsToManifest, Zone.BATTLEFIELD, source, game, false, true, false, null); @@ -145,18 +157,25 @@ public class ManifestEffect extends OneShotEffect { if (permanent != null) { // TODO: permanent already has manifested status, so code can be deleted later // TODO: add test with battlefield trigger/watcher (must not see normal card, must not see face down status without manifest) - permanent.setManifested(true); + if (cloakNotManifest) { + permanent.setCloaked(true); + } else { + permanent.setManifested(true); + } + manifested.add(permanent); } else { // TODO: looks buggy, card can't be moved to battlefield, but face down effect already active // or it can be face down on another move to battlefield } } - return true; + return manifested; } private String setText() { - StringBuilder sb = new StringBuilder("manifest the top "); + StringBuilder sb = new StringBuilder(); + sb.append(cloakNotManifest ? "cloak" : "manifest"); + sb.append(" the top "); if (isPlural) { sb.append(CardUtil.numberToText(amount.toString())).append(" cards "); } else { diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ManifestTargetPlayerEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ManifestTargetPlayerEffect.java index 599190c855f..271a6992b1a 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/ManifestTargetPlayerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ManifestTargetPlayerEffect.java @@ -40,7 +40,7 @@ public class ManifestTargetPlayerEffect extends OneShotEffect { return false; } - return ManifestEffect.doManifestCards(game, source, targetPlayer, targetPlayer.getLibrary().getTopCards(game, amount)); + return !ManifestEffect.doManifestCards(game, source, targetPlayer, targetPlayer.getLibrary().getTopCards(game, amount)).isEmpty(); } private String setText() { diff --git a/Mage/src/main/java/mage/cards/repository/TokenRepository.java b/Mage/src/main/java/mage/cards/repository/TokenRepository.java index 361d961a4af..8c845da2f4e 100644 --- a/Mage/src/main/java/mage/cards/repository/TokenRepository.java +++ b/Mage/src/main/java/mage/cards/repository/TokenRepository.java @@ -23,6 +23,7 @@ public enum TokenRepository { // - additional card name for controller like "Morph: face up name" public static final String XMAGE_IMAGE_NAME_FACE_DOWN_MANUAL = "Face Down"; public static final String XMAGE_IMAGE_NAME_FACE_DOWN_MANIFEST = "Manifest"; + public static final String XMAGE_IMAGE_NAME_FACE_DOWN_CLOAK = "Cloak"; public static final String XMAGE_IMAGE_NAME_FACE_DOWN_MORPH = "Morph"; public static final String XMAGE_IMAGE_NAME_FACE_DOWN_DISGUISE = "Disguise"; public static final String XMAGE_IMAGE_NAME_FACE_DOWN_FORETELL = "Foretell"; @@ -287,6 +288,10 @@ public enum TokenRepository { // support only 1 image: https://scryfall.com/card/tmkm/21/a-mysterious-creature res.add(createXmageToken(XMAGE_IMAGE_NAME_FACE_DOWN_DISGUISE, 1, "https://api.scryfall.com/cards/tmkm/21/en?format=image")); + // Cloak + // support only 1 image: https://scryfall.com/card/tmkm/21/a-mysterious-creature + res.add(createXmageToken(XMAGE_IMAGE_NAME_FACE_DOWN_CLOAK, 1, "https://api.scryfall.com/cards/tmkm/21/en?format=image")); + // Foretell // https://scryfall.com/search?q=Foretell+unique%3Aprints+otag%3Aassistant-cards&unique=cards&as=grid&order=name res.add(createXmageToken(XMAGE_IMAGE_NAME_FACE_DOWN_FORETELL, 1, "https://api.scryfall.com/cards/tkhm/23/en?format=image")); diff --git a/Mage/src/main/java/mage/game/permanent/Permanent.java b/Mage/src/main/java/mage/game/permanent/Permanent.java index 6ae7a036b65..06c0e6b804d 100644 --- a/Mage/src/main/java/mage/game/permanent/Permanent.java +++ b/Mage/src/main/java/mage/game/permanent/Permanent.java @@ -450,6 +450,10 @@ public interface Permanent extends Card, Controllable { boolean isManifested(); + void setCloaked(boolean value); + + boolean isCloaked(); + boolean isRingBearer(); void setRingBearer(Game game, boolean value); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentCard.java b/Mage/src/main/java/mage/game/permanent/PermanentCard.java index 283f67c1c74..ec70a4df82a 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentCard.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentCard.java @@ -188,6 +188,7 @@ public class PermanentCard extends PermanentImpl { setManifested(false); setMorphed(false); setDisguised(false); + setCloaked(false); return true; } return false; diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index c42b4f278de..cfc625fa242 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -73,6 +73,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { protected boolean renowned; protected boolean suspected; protected boolean manifested = false; + protected boolean cloaked = false; protected boolean morphed = false; protected boolean disguised = false; protected boolean ringBearerFlag = false; @@ -189,6 +190,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.morphed = permanent.morphed; this.disguised = permanent.disguised; this.manifested = permanent.manifested; + this.cloaked = permanent.cloaked; this.createOrder = permanent.createOrder; this.prototyped = permanent.prototyped; this.canBeSacrificed = permanent.canBeSacrificed; @@ -1905,6 +1907,16 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { manifested = value; } + @Override + public boolean isCloaked() { + return cloaked; + } + + @Override + public void setCloaked(boolean value) { + cloaked = value; + } + @Override public boolean isMorphed() { return morphed;