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;
* TODO: Write javadoc for Constructor. private final CounterType counterType;
* @param payment
* @param nNeeded
* @param sa
* @param type
* @param costRemoveCounter
*/
public InputPayCostRemoveCounterType(int nNeeded, SpellAbility sa, String type, CostRemoveCounter costRemoveCounter) {
this.nNeeded = nNeeded;
this.sa = sa;
this.type = type;
this.costRemoveCounter = costRemoveCounter;
}
@Override
public void showMessage() {
if ((nNeeded == 0) || (nNeeded == this.nRemove)) {
this.done();
}
final StringBuilder msg = new StringBuilder("Remove ");
final int nLeft = nNeeded - this.nRemove;
msg.append(nLeft).append(" ");
msg.append(costRemoveCounter.getCounter().getName()).append(" counters from ");
msg.append(costRemoveCounter.getDescriptiveType());
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
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString());
ButtonUtil.enableOnlyCancel();
}
/* (non-Javadoc)
* @see forge.control.input.InputSyncronizedBase#onCardSelected(forge.Card)
*/
@Override
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();
}
}
}
}
}
/**
* TODO: Write javadoc for this type.
*
*/
public static final class InputPayCostRemoveCounterFrom extends InputPayCostBase {
private final CostRemoveCounter costRemoveCounter;
private final String type;
private final SpellAbility sa;
private final int nNeeded; private final int nNeeded;
private static final long serialVersionUID = 734256837615635021L; private final List<Card> validChoices;
private List<Card> typeList;
private int nRemove = 0;
/**
* TODO: Write javadoc for Constructor.
* @param costRemoveCounter
* @param type
* @param sa
* @param nNeeded
* @param payment
*/
public InputPayCostRemoveCounterFrom(CostRemoveCounter costRemoveCounter, String type, SpellAbility sa, int nNeeded) {
this.costRemoveCounter = costRemoveCounter;
this.type = type;
this.sa = sa;
this.nNeeded = nNeeded;
public InputSelectCardToRemoveCounter(int cntCounters, CounterType cType, List<Card> validCards) {
super(cntCounters, cntCounters);
this.validChoices = validCards;
counterType = cType;
nNeeded = cntCounters;
cardsChosen = cntCounters > 1 ? new HashMap<Card, Integer>() : null;
} }
@Override @Override
public void showMessage() { protected boolean selectEntity(Card c) {
if (nNeeded == 0) { if (!isValidChoice(c)) {
this.done(); return false;
} }
this.typeList = new ArrayList<Card>(sa.getActivatingPlayer().getCardsIn(costRemoveCounter.getZone())); int tc = getTimesSelected(c);
this.typeList = CardLists.getValidCards(this.typeList, type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard()); if( tc == 0)
selected.add(c);
else
cardsChosen.put(c, tc+1);
for (int i = 0; i < nNeeded; i++) { onSelectStateChanged(c, true);
if (this.typeList.isEmpty()) { return true;
this.onCancel();
} }
final Card card = GuiChoose.oneOrNone("Remove counter(s) from a card in " + costRemoveCounter.getZone(), this.typeList); @Override
if (card != null) { protected boolean hasEnoughTargets() {
if (card.getCounters(costRemoveCounter.getCounter()) > 0) { return hasAllTargets();
this.nRemove++;
costRemoveCounter.executePayment(sa, card);
if (card.getCounters(costRemoveCounter.getCounter()) == 0) {
this.typeList.remove(card);
} }
if (nNeeded == this.nRemove) { @Override
this.done(); 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());
}
private int getDistibutedCounters() {
int sum = 0;
for(Card c : selected) {
sum += nNeeded == 1 || cardsChosen.get(c) == null ? 1 : cardsChosen.get(c).intValue();
}
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
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;
cntRemoved = 1;
if (amount.equals("All"))
cntRemoved = maxCounters;
else if (c != null) {
cntRemoved = c.intValue();
} else { } else {
this.showMessage(); cntRemoved = "XChoice".equals(ability.getSVar(amount))
? CostUtil.chooseXValue(source, ability, maxCounters)
: AbilityUtils.calculateAmount(source, amount, ability);
} }
if (this.payCostFromSource()) {
maxCounters = source.getCounters(this.counter);
if (maxCounters < c)
return false;
source.setSVar("CostCountersRemoved", Integer.toString(c));
executePayment(ability, source);
return true;
} }
} else {
this.onCancel();
break;
} 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;
source.setSVar("CostCountersRemoved", Integer.toString(inp.getSelected().size()));
// 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
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());
} }
// 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);
if(suspended.isEmpty())
return false;
final Card card = GuiChoose.oneOrNone("Remove counter(s) from a card in " + getZone(), suspended);
if( null == card)
return false;
source.setSVar("CostCountersRemoved", "1");
return executePayment(ability, card);
} }
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();
}
} }