Costs no longer keep AI's choice in the CostPart class,

CardList has filter method to apply 2 filters sequentially
Untap: old inputs replaced with synchronized ones.
InputProxy - using an AtomicReference to hold current input, just in case.
This commit is contained in:
Maxmtg
2013-03-28 08:14:13 +00:00
parent 564c97571b
commit 98a539f23a
29 changed files with 652 additions and 990 deletions

1
.gitattributes vendored
View File

@@ -13713,6 +13713,7 @@ src/main/java/forge/card/cost/CostUntap.java -text
src/main/java/forge/card/cost/CostUntapType.java -text
src/main/java/forge/card/cost/CostUtil.java -text
src/main/java/forge/card/cost/InputPayCostBase.java -text
src/main/java/forge/card/cost/PaymentDecision.java -text
src/main/java/forge/card/cost/package-info.java svneol=native#text/plain
src/main/java/forge/card/mana/IParserManaCost.java -text
src/main/java/forge/card/mana/Mana.java svneol=native#text/plain

View File

@@ -8993,7 +8993,7 @@ public class Card extends GameEntity implements Comparable<Card> {
if (getController() == null) {
return false;
}
return getController().getCardsIn(ZoneType.Battlefield).contains(this);
return getController().getZone(ZoneType.Battlefield).contains(this);
}
public void onCleanupPhase(final Player turn) {

View File

@@ -254,6 +254,10 @@ public class CardLists {
return Lists.newArrayList(Iterables.filter(cardList, filt));
}
public static List<Card> filter(Iterable<Card> cardList, Predicate<Card> f1, Predicate<Card> f2) {
return Lists.newArrayList(Iterables.filter(Iterables.filter(cardList, f1), f2));
}
public static List<Card> createCardList(Card c) {
List<Card> res = new ArrayList<Card>();
res.add(c);

View File

@@ -21,9 +21,9 @@ public class FThreads {
private FThreads() { } // no instances supposed
private final static ExecutorService threadPool = Executors.newCachedThreadPool();
private static ExecutorService getCachedPool() { return threadPool; }
private final static ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(1);
private final static ExecutorService cachedPool = Executors.newCachedThreadPool();
private static ExecutorService getCachedPool() { return cachedPool; }
private final static ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2);
private static ScheduledExecutorService getScheduledPool() { return scheduledPool; }
// This pool is designed to parallel CPU or IO intensive tasks like parse cards or download images, assuming a load factor of 0.5

View File

@@ -28,6 +28,7 @@ import forge.card.ability.SpellAbilityAi;
import forge.card.cost.Cost;
import forge.card.cost.CostDiscard;
import forge.card.cost.CostPart;
import forge.card.cost.PaymentDecision;
import forge.card.spellability.AbilitySub;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
@@ -70,8 +71,10 @@ public class DrawAi extends SpellAbilityAi {
for (final CostPart part : abCost.getCostParts()) {
if (part instanceof CostDiscard) {
CostDiscard cd = (CostDiscard) part;
cd.decideAIPayment((AIPlayer) ai, sa, sa.getSourceCard(), null);
for (Card discard : cd.getList()) {
PaymentDecision decision = cd.decideAIPayment((AIPlayer) ai, sa, sa.getSourceCard());
if ( null == decision )
return false;
for (Card discard : decision.cards) {
if (!ComputerUtil.isWorseThanDraw(ai, discard)) {
return false;
}

View File

@@ -145,13 +145,22 @@ public class Cost {
StringBuilder manaParts = new StringBuilder();
String[] parts = TextUtil.splitWithParenthesis(parse, ' ', '<', '>');
// make this before parse so that classes that need it get data in their constructor
for(String part : parts) {
if ( part.equals("T") || part.equals("Tap") )
this.tapCost = true;
if ( part.equals("Q") || part.equals("Untap") )
this.untapCost = true;
}
for(String part : parts) {
if( "XCantBe0".equals(part) )
xCantBe0 = true;
else if ( "X".equals(part) )
amountX++;
else {
CostPart cp = parseCostPart(part);
CostPart cp = parseCostPart(part, tapCost, untapCost);
if ( null != cp )
this.costParts.add(cp);
else
@@ -175,22 +184,20 @@ public class Cost {
if( cp instanceof CostUntap ) {
costParts.remove(iCp);
costParts.add(0, cp);
untapCost = true;
}
if( cp instanceof CostTap ) {
costParts.remove(iCp);
costParts.add(0, cp);
tapCost = true;
}
}
}
private static CostPart parseCostPart(String parse) {
private static CostPart parseCostPart(String parse, boolean tapCost, boolean untapCost) {
if(parse.startsWith("tapXType<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostTapType(splitStr[0], splitStr[1], description);
return new CostTapType(splitStr[0], splitStr[1], description, tapCost);
}
if(parse.startsWith("untapYType<")) {
@@ -337,9 +344,9 @@ public class Cost {
* @return an array of {@link java.lang.String} objects.
*/
private static String[] abCostParse(final String parse, final int numParse) {
final int startPos = parse.indexOf("<");
final int startPos = 1 + parse.indexOf("<");
final int endPos = parse.indexOf(">", startPos);
String str = parse.substring(startPos + 1, endPos);
String str = parse.substring(startPos, endPos);
final String[] splitStr = str.split("/", numParse);
return splitStr;

View File

@@ -29,33 +29,7 @@ import forge.gui.GuiDialog;
* The Class CostPayLife.
*/
public class CostDamage extends CostPart {
private int lastPaidAmount = 0;
/**
* Gets the last paid amount.
*
* @return the last paid amount
*/
public final int getLastPaidAmount() {
return this.lastPaidAmount;
}
/**
* 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 pay life.
*
* @param amount
* the amount
*/
public CostDamage(final String amount) {
this.setAmount(amount);
}
@@ -91,8 +65,8 @@ public class CostDamage extends CostPart {
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
ability.getActivatingPlayer().addDamage(this.getLastPaidAmount(), source);
public final void payAI(final PaymentDecision decision, final AIPlayer ai, SpellAbility ability, Card source) {
ability.getActivatingPlayer().addDamage(decision.c, source);
}
/*
@@ -139,21 +113,19 @@ public class CostDamage extends CostPart {
* , forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
public final PaymentDecision decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source) {
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(this.getAmount());
// Generalize this
if (sVar.equals("XChoice")) {
return false;
return null; // cannot pay
} else {
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
}
// activator.payLife(c, null);
this.setLastPaidAmount(c);
return true;
return new PaymentDecision(c);
}
}

View File

@@ -33,6 +33,7 @@ import forge.game.GameState;
import forge.game.player.AIPlayer;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
/**
* The Class CostDiscard.
@@ -145,19 +146,6 @@ public class CostDiscard extends CostPartWithList {
return true;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
for (final Card c : this.getList()) {
executePayment(ability, c);
}
}
/*
* (non-Javadoc)
*
@@ -172,27 +160,20 @@ public class CostDiscard extends CostPartWithList {
List<Card> handList = new ArrayList<Card>(activator.getCardsIn(ZoneType.Hand));
String discardType = this.getType();
final String amount = this.getAmount();
this.resetList();
if (this.payCostFromSource()) {
if (!handList.contains(source)) {
return false;
return handList.contains(source) && executePayment(ability, source);
}
executePayment(ability, source);
return true;
//this.addToList(source);
} else if (discardType.equals("Hand")) {
this.setList(handList);
activator.discardHand(ability);
return true;
} else if (discardType.equals("LastDrawn")) {
if (discardType.equals("Hand")) {
return executePayment(ability, handList);
}
if (discardType.equals("LastDrawn")) {
final Card lastDrawn = activator.getLastDrawnCard();
if (!handList.contains(lastDrawn)) {
return false;
return handList.contains(lastDrawn) && executePayment(ability, lastDrawn);
}
executePayment(ability, lastDrawn);
return true;
} else {
Integer c = this.convertAmount();
if (discardType.equals("Random")) {
@@ -206,8 +187,8 @@ public class CostDiscard extends CostPartWithList {
}
}
this.setList(activator.discardRandom(c, ability));
return true;
return executePayment(ability, Aggregates.random(handList, c));
} else {
String type = new String(discardType);
boolean sameName = false;
@@ -248,73 +229,62 @@ public class CostDiscard extends CostPartWithList {
FThreads.setInputAndWait(inp);
if( inp.hasCancelled() || inp.getSelected().size() != c)
return false;
for(Card crd : inp.getSelected())
executePayment(ability, crd);
return true;
}
return executePayment(ability, inp.getSelected());
}
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
final String type = this.getType();
final List<Card> hand = ai.getCardsIn(ZoneType.Hand);
this.resetList();
if (type.equals("LastDrawn")) {
if (!hand.contains(ai.getLastDrawnCard())) {
return false;
return null;
}
this.addToList(ai.getLastDrawnCard());
return new PaymentDecision(ai.getLastDrawnCard());
}
else if (this.payCostFromSource()) {
if (!hand.contains(source)) {
return false;
return null;
}
this.addToList(source);
return new PaymentDecision(source);
}
else if (type.equals("Hand")) {
this.getList().addAll(hand);
return new PaymentDecision(hand);
}
else {
if (type.contains("WithSameName")) {
return false;
return null;
}
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(this.getAmount());
if (sVar.equals("XChoice")) {
return false;
return null;
}
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
if (type.equals("Random")) {
this.setList(CardLists.getRandomSubList(hand, c));
return new PaymentDecision(CardLists.getRandomSubList(hand, c));
} else {
this.setList(ai.getAi().getCardsToDiscard(c, type.split(";"), ability));
return new PaymentDecision(ai.getAi().getCardsToDiscard(c, type.split(";"), ability));
}
}
return this.getList() != null;
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard) {
this.addToList(targetCard);
protected void doPayment(SpellAbility ability, Card targetCard) {
targetCard.getController().discard(targetCard, ability);
}
@@ -326,6 +296,14 @@ public class CostDiscard extends CostPartWithList {
return "Discarded";
}
/* (non-Javadoc)
* @see forge.card.cost.CostPart#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void payAI(PaymentDecision decision, AIPlayer ai, SpellAbility ability, Card source) {
executePayment(ability, decision.cards);
}
// Inputs
}

View File

@@ -505,28 +505,6 @@ public class CostExile extends CostPartWithList {
return true;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
for (final Card c : this.getList()) {
Singletons.getModel().getGame().getAction().exile(c);
if (this.from.equals(ZoneType.Stack)) {
ArrayList<SpellAbility> spells = c.getSpellAbilities();
for (SpellAbility spell : spells) {
if (c.isInZone(ZoneType.Exile)) {
final SpellAbilityStackInstance si = Singletons.getModel().getGame().getStack().getInstanceFromSpellAbility(spell);
Singletons.getModel().getGame().getStack().remove(si);
}
}
}
}
}
/*
* (non-Javadoc)
*
@@ -597,51 +575,7 @@ public class CostExile extends CostPartWithList {
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
this.resetList();
if (this.payCostFromSource()) {
this.getList().add(source);
} else if (this.getType().equals("All")) {
this.setList(new ArrayList<Card>(ability.getActivatingPlayer().getCardsIn(this.getFrom())));
} else {
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(this.getAmount());
// Generalize this
if (sVar.equals("XChoice")) {
return false;
}
if (sVar.equals("YChoice")) {
return false;
}
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
if (this.from.equals(ZoneType.Library)) {
this.setList(ai.getCardsIn(ZoneType.Library, c));
} else if (this.sameZone) {
// TODO Determine exile from same zone for AI
return false;
} else {
this.setList(ComputerUtil.chooseExileFrom(ai, this.getFrom(), this.getType(), source,
ability.getTargetCard(), c));
}
if ((this.getList() == null) || (this.getList().size() < c)) {
return false;
}
}
return true;
}
// Inputs
@@ -683,8 +617,7 @@ public class CostExile extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard) {
addToList(targetCard);
protected void doPayment(SpellAbility ability, Card targetCard) {
ability.getActivatingPlayer().getGame().getAction().exile(targetCard);
}
@@ -696,4 +629,57 @@ public class CostExile extends CostPartWithList {
// TODO Auto-generated method stub
return "Exiled";
}
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
if (this.payCostFromSource()) {
return new PaymentDecision(source);
}
if (this.getType().equals("All")) {
return new PaymentDecision(new ArrayList<Card>(ai.getCardsIn(this.getFrom())));
}
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(this.getAmount());
// Generalize this
if (sVar.equals("XChoice") || sVar.equals("YChoice")) {
return null;
}
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
if (this.from.equals(ZoneType.Library)) {
return new PaymentDecision(ai.getCardsIn(ZoneType.Library, c));
} else if (this.sameZone) {
// TODO Determine exile from same zone for AI
return null;
} else {
return new PaymentDecision(ComputerUtil.chooseExileFrom(ai, this.getFrom(), this.getType(), source, ability.getTargetCard(), c));
}
}
/* (non-Javadoc)
* @see forge.card.cost.CostPart#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void payAI(PaymentDecision decision, AIPlayer ai, SpellAbility ability, Card source) {
for (final Card c : decision.cards) {
executePayment(ability, c);
if (this.from.equals(ZoneType.Stack)) {
ArrayList<SpellAbility> spells = c.getSpellAbilities();
for (SpellAbility spell : spells) {
if (c.isInZone(ZoneType.Exile)) {
final SpellAbilityStackInstance si = ai.getGame().getStack().getInstanceFromSpellAbility(spell);
ai.getGame().getStack().remove(si);
}
}
}
}
}
}

View File

@@ -33,26 +33,6 @@ import forge.gui.GuiChoose;
*/
public class CostGainLife extends CostPart {
private final int cntPlayers; // MAX_VALUE means ALL/EACH PLAYERS
private int lastPaidAmount = 0;
/**
* Gets the last paid amount.
*
* @return the last paid amount
*/
public final int getLastPaidAmount() {
return this.lastPaidAmount;
}
/**
* 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 gain life.
@@ -109,7 +89,7 @@ public class CostGainLife extends CostPart {
}
}
return cntPlayers < Integer.MAX_VALUE ? cntAbleToGainLife >= cntPlayers : cntAbleToGainLife == possibleTargets.size();
return cntAbleToGainLife >= cntPlayers || cntPlayers == Integer.MAX_VALUE && cntAbleToGainLife == possibleTargets.size();
}
/*
@@ -119,12 +99,12 @@ public class CostGainLife extends CostPart {
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
public final void payAI(final PaymentDecision decision, final AIPlayer ai, SpellAbility ability, Card source) {
int playersLeft = cntPlayers;
for (final Player opp : getPotentialTargets(game, ai, source)) {
for (final Player opp : getPotentialTargets(ai.getGame(), ai, source)) {
if (opp.canGainLife() && playersLeft > 0) {
playersLeft--;
opp.gainLife(this.getLastPaidAmount(), null);
opp.gainLife(decision.c, null);
}
}
}
@@ -190,15 +170,13 @@ public class CostGainLife extends CostPart {
* , forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
public final PaymentDecision decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source) {
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(this.getAmount());
// Generalize this
if (sVar.equals("XChoice")) {
return false;
return null;
} else {
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
@@ -212,9 +190,9 @@ public class CostGainLife extends CostPart {
}
if (oppsThatCanGainLife.size() == 0) {
return false;
return null;
}
this.setLastPaidAmount(c);
return true;
return new PaymentDecision(c);
}
}

View File

@@ -17,12 +17,9 @@
*/
package forge.card.cost;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import forge.Card;
import forge.Singletons;
import forge.card.ability.AbilityUtils;
import forge.card.spellability.SpellAbility;
import forge.game.GameState;
@@ -49,6 +46,14 @@ public class CostMill extends CostPartWithList {
this.setAmount(amount);
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList()
*/
@Override
public String getHashForList() {
return "Milled";
}
/*
* (non-Javadoc)
*
@@ -74,50 +79,6 @@ public class CostMill extends CostPartWithList {
return i < zone.size();
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
this.resetList();
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(this.getAmount());
// Generalize this
if (sVar.equals("XChoice")) {
return false;
}
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
this.setList(new ArrayList<Card>(ai.getCardsIn(ZoneType.Library, c)));
if ((this.getList() == null) || (this.getList().size() < c)) {
return false;
}
return true;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
for (final Card c : this.getList()) {
Singletons.getModel().getGame().getAction().moveToGraveyard(c);
}
}
/*
* (non-Javadoc)
*
@@ -143,21 +104,13 @@ public class CostMill extends CostPartWithList {
}
final List<Card> list = activator.getCardsIn(ZoneType.Library, c);
if ((list == null) || (list.size() > c)) {
// I don't believe this is possible
return false;
}
final StringBuilder sb = new StringBuilder();
sb.append("Mill ").append(c).append(" cards from your library?");
if ( false == GuiDialog.confirm(source, sb.toString()) )
return false;
this.resetList();
final Iterator<Card> itr = list.iterator();
while (itr.hasNext()) {
final Card card = itr.next();
for(final Card card : list) { // this list is a copy, no exception expected
executePayment(ability, card);
}
return true;
@@ -193,17 +146,27 @@ public class CostMill extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard) {
this.addToList(targetCard);
protected void doPayment(SpellAbility ability, Card targetCard) {
ability.getActivatingPlayer().getGame().getAction().moveToGraveyard(targetCard);
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList()
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public String getHashForList() {
return "Milled";
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(this.getAmount());
// Generalize this
if (sVar.equals("XChoice")) {
return null;
}
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
List<Card> topLib = ai.getCardsIn(ZoneType.Library, c);
return topLib.size() < c ? null : new PaymentDecision(topLib);
}
}

View File

@@ -28,17 +28,8 @@ import forge.game.player.Player;
* The Class CostPart.
*/
public abstract class CostPart {
/** The optional. */
// private boolean optional = false;
/** The amount. */
private String amount = "1";
/** The type. */
private final String type;
/** The type description. */
private final String typeDescription;
/**
@@ -171,7 +162,7 @@ public abstract class CostPart {
* {@link forge.card.cost.CostPayment}
* @return true, if successful
*/
public abstract boolean decideAIPayment(final AIPlayer ai, SpellAbility ability, Card source, CostPayment payment);
public abstract PaymentDecision decideAIPayment(final AIPlayer ai, SpellAbility ability, Card source);
/**
* Pay ai.
@@ -186,7 +177,7 @@ public abstract class CostPart {
* {@link forge.card.cost.CostPayment}
* @param game
*/
public abstract void payAI(final AIPlayer ai, SpellAbility ability, Card source, CostPayment payment, GameState game);
public abstract void payAI(final PaymentDecision decision, final AIPlayer ai, SpellAbility ability, Card source);
/**
* Pay human.

View File

@@ -187,14 +187,11 @@ public class CostPartMana extends CostPart {
return true;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPart#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
public void payAI(PaymentDecision decision, AIPlayer ai, SpellAbility ability, Card source) {
ComputerUtilMana.payManaCost(ai, ability);
}
@@ -235,16 +232,12 @@ public class CostPartMana extends CostPart {
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
return true;
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
return new PaymentDecision(0);
}
// Inputs

View File

@@ -17,13 +17,13 @@
*/
package forge.card.cost;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import forge.Card;
import forge.CardUtil;
import forge.card.spellability.SpellAbility;
import forge.game.player.AIPlayer;
/**
* The Class CostPartWithList.
@@ -31,7 +31,7 @@ import forge.card.spellability.SpellAbility;
public abstract class CostPartWithList extends CostPart {
/** The list. */
private Set<Card> list = new HashSet<Card>();
private final List<Card> list = new ArrayList<Card>();
// set is here because executePayment() adds card to list, while ai's decide payment does the same thing.
// set allows to avoid duplication
@@ -40,21 +40,10 @@ public abstract class CostPartWithList extends CostPart {
*
* @return the list
*/
public final Set<Card> getList() {
public final List<Card> getList() {
return this.list;
}
/**
* Sets the list.
*
* @param setList
* the new list
*/
public final void setList(final List<Card> setList) {
this.list.clear();
list.addAll(setList);
}
/**
* Reset list.
*/
@@ -62,13 +51,7 @@ public abstract class CostPartWithList extends CostPart {
this.list.clear();
}
/**
* Adds the to list.
*
* @param c
* the c
*/
public final void addToList(final Card c) {
protected final void addToList(final Card c) {
this.list.add(c);
}
@@ -105,14 +88,33 @@ public abstract class CostPartWithList extends CostPart {
*/
public CostPartWithList(final String amount, final String type, final String description) {
super(amount, type, description);
this.resetList();
}
public abstract void executePayment(SpellAbility ability, Card targetCard);
public final boolean executePayment(SpellAbility ability, Card targetCard) {
addToList(targetCard);
doPayment(ability, targetCard);
return true;
}
// always returns true, made this to inline with return
public final boolean executePayment(SpellAbility ability, Collection<Card> targetCards) {
for(Card c: targetCards)
executePayment(ability, c);
return true;
}
protected abstract void doPayment(SpellAbility ability, Card targetCard);
/**
* TODO: Write javadoc for this method.
* @return
*/
public abstract String getHashForList();
@Override
public void payAI(PaymentDecision decision, AIPlayer ai, SpellAbility ability, Card source) {
executePayment(ability, decision.cards);
reportPaidCardsTo(ability);
}
}

View File

@@ -29,26 +29,7 @@ import forge.gui.GuiDialog;
* The Class CostPayLife.
*/
public class CostPayLife extends CostPart {
private int lastPaidAmount = 0;
/**
* Gets the last paid amount.
*
* @return the last paid amount
*/
public final int getLastPaidAmount() {
return this.lastPaidAmount;
}
/**
* Sets the last paid amount.
*
* @param paidAmount
* the new last paid amount
*/
public final void setLastPaidAmount(final int paidAmount) {
this.lastPaidAmount = paidAmount;
}
int paidAmount = 0;
/**
* Instantiates a new cost pay life.
@@ -80,7 +61,7 @@ public class CostPayLife extends CostPart {
@Override
public final void refund(final Card source) {
// Really should be activating player
source.getController().payLife(this.lastPaidAmount * -1, null);
source.getController().payLife(this.paidAmount * -1, null);
}
/*
@@ -104,15 +85,14 @@ public class CostPayLife extends CostPart {
return true;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPart#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
ai.payLife(this.getLastPaidAmount(), null);
public void payAI(PaymentDecision decision, AIPlayer ai, SpellAbility ability, Card source) {
// TODO Auto-generated method stub
paidAmount = decision.c;
ai.payLife(paidAmount, null);
}
/*
@@ -153,34 +133,29 @@ public class CostPayLife extends CostPart {
} else {
return false;
}
paidAmount = c;
return true;
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(this.getAmount());
// Generalize this
if (sVar.equals("XChoice")) {
return false;
return null;
} else {
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
}
if (!ai.canPayLife(c)) {
return false;
return null;
}
// activator.payLife(c, null);
this.setLastPaidAmount(c);
return true;
return new PaymentDecision(c);
}
}

View File

@@ -18,8 +18,9 @@
package forge.card.cost;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import forge.Card;
import forge.card.spellability.SpellAbility;
import forge.game.GameState;
@@ -181,15 +182,17 @@ public class CostPayment {
parts.add(new CostPartMana("0", 0, false));
}
Map<Class<? extends CostPart>, PaymentDecision> decisions = new HashMap<Class<? extends CostPart>, PaymentDecision>();
// Set all of the decisions before attempting to pay anything
for (final CostPart part : parts) {
if (!part.decideAIPayment(ai, this.ability, source, this)) {
return false;
}
PaymentDecision decision = part.decideAIPayment(ai, this.ability, source);
if ( null == decision ) return false;
decisions.put(part.getClass(), decision);
}
for (final CostPart part : parts) {
part.payAI(ai, this.ability, this.ability.getSourceCard(), this, game);
part.payAI(decisions.get(part.getClass()), ai, this.ability, this.ability.getSourceCard());
}
return true;
}

View File

@@ -217,16 +217,14 @@ public class CostPutCounter extends CostPartWithList {
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
public void payAI(PaymentDecision decision, AIPlayer ai, SpellAbility ability, Card source) {
Integer c = getNumberOfCounters(ability);
if (this.payCostFromSource()) {
executePayment(ability, source, c);
} else {
// Put counter on chosen card
for (final Card card : this.getList()) {
executePayment(ability, card);
}
executePayment(ability, decision.cards);
}
}
@@ -260,20 +258,42 @@ public class CostPutCounter extends CostPartWithList {
return c;
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
this.resetList();
protected void doPayment(SpellAbility ability, Card targetCard){
targetCard.addCounter(this.getCounter(), 1, false);
}
protected void executePayment(SpellAbility ability, Card targetCard, int c) {
CounterType counterType = this.getCounter();
if( c > 1 ) {
Integer oldValue = targetCard.getCounters().get(counterType);
int newValue = c + (oldValue == null ? 0 : oldValue.intValue()) - 1;
targetCard.getCounters().put(counterType, Integer.valueOf(newValue));
}
// added c - 1 without firing triggers, the last counter added should fire trigger.
executePayment(ability, targetCard);
}
@Override
public String getHashForList() {
return "CounterPut";
}
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
if (this.payCostFromSource()) {
this.addToList(source);
return true;
} else {
return new PaymentDecision(source);
}
final List<Card> typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), this.getType().split(";"), ai, source);
Card card = null;
@@ -282,27 +302,6 @@ public class CostPutCounter extends CostPartWithList {
} else {
card = ComputerUtilCard.getWorstPermanentAI(typeList, false, false, false, false);
}
this.addToList(card);
}
return true;
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard){
executePayment(ability, targetCard, 1);
}
public void executePayment(SpellAbility ability, Card targetCard, int c) {
targetCard.addCounter(this.getCounter(), c, false);
this.addToList(targetCard);
}
@Override
public String getHashForList() {
return "CounterPut";
return new PaymentDecision(card);
}
}

View File

@@ -183,6 +183,7 @@ public class CostRemoveCounter extends CostPartWithList {
private final CounterType counter;
private int lastPaidAmount = 0;
private int cntCounters = 1;
private ZoneType zone;
/**
@@ -320,14 +321,11 @@ public class CostRemoveCounter extends CostPartWithList {
return true;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
public void payAI(PaymentDecision decision, AIPlayer ai, SpellAbility ability, Card source) {
final String amount = this.getAmount();
Integer c = this.convertAmount();
if (c == null) {
@@ -339,10 +337,10 @@ public class CostRemoveCounter extends CostPartWithList {
}
if (this.payCostFromSource()) {
source.subtractCounter(this.counter, c);
executePayment(ability, source);
} else {
for (final Card card : this.getList()) {
card.subtractCounter(this.counter, c);
for (final Card card : decision.cards) {
executePayment(ability, card);
}
}
source.setSVar("CostCountersRemoved", "Number$" + Integer.toString(c));
@@ -362,60 +360,57 @@ public class CostRemoveCounter extends CostPartWithList {
Integer c = this.convertAmount();
int maxCounters = 0;
if (!this.payCostFromSource()) {
if (c == null) {
if (amount.equals("All"))
cntCounters = maxCounters;
else if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, maxCounters);
cntCounters = CostUtil.chooseXValue(source, ability, maxCounters);
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
cntCounters = AbilityUtils.calculateAmount(source, amount, ability);
}
} else cntCounters = c;
if (!this.payCostFromSource()) {
final InputPayment inp;
if (this.getZone().equals(ZoneType.Battlefield)) {
inp = new InputPayCostRemoveCounterType(c, ability, this.getType(), this);
inp = new InputPayCostRemoveCounterType(cntCounters, ability, this.getType(), this);
} else {
inp = new InputPayCostRemoveCounterFrom(this, this.getType(), ability, c);
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 (amount.equals("All")) {
c = maxCounters;
} else {
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, maxCounters);
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
}
if (maxCounters < c) return false;
this.addToList(source);
source.setSVar("CostCountersRemoved", "Number$" + Integer.toString(c));
executePayment(ability, source, c);
executePayment(ability, source);
return true;
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
@Override
protected void doPayment(SpellAbility ability, Card targetCard){
targetCard.subtractCounter(this.getCounter(), cntCounters);
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList()
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
public String getHashForList() {
return "CounterRemove";
}
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
final String amount = this.getAmount();
Integer c = this.convertAmount();
@@ -423,7 +418,7 @@ public class CostRemoveCounter extends CostPartWithList {
if (c == null) {
final String sVar = ability.getSVar(amount);
if (sVar.equals("XChoice")) {
return false;
return null;
}
if (amount.equals("All")) {
c = source.getCounters(this.counter);
@@ -433,41 +428,20 @@ public class CostRemoveCounter extends CostPartWithList {
}
if (!this.payCostFromSource()) {
this.getList().clear();
final List<Card> typeList =
CardLists.getValidCards(ai.getCardsIn(this.getZone()), this.getType().split(";"), ai, source);
for (Card card : typeList) {
if (card.getCounters(this.getCounter()) >= c) {
this.addToList(card);
return true;
return new PaymentDecision(card);
}
}
return false;
return null;
}
if (c > source.getCounters(this.getCounter())) {
System.out.println("Not enough " + this.counter + " on " + source.getName());
return false;
return null;
}
return true;
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard) {
executePayment(ability, targetCard, 1);
}
public void executePayment(SpellAbility ability, Card targetCard, int n) {
addToList(targetCard);
targetCard.subtractCounter(getCounter(), n);
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList()
*/
@Override
public String getHashForList() {
return "CounterRemove";
return new PaymentDecision(source);
}
}

View File

@@ -111,19 +111,6 @@ public class CostReturn extends CostPartWithList {
return true;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
for (final Card c : this.getList()) {
executePayment(ability, c);
}
}
/*
* (non-Javadoc)
*
@@ -180,30 +167,24 @@ public class CostReturn extends CostPartWithList {
* , forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
this.resetList();
if (this.payCostFromSource()) {
this.getList().add(source);
} else {
public final PaymentDecision decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source) {
if (this.payCostFromSource())
return new PaymentDecision(source);
Integer c = this.convertAmount();
if (c == null) {
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
this.setList(ComputerUtil.chooseReturnType(ai, this.getType(), source, ability.getTargetCard(), c));
if (this.getList().isEmpty()) {
return false;
}
}
return true;
List<Card> res = ComputerUtil.chooseReturnType(ai, this.getType(), source, ability.getTargetCard(), c);
return res.isEmpty() ? null : new PaymentDecision(res);
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard) {
addToList(targetCard);
protected void doPayment(SpellAbility ability, Card targetCard) {
ability.getActivatingPlayer().getGame().getAction().moveToHand(targetCard);
}
@@ -215,6 +196,16 @@ public class CostReturn extends CostPartWithList {
return "Returned";
}
/* (non-Javadoc)
* @see forge.card.cost.CostPart#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void payAI(PaymentDecision decision, AIPlayer ai, SpellAbility ability, Card source) {
for (final Card c : decision.cards) {
executePayment(ability, c);
}
}
// Inputs

View File

@@ -31,7 +31,6 @@ import forge.game.player.AIPlayer;
import forge.game.player.Player;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.view.ButtonUtil;
/**
@@ -172,29 +171,25 @@ public class CostReveal extends CostPartWithList {
return true;
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
final String type = this.getType();
List<Card> hand = new ArrayList<Card>(ai.getCardsIn(ZoneType.Hand));
this.resetList();
if (this.payCostFromSource()) {
if (!hand.contains(source)) {
return false;
return null;
}
return new PaymentDecision(source);
}
this.getList().add(source);
} else if (this.getType().equals("Hand")) {
this.setList(new ArrayList<Card>(ai.getCardsIn(ZoneType.Hand)));
return true;
} else {
if (this.getType().equals("Hand"))
return new PaymentDecision(new ArrayList<Card>(ai.getCardsIn(ZoneType.Hand)));
hand = CardLists.getValidCards(hand, type.split(";"), ai, source);
Integer c = this.convertAmount();
if (c == null) {
@@ -206,22 +201,7 @@ public class CostReveal extends CostPartWithList {
}
}
this.setList(ai.getAi().getCardsToDiscard(c, type.split(";"), ability));
}
return this.getList() != null;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
GuiChoose.oneOrNone("Revealed cards:", this.getList());
for(Card c: getList()) // should not throw concurrent modification here - no items should be added.
executePayment(ability, c);
return new PaymentDecision(ai.getAi().getCardsToDiscard(c, type.split(";"), ability));
}
/*
@@ -236,7 +216,6 @@ public class CostReveal extends CostPartWithList {
final Player activator = ability.getActivatingPlayer();
final Card source = ability.getSourceCard();
final String amount = this.getAmount();
this.resetList();
if (this.payCostFromSource()) {
executePayment(ability, source);
@@ -304,8 +283,7 @@ public class CostReveal extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard) {
addToList(targetCard);
protected void doPayment(SpellAbility ability, Card targetCard) {
// write code to actually reveal card
}

View File

@@ -184,20 +184,6 @@ public class CostSacrifice extends CostPartWithList {
return true;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
this.reportPaidCardsTo(ability);
for (final Card c : this.getList()) {
executePayment(ability, c);
}
}
/*
* (non-Javadoc)
*
@@ -219,18 +205,11 @@ public class CostSacrifice extends CostPartWithList {
if (this.payCostFromSource()) {
if (source.getController() == ability.getActivatingPlayer() && source.isInPlay()) {
if (!GuiDialog.confirm(source, source.getName() + " - Sacrifice?"))
return false;
executePayment(ability, source);
return true;
return GuiDialog.confirm(source, source.getName() + " - Sacrifice?") && executePayment(ability, source);
}
} else if (amount.equals("All")) {
this.setList(list);
// TODO Ask First
for (final Card card : list) {
executePayment(ability, card);
}
return true;
return executePayment(ability, list);
} else {
Integer c = this.convertAmount();
if (c == null) {
@@ -251,50 +230,8 @@ public class CostSacrifice extends CostPartWithList {
return false;
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
this.resetList();
final Player activator = ability.getActivatingPlayer();
if (this.payCostFromSource()) {
this.getList().add(source);
} else if (this.getAmount().equals("All")) {
/*List<Card> typeList = new ArrayList<Card>(activator.getCardsIn(ZoneType.Battlefield));
typeList = CardLists.getValidCards(typeList, this.getType().split(";"), activator, source);
if (activator.hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) {
typeList = CardLists.getNotType(typeList, "Creature");
}*/
// Does the AI want to use Sacrifice All?
return false;
} else {
Integer c = this.convertAmount();
if (c == null) {
if (ability.getSVar(this.getAmount()).equals("XChoice")) {
return false;
}
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
this.setList(ComputerUtil.chooseSacrificeType(activator, this.getType(), source, ability.getTargetCard(), c));
if (this.getList() == null) {
return false;
}
}
return true;
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard) {
this.addToList(targetCard);
protected void doPayment(SpellAbility ability, Card targetCard) {
ability.getActivatingPlayer().getGame().getAction().sacrifice(targetCard, ability);
}
@@ -306,6 +243,37 @@ public class CostSacrifice extends CostPartWithList {
return "Sacrificed";
}
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
if (this.payCostFromSource()) {
return new PaymentDecision(source);
}
if (this.getAmount().equals("All")) {
/*List<Card> typeList = new ArrayList<Card>(activator.getCardsIn(ZoneType.Battlefield));
typeList = CardLists.getValidCards(typeList, this.getType().split(";"), activator, source);
if (activator.hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) {
typeList = CardLists.getNotType(typeList, "Creature");
}*/
// Does the AI want to use Sacrifice All?
return null;
}
Integer c = this.convertAmount();
if (c == null) {
if (ability.getSVar(this.getAmount()).equals("XChoice")) {
return null;
}
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
}
List<Card> list = ComputerUtil.chooseSacrificeType(ai, this.getType(), source, ability.getTargetCard(), c);
return new PaymentDecision(list);
}
// Inputs
}

View File

@@ -74,14 +74,11 @@ public class CostTap extends CostPart {
return source.isUntapped() && (!source.isSick() || source.hasKeyword("CARDNAME may activate abilities as though it has haste."));
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPart#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
public void payAI(PaymentDecision decision, AIPlayer ai, SpellAbility ability, Card source) {
source.tap();
}
@@ -102,15 +99,11 @@ public class CostTap extends CostPart {
return true;
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
return true;
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
return new PaymentDecision(0);
}
}

View File

@@ -100,6 +100,8 @@ public class CostTapType extends CostPartWithList {
}
}
private final boolean canTapSource;
/**
* Instantiates a new cost tap type.
*
@@ -110,8 +112,9 @@ public class CostTapType extends CostPartWithList {
* @param description
* the description
*/
public CostTapType(final String amount, final String type, final String description) {
public CostTapType(final String amount, final String type, final String description, boolean costHasTapSource) {
super(amount, type, description);
canTapSource = !costHasTapSource;
}
@Override
@@ -187,19 +190,6 @@ public class CostTapType extends CostPartWithList {
return true;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
for (final Card c : this.getList()) {
c.tap();
}
}
/*
* (non-Javadoc)
*
@@ -229,16 +219,11 @@ public class CostTapType extends CostPartWithList {
return inp.isPaid();
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
final boolean tap = payment.getCost().hasTapCost();
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
final String amount = this.getAmount();
Integer c = this.convertAmount();
if (c == null) {
@@ -254,22 +239,22 @@ public class CostTapType extends CostPartWithList {
}
}
this.setList(ComputerUtil.chooseTapType(ai, this.getType(), source, tap, c));
List<Card> totap = ComputerUtil.chooseTapType(ai, this.getType(), source, !canTapSource, c);
if (this.getList() == null) {
if (totap == null) {
System.out.println("Couldn't find a valid card to tap for: " + source.getName());
return false;
return null;
}
return true;
return new PaymentDecision(totap);
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard) {
addToList(targetCard);
protected void doPayment(SpellAbility ability, Card targetCard) {
targetCard.tap();
}

View File

@@ -86,26 +86,6 @@ public class CostUnattach extends CostPartWithList {
return false;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
Card cardToUnattach = findCardToUnattach(source, (Player) ai, ability);
if (cardToUnattach == null) {
// We really shouldn't be able to get here if there's nothing to unattach
return;
}
Card equippingCard = cardToUnattach.getEquipping().get(0);
cardToUnattach.unEquipCard(equippingCard);
this.addToList(cardToUnattach);
this.reportPaidCardsTo(ability);
}
/*
* (non-Javadoc)
*
@@ -146,30 +126,29 @@ public class CostUnattach extends CostPartWithList {
return null;
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
this.resetList();
return true;
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard) {
protected void doPayment(SpellAbility ability, Card targetCard) {
targetCard.unEquipCard(targetCard.getEquipping().get(0));
this.addToList(targetCard);
}
@Override
public String getHashForList() {
return "Unattached";
}
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
Card cardToUnattach = findCardToUnattach(source, (Player) ai, ability);
if (cardToUnattach == null) {
// We really shouldn't be able to get here if there's nothing to unattach
return null;
}
return new PaymentDecision(cardToUnattach.getEquippingCard());
}
}

View File

@@ -73,17 +73,6 @@ public class CostUntap extends CostPart {
return source.isTapped() && (!source.isSick() || source.hasKeyword("CARDNAME may activate abilities as though it has haste."));
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
source.untap();
}
/*
* (non-Javadoc)
*
@@ -101,15 +90,19 @@ public class CostUntap extends CostPart {
return true;
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
return true;
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
return new PaymentDecision(0);
}
/* (non-Javadoc)
* @see forge.card.cost.CostPart#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void payAI(PaymentDecision decision, AIPlayer ai, SpellAbility ability, Card source) {
source.untap();
}
}

View File

@@ -49,6 +49,7 @@ public class CostUntapType extends CostPartWithList {
private final CostUntapType untapType;
private static final long serialVersionUID = -7151144318287088542L;
private int nUntapped = 0;
private final SpellAbility sa;
/**
@@ -56,13 +57,15 @@ public class CostUntapType extends CostPartWithList {
* @param nCards
* @param cardList
* @param untapType
* @param ability
* @param sa
* @param payment
*/
public InputPayCostUntapY(int nCards, List<Card> cardList, CostUntapType untapType) {
public InputPayCostUntapY(int nCards, List<Card> cardList, CostUntapType untapType, SpellAbility ability) {
this.nCards = nCards;
this.cardList = cardList;
this.untapType = untapType;
this.sa = ability;
}
@Override
@@ -81,14 +84,12 @@ public class CostUntapType extends CostPartWithList {
}
@Override
public void selectCard(final Card card) {
Zone zone = Singletons.getModel().getGame().getZoneOf(card);
if (zone.is(ZoneType.Battlefield) && cardList.contains(card) && card.isTapped()) {
// send in List<Card> for Typing
card.untap();
untapType.addToList(card);
untapType.executePayment(sa, card);
cardList.remove(card);
this.nUntapped++;
@@ -154,17 +155,6 @@ public class CostUntapType extends CostPartWithList {
return sb.toString();
}
/**
* Adds the card to untapped list.
*
* @param c
* the card
*/
public final void addToUntappedList(final Card c) {
this.getList().add(c);
}
/*
* (non-Javadoc)
*
@@ -205,19 +195,6 @@ public class CostUntapType extends CostPartWithList {
return true;
}
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility,
* forge.Card, forge.card.cost.Cost_Payment)
*/
@Override
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
for (final Card c : this.getList()) {
c.untap();
}
}
/*
* (non-Javadoc)
*
@@ -246,21 +223,33 @@ public class CostUntapType extends CostPartWithList {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
InputPayment inp = new InputPayCostUntapY(c, typeList, this);
InputPayment inp = new InputPayCostUntapY(c, typeList, this, ability);
FThreads.setInputAndWait(inp);
return inp.isPaid();
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility
* , forge.Card, forge.card.cost.Cost_Payment)
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) {
final boolean untap = payment.getCost().hasUntapCost();
protected void doPayment(SpellAbility ability, Card targetCard) {
targetCard.untap();
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList()
*/
@Override
public String getHashForList() {
return "Untapped";
}
/* (non-Javadoc)
* @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public PaymentDecision decideAIPayment(AIPlayer ai, SpellAbility ability, Card source) {
boolean untap = false; // payment.getCost().hasUntapCost();
final String amount = this.getAmount();
Integer c = this.convertAmount();
if (c == null) {
@@ -279,31 +268,14 @@ public class CostUntapType extends CostPartWithList {
}
}
this.setList(ComputerUtil.chooseUntapType(ai, this.getType(), source, untap, c));
List<Card> list = ComputerUtil.chooseUntapType(ai, this.getType(), source, untap, c);
if (this.getList() == null) {
if (list == null) {
System.out.println("Couldn't find a valid card to untap for: " + source.getName());
return false;
return null;
}
return true;
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/
@Override
public void executePayment(SpellAbility ability, Card targetCard) {
addToList(targetCard);
targetCard.untap();
}
/* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList()
*/
@Override
public String getHashForList() {
return "Untapped";
return new PaymentDecision(list);
}
// Inputs

View File

@@ -0,0 +1,35 @@
package forge.card.cost;
import java.util.ArrayList;
import java.util.List;
import forge.Card;
/**
* TODO: Write javadoc for this type.
*
*/
public class PaymentDecision {
public int c = 0;
public final List<Card> cards = new ArrayList<Card>();
public PaymentDecision(int cnt) {
c = cnt;
}
public PaymentDecision(List<Card> chosen) {
cards.addAll(chosen);
}
public PaymentDecision(Card chosen) {
cards.add(chosen);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("Payment Decision: %d, %s", c, cards);
}
}

View File

@@ -28,9 +28,13 @@ import forge.CardLists;
import forge.CardPredicates;
import forge.CardPredicates.Presets;
import forge.CounterType;
import forge.FThreads;
import forge.GameEntity;
import forge.Singletons;
import forge.control.input.InputBase;
import forge.control.input.InputSelectCards;
import forge.control.input.InputSelectCardsFromList;
import forge.control.input.InputSyncronizedBase;
import forge.game.GameState;
import forge.game.ai.ComputerUtilCard;
import forge.game.player.Player;
@@ -106,20 +110,28 @@ public class Untap extends Phase {
return true;
}
public static final Predicate<Card> CANUNTAP = new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return Untap.canUntap(c);
}
};
/**
* <p>
* doUntap.
* </p>
*/
private void doUntap() {
final Player player = Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn();
final Predicate<Card> tappedCanUntap = Predicates.and(Presets.TAPPED, Presets.CANUNTAP);
final Player player = game.getPhaseHandler().getPlayerTurn();
final Predicate<Card> tappedCanUntap = Predicates.and(Presets.TAPPED, CANUNTAP);
List<Card> list = new ArrayList<Card>(player.getCardsIn(ZoneType.Battlefield));
List<Card> bounceList = CardLists.getKeyword(list, "During your next untap step, as you untap your permanents, return CARDNAME to its owner's hand.");
for (final Card c : bounceList) {
Singletons.getModel().getGame().getAction().moveToHand(c);
game.getAction().moveToHand(c);
}
list = CardLists.filter(list, new Predicate<Card>() {
@@ -128,16 +140,13 @@ public class Untap extends Phase {
if (!Untap.canUntap(c)) {
return false;
}
if (Untap.canOnlyUntapOneLand() && c.isLand()) {
if (canOnlyUntapOneLand() && c.isLand()) {
return false;
}
if (c.isArtifact()
&& (Singletons.getModel().getGame().isCardInPlay("Damping Field") || Singletons.getModel().getGame().isCardInPlay("Imi Statue"))) {
if (c.isArtifact() && (game.isCardInPlay("Damping Field") || game.isCardInPlay("Imi Statue"))) {
return false;
}
if (c.isCreature()
&& (Singletons.getModel().getGame().isCardInPlay("Smoke") || Singletons.getModel().getGame().isCardInPlay("Stoic Angel")
|| Singletons.getModel().getGame().isCardInPlay("Intruder Alarm"))) {
if (c.isCreature() && (game.isCardInPlay("Smoke") || game.isCardInPlay("Stoic Angel") || game.isCardInPlay("Intruder Alarm"))) {
return false;
}
return true;
@@ -181,7 +190,7 @@ public class Untap extends Phase {
}
}
}
} else if ((c.getCounters(CounterType.WIND) > 0) && Singletons.getModel().getGame().isCardInPlay("Freyalise's Winds")) {
} else if ((c.getCounters(CounterType.WIND) > 0) && game.isCardInPlay("Freyalise's Winds")) {
// remove a WIND counter instead of untapping
c.subtractCounter(CounterType.WIND, 1);
} else {
@@ -190,7 +199,7 @@ public class Untap extends Phase {
}
// other players untapping during your untap phase
final List<Card> cardsWithKW = CardLists.getKeyword(Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield),
final List<Card> cardsWithKW = CardLists.getKeyword(game.getCardsIn(ZoneType.Battlefield),
"CARDNAME untaps during each other player's untap step.");
final List<Player> otherPlayers = player.getOpponents();
otherPlayers.addAll(player.getAllies());
@@ -200,123 +209,49 @@ public class Untap extends Phase {
}
// end other players untapping during your untap phase
if (Untap.canOnlyUntapOneLand()) {
if (canOnlyUntapOneLand()) {
final List<Card> landList = CardLists.filter(player.getLandsInPlay(), tappedCanUntap);
if (!landList.isEmpty()) {
if (player.isComputer()) {
// search for lands the computer has and only untap 1
List<Card> landList = player.getLandsInPlay();
landList = CardLists.filter(landList, tappedCanUntap);
if (landList.size() > 0) {
landList.get(0).untap();
}
} else {
final InputBase target = new InputBase() {
private static final long serialVersionUID = 6653677835629939465L;
final InputSelectCards target = new InputSelectCardsFromList(1,1, landList);
target.setMessage("Select one tapped land to untap");
FThreads.setInputAndWait(target);
if( !target.hasCancelled() && !target.getSelected().isEmpty())
target.getSelected().get(0).untap();
}
}
}
if (game.isCardInPlay("Damping Field") || game.isCardInPlay("Imi Statue")) {
final Player turnOwner = game.getPhaseHandler().getPlayerTurn();
final List<Card> artList = CardLists.filter(turnOwner.getCardsIn(ZoneType.Battlefield), Presets.ARTIFACTS, tappedCanUntap);
@Override
public void showMessage() {
CMatchUI.SINGLETON_INSTANCE.showMessage("Select one tapped land to untap");
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
this.stop();
}
@Override
public void selectCard(final Card c) {
Zone zone = Singletons.getModel().getGame().getZoneOf(c);
if (c.isLand() && zone.is(ZoneType.Battlefield) && c.isTapped() && Untap.canUntap(c)) {
c.untap();
this.stop();
}
} // selectCard()
}; // Input
List<Card> landList = player.getLandsInPlay();
landList = CardLists.filter(landList, tappedCanUntap);
if (landList.size() > 0) {
Singletons.getModel().getMatch().getInput().setInput(target);
}
}
}
if (Singletons.getModel().getGame().isCardInPlay("Damping Field") || Singletons.getModel().getGame().isCardInPlay("Imi Statue")) {
final Player turnOwner = Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn();
if (!artList.isEmpty()) {
if (turnOwner.isComputer()) {
List<Card> artList = new ArrayList<Card>(turnOwner.getCardsIn(ZoneType.Battlefield));
artList = CardLists.filter(artList, Presets.ARTIFACTS);
artList = CardLists.filter(artList, tappedCanUntap);
if (artList.size() > 0) {
ComputerUtilCard.getBestArtifactAI(artList).untap();
}
} else {
final InputBase target = new InputBase() {
private static final long serialVersionUID = 5555427219659889707L;
@Override
public void showMessage() {
CMatchUI.SINGLETON_INSTANCE.showMessage("Select one tapped artifact to untap");
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
this.stop();
}
@Override
public void selectCard(final Card c) {
Zone zone = Singletons.getModel().getGame().getZoneOf(c);
if (c.isArtifact() && zone.is(ZoneType.Battlefield) && c.getController().isHuman()
&& Untap.canUntap(c)) {
c.untap();
this.stop();
}
} // selectCard()
}; // Input
List<Card> artList = new ArrayList<Card>(turnOwner.getCardsIn(ZoneType.Battlefield));
artList = CardLists.filter(artList, Presets.ARTIFACTS);
artList = CardLists.filter(artList, tappedCanUntap);
if (artList.size() > 0) {
Singletons.getModel().getMatch().getInput().setInput(target);
final InputSelectCards target = new InputSelectCardsFromList(1,1, artList);
target.setMessage("Select one tapped artifact to untap");
FThreads.setInputAndWait(target);
if( !target.hasCancelled() && !target.getSelected().isEmpty())
target.getSelected().get(0).untap();
}
}
}
if ((Singletons.getModel().getGame().isCardInPlay("Smoke") || Singletons.getModel().getGame().isCardInPlay("Stoic Angel"))) {
if (player.isComputer()) {
List<Card> creatures = player.getCreaturesInPlay();
creatures = CardLists.filter(creatures, tappedCanUntap);
if (creatures.size() > 0) {
creatures.get(0).untap();
}
} else {
final InputBase target = new InputBase() {
private static final long serialVersionUID = 5555427219659889707L;
@Override
public void showMessage() {
CMatchUI.SINGLETON_INSTANCE.showMessage("Select one creature to untap");
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
this.stop();
}
@Override
public void selectCard(final Card c) {
Zone zone = Singletons.getModel().getGame().getZoneOf(c);
if (c.isCreature() && zone.is(ZoneType.Battlefield) && c.getController().isHuman()
&& Untap.canUntap(c)) {
c.untap();
this.stop();
}
} // selectCard()
}; // Input
if ((game.isCardInPlay("Smoke") || game.isCardInPlay("Stoic Angel"))) {
final List<Card> creatures = CardLists.filter(player.getCreaturesInPlay(), tappedCanUntap);
if (creatures.size() > 0) {
Singletons.getModel().getMatch().getInput().setInput(target);
if (!creatures.isEmpty()) {
if (player.isComputer()) {
creatures.get(0).untap();
} else {
final InputSelectCards target = new InputSelectCardsFromList(1, 1, creatures);
target.setMessage("Select one creature to untap");
FThreads.setInputAndWait(target);
if( !target.hasCancelled() && !target.getSelected().isEmpty())
target.getSelected().get(0).untap();
}
}
}
@@ -334,11 +269,10 @@ public class Untap extends Phase {
game.getStack().chooseOrderOfSimultaneousStackEntryAll();
} // end doUntap
private static boolean canOnlyUntapOneLand() {
private boolean canOnlyUntapOneLand() {
// Winter Orb was given errata so it no longer matters if it's tapped or
// not
if (Singletons.getModel().getGame().isCardInPlay("Winter Orb")
|| Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().isCardInPlay("Mungha Wurm")) {
if (game.isCardInPlay("Winter Orb") || game.getPhaseHandler().getPlayerTurn().isCardInPlay("Mungha Wurm")) {
return true;
}

View File

@@ -19,6 +19,7 @@ package forge.gui;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.atomic.AtomicReference;
import forge.Card;
import forge.FThreads;
@@ -39,7 +40,7 @@ import forge.game.player.Player;
public class InputProxy implements Observer {
/** The input. */
private Input input;
private AtomicReference<Input> input = new AtomicReference<Input>();
private MatchController match = null;
public void setMatch(MatchController matchController) {
@@ -48,7 +49,7 @@ public class InputProxy implements Observer {
@Override
public final synchronized void update(final Observable observable, final Object obj) {
this.input = null;
this.input.set(null);
final GameState game = match.getCurrentGame();
final PhaseHandler ph = game.getPhaseHandler();
@@ -68,7 +69,7 @@ public class InputProxy implements Observer {
//System.out.printf(" input is %s \t stack = %s%n", nextInput == null ? "null" : nextInput.getClass().getSimpleName(), match.getInput().printInputStack());
if (nextInput != null) {
this.input = nextInput;
this.input.set(nextInput);
FThreads.invokeInEDT(new Runnable() { @Override public void run() { nextInput.showMessage(); } });
} else if (!ph.isPlayerPriorityAllowed()) {
ph.getPriorityPlayer().getController().passPriority();
@@ -80,8 +81,9 @@ public class InputProxy implements Observer {
* </p>
*/
public final void selectButtonOK() {
if ( null == input ) return;
input.selectButtonOK();
Input inp = getInput();
if ( null != inp )
inp.selectButtonOK();
}
/**
@@ -90,8 +92,9 @@ public class InputProxy implements Observer {
* </p>
*/
public final void selectButtonCancel() {
if ( null == input ) return;
input.selectButtonCancel();
Input inp = getInput();
if ( null != inp )
inp.selectButtonCancel();
}
/**
@@ -103,8 +106,9 @@ public class InputProxy implements Observer {
* a {@link forge.game.player.Player} object.
*/
public final void selectPlayer(final Player player) {
if ( null == input ) return;
input.selectPlayer(player);
Input inp = getInput();
if ( null != inp )
inp.selectPlayer(player);
}
/**
@@ -118,19 +122,20 @@ public class InputProxy implements Observer {
* a {@link forge.game.zone.PlayerZone} object.
*/
public final void selectCard(final Card card) {
if ( null == input ) return;
input.selectCard(card);
Input inp = getInput();
if ( null != inp )
inp.selectCard(card);
}
/** {@inheritDoc} */
@Override
public final String toString() {
if ( null == input ) return "(null)";
return this.input.toString();
Input inp = getInput();
return null == inp ? "(null)" : inp.toString();
}
/** @return {@link forge.gui.InputProxy.InputBase} */
public Input getInput() {
return this.input;
return this.input.get();
}
}