diff --git a/Mage.Sets/src/mage/cards/b/BladeOfTheOni.java b/Mage.Sets/src/mage/cards/b/BladeOfTheOni.java index 44eb5f337a..ed6a5b035e 100644 --- a/Mage.Sets/src/mage/cards/b/BladeOfTheOni.java +++ b/Mage.Sets/src/mage/cards/b/BladeOfTheOni.java @@ -28,7 +28,7 @@ public final class BladeOfTheOni extends CardImpl { this.toughness = new MageInt(1); // Menace - this.addAbility(new MenaceAbility()); + this.addAbility(new MenaceAbility(false)); // Equipped creature has base power and toughness 5/5, has menace, and is a black Demon in addition to its other colors and types. this.addAbility(new SimpleStaticAbility(new BladeOfTheOniEffect())); diff --git a/Mage.Sets/src/mage/cards/b/BronzeplateBoar.java b/Mage.Sets/src/mage/cards/b/BronzeplateBoar.java index 68e64d1fbe..8895f8b47f 100644 --- a/Mage.Sets/src/mage/cards/b/BronzeplateBoar.java +++ b/Mage.Sets/src/mage/cards/b/BronzeplateBoar.java @@ -36,6 +36,7 @@ public final class BronzeplateBoar extends CardImpl { ability.addEffect(new GainAbilityAttachedEffect( TrampleAbility.getInstance(), AttachmentType.EQUIPMENT ).setText("and has trample")); + this.addAbility(ability); // Reconfigure {5} this.addAbility(new ReconfigureAbility("{5}")); diff --git a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java index e8e6b7c785..940ed43364 100644 --- a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java +++ b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java @@ -4,15 +4,11 @@ import mage.cards.ExpansionSet; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.Arrays; -import java.util.List; - /** * @author TheElk801 */ public final class KamigawaNeonDynasty extends ExpansionSet { - private static final List unfinished = Arrays.asList("Acquisition Octopus", "Armguard Familiar", "Blade of the Oni", "Bronzeplate Boar", "Chainflail Centipede", "Cloudsteel Kirin", "Leech Gauntlet", "Lion Sash", "Lizard Blades", "Ogre-Head Helm", "Rabbit Battery", "Simian Sling", "The Reality Chip", "Webspinner Cuff"); private static final KamigawaNeonDynasty instance = new KamigawaNeonDynasty(); public static KamigawaNeonDynasty getInstance() { @@ -285,7 +281,5 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("When We Were Young", 43, Rarity.UNCOMMON, mage.cards.w.WhenWeWereYoung.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 282, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); cards.add(new SetCardInfo("You Are Already Dead", 129, Rarity.COMMON, mage.cards.y.YouAreAlreadyDead.class)); - - cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); // remove when mechanic is fully implemented } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/ReconfigureTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/ReconfigureTest.java new file mode 100644 index 0000000000..887a8604b3 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/ReconfigureTest.java @@ -0,0 +1,82 @@ +package org.mage.test.cards.abilities.activated; + +import mage.abilities.keyword.TrampleAbility; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.SubType; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class ReconfigureTest extends CardTestPlayerBase { + + private static final String lion = "Silvercoat Lion"; + private static final String boar = "Bronzeplate Boar"; + private static final String aid = "Sigarda's Aid"; + + @Test + public void testAttach() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.BATTLEFIELD, playerA, boar); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reconfigure", lion); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertType(boar, CardType.CREATURE, false); + assertSubtype(boar, SubType.EQUIPMENT); + assertIsAttachedTo(playerA, boar, lion); + assertPowerToughness(playerA, lion, 2 + 3, 2 + 2); + assertAbility(playerA, lion, TrampleAbility.getInstance(), true); + } + + @Test + public void testAttachDetach() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.BATTLEFIELD, playerA, boar); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reconfigure", lion); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{5}:"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertType(boar, CardType.CREATURE, true); + assertSubtype(boar, SubType.EQUIPMENT); + assertPowerToughness(playerA, lion, 2, 2); + assertAbility(playerA, lion, TrampleAbility.getInstance(), false); + } + + @Test + public void testSigardasAid() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.BATTLEFIELD, playerA, aid); + addCard(Zone.HAND, playerA, boar); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, boar); + addTarget(playerA, lion); + setChoice(playerA, true); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertType(boar, CardType.CREATURE, false); + assertSubtype(boar, SubType.EQUIPMENT); + assertIsAttachedTo(playerA, boar, lion); + assertPowerToughness(playerA, lion, 2 + 3, 2 + 2); + assertAbility(playerA, lion, TrampleAbility.getInstance(), true); + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/ReconfigureAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReconfigureAbility.java index 15cfaa9a39..eb7bc2bb4e 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReconfigureAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReconfigureAbility.java @@ -1,7 +1,17 @@ package mage.abilities.keyword; +import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; -import mage.constants.Zone; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; /** * @author TheElk801 @@ -11,9 +21,14 @@ public class ReconfigureAbility extends ActivatedAbilityImpl { private final String manaString; public ReconfigureAbility(String manaString) { - super(Zone.BATTLEFIELD, null); + super(Zone.BATTLEFIELD, new AttachEffect(Outcome.BoostCreature), new ManaCostsImpl<>(manaString)); this.manaString = manaString; - // TODO: Implement this + this.timing = TimingRule.SORCERY; + this.addTarget(new TargetControlledCreaturePermanent()); + this.addSubAbility(new ReconfigureUnattachAbility(manaString)); + Ability ability = new SimpleStaticAbility(new ReconfigureTypeEffect()); + ability.setRuleVisible(false); + this.addSubAbility(ability); } private ReconfigureAbility(final ReconfigureAbility ability) { @@ -31,6 +46,75 @@ public class ReconfigureAbility extends ActivatedAbilityImpl { return "Reconfigure " + manaString + " (" + manaString + ": Attach to target creature you control; " + "or unattach from a creature. Reconfigure only as a sorcery. " + - "While attached, this isn’t a creature.)"; + "While attached, this isn't a creature.)"; + } +} + +class ReconfigureUnattachAbility extends ActivateAsSorceryActivatedAbility { + + protected ReconfigureUnattachAbility(String manaString) { + super(Zone.BATTLEFIELD, new ReconfigureUnattachEffect(), new ManaCostsImpl<>(manaString)); + this.setRuleVisible(true); + } + + private ReconfigureUnattachAbility(final ReconfigureUnattachAbility ability) { + super(ability); + } + + @Override + public ReconfigureUnattachAbility copy() { + return new ReconfigureUnattachAbility(this); + } +} + +class ReconfigureUnattachEffect extends OneShotEffect { + + ReconfigureUnattachEffect() { + super(Outcome.Benefit); + staticText = "unattach {this}"; + } + + private ReconfigureUnattachEffect(final ReconfigureUnattachEffect effect) { + super(effect); + } + + @Override + public ReconfigureUnattachEffect copy() { + return new ReconfigureUnattachEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent != null) { + permanent.unattach(game); + } + return true; + } +} + +class ReconfigureTypeEffect extends ContinuousEffectImpl { + + ReconfigureTypeEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + } + + private ReconfigureTypeEffect(final ReconfigureTypeEffect effect) { + super(effect); + } + + @Override + public ReconfigureTypeEffect copy() { + return new ReconfigureTypeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null || game.getPermanent(permanent.getAttachedTo()) == null) { + return false; + } + permanent.removeCardType(game, CardType.CREATURE); + return true; } }