Merge pull request #13516 from magefree/cost-adjusters-rework

This commit is contained in:
Oleg Agafonov 2025-04-08 22:30:45 +03:00 committed by GitHub
commit 2a1eebc5fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
168 changed files with 1635 additions and 540 deletions

View file

@ -1863,8 +1863,11 @@ public class ComputerPlayer extends PlayerImpl {
@Override @Override
public int announceXMana(int min, int max, String message, Game game, Ability ability) { public int announceXMana(int min, int max, String message, Game game, Ability ability) {
log.debug("announceXMana"); // current logic - use max possible mana
//TODO: improve this
// TODO: add good/bad effects support
// TODO: add simple game simulations like declare blocker?
int numAvailable = getAvailableManaProducers(game).size() - ability.getManaCosts().manaValue(); int numAvailable = getAvailableManaProducers(game).size() - ability.getManaCosts().manaValue();
if (numAvailable < 0) { if (numAvailable < 0) {
numAvailable = 0; numAvailable = 0;
@ -1881,12 +1884,17 @@ public class ComputerPlayer extends PlayerImpl {
@Override @Override
public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variablCost) { public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variablCost) {
log.debug("announceXCost"); // current logic - use random non-zero value
// TODO: add good/bad effects support
// TODO: remove random logic
int value = RandomUtil.nextInt(CardUtil.overflowInc(max, 1)); int value = RandomUtil.nextInt(CardUtil.overflowInc(max, 1));
if (value < min) { if (value < min) {
value = min; value = min;
} }
if (value < max) { if (value < max) {
// do not use zero values
value++; value++;
} }
return value; return value;

View file

@ -1709,6 +1709,8 @@ public class HumanPlayer extends PlayerImpl {
if (response.getInteger() != null) { if (response.getInteger() != null) {
break; break;
} }
// TODO: add response verify here
} }
if (response.getInteger() != null) { if (response.getInteger() != null) {

View file

@ -62,9 +62,6 @@ hand:Human:Angelic Edict:3
battlefield:Computer:Grizzly Bears:2 battlefield:Computer:Grizzly Bears:2
battlefield:Human:Grizzly Bears:2 battlefield:Human:Grizzly Bears:2
// special command, see SystemUtil for more special commands list
[@activate opponent ability]
[diff set codes example] [diff set codes example]
battlefield:Human:XLN-Island:1 battlefield:Human:XLN-Island:1
battlefield:Human:UST-Island:1 battlefield:Human:UST-Island:1

View file

@ -1,43 +1,30 @@
package mage.cards.a; package mage.cards.a;
import mage.abilities.Ability; import mage.abilities.costs.costadjusters.DiscardXCardsCostAdjuster;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.common.DiscardTargetCost;
import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.effects.common.discard.LookTargetHandChooseDiscardEffect; import mage.abilities.effects.common.discard.LookTargetHandChooseDiscardEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
/** /**
* @author fireshoes * @author fireshoes, JayDi85
*/ */
public final class AbandonHope extends CardImpl { public final class AbandonHope extends CardImpl {
public AbandonHope(UUID ownerId, CardSetInfo setInfo) { public AbandonHope(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{1}{B}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{1}{B}");
// As an additional cost to cast Abandon Hope, discard X cards. // As an additional cost to cast this spell, discard X cards.
Ability ability = new SimpleStaticAbility( DiscardXCardsCostAdjuster.addAdjusterAndMessage(this, StaticFilters.FILTER_CARD_CARDS);
Zone.ALL, new InfoEffect("As an additional cost to cast this spell, discard X cards")
);
ability.setRuleAtTheTop(true);
this.addAbility(ability);
// Look at target opponent's hand and choose X cards from it. That player discards those cards. // Look at target opponent's hand and choose X cards from it. That player discards those cards.
this.getSpellAbility().addEffect(new LookTargetHandChooseDiscardEffect(false, GetXValue.instance, StaticFilters.FILTER_CARD_CARDS)); this.getSpellAbility().addEffect(new LookTargetHandChooseDiscardEffect(false, GetXValue.instance, StaticFilters.FILTER_CARD_CARDS));
this.getSpellAbility().addTarget(new TargetOpponent()); this.getSpellAbility().addTarget(new TargetOpponent());
this.getSpellAbility().setCostAdjuster(AbandonHopeAdjuster.instance);
} }
private AbandonHope(final AbandonHope card) { private AbandonHope(final AbandonHope card) {
@ -49,15 +36,3 @@ public final class AbandonHope extends CardImpl {
return new AbandonHope(this); return new AbandonHope(this);
} }
} }
enum AbandonHopeAdjuster implements CostAdjuster {
instance;
@Override
public void adjustCosts(Ability ability, Game game) {
int xValue = CardUtil.getSourceCostsTag(game, ability, "X", 0);
if (xValue > 0) {
ability.addCost(new DiscardTargetCost(new TargetCardInHand(xValue, xValue, StaticFilters.FILTER_CARD_CARDS)));
}
}
}

View file

@ -31,7 +31,7 @@ public final class AeonChronicler extends CardImpl {
this.toughness = new MageInt(0); this.toughness = new MageInt(0);
// Aeon Chronicler's power and toughness are each equal to the number of cards in your hand. // Aeon Chronicler's power and toughness are each equal to the number of cards in your hand.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.instance))); this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.ANY)));
// Suspend X-{X}{3}{U}. X can't be 0. // Suspend X-{X}{3}{U}. X can't be 0.
this.addAbility(new SuspendAbility(Integer.MAX_VALUE, new ManaCostsImpl<>("{3}{U}"), this, true)); this.addAbility(new SuspendAbility(Integer.MAX_VALUE, new ManaCostsImpl<>("{3}{U}"), this, true));

View file

@ -1,27 +1,18 @@
package mage.cards.a; package mage.cards.a;
import mage.abilities.Ability; import mage.abilities.costs.costadjusters.DiscardXCardsCostAdjuster;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.common.DiscardTargetCost;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetadjustment.XTargetsCountAdjuster; import mage.target.targetadjustment.XTargetsCountAdjuster;
import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author jeffwadsworth * @author jeffwadsworth
*/ */
public final class AetherTide extends CardImpl { public final class AetherTide extends CardImpl {
@ -29,10 +20,8 @@ public final class AetherTide extends CardImpl {
public AetherTide(UUID ownerId, CardSetInfo setInfo) { public AetherTide(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}");
// As an additional cost to cast Aether Tide, discard X creature cards. // As an additional cost to cast this spell, discard X creature cards.
Ability ability = new SimpleStaticAbility(Zone.ALL, new InfoEffect("As an additional cost to cast this spell, discard X creature cards")); DiscardXCardsCostAdjuster.addAdjusterAndMessage(this, StaticFilters.FILTER_CARD_CREATURES);
ability.setRuleAtTheTop(true);
this.addAbility(ability);
// Return X target creatures to their owners' hands. // Return X target creatures to their owners' hands.
Effect effect = new ReturnToHandTargetEffect(); Effect effect = new ReturnToHandTargetEffect();
@ -40,8 +29,6 @@ public final class AetherTide extends CardImpl {
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().setTargetAdjuster(new XTargetsCountAdjuster()); this.getSpellAbility().setTargetAdjuster(new XTargetsCountAdjuster());
this.getSpellAbility().setCostAdjuster(AetherTideCostAdjuster.instance);
} }
private AetherTide(final AetherTide card) { private AetherTide(final AetherTide card) {
@ -53,15 +40,3 @@ public final class AetherTide extends CardImpl {
return new AetherTide(this); return new AetherTide(this);
} }
} }
enum AetherTideCostAdjuster implements CostAdjuster {
instance;
@Override
public void adjustCosts(Ability ability, Game game) {
int xValue = CardUtil.getSourceCostsTag(game, ability, "X", 0);
if (xValue > 0) {
ability.addCost(new DiscardTargetCost(new TargetCardInHand(xValue, xValue, StaticFilters.FILTER_CARD_CREATURES)));
}
}
}

View file

@ -3,9 +3,9 @@ package mage.cards.a;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
@ -36,12 +36,8 @@ public final class AladdinsLamp extends CardImpl {
// {X}, {T}: The next time you would draw a card this turn, instead look at the top X cards of your library, put all but one of them on the bottom of your library in a random order, then draw a card. X can't be 0. // {X}, {T}: The next time you would draw a card this turn, instead look at the top X cards of your library, put all but one of them on the bottom of your library in a random order, then draw a card. X can't be 0.
Ability ability = new SimpleActivatedAbility(new AladdinsLampEffect(), new ManaCostsImpl<>("{X}")); Ability ability = new SimpleActivatedAbility(new AladdinsLampEffect(), new ManaCostsImpl<>("{X}"));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
for (Object cost : ability.getManaCosts()) { ability.setCostAdjuster(AladdinsLampCostAdjuster.instance);
if (cost instanceof VariableManaCost) {
((VariableManaCost) cost).setMinX(1);
break;
}
}
this.addAbility(ability); this.addAbility(ability);
} }
@ -101,3 +97,17 @@ class AladdinsLampEffect extends ReplacementEffectImpl {
return source.isControlledBy(event.getPlayerId()); return source.isControlledBy(event.getPlayerId());
} }
} }
enum AladdinsLampCostAdjuster implements CostAdjuster {
instance;
@Override
public void prepareX(Ability ability, Game game) {
Player controller = game.getPlayer(ability.getControllerId());
if (controller == null) {
return;
}
ability.setVariableCostsMinMax(1, Math.max(1, controller.getLibrary().size()));
}
}

View file

@ -47,8 +47,8 @@ public final class AlandraSkyDreamer extends CardImpl {
// Whenever you draw your fifth card each turn, Alandra, Sky Dreamer and Drakes you control each get +X/+X until end of turn, where X is the number of cards in your hand. // Whenever you draw your fifth card each turn, Alandra, Sky Dreamer and Drakes you control each get +X/+X until end of turn, where X is the number of cards in your hand.
DrawNthCardTriggeredAbility drawNthCardTriggeredAbility = new DrawNthCardTriggeredAbility( DrawNthCardTriggeredAbility drawNthCardTriggeredAbility = new DrawNthCardTriggeredAbility(
new BoostSourceEffect( new BoostSourceEffect(
CardsInControllerHandCount.instance, CardsInControllerHandCount.ANY,
CardsInControllerHandCount.instance, CardsInControllerHandCount.ANY,
Duration.EndOfTurn Duration.EndOfTurn
).setText("{this}"), ).setText("{this}"),
false, false,
@ -56,8 +56,8 @@ public final class AlandraSkyDreamer extends CardImpl {
); );
drawNthCardTriggeredAbility.addEffect( drawNthCardTriggeredAbility.addEffect(
new BoostControlledEffect( new BoostControlledEffect(
CardsInControllerHandCount.instance, CardsInControllerHandCount.ANY,
CardsInControllerHandCount.instance, CardsInControllerHandCount.ANY,
Duration.EndOfTurn, Duration.EndOfTurn,
filter, filter,
false false

View file

@ -61,7 +61,7 @@ class AncientExcavationEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
if (player != null) { if (player != null) {
DynamicValue numCards = CardsInControllerHandCount.instance; DynamicValue numCards = CardsInControllerHandCount.ANY;
int amount = numCards.calculate(game, source, this); int amount = numCards.calculate(game, source, this);
int cardsDrawn = player.drawCards(amount, source, game); int cardsDrawn = player.drawCards(amount, source, game);
player.discard(cardsDrawn, false, false, source, game); player.discard(cardsDrawn, false, false, source, game);

View file

@ -1,4 +1,3 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID; import java.util.UUID;
@ -26,7 +25,7 @@ public final class Archivist extends CardImpl {
this.power = new MageInt(1); this.power = new MageInt(1);
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
//{T}: Draw a card. // {T}: Draw a card.
this.addAbility(new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost())); this.addAbility(new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()));
} }

View file

@ -71,7 +71,7 @@ enum ArmMountedAnchorAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
// checking state // checking state
if (HeckbentCondition.instance.apply(game, ability)) { if (HeckbentCondition.instance.apply(game, ability)) {
CardUtil.reduceCost(ability, 2); CardUtil.reduceCost(ability, 2);

View file

@ -43,7 +43,7 @@ public final class BaldinCenturyHerdmaster extends CardImpl {
// Whenever Baldin, Century Herdmaster attacks, up to one hundred target creatures each get +0/+X until end of turn, where X is the number of cards in your hand. // Whenever Baldin, Century Herdmaster attacks, up to one hundred target creatures each get +0/+X until end of turn, where X is the number of cards in your hand.
Ability ability = new AttacksTriggeredAbility(new BoostTargetEffect( Ability ability = new AttacksTriggeredAbility(new BoostTargetEffect(
StaticValue.get(0), CardsInControllerHandCount.instance, Duration.EndOfTurn StaticValue.get(0), CardsInControllerHandCount.ANY, Duration.EndOfTurn
).setText("up to one hundred target creatures each get +0/+X until end of turn, where X is the number of cards in your hand")); ).setText("up to one hundred target creatures each get +0/+X until end of turn, where X is the number of cards in your hand"));
ability.addTarget(new TargetCreaturePermanent(0, 100)); ability.addTarget(new TargetCreaturePermanent(0, 100));
this.addAbility(ability); this.addAbility(ability);

View file

@ -1,25 +1,28 @@
package mage.cards.b; package mage.cards.b;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.EarlyTargetCost;
import mage.abilities.costs.VariableCostType;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.InfoEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import java.util.Objects;
import java.util.UUID;
/** /**
* * @author awjackson, JayDi85
* @author awjackson
*/ */
public final class BargainingTable extends CardImpl { public final class BargainingTable extends CardImpl {
@ -27,13 +30,10 @@ public final class BargainingTable extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}");
// {X}, {T}: Draw a card. X is the number of cards in an opponent's hand. // {X}, {T}: Draw a card. X is the number of cards in an opponent's hand.
Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{X}")); Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new BargainingTableXCost());
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addEffect(new InfoEffect("X is the number of cards in an opponent's hand")); ability.addEffect(new InfoEffect("X is the number of cards in an opponent's hand"));
// You choose an opponent on announcement. This is not targeted, but a choice is still made. ability.setCostAdjuster(BargainingTableCostAdjuster.instance);
// This choice is made before determining the value for X that is used in the cost. (2004-10-04)
ability.addTarget(new TargetOpponent(true));
ability.setCostAdjuster(BargainingTableAdjuster.instance);
this.addAbility(ability); this.addAbility(ability);
} }
@ -47,26 +47,70 @@ public final class BargainingTable extends CardImpl {
} }
} }
enum BargainingTableAdjuster implements CostAdjuster { class BargainingTableXCost extends VariableManaCost implements EarlyTargetCost {
// You choose an opponent on announcement. This is not targeted, but a choice is still made.
// This choice is made before determining the value for X that is used in the cost.
// (2004-10-04)
public BargainingTableXCost() {
super(VariableCostType.NORMAL, 1);
}
public BargainingTableXCost(final BargainingTableXCost cost) {
super(cost);
}
@Override
public void chooseTarget(Game game, Ability source, Player controller) {
Target targetOpponent = new TargetOpponent(true);
controller.choose(Outcome.Benefit, targetOpponent, source, game);
addTarget(targetOpponent);
}
@Override
public BargainingTableXCost copy() {
return new BargainingTableXCost(this);
}
}
enum BargainingTableCostAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void prepareX(Ability ability, Game game) {
int handSize = Integer.MAX_VALUE; // make sure early target used
if (game.inCheckPlayableState()) { BargainingTableXCost cost = ability.getManaCostsToPay().getVariableCosts().stream()
for (UUID playerId : CardUtil.getAllPossibleTargets(ability, game)) { .filter(c -> c instanceof BargainingTableXCost)
Player player = game.getPlayer(playerId); .map(c -> (BargainingTableXCost) c)
if (player != null) { .findFirst()
handSize = Math.min(handSize, player.getHand().size()); .orElse(null);
} if (cost == null) {
} throw new IllegalArgumentException("Wrong code usage: cost item lost");
} else { }
Player player = game.getPlayer(ability.getFirstTarget());
if (player != null) { if (game.inCheckPlayableState()) {
handSize = player.getHand().size(); // possible X
} int minHandSize = game.getOpponents(ability.getControllerId(), true).stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.mapToInt(p -> p.getHand().size())
.min()
.orElse(0);
int maxHandSize = game.getOpponents(ability.getControllerId(), true).stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.mapToInt(p -> p.getHand().size())
.max()
.orElse(Integer.MAX_VALUE);
ability.setVariableCostsMinMax(minHandSize, maxHandSize);
} else {
// real X
Player opponent = game.getPlayer(cost.getTargets().getFirstTarget());
if (opponent == null) {
throw new IllegalStateException("Wrong code usage: cost target lost");
}
ability.setVariableCostsValue(opponent.getHand().size());
} }
ability.clearManaCostsToPay();
ability.addManaCostsToPay(new GenericManaCost(handSize));
} }
} }

View file

@ -19,10 +19,7 @@ import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
@ -116,7 +113,7 @@ enum BaruWurmspeakerAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
int value = BaruWurmspeakerValue.instance.calculate(game, ability, null); int value = BaruWurmspeakerValue.instance.calculate(game, ability, null);
if (value > 0) { if (value > 0) {
CardUtil.reduceCost(ability, value); CardUtil.reduceCost(ability, value);

View file

@ -58,7 +58,7 @@ enum BattlefieldButcherAdjuster implements CostAdjuster {
private static final Hint hint = new ValueHint("Creature cards in your graveyard", xValue); private static final Hint hint = new ValueHint("Creature cards in your graveyard", xValue);
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
CardUtil.reduceCost(ability, xValue.calculate(game, ability, null)); CardUtil.reduceCost(ability, xValue.calculate(game, ability, null));
} }

View file

@ -3,20 +3,21 @@ package mage.cards.b;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.continuous.SetBasePowerToughnessEnchantedEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessEnchantedEffect;
import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.EquipAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import mage.abilities.costs.mana.GenericManaCost;
import mage.constants.Outcome;
import mage.target.common.TargetControlledCreaturePermanent;
/** /**
* @author TheElk801 * @author TheElk801
@ -35,7 +36,7 @@ public final class BeltOfGiantStrength extends CardImpl {
// Equip {10}. This ability costs {X} less to activate where X is the power of the creature it targets. // Equip {10}. This ability costs {X} less to activate where X is the power of the creature it targets.
EquipAbility ability = new EquipAbility(Outcome.BoostCreature, new GenericManaCost(10), new TargetControlledCreaturePermanent(), false); EquipAbility ability = new EquipAbility(Outcome.BoostCreature, new GenericManaCost(10), new TargetControlledCreaturePermanent(), false);
ability.setCostReduceText("This ability costs {X} less to activate, where X is the power of the creature it targets."); ability.setCostReduceText("This ability costs {X} less to activate, where X is the power of the creature it targets.");
ability.setCostAdjuster(BeltOfGiantStrengthAdjuster.instance); ability.setCostAdjuster(BeltOfGiantStrengthCostAdjuster.instance);
this.addAbility(ability); this.addAbility(ability);
} }
@ -49,33 +50,23 @@ public final class BeltOfGiantStrength extends CardImpl {
} }
} }
enum BeltOfGiantStrengthAdjuster implements CostAdjuster { enum BeltOfGiantStrengthCostAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
int power;
if (game.inCheckPlayableState()) { if (game.inCheckPlayableState()) {
int maxPower = 0; power = CardUtil.getAllPossibleTargets(ability, game).stream()
for (UUID permId : CardUtil.getAllPossibleTargets(ability, game)) { .map(game::getPermanent)
Permanent permanent = game.getPermanent(permId); .filter(Objects::nonNull)
if (permanent != null) { .mapToInt(p -> p.getPower().getValue())
int power = permanent.getPower().getValue(); .max().orElse(0);
if (power > maxPower) {
maxPower = power;
}
}
}
if (maxPower > 0) {
CardUtil.reduceCost(ability, maxPower);
}
} else { } else {
Permanent permanent = game.getPermanent(ability.getFirstTarget()); power = Optional.ofNullable(game.getPermanent(ability.getFirstTarget()))
if (permanent != null) { .map(p -> p.getPower().getValue())
int power = permanent.getPower().getValue(); .orElse(0);
if (power > 0) {
CardUtil.reduceCost(ability, power);
}
}
} }
CardUtil.reduceCost(ability, power);
} }
} }

View file

@ -60,7 +60,7 @@ enum BiteDownOnCrimeAdjuster implements CostAdjuster {
private static final OptionalAdditionalCost collectEvidenceCost = CollectEvidenceAbility.makeCost(6); private static final OptionalAdditionalCost collectEvidenceCost = CollectEvidenceAbility.makeCost(6);
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
if (CollectedEvidenceCondition.instance.apply(game, ability) if (CollectedEvidenceCondition.instance.apply(game, ability)
|| (game.inCheckPlayableState() && collectEvidenceCost.canPay(ability, null, ability.getControllerId(), game))) { || (game.inCheckPlayableState() && collectEvidenceCost.canPay(ability, null, ability.getControllerId(), game))) {
CardUtil.reduceCost(ability, 2); CardUtil.reduceCost(ability, 2);

View file

@ -33,7 +33,7 @@ public final class BodyOfKnowledge extends CardImpl {
this.addAbility(new SimpleStaticAbility( this.addAbility(new SimpleStaticAbility(
Zone.ALL, Zone.ALL,
new SetBasePowerToughnessSourceEffect( new SetBasePowerToughnessSourceEffect(
CardsInControllerHandCount.instance CardsInControllerHandCount.ANY
) )
)); ));

View file

@ -59,7 +59,7 @@ enum CallerOfTheHuntAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void prepareCost(Ability ability, Game game) {
if (game.inCheckPlayableState()) { if (game.inCheckPlayableState()) {
return; return;
} }
@ -103,6 +103,7 @@ enum CallerOfTheHuntAdjuster implements CostAdjuster {
game.getState().setValue(sourceObject.getId() + "_type", maxSubType); game.getState().setValue(sourceObject.getId() + "_type", maxSubType);
} else { } else {
// human choose // human choose
// TODO: need early target cost instead dialog here
Effect effect = new ChooseCreatureTypeEffect(Outcome.Benefit); Effect effect = new ChooseCreatureTypeEffect(Outcome.Benefit);
effect.apply(game, ability); effect.apply(game, ability);
} }

View file

@ -4,6 +4,7 @@ import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl;
import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
@ -130,7 +131,7 @@ enum CaptainAmericaFirstAvengerValue implements DynamicValue {
} }
} }
class CaptainAmericaFirstAvengerUnattachCost extends EarlyTargetCost { class CaptainAmericaFirstAvengerUnattachCost extends CostImpl implements EarlyTargetCost {
private static final FilterPermanent filter = new FilterEquipmentPermanent("equipment attached to this creature"); private static final FilterPermanent filter = new FilterEquipmentPermanent("equipment attached to this creature");
private static final FilterPermanent subfilter = new FilterControlledPermanent("{this}"); private static final FilterPermanent subfilter = new FilterControlledPermanent("{this}");

View file

@ -40,7 +40,7 @@ public final class CastleLocthwain extends CardImpl {
Ability ability = new SimpleActivatedAbility( Ability ability = new SimpleActivatedAbility(
new DrawCardSourceControllerEffect(1).setText("draw a card,"), new ManaCostsImpl<>("{1}{B}{B}") new DrawCardSourceControllerEffect(1).setText("draw a card,"), new ManaCostsImpl<>("{1}{B}{B}")
); );
ability.addEffect(new LoseLifeSourceControllerEffect(CardsInControllerHandCount.instance) ability.addEffect(new LoseLifeSourceControllerEffect(CardsInControllerHandCount.ANY)
.setText("then you lose life equal to the number of cards in your hand")); .setText("then you lose life equal to the number of cards in your hand"));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
this.addAbility(ability); this.addAbility(ability);

View file

@ -25,7 +25,7 @@ public final class ChanneledForce extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{R}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{R}");
// As an additional cost to cast this spell, discard X cards. // As an additional cost to cast this spell, discard X cards.
this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS)); this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true));
// Target player draws X cards. Channeled Force deals X damage to up to one target creature or planeswalker. // Target player draws X cards. Channeled Force deals X damage to up to one target creature or planeswalker.
this.getSpellAbility().addEffect(new ChanneledForceEffect()); this.getSpellAbility().addEffect(new ChanneledForceEffect());

View file

@ -72,7 +72,7 @@ enum CrownOfGondorAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
if (MonarchIsSourceControllerCondition.instance.apply(game, ability)) { if (MonarchIsSourceControllerCondition.instance.apply(game, ability)) {
CardUtil.reduceCost(ability, 3); CardUtil.reduceCost(ability, 3);
} }

View file

@ -17,7 +17,6 @@ import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -59,7 +58,7 @@ public final class DamiaSageOfStone extends CardImpl {
class DamiaSageOfStoneTriggeredAbility extends BeginningOfUpkeepTriggeredAbility { class DamiaSageOfStoneTriggeredAbility extends BeginningOfUpkeepTriggeredAbility {
DamiaSageOfStoneTriggeredAbility() { DamiaSageOfStoneTriggeredAbility() {
super(TargetController.YOU, new DrawCardSourceControllerEffect(new IntPlusDynamicValue(7, new MultipliedValue(CardsInControllerHandCount.instance, -1))), false); super(TargetController.YOU, new DrawCardSourceControllerEffect(new IntPlusDynamicValue(7, new MultipliedValue(CardsInControllerHandCount.ANY, -1))), false);
} }
private DamiaSageOfStoneTriggeredAbility(final DamiaSageOfStoneTriggeredAbility ability) { private DamiaSageOfStoneTriggeredAbility(final DamiaSageOfStoneTriggeredAbility ability) {

View file

@ -62,7 +62,7 @@ enum DeepwoodDenizenAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
CardUtil.reduceCost(ability, DeepwoodDenizenValue.instance.calculate(game, ability, null)); CardUtil.reduceCost(ability, DeepwoodDenizenValue.instance.calculate(game, ability, null));
} }
} }

View file

@ -18,7 +18,7 @@ import java.util.UUID;
*/ */
public final class DemonicLore extends CardImpl { public final class DemonicLore extends CardImpl {
private static final DynamicValue xValue = new MultipliedValue(CardsInControllerHandCount.instance, 2); private static final DynamicValue xValue = new MultipliedValue(CardsInControllerHandCount.ANY, 2);
public DemonicLore(UUID ownerId, CardSetInfo setInfo) { public DemonicLore(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}");

View file

@ -12,7 +12,6 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
/** /**
* *
@ -28,7 +27,7 @@ public final class DescendantOfSoramaro extends CardImpl {
this.power = new MageInt(2); this.power = new MageInt(2);
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// {1}{U}: Look at the top X cards of your library, where X is the number of cards in your hand, then put them back in any order. // {1}{U}: Look at the top X cards of your library, where X is the number of cards in your hand, then put them back in any order.
Effect effect = new LookLibraryControllerEffect(CardsInControllerHandCount.instance); Effect effect = new LookLibraryControllerEffect(CardsInControllerHandCount.ANY);
effect.setText("Look at the top X cards of your library, where X is the number of cards in your hand, then put them back in any order"); effect.setText("Look at the top X cards of your library, where X is the number of cards in your hand, then put them back in any order");
this.addAbility(new SimpleActivatedAbility( this.addAbility(new SimpleActivatedAbility(
effect, new ManaCostsImpl<>("{1}{U}"))); effect, new ManaCostsImpl<>("{1}{U}")));

View file

@ -5,6 +5,8 @@ import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCostImpl; import mage.abilities.costs.VariableCostImpl;
import mage.abilities.costs.VariableCostType; import mage.abilities.costs.VariableCostType;
import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.costs.common.DiscardTargetCost;
import mage.abilities.costs.common.DiscardXTargetCost;
import mage.abilities.costs.costadjusters.DiscardXCardsCostAdjuster;
import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DamageAllEffect;
import mage.abilities.effects.common.SacrificeAllEffect; import mage.abilities.effects.common.SacrificeAllEffect;
@ -12,6 +14,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterControlledLandPermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game; import mage.game.Game;
@ -28,8 +31,8 @@ public final class DevastatingDreams extends CardImpl {
public DevastatingDreams(UUID ownerId, CardSetInfo setInfo) { public DevastatingDreams(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}{R}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}{R}");
// As an additional cost to cast Devastating Dreams, discard X cards at random. // As an additional cost to cast this spell, discard X cards at random.
this.getSpellAbility().addCost(new DevastatingDreamsAdditionalCost()); this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true).withRandom());
// Each player sacrifices X lands. // Each player sacrifices X lands.
this.getSpellAbility().addEffect(new SacrificeAllEffect(GetXValue.instance, new FilterControlledLandPermanent("lands"))); this.getSpellAbility().addEffect(new SacrificeAllEffect(GetXValue.instance, new FilterControlledLandPermanent("lands")));

View file

@ -27,7 +27,7 @@ public final class DivinersPortent extends CardImpl {
// Roll a d20 and add the number of cards in your hand. // Roll a d20 and add the number of cards in your hand.
RollDieWithResultTableEffect effect = new RollDieWithResultTableEffect( RollDieWithResultTableEffect effect = new RollDieWithResultTableEffect(
20, "roll a d20 and add the number " + 20, "roll a d20 and add the number " +
"of cards in your hand", CardsInControllerHandCount.instance, 0 "of cards in your hand", CardsInControllerHandCount.ANY, 0
); );
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);

View file

@ -15,7 +15,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Zone;
/** /**
* *
@ -32,7 +31,7 @@ public final class DreadSlag extends CardImpl {
// Trample // Trample
this.addAbility(TrampleAbility.getInstance()); this.addAbility(TrampleAbility.getInstance());
// Dread Slag gets -4/-4 for each card in your hand. // Dread Slag gets -4/-4 for each card in your hand.
DynamicValue amount = new MultipliedValue(CardsInControllerHandCount.instance, -4); DynamicValue amount = new MultipliedValue(CardsInControllerHandCount.ANY, -4);
Effect effect = new BoostSourceEffect(amount, amount, Duration.WhileOnBattlefield); Effect effect = new BoostSourceEffect(amount, amount, Duration.WhileOnBattlefield);
effect.setText("{this} gets -4/-4 for each card in your hand"); effect.setText("{this} gets -4/-4 for each card in your hand");
this.addAbility(new SimpleStaticAbility(effect)); this.addAbility(new SimpleStaticAbility(effect));

View file

@ -36,7 +36,7 @@ public final class DugganPrivateDetective extends CardImpl {
this.toughness = new MageInt(0); this.toughness = new MageInt(0);
// Duggan's power and toughness are each equal to the number of cards in your hand. // Duggan's power and toughness are each equal to the number of cards in your hand.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.instance))); this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.ANY)));
// Whenever Duggan enters the battlefield or attacks, investigate. // Whenever Duggan enters the battlefield or attacks, investigate.
this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new InvestigateEffect().setText("investigate"))); this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new InvestigateEffect().setText("investigate")));

View file

@ -1,12 +1,13 @@
package mage.cards.e; package mage.cards.e;
import mage.ApprovingObject;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.costadjusters.ImprintedManaValueXCostAdjuster;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card; import mage.cards.Card;
@ -23,7 +24,6 @@ import mage.players.Player;
import mage.target.TargetCard; import mage.target.TargetCard;
import java.util.UUID; import java.util.UUID;
import mage.ApprovingObject;
/** /**
* @author LevelX2 * @author LevelX2
@ -44,7 +44,7 @@ public final class EliteArcanist extends CardImpl {
// {X}, {T}: Copy the exiled card. You may cast the copy without paying its mana cost. X is the converted mana cost of the exiled card. // {X}, {T}: Copy the exiled card. You may cast the copy without paying its mana cost. X is the converted mana cost of the exiled card.
Ability ability = new SimpleActivatedAbility(new EliteArcanistCopyEffect(), new ManaCostsImpl<>("{X}")); Ability ability = new SimpleActivatedAbility(new EliteArcanistCopyEffect(), new ManaCostsImpl<>("{X}"));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.setCostAdjuster(EliteArcanistAdjuster.instance); ability.setCostAdjuster(ImprintedManaValueXCostAdjuster.instance);
this.addAbility(ability); this.addAbility(ability);
} }
@ -58,29 +58,6 @@ public final class EliteArcanist extends CardImpl {
} }
} }
enum EliteArcanistAdjuster implements CostAdjuster {
instance;
@Override
public void adjustCosts(Ability ability, Game game) {
Permanent sourcePermanent = game.getPermanent(ability.getSourceId());
if (sourcePermanent == null
|| sourcePermanent.getImprinted() == null
|| sourcePermanent.getImprinted().isEmpty()) {
return;
}
Card imprintedInstant = game.getCard(sourcePermanent.getImprinted().get(0));
if (imprintedInstant == null) {
return;
}
int cmc = imprintedInstant.getManaValue();
if (cmc > 0) {
ability.clearManaCostsToPay();
ability.addManaCostsToPay(new GenericManaCost(cmc));
}
}
}
class EliteArcanistImprintEffect extends OneShotEffect { class EliteArcanistImprintEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard("instant card from your hand"); private static final FilterCard filter = new FilterCard("instant card from your hand");

View file

@ -15,7 +15,6 @@ import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
@ -38,7 +37,7 @@ public final class EmpyrialArmor extends CardImpl {
this.addAbility(ability); this.addAbility(ability);
// Enchanted creature gets +1/+1 for each card in your hand. // Enchanted creature gets +1/+1 for each card in your hand.
DynamicValue xValue = CardsInControllerHandCount.instance; DynamicValue xValue = CardsInControllerHandCount.ANY;
this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(xValue, xValue, Duration.WhileOnBattlefield))); this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(xValue, xValue, Duration.WhileOnBattlefield)));
} }

View file

@ -12,7 +12,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone;
/** /**
* *
@ -25,7 +24,7 @@ public final class EmpyrialPlate extends CardImpl {
this.subtype.add(SubType.EQUIPMENT); this.subtype.add(SubType.EQUIPMENT);
// Equipped creature gets +1/+1 for each card in your hand. // Equipped creature gets +1/+1 for each card in your hand.
this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(CardsInControllerHandCount.instance, CardsInControllerHandCount.instance))); this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(CardsInControllerHandCount.ANY, CardsInControllerHandCount.ANY)));
// Equip {2} // Equip {2}
this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2), false)); this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2), false));

View file

@ -22,7 +22,7 @@ public final class EndlessSwarm extends CardImpl {
// Create a 1/1 green Snake creature token for each card in your hand. // Create a 1/1 green Snake creature token for each card in your hand.
this.getSpellAbility().addEffect(new CreateTokenEffect(new SnakeToken(), CardsInControllerHandCount.instance).setText("create a 1/1 green Snake creature token for each card in your hand")); this.getSpellAbility().addEffect(new CreateTokenEffect(new SnakeToken(), CardsInControllerHandCount.ANY).setText("create a 1/1 green Snake creature token for each card in your hand"));
// Epic // Epic
this.getSpellAbility().addEffect(new EpicEffect()); this.getSpellAbility().addEffect(new EpicEffect());

View file

@ -64,7 +64,7 @@ enum EsquireOfTheKingAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
if (game.getBattlefield().contains(StaticFilters.FILTER_CONTROLLED_CREATURE_LEGENDARY, ability, game, 1)) { if (game.getBattlefield().contains(StaticFilters.FILTER_CONTROLLED_CREATURE_LEGENDARY, ability, game, 1)) {
CardUtil.reduceCost(ability, 2); CardUtil.reduceCost(ability, 2);
} }

View file

@ -80,8 +80,7 @@ enum EtheriumPteramanderAdjuster implements CostAdjuster {
} }
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
int count = artifactCount.calculate(game, ability, null); CardUtil.reduceCost(ability, artifactCount.calculate(game, ability, null));
CardUtil.reduceCost(ability, count);
} }
} }

View file

@ -21,7 +21,7 @@ public final class FatefulShowdown extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}{R}"); super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}{R}");
// Fateful Showdown deals damage to any target equal to the number of cards in your hand. Discard all the cards in your hand, then draw that many cards. // Fateful Showdown deals damage to any target equal to the number of cards in your hand. Discard all the cards in your hand, then draw that many cards.
Effect effect = new DamageTargetEffect(CardsInControllerHandCount.instance); Effect effect = new DamageTargetEffect(CardsInControllerHandCount.ANY);
effect.setText("{this} deals damage to any target equal to the number of cards in your hand"); effect.setText("{this} deals damage to any target equal to the number of cards in your hand");
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addTarget(new TargetAnyTarget());

View file

@ -2,11 +2,11 @@ package mage.cards.f;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.CostModificationType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -24,8 +24,8 @@ public final class Fireball extends CardImpl {
public Fireball(UUID ownerId, CardSetInfo setInfo) { public Fireball(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}");
// Fireball deals X damage divided evenly, rounded down, among any number of target creatures and/or players. // This spell costs {1} more to cast for each target beyond the first.
// Fireball costs 1 more to cast for each target beyond the first. // Fireball deals X damage divided evenly, rounded down, among any number of targets.
this.getSpellAbility().addTarget(new FireballTargetCreatureOrPlayer(0, Integer.MAX_VALUE)); this.getSpellAbility().addTarget(new FireballTargetCreatureOrPlayer(0, Integer.MAX_VALUE));
this.getSpellAbility().addEffect(new FireballEffect()); this.getSpellAbility().addEffect(new FireballEffect());
this.getSpellAbility().setCostAdjuster(FireballAdjuster.instance); this.getSpellAbility().setCostAdjuster(FireballAdjuster.instance);
@ -45,10 +45,10 @@ enum FireballAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void increaseCost(Ability ability, Game game) {
int numTargets = ability.getTargets().isEmpty() ? 0 : ability.getTargets().get(0).getTargets().size(); int numTargets = ability.getTargets().isEmpty() ? 0 : ability.getTargets().get(0).getTargets().size();
if (numTargets > 1) { if (numTargets > 1) {
ability.addManaCostsToPay(new GenericManaCost(numTargets - 1)); CardUtil.increaseCost(ability, numTargets - 1);
} }
} }
} }

View file

@ -31,7 +31,7 @@ public final class FiresOfVictory extends CardImpl {
KickedCondition.ONCE, KickedCondition.ONCE,
"If this spell was kicked, draw a card." "If this spell was kicked, draw a card."
)); ));
this.getSpellAbility().addEffect(new DamageTargetEffect(CardsInControllerHandCount.instance) this.getSpellAbility().addEffect(new DamageTargetEffect(CardsInControllerHandCount.ANY)
.setText("{this} deals damage to target creature or planeswalker equal to the number of cards in your hand.")); .setText("{this} deals damage to target creature or planeswalker equal to the number of cards in your hand."));
this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker());
} }

View file

@ -9,6 +9,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
@ -25,8 +26,8 @@ public final class Firestorm extends CardImpl {
public Firestorm(UUID ownerId, CardSetInfo setInfo) { public Firestorm(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}");
// As an additional cost to cast Firestorm, discard X cards. // As an additional cost to cast this spell, discard X cards.
this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("cards"), true)); this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true));
// Firestorm deals X damage to each of X target creatures and/or players. // Firestorm deals X damage to each of X target creatures and/or players.
this.getSpellAbility().addEffect(new FirestormEffect()); this.getSpellAbility().addEffect(new FirestormEffect());

View file

@ -92,7 +92,7 @@ enum FugitiveCodebreakerAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
CardUtil.reduceCost(ability, FugitiveCodebreakerDisguiseAbility.xValue.calculate(game, ability, null)); CardUtil.reduceCost(ability, FugitiveCodebreakerDisguiseAbility.xValue.calculate(game, ability, null));
} }
} }

View file

@ -21,7 +21,6 @@ import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
@ -42,7 +41,7 @@ public final class GeralfsMasterpiece extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Geralf's Masterpiece gets -1/-1 for each card in your hand. // Geralf's Masterpiece gets -1/-1 for each card in your hand.
DynamicValue count = new SignInversionDynamicValue(CardsInControllerHandCount.instance); DynamicValue count = new SignInversionDynamicValue(CardsInControllerHandCount.ANY);
Effect effect = new BoostSourceEffect(count, count, Duration.WhileOnBattlefield); Effect effect = new BoostSourceEffect(count, count, Duration.WhileOnBattlefield);
effect.setText("{this} gets -1/-1 for each card in your hand"); effect.setText("{this} gets -1/-1 for each card in your hand");
this.addAbility(new SimpleStaticAbility(effect)); this.addAbility(new SimpleStaticAbility(effect));

View file

@ -20,7 +20,7 @@ public final class GerrardsWisdom extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}{W}"); super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}{W}");
// You gain 2 life for each card in your hand. // You gain 2 life for each card in your hand.
this.getSpellAbility().addEffect(new GainLifeEffect(new MultipliedValue(CardsInControllerHandCount.instance, 2), this.getSpellAbility().addEffect(new GainLifeEffect(new MultipliedValue(CardsInControllerHandCount.ANY, 2),
"You gain 2 life for each card in your hand")); "You gain 2 life for each card in your hand"));
} }

View file

@ -55,9 +55,9 @@ enum GhostfireBladeAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
// checking state
if (game.inCheckPlayableState()) { if (game.inCheckPlayableState()) {
// possible
if (CardUtil if (CardUtil
.getAllPossibleTargets(ability, game) .getAllPossibleTargets(ability, game)
.stream() .stream()
@ -67,6 +67,7 @@ enum GhostfireBladeAdjuster implements CostAdjuster {
return; return;
} }
} else { } else {
// real
Permanent permanent = game.getPermanent(ability.getFirstTarget()); Permanent permanent = game.getPermanent(ability.getFirstTarget());
if (permanent == null || !permanent.getColor(game).isColorless()) { if (permanent == null || !permanent.getColor(game).isColorless()) {
return; return;

View file

@ -74,7 +74,7 @@ enum GrimGiganotosaurusAdjuster implements CostAdjuster {
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter);
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
Player controller = game.getPlayer(ability.getControllerId()); Player controller = game.getPlayer(ability.getControllerId());
if (controller != null) { if (controller != null) {
CardUtil.reduceCost(ability, xValue.calculate(game, ability, null)); CardUtil.reduceCost(ability, xValue.calculate(game, ability, null));

View file

@ -14,7 +14,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Zone;
/** /**
* *
@ -29,7 +28,7 @@ public final class GrimStrider extends CardImpl {
this.toughness = new MageInt(6); this.toughness = new MageInt(6);
// Grim Strider gets -1/-1 for each card in your hand. // Grim Strider gets -1/-1 for each card in your hand.
DynamicValue count = new SignInversionDynamicValue(CardsInControllerHandCount.instance); DynamicValue count = new SignInversionDynamicValue(CardsInControllerHandCount.ANY);
Effect effect = new BoostSourceEffect(count, count, Duration.WhileOnBattlefield); Effect effect = new BoostSourceEffect(count, count, Duration.WhileOnBattlefield);
effect.setText("{this} gets -1/-1 for each card in your hand"); effect.setText("{this} gets -1/-1 for each card in your hand");
this.addAbility(new SimpleStaticAbility(effect)); this.addAbility(new SimpleStaticAbility(effect));

View file

@ -61,7 +61,7 @@ enum HamletGluttonAdjuster implements CostAdjuster {
private static OptionalAdditionalCost bargainCost = BargainAbility.makeBargainCost(); private static OptionalAdditionalCost bargainCost = BargainAbility.makeBargainCost();
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
if (BargainedCondition.instance.apply(game, ability) if (BargainedCondition.instance.apply(game, ability)
|| (game.inCheckPlayableState() && bargainCost.canPay(ability, null, ability.getControllerId(), game))) { || (game.inCheckPlayableState() && bargainCost.canPay(ability, null, ability.getControllerId(), game))) {
CardUtil.reduceCost(ability, 2); CardUtil.reduceCost(ability, 2);

View file

@ -47,7 +47,7 @@ public final class HandOfVecna extends CardImpl {
this.addAbility(new EquipAbility( this.addAbility(new EquipAbility(
Outcome.Benefit, Outcome.Benefit,
new PayLifeCost( new PayLifeCost(
CardsInControllerHandCount.instance, "1 life for each card in your hand"), CardsInControllerHandCount.ANY, "1 life for each card in your hand"),
false false
)); ));

View file

@ -2,9 +2,8 @@ package mage.cards.h;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.VariableCostType;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.*; import mage.cards.*;
@ -29,9 +28,8 @@ public final class HelmOfObedience extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// {X}, {T}: Target opponent puts cards from the top of their library into their graveyard until a creature card or X cards are put into that graveyard this way, whichever comes first. If a creature card is put into that graveyard this way, sacrifice Helm of Obedience and put that card onto the battlefield under your control. X can't be 0. // {X}, {T}: Target opponent puts cards from the top of their library into their graveyard until a creature card or X cards are put into that graveyard this way, whichever comes first. If a creature card is put into that graveyard this way, sacrifice Helm of Obedience and put that card onto the battlefield under your control. X can't be 0.
VariableManaCost xCosts = new VariableManaCost(VariableCostType.NORMAL); Ability ability = new SimpleActivatedAbility(new HelmOfObedienceEffect(), new ManaCostsImpl<>("{X}"));
xCosts.setMinX(1); ability.setVariableCostsMinMax(1, Integer.MAX_VALUE);
Ability ability = new SimpleActivatedAbility(new HelmOfObedienceEffect(), xCosts);
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addTarget(new TargetOpponent()); ability.addTarget(new TargetOpponent());
this.addAbility(ability); this.addAbility(ability);

View file

@ -117,6 +117,10 @@ final class HinataDawnCrownedEffectUtility
public static int getTargetCount(Game game, Ability abilityToModify) public static int getTargetCount(Game game, Ability abilityToModify)
{ {
if (game.inCheckPlayableState()) { if (game.inCheckPlayableState()) {
abilityToModify.getTargets().stream()
.mapToInt(a -> !a.isRequired() ? 0 : a.getMinNumberOfTargets())
.min()
.orElse(0);
Optional<Integer> max = abilityToModify.getTargets().stream().map(x -> x.getMaxNumberOfTargets()).max(Integer::compare); Optional<Integer> max = abilityToModify.getTargets().stream().map(x -> x.getMaxNumberOfTargets()).max(Integer::compare);
int allPossibleSize = CardUtil.getAllPossibleTargets(abilityToModify, game).size(); int allPossibleSize = CardUtil.getAllPossibleTargets(abilityToModify, game).size();
return max.isPresent() ? return max.isPresent() ?

View file

@ -49,7 +49,7 @@ enum HurkylsFinalMeditationAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void increaseCost(Ability ability, Game game) {
if (!game.isActivePlayer(ability.getControllerId())) { if (!game.isActivePlayer(ability.getControllerId())) {
CardUtil.increaseCost(ability, 3); CardUtil.increaseCost(ability, 3);
} }

View file

@ -82,7 +82,7 @@ enum HyldasCrownOfWinterAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
if (ability.getControllerId().equals(game.getActivePlayerId())) { if (ability.getControllerId().equals(game.getActivePlayerId())) {
CardUtil.reduceCost(ability, 1); CardUtil.reduceCost(ability, 1);
} }

View file

@ -52,7 +52,7 @@ enum IceOutAdjuster implements CostAdjuster {
private static OptionalAdditionalCost bargainCost = BargainAbility.makeBargainCost(); private static OptionalAdditionalCost bargainCost = BargainAbility.makeBargainCost();
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
if (BargainedCondition.instance.apply(game, ability) if (BargainedCondition.instance.apply(game, ability)
|| (game.inCheckPlayableState() && bargainCost.canPay(ability, null, ability.getControllerId(), game))) { || (game.inCheckPlayableState() && bargainCost.canPay(ability, null, ability.getControllerId(), game))) {
CardUtil.reduceCost(ability, 1); CardUtil.reduceCost(ability, 1);

View file

@ -24,7 +24,7 @@ public final class InnerCalmOuterStrength extends CardImpl {
this.subtype.add(SubType.ARCANE); this.subtype.add(SubType.ARCANE);
// Target creature gets +X/+X until end of turn, where X is the number of cards in your hand. // Target creature gets +X/+X until end of turn, where X is the number of cards in your hand.
DynamicValue xValue= CardsInControllerHandCount.instance; DynamicValue xValue= CardsInControllerHandCount.ANY;
Effect effect = new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn); Effect effect = new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn);
effect.setText("Target creature gets +X/+X until end of turn, where X is the number of cards in your hand"); effect.setText("Target creature gets +X/+X until end of turn, where X is the number of cards in your hand");
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);

View file

@ -20,7 +20,7 @@ public final class InnerFire extends CardImpl {
// Add {R} for each card in your hand. // Add {R} for each card in your hand.
this.getSpellAbility().addEffect(new DynamicManaEffect(Mana.RedMana(1), CardsInControllerHandCount.instance)); this.getSpellAbility().addEffect(new DynamicManaEffect(Mana.RedMana(1), CardsInControllerHandCount.ANY));
} }
private InnerFire(final InnerFire card) { private InnerFire(final InnerFire card) {

View file

@ -25,7 +25,7 @@ public final class InsidiousDreams extends CardImpl {
public InsidiousDreams(UUID ownerId, CardSetInfo setInfo) { public InsidiousDreams(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}");
// As an additional cost to cast Insidious Dreams, discard X cards. // As an additional cost to cast this spell, discard X cards.
this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true)); this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true));
// Search your library for X cards. Then shuffle your library and put those cards on top of it in any order. // Search your library for X cards. Then shuffle your library and put those cards on top of it in any order.

View file

@ -54,7 +54,7 @@ enum JohannsStopgapAdjuster implements CostAdjuster {
private static OptionalAdditionalCost bargainCost = BargainAbility.makeBargainCost(); private static OptionalAdditionalCost bargainCost = BargainAbility.makeBargainCost();
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
if (BargainedCondition.instance.apply(game, ability) if (BargainedCondition.instance.apply(game, ability)
|| (game.inCheckPlayableState() && bargainCost.canPay(ability, null, ability.getControllerId(), game))) { || (game.inCheckPlayableState() && bargainCost.canPay(ability, null, ability.getControllerId(), game))) {
CardUtil.reduceCost(ability, 2); CardUtil.reduceCost(ability, 2);

View file

@ -37,7 +37,7 @@ public final class JolraelMwonvuliRecluse extends CardImpl {
// {4}{G}{G}: Until end of turn, creatures you control have base power and toughness X/X, where X is the number of cards in your hand. // {4}{G}{G}: Until end of turn, creatures you control have base power and toughness X/X, where X is the number of cards in your hand.
this.addAbility(new SimpleActivatedAbility(new SetBasePowerToughnessAllEffect( this.addAbility(new SimpleActivatedAbility(new SetBasePowerToughnessAllEffect(
CardsInControllerHandCount.instance, CardsInControllerHandCount.instance, CardsInControllerHandCount.ANY, CardsInControllerHandCount.ANY,
Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES
).setText("until end of turn, creatures you control have base power and toughness X/X, " + ).setText("until end of turn, creatures you control have base power and toughness X/X, " +
"where X is the number of cards in your hand"), new ManaCostsImpl<>("{4}{G}{G}"))); "where X is the number of cards in your hand"), new ManaCostsImpl<>("{4}{G}{G}")));

View file

@ -19,7 +19,6 @@ import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.ComparisonType; import mage.constants.ComparisonType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.Zone;
import mage.game.permanent.token.TokenImpl; import mage.game.permanent.token.TokenImpl;
import mage.target.TargetPlayer; import mage.target.TargetPlayer;
@ -70,7 +69,7 @@ class TomoyaTheRevealer extends TokenImpl {
toughness = new MageInt(3); toughness = new MageInt(3);
// {3}{U}{U},{T} : Target player draws X cards, where X is the number of cards in your hand. // {3}{U}{U},{T} : Target player draws X cards, where X is the number of cards in your hand.
Ability ability = new SimpleActivatedAbility(new DrawCardTargetEffect(CardsInControllerHandCount.instance), new ManaCostsImpl<>("{3}{U}{U}")); Ability ability = new SimpleActivatedAbility(new DrawCardTargetEffect(CardsInControllerHandCount.ANY), new ManaCostsImpl<>("{3}{U}{U}"));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addTarget(new TargetPlayer()); ability.addTarget(new TargetPlayer());
this.addAbility(ability); this.addAbility(ability);

View file

@ -37,7 +37,7 @@ public final class KagemaroFirstToSuffer extends CardImpl {
this.power = new MageInt(0); this.power = new MageInt(0);
this.toughness = new MageInt(0); this.toughness = new MageInt(0);
DynamicValue xValue = CardsInControllerHandCount.instance; DynamicValue xValue = CardsInControllerHandCount.ANY;
// Kagemaro, First to Suffer's power and toughness are each equal to the number of cards in your hand. // Kagemaro, First to Suffer's power and toughness are each equal to the number of cards in your hand.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(xValue))); this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(xValue)));
// {B}, Sacrifice Kagemaro: All creatures get -X/-X until end of turn, where X is the number of cards in your hand. // {B}, Sacrifice Kagemaro: All creatures get -X/-X until end of turn, where X is the number of cards in your hand.

View file

@ -17,7 +17,6 @@ import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
@ -40,7 +39,7 @@ public final class KagemarosClutch extends CardImpl {
this.addAbility(ability); this.addAbility(ability);
// Enchanted creature gets -X/-X, where X is the number of cards in your hand. // Enchanted creature gets -X/-X, where X is the number of cards in your hand.
DynamicValue xMinusValue = new SignInversionDynamicValue(CardsInControllerHandCount.instance); DynamicValue xMinusValue = new SignInversionDynamicValue(CardsInControllerHandCount.ANY);
Effect effect = new BoostEnchantedEffect(xMinusValue, xMinusValue, Duration.WhileOnBattlefield); Effect effect = new BoostEnchantedEffect(xMinusValue, xMinusValue, Duration.WhileOnBattlefield);
effect.setText("Enchanted creature gets -X/-X, where X is the number of cards in your hand"); effect.setText("Enchanted creature gets -X/-X, where X is the number of cards in your hand");
this.addAbility(new SimpleStaticAbility(effect)); this.addAbility(new SimpleStaticAbility(effect));

View file

@ -60,7 +60,7 @@ enum KamiOfJealousThirstAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void increaseCost(Ability ability, Game game) {
int amount = CardsDrawnThisTurnDynamicValue.instance.calculate(game, ability, null); int amount = CardsDrawnThisTurnDynamicValue.instance.calculate(game, ability, null);
if (amount >= 3) { if (amount >= 3) {
CardUtil.adjustCost(ability, new ManaCostsImpl<>("{4}{B}"), false); CardUtil.adjustCost(ability, new ManaCostsImpl<>("{4}{B}"), false);

View file

@ -14,7 +14,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Zone;
/** /**
* *
@ -30,7 +29,7 @@ public final class KitsuneLoreweaver extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// {1}{W}: Kitsune Loreweaver gets +0/+X until end of turn, where X is the number of cards in your hand. // {1}{W}: Kitsune Loreweaver gets +0/+X until end of turn, where X is the number of cards in your hand.
Effect effect = new BoostSourceEffect(StaticValue.get(0), CardsInControllerHandCount.instance, Duration.EndOfTurn); Effect effect = new BoostSourceEffect(StaticValue.get(0), CardsInControllerHandCount.ANY, Duration.EndOfTurn);
effect.setText("{this} gets +0/+X until end of turn, where X is the number of cards in your hand"); effect.setText("{this} gets +0/+X until end of turn, where X is the number of cards in your hand");
this.addAbility(new SimpleActivatedAbility(effect, new ManaCostsImpl<>("{1}{W}"))); this.addAbility(new SimpleActivatedAbility(effect, new ManaCostsImpl<>("{1}{W}")));
} }

View file

@ -31,7 +31,7 @@ public final class KiyomaroFirstToStand extends CardImpl {
this.toughness = new MageInt(0); this.toughness = new MageInt(0);
// Kiyomaro, First to Stand's power and toughness are each equal to the number of cards in your hand. // Kiyomaro, First to Stand's power and toughness are each equal to the number of cards in your hand.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.instance))); this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.ANY)));
// As long as you have four or more cards in hand, Kiyomaro has vigilance. // As long as you have four or more cards in hand, Kiyomaro has vigilance.
Condition condition = new CardsInHandCondition(ComparisonType.MORE_THAN, 3); Condition condition = new CardsInHandCondition(ComparisonType.MORE_THAN, 3);

View file

@ -1,40 +1,43 @@
package mage.cards.k; package mage.cards.k;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.costs.CostImpl;
import mage.abilities.costs.EarlyTargetCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DamageTargetEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ComparisonType; import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game; import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
/** /**
* @author anonymous * @author JayDi85
*/ */
public final class KnollspineInvocation extends CardImpl { public final class KnollspineInvocation extends CardImpl {
private static final FilterCard filter = new FilterCard("a card with mana value X"); protected static final FilterCard filter = new FilterCard("a card with mana value X");
public KnollspineInvocation(UUID ownerId, CardSetInfo setInfo) { public KnollspineInvocation(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}");
// {X}, Discard a card with converted mana cost X: Knollspine Invocation deals X damage to any target. // {X}, Discard a card with mana value X: This enchantment deals X damage to any target.
Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(GetXValue.instance, true), new ManaCostsImpl<>("{X}")); Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(GetXValue.instance, true), new ManaCostsImpl<>("{X}"));
ability.addCost(new DiscardTargetCost(new TargetCardInHand(filter))); ability.addCost(new KnollspineInvocationDiscardCost());
ability.addTarget(new TargetAnyTarget()); ability.addTarget(new TargetAnyTarget());
ability.setCostAdjuster(KnollspineInvocationAdjuster.instance); ability.setCostAdjuster(KnollspineInvocationAdjuster.instance);
this.addAbility(ability); this.addAbility(ability);
@ -50,22 +53,103 @@ public final class KnollspineInvocation extends CardImpl {
} }
} }
class KnollspineInvocationDiscardCost extends CostImpl implements EarlyTargetCost {
// discard card with early target selection, so {X} mana cost can be setup after choose
public KnollspineInvocationDiscardCost() {
super();
this.text = "Discard a card with mana value X";
}
public KnollspineInvocationDiscardCost(final KnollspineInvocationDiscardCost cost) {
super(cost);
}
@Override
public KnollspineInvocationDiscardCost copy() {
return new KnollspineInvocationDiscardCost(this);
}
@Override
public void chooseTarget(Game game, Ability source, Player controller) {
Target target = new TargetCardInHand().withChooseHint("to discard with mana value for X");
controller.choose(Outcome.Discard, target, source, game);
addTarget(target);
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
Player controller = game.getPlayer(controllerId);
return controller != null && !controller.getHand().isEmpty();
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
this.paid = false;
Player controller = game.getPlayer(controllerId);
if (controller == null) {
return false;
}
Card card = controller.getHand().get(this.getTargets().getFirstTarget(), game);
if (card == null) {
return false;
}
this.paid = controller.discard(card, true, source, game);
return this.paid;
}
}
enum KnollspineInvocationAdjuster implements CostAdjuster { enum KnollspineInvocationAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void prepareX(Ability ability, Game game) {
int xValue = CardUtil.getSourceCostsTag(game, ability, "X", 0); Player controller = game.getPlayer(ability.getControllerId());
for (Cost cost : ability.getCosts()) { if (controller == null) {
if (!(cost instanceof DiscardTargetCost)) {
continue;
}
DiscardTargetCost discardCost = (DiscardTargetCost) cost;
discardCost.getTargets().clear();
FilterCard adjustedFilter = new FilterCard("a card with mana value X");
adjustedFilter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, xValue));
discardCost.addTarget(new TargetCardInHand(adjustedFilter));
return; return;
} }
// make sure early target used
VariableManaCost costX = ability.getManaCostsToPay().stream()
.filter(c -> c instanceof VariableManaCost)
.map(c -> (VariableManaCost) c)
.findFirst()
.orElse(null);
if (costX == null) {
throw new IllegalArgumentException("Wrong code usage: costX lost");
}
KnollspineInvocationDiscardCost costDiscard = ability.getCosts().stream()
.filter(c -> c instanceof KnollspineInvocationDiscardCost)
.map(c -> (KnollspineInvocationDiscardCost) c)
.findFirst()
.orElse(null);
if (costDiscard == null) {
throw new IllegalArgumentException("Wrong code usage: costDiscard lost");
}
if (game.inCheckPlayableState()) {
// possible X
int minManaValue = controller.getHand().getCards(game).stream()
.mapToInt(MageObject::getManaValue)
.min()
.orElse(0);
int maxManaValue = controller.getHand().getCards(game).stream()
.mapToInt(MageObject::getManaValue)
.max()
.orElse(0);
ability.setVariableCostsMinMax(minManaValue, maxManaValue);
} else {
// real X
Card card = controller.getHand().get(costDiscard.getTargets().getFirstTarget(), game);
if (card == null) {
throw new IllegalStateException("Wrong code usage: card to discard lost");
}
ability.setVariableCostsValue(card.getManaValue());
}
} }
} }

View file

@ -43,7 +43,7 @@ public final class LeonardoDaVinci extends CardImpl {
this.power = new MageInt(3); this.power = new MageInt(3);
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
DynamicValue xValue = CardsInControllerHandCount.instance; DynamicValue xValue = CardsInControllerHandCount.ANY;
// {3}{U}{U}: Until end of turn, Thopters you control have base power and toughness X/X, where X is the number of cards in your hand. // {3}{U}{U}: Until end of turn, Thopters you control have base power and toughness X/X, where X is the number of cards in your hand.
this.addAbility(new SimpleActivatedAbility(new BoostControlledEffect(xValue, xValue, Duration.EndOfTurn, filter, false).setText( this.addAbility(new SimpleActivatedAbility(new BoostControlledEffect(xValue, xValue, Duration.EndOfTurn, filter, false).setText(
"Until end of turn, Thopters you control have base power and toughness X/X, where X is the number of cards in your hand." "Until end of turn, Thopters you control have base power and toughness X/X, where X is the number of cards in your hand."

View file

@ -48,7 +48,7 @@ enum LoreseekersStoneAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void increaseCost(Ability ability, Game game) {
Player player = game.getPlayer(ability.getControllerId()); Player player = game.getPlayer(ability.getControllerId());
if (player != null) { if (player != null) {
CardUtil.increaseCost(ability, player.getHand().size()); CardUtil.increaseCost(ability, player.getHand().size());

View file

@ -74,7 +74,7 @@ class HighestLifeTotalAmongOpponentsCount implements DynamicValue {
@Override @Override
public DynamicValue copy() { public DynamicValue copy() {
return CardsInControllerHandCount.instance; return CardsInControllerHandCount.ANY;
} }
@Override @Override

View file

@ -26,7 +26,7 @@ public final class ManifestationSage extends CardImpl {
// When Manifestation Sage enters the battlefield, create a 0/0 green and blue Fractal creature token. Put X +1/+1 counters on it, where X is the number of cards in your hand. // When Manifestation Sage enters the battlefield, create a 0/0 green and blue Fractal creature token. Put X +1/+1 counters on it, where X is the number of cards in your hand.
this.addAbility(new EntersBattlefieldTriggeredAbility(FractalToken.getEffect( this.addAbility(new EntersBattlefieldTriggeredAbility(FractalToken.getEffect(
CardsInControllerHandCount.instance, "Put X +1/+1 counters on it, " + CardsInControllerHandCount.ANY, "Put X +1/+1 counters on it, " +
"where X is the number of cards in your hand" "where X is the number of cards in your hand"
))); )));
} }

View file

@ -64,7 +64,7 @@ enum MariposaMilitaryBaseAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
CardUtil.reduceCost(ability, SourceControllerCountersCount.RAD.calculate(game, ability, null)); CardUtil.reduceCost(ability, SourceControllerCountersCount.RAD.calculate(game, ability, null));
} }
} }

View file

@ -26,7 +26,7 @@ public final class Maro extends CardImpl {
this.toughness = new MageInt(0); this.toughness = new MageInt(0);
// Maro's power and toughness are each equal to the number of cards in your hand. // Maro's power and toughness are each equal to the number of cards in your hand.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.instance))); this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.ANY)));
} }
private Maro(final Maro card) { private Maro(final Maro card) {

View file

@ -23,7 +23,7 @@ public final class MasterTheWay extends CardImpl {
// Draw a card. Master the Way deals damage to any target equal to the number of cards in your hand. // Draw a card. Master the Way deals damage to any target equal to the number of cards in your hand.
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1));
Effect effect = new DamageTargetEffect(CardsInControllerHandCount.instance); Effect effect = new DamageTargetEffect(CardsInControllerHandCount.ANY);
effect.setText("{this} deals damage to any target equal to the number of cards in your hand"); effect.setText("{this} deals damage to any target equal to the number of cards in your hand");
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addTarget(new TargetAnyTarget());

View file

@ -31,7 +31,7 @@ public final class MasumaroFirstToLive extends CardImpl {
this.toughness = new MageInt(0); this.toughness = new MageInt(0);
// Masumaro, First to Live's power and toughness are each equal to twice the number of cards in your hand. // Masumaro, First to Live's power and toughness are each equal to twice the number of cards in your hand.
DynamicValue xValue= new MultipliedValue(CardsInControllerHandCount.instance, 2); DynamicValue xValue= new MultipliedValue(CardsInControllerHandCount.ANY, 2);
Effect effect = new SetBasePowerToughnessSourceEffect(xValue); Effect effect = new SetBasePowerToughnessSourceEffect(xValue);
effect.setText("{this}'s power and toughness are each equal to twice the number of cards in your hand"); effect.setText("{this}'s power and toughness are each equal to twice the number of cards in your hand");
this.addAbility(new SimpleStaticAbility(Zone.ALL, effect)); this.addAbility(new SimpleStaticAbility(Zone.ALL, effect));

View file

@ -12,7 +12,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
/** /**
@ -26,7 +25,7 @@ public final class MeishinTheMindCage extends CardImpl {
this.supertype.add(SuperType.LEGENDARY); this.supertype.add(SuperType.LEGENDARY);
// All creatures get -X/-0, where X is the number of cards in your hand. // All creatures get -X/-0, where X is the number of cards in your hand.
this.addAbility(new SimpleStaticAbility(new BoostAllEffect(new SignInversionDynamicValue(CardsInControllerHandCount.instance), StaticValue.get(0), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, false, "All creatures get -X/-0, where X is the number of cards in your hand"))); this.addAbility(new SimpleStaticAbility(new BoostAllEffect(new SignInversionDynamicValue(CardsInControllerHandCount.ANY), StaticValue.get(0), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, false, "All creatures get -X/-0, where X is the number of cards in your hand")));
} }
private MeishinTheMindCage(final MeishinTheMindCage card) { private MeishinTheMindCage(final MeishinTheMindCage card) {

View file

@ -39,7 +39,7 @@ public final class MinasTirithGarrison extends CardImpl {
// Minas Tirith Garrison's power is equal to the number of cards in your hand. // Minas Tirith Garrison's power is equal to the number of cards in your hand.
this.addAbility(new SimpleStaticAbility( this.addAbility(new SimpleStaticAbility(
Zone.ALL, new SetBasePowerSourceEffect(CardsInControllerHandCount.instance) Zone.ALL, new SetBasePowerSourceEffect(CardsInControllerHandCount.ANY)
)); ));
// Whenever Minas Tirith Garrison attacks, you may tap any number of untapped Humans you control. Draw a card for each Human tapped this way. // Whenever Minas Tirith Garrison attacks, you may tap any number of untapped Humans you control. Draw a card for each Human tapped this way.

View file

@ -66,7 +66,7 @@ enum MirrorOfGaladrielAdjuster implements CostAdjuster {
} }
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
int value = game.getBattlefield().count( int value = game.getBattlefield().count(
StaticFilters.FILTER_CONTROLLED_CREATURE_LEGENDARY, StaticFilters.FILTER_CONTROLLED_CREATURE_LEGENDARY,
ability.getControllerId(), ability, game ability.getControllerId(), ability, game

View file

@ -74,7 +74,7 @@ enum MobilizedDistrictAdjuster implements CostAdjuster {
} }
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
Player controller = game.getPlayer(ability.getControllerId()); Player controller = game.getPlayer(ability.getControllerId());
if (controller != null) { if (controller != null) {
int count = cardsCount.calculate(game, ability, null); int count = cardsCount.calculate(game, ability, null);

View file

@ -8,6 +8,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.target.common.TargetCreatureOrPlaneswalker; import mage.target.common.TargetCreatureOrPlaneswalker;
import mage.target.targetadjustment.XTargetsCountAdjuster; import mage.target.targetadjustment.XTargetsCountAdjuster;
@ -21,8 +22,8 @@ public final class NahirisWrath extends CardImpl {
public NahirisWrath(UUID ownerId, CardSetInfo setInfo) { public NahirisWrath(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}");
// As an additional cost to cast Nahiri's Wrath, discard X cards. // As an additional cost to cast this spell, discard X cards.
this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("cards"), true)); this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true));
// Nahiri's Wrath deals damage equal to the total converted mana cost of the discarded cards to each of up to X target creatures and/or planeswalkers. // Nahiri's Wrath deals damage equal to the total converted mana cost of the discarded cards to each of up to X target creatures and/or planeswalkers.
Effect effect = new DamageTargetEffect(DiscardCostCardManaValue.instance); Effect effect = new DamageTargetEffect(DiscardCostCardManaValue.instance);

View file

@ -6,11 +6,9 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.common.ExileFromGraveCost;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue;
@ -86,16 +84,12 @@ enum NecropolisFiendCostAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void prepareX(Ability ability, Game game) {
Player controller = game.getPlayer(ability.getControllerId()); Player controller = game.getPlayer(ability.getControllerId());
if (controller == null) { if (controller == null) {
return; return;
} }
for (VariableCost variableCost : ability.getManaCostsToPay().getVariableCosts()) { ability.setVariableCostsMinMax(0, controller.getGraveyard().size());
if (variableCost instanceof VariableManaCost) {
((VariableManaCost) variableCost).setMaxX(controller.getGraveyard().size());
}
}
} }
} }

View file

@ -63,7 +63,7 @@ enum NemesisOfMortalsAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
Player controller = game.getPlayer(ability.getControllerId()); Player controller = game.getPlayer(ability.getControllerId());
if (controller != null) { if (controller != null) {
CardUtil.reduceCost(ability, controller.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game)); CardUtil.reduceCost(ability, controller.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game));

View file

@ -18,7 +18,7 @@ import mage.target.common.TargetCreaturePermanent;
*/ */
public final class NightmarishEnd extends CardImpl { public final class NightmarishEnd extends CardImpl {
private static final DynamicValue xValue = new SignInversionDynamicValue(CardsInControllerHandCount.instance); private static final DynamicValue xValue = new SignInversionDynamicValue(CardsInControllerHandCount.ANY);
public NightmarishEnd(UUID ownerId, CardSetInfo setInfo) { public NightmarishEnd(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}"); super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}");

View file

@ -22,8 +22,8 @@ public final class NostalgicDreams extends CardImpl {
public NostalgicDreams(UUID ownerId, CardSetInfo setInfo) { public NostalgicDreams(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}{G}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}{G}");
// As an additional cost to cast Nostalgic Dreams, discard X cards. // As an additional cost to cast this spell, discard X cards.
this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("cards"), true)); this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true));
// Return X target cards from your graveyard to your hand. // Return X target cards from your graveyard to your hand.
Effect effect = new ReturnFromGraveyardToHandTargetEffect(); Effect effect = new ReturnFromGraveyardToHandTargetEffect();

View file

@ -28,7 +28,7 @@ import mage.target.common.TargetCreaturePermanent;
*/ */
public final class OboroEnvoy extends CardImpl { public final class OboroEnvoy extends CardImpl {
private static final DynamicValue xValue = new SignInversionDynamicValue(CardsInControllerHandCount.instance); private static final DynamicValue xValue = new SignInversionDynamicValue(CardsInControllerHandCount.ANY);
public OboroEnvoy(UUID ownerId, CardSetInfo setInfo) { public OboroEnvoy(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}");

View file

@ -3,7 +3,6 @@ package mage.cards.o;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.InfoEffect;
import mage.cards.*; import mage.cards.*;
@ -28,7 +27,7 @@ public final class OpenTheWay extends CardImpl {
this.addAbility(new SimpleStaticAbility( this.addAbility(new SimpleStaticAbility(
Zone.ALL, new InfoEffect("X can't be greater than the number of players in the game") Zone.ALL, new InfoEffect("X can't be greater than the number of players in the game")
).setRuleAtTheTop(true)); ).setRuleAtTheTop(true));
this.getSpellAbility().setCostAdjuster(OpenTheWayAdjuster.instance); this.getSpellAbility().setCostAdjuster(OpenTheWayCostAdjuster.instance);
// Reveal cards from the top of your library until you reveal X land cards. Put those land cards onto the battlefield tapped and the rest on the bottom of your library in a random order. // Reveal cards from the top of your library until you reveal X land cards. Put those land cards onto the battlefield tapped and the rest on the bottom of your library in a random order.
this.getSpellAbility().addEffect(new OpenTheWayEffect()); this.getSpellAbility().addEffect(new OpenTheWayEffect());
@ -44,14 +43,12 @@ public final class OpenTheWay extends CardImpl {
} }
} }
enum OpenTheWayAdjuster implements CostAdjuster { enum OpenTheWayCostAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void prepareX(Ability ability, Game game) {
int playerCount = game.getPlayers().size(); ability.setVariableCostsMinMax(0, game.getState().getPlayersInRange(ability.getControllerId(), game, true).size());
CardUtil.castStream(ability.getCosts().stream(), VariableManaCost.class)
.forEach(cost -> cost.setMaxX(playerCount));
} }
} }

View file

@ -33,7 +33,6 @@ import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author Arketec * @author Arketec
*/ */
public final class OsgirTheReconstructor extends CardImpl { public final class OsgirTheReconstructor extends CardImpl {
@ -81,15 +80,15 @@ enum OsgirTheReconstructorCostAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void prepareCost(Ability ability, Game game) {
int xValue = CardUtil.getSourceCostsTag(game, ability, "X", 0); int xValue = CardUtil.getSourceCostsTag(game, ability, "X", 0);
Player controller = game.getPlayer(ability.getControllerId()); Player controller = game.getPlayer(ability.getControllerId());
if (controller == null) { if (controller == null) {
return; return;
} }
FilterCard filter = new FilterArtifactCard("an artifact card with mana value "+xValue+" from your graveyard"); FilterCard filter = new FilterArtifactCard("an artifact card with mana value " + xValue + " from your graveyard");
filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, xValue)); filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, xValue));
for (Cost cost: ability.getCosts()) { for (Cost cost : ability.getCosts()) {
if (cost instanceof ExileFromGraveCost) { if (cost instanceof ExileFromGraveCost) {
cost.getTargets().set(0, new TargetCardInYourGraveyard(filter)); cost.getTargets().set(0, new TargetCardInYourGraveyard(filter));
} }
@ -104,7 +103,7 @@ class OsgirTheReconstructorCreateArtifactTokensEffect extends OneShotEffect {
this.staticText = "Create two tokens that are copies of the exiled card."; this.staticText = "Create two tokens that are copies of the exiled card.";
} }
private OsgirTheReconstructorCreateArtifactTokensEffect(final OsgirTheReconstructorCreateArtifactTokensEffect effect) { private OsgirTheReconstructorCreateArtifactTokensEffect(final OsgirTheReconstructorCreateArtifactTokensEffect effect) {
super(effect); super(effect);
} }
@ -127,11 +126,11 @@ class OsgirTheReconstructorCreateArtifactTokensEffect extends OneShotEffect {
effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId()))); effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId())));
effect.apply(game, source); effect.apply(game, source);
return true; return true;
} }
@Override @Override
public OsgirTheReconstructorCreateArtifactTokensEffect copy() { public OsgirTheReconstructorCreateArtifactTokensEffect copy() {
return new OsgirTheReconstructorCreateArtifactTokensEffect(this); return new OsgirTheReconstructorCreateArtifactTokensEffect(this);
} }
} }

View file

@ -13,7 +13,6 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
/** /**
@ -32,7 +31,7 @@ public final class OverbeingOfMyth extends CardImpl {
this.toughness = new MageInt(0); this.toughness = new MageInt(0);
// Overbeing of Myth's power and toughness are each equal to the number of cards in your hand. // Overbeing of Myth's power and toughness are each equal to the number of cards in your hand.
DynamicValue number = CardsInControllerHandCount.instance; DynamicValue number = CardsInControllerHandCount.ANY;
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(number))); this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(number)));
// At the beginning of your draw step, draw an additional card. // At the beginning of your draw step, draw an additional card.

View file

@ -46,7 +46,7 @@ enum PhyrexianPurgeCostAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void increaseCost(Ability ability, Game game) {
int numTargets = ability.getTargets().get(0).getTargets().size(); int numTargets = ability.getTargets().get(0).getTargets().size();
if (numTargets > 0) { if (numTargets > 0) {
ability.addCost(new PayLifeCost(numTargets * 3)); ability.addCost(new PayLifeCost(numTargets * 3));

View file

@ -81,7 +81,7 @@ enum PlateArmorAdjuster implements CostAdjuster {
} }
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
Player controller = game.getPlayer(ability.getControllerId()); Player controller = game.getPlayer(ability.getControllerId());
if (controller != null) { if (controller != null) {
int count = equipmentCount.calculate(game, ability, null); int count = equipmentCount.calculate(game, ability, null);

View file

@ -20,7 +20,7 @@ public final class PresenceOfTheWise extends CardImpl {
// You gain 2 life for each card in your hand. // You gain 2 life for each card in your hand.
this.getSpellAbility().addEffect(new GainLifeEffect( this.getSpellAbility().addEffect(new GainLifeEffect(
new MultipliedValue(CardsInControllerHandCount.instance, 2),"You gain 2 life for each card in your hand")); new MultipliedValue(CardsInControllerHandCount.ANY, 2),"You gain 2 life for each card in your hand"));
} }
private PresenceOfTheWise(final PresenceOfTheWise card) { private PresenceOfTheWise(final PresenceOfTheWise card) {

View file

@ -4,11 +4,8 @@ import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.costadjusters.ImprintedManaValueXCostAdjuster;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card; import mage.cards.Card;
@ -42,10 +39,10 @@ public final class PrototypePortal extends CardImpl {
.setAbilityWord(AbilityWord.IMPRINT) .setAbilityWord(AbilityWord.IMPRINT)
); );
// {X}, {tap}: Create a token that's a copy of the exiled card. X is the converted mana cost of that card. // {X}, {T}: Create a token that's a copy of the exiled card. X is the converted mana cost of that card.
Ability ability = new SimpleActivatedAbility(new PrototypePortalCreateTokenEffect(), new ManaCostsImpl<>("{X}")); Ability ability = new SimpleActivatedAbility(new PrototypePortalCreateTokenEffect(), new ManaCostsImpl<>("{X}"));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.setCostAdjuster(PrototypePortalAdjuster.instance); ability.setCostAdjuster(ImprintedManaValueXCostAdjuster.instance);
this.addAbility(ability); this.addAbility(ability);
} }
@ -59,31 +56,6 @@ public final class PrototypePortal extends CardImpl {
} }
} }
enum PrototypePortalAdjuster implements CostAdjuster {
instance;
@Override
public void adjustCosts(Ability ability, Game game) {
Permanent card = game.getPermanent(ability.getSourceId());
if (card != null) {
if (!card.getImprinted().isEmpty()) {
Card imprinted = game.getCard(card.getImprinted().get(0));
if (imprinted != null) {
ability.clearManaCostsToPay();
ability.addManaCostsToPay(new GenericManaCost(imprinted.getManaValue()));
}
}
}
// no {X} anymore as we already have imprinted the card with defined manacost
for (ManaCost cost : ability.getManaCostsToPay()) {
if (cost instanceof VariableCost) {
cost.setPaid();
}
}
}
}
class PrototypePortalEffect extends OneShotEffect { class PrototypePortalEffect extends OneShotEffect {
PrototypePortalEffect() { PrototypePortalEffect() {

View file

@ -28,7 +28,7 @@ public final class PsychosisCrawler extends CardImpl {
this.power = new MageInt(0); this.power = new MageInt(0);
this.toughness = new MageInt(0); this.toughness = new MageInt(0);
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.instance))); this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.ANY)));
this.addAbility(new DrawCardControllerTriggeredAbility(new LoseLifeOpponentsEffect(1), false)); this.addAbility(new DrawCardControllerTriggeredAbility(new LoseLifeOpponentsEffect(1), false));
} }

View file

@ -70,7 +70,7 @@ enum PteramanderAdjuster implements CostAdjuster {
} }
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
int count = cardsCount.calculate(game, ability, null); int count = cardsCount.calculate(game, ability, null);
CardUtil.reduceCost(ability, count); CardUtil.reduceCost(ability, count);
} }

View file

@ -56,7 +56,7 @@ enum QuestForTheNecropolisAdjuster implements CostAdjuster {
instance; instance;
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
int amount = Optional int amount = Optional
.ofNullable(ability.getSourcePermanentIfItStillExists(game)) .ofNullable(ability.getSourcePermanentIfItStillExists(game))
.map(permanent -> permanent.getCounters(game).getCount(CounterType.QUEST)) .map(permanent -> permanent.getCounters(game).getCount(CounterType.QUEST))

View file

@ -45,7 +45,7 @@ public final class RalsStaticaster extends CardImpl {
// Whenever Ral's Staticaster attacks, if you control a Ral planeswalker, Ral's Staticaster gets +1/+0 for each card in your hand until end of turn. // Whenever Ral's Staticaster attacks, if you control a Ral planeswalker, Ral's Staticaster gets +1/+0 for each card in your hand until end of turn.
this.addAbility(new ConditionalInterveningIfTriggeredAbility( this.addAbility(new ConditionalInterveningIfTriggeredAbility(
new AttacksTriggeredAbility(new BoostSourceEffect( new AttacksTriggeredAbility(new BoostSourceEffect(
CardsInControllerHandCount.instance, StaticValue.get(0), CardsInControllerHandCount.ANY, StaticValue.get(0),
Duration.EndOfTurn), false), Duration.EndOfTurn), false),
new PermanentsOnTheBattlefieldCondition(filter), new PermanentsOnTheBattlefieldCondition(filter),
"Whenever {this} attacks, if you control a Ral planeswalker, " "Whenever {this} attacks, if you control a Ral planeswalker, "

View file

@ -69,7 +69,7 @@ enum RazorlashTransmograntAdjuster implements CostAdjuster {
} }
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
if (makeMap(game, ability).values().stream().anyMatch(x -> x >= 4)) { if (makeMap(game, ability).values().stream().anyMatch(x -> x >= 4)) {
CardUtil.reduceCost(ability, 4); CardUtil.reduceCost(ability, 4);
} }

View file

@ -20,7 +20,7 @@ public final class RestlessDreams extends CardImpl {
public RestlessDreams(UUID ownerId, CardSetInfo setInfo) { public RestlessDreams(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}");
// As an additional cost to cast Restless Dreams, discard X cards. // As an additional cost to cast this spell, discard X cards.
this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true)); this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true));
// Return X target creature cards from your graveyard to your hand. // Return X target creature cards from your graveyard to your hand.

View file

@ -42,7 +42,7 @@ public final class RobobrainWarMind extends CardImpl {
this.toughness = new MageInt(5); this.toughness = new MageInt(5);
// Robobrain War Mind's power is equal to the number of cards in your hand. // Robobrain War Mind's power is equal to the number of cards in your hand.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerSourceEffect(CardsInControllerHandCount.instance))); this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerSourceEffect(CardsInControllerHandCount.ANY)));
// When Robobrain War Mind enters the battlefield, you get an amount of {E} equal to the number of artifact creatures you control. // When Robobrain War Mind enters the battlefield, you get an amount of {E} equal to the number of artifact creatures you control.
this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(new PermanentsOnBattlefieldCount(filter)) this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(new PermanentsOnBattlefieldCount(filter))

View file

@ -35,7 +35,7 @@ public final class SageOfAncientLore extends CardImpl {
this.secondSideCardClazz = mage.cards.w.WerewolfOfAncientHunger.class; this.secondSideCardClazz = mage.cards.w.WerewolfOfAncientHunger.class;
// Sage of Ancient Lore's power and toughness are each equal to the number of cards in your hand. // Sage of Ancient Lore's power and toughness are each equal to the number of cards in your hand.
DynamicValue xValue = CardsInControllerHandCount.instance; DynamicValue xValue = CardsInControllerHandCount.ANY;
this.addAbility(new SimpleStaticAbility(Zone.ALL, this.addAbility(new SimpleStaticAbility(Zone.ALL,
new ConditionalContinuousEffect(new SetBasePowerToughnessSourceEffect(xValue), new ConditionalContinuousEffect(new SetBasePowerToughnessSourceEffect(xValue),
new TransformedCondition(true), "{this}'s power and toughness are each equal to the total number of cards in your hand"))); new TransformedCondition(true), "{this}'s power and toughness are each equal to the total number of cards in your hand")));

View file

@ -65,7 +65,7 @@ enum SanctumOfTranquilLightAdjuster implements CostAdjuster {
} }
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void reduceCost(Ability ability, Game game) {
Player controller = game.getPlayer(ability.getControllerId()); Player controller = game.getPlayer(ability.getControllerId());
if (controller != null) { if (controller != null) {
CardUtil.reduceCost(ability, count.calculate(game, ability, null)); CardUtil.reduceCost(ability, count.calculate(game, ability, null));

Some files were not shown because too many files have changed in this diff Show more