mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 02:38:02 +00:00
Fixed double extraction of InputPayManaBase inputs, that lead to stack incosistency
This commit is contained in:
@@ -41,6 +41,8 @@ public class ManaCostBeingPaid {
|
||||
private int cntX = 0;
|
||||
private final ArrayList<String> manaNeededToAvoidNegativeEffect = 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"
|
||||
// or "split hybrid mana" like "2/G 2/G", "2/B 2/B 2/B"
|
||||
@@ -59,6 +61,7 @@ public class ManaCostBeingPaid {
|
||||
}
|
||||
|
||||
public ManaCostBeingPaid(ManaCost manaCost) {
|
||||
originalCost = manaCost;
|
||||
if ( null == manaCost )
|
||||
return;
|
||||
|
||||
@@ -645,4 +648,8 @@ public class ManaCostBeingPaid {
|
||||
public final ArrayList<String> getManaPaidToAvoidNegativeEffect() {
|
||||
return this.manaPaidToAvoidNegativeEffect;
|
||||
}
|
||||
|
||||
public ManaCost getStartingCost() {
|
||||
return originalCost;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,14 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
*/
|
||||
public final void removeInput(Input inp) {
|
||||
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 )
|
||||
throw new RuntimeException("Inputs adding/removal into stack is imbalanced! Check your code again!");
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import java.util.Map;
|
||||
import forge.Card;
|
||||
import forge.CardUtil;
|
||||
import forge.Constant;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.ability.ApiType;
|
||||
@@ -129,7 +128,7 @@ public abstract class InputPayManaBase extends InputSyncronizedBase implements I
|
||||
|
||||
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
|
||||
subchosen.getManaPart().setExpressChoice(colorsNeeded);
|
||||
|
||||
final SpellAbility finallyChosen = chosen;
|
||||
// System.out.println("Chosen sa=" + chosen + " of " + chosen.getSourceCard() + " to pay mana");
|
||||
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);
|
||||
}
|
||||
});
|
||||
// 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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
});
|
||||
protected final void checkIfAlredyPaid() {
|
||||
if (manaCost.isPaid()) {
|
||||
bPaid = true;
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onManaAbilityPaid() {} // some inputs overload it
|
||||
@@ -328,7 +329,7 @@ public abstract class InputPayManaBase extends InputSyncronizedBase implements I
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PayManaBase (" + manaCost.toString() + ")";
|
||||
return String.format("PayManaBase %s (out of %s)", manaCost.toString(), manaCost.getStartingCost() );
|
||||
}
|
||||
|
||||
protected void handleConvokedCards(boolean isCancelled) {
|
||||
|
||||
@@ -23,7 +23,6 @@ import forge.card.mana.ManaCostBeingPaid;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.game.GameState;
|
||||
import forge.game.player.Player;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
//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.)");
|
||||
}
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString());
|
||||
showMessage(msg.toString());
|
||||
checkIfAlredyPaid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +72,6 @@ public class InputPayManaOfCostPayment extends InputPayManaBase {
|
||||
}
|
||||
|
||||
showMessage(msg.toString());
|
||||
if (manaCost.isPaid()) {
|
||||
bPaid = true;
|
||||
this.done();
|
||||
}
|
||||
checkIfAlredyPaid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import forge.card.spellability.SpellAbility;
|
||||
import forge.game.GameState;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
//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.)");
|
||||
}
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString());
|
||||
// has its own variant of checkIfPaid
|
||||
showMessage(msg.toString());
|
||||
if (this.manaCost.isPaid() && !new ManaCostBeingPaid(this.originalManaCost).isPaid()) {
|
||||
this.originalCard.setSunburstValue(this.manaCost.getSunburst());
|
||||
this.done();
|
||||
|
||||
@@ -5,7 +5,6 @@ import forge.card.cost.CostPartMana;
|
||||
import forge.card.mana.ManaCostBeingPaid;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.game.GameState;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
public class InputPayManaX extends InputPayManaBase {
|
||||
@@ -34,18 +33,15 @@ public class InputPayManaX extends InputPayManaBase {
|
||||
*/
|
||||
@Override
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage() {
|
||||
// only cancel if partially paid an X value
|
||||
// or X is 0, and x can't be 0
|
||||
if (!isPaid()) {
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
} else {
|
||||
@@ -59,7 +55,7 @@ public class InputPayManaX extends InputPayManaBase {
|
||||
msg.append(" X Can't be 0.");
|
||||
}
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString());
|
||||
showMessage(msg.toString());
|
||||
}
|
||||
|
||||
// selectCard
|
||||
|
||||
@@ -23,7 +23,6 @@ import forge.card.spellability.SpellAbilityRequirements;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.card.spellability.TargetSelection;
|
||||
import forge.card.staticability.StaticAbility;
|
||||
import forge.control.input.InputPayManaBase;
|
||||
import forge.control.input.InputPayManaSimple;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.player.Player;
|
||||
@@ -518,14 +517,14 @@ public class GameActionPlay {
|
||||
* @param manaCost
|
||||
* @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() {
|
||||
@Override
|
||||
public void run() {
|
||||
p.getGame().getActionPlay().playSpellAbility(chosen, p);
|
||||
inputPayManaBase.onManaAbilityPlayed(p, chosen);
|
||||
playSpellAbility(chosen, p);
|
||||
beforeUnlock.run();
|
||||
}
|
||||
};
|
||||
};
|
||||
FThreads.invokeInNewThread(proc, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,7 +573,7 @@ public final class GameActionUtil {
|
||||
if (!((CostPartMana) part).getManaToPay().equals("0")) // non-zero costs require input
|
||||
dontRemove = true;
|
||||
} 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 )
|
||||
|
||||
Reference in New Issue
Block a user