* Reworked non mana costs with variable amount. The values have now to be announced before targeting. Fixed some wrong implementations (Firestorm, Myr Battlesphere, Skeletal Scrying).

This commit is contained in:
LevelX2 2014-03-09 19:47:31 +01:00
parent 2d9f260b1e
commit 7ebb8a9cbe
46 changed files with 1176 additions and 1187 deletions

View file

@ -81,6 +81,7 @@ import java.lang.String;
import java.util.*; import java.util.*;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map.Entry; import java.util.Map.Entry;
import mage.abilities.costs.VariableCost;
import mage.cards.repository.ExpansionInfo; import mage.cards.repository.ExpansionInfo;
import mage.cards.repository.ExpansionRepository; import mage.cards.repository.ExpansionRepository;
@ -1035,6 +1036,18 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
return numAvailable; return numAvailable;
} }
@Override
public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variablCost) {
log.debug("announceXMana");
//TODO: improve this
int value = new Random().nextInt(max+1);
if (value < max) {
max++;
}
return value;
}
@Override @Override
public void abort() { public void abort() {
abort = true; abort = true;

View file

@ -46,10 +46,10 @@ import mage.abilities.SpecialAction;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.PhyrexianManaCost; import mage.abilities.costs.mana.PhyrexianManaCost;
import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.RequirementEffect;
@ -534,6 +534,18 @@ public class HumanPlayer extends PlayerImpl<HumanPlayer> {
return xValue; return xValue;
} }
@Override
public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost) {
int xValue = 0;
updateGameStatePriority("announceXCost", game);
game.fireGetAmountEvent(playerId, message, min, max);
waitForIntegerResponse(game);
if (response != null && response.getInteger() != null) {
xValue = response.getInteger().intValue();
}
return xValue;
}
protected void playManaAbilities(ManaCost unpaid, Game game) { protected void playManaAbilities(ManaCost unpaid, Game game) {
updateGameStatePriority("playManaAbilities", game); updateGameStatePriority("playManaAbilities", game);
MageObject object = game.getObject(response.getUUID()); MageObject object = game.getObject(response.getUUID());

View file

@ -28,24 +28,20 @@
package mage.sets.avacynrestored; package mage.sets.avacynrestored;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapVariableTargetCost;
import mage.abilities.costs.VariableCost;
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.CardImpl; import mage.cards.CardImpl;
import mage.filter.FilterMana; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.TappedPredicate; import mage.filter.predicate.permanent.TappedPredicate;
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;
import mage.target.Target;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreatureOrPlayer; import mage.target.common.TargetCreatureOrPlayer;
/** /**
@ -54,6 +50,12 @@ import mage.target.common.TargetCreatureOrPlayer;
*/ */
public class BurnAtTheStake extends CardImpl<BurnAtTheStake> { public class BurnAtTheStake extends CardImpl<BurnAtTheStake> {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control");
static {
filter.add(Predicates.not(new TappedPredicate()));
}
public BurnAtTheStake(UUID ownerId) { public BurnAtTheStake(UUID ownerId) {
super(ownerId, 130, "Burn at the Stake", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{R}{R}{R}"); super(ownerId, 130, "Burn at the Stake", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{R}{R}{R}");
this.expansionSetCode = "AVR"; this.expansionSetCode = "AVR";
@ -61,10 +63,10 @@ public class BurnAtTheStake extends CardImpl<BurnAtTheStake> {
this.color.setRed(true); this.color.setRed(true);
// As an additional cost to cast Burn at the Stake, tap any number of untapped creatures you control. // As an additional cost to cast Burn at the Stake, tap any number of untapped creatures you control.
this.getSpellAbility().addCost(new BurnAtTheStakeCost()); this.getSpellAbility().addCost(new TapVariableTargetCost(filter, true, "any number of"));
// Burn at the Stake deals damage to target creature or player equal to three times the number of creatures tapped this way. // Burn at the Stake deals damage to target creature or player equal to three times the number of creatures tapped this way.
this.getSpellAbility().addEffect(new BurnAtTheStakeEffect()); this.getSpellAbility().addEffect(new BurnAtTheStakeEffect());
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); this.getSpellAbility().addTarget(new TargetCreatureOrPlayer(true));
} }
public BurnAtTheStake(final BurnAtTheStake card) { public BurnAtTheStake(final BurnAtTheStake card) {
@ -77,81 +79,6 @@ public class BurnAtTheStake extends CardImpl<BurnAtTheStake> {
} }
} }
class BurnAtTheStakeCost extends CostImpl<BurnAtTheStakeCost> implements VariableCost {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control");
static {
filter.add(Predicates.not(new TappedPredicate()));
}
private int amountPaid = 0;
public BurnAtTheStakeCost() {
this.text = "As an additional cost to cast {this}, tap any number of untapped creatures you control";
}
public BurnAtTheStakeCost(final BurnAtTheStakeCost cost) {
super(cost);
this.amountPaid = cost.amountPaid;
}
@Override
public BurnAtTheStakeCost copy() {
return new BurnAtTheStakeCost(this);
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
return true;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
this.amountPaid = 0;
Target target = new TargetControlledCreaturePermanent(1, 1, filter, false);
while (target.canChoose(controllerId, game) && target.choose(Outcome.Tap, controllerId, sourceId, game)) {
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null) {
permanent.tap(game);
amountPaid++;
}
target.clearChosen();
}
paid = true;
return true;
}
@Override
public int getAmount() {
return this.amountPaid;
}
/**
* Not Supported
* @param filter
*/
@Override
public void setFilter(FilterMana filter) {
}
/**
* Not supported
* @return
*/
@Override
public FilterMana getFilter() {
return new FilterMana();
}
@Override
public void setAmount(int amount) {
this.amountPaid = amount;
}
}
class BurnAtTheStakeEffect extends OneShotEffect<BurnAtTheStakeEffect> { class BurnAtTheStakeEffect extends OneShotEffect<BurnAtTheStakeEffect> {
public BurnAtTheStakeEffect() { public BurnAtTheStakeEffect() {

View file

@ -29,10 +29,6 @@
package mage.sets.betrayersofkamigawa; package mage.sets.betrayersofkamigawa;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
@ -43,8 +39,12 @@ import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.Filter; import mage.filter.Filter;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
@ -77,10 +77,27 @@ public class QuillmaneBaku extends CardImpl<QuillmaneBaku> {
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new QuillmaneBakuReturnEffect(), new GenericManaCost(1)); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new QuillmaneBakuReturnEffect(), new GenericManaCost(1));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance(1))); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance(1)));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent(true));
this.addAbility(ability); this.addAbility(ability);
} }
@Override
public void adjustTargets(Ability ability, Game game) {
if (ability instanceof SimpleActivatedAbility) {
int maxConvManaCost = 0;
for (Cost cost : ability.getCosts()) {
if (cost instanceof RemoveVariableCountersSourceCost) {
maxConvManaCost = ((RemoveVariableCountersSourceCost)cost).getAmount();
}
}
ability.getTargets().clear();
FilterCreaturePermanent newFilter = new FilterCreaturePermanent("creature with converted mana cost " + maxConvManaCost + " or less");
newFilter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, maxConvManaCost + 1));
TargetCreaturePermanent target = new TargetCreaturePermanent(newFilter, true);
ability.getTargets().add(target);
}
}
public QuillmaneBaku(final QuillmaneBaku card) { public QuillmaneBaku(final QuillmaneBaku card) {
super(card); super(card);
} }
@ -112,23 +129,12 @@ public class QuillmaneBaku extends CardImpl<QuillmaneBaku> {
if (player == null) { if (player == null) {
return false; return false;
} }
Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source));
int maxConvManaCost = 0;
for (Cost cost : source.getCosts()) {
if (cost instanceof RemoveVariableCountersSourceCost) {
maxConvManaCost = ((RemoveVariableCountersSourceCost)cost).getAmount();
}
}
FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost " + maxConvManaCost + " or less");
filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, maxConvManaCost + 1));
TargetCreaturePermanent target = new TargetCreaturePermanent(filter);
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null) { if (permanent != null) {
return permanent.moveToZone(Zone.HAND, source.getId(), game, false); player.moveCardToHandWithInfo((Card) permanent, source.getSourceId(), game, Zone.BATTLEFIELD);
return true;
} }
return false; return false;
} }
} }
} }

View file

@ -27,33 +27,26 @@
*/ */
package mage.sets.bornofthegods; package mage.sets.bornofthegods;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.SacrificeXTargetCost;
import mage.abilities.costs.VariableCost;
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.dynamicvalue.common.GetXValue;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.common.PutOnLibrarySourceEffect; import mage.abilities.effects.common.PutOnLibrarySourceEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterMana; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreatureCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.AnotherPredicate; import mage.filter.predicate.permanent.AnotherPredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
import mage.target.common.TargetCreaturePermanent;
/** /**
* *
@ -61,6 +54,12 @@ import mage.target.common.TargetCreaturePermanent;
*/ */
public class ChampionOfStraySouls extends CardImpl<ChampionOfStraySouls> { public class ChampionOfStraySouls extends CardImpl<ChampionOfStraySouls> {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other creatures");
static {
filter.add(new AnotherPredicate());
}
public ChampionOfStraySouls(UUID ownerId) { public ChampionOfStraySouls(UUID ownerId) {
super(ownerId, 63, "Champion of Stray Souls", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); super(ownerId, 63, "Champion of Stray Souls", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{4}{B}{B}");
this.expansionSetCode = "BNG"; this.expansionSetCode = "BNG";
@ -80,8 +79,8 @@ public class ChampionOfStraySouls extends CardImpl<ChampionOfStraySouls> {
effect.setText("Return X target creatures from your graveyard to the battlefield"); effect.setText("Return X target creatures from your graveyard to the battlefield");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{3}{B}{B}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{3}{B}{B}"));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new ChampionOfStraySoulsSacrificeCost()); ability.addCost(new SacrificeXTargetCost(filter));
ability.addTarget(new TargetCardInYourGraveyard(0,Integer.MAX_VALUE, new FilterCreatureCard())); ability.addTarget(new TargetCardInYourGraveyard(0,Integer.MAX_VALUE, new FilterCreatureCard("creature cards from your graveyard")));
this.addAbility(ability); this.addAbility(ability);
// {5}{B}{B}: Put Champion of Stray Souls on top of your library from your graveyard. // {5}{B}{B}: Put Champion of Stray Souls on top of your library from your graveyard.
@ -91,6 +90,19 @@ public class ChampionOfStraySouls extends CardImpl<ChampionOfStraySouls> {
} }
@Override
public void adjustTargets(Ability ability, Game game) {
if (ability instanceof SimpleActivatedAbility) {
for (Effect effect : ability.getEffects()) {
if (effect instanceof ReturnFromGraveyardToBattlefieldTargetEffect) {
int xValue = new GetXValue().calculate(game, ability);
ability.getTargets().clear();
ability.addTarget(new TargetCardInYourGraveyard(xValue,xValue, new FilterCreatureCard("creature cards from your graveyard")));
}
}
}
}
public ChampionOfStraySouls(final ChampionOfStraySouls card) { public ChampionOfStraySouls(final ChampionOfStraySouls card) {
super(card); super(card);
} }
@ -100,74 +112,3 @@ public class ChampionOfStraySouls extends CardImpl<ChampionOfStraySouls> {
return new ChampionOfStraySouls(this); return new ChampionOfStraySouls(this);
} }
} }
class ChampionOfStraySoulsSacrificeCost extends CostImpl<ChampionOfStraySoulsSacrificeCost> implements VariableCost {
protected int amountPaid = 0;
public ChampionOfStraySoulsSacrificeCost() {
this.text = "Sacrifice X other creatures";
}
public ChampionOfStraySoulsSacrificeCost(final ChampionOfStraySoulsSacrificeCost cost) {
super(cost);
this.amountPaid = cost.amountPaid;
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
return true;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
amountPaid = 0;
int creaturesToSacrifice = ability.getTargets().get(0).getTargets().size();
this.text = new StringBuilder(creaturesToSacrifice).append(" other creatures you control").toString();
FilterCreaturePermanent filter = new FilterCreaturePermanent(this.text);
filter.add(new ControllerPredicate(TargetController.YOU));
filter.add(new AnotherPredicate());
TargetCreaturePermanent target = new TargetCreaturePermanent(creaturesToSacrifice, creaturesToSacrifice, filter, true);
if (target.canChoose(controllerId, game) && target.choose(Outcome.Sacrifice, controllerId, sourceId, game)) {
for (UUID creatureId: (List<UUID>) target.getTargets()) {
Permanent creature = game.getPermanent(creatureId);
if (creature != null) {
creature.sacrifice(sourceId, game);
amountPaid++;
}
}
} else {
return false;
}
paid = true;
return true;
}
@Override
public int getAmount() {
return amountPaid;
}
@Override
public void setFilter(FilterMana filter) {
}
@Override
public FilterMana getFilter() {
return new FilterMana();
}
@Override
public ChampionOfStraySoulsSacrificeCost copy() {
return new ChampionOfStraySoulsSacrificeCost(this);
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
}

View file

@ -1,4 +1,4 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
@ -33,29 +33,25 @@ import mage.Mana;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.SacrificeXTargetCost;
import mage.abilities.costs.VariableCost;
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.dynamicvalue.common.GetXValue; import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.choices.ChoiceColor; import mage.choices.ChoiceColor;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterMana; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.token.Token; import mage.game.permanent.token.Token;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
/** /**
* *
@ -64,6 +60,12 @@ import mage.target.common.TargetCreaturePermanent;
*/ */
public class SpringjackPasture extends CardImpl<SpringjackPasture> { public class SpringjackPasture extends CardImpl<SpringjackPasture> {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Goats");
static {
filter.add(new SubtypePredicate("Goat"));
}
public SpringjackPasture(UUID ownerId) { public SpringjackPasture(UUID ownerId) {
super(ownerId, 326, "Springjack Pasture", Rarity.RARE, new CardType[]{CardType.LAND}, ""); super(ownerId, 326, "Springjack Pasture", Rarity.RARE, new CardType[]{CardType.LAND}, "");
this.expansionSetCode = "C13"; this.expansionSetCode = "C13";
@ -77,10 +79,11 @@ public class SpringjackPasture extends CardImpl<SpringjackPasture> {
this.addAbility(ability); this.addAbility(ability);
// {tap}, Sacrifice X Goats: Add X mana of any one color to your mana pool. You gain X life. // {tap}, Sacrifice X Goats: Add X mana of any one color to your mana pool. You gain X life.
Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SpringjackPastureEffect(), new TapSourceCost()); ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SpringjackPastureEffect(), new TapSourceCost());
ability2.addChoice(new ChoiceColor()); ability.addChoice(new ChoiceColor());
ability2.addCost(new SpringjackPastureCost()); ability.addCost(new SacrificeXTargetCost(filter));
this.addAbility(ability2); ability.addEffect(new GainLifeEffect(new GetXValue()));
this.addAbility(ability);
} }
@ -98,7 +101,7 @@ class SpringjackPastureEffect extends OneShotEffect<SpringjackPastureEffect> {
public SpringjackPastureEffect() { public SpringjackPastureEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
staticText = "Add X mana of any one color to your mana pool. You gain X life"; staticText = "Add X mana of any one color to your mana pool";
} }
public SpringjackPastureEffect(final SpringjackPastureEffect effect) { public SpringjackPastureEffect(final SpringjackPastureEffect effect) {
@ -110,22 +113,17 @@ class SpringjackPastureEffect extends OneShotEffect<SpringjackPastureEffect> {
Player you = game.getPlayer(source.getControllerId()); Player you = game.getPlayer(source.getControllerId());
ChoiceColor choice = (ChoiceColor) source.getChoices().get(0); ChoiceColor choice = (ChoiceColor) source.getChoices().get(0);
if (you != null && choice != null) { if (you != null && choice != null) {
int count = source.getManaCostsToPay().getX(); int count = new GetXValue().calculate(game, source);
if (choice.getColor().isBlack()) { if (choice.getColor().isBlack()) {
you.getManaPool().addMana(new Mana(0, 0, 0, 0, count, 0, 0), game, source); you.getManaPool().addMana(new Mana(0, 0, 0, 0, count, 0, 0), game, source);
you.gainLife(count, game);
} else if (choice.getColor().isBlue()) { } else if (choice.getColor().isBlue()) {
you.getManaPool().addMana(new Mana(0, 0, count, 0, 0, 0, 0), game, source); you.getManaPool().addMana(new Mana(0, 0, count, 0, 0, 0, 0), game, source);
you.gainLife(count, game);
} else if (choice.getColor().isRed()) { } else if (choice.getColor().isRed()) {
you.getManaPool().addMana(new Mana(count, 0, 0, 0, 0, 0, 0), game, source); you.getManaPool().addMana(new Mana(count, 0, 0, 0, 0, 0, 0), game, source);
you.gainLife(count, game);
} else if (choice.getColor().isGreen()) { } else if (choice.getColor().isGreen()) {
you.getManaPool().addMana(new Mana(0, count, 0, 0, 0, 0, 0), game, source); you.getManaPool().addMana(new Mana(0, count, 0, 0, 0, 0, 0), game, source);
you.gainLife(count, game);
} else if (choice.getColor().isWhite()) { } else if (choice.getColor().isWhite()) {
you.getManaPool().addMana(new Mana(0, 0, 0, count, 0, 0, 0), game, source); you.getManaPool().addMana(new Mana(0, 0, 0, count, 0, 0, 0), game, source);
you.gainLife(count, game);
} }
return true; return true;
@ -139,80 +137,15 @@ class SpringjackPastureEffect extends OneShotEffect<SpringjackPastureEffect> {
} }
} }
class SpringjackPastureCost extends CostImpl<SpringjackPastureCost> implements VariableCost {
protected int amountPaid = 0;
public SpringjackPastureCost() {
this.text = "sacrifice X Goats";
}
public SpringjackPastureCost(final SpringjackPastureCost cost) {
super(cost);
this.amountPaid = cost.amountPaid;
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
return true;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
amountPaid = 0;
FilterCreaturePermanent filter = new FilterCreaturePermanent("X number of goats you control.");
filter.add(new SubtypePredicate("Goat"));
filter.add(new ControllerPredicate(TargetController.YOU));
TargetCreaturePermanent target = new TargetCreaturePermanent(filter);
while (true) {
target.clearChosen();
if (target.canChoose(controllerId, game) && target.choose(Outcome.Sacrifice, controllerId, sourceId, game)) {
UUID goat = target.getFirstTarget();
if (goat != null) {
game.getPermanent(goat).sacrifice(sourceId, game);
amountPaid++;
}
} else {
break;
}
}
paid = true;
return true;
}
@Override
public int getAmount() {
return amountPaid;
}
@Override
public void setFilter(FilterMana filter) {
}
@Override
public FilterMana getFilter() {
return new FilterMana();
}
@Override
public SpringjackPastureCost copy() {
return new SpringjackPastureCost(this);
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
}
class GoatToken extends Token { class GoatToken extends Token {
public GoatToken() { public GoatToken() {
super("Goat", "0/1 white Goat creature token"); super("Goat", "0/1 white Goat creature token");
setOriginalExpansionSetCode("EVE");
cardType.add(CardType.CREATURE); cardType.add(CardType.CREATURE);
color = ObjectColor.WHITE; color = ObjectColor.WHITE;
subtype.add("Goat"); subtype.add("Goat");
power = new MageInt(0); power = new MageInt(0);
toughness = new MageInt(1); toughness = new MageInt(1);
} }
} }

View file

@ -51,7 +51,7 @@ public class ToxicDeluge extends CardImpl<ToxicDeluge> {
this.color.setBlack(true); this.color.setBlack(true);
// As an additional cost to cast Toxic Deluge, pay X life. // As an additional cost to cast Toxic Deluge, pay X life.
this.getSpellAbility().addCost(new PayVariableLifeCost()); this.getSpellAbility().addCost(new PayVariableLifeCost(true));
// All creatures get -X/-X until end of turn. // All creatures get -X/-X until end of turn.
DynamicValue xValue = new SignInversionDynamicValue(new GetXValue()); DynamicValue xValue = new SignInversionDynamicValue(new GetXValue());
this.getSpellAbility().addEffect(new BoostAllEffect(xValue, xValue, Duration.EndOfTurn)); this.getSpellAbility().addEffect(new BoostAllEffect(xValue, xValue, Duration.EndOfTurn));

View file

@ -62,7 +62,7 @@ public class Quillspike extends CardImpl<Quillspike> {
// {BG}, Remove a -1/-1 counter from a creature you control: Quillspike gets +3/+3 until end of turn. // {BG}, Remove a -1/-1 counter from a creature you control: Quillspike gets +3/+3 until end of turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(3, 3, Duration.EndOfTurn), new ManaCostsImpl("{B/G}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(3, 3, Duration.EndOfTurn), new ManaCostsImpl("{B/G}"));
TargetPermanent target = new TargetPermanent(1, 1, new FilterControlledCreaturePermanent(), true); TargetPermanent target = new TargetPermanent(1, 1, new FilterControlledCreaturePermanent("creature you control"), true);
ability.addCost(new RemoveCounterCost(target, CounterType.M1M1)); ability.addCost(new RemoveCounterCost(target, CounterType.M1M1));
this.addAbility(ability); this.addAbility(ability);

View file

@ -59,8 +59,7 @@ public class OozeFlux extends CardImpl<OozeFlux> {
// {1}{G}, Remove one or more +1/+1 counters from among creatures you control: Put an X/X green Ooze creature token onto the battlefield, where X is the number of +1/+1 counters removed this way. // {1}{G}, Remove one or more +1/+1 counters from among creatures you control: Put an X/X green Ooze creature token onto the battlefield, where X is the number of +1/+1 counters removed this way.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new OozeFluxCreateTokenEffect(new OozeToken()),new ManaCostsImpl("{1}{G}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new OozeFluxCreateTokenEffect(new OozeToken()),new ManaCostsImpl("{1}{G}"));
ability.addCost(new RemoveVariableCountersTargetCost( ability.addCost(new RemoveVariableCountersTargetCost(new FilterControlledCreaturePermanent("creatures you control"), CounterType.P1P1, "one or more", 1));
new TargetControlledCreaturePermanent(1,Integer.MAX_VALUE,new FilterControlledCreaturePermanent(), true), CounterType.P1P1));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -81,7 +81,7 @@ public class DelverOfSecrets extends CardImpl<DelverOfSecrets> {
class DelverOfSecretsAbility extends TriggeredAbilityImpl<DelverOfSecretsAbility> { class DelverOfSecretsAbility extends TriggeredAbilityImpl<DelverOfSecretsAbility> {
public DelverOfSecretsAbility() { public DelverOfSecretsAbility() {
super(Zone.BATTLEFIELD, new TransformSourceEffect(true), false); super(Zone.BATTLEFIELD, new TransformSourceEffect(true, false), false);
} }
public DelverOfSecretsAbility(DelverOfSecretsAbility ability) { public DelverOfSecretsAbility(DelverOfSecretsAbility ability) {

View file

@ -28,21 +28,13 @@
package mage.sets.innistrad; package mage.sets.innistrad;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType; import mage.abilities.costs.common.ExileXFromYourGraveCost;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.abilities.Ability;
import mage.abilities.costs.CostImpl;
import mage.abilities.costs.VariableCost;
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.filter.FilterMana; import mage.constants.CardType;
import mage.game.Game; import mage.constants.Rarity;
import mage.players.Player; import mage.filter.FilterCard;
import mage.target.Target;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
/** /**
@ -58,7 +50,7 @@ public class HarvestPyre extends CardImpl<HarvestPyre> {
this.color.setRed(true); this.color.setRed(true);
// As an additional cost to cast Harvest Pyre, exile X cards from your graveyard. // As an additional cost to cast Harvest Pyre, exile X cards from your graveyard.
this.getSpellAbility().addCost(new HarvestPyreCost()); this.getSpellAbility().addCost(new ExileXFromYourGraveCost(new FilterCard("cards from your graveyard")));
// Harvest Pyre deals X damage to target creature. // Harvest Pyre deals X damage to target creature.
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent());
@ -74,77 +66,3 @@ public class HarvestPyre extends CardImpl<HarvestPyre> {
return new HarvestPyre(this); return new HarvestPyre(this);
} }
} }
class HarvestPyreCost extends CostImpl<HarvestPyreCost> implements VariableCost {
protected int amountPaid = 0;
public HarvestPyreCost() {
this.text = "As an additional cost to cast Harvest Pyre, exile X cards from your graveyard";
}
public HarvestPyreCost(final HarvestPyreCost cost) {
super(cost);
this.amountPaid = cost.amountPaid;
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
return true;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
amountPaid = 0;
Target target = new TargetCardInYourGraveyard();
Player player = game.getPlayer(controllerId);
while (true) {
target.clearChosen();
if (target.canChoose(controllerId, game) && target.choose(Outcome.Exile, controllerId, sourceId, game)) {
Card card = player.getGraveyard().get(target.getFirstTarget(), game);
if (card != null) {
player.getGraveyard().remove(card);
card.moveToExile(null, "", sourceId, game);
amountPaid++;
}
}
else
break;
}
paid = true;
return true;
}
@Override
public int getAmount() {
return amountPaid;
}
/**
* Not Supported
* @param filter
*/
@Override
public void setFilter(FilterMana filter) {
}
/**
* Not supported
* @return
*/
@Override
public FilterMana getFilter() {
return new FilterMana();
}
@Override
public HarvestPyreCost copy() {
return new HarvestPyreCost(this);
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
}

View file

@ -30,6 +30,8 @@ package mage.sets.limitedalpha;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
@ -65,7 +67,10 @@ public class DrainLife extends CardImpl<DrainLife> {
// Drain Life deals X damage to target creature or player. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness. // Drain Life deals X damage to target creature or player. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness.
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
this.getSpellAbility().addEffect(new DrainLifeEffect()); this.getSpellAbility().addEffect(new DrainLifeEffect());
this.getSpellAbility().getManaCostsToPay().getVariableCosts().get(0).setFilter(filterBlack); VariableCost variableCost = this.getSpellAbility().getManaCostsToPay().getVariableCosts().get(0);
if (variableCost instanceof VariableManaCost) {
((VariableManaCost) variableCost).setFilter(filterBlack);
}
} }
public DrainLife(final DrainLife card) { public DrainLife(final DrainLife card) {

View file

@ -32,6 +32,8 @@ import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.filter.FilterMana; import mage.filter.FilterMana;
@ -63,7 +65,10 @@ public class ConsumeSpirit extends CardImpl<ConsumeSpirit> {
// Consume Spirit deals X damage to target creature or player and you gain X life. // Consume Spirit deals X damage to target creature or player and you gain X life.
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
this.getSpellAbility().addEffect(new ConsumeSpiritEffect()); this.getSpellAbility().addEffect(new ConsumeSpiritEffect());
this.getSpellAbility().getManaCostsToPay().getVariableCosts().get(0).setFilter(filterBlack); VariableCost variableCost = this.getSpellAbility().getManaCostsToPay().getVariableCosts().get(0);
if (variableCost instanceof VariableManaCost) {
((VariableManaCost) variableCost).setFilter(filterBlack);
}
} }
public ConsumeSpirit(final ConsumeSpirit card) { public ConsumeSpirit(final ConsumeSpirit card) {

View file

@ -27,6 +27,9 @@
*/ */
package mage.sets.magic2014; package mage.sets.magic2014;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -39,6 +42,7 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.TappedPredicate; import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.token.AngelToken; import mage.game.permanent.token.AngelToken;
import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
/** /**
@ -87,23 +91,35 @@ class DevoutInvocationEffect extends OneShotEffect<DevoutInvocationEffect> {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
int tappedAmount = 0; Player controller = game.getPlayer(source.getControllerId());
TargetPermanent target = new TargetPermanent(filter); if (controller != null) {
while (true) { int tappedAmount = 0;
target.clearChosen(); TargetPermanent target = new TargetPermanent(0,1,filter, false);
if (target.canChoose(source.getControllerId(), game) && target.choose(Outcome.Tap, source.getControllerId(), source.getId(), game)) { while (true && controller.isInGame()) {
UUID creature = target.getFirstTarget(); target.clearChosen();
if (creature != null) { if (target.canChoose(source.getControllerId(), game)) {
game.getPermanent(creature).tap(game); Map<String, Serializable> options = new HashMap<>();
tappedAmount++; options.put("UI.right.btn.text", "Tapping complete");
controller.choose(outcome, target, source.getControllerId(), game, options);
if (target.getTargets().size() > 0) {
UUID creature = target.getFirstTarget();
if (creature != null) {
game.getPermanent(creature).tap(game);
tappedAmount++;
}
} else {
break;
}
}
else {
break;
} }
} }
else if (tappedAmount > 0) {
break; AngelToken angelToken = new AngelToken();
} angelToken.putOntoBattlefield(tappedAmount, game, source.getSourceId(), source.getControllerId());
if (tappedAmount > 0) { game.informPlayers(new StringBuilder(controller.getName()).append(" puts ").append(tappedAmount).append(" token").append(tappedAmount != 1 ?"s":"").append(" onto the battlefield").toString());
AngelToken angelToken = new AngelToken(); }
angelToken.putOntoBattlefield(tappedAmount, game, source.getId(), source.getControllerId());
return true; return true;
} }
return false; return false;

View file

@ -65,7 +65,7 @@ public class ParasiticImplant extends CardImpl<ParasiticImplant> {
Ability ability = new EnchantAbility(auraTarget.getTargetName()); Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability); this.addAbility(ability);
ability = new BeginningOfUpkeepTriggeredAbility(new ParasiticImplantEffect(), TargetController.YOU, false); ability = new BeginningOfUpkeepTriggeredAbility(new ParasiticImplantEffect(), TargetController.YOU, false);
ability.addEffect(new CreateTokenEffect(new MyrToken())); ability.addEffect(new CreateTokenEffect(new MyrToken("NPH")));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -69,7 +69,7 @@ public class ShrineOfLoyalLegions extends CardImpl<ShrineOfLoyalLegions> {
this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), filter, false)); this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), filter, false));
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new CreateTokenEffect(new MyrToken(), new CountersCount(CounterType.CHARGE)), new CreateTokenEffect(new MyrToken("NPH"), new CountersCount(CounterType.CHARGE)),
new GenericManaCost(3)); new GenericManaCost(3));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost()); ability.addCost(new SacrificeSourceCost());

View file

@ -28,23 +28,22 @@
package mage.sets.odyssey; package mage.sets.odyssey;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.common.ExileFromGraveCost;
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.ManacostVariableValue;
import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.filter.FilterMana; import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
/** /**
@ -60,10 +59,11 @@ public class SkeletalScrying extends CardImpl<SkeletalScrying> {
this.color.setBlack(true); this.color.setBlack(true);
// As an additional cost to cast Skeletal Scrying, exile X cards from your graveyard. // As an additional cost to cast Skeletal Scrying, exile X cards from your graveyard.
this.getSpellAbility().addCost(new ExileXFromGraveyardCost()); Ability ability = new SimpleStaticAbility(Zone.ALL,new SkeletalScryingRuleEffect());
ability.setRuleAtTheTop(true);
this.addAbility(ability);
// You draw X cards and you lose X life. // You draw X cards and you lose X life.
this.getSpellAbility().addEffect(new SkeletalScryingEffect(new GetXValue())); this.getSpellAbility().addEffect(new SkeletalScryingEffect(new ManacostVariableValue()));
} }
@ -71,86 +71,41 @@ public class SkeletalScrying extends CardImpl<SkeletalScrying> {
super(card); super(card);
} }
@Override
public void adjustCosts(Ability ability, Game game) {
int xValue = ability.getManaCostsToPay().getX();
if (xValue > 0) {
ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(xValue, xValue, new FilterCard("cards from your graveyard"))));
}
}
@Override @Override
public SkeletalScrying copy() { public SkeletalScrying copy() {
return new SkeletalScrying(this); return new SkeletalScrying(this);
} }
} }
class ExileXFromGraveyardCost extends CostImpl<ExileXFromGraveyardCost> implements VariableCost { class SkeletalScryingRuleEffect extends OneShotEffect<SkeletalScryingRuleEffect> {
protected int amountPaid = 0; public SkeletalScryingRuleEffect() {
super(Outcome.Benefit);
public ExileXFromGraveyardCost() { this.staticText = "As an additional cost to cast Skeletal Scrying, exile X cards from your graveyard";
this.text = "As an additional cost to cast Skeletal Scrying, exile X cards from your graveyard";
} }
public ExileXFromGraveyardCost(final ExileXFromGraveyardCost cost) { public SkeletalScryingRuleEffect(final SkeletalScryingRuleEffect effect) {
super(cost); super(effect);
this.amountPaid = cost.amountPaid;
} }
@Override @Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) { public SkeletalScryingRuleEffect copy() {
return new SkeletalScryingRuleEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true; return true;
} }
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
amountPaid = 0;
Target target = new TargetCardInYourGraveyard();
Player player = game.getPlayer(controllerId);
while (true) {
target.clearChosen();
if (target.canChoose(controllerId, game) && target.choose(Outcome.Exile, controllerId, sourceId, game)) {
Card card = player.getGraveyard().get(target.getFirstTarget(), game);
if (card != null) {
player.getGraveyard().remove(card);
card.moveToExile(null, "", sourceId, game);
amountPaid++;
}
}
else
break;
}
paid = true;
return true;
}
@Override
public int getAmount() {
return amountPaid;
}
/**
* Not Supported
* @param filter
*/
@Override
public void setFilter(FilterMana filter) {
}
/**
* Not supported
* @return
*/
@Override
public FilterMana getFilter() {
return new FilterMana();
}
@Override
public ExileXFromGraveyardCost copy() {
return new ExileXFromGraveyardCost(this);
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
} }
class SkeletalScryingEffect extends OneShotEffect<SkeletalScryingEffect> { class SkeletalScryingEffect extends OneShotEffect<SkeletalScryingEffect> {
protected DynamicValue amount; protected DynamicValue amount;

View file

@ -28,22 +28,18 @@
package mage.sets.riseoftheeldrazi; package mage.sets.riseoftheeldrazi;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.SacrificeXTargetCost;
import mage.abilities.costs.VariableCost;
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.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.filter.FilterMana; import mage.constants.Rarity;
import mage.filter.common.FilterLandPermanent; import mage.filter.common.FilterControlledLandPermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.token.Token; import mage.game.permanent.token.Token;
import mage.target.common.TargetLandPermanent;
/** /**
* *
@ -58,7 +54,7 @@ public class DevastatingSummons extends CardImpl<DevastatingSummons> {
this.color.setRed(true); this.color.setRed(true);
// As an additional cost to cast Devastating Summons, sacrifice X lands. // As an additional cost to cast Devastating Summons, sacrifice X lands.
this.getSpellAbility().addCost(new DevastatingSummonsCost()); this.getSpellAbility().addCost(new SacrificeXTargetCost(new FilterControlledLandPermanent("lands"), true));
// Put two X/X red Elemental creature tokens onto the battlefield. // Put two X/X red Elemental creature tokens onto the battlefield.
this.getSpellAbility().addEffect(new DevastatingSummonsEffect()); this.getSpellAbility().addEffect(new DevastatingSummonsEffect());
@ -74,78 +70,6 @@ public class DevastatingSummons extends CardImpl<DevastatingSummons> {
} }
} }
class DevastatingSummonsCost extends CostImpl<DevastatingSummonsCost> implements VariableCost {
protected int amountPaid = 0;
public DevastatingSummonsCost() {
this.text = "sacrifice X lands";
}
public DevastatingSummonsCost(final DevastatingSummonsCost cost) {
super(cost);
this.amountPaid = cost.amountPaid;
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
return true;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
amountPaid = 0;
FilterLandPermanent filter = new FilterLandPermanent("X number of lands you control.");
TargetLandPermanent target = new TargetLandPermanent(filter);
while (true) {
target.clearChosen();
if (target.canChoose(controllerId, game) && target.choose(Outcome.Sacrifice, controllerId, sourceId, game)) {
UUID land = target.getFirstTarget();
if (land != null) {
game.getPermanent(land).sacrifice(sourceId, game);
amountPaid++;
}
}
else
break;
}
paid = true;
return true;
}
@Override
public int getAmount() {
return amountPaid;
}
/**
* Not Supported
* @param filter
*/
@Override
public void setFilter(FilterMana filter) {
}
/**
* Not supported
* @return
*/
@Override
public FilterMana getFilter() {
return new FilterMana();
}
@Override
public DevastatingSummonsCost copy() {
return new DevastatingSummonsCost(this);
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
}
class DevastatingSummonsEffect extends OneShotEffect<DevastatingSummonsEffect> { class DevastatingSummonsEffect extends OneShotEffect<DevastatingSummonsEffect> {
public DevastatingSummonsEffect() { public DevastatingSummonsEffect() {

View file

@ -28,33 +28,30 @@
package mage.sets.scarsofmirrodin; package mage.sets.scarsofmirrodin;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.common.TapVariableTargetCost;
import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.continious.BoostSourceEffect; import mage.abilities.effects.common.continious.BoostSourceEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.filter.predicate.permanent.TappedPredicate; import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.token.MyrToken; import mage.game.permanent.token.MyrToken;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.TargetPermanent;
/** /**
* *
@ -74,7 +71,7 @@ public class MyrBattlesphere extends CardImpl<MyrBattlesphere> {
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new MyrToken(), 4), false)); this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new MyrToken(), 4), false));
// Whenever Myr Battlesphere attacks, you may tap X untapped Myr you control. If you do, Myr Battlesphere gets +X/+0 until end of turn and deals X damage to defending player. // Whenever Myr Battlesphere attacks, you may tap X untapped Myr you control. If you do, Myr Battlesphere gets +X/+0 until end of turn and deals X damage to defending player.
this.addAbility(new MyrBattlesphereAbility()); this.addAbility(new AttacksTriggeredAbility(new MyrBattlesphereEffect(), true));
} }
public MyrBattlesphere(final MyrBattlesphere card) { public MyrBattlesphere(final MyrBattlesphere card) {
@ -88,77 +85,63 @@ public class MyrBattlesphere extends CardImpl<MyrBattlesphere> {
} }
class MyrBattlesphereAbility extends TriggeredAbilityImpl<MyrBattlesphereAbility> {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Myr");
static {
filter.add(new SubtypePredicate("Myr"));
filter.add(Predicates.not(new TappedPredicate()));
}
public MyrBattlesphereAbility() {
super(Zone.BATTLEFIELD, new BoostSourceEffect(new GetXValue(), new StaticValue(0), Duration.EndOfTurn), true);
this.addEffect(new MyrBattlesphereEffect());
this.addCost(new TapVariableTargetCost(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, false)));
}
public MyrBattlesphereAbility(final MyrBattlesphereAbility ability) {
super(ability);
}
@Override
public boolean checkInterveningIfClause(Game game) {
if (costs.isPaid()) {
return true;
}
if (costs.canPay(this.getId(), this.getControllerId(), game)) {
return costs.pay(this, game, this.getId(), this.getControllerId(), false);
}
return false;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getType() == EventType.ATTACKER_DECLARED && event.getSourceId().equals(this.getSourceId()) ) {
costs.clearPaid();
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever {this} attacks, " + super.getRule();
}
@Override
public MyrBattlesphereAbility copy() {
return new MyrBattlesphereAbility(this);
}
}
class MyrBattlesphereEffect extends OneShotEffect<MyrBattlesphereEffect> { class MyrBattlesphereEffect extends OneShotEffect<MyrBattlesphereEffect> {
private GetXValue amount = new GetXValue(); private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Myr you control");
static {
filter.add(Predicates.not(new TappedPredicate()));
filter.add(new SubtypePredicate("Myr"));
}
public MyrBattlesphereEffect() { public MyrBattlesphereEffect() {
super(Outcome.Damage); super(Outcome.Damage);
staticText = "{source} deals X damage to defending player"; staticText = "tap X untapped Myr you control. If you do, {source} gets +X/+0 until end of turn and deals X damage to defending player";
} }
public MyrBattlesphereEffect(final MyrBattlesphereEffect effect) { public MyrBattlesphereEffect(final MyrBattlesphereEffect effect) {
super(effect); super(effect);
this.amount = effect.amount.copy();
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
UUID defenderId = game.getCombat().getDefenderId(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId());
Player defender = game.getPlayer(defenderId); if (controller != null) {
if (defender != null) { int tappedAmount = 0;
defender.damage(amount.calculate(game, source), source.getSourceId(), game, false, false); TargetPermanent target = new TargetPermanent(0,1,filter, false);
while (true && controller.isInGame()) {
target.clearChosen();
if (target.canChoose(source.getControllerId(), game)) {
Map<String, Serializable> options = new HashMap<>();
options.put("UI.right.btn.text", "Myr tapping complete");
controller.choose(outcome, target, source.getControllerId(), game, options);
if (target.getTargets().size() > 0) {
UUID creature = target.getFirstTarget();
if (creature != null) {
game.getPermanent(creature).tap(game);
tappedAmount++;
}
} else {
break;
}
}
else {
break;
}
}
if (tappedAmount > 0) {
game.informPlayers(new StringBuilder(controller.getName()).append(" taps ").append(tappedAmount).append(" Myrs").toString());
// boost effect
game.addEffect(new BoostSourceEffect(tappedAmount, 0, Duration.EndOfTurn), source);
// damage to defender
UUID defenderId = game.getCombat().getDefenderId(source.getSourceId());
Player defender = game.getPlayer(defenderId);
if (defender != null) {
defender.damage(tappedAmount, source.getSourceId(), game, false, true);
return true;
}
}
return true; return true;
} }
return false; return false;

View file

@ -31,8 +31,10 @@ import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.VariableCost;
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.common.ManacostVariableValue; import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
@ -69,7 +71,10 @@ public class CrimsonHellkite extends CardImpl<CrimsonHellkite> {
// {X}, {tap}: Crimson Hellkite deals X damage to target creature. Spend only red mana this way. // {X}, {tap}: Crimson Hellkite deals X damage to target creature. Spend only red mana this way.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}"));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.getManaCostsToPay().getVariableCosts().get(0).setFilter(filterRedMana); VariableCost variableCost = ability.getManaCostsToPay().getVariableCosts().get(0);
if (variableCost instanceof VariableManaCost) {
((VariableManaCost) variableCost).setFilter(filterRedMana);
}
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -28,16 +28,19 @@
package mage.sets.visions; package mage.sets.visions;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageEverythingEffect; import mage.abilities.effects.common.DamageEverythingEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.FilterMana; import mage.filter.FilterMana;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
@ -48,6 +51,7 @@ import mage.filter.FilterPermanent;
public class CryptRats extends CardImpl<CryptRats> { public class CryptRats extends CardImpl<CryptRats> {
public static final FilterMana filterBlack = new FilterMana(); public static final FilterMana filterBlack = new FilterMana();
static { static {
filterBlack.setBlack(true); filterBlack.setBlack(true);
} }
@ -61,10 +65,14 @@ public class CryptRats extends CardImpl<CryptRats> {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// {X}: Crypt Rats deals X damage to each creature and each player. Spend only black mana this way. // {X}: Crypt Rats deals X damage to each creature and each player. Spend only black mana this way.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageEverythingEffect(new ManacostVariableValue(), new FilterPermanent()), new ManaCostsImpl("{X}")); Effect effect = new DamageEverythingEffect(new ManacostVariableValue(), new FilterPermanent());
ability.getManaCostsToPay().getVariableCosts().get(0).setFilter(filterBlack); effect.setText("{this} deals X damage to each creature and each player. Spend only black mana this way");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect,new ManaCostsImpl("{X}"));
VariableCost variableCost = ability.getManaCostsToPay().getVariableCosts().get(0);
if (variableCost instanceof VariableManaCost) {
((VariableManaCost) variableCost).setFilter(filterBlack);
}
this.addAbility(ability); this.addAbility(ability);
this.addInfo("01", "Spend only black mana this way.");
} }
public CryptRats(final CryptRats card) { public CryptRats(final CryptRats card) {

View file

@ -29,24 +29,19 @@ package mage.sets.weatherlight;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.DiscardXTargetCost;
import mage.abilities.costs.VariableCost;
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.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Rarity;
import mage.filter.FilterMana; import mage.filter.FilterCard;
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;
import mage.target.Target; import mage.target.Target;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCreatureOrPlayer; import mage.target.common.TargetCreatureOrPlayer;
/** /**
@ -62,16 +57,25 @@ public class Firestorm extends CardImpl<Firestorm> {
this.color.setRed(true); this.color.setRed(true);
// As an additional cost to cast Firestorm, discard X cards. // As an additional cost to cast Firestorm, discard X cards.
this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("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());
this.getSpellAbility().addCost(new FirestormCost());
} }
public Firestorm(final Firestorm card) { public Firestorm(final Firestorm card) {
super(card); super(card);
} }
@Override
public void adjustTargets(Ability ability, Game game) {
int xValue = new GetXValue().calculate(game, ability);
if (xValue > 0) {
Target target = new TargetCreatureOrPlayer(xValue);
target.setRequired(true);
ability.addTarget(target);
}
}
@Override @Override
public Firestorm copy() { public Firestorm copy() {
return new Firestorm(this); return new Firestorm(this);
@ -93,105 +97,30 @@ class FirestormEffect extends OneShotEffect<FirestormEffect> {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player you = game.getPlayer(source.getControllerId()); Player you = game.getPlayer(source.getControllerId());
int amount = (new GetXValue()).calculate(game, source); int amount = (new GetXValue()).calculate(game, source);
TargetCreatureOrPlayer target = new TargetCreatureOrPlayer(amount);
if (you != null) { if (you != null) {
if (target.canChoose(source.getControllerId(), game) && target.choose(Outcome.Neutral, source.getControllerId(), source.getId(), game)) { if (source.getTargets().size() > 0) {
if (!target.getTargets().isEmpty()) { for (UUID targetId : this.getTargetPointer().getTargets(game, source)) {
List<UUID> targets = target.getTargets(); Permanent creature = game.getPermanent(targetId);
for (UUID targetId : targets) { if (creature != null) {
Permanent creature = game.getPermanent(targetId); creature.damage(amount, source.getSourceId(), game, true, false);
if (creature != null) { } else {
creature.damage(amount, source.getSourceId(), game, true, false); Player player = game.getPlayer(targetId);
} else { if (player != null) {
Player player = game.getPlayer(targetId); player.damage(amount, source.getSourceId(), game, false, true);
if (player != null) {
player.damage(amount, source.getSourceId(), game, true, false);
}
} }
} }
} }
return true;
} }
return true;
} }
return false; return false;
} }
@Override @Override
public FirestormEffect copy() { public FirestormEffect copy() {
return new FirestormEffect(this); return new FirestormEffect(this);
} }
} }
class FirestormCost extends CostImpl<FirestormCost> implements VariableCost {
protected int amountPaid = 0;
public FirestormCost() {
this.text = "discard X cards";
}
public FirestormCost(final FirestormCost cost) {
super(cost);
this.amountPaid = cost.amountPaid;
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
return true;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
amountPaid = 0;
Target target = new TargetCardInHand();
Player you = game.getPlayer(controllerId);
while (true) {
target.clearChosen();
if (target.canChoose(controllerId, game) && target.choose(Outcome.Discard, controllerId, sourceId, game)) {
Card card = you.getHand().get(target.getFirstTarget(), game);
if (card != null) {
you.getHand().remove(card);
card.moveToZone(Zone.GRAVEYARD, sourceId, game, false);
amountPaid++;
}
} else {
break;
}
}
paid = true;
return true;
}
@Override
public int getAmount() {
return amountPaid;
}
/**
* Not Supported
* @param filter
*/
@Override
public void setFilter(FilterMana filter) {
}
/**
* Not supported
* @return
*/
@Override
public FilterMana getFilter() {
return new FilterMana();
}
@Override
public FirestormCost copy() {
return new FirestormCost(this);
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
}

View file

@ -28,33 +28,43 @@
package mage.abilities; package mage.abilities;
import mage.constants.AbilityType; import java.util.ArrayList;
import mage.constants.EffectType; import java.util.List;
import mage.constants.Outcome; import java.util.UUID;
import mage.constants.Zone;
import mage.MageObject; import mage.MageObject;
import mage.abilities.costs.*; import mage.abilities.costs.AdjustingSourceCosts;
import mage.abilities.costs.AlternativeCost;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.CostsImpl;
import mage.abilities.costs.OptionalAdditionalSourceCosts;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.effects.*; import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.PostResolveEffect;
import mage.abilities.mana.ManaAbility; import mage.abilities.mana.ManaAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.choices.Choice; import mage.choices.Choice;
import mage.choices.Choices; import mage.choices.Choices;
import mage.constants.AbilityType;
import mage.constants.EffectType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.command.Emblem;
import mage.game.permanent.PermanentCard; import mage.game.permanent.PermanentCard;
import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.Targets; import mage.target.Targets;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.game.command.Emblem;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -72,7 +82,7 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
protected ManaCosts<ManaCost> manaCosts; protected ManaCosts<ManaCost> manaCosts;
protected ManaCosts<ManaCost> manaCostsToPay; protected ManaCosts<ManaCost> manaCostsToPay;
protected Costs<Cost> costs; protected Costs<Cost> costs;
protected ArrayList<AlternativeCost> alternativeCosts = new ArrayList<AlternativeCost>(); protected ArrayList<AlternativeCost> alternativeCosts = new ArrayList<>();
protected Costs<Cost> optionalCosts; protected Costs<Cost> optionalCosts;
protected Modes modes; protected Modes modes;
protected Zone zone; protected Zone zone;
@ -89,10 +99,10 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
this.originalId = id; this.originalId = id;
this.abilityType = abilityType; this.abilityType = abilityType;
this.zone = zone; this.zone = zone;
this.manaCosts = new ManaCostsImpl<ManaCost>(); this.manaCosts = new ManaCostsImpl<>();
this.manaCostsToPay = new ManaCostsImpl<ManaCost>(); this.manaCostsToPay = new ManaCostsImpl<>();
this.costs = new CostsImpl<Cost>(); this.costs = new CostsImpl<>();
this.optionalCosts = new CostsImpl<Cost>(); this.optionalCosts = new CostsImpl<>();
this.modes = new Modes(); this.modes = new Modes();
} }
@ -222,7 +232,8 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
// 20121001 - 601.2b // 20121001 - 601.2b
// If the spell has a variable cost that will be paid as it's being cast (such as an {X} in // If the spell has a variable cost that will be paid as it's being cast (such as an {X} in
// its mana cost; see rule 107.3), the player announces the value of that variable. // its mana cost; see rule 107.3), the player announces the value of that variable.
VariableManaCost variableManaCost = handleXCosts(game, noMana); VariableManaCost variableManaCost = handleManaXCosts(game, noMana);
String announceString = handleOtherXCosts(game);
for (UUID modeId :this.getModes().getSelectedModes()) { for (UUID modeId :this.getModes().getSelectedModes()) {
this.getModes().setMode(this.getModes().get(modeId)); this.getModes().setMode(this.getModes().get(modeId));
@ -247,8 +258,11 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
card.adjustTargets(this, game); card.adjustTargets(this, game);
} }
if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, game) == false) { if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, game) == false) {
if (variableManaCost != null) { if (variableManaCost != null || announceString != null) {
game.informPlayers(new StringBuilder(card != null ? card.getName(): "").append(": no valid targets with this value of X").toString()); Player controller = game.getPlayer(this.getControllerId());
if (controller != null) {
game.informPlayer(controller, new StringBuilder(card != null ? card.getName(): "").append(": no valid targets with this value of X").toString());
}
} else { } else {
logger.debug("activate failed - target"); logger.debug("activate failed - target");
} }
@ -305,21 +319,52 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
return false; return false;
} }
// inform about x costs now, so canceled announcements are not shown in the log // inform about x costs now, so canceled announcements are not shown in the log
if (announceString != null) {
game.informPlayers(announceString);
}
if (variableManaCost != null) { if (variableManaCost != null) {
int xValue = getManaCostsToPay().getX(); int xValue = getManaCostsToPay().getX();
game.informPlayers(new StringBuilder(game.getPlayer(this.controllerId).getName()).append(" announced a value of ").append(xValue).append(" for ").append(variableManaCost.getText()).toString()); game.informPlayers(new StringBuilder(game.getPlayer(this.controllerId).getName()).append(" announces a value of ").append(xValue).append(" for ").append(variableManaCost.getText()).toString());
} }
return true; return true;
} }
/** /**
* Handles the announcement of X mana costs and sets manaCostsToPay. * Handles the setting of non mana X costs
*
* @param game
* @return announce message
*
*/
protected String handleOtherXCosts(Game game) {
String announceString = null;
for (VariableCost variableCost : this.costs.getVariableCosts()) {
if (!(variableCost instanceof VariableManaCost)) {
int xValue = variableCost.announceXValue(this, game);
costs.add(variableCost.getFixedCostsFromAnnouncedValue(xValue));
// set the xcosts to paid
variableCost.setAmount(xValue);
((Cost) variableCost).setPaid();
String message = new StringBuilder(game.getPlayer(this.controllerId).getName())
.append(" announces a value of ").append(xValue).append(" (").append(variableCost.getActionText()).append(")").toString();
if (announceString == null) {
announceString = message;
} else {
announceString = new StringBuilder(announceString).append(" ").append(message).toString();
}
}
}
return announceString;
}
/**
* Handles X mana costs and sets manaCostsToPay.
* *
* @param game * @param game
* @param noMana * @param noMana
* @return variableManaCost for late check * @return variableManaCost for posting to log later
*/ */
protected VariableManaCost handleXCosts(Game game, boolean noMana) { protected VariableManaCost handleManaXCosts(Game game, boolean noMana) {
// 20121001 - 601.2b // 20121001 - 601.2b
// If the spell has a variable cost that will be paid as it's being cast (such as an {X} in // If the spell has a variable cost that will be paid as it's being cast (such as an {X} in
// its mana cost; see rule 107.3), the player announces the value of that variable. // its mana cost; see rule 107.3), the player announces the value of that variable.

View file

@ -213,8 +213,8 @@ public abstract class ActivatedAbilityImpl<T extends ActivatedAbilityImpl<T>> ex
return ""; return "";
} }
MageObject object = game.getObject(this.sourceId); MageObject object = game.getObject(this.sourceId);
return new StringBuilder(" activates ") return new StringBuilder(" activates: ")
.append(object != null ? this.getRule(object.getName()) :this.getRule()) .append(object != null ? this.formatRule(modes.getText(), object.getName()) :modes.getText())
.append(" from ") .append(" from ")
.append(getMessageText(game)).toString(); .append(getMessageText(game)).toString();
} }

View file

@ -28,16 +28,61 @@
package mage.abilities.costs; package mage.abilities.costs;
import mage.filter.FilterMana; import mage.abilities.Ability;
import mage.game.Game;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public interface VariableCost { public interface VariableCost {
/**
* Returns the variable amount if alreaady set
*
* @return
*/
int getAmount(); int getAmount();
/**
* Sets the variable amount
*
* @param amount
*/
void setAmount(int amount); void setAmount(int amount);
void setFilter(FilterMana filter);
FilterMana getFilter(); /**
* returns the action text (e.g. "creature cards to exile from your hand", "life to pay")
*
* @return
*/
String getActionText();
/**
* Return a min value to announce
*
* @param source
* @param game
* @return
*/
int getMinValue(Ability source, Game game);
/**
* Returns a max value to announce
*
* @param source
* @param game
* @return
*/
int getMaxValue(Ability source, Game game);
/**
* Asks the controller to announce the variable value
* @param source
* @param game
* @return
*/
int announceXValue(Ability source, Game game);
/**
* Returns a fixed cost with the announced variabke value
*
* @param xValue
* @return
*/
Cost getFixedCostsFromAnnouncedValue(int xValue);
} }

View file

@ -0,0 +1,166 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.costs;
import java.util.UUID;
import mage.abilities.Ability;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.Targets;
/**
*
* @author LevelX2
* @param <T> variable cost type
*/
public abstract class VariableCostImpl<T extends VariableCostImpl<T>> implements Cost, VariableCost {
protected UUID id;
protected String text;
protected boolean paid;
protected Targets targets;
protected int amountPaid;
protected String xText;
protected String actionText;
@Override
public abstract T copy();
public VariableCostImpl(String actionText) {
this("X", actionText);
}
/**
*
* @param xText string for the defined value
* @param actionText what happens with the value (e.g. "to tap", "to exile from your graveyard")
*/
public VariableCostImpl(String xText, String actionText) {
id = UUID.randomUUID();
paid = false;
targets = new Targets();
amountPaid = 0;
this.xText = xText;
this.actionText = actionText;
}
public VariableCostImpl(final VariableCostImpl cost) {
this.id = cost.id;
this.text = cost.text;
this.paid = cost.paid;
this.targets = cost.targets.copy();
this.xText = cost.xText;
this.actionText = cost.actionText;
}
@Override
public String getText() {
return text;
}
@Override
public String getActionText() {
return actionText;
}
public void addTarget(Target target) {
if (target != null) {
this.targets.add(target);
}
}
@Override
public Targets getTargets() {
return this.targets;
}
@Override
public boolean isPaid() {
return paid;
}
@Override
public void clearPaid() {
paid = false;
amountPaid = 0;
}
@Override
public void setPaid() {
paid = true;
}
@Override
public UUID getId() {
return this.id;
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
return true; /* not used */
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
return true; /* not used */
}
@Override
public int getAmount() {
return amountPaid;
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
@Override
public int getMinValue(Ability source, Game game) {
return 0;
}
@Override
public int getMaxValue(Ability source, Game game) {
return Integer.MAX_VALUE;
}
@Override
public int announceXValue(Ability source, Game game) {
int xValue = 0;
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
xValue = controller.announceXCost(0, getMaxValue(source, game),
new StringBuilder("Announce the number of ").append(actionText).toString(),
game, source, this);
}
return xValue;
}
}

View file

@ -0,0 +1,84 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.costs.common;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCostImpl;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInHand;
/**
*
* @author LevelX2
*/
public class DiscardXTargetCost extends VariableCostImpl<DiscardXTargetCost> {
protected FilterCard filter;
public DiscardXTargetCost(FilterCard filter) {
this(filter, false);
}
public DiscardXTargetCost(FilterCard filter, boolean additionalCostText) {
super(new StringBuilder(filter.getMessage()).append(" to discard").toString());
this.text = new StringBuilder(additionalCostText ? "As an additional cost to cast {source}, discard ":"Discard ")
.append(xText).append(" ").append(filter.getMessage()).toString();
this.filter = filter;
}
public DiscardXTargetCost(final DiscardXTargetCost cost) {
super(cost);
this.filter = cost.filter;
}
@Override
public DiscardXTargetCost copy() {
return new DiscardXTargetCost(this);
}
@Override
public int getMaxValue(Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
return controller.getHand().count(filter, game);
}
return 0;
}
@Override
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
TargetCardInHand target = new TargetCardInHand(xValue, filter);
target.setRequired(true);
return new DiscardTargetCost(target);
}
}

View file

@ -76,14 +76,18 @@ public class ExileFromGraveCost extends CostImpl<ExileFromGraveCost> {
@Override @Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { Player controller = game.getPlayer(controllerId);
for (UUID targetId: targets.get(0).getTargets()) { if (controller != null) {
Card card = game.getCard(targetId); if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) {
if (card == null || !game.getState().getZone(targetId).equals(Zone.GRAVEYARD)) { for (UUID targetId: targets.get(0).getTargets()) {
return false; Card card = game.getCard(targetId);
if (card == null || !game.getState().getZone(targetId).equals(Zone.GRAVEYARD)) {
return false;
}
paid |= controller.moveCardToExileWithInfo(card, null, null, sourceId, game, Zone.GRAVEYARD);
} }
paid |= card.moveToZone(Zone.EXILED, sourceId, game, false);
} }
} }
return paid; return paid;
} }

View file

@ -0,0 +1,86 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.costs.common;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCostImpl;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
/**
*
* @author LevelX2
*/
public class ExileXFromYourGraveCost extends VariableCostImpl<ExileXFromYourGraveCost> {
protected FilterCard filter;
public ExileXFromYourGraveCost(FilterCard filter) {
this(filter, false);
}
public ExileXFromYourGraveCost(FilterCard filter, boolean additionalCostText) {
super(new StringBuilder(filter.getMessage()).append(" to exile").toString());
this.filter = filter;
this.text = new StringBuilder(additionalCostText ? "As an additional cost to cast {source}, exile ":"Exile ")
.append(xText).append(" ").append(filter.getMessage()).toString();
}
public ExileXFromYourGraveCost(final ExileXFromYourGraveCost cost) {
super(cost);
this.amountPaid = cost.amountPaid;
this.filter = cost.filter;
}
@Override
public ExileXFromYourGraveCost copy() {
return new ExileXFromYourGraveCost(this);
}
@Override
public int getMaxValue(Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
return controller.getGraveyard().count(filter, game);
}
return 0;
}
@Override
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(xValue, filter);
target.setRequired(true);
return new ExileFromGraveCost(target);
}
}

View file

@ -28,11 +28,9 @@
package mage.abilities.costs.common; package mage.abilities.costs.common;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.VariableCostImpl;
import mage.filter.FilterMana;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -41,70 +39,20 @@ import mage.players.Player;
* @author LevelX2 * @author LevelX2
*/ */
public class PayVariableLifeCost extends CostImpl<PayVariableLifeCost> implements VariableCost { public class PayVariableLifeCost extends VariableCostImpl<PayVariableLifeCost> {
protected int amountPaid = 0;
public PayVariableLifeCost() { public PayVariableLifeCost() {
this.text = "pay X life"; this(false);
}
public PayVariableLifeCost(boolean additionalCostText) {
super("life to pay");
this.text = new StringBuilder(additionalCostText ? "As an additional cost to cast {source}, pay ":"Pay ")
.append(xText).append(" ").append("life").toString();
} }
public PayVariableLifeCost(final PayVariableLifeCost cost) { public PayVariableLifeCost(final PayVariableLifeCost cost) {
super(cost); super(cost);
this.amountPaid = cost.amountPaid;
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
Player controller = game.getPlayer(controllerId);
return controller != null && controller.getLife() > 0;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
Player controller = game.getPlayer(controllerId);
if (controller != null) {
this.amountPaid = controller.getAmount(0, controller.getLife(), "Choose X (life to pay)", game);
if (this.amountPaid> 0) {
controller.loseLife(amountPaid, game);
}
game.informPlayers(new StringBuilder(controller.getName()).append(" pays ").append(amountPaid).append(" life.").toString());
this.paid = true;
}
return paid;
}
@Override
public void clearPaid() {
paid = false;
amountPaid = 0;
}
@Override
public int getAmount() {
return amountPaid;
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
/**
* Not Supported
* @param filter
*/
@Override
public void setFilter(FilterMana filter) {
}
/**
* Not supported
* @return
*/
@Override
public FilterMana getFilter() {
return new FilterMana();
} }
@Override @Override
@ -112,4 +60,19 @@ public class PayVariableLifeCost extends CostImpl<PayVariableLifeCost> implement
return new PayVariableLifeCost(this); return new PayVariableLifeCost(this);
} }
@Override
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
return new PayLifeCost(xValue);
}
@Override
public int getMaxValue(Ability source, Game game) {
int maxValue = 0;
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
maxValue = controller.getLife();
}
return maxValue;
}
} }

View file

@ -28,91 +28,46 @@
package mage.abilities.costs.common; package mage.abilities.costs.common;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.VariableCostImpl;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterMana;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public class PayVariableLoyaltyCost extends CostImpl<PayVariableLoyaltyCost> implements VariableCost { public class PayVariableLoyaltyCost extends VariableCostImpl<PayVariableLoyaltyCost> {
protected int amountPaid = 0;
public PayVariableLoyaltyCost() { public PayVariableLoyaltyCost() {
super("loyality counters to remove");
this.text = "-X"; this.text = "-X";
} }
public PayVariableLoyaltyCost(final PayVariableLoyaltyCost cost) { public PayVariableLoyaltyCost(final PayVariableLoyaltyCost cost) {
super(cost); super(cost);
this.amountPaid = cost.amountPaid;
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
Permanent planeswalker = game.getPermanent(sourceId);
return !planeswalker.isLoyaltyUsed();
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
Permanent planeswalker = game.getPermanent(sourceId);
Player player = game.getPlayer(planeswalker.getControllerId());
this.amountPaid = player.getAmount(0, planeswalker.getCounters().getCount(CounterType.LOYALTY), "Choose X", game);
if (this.amountPaid> 0) {
planeswalker.getCounters().removeCounter(CounterType.LOYALTY, this.amountPaid);
} else if (this.amountPaid < 0) {
planeswalker.getCounters().addCounter(CounterType.LOYALTY.createInstance(Math.abs(this.amountPaid)));
}
planeswalker.setLoyaltyUsed(true);
this.paid = true;
return paid;
}
@Override
public void clearPaid() {
paid = false;
amountPaid = 0;
}
@Override
public int getAmount() {
return amountPaid;
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
/**
* Not Supported
* @param filter
*/
@Override
public void setFilter(FilterMana filter) {
}
/**
* Not supported
* @return
*/
@Override
public FilterMana getFilter() {
return new FilterMana();
} }
@Override @Override
public PayVariableLoyaltyCost copy() { public PayVariableLoyaltyCost copy() {
return new PayVariableLoyaltyCost(this); return new PayVariableLoyaltyCost(this);
} }
@Override
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
return new PayLoyaltyCost(xValue);
}
@Override
public int getMaxValue(Ability source, Game game) {
int maxValue = 0;
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
maxValue = permanent.getCounters().getCount(CounterType.LOYALTY.getName());
}
return maxValue;
}
} }

View file

@ -32,17 +32,18 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.constants.Outcome;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.CostImpl;
import mage.choices.Choice; import mage.choices.Choice;
import mage.choices.ChoiceImpl; import mage.choices.ChoiceImpl;
import mage.constants.Outcome;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.CounterType; import mage.counters.CounterType;
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;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.util.CardUtil;
/** /**
* *
@ -53,69 +54,96 @@ public class RemoveCounterCost extends CostImpl<RemoveCounterCost> {
private TargetPermanent target; private TargetPermanent target;
private String name; private String name;
private CounterType counterTypeToRemove; private CounterType counterTypeToRemove;
private int countersToRemove;
public RemoveCounterCost(TargetPermanent target) { public RemoveCounterCost(TargetPermanent target) {
this(target, null); this(target, null);
} }
public RemoveCounterCost(TargetPermanent target, CounterType counterTypeToRemove) { public RemoveCounterCost(TargetPermanent target, CounterType counterTypeToRemove) {
this(target, counterTypeToRemove, 1);
}
public RemoveCounterCost(TargetPermanent target, CounterType counterTypeToRemove, int countersToRemove) {
this.target = target; this.target = target;
this.counterTypeToRemove = counterTypeToRemove; this.counterTypeToRemove = counterTypeToRemove;
text = setText(); this.countersToRemove = countersToRemove;
this.text = setText();
} }
public RemoveCounterCost(final RemoveCounterCost cost) { public RemoveCounterCost(final RemoveCounterCost cost) {
super(cost); super(cost);
this.target = cost.target.copy(); this.target = cost.target.copy();
this.name = cost.name; this.name = cost.name;
this.countersToRemove = cost.countersToRemove;
} }
@Override @Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
paid = false; paid = false;
int countersRemoved = 0;
Player controller = game.getPlayer(controllerId); Player controller = game.getPlayer(controllerId);
if (target.choose(Outcome.UnboostCreature, controllerId, sourceId, game)) { if (controller != null) {
for (UUID targetId: (List<UUID>)target.getTargets()) { target.clearChosen();
Permanent permanent = game.getPermanent(targetId); if (target.choose(Outcome.UnboostCreature, controllerId, sourceId, game)) {
if (permanent != null) { for (UUID targetId: (List<UUID>)target.getTargets()) {
if (permanent.getCounters().size() > 0 && (counterTypeToRemove == null || permanent.getCounters().containsKey(counterTypeToRemove))) { Permanent permanent = game.getPermanent(targetId);
String counterName = null; if (permanent != null) {
if (counterTypeToRemove != null) { if (permanent.getCounters().size() > 0 && (counterTypeToRemove == null || permanent.getCounters().containsKey(counterTypeToRemove))) {
counterName = counterTypeToRemove.getName(); String counterName = null;
} else {
if (permanent.getCounters().size() > 1 && counterTypeToRemove == null) { if (counterTypeToRemove != null) {
Choice choice = new ChoiceImpl(true); counterName = counterTypeToRemove.getName();
Set<String> choices = new HashSet<String>();
for (Counter counter : permanent.getCounters().values()) {
if (permanent.getCounters().getCount(counter.getName()) > 0) {
choices.add(counter.getName());
}
}
choice.setChoices(choices);
choice.setMessage("Choose a counter to remove from " + permanent.getName());
controller.choose(Outcome.UnboostCreature, choice, game);
counterName = choice.getChoice();
} else { } else {
for (Counter counter : permanent.getCounters().values()) { if (permanent.getCounters().size() > 1 && counterTypeToRemove == null) {
if (counter.getCount() > 0) { Choice choice = new ChoiceImpl(true);
counterName = counter.getName(); Set<String> choices = new HashSet<>();
for (Counter counter : permanent.getCounters().values()) {
if (permanent.getCounters().getCount(counter.getName()) > 0) {
choices.add(counter.getName());
}
}
choice.setChoices(choices);
choice.setMessage("Choose a counter to remove from " + permanent.getName());
controller.choose(Outcome.UnboostCreature, choice, game);
counterName = choice.getChoice();
} else {
for (Counter counter : permanent.getCounters().values()) {
if (counter.getCount() > 0) {
counterName = counter.getName();
}
} }
} }
} }
} if (counterName != null) {
if (counterName != null) { int countersLeft = countersToRemove - countersRemoved;
permanent.removeCounters(counterName, 1, game); int countersOnPermanent = permanent.getCounters().getCount(counterName);
if (permanent.getCounters().getCount(counterName) == 0 ){ int numberOfCountersSelected = 1;
permanent.getCounters().removeCounter(counterName); if (countersLeft > 1 && countersOnPermanent > 1) {
numberOfCountersSelected = controller.getAmount(1, Math.min(countersLeft, countersOnPermanent),
new StringBuilder("Remove how many counters from ").append(permanent.getName()).toString(), game);
}
permanent.removeCounters(counterName, numberOfCountersSelected, game);
if (permanent.getCounters().getCount(counterName) == 0 ){
permanent.getCounters().removeCounter(counterName);
}
countersRemoved += numberOfCountersSelected;
game.informPlayers(new StringBuilder(controller.getName())
.append(" removes ").append(numberOfCountersSelected == 1 ? "a":numberOfCountersSelected).append(" ")
.append(counterName).append(numberOfCountersSelected == 1 ? " counter from ":" counters from ")
.append(permanent.getName()).toString());
if (countersRemoved == countersToRemove) {
this.paid = true;
break;
}
} }
this.paid = true;
game.informPlayers(new StringBuilder(controller.getName()).append(" removes a ").append(counterName).append(" counter from ").append(permanent.getName()).toString());
} }
} }
} }
} }
} }
target.clearChosen();
return paid; return paid;
} }
@ -125,11 +153,12 @@ public class RemoveCounterCost extends CostImpl<RemoveCounterCost> {
} }
private String setText() { private String setText() {
StringBuilder sb = new StringBuilder("Remove a "); StringBuilder sb = new StringBuilder("Remove ");
sb.append(CardUtil.numberToText(countersToRemove, "a")).append(" ");
if (counterTypeToRemove != null) { if (counterTypeToRemove != null) {
sb.append(counterTypeToRemove.getName()).append(" "); sb.append(counterTypeToRemove.getName());
} }
sb.append("counter from a ").append(target.getTargetName()); sb.append(countersToRemove == 1 ? " counter from ":" counters from ").append(target.getMaxNumberOfTargets() == 1 ? "a ":"").append(target.getTargetName());
return sb.toString(); return sb.toString();
} }

View file

@ -28,30 +28,27 @@
package mage.abilities.costs.common; package mage.abilities.costs.common;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.VariableCostImpl;
import mage.counters.Counter; import mage.counters.Counter;
import mage.filter.FilterMana;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player;
/** /**
* *
* @author LevelX2 * @author LevelX2
*/ */
public class RemoveVariableCountersSourceCost extends CostImpl<RemoveVariableCountersSourceCost> implements VariableCost { public class RemoveVariableCountersSourceCost extends VariableCostImpl<RemoveVariableCountersSourceCost> {
protected int amountPaid = 0;
protected int minimalCountersToPay = 0; protected int minimalCountersToPay = 0;
private String name; private String counterName;
public RemoveVariableCountersSourceCost(Counter counter, int minimalCountersToPay) { public RemoveVariableCountersSourceCost(Counter counter, int minimalCountersToPay) {
super(new StringBuilder(counter.getName()).append(" counters to remove").toString());
this.minimalCountersToPay = minimalCountersToPay; this.minimalCountersToPay = minimalCountersToPay;
this.name = counter.getName(); this.counterName = counter.getName();
this.text = "Remove X " + name + " counters from {this}"; this.text = new StringBuilder("Remove ").append(xText).append(" ").append(counterName).append(" counters from {this}").toString();
} }
public RemoveVariableCountersSourceCost(Counter counter) { public RemoveVariableCountersSourceCost(Counter counter) {
@ -60,65 +57,8 @@ public class RemoveVariableCountersSourceCost extends CostImpl<RemoveVariableCou
public RemoveVariableCountersSourceCost(final RemoveVariableCountersSourceCost cost) { public RemoveVariableCountersSourceCost(final RemoveVariableCountersSourceCost cost) {
super(cost); super(cost);
this.amountPaid = cost.amountPaid;
this.minimalCountersToPay = cost.minimalCountersToPay; this.minimalCountersToPay = cost.minimalCountersToPay;
this.name = cost.name; this.counterName = cost.counterName;
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
Permanent permanent = game.getPermanent(sourceId);
return permanent != null && permanent.getCounters().getCount(name) >= minimalCountersToPay;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
Permanent permanent = game.getPermanent(sourceId);
if (permanent != null) {
Player player = game.getPlayer(permanent.getControllerId());
if (player != null) {
this.amountPaid = player.getAmount(minimalCountersToPay, permanent.getCounters().getCount(name), "Choose X counters to remove", game);
if (this.amountPaid >= minimalCountersToPay) {
permanent.removeCounters(name, amountPaid, game);
this.paid = true;
}
game.informPlayers(new StringBuilder(player.getName()).append(" removes ").append(this.amountPaid).append(" ").append(name).append(" counter from ").append(permanent.getName()).toString());
}
}
return paid;
}
@Override
public void clearPaid() {
paid = false;
amountPaid = 0;
}
@Override
public int getAmount() {
return amountPaid;
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
/**
* Not Supported
* @param filter
*/
@Override
public void setFilter(FilterMana filter) {
}
/**
* Not supported
* @return
*/
@Override
public FilterMana getFilter() {
return new FilterMana();
} }
@Override @Override
@ -126,5 +66,25 @@ public class RemoveVariableCountersSourceCost extends CostImpl<RemoveVariableCou
return new RemoveVariableCountersSourceCost(this); return new RemoveVariableCountersSourceCost(this);
} }
@Override
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
return new RemoveCountersSourceCost(new Counter(counterName, xValue));
}
@Override
public int getMinValue(Ability source, Game game) {
return minimalCountersToPay;
}
@Override
public int getMaxValue(Ability source, Game game) {
int maxValue = 0;
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
maxValue = permanent.getCounters().getCount(counterName);
}
return maxValue;
}
} }

View file

@ -28,144 +28,109 @@
package mage.abilities.costs.common; package mage.abilities.costs.common;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.constants.Outcome;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.VariableCostImpl;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterMana; import mage.filter.FilterPermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
/** /**
* *
* @author LevelX * @author LevelX
*/ */
public class RemoveVariableCountersTargetCost extends CostImpl<RemoveVariableCountersTargetCost> implements VariableCost { public class RemoveVariableCountersTargetCost extends VariableCostImpl<RemoveVariableCountersTargetCost> {
protected int amountPaid = 0; protected FilterPermanent filter;
protected TargetPermanent target;
protected String name;
protected CounterType counterTypeToRemove; protected CounterType counterTypeToRemove;
protected int minValue;
public RemoveVariableCountersTargetCost(TargetPermanent target) { public RemoveVariableCountersTargetCost(FilterPermanent filter) {
this(target, null); this(filter, null);
} }
public RemoveVariableCountersTargetCost(TargetPermanent target, CounterType counterTypeToRemove) { public RemoveVariableCountersTargetCost(FilterPermanent filter, CounterType counterTypeToRemove) {
this.target = target; this(filter, counterTypeToRemove, "X", 0);
}
public RemoveVariableCountersTargetCost(FilterPermanent filter, CounterType counterTypeToRemove, String xText, int minValue) {
super(xText, new StringBuilder(counterTypeToRemove != null ? counterTypeToRemove.getName() + " ":"").append("counters to remove").toString());
this.filter = filter;
this.counterTypeToRemove = counterTypeToRemove; this.counterTypeToRemove = counterTypeToRemove;
text = setText(); this.text = setText();
this.minValue = minValue;
} }
public RemoveVariableCountersTargetCost(final RemoveVariableCountersTargetCost cost) { public RemoveVariableCountersTargetCost(final RemoveVariableCountersTargetCost cost) {
super(cost); super(cost);
this.target = cost.target.copy(); this.filter = cost.filter;
this.name = cost.name; this.minValue = cost.minValue;
} }
@Override @Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
paid = false; // paid = false;
Player controller = game.getPlayer(controllerId); // Player controller = game.getPlayer(controllerId);
if (target.choose(Outcome.UnboostCreature, controllerId, sourceId, game)) { // if (target.choose(Outcome.UnboostCreature, controllerId, sourceId, game)) {
for (UUID targetId: (List<UUID>)target.getTargets()) { // for (UUID targetId: (List<UUID>)target.getTargets()) {
Permanent permanent = game.getPermanent(targetId); // Permanent permanent = game.getPermanent(targetId);
if (permanent != null) { // if (permanent != null) {
if (permanent.getCounters().size() > 0 && (counterTypeToRemove == null || permanent.getCounters().containsKey(counterTypeToRemove))) { // if (permanent.getCounters().size() > 0 && (counterTypeToRemove == null || permanent.getCounters().containsKey(counterTypeToRemove))) {
String counterName = null; // String counterName = null;
if (counterTypeToRemove != null) { // if (counterTypeToRemove != null) {
counterName = counterTypeToRemove.getName(); // counterName = counterTypeToRemove.getName();
} else { // } else {
if (permanent.getCounters().size() > 1 && counterTypeToRemove == null) { // if (permanent.getCounters().size() > 1 && counterTypeToRemove == null) {
Choice choice = new ChoiceImpl(true); // Choice choice = new ChoiceImpl(true);
Set<String> choices = new HashSet<String>(); // Set<String> choices = new HashSet<>();
for (Counter counter : permanent.getCounters().values()) { // for (Counter counter : permanent.getCounters().values()) {
if (permanent.getCounters().getCount(counter.getName()) > 0) { // if (permanent.getCounters().getCount(counter.getName()) > 0) {
choices.add(counter.getName()); // choices.add(counter.getName());
} // }
} // }
choice.setChoices(choices); // choice.setChoices(choices);
choice.setMessage("Choose a counter to remove from " + permanent.getName()); // choice.setMessage("Choose a counter to remove from " + permanent.getName());
controller.choose(Outcome.UnboostCreature, choice, game); // controller.choose(Outcome.UnboostCreature, choice, game);
counterName = choice.getChoice(); // counterName = choice.getChoice();
} else { // } else {
for (Counter counter : permanent.getCounters().values()) { // for (Counter counter : permanent.getCounters().values()) {
if (counter.getCount() > 0) { // if (counter.getCount() > 0) {
counterName = counter.getName(); // counterName = counter.getName();
} // }
} // }
} // }
} // }
if (counterName != null) { // if (counterName != null) {
int countersToRemove = 1; // int countersToRemove = 1;
if (permanent.getCounters().getCount(counterName) > 1) { // if (permanent.getCounters().getCount(counterName) > 1) {
countersToRemove = controller.getAmount(1, permanent.getCounters().getCount(counterName),"Remove how many counters from " + permanent.getName(), game); // countersToRemove = controller.getAmount(1, permanent.getCounters().getCount(counterName),"Remove how many counters from " + permanent.getName(), game);
} // }
permanent.removeCounters(counterName, countersToRemove, game); // permanent.removeCounters(counterName, countersToRemove, game);
if (permanent.getCounters().getCount(counterName) == 0 ){ // if (permanent.getCounters().getCount(counterName) == 0 ){
permanent.getCounters().removeCounter(counterName); // permanent.getCounters().removeCounter(counterName);
} // }
this.amountPaid += countersToRemove; // this.amountPaid += countersToRemove;
this.paid = true; // this.paid = true;
game.informPlayers(new StringBuilder(controller.getName()).append(" removes ").append(countersToRemove).append(" ").append(counterName).append(" counter from ").append(permanent.getName()).toString()); // game.informPlayers(new StringBuilder(controller.getName()).append(" removes ").append(countersToRemove).append(" ").append(counterName).append(" counter from ").append(permanent.getName()).toString());
} // }
} // }
} // }
} // }
} // }
target.clearChosen(); // target.clearChosen();
return paid; return paid;
} }
@Override
public int getAmount() {
return amountPaid;
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
/**
* Not Supported
* @param filter
*/
@Override
public void setFilter(FilterMana filter) {
}
/**
* Not supported
* @return
*/
@Override
public FilterMana getFilter() {
return new FilterMana();
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
return target.canChoose(controllerId, game);
}
private String setText() { private String setText() {
// Remove one or more +1/+1 counters from among creatures you control StringBuilder sb = new StringBuilder("Remove ").append(xText);
StringBuilder sb = new StringBuilder("Remove one or more ");
if (counterTypeToRemove != null) { if (counterTypeToRemove != null) {
sb.append(counterTypeToRemove.getName()).append(" "); sb.append(" ").append(counterTypeToRemove.getName());
} }
sb.append("counter from among ").append(target.getTargetName()); sb.append(" counters from among ").append(filter.getMessage());
return sb.toString(); return sb.toString();
} }
@ -173,4 +138,25 @@ public class RemoveVariableCountersTargetCost extends CostImpl<RemoveVariableCou
public RemoveVariableCountersTargetCost copy() { public RemoveVariableCountersTargetCost copy() {
return new RemoveVariableCountersTargetCost(this); return new RemoveVariableCountersTargetCost(this);
} }
@Override
public int getMaxValue(Ability source, Game game) {
int maxValue = 0;
for (Permanent permanent :game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) {
if (counterTypeToRemove != null) {
maxValue += permanent.getCounters().getCount(counterTypeToRemove);
} else {
for(Counter counter :permanent.getCounters().values()){
maxValue += counter.getCount();
}
}
}
return maxValue;
}
@Override
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
return new RemoveCounterCost(new TargetPermanent(1,Integer.MAX_VALUE, filter, true), counterTypeToRemove, xValue);
}
} }

View file

@ -0,0 +1,78 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.costs.common;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCostImpl;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.target.common.TargetControlledPermanent;
/**
*
* @author LevelX2
*/
public class SacrificeXTargetCost extends VariableCostImpl<SacrificeXTargetCost> {
protected FilterControlledPermanent filter;
public SacrificeXTargetCost(FilterControlledPermanent filter) {
this(filter, false);
}
public SacrificeXTargetCost(FilterControlledPermanent filter, boolean additionalCostText) {
super(new StringBuilder(filter.getMessage()).append(" to sacrifice").toString());
this.text = new StringBuilder(additionalCostText ? "As an additional cost to cast {source}, sacrifice ":"Sacrifice ").append(xText).append(" ").append(filter.getMessage()).toString();
this.filter = filter;
}
public SacrificeXTargetCost(final SacrificeXTargetCost cost) {
super(cost);
this.filter = cost.filter;
}
@Override
public SacrificeXTargetCost copy() {
return new SacrificeXTargetCost(this);
}
@Override
public int getMaxValue(Ability source, Game game) {
return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game);
}
@Override
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
TargetControlledPermanent target = new TargetControlledPermanent(xValue, xValue, filter, true);
target.setRequired(true);
return new SacrificeTargetCost(target);
}
}

View file

@ -28,90 +28,35 @@
package mage.abilities.costs.common; package mage.abilities.costs.common;
import java.util.Iterator;
import java.util.UUID;
import mage.constants.Outcome;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.VariableCostImpl;
import mage.filter.FilterMana; import mage.filter.common.FilterControlledPermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public class TapVariableTargetCost extends CostImpl<TapVariableTargetCost> implements VariableCost { public class TapVariableTargetCost extends VariableCostImpl<TapVariableTargetCost> {
protected int amountPaid = 0; protected FilterControlledPermanent filter;
protected TargetControlledPermanent target;
public TapVariableTargetCost(TargetControlledPermanent target) { public TapVariableTargetCost(FilterControlledPermanent filter) {
this.target = target; this(filter, false, "X");
this.text = "tap X " + target.getTargetName() + " you control"; }
public TapVariableTargetCost(FilterControlledPermanent filter, boolean additionalCostText, String xText) {
super(xText, new StringBuilder(filter.getMessage()).append(" to tap").toString());
this.filter = filter;
this.text = new StringBuilder(additionalCostText ? "As an additional cost to cast {source}, tap ":"Tap ")
.append(this.xText).append(" ").append(filter.getMessage()).toString();
} }
public TapVariableTargetCost(final TapVariableTargetCost cost) { public TapVariableTargetCost(final TapVariableTargetCost cost) {
super(cost); super(cost);
this.target = cost.target.copy(); this.filter = cost.filter.copy();
this.amountPaid = cost.amountPaid;
}
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
return target.canChoose(controllerId, game);
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
amountPaid = 0;
target.clearChosen();
if (target.canChoose(sourceId, controllerId, game) && target.choose(Outcome.Tap, controllerId, sourceId, game)) {
for (Iterator it = target.getTargets().iterator(); it.hasNext();) {
UUID uuid = (UUID) it.next();
Permanent permanent = game.getPermanent(uuid);
if (permanent != null && permanent.tap(game)) {
amountPaid++;
}
}
}
paid = true;
return true;
}
@Override
public void clearPaid() {
paid = false;
amountPaid = 0;
}
@Override
public int getAmount() {
return amountPaid;
}
@Override
public void setAmount(int amount) {
amountPaid = amount;
}
/**
* Not Supported
* @param filter
*/
@Override
public void setFilter(FilterMana filter) {
}
/**
* Not supported
* @return
*/
@Override
public FilterMana getFilter() {
return new FilterMana();
} }
@Override @Override
@ -119,4 +64,14 @@ public class TapVariableTargetCost extends CostImpl<TapVariableTargetCost> imple
return new TapVariableTargetCost(this); return new TapVariableTargetCost(this);
} }
@Override
public int getMaxValue(Ability source, Game game) {
return game.getBattlefield().countAll(filter, source.getControllerId(), game);
}
@Override
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
return new TapTargetCost(new TargetControlledPermanent(xValue, xValue, filter, true));
}
} }

View file

@ -35,6 +35,7 @@ import mage.abilities.costs.VariableCost;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
* @param <T>
*/ */
public interface ManaCosts<T extends ManaCost> extends List<T>, ManaCost { public interface ManaCosts<T extends ManaCost> extends List<T>, ManaCost {

View file

@ -30,6 +30,7 @@ package mage.abilities.costs.mana;
import mage.Mana; import mage.Mana;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.VariableCost;
import mage.constants.ColoredManaSymbol; import mage.constants.ColoredManaSymbol;
import mage.filter.FilterMana; import mage.filter.FilterMana;
@ -113,16 +114,6 @@ public class VariableManaCost extends ManaCostImpl<VariableManaCost> implements
return true; return true;
} }
@Override
public void setFilter(FilterMana filter) {
this.filter = filter;
}
@Override
public FilterMana getFilter() {
return filter;
}
@Override @Override
public VariableManaCost copy() { public VariableManaCost copy() {
return new VariableManaCost(this); return new VariableManaCost(this);
@ -152,4 +143,37 @@ public class VariableManaCost extends ManaCostImpl<VariableManaCost> implements
public boolean containsColor(ColoredManaSymbol coloredManaSymbol) { public boolean containsColor(ColoredManaSymbol coloredManaSymbol) {
return false; return false;
} }
@Override
public int announceXValue(Ability source, Game game) {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public String getActionText() {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public int getMinValue(Ability source, Game game) {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public int getMaxValue(Ability source, Game game) {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
}
public FilterMana getFilter() {
return filter;
}
public void setFilter(FilterMana filter) {
this.filter = filter;
}
} }

View file

@ -86,6 +86,9 @@ public class ReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEffect<
@Override @Override
public String getText(Mode mode) { public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
Target target = mode.getTargets().get(0); Target target = mode.getTargets().get(0);
sb.append("Return "); sb.append("Return ");

View file

@ -50,7 +50,7 @@ public class TransformSourceEffect extends OneShotEffect<TransformSourceEffect>
this(fromDayToNight, false); this(fromDayToNight, false);
} }
private TransformSourceEffect(boolean fromDayToNight, boolean withoutTrigger) { public TransformSourceEffect(boolean fromDayToNight, boolean withoutTrigger) {
super(Outcome.Transform); super(Outcome.Transform);
this.withoutTrigger = withoutTrigger; this.withoutTrigger = withoutTrigger;
this.fromDayToNight = fromDayToNight; this.fromDayToNight = fromDayToNight;

View file

@ -33,6 +33,7 @@ import java.io.Serializable;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
* @param <T>
*/ */
public class Counter<T extends Counter<T>> implements Serializable { public class Counter<T extends Counter<T>> implements Serializable {

View file

@ -53,27 +53,31 @@ public class Counters extends HashMap<String, Counter> implements Serializable {
} }
public void addCounter(String name) { public void addCounter(String name) {
if (!this.containsKey(name)) if (!this.containsKey(name)) {
this.put(name, new Counter(name)); this.put(name, new Counter(name));
}
this.get(name).add(); this.get(name).add();
} }
public void addCounter(String name, int amount) { public void addCounter(String name, int amount) {
if (!this.containsKey(name)) if (!this.containsKey(name)) {
this.put(name, new Counter(name)); this.put(name, new Counter(name));
}
this.get(name).add(amount); this.get(name).add(amount);
} }
public void addCounter(Counter counter) { public void addCounter(Counter counter) {
if (!this.containsKey(counter.name)) if (!this.containsKey(counter.name)) {
put(counter.name, counter); put(counter.name, counter);
else } else {
get(counter.name).add(counter.getCount()); get(counter.name).add(counter.getCount());
}
} }
public void removeCounter(String name) { public void removeCounter(String name) {
if (this.containsKey(name)) if (this.containsKey(name)) {
this.get(name).remove(); this.get(name).remove();
}
} }
public void removeCounter(CounterType counterType, int amount) { public void removeCounter(CounterType counterType, int amount) {
@ -83,13 +87,15 @@ public class Counters extends HashMap<String, Counter> implements Serializable {
} }
public void removeCounter(String name, int amount) { public void removeCounter(String name, int amount) {
if (this.containsKey(name)) if (this.containsKey(name)) {
this.get(name).remove(amount); this.get(name).remove(amount);
}
} }
public int getCount(String name) { public int getCount(String name) {
if (this.containsKey(name)) if (this.containsKey(name)) {
return this.get(name).getCount(); return this.get(name).getCount();
}
return 0; return 0;
} }
@ -98,16 +104,18 @@ public class Counters extends HashMap<String, Counter> implements Serializable {
} }
public int getCount(CounterType type) { public int getCount(CounterType type) {
if (this.containsKey(type.getName())) if (this.containsKey(type.getName())) {
return this.get(type.getName()).getCount(); return this.get(type.getName()).getCount();
}
return 0; return 0;
} }
public List<BoostCounter> getBoostCounters() { public List<BoostCounter> getBoostCounters() {
List<BoostCounter> boosters = new ArrayList<BoostCounter>(); List<BoostCounter> boosters = new ArrayList<>();
for (Counter counter: this.values()) { for (Counter counter: this.values()) {
if (counter instanceof BoostCounter) if (counter instanceof BoostCounter) {
boosters.add((BoostCounter)counter); boosters.add((BoostCounter)counter);
}
} }
return boosters; return boosters;
} }

View file

@ -6,13 +6,20 @@ import mage.abilities.keyword.FlyingAbility;
import mage.constants.CardType; import mage.constants.CardType;
public class AngelToken extends Token { public class AngelToken extends Token {
public AngelToken() { public AngelToken() {
this("M14");
}
public AngelToken(String tokenImageSetCode) {
super("Angel", "4/4 white Angel creature token with flying"); super("Angel", "4/4 white Angel creature token with flying");
this.setOriginalExpansionSetCode(tokenImageSetCode);
cardType.add(CardType.CREATURE); cardType.add(CardType.CREATURE);
color = ObjectColor.WHITE; color = ObjectColor.WHITE;
subtype.add("Angel"); subtype.add("Angel");
power = new MageInt(4); power = new MageInt(4);
toughness = new MageInt(4); toughness = new MageInt(4);
addAbility(FlyingAbility.getInstance()); addAbility(FlyingAbility.getInstance());
} }
} }

View file

@ -4,8 +4,14 @@ import mage.MageInt;
import mage.constants.CardType; import mage.constants.CardType;
public class MyrToken extends Token { public class MyrToken extends Token {
public MyrToken() { public MyrToken() {
this("SOM");
}
public MyrToken(String expansionSetCode) {
super("Myr", "1/1 colorless Myr artifact creature token"); super("Myr", "1/1 colorless Myr artifact creature token");
this.setOriginalExpansionSetCode(expansionSetCode);
cardType.add(CardType.CREATURE); cardType.add(CardType.CREATURE);
cardType.add(CardType.ARTIFACT); cardType.add(CardType.ARTIFACT);
subtype.add("Myr"); subtype.add("Myr");

View file

@ -43,6 +43,7 @@ import mage.abilities.Mode;
import mage.abilities.Modes; import mage.abilities.Modes;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.Cards; import mage.cards.Cards;
@ -278,9 +279,12 @@ public interface Player extends MageItem, Copyable<Player> {
*/ */
boolean putCardsOnBottomOfLibrary(Cards cards, Game game, Ability source, boolean anyOrder); boolean putCardsOnBottomOfLibrary(Cards cards, Game game, Ability source, boolean anyOrder);
// set the value for X spells and abilities // set the value for X mana spells and abilities
int announceXMana(int min, int max, String message, Game game, Ability ability); int announceXMana(int min, int max, String message, Game game, Ability ability);
// set the value for non mana X costs
int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost);
int chooseEffect(List<String> rEffects, Game game); int chooseEffect(List<String> rEffects, Game game);
TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game); TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game);
Mode chooseMode(Modes modes, Ability source, Game game); Mode chooseMode(Modes modes, Ability source, Game game);

View file

@ -46,8 +46,8 @@ import java.util.*;
*/ */
public abstract class TargetImpl<T extends TargetImpl<T>> implements Target { public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
protected Map<UUID, Integer> targets = new LinkedHashMap<UUID, Integer>(); protected Map<UUID, Integer> targets = new LinkedHashMap<>();
protected Map<UUID, Integer> zoneChangeCounters = new HashMap<UUID, Integer>(); protected Map<UUID, Integer> zoneChangeCounters = new HashMap<>();
protected String targetName; protected String targetName;
protected Zone zone; protected Zone zone;