Add "Auto" button for automatically paying a mana cost

Code cleanup
This commit is contained in:
drdev
2013-12-02 03:07:19 +00:00
parent dcb9553807
commit 0b6be04428
14 changed files with 247 additions and 166 deletions

View File

@@ -12,8 +12,8 @@ import forge.util.ThreadUtil;
* *
*/ */
public class FThreads { public class FThreads {
private FThreads() { } // no instances supposed private FThreads() { } // no instances supposed
/** Checks if calling method uses event dispatch thread. /** Checks if calling method uses event dispatch thread.
* Exception thrown if method is on "wrong" thread. * Exception thrown if method is on "wrong" thread.
* A boolean is passed to indicate if the method must be EDT or not. * A boolean is passed to indicate if the method must be EDT or not.
@@ -22,11 +22,11 @@ public class FThreads {
* @param mustBeEDT   boolean: true = exception if not EDT, false = exception if EDT * @param mustBeEDT   boolean: true = exception if not EDT, false = exception if EDT
*/ */
public static void assertExecutedByEdt(final boolean mustBeEDT) { public static void assertExecutedByEdt(final boolean mustBeEDT) {
if (isGuiThread() != mustBeEDT ) { if (isGuiThread() != mustBeEDT) {
StackTraceElement[] trace = Thread.currentThread().getStackTrace(); StackTraceElement[] trace = Thread.currentThread().getStackTrace();
final String methodName = trace[2].getClassName() + "." + trace[2].getMethodName(); final String methodName = trace[2].getClassName() + "." + trace[2].getMethodName();
String modalOperator = mustBeEDT ? " must be" : " may not be"; String modalOperator = mustBeEDT ? " must be" : " may not be";
throw new IllegalStateException( methodName + modalOperator + " accessed from the event dispatch thread."); throw new IllegalStateException(methodName + modalOperator + " accessed from the event dispatch thread.");
} }
} }
@@ -42,11 +42,13 @@ public class FThreads {
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
*/ */
public static void invokeInEdtNowOrLater(Runnable proc) { public static void invokeInEdtNowOrLater(Runnable proc) {
if( isGuiThread() ) if (isGuiThread()) {
proc.run(); proc.run();
else }
else {
invokeInEdtLater(proc); invokeInEdtLater(proc);
} }
}
/** /**
* Invoke the given Runnable in an Event Dispatch Thread and wait for it to * Invoke the given Runnable in an Event Dispatch Thread and wait for it to
@@ -64,20 +66,20 @@ public class FThreads {
if (SwingUtilities.isEventDispatchThread()) { if (SwingUtilities.isEventDispatchThread()) {
// Just run in the current thread. // Just run in the current thread.
proc.run(); proc.run();
} else { }
else {
try { try {
SwingUtilities.invokeAndWait(proc); SwingUtilities.invokeAndWait(proc);
} catch (final InterruptedException exn) { }
catch (final InterruptedException exn) {
throw new RuntimeException(exn); throw new RuntimeException(exn);
} catch (final InvocationTargetException exn) { }
catch (final InvocationTargetException exn) {
throw new RuntimeException(exn); throw new RuntimeException(exn);
} }
} }
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @return * @return
@@ -86,10 +88,10 @@ public class FThreads {
return SwingUtilities.isEventDispatchThread(); return SwingUtilities.isEventDispatchThread();
} }
public static void delayInEDT(int milliseconds, final Runnable inputUpdater) { public static void delayInEDT(int milliseconds, final Runnable inputUpdater) {
Runnable runInEdt = new Runnable() { Runnable runInEdt = new Runnable() {
@Override public void run() { @Override
public void run() {
FThreads.invokeInEdtNowOrLater(inputUpdater); FThreads.invokeInEdtNowOrLater(inputUpdater);
} }
}; };
@@ -106,25 +108,27 @@ public class FThreads {
public static void dumpStackTrace(PrintStream stream) { public static void dumpStackTrace(PrintStream stream) {
StackTraceElement[] trace = Thread.currentThread().getStackTrace(); StackTraceElement[] trace = Thread.currentThread().getStackTrace();
stream.printf("%s > %s called from %s%n", debugGetCurrThreadId(), trace[2].getClassName()+"."+trace[2].getMethodName(), trace[3].toString()); stream.printf("%s > %s called from %s%n", debugGetCurrThreadId(),
trace[2].getClassName() + "." + trace[2].getMethodName(), trace[3].toString());
int i = 0; int i = 0;
for(StackTraceElement se : trace) { for (StackTraceElement se : trace) {
if(i<2) i++; if (i<2) { i++; }
else stream.println(se.toString()); else { stream.println(se.toString()); }
} }
} }
public static String debugGetStackTraceItem(int depth, boolean shorter) { public static String debugGetStackTraceItem(int depth, boolean shorter) {
StackTraceElement[] trace = Thread.currentThread().getStackTrace(); StackTraceElement[] trace = Thread.currentThread().getStackTrace();
String lastItem = trace[depth].toString(); String lastItem = trace[depth].toString();
if( shorter ) { if (shorter) {
int lastPeriod = lastItem.lastIndexOf('.'); int lastPeriod = lastItem.lastIndexOf('.');
lastPeriod = lastItem.lastIndexOf('.', lastPeriod-1); lastPeriod = lastItem.lastIndexOf('.', lastPeriod-1);
lastPeriod = lastItem.lastIndexOf('.', lastPeriod-1); lastPeriod = lastItem.lastIndexOf('.', lastPeriod-1);
lastItem = lastItem.substring(lastPeriod+1); lastItem = lastItem.substring(lastPeriod+1);
return String.format("%s > from %s", debugGetCurrThreadId(), lastItem); return String.format("%s > from %s", debugGetCurrThreadId(), lastItem);
} }
return String.format("%s > %s called from %s", debugGetCurrThreadId(), trace[2].getClassName()+"."+trace[2].getMethodName(), lastItem); return String.format("%s > %s called from %s", debugGetCurrThreadId(),
trace[2].getClassName() + "." + trace[2].getMethodName(), lastItem);
} }
public static String debugGetStackTraceItem(int depth) { public static String debugGetStackTraceItem(int depth) {

View File

@@ -47,9 +47,17 @@ import forge.util.maps.MapOfLists;
* *
*/ */
public class ComputerUtilMana { public class ComputerUtilMana {
private final static boolean DEBUG_MANA_PAYMENT = false; private final static boolean DEBUG_MANA_PAYMENT = false;
public static boolean canPayManaCost(ManaCostBeingPaid cost, final SpellAbility sa, final Player ai) {
cost = new ManaCostBeingPaid(cost); //check copy of cost so it doesn't modify the exist cost being paid
return payManaCost(cost, sa, ai, true, 0, true);
}
public static boolean payManaCost(ManaCostBeingPaid cost, final SpellAbility sa, final Player ai) {
return payManaCost(cost, sa, ai, false, 0, true);
}
public static boolean canPayManaCost(final SpellAbility sa, final Player ai, final int extraMana) { public static boolean canPayManaCost(final SpellAbility sa, final Player ai, final int extraMana) {
return payManaCost(sa, ai, true, extraMana, true); return payManaCost(sa, ai, true, extraMana, true);
} }

View File

@@ -50,7 +50,7 @@ import forge.util.maps.MapToAmount;
/** /**
* <p> * <p>
* ManaCost class. * ManaCostBeingPaid class.
* </p> * </p>
* *
* @author Forge * @author Forge
@@ -74,28 +74,32 @@ public class ManaCostBeingPaid {
@Override @Override
public ManaCostShard next() { public ManaCostShard next() {
if (remainingShards == 0) if (remainingShards == 0) {
throw new UnsupportedOperationException("All shards were depleted, call hasNext()"); throw new UnsupportedOperationException("All shards were depleted, call hasNext()");
}
remainingShards--; remainingShards--;
return nextShard; return nextShard;
} }
@Override @Override
public boolean hasNext() { public boolean hasNext() {
if ( remainingShards > 0 ) return true; if (remainingShards > 0) { return true; }
if ( !hasSentX ) { if (!hasSentX) {
if ( nextShard != ManaCostShard.X && cntX > 0) { if (nextShard != ManaCostShard.X && cntX > 0) {
nextShard = ManaCostShard.X; nextShard = ManaCostShard.X;
remainingShards = cntX; remainingShards = cntX;
return true; return true;
} else }
else {
hasSentX = true; hasSentX = true;
} }
if ( !mch.hasNext() ) return false; }
if (!mch.hasNext()) { return false; }
nextShard = mch.next(); nextShard = mch.next();
if ( nextShard == ManaCostShard.COLORLESS ) if (nextShard == ManaCostShard.COLORLESS) {
return this.hasNext(); // skip colorless return this.hasNext(); // skip colorless
}
remainingShards = unpaidShards.get(nextShard); remainingShards = unpaidShards.get(nextShard);
return true; return true;
@@ -110,15 +114,25 @@ public class ManaCostBeingPaid {
// holds Mana_Part objects // holds Mana_Part objects
// ManaPartColor is stored before ManaPartColorless // ManaPartColor is stored before ManaPartColorless
private final MapToAmount<ManaCostShard> unpaidShards = new EnumMapToAmount<ManaCostShard>(ManaCostShard.class); private final MapToAmount<ManaCostShard> unpaidShards;
private final String sourceRestriction;
private byte sunburstMap = 0; private byte sunburstMap = 0;
private int cntX = 0; private int cntX = 0;
private final String sourceRestriction;
/**
* Copy constructor
* @param manaCostBeingPaid
*/
public ManaCostBeingPaid(ManaCostBeingPaid manaCostBeingPaid) {
unpaidShards = new EnumMapToAmount<ManaCostShard>(manaCostBeingPaid.unpaidShards);
sourceRestriction = manaCostBeingPaid.sourceRestriction;
sunburstMap = manaCostBeingPaid.sunburstMap;
cntX = manaCostBeingPaid.cntX;
}
// 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
/** /**
* <p> * <p>
* Constructor for ManaCost. * Constructor for ManaCost.
@@ -134,9 +148,11 @@ public class ManaCostBeingPaid {
public ManaCostBeingPaid(ManaCost manaCost) { public ManaCostBeingPaid(ManaCost manaCost) {
this(manaCost, null); this(manaCost, null);
} }
public ManaCostBeingPaid(ManaCost manaCost, String srcRestriction) { public ManaCostBeingPaid(ManaCost manaCost, String srcRestriction) {
unpaidShards = new EnumMapToAmount<ManaCostShard>(ManaCostShard.class);
sourceRestriction = srcRestriction; sourceRestriction = srcRestriction;
if( manaCost == null ) return; if (manaCost == null) { return; }
for (ManaCostShard shard : manaCost.getShards()) { for (ManaCostShard shard : manaCost.getShards()) {
if (shard == ManaCostShard.X) { if (shard == ManaCostShard.X) {
cntX++; cntX++;
@@ -163,7 +179,6 @@ public class ManaCostBeingPaid {
return sunburstMap; return sunburstMap;
} }
public final boolean containsPhyrexianMana() { public final boolean containsPhyrexianMana() {
for (ManaCostShard shard : unpaidShards.keySet()) { for (ManaCostShard shard : unpaidShards.keySet()) {
if (shard.isPhyrexian()) { if (shard.isPhyrexian()) {
@@ -175,33 +190,37 @@ public class ManaCostBeingPaid {
public final boolean payPhyrexian() { public final boolean payPhyrexian() {
ManaCostShard phy = null; ManaCostShard phy = null;
for(ManaCostShard mcs : unpaidShards.keySet()) { for (ManaCostShard mcs : unpaidShards.keySet()) {
if( mcs.isPhyrexian() ) { if (mcs.isPhyrexian()) {
phy = mcs; phy = mcs;
break; break;
} }
} }
if (phy == null ) if (phy == null) {
return false; return false;
}
decreaseShard(phy, 1); decreaseShard(phy, 1);
return true; return true;
} }
// takes a Short Color and returns true if it exists in the mana cost. // takes a Short Color and returns true if it exists in the mana cost.
// Easier for split costs // Easier for split costs
public final boolean needsColor(final byte colorMask) { public final boolean needsColor(final byte colorMask) {
for (ManaCostShard shard : unpaidShards.keySet()) { for (ManaCostShard shard : unpaidShards.keySet()) {
if (shard == ManaCostShard.COLORLESS) if (shard == ManaCostShard.COLORLESS) {
continue; continue;
}
if (shard.isOr2Colorless()) { if (shard.isOr2Colorless()) {
if ((shard.getColorMask() & colorMask) != 0 ) if ((shard.getColorMask() & colorMask) != 0) {
return true; return true;
} else if (shard.canBePaidWithManaOfColor(colorMask)) }
}
else if (shard.canBePaidWithManaOfColor(colorMask)) {
return true; return true;
} }
}
return false; return false;
} }
@@ -224,10 +243,9 @@ public class ManaCostBeingPaid {
return false; return false;
} }
public final boolean isPaid() { public final boolean isPaid() {
return unpaidShards.isEmpty(); return unpaidShards.isEmpty();
} // isPaid() }
/** /**
* <p> * <p>
@@ -242,20 +260,22 @@ public class ManaCostBeingPaid {
List<String> unused = new ArrayList<String>(4); List<String> unused = new ArrayList<String>(4);
for (String manaPart : TextUtil.split(mana, ' ')) { for (String manaPart : TextUtil.split(mana, ' ')) {
if (StringUtils.isNumeric(manaPart)) { if (StringUtils.isNumeric(manaPart)) {
for(int i = Integer.parseInt(manaPart); i > 0; i--) { for (int i = Integer.parseInt(manaPart); i > 0; i--) {
boolean wasNeeded = this.payMana("1"); boolean wasNeeded = this.payMana("1");
if(!wasNeeded) { if (!wasNeeded) {
unused.add(Integer.toString(i)); unused.add(Integer.toString(i));
break; break;
} }
} }
} else { }
else {
String color = MagicColor.toShortString(manaPart); String color = MagicColor.toShortString(manaPart);
boolean wasNeeded = this.payMana(color); boolean wasNeeded = this.payMana(color);
if(!wasNeeded) if (!wasNeeded) {
unused.add(color); unused.add(color);
} }
} }
}
return unused.isEmpty() ? null : StringUtils.join(unused, ' '); return unused.isEmpty() ? null : StringUtils.join(unused, ' ');
} }
@@ -305,7 +325,8 @@ public class ManaCostBeingPaid {
} }
Predicate<ManaCostShard> predCanBePaid = new Predicate<ManaCostShard>() { Predicate<ManaCostShard> predCanBePaid = new Predicate<ManaCostShard>() {
@Override public boolean apply(ManaCostShard ms) { @Override
public boolean apply(ManaCostShard ms) {
return ms.canBePaidWithManaOfColor(colorMask); return ms.canBePaidWithManaOfColor(colorMask);
} }
}; };
@@ -328,7 +349,8 @@ public class ManaCostBeingPaid {
} }
Predicate<ManaCostShard> predCanBePaid = new Predicate<ManaCostShard>() { Predicate<ManaCostShard> predCanBePaid = new Predicate<ManaCostShard>() {
@Override public boolean apply(ManaCostShard ms) { @Override
public boolean apply(ManaCostShard ms) {
return canBePaidWith(ms, mana); return canBePaidWith(ms, mana);
} }
}; };
@@ -353,7 +375,7 @@ public class ManaCostBeingPaid {
} }
decreaseShard(choice, 1); decreaseShard(choice, 1);
if (choice.isOr2Colorless() && choice.getColorMask() != colorMask ) { if (choice.isOr2Colorless() && choice.getColorMask() != colorMask) {
this.increaseColorlessMana(1); this.increaseColorlessMana(1);
} }
@@ -395,7 +417,8 @@ public class ManaCostBeingPaid {
for (ManaCostShard shard : extra.getShards()) { for (ManaCostShard shard : extra.getShards()) {
if (shard == ManaCostShard.X) { if (shard == ManaCostShard.X) {
cntX++; cntX++;
} else { }
else {
increaseShard(shard, 1); increaseShard(shard, 1);
} }
} }
@@ -406,9 +429,11 @@ public class ManaCostBeingPaid {
for (ManaCostShard shard : subThisManaCost.getShards()) { for (ManaCostShard shard : subThisManaCost.getShards()) {
if (shard == ManaCostShard.X) { if (shard == ManaCostShard.X) {
cntX--; cntX--;
} else if (unpaidShards.containsKey(shard)) { }
else if (unpaidShards.containsKey(shard)) {
decreaseShard(shard, 1); decreaseShard(shard, 1);
} else { }
else {
decreaseColorlessMana(1); decreaseColorlessMana(1);
} }
} }
@@ -493,15 +518,14 @@ public class ManaCostBeingPaid {
return cntX; return cntX;
} }
public final List<ManaCostShard> getUnpaidShards() { public final List<ManaCostShard> getUnpaidShards() {
List<ManaCostShard> result = new ArrayList<ManaCostShard>(); List<ManaCostShard> result = new ArrayList<ManaCostShard>();
for(Entry<ManaCostShard, Integer> kv : unpaidShards.entrySet()) { for (Entry<ManaCostShard, Integer> kv : unpaidShards.entrySet()) {
for(int i = kv.getValue().intValue(); i > 0; i--) { for (int i = kv.getValue().intValue(); i > 0; i--) {
result.add(kv.getKey()); result.add(kv.getKey());
} }
} }
for(int i = cntX; i > 0; i--) { for (int i = cntX; i > 0; i--) {
result.add(ManaCostShard.X); result.add(ManaCostShard.X);
} }
return result; return result;
@@ -524,7 +548,6 @@ public class ManaCostBeingPaid {
final Card originalCard = sa.getSourceCard(); final Card originalCard = sa.getSourceCard();
final SpellAbility spell = sa; final SpellAbility spell = sa;
if (sa.isXCost() && !originalCard.isCopiedSpell()) { if (sa.isXCost() && !originalCard.isCopiedSpell()) {
originalCard.setXManaCostPaid(0); originalCard.setXManaCostPaid(0);
} }
@@ -544,7 +567,8 @@ public class ManaCostBeingPaid {
pc.getGame().getAction().exile(c); pc.getGame().getAction().exile(c);
} }
} }
} else if (spell.getSourceCard().hasKeyword("Convoke")) { }
else if (spell.getSourceCard().hasKeyword("Convoke")) {
adjustCostByConvoke(sa, spell); adjustCostByConvoke(sa, spell);
} }
} // isSpell } // isSpell
@@ -565,9 +589,11 @@ public class ManaCostBeingPaid {
for (final StaticAbility stAb : staticAbilities) { for (final StaticAbility stAb : staticAbilities) {
if (stAb.getMapParams().get("Mode").equals("RaiseCost")) { if (stAb.getMapParams().get("Mode").equals("RaiseCost")) {
raiseAbilities.add(stAb); raiseAbilities.add(stAb);
} else if (stAb.getMapParams().get("Mode").equals("ReduceCost")) { }
else if (stAb.getMapParams().get("Mode").equals("ReduceCost")) {
reduceAbilities.add(stAb); reduceAbilities.add(stAb);
} else if (stAb.getMapParams().get("Mode").equals("SetCost")) { }
else if (stAb.getMapParams().get("Mode").equals("SetCost")) {
setAbilities.add(stAb); setAbilities.add(stAb);
} }
} }
@@ -601,27 +627,29 @@ public class ManaCostBeingPaid {
String chosenColor = null; String chosenColor = null;
if (sa.getActivatingPlayer().isHuman()) { if (sa.getActivatingPlayer().isHuman()) {
workingCard = GuiChoose.oneOrNone("Tap for Convoke? " + toString(), untappedCreats); workingCard = GuiChoose.oneOrNone("Tap for Convoke? " + toString(), untappedCreats);
if( null == workingCard ) if (null == workingCard) {
break; // that means "I'm done" break; // that means "I'm done"
}
List<String> usableColors = getConvokableColors(workingCard); List<String> usableColors = getConvokableColors(workingCard);
if ( !usableColors.isEmpty() ) { if (!usableColors.isEmpty()) {
chosenColor = usableColors.size() == 1 ? usableColors.get(0) : GuiChoose.one("Convoke for which color?", usableColors); chosenColor = usableColors.size() == 1 ? usableColors.get(0) : GuiChoose.one("Convoke for which color?", usableColors);
} }
} else { }
else {
// TODO: AI to choose a creature to tap would go here // TODO: AI to choose a creature to tap would go here
// Probably along with deciding how many creatures to tap // Probably along with deciding how many creatures to tap
break; break;
} }
untappedCreats.remove(workingCard); untappedCreats.remove(workingCard);
if (null == chosenColor) {
if ( null == chosenColor )
continue; continue;
}
else if (chosenColor.equals("colorless")) { else if (chosenColor.equals("colorless")) {
decreaseColorlessMana(1); decreaseColorlessMana(1);
} else { }
else {
decreaseShard(ManaCostShard.valueOf(MagicColor.fromName(chosenColor)), 1); decreaseShard(ManaCostShard.valueOf(MagicColor.fromName(chosenColor)), 1);
} }
@@ -640,7 +668,6 @@ public class ManaCostBeingPaid {
for (final Card c : sa.getTappedForConvoke()) { for (final Card c : sa.getTappedForConvoke()) {
c.setTapped(true); c.setTapped(true);
} }
} }
/** /**
@@ -659,10 +686,11 @@ public class ManaCostBeingPaid {
usableColors.add("colorless"); usableColors.add("colorless");
} }
ColorSet cs = CardUtil.getColors(cardToConvoke); ColorSet cs = CardUtil.getColors(cardToConvoke);
for(byte color : MagicColor.WUBRG) { for (byte color : MagicColor.WUBRG) {
if( cs.hasAnyColor(color)) if (cs.hasAnyColor(color)) {
usableColors.add(MagicColor.toLongString(color)); usableColors.add(MagicColor.toLongString(color));
} }
}
return usableColors; return usableColors;
} }
@@ -684,7 +712,8 @@ public class ManaCostBeingPaid {
if (!toSacList.isEmpty()) { if (!toSacList.isEmpty()) {
toSac = toSacList.get(0); toSac = toSacList.get(0);
} else { }
else {
return; return;
} }

View File

@@ -76,13 +76,10 @@ import forge.util.TextUtil;
* Handles phase skips for now. * Handles phase skips for now.
*/ */
public class PlayerControllerHuman extends PlayerController { public class PlayerControllerHuman extends PlayerController {
public PlayerControllerHuman(Game game0, Player p, LobbyPlayer lp) { public PlayerControllerHuman(Game game0, Player p, LobbyPlayer lp) {
super(game0, p, lp); super(game0, p, lp);
} }
public boolean isUiSetToSkipPhase(final Player turn, final PhaseType phase) { public boolean isUiSetToSkipPhase(final Player turn, final PhaseType phase) {
return !CMatchUI.SINGLETON_INSTANCE.stopAtPhase(turn, phase); return !CMatchUI.SINGLETON_INSTANCE.stopAtPhase(turn, phase);
} }

View File

@@ -280,7 +280,9 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
* a {@link forge.game.spellability.SpellAbility} object. * a {@link forge.game.spellability.SpellAbility} object.
*/ */
public final void add(final SpellAbility sp) { public final void add(final SpellAbility sp) {
if (!sp.isManaAbility()) { //allow adding mana abilities on EDT
FThreads.assertExecutedByEdt(false); FThreads.assertExecutedByEdt(false);
}
SpellAbilityStackInstance si = null; SpellAbilityStackInstance si = null;
final Card source = sp.getSourceCard(); final Card source = sp.getSourceCard();
Player activator = sp.getActivatingPlayer(); Player activator = sp.getActivatingPlayer();

View File

@@ -8,6 +8,7 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import forge.FThreads; import forge.FThreads;
import forge.ai.ComputerUtilMana;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaCostShard; import forge.card.mana.ManaCostShard;
@@ -109,7 +110,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
boolean canUseColorless = manaCost.isAnyPartPayableWith((byte)0); boolean canUseColorless = manaCost.isAnyPartPayableWith((byte)0);
List<SpellAbility> abilities = new ArrayList<SpellAbility>(); List<SpellAbility> abilities = new ArrayList<SpellAbility>();
// you can't remove unneeded abilities inside a for(am:abilities) loop :( // you can't remove unneeded abilities inside a for (am:abilities) loop :(
final String typeRes = manaCost.getSourceRestriction(); final String typeRes = manaCost.getSourceRestriction();
if (StringUtils.isNotBlank(typeRes) && !card.isType(typeRes)) { if (StringUtils.isNotBlank(typeRes) && !card.isType(typeRes)) {
@@ -193,7 +194,6 @@ public abstract class InputPayMana extends InputSyncronizedBase {
game.getAction().invoke(proc); game.getAction().invoke(proc);
} }
/** /**
* <p> * <p>
* canMake. color is like "G", returns "Green". * canMake. color is like "G", returns "Green".
@@ -272,16 +272,52 @@ public abstract class InputPayMana extends InputSyncronizedBase {
return bPaid; return bPaid;
} }
protected boolean supportAutoPay() {
return true;
}
/** {@inheritDoc} */
@Override
protected void onOk() {
if (supportAutoPay()) {
//use AI utility to automatically pay mana cost if possible
ComputerUtilMana.payManaCost(manaCost, saPaidFor, player);
this.showMessage();
}
}
protected void updateButtons() {
if (supportAutoPay()) {
ButtonUtil.setButtonText("Auto", "Cancel");
}
ButtonUtil.enableOnlyCancel();
}
protected final void updateMessage() {
if (supportAutoPay() && ComputerUtilMana.canPayManaCost(manaCost, saPaidFor, player)) {
ButtonUtil.enableAllFocusOk(); //enabled Auto button if mana cost can be paid
}
showMessage(getMessage());
}
/** {@inheritDoc} */
@Override
protected final void onStop() {
if (supportAutoPay()) {
ButtonUtil.reset();
}
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void showMessage() { public void showMessage() {
if (isFinished()) { return; } if (isFinished()) { return; }
ButtonUtil.enableOnlyCancel(); updateButtons();
onStateChanged(); onStateChanged();
} }
protected void onStateChanged() { protected void onStateChanged() {
if(isAlreadyPaid()) { if (isAlreadyPaid()) {
done(); done();
stop(); stop();
} }
@@ -297,11 +333,11 @@ public abstract class InputPayMana extends InputSyncronizedBase {
protected void onManaAbilityPaid() {} // some inputs overload it protected void onManaAbilityPaid() {} // some inputs overload it
protected abstract void done(); protected abstract void done();
protected abstract void updateMessage(); protected abstract String getMessage();
@Override @Override
public String toString() { public String toString() {
return String.format("PayManaBase %s left", manaCost.toString() ); return String.format("PayManaBase %s left", manaCost.toString());
} }
public boolean isPaid() { return bPaid; } public boolean isPaid() { return bPaid; }

View File

@@ -102,11 +102,9 @@ public class InputPayManaExecuteCommands extends InputPayMana {
this.stop(); this.stop();
} }
/* (non-Javadoc) /** {@inheritDoc} */
* @see forge.control.input.InputPayManaBase#updateMessage()
*/
@Override @Override
protected void updateMessage() { protected String getMessage() {
final StringBuilder msg = new StringBuilder(this.message + "Pay Mana Cost: " + this.manaCost); final StringBuilder msg = new StringBuilder(this.message + "Pay Mana Cost: " + this.manaCost);
if (this.phyLifeToLose > 0) { if (this.phyLifeToLose > 0) {
msg.append(" ("); msg.append(" (");
@@ -117,6 +115,6 @@ public class InputPayManaExecuteCommands extends InputPayMana {
if (this.manaCost.containsPhyrexianMana()) { if (this.manaCost.containsPhyrexianMana()) {
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.)");
} }
showMessage(msg.toString()); return msg.toString();
} }
} }

View File

@@ -6,7 +6,6 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
public class InputPayManaOfCostPayment extends InputPayMana { public class InputPayManaOfCostPayment extends InputPayMana {
public InputPayManaOfCostPayment(ManaCostBeingPaid cost, SpellAbility spellAbility) { public InputPayManaOfCostPayment(ManaCostBeingPaid cost, SpellAbility spellAbility) {
super(spellAbility); super(spellAbility);
manaCost = cost; manaCost = cost;
@@ -39,7 +38,8 @@ public class InputPayManaOfCostPayment extends InputPayMana {
stop(); stop();
} }
protected void updateMessage() { @Override
protected String getMessage() {
final String displayMana = manaCost.toString(false); final String displayMana = manaCost.toString(false);
final StringBuilder msg = new StringBuilder("Pay Mana Cost: " + displayMana); final StringBuilder msg = new StringBuilder("Pay Mana Cost: " + displayMana);
@@ -53,6 +53,6 @@ public class InputPayManaOfCostPayment extends InputPayMana {
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.)");
} }
showMessage(msg.toString()); return msg.toString();
} }
} }

View File

@@ -22,7 +22,6 @@ import forge.game.card.Card;
import forge.game.mana.ManaCostBeingPaid; import forge.game.mana.ManaCostBeingPaid;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
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
//the card is removed from the players hand if the cost is paid //the card is removed from the players hand if the cost is paid
@@ -102,7 +101,7 @@ public class InputPayManaSimple extends InputPayMana {
public final void showMessage() { public final void showMessage() {
if (isFinished()) { return; } if (isFinished()) { return; }
ButtonUtil.enableOnlyCancel(); updateButtons();
if (this.manaCost.isPaid() && !new ManaCostBeingPaid(this.originalManaCost).isPaid()) { if (this.manaCost.isPaid() && !new ManaCostBeingPaid(this.originalManaCost).isPaid()) {
this.done(); this.done();
@@ -117,7 +116,7 @@ public class InputPayManaSimple extends InputPayMana {
* @see forge.control.input.InputPayManaBase#updateMessage() * @see forge.control.input.InputPayManaBase#updateMessage()
*/ */
@Override @Override
protected void updateMessage() { protected String getMessage() {
final StringBuilder msg = new StringBuilder("Pay Mana Cost: " + this.manaCost.toString()); final StringBuilder msg = new StringBuilder("Pay Mana Cost: " + this.manaCost.toString());
if (this.phyLifeToLose > 0) { if (this.phyLifeToLose > 0) {
msg.append(" ("); msg.append(" (");
@@ -130,6 +129,6 @@ public class InputPayManaSimple extends InputPayMana {
} }
// has its own variant of checkIfPaid // has its own variant of checkIfPaid
showMessage(msg.toString()); return msg.toString();
} }
} }

View File

@@ -55,6 +55,11 @@ public class InputPayManaX extends InputPayMana {
return !canceled && (xPaid > 0 || xCanBe0); return !canceled && (xPaid > 0 || xCanBe0);
} }
@Override
protected boolean supportAutoPay() {
return false;
}
@Override @Override
public void showMessage() { public void showMessage() {
if (isFinished()) { return; } if (isFinished()) { return; }
@@ -63,7 +68,7 @@ public class InputPayManaX extends InputPayMana {
} }
@Override @Override
protected void updateMessage() { protected String getMessage() {
StringBuilder msg = new StringBuilder("Pay X Mana Cost for "); StringBuilder msg = new StringBuilder("Pay X Mana Cost for ");
msg.append(saPaidFor.getSourceCard().getName()).append("\n").append(this.xPaid); msg.append(saPaidFor.getSourceCard().getName()).append("\n").append(this.xPaid);
msg.append(" Paid so far."); msg.append(" Paid so far.");
@@ -79,7 +84,7 @@ public class InputPayManaX extends InputPayMana {
ButtonUtil.enableAllFocusOk(); ButtonUtil.enableAllFocusOk();
} }
showMessage(msg.toString()); return msg.toString();
} }
@Override @Override

View File

@@ -28,11 +28,20 @@ public abstract class InputSyncronizedBase extends InputBase implements InputSyn
} }
protected final void stop() { protected final void stop() {
onStop();
// ensure input won't accept any user actions. // ensure input won't accept any user actions.
FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public void run() { setFinished(); } }); FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override
public void run() {
setFinished();
}
});
// thread irrelevant // thread irrelevant
Singletons.getControl().getInputQueue().removeInput(InputSyncronizedBase.this); Singletons.getControl().getInputQueue().removeInput(InputSyncronizedBase.this);
cdlDone.countDown(); cdlDone.countDown();
} }
protected void onStop() { }
} }

View File

@@ -4,7 +4,6 @@ import java.util.EnumMap;
import java.util.Map; import java.util.Map;
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
* *
@@ -12,7 +11,6 @@ import java.util.Map;
public class EnumMapToAmount<T extends Enum<T>> extends EnumMap<T, Integer> implements MapToAmount<T> { public class EnumMapToAmount<T extends Enum<T>> extends EnumMap<T, Integer> implements MapToAmount<T> {
private static final long serialVersionUID = -4749796492075359368L; private static final long serialVersionUID = -4749796492075359368L;
public EnumMapToAmount(Class<T> keyType) { public EnumMapToAmount(Class<T> keyType) {
super(keyType); super(keyType);
} }
@@ -32,15 +30,17 @@ public class EnumMapToAmount<T extends Enum<T>> extends EnumMap<T, Integer> impl
@Override @Override
public void add(T item, int amount) { public void add(T item, int amount) {
if (amount <= 0) return; // throw an exception maybe? if (amount <= 0) { return; } // throw an exception maybe?
Integer cur = get(item); Integer cur = get(item);
int newVal = cur == null ? amount : amount + cur.intValue(); int newVal = cur == null ? amount : amount + cur.intValue();
put(item, Integer.valueOf(newVal)); put(item, Integer.valueOf(newVal));
} }
@Override @Override
public void addAll(Iterable<T> item) { public void addAll(Iterable<T> items) {
for(T i : item) add(i, 1); for (T i : items) {
add(i, 1);
}
} }
@Override @Override
@@ -48,39 +48,39 @@ public class EnumMapToAmount<T extends Enum<T>> extends EnumMap<T, Integer> impl
return substract(item, 1); return substract(item, 1);
} }
@Override @Override
public boolean substract(T item, int amount) { public boolean substract(T item, int amount) {
Integer cur = get(item); Integer cur = get(item);
if( cur == null ) return false; if (cur == null) { return false; }
int newVal = cur.intValue() - amount; int newVal = cur.intValue() - amount;
if(newVal > 0) if (newVal > 0) {
put(item, Integer.valueOf(newVal)); put(item, Integer.valueOf(newVal));
else }
else {
remove(item); remove(item);
}
return true; return true;
} }
@Override @Override
public void substractAll(Iterable<T> item) { public void substractAll(Iterable<T> items) {
for(T i : item) substract(i); for (T i : items) {
substract(i);
}
} }
@Override @Override
public int countAll() { public int countAll() {
int c = 0; int c = 0;
for(java.util.Map.Entry<T, Integer> kv : this.entrySet()) { for (java.util.Map.Entry<T, Integer> kv : this.entrySet()) {
c += kv.getValue().intValue(); c += kv.getValue().intValue();
} }
return c; return c;
} }
@Override @Override
public int count(T item) { public int count(T item) {
Integer cur = get(item); Integer cur = get(item);
return cur == null ? 0 : cur.intValue(); return cur == null ? 0 : cur.intValue();
} }
} }

View File

@@ -9,10 +9,10 @@ import java.util.Map;
public interface MapToAmount<K> extends Map<K, Integer> { public interface MapToAmount<K> extends Map<K, Integer> {
void add(K item); void add(K item);
void add(K item, int amount); void add(K item, int amount);
void addAll(Iterable<K> item); void addAll(Iterable<K> items);
boolean substract(K item); boolean substract(K item);
boolean substract(K item, int amount); boolean substract(K item, int amount);
void substractAll(Iterable<K> item); void substractAll(Iterable<K> items);
int countAll(); int countAll();
int count(K item); // just unboxes and returns zero instead of null int count(K item); // just unboxes and returns zero instead of null
} }

View File

@@ -113,7 +113,6 @@ public abstract class CardPanelContainer extends JPanel {
} }
private void setupMouseListener(final MouseMotionListener mml) { private void setupMouseListener(final MouseMotionListener mml) {
this.addMouseListener(new MouseAdapter() { this.addMouseListener(new MouseAdapter() {
private final boolean[] buttonsDown = new boolean[4]; private final boolean[] buttonsDown = new boolean[4];
@@ -181,13 +180,10 @@ public abstract class CardPanelContainer extends JPanel {
CardPanelContainer.this.mouseOutPanel(evt); CardPanelContainer.this.mouseOutPanel(evt);
} }
}); });
} }
private MouseMotionListener setupMotionMouseListener() { private MouseMotionListener setupMotionMouseListener() {
final MouseMotionListener mml = new MouseMotionListener() { final MouseMotionListener mml = new MouseMotionListener() {
@Override @Override
public void mouseDragged(final MouseEvent evt) { public void mouseDragged(final MouseEvent evt) {
if (CardZoomer.SINGLETON_INSTANCE.isZoomerOpen() || !SwingUtilities.isLeftMouseButton(evt)) { if (CardZoomer.SINGLETON_INSTANCE.isZoomerOpen() || !SwingUtilities.isLeftMouseButton(evt)) {
@@ -348,8 +344,6 @@ public abstract class CardPanelContainer extends JPanel {
CardPanelContainer.this.remove(fromPanel); CardPanelContainer.this.remove(fromPanel);
CardPanelContainer.this.invalidate(); CardPanelContainer.this.invalidate();
CardPanelContainer.this.repaint(); CardPanelContainer.this.repaint();
} }
/** /**