diff --git a/Mage.Sets/src/mage/cards/h/HourglassOfTheLost.java b/Mage.Sets/src/mage/cards/h/HourglassOfTheLost.java new file mode 100644 index 00000000000..60e57a33da5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HourglassOfTheLost.java @@ -0,0 +1,97 @@ +package mage.cards.h; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.*; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInGraveyard; +import mage.util.CardUtil; + +/** + * + * @author grimreap124 + */ +public final class HourglassOfTheLost extends CardImpl { + + + public HourglassOfTheLost(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}"); + + // {T}: Add {W}. Put a time counter on Hourglass of the Lost. + Ability ability = new WhiteManaAbility(); + ability.addEffect(new AddCountersSourceEffect(CounterType.TIME.createInstance())); + this.addAbility(ability); + // {T}, Remove X time counters from Hourglass of the Lost and exile it: Return each nonland permanent card with mana value X from your graveyard to the battlefield. Activate only as a sorcery. + Ability returnAbility = new ActivateAsSorceryActivatedAbility(new HourglassOfTheLostEffect(), null); + returnAbility.addCost(new TapSourceCost()); + returnAbility.addCost(new RemoveVariableCountersSourceCost(CounterType.TIME)); + returnAbility.addCost(new ExileSourceCost().setText("and exile it")); + this.addAbility(returnAbility); + } + + private HourglassOfTheLost(final HourglassOfTheLost card) { + super(card); + } + + @Override + public HourglassOfTheLost copy() { + return new HourglassOfTheLost(this); + } +} + +class HourglassOfTheLostEffect extends OneShotEffect { + + HourglassOfTheLostEffect() { + super(Outcome.Benefit); + this.staticText = "Return each nonland permanent card with mana value X from your graveyard to the battlefield."; + } + + private HourglassOfTheLostEffect(final HourglassOfTheLostEffect effect) { + super(effect); + } + + @Override + public HourglassOfTheLostEffect copy() { + return new HourglassOfTheLostEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + FilterCard filter = new FilterNonlandCard(); + int xValue = CardUtil.getSourceCostsTag(game, source, "X", 0); + game.informPlayers(xValue + " Time counters removed"); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, xValue)); + return controller.moveCards(controller.getGraveyard().getCards(filter, game), Zone.BATTLEFIELD, source, game); + } + game.informPlayers("controller is null"); + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons3Commander.java b/Mage.Sets/src/mage/sets/ModernHorizons3Commander.java index 75b160e0e42..be21bb6e03b 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons3Commander.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons3Commander.java @@ -157,6 +157,7 @@ public final class ModernHorizons3Commander extends ExpansionSet { cards.add(new SetCardInfo("Hideous Taskmaster", 57, Rarity.RARE, mage.cards.h.HideousTaskmaster.class)); cards.add(new SetCardInfo("Horizon of Progress", 78, Rarity.RARE, mage.cards.h.HorizonOfProgress.class)); cards.add(new SetCardInfo("Hour of Promise", 232, Rarity.RARE, mage.cards.h.HourOfPromise.class)); + cards.add(new SetCardInfo("Hourglass of the Lost", 40, Rarity.RARE, mage.cards.h.HourglassOfTheLost.class)); cards.add(new SetCardInfo("Hydra Broodmaster", 233, Rarity.RARE, mage.cards.h.HydraBroodmaster.class)); cards.add(new SetCardInfo("Hydroid Krasis", 266, Rarity.RARE, mage.cards.h.HydroidKrasis.class)); cards.add(new SetCardInfo("Idol of Oblivion", 297, Rarity.UNCOMMON, mage.cards.i.IdolOfOblivion.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/m3c/HourglassOfTheLostTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/m3c/HourglassOfTheLostTest.java new file mode 100644 index 00000000000..b9f3e149385 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/m3c/HourglassOfTheLostTest.java @@ -0,0 +1,45 @@ +package org.mage.test.cards.single.m3c; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author Susucr + */ +public class HourglassOfTheLostTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.h.HourglassOfTheLost HourglassOfTheLost} {2}{U} + */ + private static final String hourglass = "Hourglass of the Lost"; + + @Test + public void test_Simple() { + setStrictChooseMode(true); + skipInitShuffling(); + + addCard(Zone.BATTLEFIELD, playerA, hourglass); + addCard(Zone.GRAVEYARD, playerA, "Birds of Paradise"); // Mana value 1 + addCard(Zone.GRAVEYARD, playerA, "+2 Mace"); // Mana value 2 + + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {W}"); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + assertCounterCount(playerA, hourglass, CounterType.TIME,1); + assertExileCount(playerA, 0); + assertGraveyardCount(playerA, 2); + + setChoiceAmount(playerA, 1); // Remove 1 counter + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Remove X"); // Return all with mana value 1 + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + + execute(); + assertExileCount(playerA, 1); + assertGraveyardCount(playerA, 1); // +2 Mace still in graveyard + assertPermanentCount(playerA, "Birds of Paradise", 1); + + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index af9c1ec624e..bea01c9d349 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -644,7 +644,12 @@ public abstract class AbilityImpl implements Ability { if (!(variableCost instanceof VariableManaCost) && !((Cost) variableCost).isPaid()) { int xValue = variableCost.announceXValue(this, game); Cost fixedCost = variableCost.getFixedCostsFromAnnouncedValue(xValue); - addCost(fixedCost); + int index = getCosts().indexOf(variableCost); + if (index == -1) { + addCost(fixedCost); + } else { + addCost(fixedCost, index + 1); + } // set the xcosts to paid variableCost.setAmount(xValue, xValue, false); ((Cost) variableCost).setPaid(); @@ -1076,6 +1081,31 @@ public abstract class AbilityImpl implements Ability { } } + public void addCost(Cost cost, int index) { + if (cost == null) { + return; + } + if (cost instanceof Costs) { + // as list of costs + Costs list = (Costs) cost; + for (Cost single : list) { + addCost(single, index); + } + } else { + // as single cost + if (cost instanceof ManaCost) { + manaCosts.add((ManaCost) cost); + manaCostsToPay.add((ManaCost) cost); + } else { + if (index > costs.size()) { + costs.add(cost); + } else { + costs.add(index, cost); + } + } + } + } + @Override public void addManaCostsToPay(ManaCost manaCost) { if (manaCost == null) {