Fixed double extraction of InputPayManaBase inputs, that lead to stack incosistency

This commit is contained in:
Maxmtg
2013-03-26 08:34:06 +00:00
parent 9fc0c5c508
commit 5d3af30b87
9 changed files with 50 additions and 42 deletions

View File

@@ -42,6 +42,8 @@ public class ManaCostBeingPaid {
private final ArrayList<String> manaNeededToAvoidNegativeEffect = new ArrayList<String>(); private final ArrayList<String> manaNeededToAvoidNegativeEffect = new ArrayList<String>();
private final ArrayList<String> manaPaidToAvoidNegativeEffect = new ArrayList<String>(); private final ArrayList<String> manaPaidToAvoidNegativeEffect = new ArrayList<String>();
private final ManaCost originalCost;
// manaCost can be like "0", "3", "G", "GW", "10", "3 GW", "10 GW" // manaCost can be like "0", "3", "G", "GW", "10", "3 GW", "10 GW"
// or "split hybrid mana" like "2/G 2/G", "2/B 2/B 2/B" // or "split hybrid mana" like "2/G 2/G", "2/B 2/B 2/B"
// "GW" can be paid with either G or W // "GW" can be paid with either G or W
@@ -59,6 +61,7 @@ public class ManaCostBeingPaid {
} }
public ManaCostBeingPaid(ManaCost manaCost) { public ManaCostBeingPaid(ManaCost manaCost) {
originalCost = manaCost;
if ( null == manaCost ) if ( null == manaCost )
return; return;
@@ -645,4 +648,8 @@ public class ManaCostBeingPaid {
public final ArrayList<String> getManaPaidToAvoidNegativeEffect() { public final ArrayList<String> getManaPaidToAvoidNegativeEffect() {
return this.manaPaidToAvoidNegativeEffect; return this.manaPaidToAvoidNegativeEffect;
} }
public ManaCost getStartingCost() {
return originalCost;
}
} }

View File

@@ -88,6 +88,14 @@ public class InputControl extends MyObservable implements java.io.Serializable {
*/ */
public final void removeInput(Input inp) { public final void removeInput(Input inp) {
Input topMostInput = inputStack.isEmpty() ? null : inputStack.pop(); Input topMostInput = inputStack.isEmpty() ? null : inputStack.pop();
// StackTraceElement[] trace = Thread.currentThread().getStackTrace();
// System.out.printf("%s > Remove input %s -- called from %s%n", FThreads.isEDT() ? "EDT" : "TRD", topMostInput, trace[2].toString());
// if( trace[2].toString().contains("InputBase.stop"))
// for(StackTraceElement se : trace) {
// System.out.println(se.toString());
// }
if( topMostInput != inp ) if( topMostInput != inp )
throw new RuntimeException("Inputs adding/removal into stack is imbalanced! Check your code again!"); throw new RuntimeException("Inputs adding/removal into stack is imbalanced! Check your code again!");

View File

@@ -9,7 +9,6 @@ import java.util.Map;
import forge.Card; import forge.Card;
import forge.CardUtil; import forge.CardUtil;
import forge.Constant; import forge.Constant;
import forge.FThreads;
import forge.Singletons; import forge.Singletons;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.ability.ApiType; import forge.card.ability.ApiType;
@@ -129,7 +128,7 @@ public abstract class InputPayManaBase extends InputSyncronizedBase implements I
this.manaCost = mp.payManaFromPool(saPaidFor, manaCost, manaStr); this.manaCost = mp.payManaFromPool(saPaidFor, manaCost, manaStr);
onManaAbilityPlayed(saPaidFor.getActivatingPlayer(), null); onManaAbilityPlayed(null);
} }
/** /**
@@ -299,28 +298,30 @@ public abstract class InputPayManaBase extends InputSyncronizedBase implements I
// save off color needed for use by any mana and reflected mana // save off color needed for use by any mana and reflected mana
subchosen.getManaPart().setExpressChoice(colorsNeeded); subchosen.getManaPart().setExpressChoice(colorsNeeded);
final SpellAbility finallyChosen = chosen;
// System.out.println("Chosen sa=" + chosen + " of " + chosen.getSourceCard() + " to pay mana"); // System.out.println("Chosen sa=" + chosen + " of " + chosen.getSourceCard() + " to pay mana");
Player p = chosen.getActivatingPlayer(); Player p = chosen.getActivatingPlayer();
p.getGame().getActionPlay().playManaAbilityAsPayment(chosen, p, this); p.getGame().getActionPlay().playManaAbilityAsPayment(finallyChosen, p, new Runnable( ) {
} @Override public void run() {
onManaAbilityPlayed(finallyChosen);
public void onManaAbilityPlayed(final Player p, final SpellAbility saPaymentSrc) {
if ( saPaymentSrc != null) // null comes when they've paid from pool
this.manaCost = p.getManaPool().payManaFromAbility(saPaidFor, manaCost, saPaymentSrc);
onManaAbilityPaid();
FThreads.invokeInEDT(new Runnable( ) {
@Override
public void run() {
if (manaCost.isPaid()) {
bPaid = true;
done();
} else if (Singletons.getModel().getMatch().getInput().getInput() == InputPayManaBase.this) {
showMessage();
}
} }
}); });
// EDT that removes lockUI from stack will call our showMessage() method
}
public void onManaAbilityPlayed(final SpellAbility saPaymentSrc) {
if ( saPaymentSrc != null) // null comes when they've paid from pool
this.manaCost = whoPays.getManaPool().payManaFromAbility(saPaidFor, manaCost, saPaymentSrc);
onManaAbilityPaid();
}
protected final void checkIfAlredyPaid() {
if (manaCost.isPaid()) {
bPaid = true;
done();
}
} }
protected void onManaAbilityPaid() {} // some inputs overload it protected void onManaAbilityPaid() {} // some inputs overload it
@@ -328,7 +329,7 @@ public abstract class InputPayManaBase extends InputSyncronizedBase implements I
@Override @Override
public String toString() { public String toString() {
return "PayManaBase (" + manaCost.toString() + ")"; return String.format("PayManaBase %s (out of %s)", manaCost.toString(), manaCost.getStartingCost() );
} }
protected void handleConvokedCards(boolean isCancelled) { protected void handleConvokedCards(boolean isCancelled) {

View File

@@ -23,7 +23,6 @@ import forge.card.mana.ManaCostBeingPaid;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.game.GameState; import forge.game.GameState;
import forge.game.player.Player; import forge.game.player.Player;
import forge.gui.match.CMatchUI;
import forge.view.ButtonUtil; import forge.view.ButtonUtil;
//if cost is paid, Command.execute() is called //if cost is paid, Command.execute() is called
@@ -174,6 +173,7 @@ public class InputPayManaExecuteCommands extends InputPayManaBase implements Inp
msg.append("\n(Click on your life total to pay life for phyrexian mana.)"); msg.append("\n(Click on your life total to pay life for phyrexian mana.)");
} }
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); showMessage(msg.toString());
checkIfAlredyPaid();
} }
} }

View File

@@ -72,9 +72,6 @@ public class InputPayManaOfCostPayment extends InputPayManaBase {
} }
showMessage(msg.toString()); showMessage(msg.toString());
if (manaCost.isPaid()) { checkIfAlredyPaid();
bPaid = true;
this.done();
}
} }
} }

View File

@@ -23,7 +23,6 @@ import forge.card.spellability.SpellAbility;
import forge.game.GameState; import forge.game.GameState;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.match.CMatchUI;
import forge.view.ButtonUtil; import forge.view.ButtonUtil;
//pays the cost of a card played from the player's hand //pays the cost of a card played from the player's hand
@@ -133,7 +132,8 @@ public class InputPayManaSimple extends InputPayManaBase {
msg.append("\n(Click on your life total to pay life for phyrexian mana.)"); msg.append("\n(Click on your life total to pay life for phyrexian mana.)");
} }
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); // has its own variant of checkIfPaid
showMessage(msg.toString());
if (this.manaCost.isPaid() && !new ManaCostBeingPaid(this.originalManaCost).isPaid()) { if (this.manaCost.isPaid() && !new ManaCostBeingPaid(this.originalManaCost).isPaid()) {
this.originalCard.setSunburstValue(this.manaCost.getSunburst()); this.originalCard.setSunburstValue(this.manaCost.getSunburst());
this.done(); this.done();

View File

@@ -5,7 +5,6 @@ import forge.card.cost.CostPartMana;
import forge.card.mana.ManaCostBeingPaid; import forge.card.mana.ManaCostBeingPaid;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.game.GameState; import forge.game.GameState;
import forge.gui.match.CMatchUI;
import forge.view.ButtonUtil; import forge.view.ButtonUtil;
public class InputPayManaX extends InputPayManaBase { public class InputPayManaX extends InputPayManaBase {
@@ -34,18 +33,15 @@ public class InputPayManaX extends InputPayManaBase {
*/ */
@Override @Override
public boolean isPaid() { public boolean isPaid() {
// only cancel if partially paid an X value
// or X is 0, and x can't be 0
//return !( xPaid == 0 && !costMana.canXbe0() || this.colorX.equals("") && !this.manaCost.toString().equals(strX) ); //return !( xPaid == 0 && !costMana.canXbe0() || this.colorX.equals("") && !this.manaCost.toString().equals(strX) );
// return !( xPaid == 0 && !costMana.canXbe0()) && !(this.colorX.equals("") && !this.manaCost.toString().equals(strX)); // return !( xPaid == 0 && !costMana.canXbe0()) && !(this.colorX.equals("") && !this.manaCost.toString().equals(strX));
return ( xPaid > 0 || costMana.canXbe0()) && (!this.colorX.equals("") || this.manaCost.toString().equals(strX)); return ( xPaid > 0 || costMana.canXbe0()) && (!this.colorX.equals("") || this.manaCost.toString().equals(strX));
} }
@Override @Override
public void showMessage() { public void showMessage() {
// only cancel if partially paid an X value
// or X is 0, and x can't be 0
if (!isPaid()) { if (!isPaid()) {
ButtonUtil.enableOnlyCancel(); ButtonUtil.enableOnlyCancel();
} else { } else {
@@ -59,7 +55,7 @@ public class InputPayManaX extends InputPayManaBase {
msg.append(" X Can't be 0."); msg.append(" X Can't be 0.");
} }
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); showMessage(msg.toString());
} }
// selectCard // selectCard

View File

@@ -23,7 +23,6 @@ import forge.card.spellability.SpellAbilityRequirements;
import forge.card.spellability.Target; import forge.card.spellability.Target;
import forge.card.spellability.TargetSelection; import forge.card.spellability.TargetSelection;
import forge.card.staticability.StaticAbility; import forge.card.staticability.StaticAbility;
import forge.control.input.InputPayManaBase;
import forge.control.input.InputPayManaSimple; import forge.control.input.InputPayManaSimple;
import forge.game.ai.ComputerUtilCard; import forge.game.ai.ComputerUtilCard;
import forge.game.player.Player; import forge.game.player.Player;
@@ -518,12 +517,12 @@ public class GameActionPlay {
* @param manaCost * @param manaCost
* @param saPaidFor * @param saPaidFor
*/ */
public void playManaAbilityAsPayment(final SpellAbility chosen, final Player p, final InputPayManaBase inputPayManaBase) { public void playManaAbilityAsPayment(final SpellAbility chosen, final Player p, final Runnable beforeUnlock) {;
Runnable proc = new Runnable() { Runnable proc = new Runnable() {
@Override @Override
public void run() { public void run() {
p.getGame().getActionPlay().playSpellAbility(chosen, p); playSpellAbility(chosen, p);
inputPayManaBase.onManaAbilityPlayed(p, chosen); beforeUnlock.run();
} }
}; };
FThreads.invokeInNewThread(proc, true); FThreads.invokeInNewThread(proc, true);

View File

@@ -573,7 +573,7 @@ public final class GameActionUtil {
if (!((CostPartMana) part).getManaToPay().equals("0")) // non-zero costs require input if (!((CostPartMana) part).getManaToPay().equals("0")) // non-zero costs require input
dontRemove = true; dontRemove = true;
} else } else
throw new RuntimeException("GameActionUtil.payCostDuringAbilityResolve - An unhadled type of cost has ocurred: " + part.getClass()); throw new RuntimeException("GameActionUtil.payCostDuringAbilityResolve - An unhandled type of cost has ocurred: " + part.getClass());
if ( !hasPaid ) if ( !hasPaid )