mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +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 int cntX = 0;
|
||||||
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"
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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!");
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 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) {
|
protected final void checkIfAlredyPaid() {
|
||||||
if ( saPaymentSrc != null) // null comes when they've paid from pool
|
if (manaCost.isPaid()) {
|
||||||
this.manaCost = p.getManaPool().payManaFromAbility(saPaidFor, manaCost, saPaymentSrc);
|
bPaid = true;
|
||||||
|
done();
|
||||||
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 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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,9 +72,6 @@ public class InputPayManaOfCostPayment extends InputPayManaBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showMessage(msg.toString());
|
showMessage(msg.toString());
|
||||||
if (manaCost.isPaid()) {
|
checkIfAlredyPaid();
|
||||||
bPaid = true;
|
|
||||||
this.done();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,14 +517,14 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 )
|
||||||
|
|||||||
Reference in New Issue
Block a user