Human payment for costs now uses visitor pattern... as a result the concrete Cost classes no longer depend on UI

This commit is contained in:
Maxmtg
2014-01-12 16:15:41 +00:00
parent ce6d092b16
commit f1ff893962
32 changed files with 1210 additions and 1416 deletions

1
.gitattributes vendored
View File

@@ -15438,6 +15438,7 @@ forge-gui/src/main/java/forge/gui/menus/IMenuProvider.java -text
forge-gui/src/main/java/forge/gui/menus/LayoutMenu.java -text forge-gui/src/main/java/forge/gui/menus/LayoutMenu.java -text
forge-gui/src/main/java/forge/gui/menus/MenuUtil.java -text forge-gui/src/main/java/forge/gui/menus/MenuUtil.java -text
forge-gui/src/main/java/forge/gui/package-info.java svneol=native#text/plain forge-gui/src/main/java/forge/gui/package-info.java svneol=native#text/plain
forge-gui/src/main/java/forge/gui/player/HumanCostDecision.java -text
forge-gui/src/main/java/forge/gui/player/HumanPlay.java -text forge-gui/src/main/java/forge/gui/player/HumanPlay.java -text
forge-gui/src/main/java/forge/gui/player/LobbyPlayerHuman.java -text forge-gui/src/main/java/forge/gui/player/LobbyPlayerHuman.java -text
forge-gui/src/main/java/forge/gui/player/PlayerControllerHuman.java -text forge-gui/src/main/java/forge/gui/player/PlayerControllerHuman.java -text

View File

@@ -525,7 +525,7 @@ public class AiCostDecision implements ICostVisitor<PaymentDecision> {
return null; return null;
} }
if (amount.equals("All")) { if (amount.equals("All")) {
c = source.getCounters(cost.getCounter()); c = source.getCounters(cost.counter);
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }
@@ -536,18 +536,18 @@ public class AiCostDecision implements ICostVisitor<PaymentDecision> {
if (type.equals("OriginalHost")) { if (type.equals("OriginalHost")) {
typeList = Lists.newArrayList(ability.getOriginalHost()); typeList = Lists.newArrayList(ability.getOriginalHost());
} else { } else {
typeList = CardLists.getValidCards(ai.getCardsIn(cost.getZone()), type.split(";"), ai, source); typeList = CardLists.getValidCards(ai.getCardsIn(cost.zone), type.split(";"), ai, source);
} }
for (Card card : typeList) { for (Card card : typeList) {
if (card.getCounters(cost.getCounter()) >= c) { if (card.getCounters(cost.counter) >= c) {
return PaymentDecision.card(card); return PaymentDecision.card(card);
} }
} }
return null; return null;
} }
if (c > source.getCounters(cost.getCounter())) { if (c > source.getCounters(cost.counter)) {
System.out.println("Not enough " + cost.getCounter() + " on " + source.getName()); System.out.println("Not enough " + cost.counter + " on " + source.getName());
return null; return null;
} }

View File

@@ -73,7 +73,7 @@ public class ComputerUtilCost {
if (part instanceof CostRemoveCounter) { if (part instanceof CostRemoveCounter) {
final CostRemoveCounter remCounter = (CostRemoveCounter) part; final CostRemoveCounter remCounter = (CostRemoveCounter) part;
final CounterType type = remCounter.getCounter(); final CounterType type = remCounter.counter;
if (!part.payCostFromSource()) { if (!part.payCostFromSource()) {
if (type.name().equals("P1P1")) { if (type.name().equals("P1P1")) {
return false; return false;

View File

@@ -23,7 +23,6 @@ import org.apache.commons.lang3.StringUtils;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.game.GameType; import forge.game.GameType;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.mana.Mana; import forge.game.mana.Mana;
import forge.game.player.Player; import forge.game.player.Player;
@@ -51,21 +50,10 @@ public class CostAddMana extends CostPart {
public final String toString() { public final String toString() {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
final Integer i = this.convertAmount(); final Integer i = this.convertAmount();
sb.append("Add ").append(convertManaAmountType(i, this.getType())); sb.append("Add ").append(StringUtils.repeat("{" + this.getType() + "}", i)).append(" to your mana pool");
sb.append(" to your mana pool");
return sb.toString(); return sb.toString();
} }
/**
* convertManaAmountType.
* @param i
* @param type
* @return a String
*/
private String convertManaAmountType(Integer i, String type) {
return StringUtils.repeat("{" + type + "}", i);
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@@ -78,23 +66,6 @@ public class CostAddMana extends CostPart {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
if (c == null) {
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
return PaymentDecision.number(c);
}
@Override @Override
public boolean payAsDecided(Player ai, PaymentDecision decision, SpellAbility sa) { public boolean payAsDecided(Player ai, PaymentDecision decision, SpellAbility sa) {
Card source = sa.getSourceCard(); Card source = sa.getSourceCard();

View File

@@ -17,9 +17,6 @@
*/ */
package forge.game.cost; package forge.game.cost;
import java.util.ArrayList;
import forge.card.CardType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -50,20 +47,6 @@ public class CostChooseCreatureType extends CostPart {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player payer) {
String choice = payer.getController().chooseSomeType("Creature", ability, new ArrayList<String>(CardType.getCreatureTypes()), new ArrayList<String>(), true);
if( null == choice )
return null;
return PaymentDecision.type(choice);
}
@Override @Override
public boolean payAsDecided(Player payer, PaymentDecision pd, SpellAbility sa) { public boolean payAsDecided(Player payer, PaymentDecision pd, SpellAbility sa) {

View File

@@ -17,8 +17,6 @@
*/ */
package forge.game.cost; package forge.game.cost;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -60,37 +58,6 @@ public class CostDamage extends CostPart {
return payer.addDamage(decision.c, sa.getSourceCard()); return payer.addDamage(decision.c, sa.getSourceCard());
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final String amount = this.getAmount();
final int life = activator.getLife();
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, life);
}
else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
if (activator.canPayLife(c) && activator.getController().confirmPayment(this, "Pay " + c + " Life?")) {
return PaymentDecision.number(c);
}
return null;
}
@Override @Override
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);

View File

@@ -19,18 +19,12 @@ package forge.game.cost;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates; import forge.game.card.CardPredicates;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.input.InputSelectCardsFromList;
import forge.util.Aggregates;
/** /**
* The Class CostDiscard. * The Class CostDiscard.
@@ -82,8 +76,7 @@ public class CostDiscard extends CostPartWithList {
desc.append("card"); desc.append("card");
} }
else { else {
desc.append(this.getTypeDescription() == null ? this.getType() : this.getTypeDescription()).append( desc.append(this.getTypeDescription() == null ? this.getType() : this.getTypeDescription()).append(" card");
" card");
} }
sb.append(Cost.convertAmountTypeToWords(i, this.getAmount(), desc.toString())); sb.append(Cost.convertAmountTypeToWords(i, this.getAmount(), desc.toString()));
@@ -151,111 +144,6 @@ public class CostDiscard extends CostPartWithList {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player payer) {
final Card source = ability.getSourceCard();
List<Card> handList = new ArrayList<Card>(payer.getCardsIn(ZoneType.Hand));
String discardType = this.getType();
final String amount = this.getAmount();
if (this.payCostFromSource()) {
return handList.contains(source) ? PaymentDecision.card(source) : null;
}
if (discardType.equals("Hand")) {
return PaymentDecision.card(handList);
}
if (discardType.equals("LastDrawn")) {
final Card lastDrawn = payer.getLastDrawnCard();
return handList.contains(lastDrawn) ? PaymentDecision.card(lastDrawn) : null;
}
Integer c = this.convertAmount();
if (discardType.equals("Random")) {
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, handList.size());
}
else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
return PaymentDecision.card(Aggregates.random(handList, c));
}
if (discardType.contains("+WithSameName")) {
String type = discardType.replace("+WithSameName", "");
handList = CardLists.getValidCards(handList, type.split(";"), payer, source);
final List<Card> landList2 = handList;
handList = CardLists.filter(handList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
for (Card card : landList2) {
if (!card.equals(c) && card.getName().equals(c.getName())) {
return true;
}
}
return false;
}
});
if (c == 0) { return PaymentDecision.card(Lists.<Card>newArrayList()); }
List<Card> discarded = new ArrayList<Card>();
while (c > 0) {
InputSelectCardsFromList inp = new InputSelectCardsFromList(1, 1, handList);
inp.setMessage("Select one of the cards with the same name to discard. Already chosen: " + discarded);
inp.setCancelAllowed(true);
inp.showAndWait();
if (inp.hasCancelled()) {
return null;
}
final Card first = inp.getFirstSelected();
discarded.add(first);
handList = CardLists.filter(handList, CardPredicates.nameEquals(first.getName()));
handList.remove(first);
c--;
}
return PaymentDecision.card(discarded);
}
else {
String type = new String(discardType);
final String[] validType = type.split(";");
handList = CardLists.getValidCards(handList, validType, payer, source);
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, handList.size());
}
else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
InputSelectCardsFromList inp = new InputSelectCardsFromList(c, c, handList);
inp.setMessage("Select %d more " + getDescriptiveType() + " to discard.");
inp.setCancelAllowed(true);
inp.showAndWait();
if (inp.hasCancelled() || inp.getSelected().size() != c) {
return null;
}
return PaymentDecision.card(inp.getSelected());
}
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */

View File

@@ -20,7 +20,6 @@ package forge.game.cost;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -94,30 +93,6 @@ public class CostDraw extends CostPart {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player payer) {
final String amount = this.getAmount();
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
if (c == null) {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
if (!payer.getController().confirmPayment(this, "Draw " + c + " Card" + (c == 1 ? "" : "s"))) {
return null;
}
return PaymentDecision.number(c);
}
@Override @Override
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);

View File

@@ -18,14 +18,9 @@
package forge.game.cost; package forge.game.cost;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates; import forge.game.card.CardPredicates;
@@ -33,9 +28,6 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.gui.input.InputSelectCardsFromList;
import forge.util.Lang;
/** /**
* The Class CostExile. * The Class CostExile.
@@ -52,7 +44,7 @@ public class CostExile extends CostPartWithList {
* *
*/ */
private ZoneType from = ZoneType.Battlefield; public final ZoneType from;
public final boolean sameZone; public final boolean sameZone;
/** /**
@@ -82,9 +74,7 @@ public class CostExile extends CostPartWithList {
public CostExile(final String amount, final String type, final String description, final ZoneType from, final boolean sameZone) { public CostExile(final String amount, final String type, final String description, final ZoneType from, final boolean sameZone) {
super(amount, type, description); super(amount, type, description);
if (from != null) { this.from = from != null ? from : ZoneType.Battlefield;
this.from = from;
}
this.sameZone = sameZone; this.sameZone = sameZone;
} }
@@ -206,206 +196,6 @@ public class CostExile extends CostPartWithList {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final String amount = this.getAmount();
final Card source = ability.getSourceCard();
final Game game = activator.getGame();
Integer c = this.convertAmount();
String type = this.getType();
boolean fromTopGrave = false;
if (type.contains("FromTopGrave")) {
type = type.replace("FromTopGrave", "");
fromTopGrave = true;
}
List<Card> list;
if (this.from.equals(ZoneType.Stack)) {
list = new ArrayList<Card>();
for (SpellAbilityStackInstance si : game.getStack()) {
list.add(si.getSourceCard());
}
}
else if (this.sameZone) {
list = new ArrayList<Card>(game.getCardsIn(this.from));
}
else {
list = new ArrayList<Card>(activator.getCardsIn(this.from));
}
if (this.payCostFromSource()) {
return source.getZone() == activator.getZone(from) && activator.getController().confirmPayment(this, "Exile " + source.getName() + "?") ? PaymentDecision.card(source) : null;
}
if (type.equals("All")) {
return PaymentDecision.card(list);
}
list = CardLists.getValidCards(list, type.split(";"), activator, source);
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, list.size());
}
else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
if (this.from == ZoneType.Battlefield || this.from == ZoneType.Hand) {
InputSelectCardsFromList inp = new InputSelectCardsFromList(c, c, list);
inp.setMessage("Exile %d card(s) from your" + from);
inp.setCancelAllowed(true);
inp.showAndWait();
return inp.hasCancelled() ? null : PaymentDecision.card(inp.getSelected());
}
if (this.from == ZoneType.Stack) { return exileFromStack(ability, c); }
if (this.from == ZoneType.Library) { return exileFromTop(ability, activator, c); }
if (fromTopGrave) { return exileFromTopGraveType(ability, c, list); }
if (!this.sameZone) { return exileFromMiscZone(ability, c, list); }
List<Player> players = game.getPlayers();
List<Player> payableZone = new ArrayList<Player>();
for (Player p : players) {
List<Card> enoughType = CardLists.filter(list, CardPredicates.isOwner(p));
if (enoughType.size() < c) {
list.removeAll(enoughType);
}
else {
payableZone.add(p);
}
}
return exileFromSame(list, c, payableZone);
}
// Inputs
// Exile<Num/Type{/TypeDescription}>
// ExileFromHand<Num/Type{/TypeDescription}>
// ExileFromGrave<Num/Type{/TypeDescription}>
// ExileFromTop<Num/Type{/TypeDescription}> (of library)
// ExileSameGrave<Num/Type{/TypeDescription}>
private PaymentDecision exileFromSame(List<Card> list, int nNeeded, List<Player> payableZone) {
if (nNeeded == 0) {
return PaymentDecision.number(0);
}
final Player p = GuiChoose.oneOrNone(String.format("Exile from whose %s?", getFrom()), payableZone);
if (p == null) {
return null;
}
List<Card> typeList = CardLists.filter(list, CardPredicates.isOwner(p));
if(typeList.size() < nNeeded)
return null;
List<Card> toExile = GuiChoose.many("Exile from " + getFrom(), "To be exiled", nNeeded, typeList, null);
return PaymentDecision.card(toExile);
}
/**
* TODO: Write javadoc for Constructor.
* @param payment
* @param sa
* @param type
* @param nNeeded
* @param part
*/
private PaymentDecision exileFromStack(SpellAbility sa, int nNeeded) {
if (nNeeded == 0) {
return PaymentDecision.number(0);
}
final Game game = sa.getActivatingPlayer().getGame();
ArrayList<SpellAbility> saList = new ArrayList<SpellAbility>();
ArrayList<String> descList = new ArrayList<String>();
for (SpellAbilityStackInstance si : game.getStack()) {
final Card stC = si.getSourceCard();
final SpellAbility stSA = si.getSpellAbility().getRootAbility();
if (stC.isValid(getType().split(";"), sa.getActivatingPlayer(), sa.getSourceCard()) && stSA.isSpell()) {
saList.add(stSA);
if (stC.isCopiedSpell()) {
descList.add(stSA.getStackDescription() + " (Copied Spell)");
} else {
descList.add(stSA.getStackDescription());
}
}
}
if (saList.size() < nNeeded) {
return null;
}
List<Card> exiled = new ArrayList<Card>();
for (int i = 0; i < nNeeded; i++) {
//Have to use the stack descriptions here because some copied spells have no description otherwise
final String o = GuiChoose.oneOrNone("Exile from " + getFrom(), descList);
if (o != null) {
final SpellAbility toExile = saList.get(descList.indexOf(o));
final Card c = toExile.getSourceCard();
saList.remove(toExile);
descList.remove(o);
exiled.add(c);
}
else {
return null;
}
}
return PaymentDecision.card(exiled);
}
private PaymentDecision exileFromTop(final SpellAbility sa, final Player payer, final int nNeeded) {
final StringBuilder sb = new StringBuilder();
sb.append("Exile ").append(nNeeded).append(" cards from the top of your library?");
final List<Card> list = payer.getCardsIn(ZoneType.Library, nNeeded);
if (list.size() > nNeeded || !payer.getController().confirmPayment(this, "Exile " + Lang.nounWithAmount(nNeeded, "card") + " from the top of your library?")) {
return null;
}
return PaymentDecision.card(list);
}
private PaymentDecision exileFromMiscZone(SpellAbility sa, int nNeeded, List<Card> typeList) {
if (typeList.size() < nNeeded)
return null;
List<Card> exiled = new ArrayList<Card>();
for (int i = 0; i < nNeeded; i++) {
final Card c = GuiChoose.oneOrNone("Exile from " + getFrom(), typeList);
if (c != null) {
typeList.remove(c);
exiled.add(c);
} else {
return null;
}
}
return PaymentDecision.card(exiled);
}
private PaymentDecision exileFromTopGraveType(SpellAbility sa, int nNeeded, List<Card> typeList) {
if (typeList.size() < nNeeded)
return null;
Collections.reverse(typeList);
return PaymentDecision.card(Lists.newArrayList(Iterables.limit(typeList, nNeeded)));
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)

View File

@@ -25,7 +25,6 @@ import forge.game.card.CardLists;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
/** /**
* This is for the "ExiledMoveToGrave" Cost. * This is for the "ExiledMoveToGrave" Cost.
@@ -104,32 +103,6 @@ public class CostExiledMoveToGrave extends CostPartWithList {
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player payer) {
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
if (c == null) {
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
final Player activator = ability.getActivatingPlayer();
List<Card> list = activator.getGame().getCardsIn(ZoneType.Exile);
list = CardLists.getValidCards(list, this.getType().split(";"), activator, source);
if (list.size() < c)
return null;
return PaymentDecision.card(GuiChoose.many("Choose an exiled card to put into graveyard", "To graveyard", c, list, source));
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */

View File

@@ -17,7 +17,6 @@
*/ */
package forge.game.cost; package forge.game.cost;
import forge.game.ability.AbilityUtils;
import forge.game.ability.effects.FlipCoinEffect; import forge.game.ability.effects.FlipCoinEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
@@ -58,36 +57,6 @@ public class CostFlipCoin extends CostPartWithList {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final String amount = this.getAmount();
Integer c = this.convertAmount();
final Card source = ability.getSourceCard();
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, this.getList().size());
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
return PaymentDecision.number(c);
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#toString()
*/
@Override @Override
public final String toString() { public final String toString() {
return Cost.convertAmountTypeToWords(this.convertAmount(), this.getAmount(), "Coin"); return Cost.convertAmountTypeToWords(this.convertAmount(), this.getAmount(), "Coin");

View File

@@ -25,7 +25,6 @@ import forge.game.card.CardLists;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.input.InputSelectCardsFromList;
/** /**
* The Class CostReturn. * The Class CostReturn.
@@ -84,35 +83,6 @@ public class CostGainControl extends CostPartWithList {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player payer) {
final String amount = this.getAmount();
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
if (c == null) {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
final List<Card> list = payer.getCardsIn(ZoneType.Battlefield);
List<Card> validCards = CardLists.getValidCards(list, this.getType().split(";"), payer, source);
InputSelectCardsFromList inp = new InputSelectCardsFromList(c, validCards);
final String desc = this.getTypeDescription() == null ? this.getType() : this.getTypeDescription();
inp.setMessage("Gain control of %d " + desc);
inp.showAndWait();
if (inp.hasCancelled()) {
return null;
}
return PaymentDecision.card(inp.getSelected());
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */

View File

@@ -20,13 +20,9 @@ package forge.game.cost;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.google.common.collect.Lists;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.gui.GuiChoose;
/** /**
* The Class CostGainLife. * The Class CostGainLife.
@@ -45,6 +41,13 @@ public class CostGainLife extends CostPart {
cntPlayers = qty; cntPlayers = qty;
} }
/**
* @return the cntPlayers
*/
public int getCntPlayers() {
return cntPlayers;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@@ -116,51 +119,6 @@ public class CostGainLife extends CostPart {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final Card source = ability.getSourceCard();
final String amount = this.getAmount();
final int life = activator.getLife();
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, life);
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
final List<Player> oppsThatCanGainLife = new ArrayList<Player>();
for (final Player opp : getPotentialTargets(activator, source)) {
if (opp.canGainLife()) {
oppsThatCanGainLife.add(opp);
}
}
if (cntPlayers == Integer.MAX_VALUE) // applied to all players who can gain
return PaymentDecision.players(oppsThatCanGainLife);
final StringBuilder sb = new StringBuilder();
sb.append(source.getName()).append(" - Choose an opponent to gain ").append(c).append(" life:");
final Player chosenToGain = GuiChoose.oneOrNone(sb.toString(), oppsThatCanGainLife);
if (null == chosenToGain)
return null;
else
return PaymentDecision.players(Lists.newArrayList(chosenToGain));
}
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);

View File

@@ -76,36 +76,6 @@ public class CostMill extends CostPartWithList {
return i < zone.size(); return i < zone.size();
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final String amount = this.getAmount();
Integer c = this.convertAmount();
final Card source = ability.getSourceCard();
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, this.getList().size());
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
if (!activator.getController().confirmPayment(this, "Mill " + c + " card" + (c == 1 ? "" : "s") + " from your library?")) {
return null;
}
return PaymentDecision.card(activator.getCardsIn(ZoneType.Library, c));
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *

View File

@@ -151,20 +151,6 @@ public abstract class CostPart {
public abstract <T> T accept(final ICostVisitor<T> visitor); public abstract <T> T accept(final ICostVisitor<T> visitor);
/**
* Pay human.
*
* @param ability
* {@link forge.game.spellability.SpellAbility}
* @param source
* {@link forge.game.card.Card}
* @param payment
* {@link forge.game.cost.CostPayment}
* @param game
* @return true, if successful
*/
public abstract PaymentDecision payHuman(SpellAbility ability, Player humanPayer);
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@@ -192,17 +178,6 @@ public abstract class CostPart {
this.amount = amountIn; this.amount = amountIn;
} }
protected int chooseXValue(final Card card, final SpellAbility sa, final int maxValue) {
/*final String chosen = sa.getSVar("ChosenX");
if (chosen.length() > 0) {
return AbilityFactory.calculateAmount(card, "ChosenX", null);
}*/
int chosenX = sa.getActivatingPlayer().getController().chooseNumber(sa, card.toString() + " - Choose a Value for X", 0, maxValue);
sa.setSVar("ChosenX", Integer.toString(chosenX));
card.setSVar("ChosenX", Integer.toString(chosenX));
return chosenX;
}
public abstract boolean payAsDecided(Player payer, PaymentDecision pd, SpellAbility sa); public abstract boolean payAsDecided(Player payer, PaymentDecision pd, SpellAbility sa);
} }

View File

@@ -111,10 +111,4 @@ public class CostPartMana extends CostPart {
return payer.getController().payManaCost(this, pd, sa); return payer.getController().payManaCost(this, pd, sa);
} }
@Override
public PaymentDecision payHuman(SpellAbility ability, Player humanPayer) {
// TODO Auto-generated method stub
return new PaymentDecision(0);
}
} }

View File

@@ -101,41 +101,6 @@ public class CostPayLife extends CostPart {
return ai.payLife(paidAmount, null); return ai.payLife(paidAmount, null);
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final Card source = ability.getSourceCard();
final String amount = this.getAmount();
final int life = activator.getLife();
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.startsWith("XChoice")) {
int limit = life;
if (sVar.contains("LimitMax")) {
limit = AbilityUtils.calculateAmount(source, sVar.split("LimitMax.")[1], ability);
}
int maxLifePayment = limit < life ? limit : life;
c = chooseXValue(source, ability, maxLifePayment);
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
if (activator.canPayLife(c) && activator.getController().confirmPayment(this, "Pay " + c + " Life?")) {
return PaymentDecision.number(c);
}
return null;
}
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
} }

View File

@@ -27,6 +27,7 @@ import forge.game.Game;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.gui.player.HumanCostDecision;
/** /**
* <p> * <p>
@@ -107,13 +108,13 @@ public class CostPayment {
* @return a boolean. * @return a boolean.
*/ */
public boolean payCost(final Player payer) { public boolean payCost(final Player payer) {
for (final CostPart part : this.cost.getCostParts()) { HumanCostDecision hcd = new HumanCostDecision(payer, ability, ability.getSourceCard());
PaymentDecision pd = part.payHuman(this.ability, payer);
if ( null == pd ) { for (final CostPart part : this.cost.getCostParts()) {
PaymentDecision pd = part.accept(hcd);
if ( null == pd || !part.payAsDecided(payer, pd, ability))
return false; return false;
} else
part.payAsDecided(payer, pd, ability);
// abilities care what was used to pay for them // abilities care what was used to pay for them
if( part instanceof CostPartWithList ) if( part instanceof CostPartWithList )

View File

@@ -28,8 +28,6 @@ import forge.game.card.CardPredicates;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.gui.input.InputSelectCardsFromList;
/** /**
* This is for the "PutCardToLib" Cost. * This is for the "PutCardToLib" Cost.
@@ -39,8 +37,8 @@ public class CostPutCardToLib extends CostPartWithList {
// PutCardToLibFromSameGrave<Num/LibPos/Type{/TypeDescription}> // PutCardToLibFromSameGrave<Num/LibPos/Type{/TypeDescription}>
// PutCardToLibFromGrave<Num/LibPos/Type{/TypeDescription}> // PutCardToLibFromGrave<Num/LibPos/Type{/TypeDescription}>
private ZoneType from = ZoneType.Hand; public final ZoneType from;
private boolean sameZone = false; public final boolean sameZone;
private String libPosition = "0"; private String libPosition = "0";
/** /**
@@ -82,18 +80,14 @@ public class CostPutCardToLib extends CostPartWithList {
* @param from * @param from
* the from * the from
*/ */
public CostPutCardToLib(final String amount, final String libpos, public CostPutCardToLib(final String amount, final String libpos, final String type, final String description, final ZoneType from) {
final String type, final String description, final ZoneType from) { this(amount, libpos, type, description, from, false);
super(amount, type, description);
if (from != null) {
this.from = from;
}
this.libPosition = libpos;
} }
public CostPutCardToLib(final String amount, final String libpos, final String type, public CostPutCardToLib(final String amount, final String libpos, final String type, final String description, final ZoneType from, final boolean sameZone) {
final String description, final ZoneType from, final boolean sameZone) { super(amount, type, description);
this(amount, libpos, type, description, from); this.from = from == null ? ZoneType.Hand : from;
this.libPosition = libpos;
this.sameZone = sameZone; this.sameZone = sameZone;
} }
@@ -197,113 +191,6 @@ public class CostPutCardToLib extends CostPartWithList {
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final String amount = this.getAmount();
Integer c = this.convertAmount();
final Card source = ability.getSourceCard();
List<Card> list;
if (this.sameZone) {
list = new ArrayList<Card>(activator.getGame().getCardsIn(this.getFrom()));
} else {
list = new ArrayList<Card>(activator.getCardsIn(this.getFrom()));
}
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, this.getList().size());
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
list = CardLists.getValidCards(list, this.getType().split(";"), activator, source);
if (this.from == ZoneType.Hand) {
InputSelectCardsFromList inp = new InputSelectCardsFromList(c, c, list);
inp.setMessage("Put %d card(s) from your " + from );
inp.setCancelAllowed(true);
inp.showAndWait();
return inp.hasCancelled() ? null : PaymentDecision.card(inp.getSelected());
}
if (this.sameZone){
List<Player> players = activator.getGame().getPlayers();
List<Player> payableZone = new ArrayList<Player>();
for (Player p : players) {
List<Card> enoughType = CardLists.filter(list, CardPredicates.isOwner(p));
if (enoughType.size() < c) {
list.removeAll(enoughType);
} else {
payableZone.add(p);
}
}
return putFromSame(list, c, payableZone);
} else {//Graveyard
return putFromMiscZone(ability, c, list);
}
}
/**
* PutFromMiscZone
* @param sa
* @param nNeeded
* @param typeList
* @return a boolean
*/
private PaymentDecision putFromMiscZone(SpellAbility sa, int nNeeded, List<Card> typeList) {
if(typeList.size() < nNeeded)
return null;
List<Card> chosen = new ArrayList<>();
for (int i = 0; i < nNeeded; i++) {
final Card c = GuiChoose.oneOrNone("Put from " + getFrom() + " to library", typeList);
if (c == null)
return null;
typeList.remove(c);
chosen.add(c);
}
return PaymentDecision.card(chosen);
}
private PaymentDecision putFromSame(List<Card> list, int nNeeded, List<Player> payableZone) {
if (nNeeded == 0) {
return PaymentDecision.number(0);
}
final Player p = GuiChoose.oneOrNone(String.format("Put cards from whose %s?", getFrom()), payableZone);
if (p == null) {
return null;
}
List<Card> typeList = CardLists.filter(list, CardPredicates.isOwner(p));
if(typeList.size() < nNeeded)
return null;
List<Card> chosen = new ArrayList<>();
for (int i = 0; i < nNeeded; i++) {
final Card c = GuiChoose.oneOrNone("Put cards from " + getFrom() + " to Library", typeList);
if (c == null)
return null;
typeList.remove(c);
chosen.add(c);
}
return PaymentDecision.card(chosen);
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */

View File

@@ -25,8 +25,6 @@ import forge.game.card.CounterType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.input.InputSelectCardsFromList;
import forge.util.Lang;
/** /**
* The Class CostPutCounter. * The Class CostPutCounter.
@@ -164,37 +162,7 @@ public class CostPutCounter extends CostPartWithList {
return true; return true;
} }
/* public Integer getNumberOfCounters(final SpellAbility ability) {
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
Integer c = getNumberOfCounters(ability);
if (this.payCostFromSource()) {
lastPaidAmount = c;
return PaymentDecision.number(c);
}
// Cards to use this branch: Scarscale Ritual, Wandering Mage - each adds only one counter
List<Card> typeList = CardLists.getValidCards(activator.getCardsIn(ZoneType.Battlefield), getType().split(";"), activator, ability.getSourceCard());
InputSelectCardsFromList inp = new InputSelectCardsFromList(1, 1, typeList);
inp.setMessage("Put " + Lang.nounWithAmount(c, getCounter().getName() + " counter") + " on " + getDescriptiveType());
inp.setCancelAllowed(true);
inp.showAndWait();
if(inp.hasCancelled())
return null;
return PaymentDecision.card(inp.getSelected());
}
private Integer getNumberOfCounters(final SpellAbility ability) {
Integer c = this.convertAmount(); Integer c = this.convertAmount();
if (c == null) { if (c == null) {
c = AbilityUtils.calculateAmount(ability.getSourceCard(), this.getAmount(), ability); c = AbilityUtils.calculateAmount(ability.getSourceCard(), this.getAmount(), ability);

View File

@@ -30,8 +30,6 @@ import forge.game.card.CounterType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.gui.input.InputSelectCardsFromList;
/** /**
* The Class CostRemoveAnyCounter. * The Class CostRemoveAnyCounter.
@@ -41,6 +39,13 @@ public class CostRemoveAnyCounter extends CostPartWithList {
// Power Conduit and Chisei, Heart of Oceans // Power Conduit and Chisei, Heart of Oceans
// Both cards have "Remove a counter from a permanent you control" // Both cards have "Remove a counter from a permanent you control"
private CounterType counterType; private CounterType counterType;
/**
* @param counterType the counterType to set
*/
public void setCounterType(CounterType counterType) {
this.counterType = counterType;
}
/** /**
* Instantiates a new cost CostRemoveAnyCounter. * Instantiates a new cost CostRemoveAnyCounter.
* *
@@ -64,7 +69,7 @@ public class CostRemoveAnyCounter extends CostPartWithList {
* *
* @return the counter * @return the counter
*/ */
private CounterType getCounter() { public CounterType getCounter() {
return this.counterType; return this.counterType;
} }
@@ -106,45 +111,6 @@ public class CostRemoveAnyCounter extends CostPartWithList {
return i <= allCounters; return i <= allCounters;
} }
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
final String type = this.getType();
if (c == null) {
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
List<Card> list = new ArrayList<Card>(activator.getCardsIn(ZoneType.Battlefield));
list = CardLists.getValidCards(list, type.split(";"), activator, source);
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card card) {
return card.hasCounters();
}
});
InputSelectCardsFromList inp = new InputSelectCardsFromList(1, 1, list);
inp.setMessage("Select " + this.getDescriptiveType() + " to remove a counter");
inp.setCancelAllowed(false);
inp.showAndWait();
Card selected = inp.getFirstSelected();
final Map<CounterType, Integer> tgtCounters = selected.getCounters();
final ArrayList<CounterType> typeChoices = new ArrayList<CounterType>();
for (CounterType key : tgtCounters.keySet()) {
if (tgtCounters.get(key) > 0) {
typeChoices.add(key);
}
}
String prompt = "Select type counters to remove";
counterType = GuiChoose.one(prompt, typeChoices);
return PaymentDecision.card(selected, counterType);
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *

View File

@@ -17,16 +17,9 @@
*/ */
package forge.game.cost; package forge.game.cost;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.game.GameEntity;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
@@ -34,8 +27,6 @@ import forge.game.card.CounterType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.gui.input.InputSelectManyBase;
/** /**
* The Class CostRemoveCounter. * The Class CostRemoveCounter.
@@ -48,170 +39,17 @@ public class CostRemoveCounter extends CostPartWithList {
// Counter is tough), // Counter is tough),
// Quillspike, Rift Elemental, Sage of Fables, Spike Rogue // Quillspike, Rift Elemental, Sage of Fables, Spike Rogue
/**
* TODO: Write javadoc for this type.
*
*/
public static final class InputSelectCardToRemoveCounter extends InputSelectManyBase<Card> {
private static final long serialVersionUID = 2685832214519141903L;
private final Map<Card,Integer> cardsChosen; public final CounterType counter;
private final CounterType counterType; public final ZoneType zone;
private final List<Card> validChoices;
public InputSelectCardToRemoveCounter(int cntCounters, CounterType cType, List<Card> validCards) {
super(cntCounters, cntCounters);
this.validChoices = validCards;
counterType = cType;
cardsChosen = cntCounters > 0 ? new HashMap<Card, Integer>() : null;
}
@Override
protected void onCardSelected(Card c, java.awt.event.MouseEvent triggerEvent) {
if (!isValidChoice(c) || c.getCounters(counterType) <= getTimesSelected(c)) {
return;
}
int tc = getTimesSelected(c);
cardsChosen.put(c, tc+1);
onSelectStateChanged(c, true);
refresh();
};
@Override
protected boolean hasEnoughTargets() {
return hasAllTargets();
}
@Override
protected boolean hasAllTargets() {
int sum = getDistibutedCounters();
return sum >= max;
}
protected String getMessage() {
return max == Integer.MAX_VALUE
? String.format(message, getDistibutedCounters())
: String.format(message, max - getDistibutedCounters());
}
private int getDistibutedCounters() {
int sum = 0;
for(Entry<Card, Integer> kv : cardsChosen.entrySet()) {
sum += kv.getValue().intValue();
}
return sum;
}
protected final boolean isValidChoice(GameEntity choice) {
return validChoices.contains(choice);
}
public int getTimesSelected(Card c) {
return cardsChosen.containsKey(c) ? cardsChosen.get(c).intValue() : 0;
}
@Override
public Collection<Card> getSelected() {
return cardsChosen.keySet();
}
}
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final String amount = this.getAmount();
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
final String type = this.getType();
String sVarAmount = ability.getSVar(amount);
cntRemoved = 1;
if (c != null)
cntRemoved = c.intValue();
else if (!"XChoice".equals(sVarAmount)) {
cntRemoved = AbilityUtils.calculateAmount(source, amount, ability);
}
if (this.payCostFromSource()) {
int maxCounters = source.getCounters(this.counter);
if (amount.equals("All"))
cntRemoved = maxCounters;
else if ( c == null && "XChoice".equals(sVarAmount)) {
cntRemoved = chooseXValue(source, ability, maxCounters);
}
if (maxCounters < cntRemoved)
return null;
PaymentDecision res = PaymentDecision.card(source);
res.c = cntRemoved >= 0 ? cntRemoved : maxCounters;
return res;
} else if (type.equals("OriginalHost")) {
int maxCounters = ability.getOriginalHost().getCounters(this.counter);
if (amount.equals("All")) {
cntRemoved = maxCounters;
}
if (maxCounters < cntRemoved)
return null;
PaymentDecision res = PaymentDecision.card(ability.getOriginalHost());
res.c = cntRemoved >= 0 ? cntRemoved : maxCounters;
return res;
}
List<Card> validCards = CardLists.getValidCards(activator.getCardsIn(getZone()), type.split(";"), activator, source);
if (this.getZone().equals(ZoneType.Battlefield)) {
final InputSelectCardToRemoveCounter inp = new InputSelectCardToRemoveCounter(cntRemoved, getCounter(), validCards);
inp.setMessage("Remove %d " + getCounter().getName() + " counters from " + getDescriptiveType());
inp.setCancelAllowed(true);
inp.showAndWait();
if(inp.hasCancelled())
return null;
// Have to hack here: remove all counters minus one, without firing any triggers,
// triggers will fire when last is removed by executePayment.
// They don't care how many were removed anyway
// int sum = 0;
for(Card crd : inp.getSelected()) {
int removed = inp.getTimesSelected(crd);
// sum += removed;
if(removed < 2) continue;
int oldVal = crd.getCounters().get(getCounter()).intValue();
crd.getCounters().put(getCounter(), Integer.valueOf(oldVal - removed + 1));
}
cntRemoved = 1;
return PaymentDecision.card(inp.getSelected());
}
// Rift Elemental only - always removes 1 counter, so there will be no code for N counters.
List<Card> suspended = new ArrayList<Card>();
for(Card crd : validCards)
if(crd.getCounters( getCounter()) > 0 )
suspended.add(crd);
final Card card = GuiChoose.oneOrNone("Remove counter(s) from a card in " + getZone(), suspended);
return null == card ? null : PaymentDecision.card(card);
}
private final CounterType counter;
private final ZoneType zone;
private int cntRemoved; private int cntRemoved;
/** /**
* Gets the counter. * @param cntRemoved the cntRemoved to set
*
* @return the counter
*/ */
public final CounterType getCounter() { public void setCntRemoved(int cntRemoved) {
return this.counter; this.cntRemoved = cntRemoved;
}
/**
* @return the zone
*/
public final ZoneType getZone() {
return zone;
} }
/** /**
@@ -293,7 +131,7 @@ public class CostRemoveCounter extends CostPartWithList {
*/ */
@Override @Override
public final boolean canPay(final SpellAbility ability) { public final boolean canPay(final SpellAbility ability) {
final CounterType cntrs = this.getCounter(); final CounterType cntrs = this.counter;
final Player activator = ability.getActivatingPlayer(); final Player activator = ability.getActivatingPlayer();
final Card source = ability.getSourceCard(); final Card source = ability.getSourceCard();
final String type = this.getType(); final String type = this.getType();
@@ -309,7 +147,7 @@ public class CostRemoveCounter extends CostPartWithList {
if (type.equals("OriginalHost")) { if (type.equals("OriginalHost")) {
typeList = Lists.newArrayList(ability.getOriginalHost()); typeList = Lists.newArrayList(ability.getOriginalHost());
} else { } else {
typeList = CardLists.getValidCards(activator.getCardsIn(this.getZone()), type.split(";"), activator, source); typeList = CardLists.getValidCards(activator.getCardsIn(this.zone), type.split(";"), activator, source);
} }
if (amount != null) { if (amount != null) {
for (Card c : typeList) { for (Card c : typeList) {
@@ -354,7 +192,7 @@ public class CostRemoveCounter extends CostPartWithList {
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard){ protected void doPayment(SpellAbility ability, Card targetCard){
targetCard.subtractCounter(this.getCounter(), cntRemoved); targetCard.subtractCounter(this.counter, cntRemoved);
} }
/* (non-Javadoc) /* (non-Javadoc)

View File

@@ -20,13 +20,11 @@ package forge.game.cost;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.input.InputSelectCardsFromList;
/** /**
* The Class CostReturn. * The Class CostReturn.
@@ -108,49 +106,6 @@ public class CostReturn extends CostPartWithList {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player payer) {
final String amount = this.getAmount();
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
final List<Card> list = payer.getCardsIn(ZoneType.Battlefield);
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, list.size());
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
if (this.payCostFromSource()) {
final Card card = ability.getSourceCard();
if (card.getController() == payer && card.isInPlay()) {
return payer.getController().confirmPayment(this, "Return " + card.getName() + " to hand?") ? PaymentDecision.card(card) : null;
}
}
else {
List<Card> validCards = CardLists.getValidCards(ability.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), this.getType().split(";"), ability.getActivatingPlayer(), ability.getSourceCard());
InputSelectCardsFromList inp = new InputSelectCardsFromList(c, c, validCards);
inp.setMessage("Return %d " + this.getType() + " " + this.getType() + " card(s) to hand");
inp.showAndWait();
if (inp.hasCancelled())
return null;
return PaymentDecision.card(inp.getSelected());
}
return null;
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */

View File

@@ -17,24 +17,18 @@
*/ */
package forge.game.cost; package forge.game.cost;
import java.awt.event.MouseEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.input.InputSelectCardsFromList;
import forge.util.Lang;
/** /**
* The Class CostReveal. * The Class CostReveal.
@@ -115,86 +109,6 @@ public class CostReveal extends CostPartWithList {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final Card source = ability.getSourceCard();
final String amount = this.getAmount();
if (this.payCostFromSource())
return PaymentDecision.card(source);
if (this.getType().equals("Hand"))
return PaymentDecision.card(activator.getCardsIn(ZoneType.Hand));
InputSelectCardsFromList inp = null;
if (this.getType().equals("SameColor")) {
Integer num = this.convertAmount();
List<Card> handList = activator.getCardsIn(ZoneType.Hand);
final List<Card> handList2 = handList;
handList = CardLists.filter(handList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
for (Card card : handList2) {
if (!card.equals(c) && card.sharesColorWith(c)) {
return true;
}
}
return false;
}
});
if (num == 0)
return PaymentDecision.number(0);
inp = new InputSelectCardsFromList(num, handList) {
private static final long serialVersionUID = 8338626212893374798L;
@Override
protected void onCardSelected(Card c, MouseEvent triggerEvent) {
Card firstCard = Iterables.getFirst(this.selected, null);
if(firstCard != null && !CardPredicates.sharesColorWith(firstCard).apply(c))
return;
super.onCardSelected(c, triggerEvent);
}
};
inp.setMessage("Select " + Lang.nounWithAmount(num, "card" ) + " of same color to reveal.");
} else {
Integer num = this.convertAmount();
List<Card> handList = activator.getCardsIn(ZoneType.Hand);
handList = CardLists.getValidCards(handList, this.getType().split(";"), activator, ability.getSourceCard());
if (num == null) {
final String sVar = ability.getSVar(amount);
if (sVar.equals("XChoice")) {
num = chooseXValue(source, ability, handList.size());
} else {
num = AbilityUtils.calculateAmount(source, amount, ability);
}
}
if ( num == 0 )
return PaymentDecision.number(0);;
inp = new InputSelectCardsFromList(num, num, handList);
inp.setMessage("Select %d more " + getDescriptiveType() + " card(s) to reveal.");
}
inp.setCancelAllowed(true);
inp.showAndWait();
if (inp.hasCancelled())
return null;
return PaymentDecision.card(inp.getSelected());
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *

View File

@@ -20,13 +20,11 @@ package forge.game.cost;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.input.InputSelectCardsFromList;
/** /**
* The Class CostSacrifice. * The Class CostSacrifice.
@@ -117,59 +115,6 @@ public class CostSacrifice extends CostPartWithList {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final String amount = this.getAmount();
final Card source = ability.getSourceCard();
final String type = this.getType();
List<Card> list = new ArrayList<Card>(activator.getCardsIn(ZoneType.Battlefield));
list = CardLists.getValidCards(list, type.split(";"), activator, source);
if (activator.hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) {
list = CardLists.getNotType(list, "Creature");
}
if (this.payCostFromSource()) {
if (source.getController() == ability.getActivatingPlayer() && source.isInPlay()) {
return activator.getController().confirmPayment(this, "Sacrifice " + source.getName() + "?") ? PaymentDecision.card(source) : null;
} else
return null;
}
if (amount.equals("All"))
return PaymentDecision.card(list);
Integer c = this.convertAmount();
if (c == null) {
// Generalize this
if (ability.getSVar(amount).equals("XChoice")) {
c = chooseXValue(source, ability, list.size());
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
if (0 == c.intValue()) {
return PaymentDecision.number(0);
}
InputSelectCardsFromList inp = new InputSelectCardsFromList(c, c, list);
inp.setMessage("Select a " + this.getDescriptiveType() + " to sacrifice (%d left)");
inp.setCancelAllowed(true);
inp.showAndWait();
if ( inp.hasCancelled() )
return null;
return PaymentDecision.card(inp.getSelected());
}
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected void doPayment(SpellAbility ability, Card targetCard) {
targetCard.getGame().getAction().sacrifice(targetCard, ability); targetCard.getGame().getAction().sacrifice(targetCard, ability);

View File

@@ -84,23 +84,6 @@ public class CostTap extends CostPart {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
// if (!canPay(ability, source, ability.getActivatingPlayer(),
// payment.getCost()))
// return false;
return PaymentDecision.number(1);
}
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
} }

View File

@@ -22,14 +22,12 @@ import java.util.List;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.input.InputSelectCardsFromList;
/** /**
* The Class CostTapType. * The Class CostTapType.
@@ -161,107 +159,6 @@ public class CostTapType extends CostPartWithList {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
List<Card> typeList = new ArrayList<Card>(activator.getCardsIn(ZoneType.Battlefield));
String type = this.getType();
final String amount = this.getAmount();
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
boolean sameType = false;
if (type.contains("sharesCreatureTypeWith")) {
sameType = true;
type = type.replace("sharesCreatureTypeWith", "");
}
boolean totalPower = false;
String totalP = "";
if (type.contains("+withTotalPowerGE")) {
totalPower = true;
totalP = type.split("withTotalPowerGE")[1];
type = type.replace("+withTotalPowerGE" + totalP, "");
}
typeList = CardLists.getValidCards(typeList, type.split(";"), activator, ability.getSourceCard());
typeList = CardLists.filter(typeList, Presets.UNTAPPED);
if (c == null && !amount.equals("Any")) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, typeList.size());
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
if (sameType) {
final List<Card> List2 = typeList;
typeList = CardLists.filter(typeList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
for (Card card : List2) {
if (!card.equals(c) && card.sharesCreatureTypeWith(c)) {
return true;
}
}
return false;
}
});
if (c == 0) return PaymentDecision.number(0);
List<Card> tapped = new ArrayList<Card>();
while (c > 0) {
InputSelectCardsFromList inp = new InputSelectCardsFromList(1, 1, typeList);
inp.setMessage("Select one of the cards to tap. Already chosen: " + tapped);
inp.setCancelAllowed(true);
inp.showAndWait();
if (inp.hasCancelled())
return null;
final Card first = inp.getFirstSelected();
tapped.add(first);
typeList = CardLists.filter(typeList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.sharesCreatureTypeWith(first);
}
});
typeList.remove(first);
c--;
}
return PaymentDecision.card(tapped);
}
if (totalPower) {
int i = Integer.parseInt(totalP);
InputSelectCardsFromList inp = new InputSelectCardsFromList(0, typeList.size(), typeList);
inp.setMessage("Select a card to tap.");
inp.setUnselectAllowed(true);
inp.setCancelAllowed(true);
inp.showAndWait();
if (inp.hasCancelled() || CardLists.getTotalPower(inp.getSelected()) < i) {
return null;
} else {
return PaymentDecision.card(inp.getSelected());
}
}
InputSelectCardsFromList inp = new InputSelectCardsFromList(c, c, typeList);
inp.setMessage("Select a " + getDescriptiveType() + " to tap (%d left)");
inp.showAndWait();
if ( inp.hasCancelled() )
return null;
return PaymentDecision.card(inp.getSelected());
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */

View File

@@ -86,24 +86,6 @@ public class CostUnattach extends CostPartWithList {
return false; return false;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
final Card source = ability.getSourceCard();
Card cardToUnattach = findCardToUnattach(source, activator, ability);
if (cardToUnattach != null && activator.getController().confirmPayment(this, "Unattach " + cardToUnattach.getName() + "?")) {
return PaymentDecision.card(cardToUnattach);
}
return null;
}
public Card findCardToUnattach(final Card source, Player activator, SpellAbility ability) { public Card findCardToUnattach(final Card source, Player activator, SpellAbility ability) {
if (getType().equals("CARDNAME")) { if (getType().equals("CARDNAME")) {
if (source.isEquipping()) { if (source.isEquipping()) {

View File

@@ -75,18 +75,6 @@ public class CostUntap extends CostPart {
return source.isTapped() && (!source.isSick() || source.hasKeyword("CARDNAME may activate abilities as though it has haste.")); return source.isTapped() && (!source.isSick() || source.hasKeyword("CARDNAME may activate abilities as though it has haste."));
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player activator) {
return PaymentDecision.number(1);
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPart#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPart#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/ */

View File

@@ -18,14 +18,12 @@
package forge.game.cost; package forge.game.cost;
import java.util.List; import java.util.List;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.input.InputSelectCardsFromList;
/** /**
* The Class CostUntapType. * The Class CostUntapType.
@@ -120,41 +118,6 @@ public class CostUntapType extends CostPartWithList {
return true; return true;
} }
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final PaymentDecision payHuman(final SpellAbility ability, final Player payer) {
List<Card> typeList = CardLists.getValidCards(payer.getGame().getCardsIn(ZoneType.Battlefield), this.getType().split(";"),
payer, ability.getSourceCard());
typeList = CardLists.filter(typeList, Presets.TAPPED);
final Card source = ability.getSourceCard();
if (!canUntapSource) {
typeList.remove(source);
}
final String amount = this.getAmount();
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = chooseXValue(source, ability, typeList.size());
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
InputSelectCardsFromList inp = new InputSelectCardsFromList(c, c, typeList);
inp.setMessage("Select a " + getDescriptiveType() + " to untap (%d left)");
inp.showAndWait();
if( inp.hasCancelled() || inp.getSelected().size() != c )
return null;
return PaymentDecision.card(inp.getSelected());
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */

File diff suppressed because it is too large Load Diff

View File

@@ -321,6 +321,8 @@ public class HumanPlay {
} }
} }
HumanCostDecision hcd = new HumanCostDecision(p, sourceAbility, source);
//the following costs do not need inputs //the following costs do not need inputs
for (CostPart part : parts) { for (CostPart part : parts) {
boolean mayRemovePart = true; boolean mayRemovePart = true;
@@ -364,7 +366,7 @@ public class HumanPlay {
} }
} }
else if (part instanceof CostGainLife) { else if (part instanceof CostGainLife) {
PaymentDecision pd = part.payHuman(sourceAbility, p); PaymentDecision pd = part.accept(hcd);
if (pd == null) if (pd == null)
return false; return false;
@@ -375,7 +377,7 @@ public class HumanPlay {
if (!p.getController().confirmPayment(part, "Do you want to add " + ((CostAddMana) part).toString() + " to your mana pool?" + orString)) { if (!p.getController().confirmPayment(part, "Do you want to add " + ((CostAddMana) part).toString() + " to your mana pool?" + orString)) {
return false; return false;
} }
PaymentDecision pd = part.payHuman(sourceAbility, p); PaymentDecision pd = part.accept(hcd);
if (pd == null) if (pd == null)
return false; return false;
@@ -452,7 +454,7 @@ public class HumanPlay {
} }
} }
else if (part instanceof CostRemoveCounter) { else if (part instanceof CostRemoveCounter) {
CounterType counterType = ((CostRemoveCounter) part).getCounter(); CounterType counterType = ((CostRemoveCounter) part).counter;
int amount = getAmountFromPartX(part, source, sourceAbility); int amount = getAmountFromPartX(part, source, sourceAbility);
if (!part.canPay(sourceAbility)) { if (!part.canPay(sourceAbility)) {