diff --git a/Mage.Sets/src/mage/cards/b/BenevolentRiverSpirit.java b/Mage.Sets/src/mage/cards/b/BenevolentRiverSpirit.java index 8302c8ec223..6a4985504b2 100644 --- a/Mage.Sets/src/mage/cards/b/BenevolentRiverSpirit.java +++ b/Mage.Sets/src/mage/cards/b/BenevolentRiverSpirit.java @@ -33,7 +33,7 @@ public final class BenevolentRiverSpirit extends CardImpl { this.getSpellAbility().addCost(new WaterbendCost(5)); this.addAbility(new SimpleStaticAbility( Zone.ALL, new InfoEffect("as an additional cost to cast this spell, waterbend {5}") - )); + ).setRuleAtTheTop(true)); // Flying this.addAbility(FlyingAbility.getInstance()); diff --git a/Mage.Sets/src/mage/cards/c/CrashingWave.java b/Mage.Sets/src/mage/cards/c/CrashingWave.java index 0b29c86770e..f4815dd3d1e 100644 --- a/Mage.Sets/src/mage/cards/c/CrashingWave.java +++ b/Mage.Sets/src/mage/cards/c/CrashingWave.java @@ -1,13 +1,16 @@ package mage.cards.c; import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.WaterbendXCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterOpponentsCreaturePermanent; @@ -31,6 +34,9 @@ public final class CrashingWave extends CardImpl { // As an additional cost to cast this spell, waterbend {X}. this.getSpellAbility().addCost(new WaterbendXCost()); + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new InfoEffect("as an additional cost to cast this spell, waterbend {X}") + ).setRuleAtTheTop(true)); // Tap up to X target creatures, then distribute three stun counters among tapped creatures your opponents control. this.getSpellAbility().addEffect(new TapTargetEffect("tap up to X target creatures")); @@ -79,7 +85,7 @@ class CrashingWaveEffect extends OneShotEffect { } TargetPermanentAmount target = new TargetPermanentAmount(3, 1, filter); target.withNotTarget(true); - player.chooseTarget(outcome, target, source, game); + target.chooseTarget(outcome, player.getId(), source, game); for (UUID targetId : target.getTargets()) { Optional.ofNullable(targetId) .map(game::getPermanent) diff --git a/Mage.Sets/src/mage/cards/f/FoggySwampVisions.java b/Mage.Sets/src/mage/cards/f/FoggySwampVisions.java index 81ba443a62f..72ac7cb4022 100644 --- a/Mage.Sets/src/mage/cards/f/FoggySwampVisions.java +++ b/Mage.Sets/src/mage/cards/f/FoggySwampVisions.java @@ -1,11 +1,12 @@ package mage.cards.f; import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.costs.common.WaterbendCost; import mage.abilities.costs.common.WaterbendXCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.cards.*; import mage.constants.CardType; @@ -35,6 +36,9 @@ public final class FoggySwampVisions extends CardImpl { // As an additional cost to cast this spell, waterbend {X}. this.getSpellAbility().addCost(new WaterbendXCost()); + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new InfoEffect("as an additional cost to cast this spell, waterbend {X}") + ).setRuleAtTheTop(true)); // Exile X target creature cards from graveyards. For each creature card exiled this way, create a token that's a copy of it. At the beginning of your next end step, sacrifice those tokens. this.getSpellAbility().addEffect(new FoggySwampVisionsEffect()); diff --git a/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java b/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java index 572857358d2..c8e25cc4cf0 100644 --- a/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java +++ b/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java @@ -6,7 +6,6 @@ import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.WaterbendXCost; -import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.InfoEffect; @@ -20,7 +19,6 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.StaticFilters; import mage.game.permanent.token.AllyToken; -import mage.util.CardUtil; import java.util.UUID; @@ -49,9 +47,8 @@ public final class KataraWaterTribesHope extends CardImpl { Ability ability = new ActivateIfConditionActivatedAbility(new SetBasePowerToughnessAllEffect( GetXValue.instance, GetXValue.instance, Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES - ), new WaterbendXCost(), MyTurnCondition.instance); + ), new WaterbendXCost(1), MyTurnCondition.instance); ability.addEffect(new InfoEffect("X can't be 0")); - CardUtil.castStream(ability.getCosts(), VariableManaCost.class).forEach(cost -> cost.setMinX(1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WaterWhip.java b/Mage.Sets/src/mage/cards/w/WaterWhip.java index 204e3e59992..5917a472da4 100644 --- a/Mage.Sets/src/mage/cards/w/WaterWhip.java +++ b/Mage.Sets/src/mage/cards/w/WaterWhip.java @@ -28,7 +28,7 @@ public final class WaterWhip extends CardImpl { this.getSpellAbility().addCost(new WaterbendCost(5)); this.addAbility(new SimpleStaticAbility( Zone.ALL, new InfoEffect("as an additional cost to cast this spell, waterbend {5}") - )); + ).setRuleAtTheTop(true)); // Return up to two target creatures to their owners' hands. Draw two cards. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/w/WaterbendersRestoration.java b/Mage.Sets/src/mage/cards/w/WaterbendersRestoration.java index 34a6b9cf34d..a8ae100f9f5 100644 --- a/Mage.Sets/src/mage/cards/w/WaterbendersRestoration.java +++ b/Mage.Sets/src/mage/cards/w/WaterbendersRestoration.java @@ -1,11 +1,14 @@ package mage.cards.w; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.WaterbendXCost; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetadjustment.XTargetsCountAdjuster; @@ -23,6 +26,9 @@ public final class WaterbendersRestoration extends CardImpl { // As an additional cost to cast this spell, waterbend {X}. this.getSpellAbility().addCost(new WaterbendXCost()); + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new InfoEffect("as an additional cost to cast this spell, waterbend {X}") + ).setRuleAtTheTop(true)); // Exile X target creatures you control. Return those cards to the battlefield under their owner's control at the beginning of the next end step. this.getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect() diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index bbf51847206..4d0f3cec930 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -8,6 +8,7 @@ import mage.abilities.condition.Condition; import mage.abilities.costs.*; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.costs.common.WaterbendXCost; import mage.abilities.costs.mana.*; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; @@ -814,54 +815,59 @@ public abstract class AbilityImpl implements Ability { } } } - if (variableManaCost != null) { - if (!variableManaCost.isPaid()) { // should only happen for human players - int xValue; - if (!noMana || variableManaCost.getCostType().canUseAnnounceOnFreeCast()) { - if (variableManaCost.wasAnnounced()) { - // announce by rules - xValue = variableManaCost.getAmount(); - } else { - // announce by player - xValue = controller.announceX(variableManaCost.getMinX(), variableManaCost.getMaxX(), - "Announce the value for " + variableManaCost.getText(), game, this, true); - } - - int amountMana = xValue * variableManaCost.getXInstancesCount(); - StringBuilder manaString = threadLocalBuilder.get(); - if (variableManaCost.getFilter() == null || variableManaCost.getFilter().isGeneric()) { - manaString.append('{').append(amountMana).append('}'); - } else { - String manaSymbol = null; - if (variableManaCost.getFilter().isBlack()) { - if (variableManaCost.getFilter().isRed()) { - manaSymbol = "B/R"; - } else { - manaSymbol = "B"; - } - } else if (variableManaCost.getFilter().isRed()) { - manaSymbol = "R"; - } else if (variableManaCost.getFilter().isBlue()) { - manaSymbol = "U"; - } else if (variableManaCost.getFilter().isGreen()) { - manaSymbol = "G"; - } else if (variableManaCost.getFilter().isWhite()) { - manaSymbol = "W"; - } - if (manaSymbol == null) { - throw new UnsupportedOperationException("ManaFilter is not supported: " + this); - } - for (int i = 0; i < amountMana; i++) { - manaString.append('{').append(manaSymbol).append('}'); - } - } - addManaCostsToPay(new ManaCostsImpl<>(manaString.toString())); - getManaCostsToPay().setX(xValue, amountMana); - setCostsTag("X", xValue); - } - variableManaCost.setPaid(); - } + if (variableManaCost == null) { + return variableManaCost; } + if (variableManaCost.isPaid()) { + return variableManaCost; + } // should only happen for human players + int xValue; + if (!noMana || variableManaCost.getCostType().canUseAnnounceOnFreeCast()) { + if (variableManaCost.wasAnnounced()) { + // announce by rules + xValue = variableManaCost.getAmount(); + } else { + // announce by player + xValue = controller.announceX(variableManaCost.getMinX(), variableManaCost.getMaxX(), + "Announce the value for " + variableManaCost.getText(), game, this, true); + } + + int amountMana = xValue * variableManaCost.getXInstancesCount(); + StringBuilder manaString = threadLocalBuilder.get(); + if (!(variableManaCost instanceof WaterbendXCost)) { + if (variableManaCost.getFilter() == null || variableManaCost.getFilter().isGeneric()) { + manaString.append('{').append(amountMana).append('}'); + } else { + String manaSymbol; + if (variableManaCost.getFilter().isBlack()) { + if (variableManaCost.getFilter().isRed()) { + manaSymbol = "B/R"; + } else { + manaSymbol = "B"; + } + } else if (variableManaCost.getFilter().isRed()) { + manaSymbol = "R"; + } else if (variableManaCost.getFilter().isBlue()) { + manaSymbol = "U"; + } else if (variableManaCost.getFilter().isGreen()) { + manaSymbol = "G"; + } else if (variableManaCost.getFilter().isWhite()) { + manaSymbol = "W"; + } else { + throw new UnsupportedOperationException("ManaFilter is not supported: " + this); + } + for (int i = 0; i < amountMana; i++) { + manaString.append('{').append(manaSymbol).append('}'); + } + } + addManaCostsToPay(new ManaCostsImpl<>(manaString.toString())); + } else { + addManaCostsToPay(new WaterbendCost(amountMana)); + } + getManaCostsToPay().setX(xValue, amountMana); + setCostsTag("X", xValue); + } + variableManaCost.setPaid(); return variableManaCost; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java b/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java index 1b350bbc2da..98605bc23f0 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java @@ -12,6 +12,9 @@ import mage.abilities.costs.mana.GenericManaCost; * (usually because the waterbend cost itself is an additional cost), the alternate method to pay for mana * described in rule 701.67a may be used only to pay for the amount of generic mana in the waterbend cost, * even if the total cost to cast that spell or activate that ability includes other generic mana components. + *

+ * If you need Waterbend {X} then use {@link WaterbendXCost} + * If using as an additional cost for a spell, add an ability with an InfoEffect for proper text generation (see WaterWhip) * * @author TheElk801 */ diff --git a/Mage/src/main/java/mage/abilities/costs/common/WaterbendXCost.java b/Mage/src/main/java/mage/abilities/costs/common/WaterbendXCost.java index f0b5ceda762..b9d2e4d25a8 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/WaterbendXCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/WaterbendXCost.java @@ -1,22 +1,23 @@ package mage.abilities.costs.common; -import mage.abilities.Ability; -import mage.abilities.costs.Cost; -import mage.abilities.costs.CostImpl; -import mage.game.Game; - -import java.util.UUID; +import mage.abilities.costs.VariableCostType; +import mage.abilities.costs.mana.VariableManaCost; /** - * TODO: Implement properly + * Used for Waterbend {X} costs, otherwise use {@link WaterbendCost} + * If using as an additional cost for a spell, add an ability with an InfoEffect for proper text generation (see WaterbendersRestoration) * * @author TheElk801 */ -public class WaterbendXCost extends CostImpl { +public class WaterbendXCost extends VariableManaCost { public WaterbendXCost() { - super(); - this.text = "waterbend {X}"; + this(0); + } + + public WaterbendXCost(int minX) { + super(VariableCostType.NORMAL); + this.setMinX(minX); } private WaterbendXCost(final WaterbendXCost cost) { @@ -29,12 +30,7 @@ public class WaterbendXCost extends CostImpl { } @Override - public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return false; - } - - @Override - public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - return false; + public String getText() { + return "waterbend {X}"; } }