cost removecounter - needs testing

This commit is contained in:
Maxmtg
2013-04-07 23:48:19 +00:00
parent 58a72c1dce
commit ae06422531
2 changed files with 134 additions and 200 deletions

View File

@@ -18,21 +18,22 @@
package forge.card.cost; package forge.card.cost;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import forge.Card; import forge.Card;
import forge.CardLists; import forge.CardLists;
import forge.CounterType; import forge.CounterType;
import forge.FThreads; import forge.FThreads;
import forge.card.ability.AbilityUtils; import forge.card.ability.AbilityUtils;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.control.input.InputPayment; import forge.control.input.InputSelectCards;
import forge.game.GameState; import forge.game.GameState;
import forge.game.player.AIPlayer; import forge.game.player.AIPlayer;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose; import forge.gui.GuiChoose;
import forge.gui.match.CMatchUI;
import forge.view.ButtonUtil;
/** /**
* The Class CostRemoveCounter. * The Class CostRemoveCounter.
@@ -49,141 +50,146 @@ public class CostRemoveCounter extends CostPartWithList {
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
* *
*/ */
public static final class InputPayCostRemoveCounterType extends InputPayCostBase { public static final class InputSelectCardToRemoveCounter extends InputSelectCards {
private final int nNeeded;
private final SpellAbility sa;
private final String type;
private final CostRemoveCounter costRemoveCounter;
private static final long serialVersionUID = 2685832214519141903L; private static final long serialVersionUID = 2685832214519141903L;
private List<Card> typeList;
private int nRemove = 0; private final Map<Card,Integer> cardsChosen;
private final CounterType counterType;
/** private final int nNeeded;
* TODO: Write javadoc for Constructor. private final List<Card> validChoices;
* @param payment
* @param nNeeded public InputSelectCardToRemoveCounter(int cntCounters, CounterType cType, List<Card> validCards) {
* @param sa super(cntCounters, cntCounters);
* @param type this.validChoices = validCards;
* @param costRemoveCounter counterType = cType;
*/ nNeeded = cntCounters;
public InputPayCostRemoveCounterType(int nNeeded, SpellAbility sa, String type, CostRemoveCounter costRemoveCounter) { cardsChosen = cntCounters > 1 ? new HashMap<Card, Integer>() : null;
this.nNeeded = nNeeded;
this.sa = sa;
this.type = type;
this.costRemoveCounter = costRemoveCounter;
} }
@Override @Override
public void showMessage() { protected boolean selectEntity(Card c) {
if ((nNeeded == 0) || (nNeeded == this.nRemove)) { if (!isValidChoice(c)) {
this.done(); return false;
} }
final StringBuilder msg = new StringBuilder("Remove "); int tc = getTimesSelected(c);
final int nLeft = nNeeded - this.nRemove; if( tc == 0)
msg.append(nLeft).append(" "); selected.add(c);
msg.append(costRemoveCounter.getCounter().getName()).append(" counters from "); else
msg.append(costRemoveCounter.getDescriptiveType()); cardsChosen.put(c, tc+1);
this.typeList = CardLists.getValidCards(sa.getActivatingPlayer().getCardsIn(costRemoveCounter.getZone()), type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard());
// TODO Tabulate typelist vs nNeeded to see if there are enough counters to remove onSelectStateChanged(c, true);
return true;
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); }
ButtonUtil.enableOnlyCancel();
@Override
protected boolean hasEnoughTargets() {
return hasAllTargets();
}
@Override
protected boolean hasAllTargets() {
int sum = getDistibutedCounters();
return sum >= nNeeded;
}
protected String getMessage() {
return max == Integer.MAX_VALUE
? String.format(message, getDistibutedCounters())
: String.format(message, nNeeded - getDistibutedCounters());
} }
/* (non-Javadoc) private int getDistibutedCounters() {
* @see forge.control.input.InputSyncronizedBase#onCardSelected(forge.Card) int sum = 0;
*/ for(Card c : selected) {
@Override sum += nNeeded == 1 || cardsChosen.get(c) == null ? 1 : cardsChosen.get(c).intValue();
protected void onCardSelected(Card card) {
if (this.typeList.contains(card)) {
if (card.getCounters(costRemoveCounter.getCounter()) > 0) {
this.nRemove++;
costRemoveCounter.executePayment(sa, card);
if (nNeeded == this.nRemove) {
this.done();
} else {
this.showMessage();
}
}
} }
return sum;
}
@Override
protected final boolean isValidChoice(Card choice) {
return validChoices.contains(choice) && choice.getCounters(counterType) > getTimesSelected(choice);
}
public int getTimesSelected(Card c) {
return selected.contains(c) ? nNeeded == 1 || cardsChosen.get(c) == null ? 1 : cardsChosen.get(c).intValue() : 0;
} }
} }
/** @Override
* TODO: Write javadoc for this type. public final boolean payHuman(final SpellAbility ability, final GameState game) {
* final String amount = this.getAmount();
*/ final Card source = ability.getSourceCard();
public static final class InputPayCostRemoveCounterFrom extends InputPayCostBase { Integer c = this.convertAmount();
private final CostRemoveCounter costRemoveCounter; int maxCounters = 0;
private final String type;
private final SpellAbility sa; cntRemoved = 1;
private final int nNeeded; if (amount.equals("All"))
private static final long serialVersionUID = 734256837615635021L; cntRemoved = maxCounters;
private List<Card> typeList; else if (c != null) {
private int nRemove = 0; cntRemoved = c.intValue();
} else {
/** cntRemoved = "XChoice".equals(ability.getSVar(amount))
* TODO: Write javadoc for Constructor. ? CostUtil.chooseXValue(source, ability, maxCounters)
* @param costRemoveCounter : AbilityUtils.calculateAmount(source, amount, ability);
* @param type }
* @param sa
* @param nNeeded if (this.payCostFromSource()) {
* @param payment maxCounters = source.getCounters(this.counter);
*/ if (maxCounters < c)
public InputPayCostRemoveCounterFrom(CostRemoveCounter costRemoveCounter, String type, SpellAbility sa, int nNeeded) { return false;
this.costRemoveCounter = costRemoveCounter; source.setSVar("CostCountersRemoved", Integer.toString(c));
this.type = type; executePayment(ability, source);
this.sa = sa; return true;
this.nNeeded = nNeeded; }
List<Card> validCards = CardLists.getValidCards(ability.getActivatingPlayer().getCardsIn(getZone()), getType().split(";"), ability.getActivatingPlayer(), source);
if (this.getZone().equals(ZoneType.Battlefield)) {
final InputSelectCardToRemoveCounter inp = new InputSelectCardToRemoveCounter(cntRemoved, getCounter(), validCards);
inp.setMessage("Remove %d " + getCounter().getName() + " counters from " + getDescriptiveType());
} FThreads.setInputAndWait(inp);
if(inp.hasCancelled())
return false;
@Override source.setSVar("CostCountersRemoved", Integer.toString(inp.getSelected().size()));
public void showMessage() { // Have to hack here: remove all counters minus one, without firing any triggers,
if (nNeeded == 0) { // triggers will fire when last is removed by executePayment.
this.done(); // They don't care how many were removed anyway
for(Card crd : inp.getSelected()) {
int cntRemoved = inp.getTimesSelected(crd);
if(cntRemoved < 2) continue;
int oldVal = crd.getCounters().get(getCounter()).intValue();
crd.getCounters().put(getCounter(), Integer.valueOf(oldVal - cntRemoved + 1));
} }
return executePayment(ability, inp.getSelected());
this.typeList = new ArrayList<Card>(sa.getActivatingPlayer().getCardsIn(costRemoveCounter.getZone())); }
this.typeList = CardLists.getValidCards(this.typeList, type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard());
// 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);
for (int i = 0; i < nNeeded; i++) { if(suspended.isEmpty())
if (this.typeList.isEmpty()) { return false;
this.onCancel();
}
final Card card = GuiChoose.oneOrNone("Remove counter(s) from a card in " + costRemoveCounter.getZone(), this.typeList); final Card card = GuiChoose.oneOrNone("Remove counter(s) from a card in " + getZone(), suspended);
if (card != null) { if( null == card)
if (card.getCounters(costRemoveCounter.getCounter()) > 0) { return false;
this.nRemove++;
costRemoveCounter.executePayment(sa, card); source.setSVar("CostCountersRemoved", "1");
return executePayment(ability, card);
if (card.getCounters(costRemoveCounter.getCounter()) == 0) {
this.typeList.remove(card);
}
if (nNeeded == this.nRemove) {
this.done();
} else {
this.showMessage();
}
}
} else {
this.onCancel();
break;
}
}
}
} }
private final CounterType counter; private final CounterType counter;
private int lastPaidAmount = 0; private final ZoneType zone;
private int cntCounters = 1; private int cntRemoved;
private ZoneType zone;
/** /**
* Gets the counter. * Gets the counter.
@@ -197,27 +203,10 @@ public class CostRemoveCounter extends CostPartWithList {
/** /**
* @return the zone * @return the zone
*/ */
public ZoneType getZone() { private ZoneType getZone() {
return zone; return zone;
} }
/**
* @param zone the zone to set
*/
public void setZone(ZoneType zone) {
this.zone = zone;
}
/**
* Sets the last paid amount.
*
* @param paidAmount
* the new last paid amount
*/
public final void setLastPaidAmount(final int paidAmount) {
this.lastPaidAmount = paidAmount;
}
/** /**
* Instantiates a new cost remove counter. * Instantiates a new cost remove counter.
* *
@@ -235,7 +224,7 @@ public class CostRemoveCounter extends CostPartWithList {
super(amount, type, description); super(amount, type, description);
this.counter = counter; this.counter = counter;
this.setZone(zone); this.zone = zone;
} }
@Override @Override
@@ -282,7 +271,7 @@ public class CostRemoveCounter extends CostPartWithList {
*/ */
@Override @Override
public final void refund(final Card source) { public final void refund(final Card source) {
int refund = this.getList().size() == 1 ? this.lastPaidAmount : 1; int refund = this.getList().size() == 1 ? this.cntRemoved : 1; // is wrong for Ooze Flux and Novijen Sages
for (final Card c : this.getList()) { for (final Card c : this.getList()) {
c.addCounter(this.counter, refund, false); c.addCounter(this.counter, refund, false);
} }
@@ -344,59 +333,12 @@ public class CostRemoveCounter extends CostPartWithList {
executePayment(ability, card); executePayment(ability, card);
} }
} }
source.setSVar("CostCountersRemoved", "Number$" + Integer.toString(c)); source.setSVar("CostCountersRemoved", Integer.toString(c));
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final boolean payHuman(final SpellAbility ability, final GameState game) {
final String amount = this.getAmount();
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
int maxCounters = 0;
if (amount.equals("All"))
cntCounters = maxCounters;
else if (c == null) {
final String sVar = ability.getSVar(amount);
if (sVar.equals("XChoice")) {
cntCounters = CostUtil.chooseXValue(source, ability, maxCounters);
} else {
cntCounters = AbilityUtils.calculateAmount(source, amount, ability);
}
} else cntCounters = c;
if (!this.payCostFromSource()) {
final InputPayment inp;
if (this.getZone().equals(ZoneType.Battlefield)) {
inp = new InputPayCostRemoveCounterType(cntCounters, ability, this.getType(), this);
} else {
inp = new InputPayCostRemoveCounterFrom(this, this.getType(), ability, cntCounters);
}
FThreads.setInputAndWait(inp);
if( inp.isPaid() ) source.setSVar("CostCountersRemoved", "Number$" + Integer.toString(c));
return inp.isPaid();
}
maxCounters = source.getCounters(this.counter);
if (maxCounters < c) return false;
source.setSVar("CostCountersRemoved", "Number$" + Integer.toString(c));
executePayment(ability, source);
return true;
} }
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard){ protected void doPayment(SpellAbility ability, Card targetCard){
targetCard.subtractCounter(this.getCounter(), cntCounters); targetCard.subtractCounter(this.getCounter(), 1);
} }
/* (non-Javadoc) /* (non-Javadoc)

View File

@@ -19,7 +19,7 @@ public abstract class InputSelectManyBase<T extends GameEntity> extends InputSyn
public boolean allowUnselect = false; public boolean allowUnselect = false;
private boolean allowCancel = false; private boolean allowCancel = false;
private String message = "Source-Card-Name - Select %d more card(s)"; protected String message = "Source-Card-Name - Select %d more card(s)";
@@ -45,21 +45,13 @@ public abstract class InputSelectManyBase<T extends GameEntity> extends InputSyn
public final void showMessage() { public final void showMessage() {
showMessage(getMessage()); showMessage(getMessage());
boolean canCancel = (min == 0 && selected.isEmpty()) || allowCancel; boolean canCancel = allowCancel;
boolean canOk = hasEnoughTargets(); boolean canOk = hasEnoughTargets();
if (canOk && canCancel) { if (canOk && canCancel) { ButtonUtil.enableAllFocusOk(); }
ButtonUtil.enableAllFocusOk(); if (!canOk && canCancel) { ButtonUtil.enableOnlyCancel(); }
} if (canOk && !canCancel) { ButtonUtil.enableOnlyOk(); }
if (!canOk && canCancel) { if (!canOk && !canCancel) { ButtonUtil.disableAll(); }
ButtonUtil.enableOnlyCancel();
}
if (canOk && !canCancel) {
ButtonUtil.enableOnlyOk();
}
if (!canOk && !canCancel) {
ButtonUtil.disableAll();
}
} }
@@ -67,7 +59,7 @@ public abstract class InputSelectManyBase<T extends GameEntity> extends InputSyn
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @return * @return
*/ */
protected String getMessage() { protected String getMessage() {
return max == Integer.MAX_VALUE return max == Integer.MAX_VALUE
? String.format(message, selected.size()) ? String.format(message, selected.size())
: String.format(message, max - selected.size()); : String.format(message, max - selected.size());