GameAction.payCostDuringAbilityResolve now returns a boolean indicating whether the cost was paid,

all the paid/unpaid commands eliminated, since the code may be executed right after payCostDuringAbilityResolve under if's branches
This commit is contained in:
Maxmtg
2013-03-25 19:47:10 +00:00
parent a82abd077c
commit 19a1a7b173
5 changed files with 58 additions and 170 deletions

View File

@@ -10,7 +10,6 @@ import org.apache.commons.lang3.StringUtils;
import forge.Card; import forge.Card;
import forge.CardLists; import forge.CardLists;
import forge.CardUtil; import forge.CardUtil;
import forge.Command;
import forge.Constant; import forge.Constant;
import forge.CounterType; import forge.CounterType;
import forge.Singletons; import forge.Singletons;
@@ -1036,6 +1035,19 @@ public class AbilityUtils {
AbilityUtils.resolveApiAbility(abSub, usedStack, game); AbilityUtils.resolveApiAbility(abSub, usedStack, game);
} }
private static void resolveApiAbility(final SpellAbility sa, boolean usedStack, final GameState game) {
// check conditions
if (sa.getConditions().areMet(sa)) {
if (sa.isWrapper() || StringUtils.isBlank(sa.getParam("UnlessCost"))) {
sa.resolve();
} else {
handleUnlessCost(sa, usedStack, game);
return;
}
}
resolveSubAbilities(sa, usedStack, game);
}
private static void handleUnlessCost(final SpellAbility sa, final boolean usedStack, final GameState game) { private static void handleUnlessCost(final SpellAbility sa, final boolean usedStack, final GameState game) {
final Card source = sa.getSourceCard(); final Card source = sa.getSourceCard();
String unlessCost = sa.getParam("UnlessCost"); String unlessCost = sa.getParam("UnlessCost");
@@ -1047,6 +1059,7 @@ public class AbilityUtils {
final String resolveSubs = sa.getParam("UnlessResolveSubs"); // no value means 'Always' final String resolveSubs = sa.getParam("UnlessResolveSubs"); // no value means 'Always'
final boolean execSubsWhenPaid = "WhenPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs); final boolean execSubsWhenPaid = "WhenPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs);
final boolean execSubsWhenNotPaid = "WhenNotPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs); final boolean execSubsWhenNotPaid = "WhenNotPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs);
final boolean isSwitched = sa.hasParam("UnlessSwitched");
// The cost // The cost
if (unlessCost.equals("CardManaCost")) { if (unlessCost.equals("CardManaCost")) {
@@ -1070,43 +1083,6 @@ public class AbilityUtils {
//instead of just X for cards like Draco. //instead of just X for cards like Draco.
} }
final boolean isSwitched = sa.hasParam("UnlessSwitched");
Command paidCommand = new Command() {
private static final long serialVersionUID = 8094833091127334678L;
@Override
public void execute() {
if (isSwitched && execSubsWhenNotPaid || execSubsWhenPaid) {
resolveSubAbilities(sa, usedStack, game);
} else if (usedStack) {
SpellAbility root = sa.getRootAbility();
game.getStack().finishResolving(root, false);
}
}
};
Command unpaidCommand = new Command() {
private static final long serialVersionUID = 8094833091127334678L;
@Override
public void execute() {
sa.resolve();
if (isSwitched && execSubsWhenPaid || execSubsWhenNotPaid) {
resolveSubAbilities(sa, usedStack, game);
} else if (usedStack) {
SpellAbility root = sa.getRootAbility();
game.getStack().finishResolving(root, false);
}
}
};
if (isSwitched) {
final Command dummy = paidCommand;
paidCommand = unpaidCommand;
unpaidCommand = dummy;
}
final Cost cost = new Cost(source, unlessCost, true); final Cost cost = new Cost(source, unlessCost, true);
final Ability ability = new AbilityStatic(source, cost, null) { final Ability ability = new AbilityStatic(source, cost, null) {
@Override @Override
@@ -1117,34 +1093,35 @@ public class AbilityUtils {
boolean paid = false; boolean paid = false;
for (Player payer : payers) { for (Player payer : payers) {
if (payer.isComputer()) {
ability.setActivatingPlayer(payer); ability.setActivatingPlayer(payer);
if (AbilityUtils.willAIPayForAbility(sa, payer, ability, paid, payers)) {
ability.setTarget(sa.getTarget()); ability.setTarget(sa.getTarget());
if (payer.isComputer()) {
if (AbilityUtils.willAIPayForAbility(sa, payer, ability, paid, payers)) {
ComputerUtil.playNoStack((AIPlayer) payer, ability, game); // Unless cost was payed - no resolve ComputerUtil.playNoStack((AIPlayer) payer, ability, game); // Unless cost was payed - no resolve
paid = true; paid = true;
} }
} } else {
}
boolean waitForInput = false;
for (Player payer : payers) {
if (payer.isHuman()) {
// if it's paid by the AI already the human can pay, but it won't change anything // if it's paid by the AI already the human can pay, but it won't change anything
if (paid) { paid = GameActionUtil.payCostDuringAbilityResolve(payer, ability, cost, sa, game);
unpaidCommand = paidCommand;
} }
ability.setActivatingPlayer(payer);
ability.setTarget(sa.getTarget());
GameActionUtil.payCostDuringAbilityResolve(payer, ability, cost, paidCommand, unpaidCommand, sa, game);
waitForInput = true; // wait for the human input
break; // multiple human players are not supported
}
}
if (!waitForInput) {
Command toExecute = paid ? paidCommand : unpaidCommand;
toExecute.execute();
} }
if ( paid ^ isSwitched ) {
if (isSwitched && execSubsWhenNotPaid || execSubsWhenPaid) {
resolveSubAbilities(sa, usedStack, game);
} else if (usedStack) {
SpellAbility root = sa.getRootAbility();
game.getStack().finishResolving(root, false);
}
} else {
sa.resolve();
if (isSwitched && execSubsWhenPaid || execSubsWhenNotPaid) {
resolveSubAbilities(sa, usedStack, game);
} else if (usedStack) {
SpellAbility root = sa.getRootAbility();
game.getStack().finishResolving(root, false);
}
}
} }
/** /**
@@ -1221,19 +1198,6 @@ public class AbilityUtils {
return false; return false;
} }
private static void resolveApiAbility(final SpellAbility sa, boolean usedStack, final GameState game) {
// check conditions
if (sa.getConditions().areMet(sa)) {
if (sa.isWrapper() || StringUtils.isBlank(sa.getParam("UnlessCost"))) {
sa.resolve();
} else {
handleUnlessCost(sa, usedStack, game);
return;
}
}
resolveSubAbilities(sa, usedStack, game);
}
/** /**
* <p> * <p>
* Parse non-mana X variables. * Parse non-mana X variables.

View File

@@ -486,24 +486,6 @@ public class GameAction {
final String recoverCost = recoverable.getKeyword().get(recoverable.getKeywordPosition("Recover")).split(":")[1]; final String recoverCost = recoverable.getKeyword().get(recoverable.getKeywordPosition("Recover")).split(":")[1];
final Cost cost = new Cost(recoverable, recoverCost, true); final Cost cost = new Cost(recoverable, recoverCost, true);
final Command paidCommand = new Command() {
private static final long serialVersionUID = -6357156873861051845L;
@Override
public void execute() {
moveToHand(recoverable);
}
};
final Command unpaidCommand = new Command() {
private static final long serialVersionUID = -7354791599039157375L;
@Override
public void execute() {
exile(recoverable);
}
};
final SpellAbility abRecover = new AbilityActivated(recoverable, cost, null) { final SpellAbility abRecover = new AbilityActivated(recoverable, cost, null) {
private static final long serialVersionUID = 8858061639236920054L; private static final long serialVersionUID = 8858061639236920054L;
@@ -535,8 +517,10 @@ public class GameAction {
Player p = recoverable.getController(); Player p = recoverable.getController();
if (p.isHuman()) { if (p.isHuman()) {
GameActionUtil.payCostDuringAbilityResolve(p, abRecover, abRecover.getPayCosts(), if ( GameActionUtil.payCostDuringAbilityResolve(p, abRecover, abRecover.getPayCosts(), null, game) )
paidCommand, unpaidCommand, null, game); moveToHand(recoverable);
else
exile(recoverable);
} else { // computer } else { // computer
if (ComputerUtilCost.canPayCost(abRecover, p)) { if (ComputerUtilCost.canPayCost(abRecover, p)) {
ComputerUtil.playNoStack((AIPlayer)p, abRecover, game); ComputerUtil.playNoStack((AIPlayer)p, abRecover, game);

View File

@@ -382,8 +382,7 @@ public final class GameActionUtil {
* a {@link forge.Command} object. * a {@link forge.Command} object.
* @param sourceAbility TODO * @param sourceAbility TODO
*/ */
public static void payCostDuringAbilityResolve(final Player p, final SpellAbility ability, final Cost cost, final Command paid, public static boolean payCostDuringAbilityResolve(final Player p, final SpellAbility ability, final Cost cost, SpellAbility sourceAbility, final GameState game) {
final Command unpaid, SpellAbility sourceAbility, final GameState game) {
final Card source = ability.getSourceCard(); final Card source = ability.getSourceCard();
final List<CostPart> parts = cost.getCostParts(); final List<CostPart> parts = cost.getCostParts();
ArrayList<CostPart> remainingParts = new ArrayList<CostPart>(cost.getCostParts()); ArrayList<CostPart> remainingParts = new ArrayList<CostPart>(cost.getCostParts());
@@ -396,13 +395,9 @@ public final class GameActionUtil {
orString = " (or: " + sourceAbility.getStackDescription() + ")"; orString = " (or: " + sourceAbility.getStackDescription() + ")";
} }
if (parts.isEmpty() || costPart.getAmount().equals("0")) { if (parts.isEmpty() || costPart.getAmount().equals("0")) {
if (GuiDialog.confirm(source, "Do you want to pay 0?" + orString)) { return GuiDialog.confirm(source, "Do you want to pay 0?" + orString);
paid.execute();
} else {
unpaid.execute();
}
return;
} }
boolean hasPaid = true; boolean hasPaid = true;
//the following costs do not need inputs //the following costs do not need inputs
for (CostPart part : parts) { for (CostPart part : parts) {
@@ -591,12 +586,10 @@ public final class GameActionUtil {
GuiUtils.clearPanelSelections(); GuiUtils.clearPanelSelections();
if (!hasPaid) { if (!hasPaid) {
unpaid.execute(); return false;
return;
} }
if (remainingParts.isEmpty()) { if (remainingParts.isEmpty()) {
paid.execute(); return true;
return;
} }
if (remainingParts.size() > 1) { if (remainingParts.size() > 1) {
throw new RuntimeException("GameActionUtil::payCostDuringAbilityResolve - Too many payment types - " + source); throw new RuntimeException("GameActionUtil::payCostDuringAbilityResolve - Too many payment types - " + source);
@@ -609,11 +602,7 @@ public final class GameActionUtil {
InputPayment toSet = new InputPayManaExecuteCommands(game, source + "\r\n", ability.getManaCost()); InputPayment toSet = new InputPayManaExecuteCommands(game, source + "\r\n", ability.getManaCost());
FThreads.setInputAndWait(toSet); FThreads.setInputAndWait(toSet);
if (toSet.isPaid() ) { return toSet.isPaid();
paid.execute();
} else {
unpaid.execute();
}
} }
// not restricted to combat damage, not restricted to dealing damage to // not restricted to combat damage, not restricted to dealing damage to

View File

@@ -1150,39 +1150,13 @@ public class CombatUtil {
} }
}; };
final Command unpaidCommand = new Command() {
private static final long serialVersionUID = -6483405139208343935L;
@Override
public void execute() {
game.getCombat().removeFromCombat(crd);
if (bLast) {
PhaseUtil.handleAttackingTriggers();
}
}
};
final Command paidCommand = new Command() {
private static final long serialVersionUID = -8303368287601871955L;
@Override
public void execute() {
// if Propaganda is paid, tap this card
if (!crd.hasKeyword("Vigilance")) {
crd.tap();
}
if (bLast) {
PhaseUtil.handleAttackingTriggers();
}
}
};
ability.setActivatingPlayer(c.getController()); ability.setActivatingPlayer(c.getController());
if (c.getController().isHuman()) { if (c.getController().isHuman()) {
GameActionUtil.payCostDuringAbilityResolve(c.getController(), ability, attackCost, paidCommand, unpaidCommand, null, game); if ( GameActionUtil.payCostDuringAbilityResolve(c.getController(), ability, attackCost, null, game) ) {
if (!crd.hasKeyword("Vigilance")) { crd.tap(); }
} else {
game.getCombat().removeFromCombat(crd);
}
} else { // computer } else { // computer
if (ComputerUtilCost.canPayCost(ability, c.getController())) { if (ComputerUtilCost.canPayCost(ability, c.getController())) {
ComputerUtil.playNoStack((AIPlayer)c.getController(), ability, game); ComputerUtil.playNoStack((AIPlayer)c.getController(), ability, game);
@@ -1194,12 +1168,11 @@ public class CombatUtil {
// during Declare_Attackers // during Declare_Attackers
game.getCombat().removeFromCombat(crd); game.getCombat().removeFromCombat(crd);
} }
if (bLast) { }
if (bLast)
PhaseUtil.handleAttackingTriggers(); PhaseUtil.handleAttackingTriggers();
} }
} }
}
}
/** /**
* <p> * <p>

View File

@@ -175,18 +175,6 @@ public class Upkeep extends Phase {
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
final Card c = list.get(i); final Card c = list.get(i);
if (c.hasStartOfKeyword("(Echo unpaid)")) { if (c.hasStartOfKeyword("(Echo unpaid)")) {
final Command paidCommand = Command.BLANK;
final Command unpaidCommand = new Command() {
private static final long serialVersionUID = -7354791599039157375L;
@Override
public void execute() {
game.getAction().sacrifice(c, null);
}
};
final Ability blankAbility = Upkeep.BlankAbility(c, c.getEchoCost()); final Ability blankAbility = Upkeep.BlankAbility(c, c.getEchoCost());
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
@@ -199,7 +187,9 @@ public class Upkeep extends Phase {
Player controller = c.getController(); Player controller = c.getController();
if (controller.isHuman()) { if (controller.isHuman()) {
Cost cost = new Cost(c, c.getEchoCost().trim(), true); Cost cost = new Cost(c, c.getEchoCost().trim(), true);
GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, cost, paidCommand, unpaidCommand, null, game); if ( !GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, cost, null, game) )
game.getAction().sacrifice(c, null);;
} else { // computer } else { // computer
if (ComputerUtilCost.canPayCost(blankAbility, controller)) { if (ComputerUtilCost.canPayCost(blankAbility, controller)) {
ComputerUtil.playNoStack((AIPlayer)controller, blankAbility, game); ComputerUtil.playNoStack((AIPlayer)controller, blankAbility, game);
@@ -332,18 +322,6 @@ public class Upkeep extends Phase {
} }
final String upkeepCost = cost; final String upkeepCost = cost;
final Command unpaidCommand = new Command() {
private static final long serialVersionUID = 5612348769167529102L;
@Override
public void execute() {
game.getAction().sacrifice(c, null);
}
};
final Command paidCommand = Command.BLANK;
final Ability blankAbility = Upkeep.BlankAbility(c, upkeepCost); final Ability blankAbility = Upkeep.BlankAbility(c, upkeepCost);
blankAbility.setActivatingPlayer(controller); blankAbility.setActivatingPlayer(controller);
@@ -351,11 +329,11 @@ public class Upkeep extends Phase {
@Override @Override
public void resolve() { public void resolve() {
if (controller.isHuman()) { if (controller.isHuman()) {
GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, blankAbility.getPayCosts(), if ( !GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, blankAbility.getPayCosts(), this, game))
paidCommand, unpaidCommand, this, game); game.getAction().sacrifice(c, null);
} else { // computer } else { // computer
if (ComputerUtilCost.shouldPayCost(controller, c, upkeepCost) && ComputerUtilCost.canPayCost(blankAbility, controller)) { if (ComputerUtilCost.shouldPayCost(controller, c, upkeepCost) && ComputerUtilCost.canPayCost(blankAbility, controller)) {
ComputerUtil.playNoStack((AIPlayer)controller, blankAbility, game); ComputerUtil.playNoStack((AIPlayer)controller, blankAbility, game); // this makes AI pay
} else { } else {
game.getAction().sacrifice(c, null); game.getAction().sacrifice(c, null);
} }