diff --git a/Mage.Sets/src/mage/cards/s/Spellskite.java b/Mage.Sets/src/mage/cards/s/Spellskite.java index 8b10e2afdc7..c2e22763600 100644 --- a/Mage.Sets/src/mage/cards/s/Spellskite.java +++ b/Mage.Sets/src/mage/cards/s/Spellskite.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -14,7 +13,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; import mage.game.stack.Spell; import mage.game.stack.StackAbility; @@ -76,8 +74,7 @@ class SpellskiteEffect extends OneShotEffect { Spell spell = (Spell) stackObject; sourceAbility = spell.getSpellAbility(); } else if (stackObject instanceof StackAbility) { - StackAbility stackAbility = (StackAbility) stackObject; - sourceAbility = stackAbility; + sourceAbility = (StackAbility) stackObject; } else { return false; } @@ -86,7 +83,6 @@ class SpellskiteEffect extends OneShotEffect { targets.addAll(mode.getTargets()); } - boolean twoTimesTarget = false; if (targets.size() == 1 && targets.get(0).getTargets().size() == 1) { Target target = targets.get(0); if (target.getFirstTarget().equals(source.getSourceId())) { @@ -134,10 +130,9 @@ class SpellskiteEffect extends OneShotEffect { } if (oldTargetName != null) { game.informPlayers(sourceObject.getLogName() + ": Changed target of " + stackObject.getLogName() + " from " + oldTargetName + " to " + sourceObject.getLogName()); - } else if (twoTimesTarget) { - game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its not valid to target it twice for " + stackObject.getLogName()); - } else { - game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getLogName()); + } + else { + game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because it's not a valid target for " + stackObject.getLogName()); } return true; } diff --git a/Mage.Sets/src/mage/cards/t/TheSoulStone.java b/Mage.Sets/src/mage/cards/t/TheSoulStone.java new file mode 100644 index 00000000000..252ea24aafa --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheSoulStone.java @@ -0,0 +1,67 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.ExileTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.HarnessSourceEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.continuous.GainHarnessedAbilitySourceEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * + * @author Jmlundeen + */ +public final class TheSoulStone extends CardImpl { + + public TheSoulStone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.INFINITY); + this.subtype.add(SubType.STONE); + + // Indestructible + this.addAbility(IndestructibleAbility.getInstance()); + + // {T}: Add {B}. + this.addAbility(new BlackManaAbility()); + + // {6}{B}, {T}, Exile a creature you control: Harness The Soul Stone. + Ability ability = new SimpleActivatedAbility(new HarnessSourceEffect(), new ManaCostsImpl<>("{6}{B}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE))); + this.addAbility(ability); + + // ∞ -- At the beginning of your upkeep, return target creature card from your graveyard to the battlefield. + Ability soulStoneAbility = new BeginningOfUpkeepTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()); + soulStoneAbility.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(new SimpleStaticAbility( + new GainHarnessedAbilitySourceEffect(soulStoneAbility)) + ); + } + + private TheSoulStone(final TheSoulStone card) { + super(card); + } + + @Override + public TheSoulStone copy() { + return new TheSoulStone(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 8d8db43064d..6479f72823e 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -1,7 +1,6 @@ package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.s.SilkWebWeaver; import mage.constants.Rarity; import mage.constants.SetType; @@ -25,6 +24,8 @@ public final class MarvelsSpiderMan extends ExpansionSet { this.blockName = "Marvel's Spider-Man"; // for sorting in GUI this.hasBasicLands = true; + this.enablePlayBooster(Integer.MAX_VALUE); + cards.add(new SetCardInfo("Agent Venom", 255, Rarity.RARE, mage.cards.a.AgentVenom.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Agent Venom", 49, Rarity.RARE, mage.cards.a.AgentVenom.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Alien Symbiosis", 50, Rarity.UNCOMMON, mage.cards.a.AlienSymbiosis.class)); @@ -74,7 +75,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Ezekiel Sims, Spider-Totem", 100, Rarity.UNCOMMON, mage.cards.e.EzekielSimsSpiderTotem.class)); cards.add(new SetCardInfo("Flash Thompson, Spider-Fan", 7, Rarity.UNCOMMON, mage.cards.f.FlashThompsonSpiderFan.class)); cards.add(new SetCardInfo("Flying Octobot", 31, Rarity.UNCOMMON, mage.cards.f.FlyingOctobot.class)); - cards.add(new SetCardInfo("Forest", 193, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 193, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Friendly Neighborhood", 246, Rarity.RARE, mage.cards.f.FriendlyNeighborhood.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Friendly Neighborhood", 8, Rarity.RARE, mage.cards.f.FriendlyNeighborhood.class, NON_FULL_USE_VARIOUS)); @@ -140,7 +141,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Morbius the Living Vampire", 137, Rarity.UNCOMMON, mage.cards.m.MorbiusTheLivingVampire.class)); cards.add(new SetCardInfo("Morlun, Devourer of Spiders", 257, Rarity.RARE, mage.cards.m.MorlunDevourerOfSpiders.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Morlun, Devourer of Spiders", 59, Rarity.RARE, mage.cards.m.MorlunDevourerOfSpiders.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 192, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 192, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", 197, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Multiversal Passage", 180, Rarity.RARE, mage.cards.m.MultiversalPassage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Multiversal Passage", 206, Rarity.RARE, mage.cards.m.MultiversalPassage.class, NON_FULL_USE_VARIOUS)); @@ -165,7 +166,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Peter Parker's Camera", 171, Rarity.RARE, mage.cards.p.PeterParkersCamera.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Peter Parker's Camera", 280, Rarity.RARE, mage.cards.p.PeterParkersCamera.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Pictures of Spider-Man", 109, Rarity.UNCOMMON, mage.cards.p.PicturesOfSpiderMan.class)); - cards.add(new SetCardInfo("Plains", 189, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 189, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Prison Break", 61, Rarity.UNCOMMON, mage.cards.p.PrisonBreak.class)); cards.add(new SetCardInfo("Professional Wrestler", 110, Rarity.COMMON, mage.cards.p.ProfessionalWrestler.class)); @@ -202,8 +203,8 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Shocker, Unshakable", 89, Rarity.UNCOMMON, mage.cards.s.ShockerUnshakable.class)); cards.add(new SetCardInfo("Shriek, Treblemaker", 144, Rarity.UNCOMMON, mage.cards.s.ShriekTreblemaker.class)); - cards.add(new SetCardInfo("Silk, Web Weaver", 145, Rarity.RARE, SilkWebWeaver.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Silk, Web Weaver", 215, Rarity.RARE, SilkWebWeaver.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Silk, Web Weaver", 145, Rarity.RARE, mage.cards.s.SilkWebWeaver.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Silk, Web Weaver", 215, Rarity.RARE, mage.cards.s.SilkWebWeaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Silver Sable, Mercenary Leader", 13, Rarity.UNCOMMON, mage.cards.s.SilverSableMercenaryLeader.class)); cards.add(new SetCardInfo("Sinister Hideout", 184, Rarity.COMMON, mage.cards.s.SinisterHideout.class)); cards.add(new SetCardInfo("Skyward Spider", 146, Rarity.COMMON, mage.cards.s.SkywardSpider.class)); @@ -264,7 +265,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Superior Spider-Man", 155, Rarity.RARE, mage.cards.s.SuperiorSpiderMan.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Superior Spider-Man", 275, Rarity.RARE, mage.cards.s.SuperiorSpiderMan.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Supportive Parents", 119, Rarity.UNCOMMON, mage.cards.s.SupportiveParents.class)); - cards.add(new SetCardInfo("Swamp", 191, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 191, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swarm, Being of Bees", 69, Rarity.COMMON, mage.cards.s.SwarmBeingOfBees.class)); cards.add(new SetCardInfo("Symbiote Spider-Man", 156, Rarity.RARE, mage.cards.s.SymbioteSpiderMan.class, NON_FULL_USE_VARIOUS)); @@ -275,6 +276,9 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("The Clone Saga", 28, Rarity.RARE, mage.cards.t.TheCloneSaga.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Death of Gwen Stacy", 223, Rarity.RARE, mage.cards.t.TheDeathOfGwenStacy.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("The Death of Gwen Stacy", 54, Rarity.RARE, mage.cards.t.TheDeathOfGwenStacy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Soul Stone", 242, Rarity.MYTHIC, mage.cards.t.TheSoulStone.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Soul Stone", 243, Rarity.MYTHIC, mage.cards.t.TheSoulStone.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Soul Stone", 66, Rarity.MYTHIC, mage.cards.t.TheSoulStone.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Spot's Portal", 68, Rarity.UNCOMMON, mage.cards.t.TheSpotsPortal.class)); cards.add(new SetCardInfo("The Spot, Living Portal", 153, Rarity.RARE, mage.cards.t.TheSpotLivingPortal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Spot, Living Portal", 231, Rarity.RARE, mage.cards.t.TheSpotLivingPortal.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/TheSoulStoneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/TheSoulStoneTest.java new file mode 100644 index 00000000000..c61b8fc1655 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/TheSoulStoneTest.java @@ -0,0 +1,121 @@ +package org.mage.test.cards.single.spm; + +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.Card; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertTrue; + +/** + * + * @author Jmlundeen + */ +public class TheSoulStoneTest extends CardTestPlayerBase { + + /* + The Soul Stone + {1}{B} + Legendary Artifact - Infinity Stone + Indestructible + {T}: Add {B}. + {6}{B}, {T}, Exile a creature you control: Harness The Soul Stone. + ∞ -- At the beginning of your upkeep, return target creature card from your graveyard to the battlefield. + */ + private static final String theSoulStone = "The Soul Stone"; + + /* + Bear Cub + {1}{G} + Creature - Bear + + 2/2 + */ + private static final String bearCub = "Bear Cub"; + + /* + Teferi's Time Twist + {1}{U} + Instant + Exile target permanent you control. Return that card to the battlefield under its owner's control at the beginning of the next end step. If it enters the battlefield as a creature, it enters with an additional +1/+1 counter on it. + */ + private static final String teferisTimeTwist = "Teferi's Time Twist"; + + @Test + public void testTheSoulStone() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, theSoulStone); + addCard(Zone.BATTLEFIELD, playerA, bearCub); + addCard(Zone.GRAVEYARD, playerA, bearCub); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{6}{B}, {T}"); + setChoice(playerA, bearCub); // exile as cost + addTarget(playerA, bearCub); // return to battlefield + + setStopAt(3, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, bearCub, 1); + assertExileCount(playerA, bearCub, 1); + // doesn't have ability if blinked + assertAbilityCount(playerA, theSoulStone, BeginningOfUpkeepTriggeredAbility.class, 1); + } + + @Test + public void testBlinkSoulStone() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, theSoulStone); + addCard(Zone.BATTLEFIELD, playerA, bearCub); + addCard(Zone.GRAVEYARD, playerA, bearCub); + addCard(Zone.HAND, playerA, teferisTimeTwist); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7); + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{6}{B}, {T}"); + setChoice(playerA, bearCub); + + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, teferisTimeTwist, theSoulStone); + + setStopAt(3, PhaseStep.END_TURN); + execute(); + + assertExileCount(playerA, bearCub, 1); + assertPermanentCount(playerA, bearCub, 0); + assertGraveyardCount(playerA, bearCub, 1); + // doesn't have ability if blinked + assertAbilityCount(playerA, theSoulStone, BeginningOfUpkeepTriggeredAbility.class, 0); + } + + @Test + public void testSoulStoneHasNoInfinityAbility() { + setStrictChooseMode(true); + removeAllCardsFromLibrary(playerA); + + addCard(Zone.HAND, playerA, theSoulStone); + addCard(Zone.LIBRARY, playerA, theSoulStone); + addCard(Zone.GRAVEYARD, playerA, theSoulStone); + addCard(Zone.EXILED, playerA, theSoulStone); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + List cards = new ArrayList<>(getHandCards(playerA)); + cards.addAll(getLibraryCards(playerA)); + cards.addAll(getGraveCards(playerA)); + cards.addAll(getExiledCards(playerA)); + + cards.forEach(card -> { + if (card.getName().equals(theSoulStone)) { + assertTrue("Should not have Infinity ability", !card.getAbilities(currentGame).containsClass(BeginningOfUpkeepTriggeredAbility.class)); + } + }); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceHarnessedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceHarnessedCondition.java new file mode 100644 index 00000000000..7d5de8a4545 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceHarnessedCondition.java @@ -0,0 +1,25 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author Jmlundee + */ + +public enum SourceHarnessedCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + return permanent != null && permanent.isHarnessed(); + } + + @Override + public String toString() { + return "{this} is harnessed"; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java new file mode 100644 index 00000000000..a47aa31f40b --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java @@ -0,0 +1,37 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author Jmlundeen + */ +public class HarnessSourceEffect extends OneShotEffect { + + public HarnessSourceEffect() { + super(Outcome.AIDontUseIt); + staticText = "Harness {this}. (Once harnessed, its ∞ ability is active.)"; + } + + protected HarnessSourceEffect(final HarnessSourceEffect effect) { + super(effect); + } + + @Override + public HarnessSourceEffect copy() { + return new HarnessSourceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + permanent.setHarnessed(true); + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainHarnessedAbilitySourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainHarnessedAbilitySourceEffect.java new file mode 100644 index 00000000000..157a05bdb5b --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainHarnessedAbilitySourceEffect.java @@ -0,0 +1,58 @@ +package mage.abilities.effects.common.continuous; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author Jmlundeen + */ +public class GainHarnessedAbilitySourceEffect extends ContinuousEffectImpl { + + private final Ability ability; + + public GainHarnessedAbilitySourceEffect(Effect effect) { + this(new SimpleStaticAbility(effect)); + } + + public GainHarnessedAbilitySourceEffect(Ability ability) { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = ability.getRule(); + this.ability = ability; + this.ability.setRuleVisible(false); + generateGainAbilityDependencies(ability, null); + } + + private GainHarnessedAbilitySourceEffect(final GainHarnessedAbilitySourceEffect effect) { + super(effect); + this.ability = effect.ability; + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null || !permanent.isHarnessed()) { + return false; + } + permanent.addAbility(ability, source.getSourceId(), game); + return true; + } + + @Override + public GainHarnessedAbilitySourceEffect copy() { + return new GainHarnessedAbilitySourceEffect(this); + } + + @Override + public String getText(Mode mode) { + return "∞ — " + super.getText(mode); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/Permanent.java b/Mage/src/main/java/mage/game/permanent/Permanent.java index 73075f8f663..3b88aff182b 100644 --- a/Mage/src/main/java/mage/game/permanent/Permanent.java +++ b/Mage/src/main/java/mage/game/permanent/Permanent.java @@ -470,6 +470,10 @@ public interface Permanent extends Card, Controllable { boolean solve(Game game, Ability source); + boolean isHarnessed(); + + void setHarnessed(boolean value); + @Override Permanent copy(); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index c4a812dc4cb..23422c76a64 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -72,6 +72,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { protected boolean monstrous; protected boolean renowned; protected boolean suspected; + protected boolean harnessed = false; protected boolean manifested = false; protected boolean cloaked = false; protected boolean morphed = false; @@ -176,6 +177,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.monstrous = permanent.monstrous; this.renowned = permanent.renowned; this.suspected = permanent.suspected; + this.harnessed = permanent.harnessed; this.ringBearerFlag = permanent.ringBearerFlag; this.classLevel = permanent.classLevel; this.goadingPlayers.addAll(permanent.goadingPlayers); @@ -2004,6 +2006,16 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return true; } + @Override + public boolean isHarnessed() { + return this.harnessed; + } + + @Override + public void setHarnessed(boolean value) { + this.harnessed = value; + } + @Override public boolean fight(Permanent fightTarget, Ability source, Game game) { return this.fight(fightTarget, source, game, true);