From ec294376407223f5c7bd3d355d77e3ce45b50c90 Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 03:55:14 +0000 Subject: [PATCH] Moved reflected mana ability code into a new class. Made reflected lands playable from Input_PayManaCost. --- .gitattributes | 1 + src/forge/Ability_Mana.java | 14 +- src/forge/Ability_Reflected_Mana.java | 224 ++++++++++++++++++++++++++ src/forge/Card.java | 4 + src/forge/CardFactoryUtil.java | 113 +------------ src/forge/ComputerUtil.java | 4 +- src/forge/GameAction.java | 2 +- src/forge/GameActionUtil.java | 115 ------------- src/forge/Input_PayManaCostUtil.java | 48 ++++-- src/forge/SpellAbility.java | 5 + 10 files changed, 283 insertions(+), 247 deletions(-) create mode 100644 src/forge/Ability_Reflected_Mana.java diff --git a/.gitattributes b/.gitattributes index 80e4d673bcb..7a3337ab406 100644 --- a/.gitattributes +++ b/.gitattributes @@ -87,6 +87,7 @@ src/forge/Ability.java svneol=native#text/plain src/forge/Ability_Activated.java svneol=native#text/plain src/forge/Ability_Hand.java svneol=native#text/plain src/forge/Ability_Mana.java -text svneol=native#text/plain +src/forge/Ability_Reflected_Mana.java svneol=native#text/plain src/forge/Ability_Tap.java svneol=native#text/plain src/forge/Ability_Triggered.java svneol=native#text/plain src/forge/All.java svneol=native#text/plain diff --git a/src/forge/Ability_Mana.java b/src/forge/Ability_Mana.java index c2aaf3bcc9e..b1238582ba0 100644 --- a/src/forge/Ability_Mana.java +++ b/src/forge/Ability_Mana.java @@ -4,7 +4,6 @@ package forge; import java.util.ArrayList; - abstract public class Ability_Mana extends SpellAbility implements java.io.Serializable { private ArrayList runcommands = new ArrayList(); public String orig; @@ -38,16 +37,6 @@ abstract public class Ability_Mana extends SpellAbility implements java.io.Seria return isTapAbility(orig); } - // This is a work-in-progress *coughcough HACK coughcough* - // This should return the list of all possible colors for the mana ability - // Instead, right now it only does so for reflected lands, which override - // this ability. - // For any other kind of land, the method asserts. If you find you need to call - // this method, implement it... - public ArrayList getPossibleColors() { - throw new RuntimeException("Ability_Mana : getPossibleColors() not implemented"); - } - private static boolean isTapAbility(String orig) { String cost = orig.split(":")[0]; cost = cost.replaceAll("Tap", "tap").replaceAll("tap", "T"); @@ -279,4 +268,7 @@ abstract public class Ability_Mana extends SpellAbility implements java.io.Seria } return false; } + + } + diff --git a/src/forge/Ability_Reflected_Mana.java b/src/forge/Ability_Reflected_Mana.java new file mode 100644 index 00000000000..c34b78f8758 --- /dev/null +++ b/src/forge/Ability_Reflected_Mana.java @@ -0,0 +1,224 @@ +package forge; + +import java.util.ArrayList; + +public class Ability_Reflected_Mana extends Ability_Mana { + + private static final long serialVersionUID = 7050614528410938233L; + + String colorChosen; + String colorOrType; + String who; + boolean choiceWasMade = false; + + public Ability_Reflected_Mana(final Card card, String abString, String colorOrType, String who) { + super(card, abString); + this.colorOrType = new String(colorOrType); + this.who = new String(who); + this.setReflectedMana(true); + this.colorChosen = new String("0"); // Default -- add no mana + this.undoable = true; + } + + public String getTargetPlayer() { + String targetPlayer; + if (this.who.startsWith("Opp")) { + targetPlayer = AllZone.GameAction.getOpponent(this.getSourceCard().getController()); + } else { + targetPlayer = this.getSourceCard().getController(); + } + return targetPlayer; + } + + public void undo() { + this.reset(); + super.undo(); + } + + public ArrayList getPossibleColors() { + String targetPlayer; + if (this.who.startsWith("Opp")) { + targetPlayer = AllZone.GameAction.getOpponent(this.getSourceCard().getController()); + } else { + targetPlayer = this.getSourceCard().getController(); + } + + ArrayList possibleColors = getManaProduceList(targetPlayer, this.colorOrType); + return possibleColors; + } + + public boolean canPlay() { + ArrayList possibleColors = this.getPossibleColors(); + if (possibleColors.isEmpty()) { + // Can't use these cards if there are no mana-producing lands in play + return false; + } else { + return super.canPlay(); + } + } + + public void resolve() { + if (!this.choiceWasMade) + this.chooseManaColor(); + if (this.choiceWasMade) + super.resolve(); + } + + public String mana() { + return this.colorChosen; + } + + public void reset() { + this.colorChosen = "0"; + this.choiceWasMade = false; + } + + public boolean wasCancelled() { + return !this.choiceWasMade; + } + + + public void chooseManaColor() { + ArrayList possibleColors = this.getPossibleColors(); + if (possibleColors.isEmpty()) { + // No mana available: card doesn't tap and nothing happens + this.colorChosen = "0"; + } else if (possibleColors.size() == 1) { + // Card taps for the only mana available + this.colorChosen = + Input_PayManaCostUtil.getShortColorString(possibleColors.get(0)); + this.choiceWasMade = true; + } + else { + // Choose a color of mana to produce. + Object o = AllZone.Display.getChoiceOptional("Select Mana to Produce", possibleColors.toArray()); + if (o == null) { + // User hit cancel + this.colorChosen = "0"; + this.choiceWasMade = false; + } else { + this.colorChosen = + Input_PayManaCostUtil.getShortColorString((String) o); + this.choiceWasMade = true; + } + } + } + + // Return the list of mana types or colors that the target player's land can produce + // This is used by the mana abilities created by the abReflectedMana keyword + public static ArrayList getManaProduceList(String player, String colorOrType) { + ArrayList colorsPlayerCanProduce = new ArrayList(); + ArrayList colorsToLookFor = new ArrayList(); + + if (colorOrType.startsWith("Type")) { + // Includes colorless (like Reflecting Pool) + for (int ic = 0; ic < Constant.Color.Colors.length; ic++) { + colorsToLookFor.add(Constant.Color.Colors[ic]); + } + } else { + // Excludes colorless (like Exotic Orchard) + for (int ic = 0; ic < Constant.Color.onlyColors.length; ic++) { + colorsToLookFor.add(Constant.Color.onlyColors[ic]); + } + } + + // Build the list of cards to search for mana colors + // First, add all the cards owned by the target player + CardList cl = new CardList(); + cl.addAll(AllZone.getZone(Constant.Zone.Play,player).getCards()); + + // Narrow down the card list to only non-reflected lands + // If during this search we find another reflected land, and it targets a different player + // than this land, then we have to search that player's lands as well + boolean addOtherPlayerLands = false; + int ix = 0; + while (ix < cl.size()) { + Card otherCard = cl.get(ix); + if (otherCard.isLand()) { + if (otherCard.isReflectedLand() && !addOtherPlayerLands) { + ArrayList amList = otherCard.getManaAbility(); + // We assume reflected lands have only one mana ability + // Find out which player it targets + Ability_Mana am = amList.get(0); + String otherTargetPlayer = am.getTargetPlayer(); + + // If the target player of the other land isn't the same as the target player + // of this land, we need to search the sets of mana he can produce as well. + if (!otherTargetPlayer.equals(player)) { + addOtherPlayerLands = true; // We only need to record this decision once + } + // Don't keep reflected lands in the list of lands + cl.remove(ix); + } else { + // Other card is a land but not a reflected land + ix++; // leave in list & look at next card + } + } else { + // Other card is not a land -- remove it + cl.remove(ix); + } + } // while ix < cl.size + + getManaFromCardList(cl, colorsPlayerCanProduce, colorsToLookFor); + if (addOtherPlayerLands) { + cl.clear(); + cl.addAll(AllZone.getZone(Constant.Zone.Play,AllZone.GameAction.getOpponent(player)).getCards()); + cl = cl.filter(new CardListFilter() { + public boolean addCard(Card c) { + return c.isLand() && !c.isReflectedLand(); + } + }); + + // Exotic Orchard, which is the only way to get colors from another + // player's lands, looks for colors. Therefore, we should not look + // through another player's lands for colorless mana. This is true + // even if the original card happens to have been a reflecting pool. + if (colorsToLookFor.contains(Constant.Color.Colorless)) { + colorsToLookFor.remove(Constant.Color.Colorless); + } + if (!colorsToLookFor.isEmpty()) { + getManaFromCardList(cl, colorsPlayerCanProduce, colorsToLookFor); + } + } + return colorsPlayerCanProduce; + } + + private static void getManaFromCardList(CardList cl, ArrayList colorsPlayerCanProduce, ArrayListcolorsToLookFor) { + int ix; + // In this routine, the list cl must be a list of lands that are not reflected lands + // Otherwise if both players had Exotic Orchards we might keep searching + // their lands forever. + for (ix = 0; ix < cl.size(); ix++) { + Card otherCard = cl.get(ix); + ArrayList amList = otherCard.getManaAbility(); + for (int im = 0; im < amList.size(); im++) { + // Search all the mana abilities and add colors of mana + Ability_Mana am = amList.get(im); + String newMana = am.mana(); // This call would break for a reflected mana ability + int ic = 0; + // Check if any of the remaining colors are in this mana ability + while (ic < colorsToLookFor.size()) { + if (newMana.contains(Input_PayManaCostUtil.getShortColorString(colorsToLookFor.get(ic)))) { + colorsPlayerCanProduce.add(colorsToLookFor.remove(ic)); + continue; // Don't increment index -- list got smaller + } + ic++; // Only increment if nothing was found + } + + // If the search list is empty stop + if (colorsToLookFor.isEmpty()) { + break; // No point in continuing + } + } // Loop over mana abilities + + if (colorsToLookFor.isEmpty()) { + break; + } + } // loop over list of lands + + } + + + +} // end of Ability_Reflected_Mana + diff --git a/src/forge/Card.java b/src/forge/Card.java index 502c3f7f914..72d96cf7ddd 100644 --- a/src/forge/Card.java +++ b/src/forge/Card.java @@ -1304,6 +1304,10 @@ public class Card extends MyObservable { } public void untap() { + if (isTapped() && isReflectedLand()) { + Ability_Reflected_Mana am = (Ability_Reflected_Mana) getManaAbility().get(0); + am.reset(); + } setTapped(false); } diff --git a/src/forge/CardFactoryUtil.java b/src/forge/CardFactoryUtil.java index 8d10d2e759a..432b41522f5 100644 --- a/src/forge/CardFactoryUtil.java +++ b/src/forge/CardFactoryUtil.java @@ -1637,12 +1637,7 @@ public class CardFactoryUtil { return onLeavesPlay; }//enPump_LeavesPlay - public static Ability_Mana getReflectedManaAbility(final Card card, String colorOrType, String who) { - class ReflectedManaInfo { - String colorChosen; - String colorOrType; - String who; - }; + public static Ability_Reflected_Mana getReflectedManaAbility(final Card card, String colorOrType, String who) { String whoString; if (who.startsWith("Opp")) { @@ -1652,115 +1647,13 @@ public class CardFactoryUtil { String abString = "tap: add to your mana pool one mana of any " + colorOrType.toLowerCase() + " that a land " + whoString + " could produce."; - - - final Ability_Mana theAbility = new Ability_Mana(card, abString) { - private static final long serialVersionUID = 1839038296416458319L; - @Override - public void undo() { - card.untap(); - } - - @Override - public String getTargetPlayer() { - ReflectedManaInfo rfi = (ReflectedManaInfo) this.choices_made[0]; - String targetPlayer; - if (rfi.who.startsWith("Opp")) { - targetPlayer = AllZone.GameAction.getOpponent(card.getController()); - } else { - targetPlayer = card.getController(); - } - return targetPlayer; - } - - @Override - public void resolve() { - // Only tap the card if it was not canceled - ReflectedManaInfo rfi = (ReflectedManaInfo) this.choices_made[0]; - if (rfi.colorChosen != "0") { - card.tap(); - super.resolve(); - } - } - @Override - public String mana() { - ReflectedManaInfo rfi = (ReflectedManaInfo) this.choices_made[0]; - return rfi.colorChosen; - } - - @Override - public ArrayList getPossibleColors() { - ReflectedManaInfo rfi = (ReflectedManaInfo) this.choices_made[0]; - String targetPlayer; - if (rfi.who.startsWith("Opp")) { - targetPlayer = AllZone.GameAction.getOpponent(card.getController()); - } else { - targetPlayer = card.getController(); - } - - ArrayList possibleColors = GameActionUtil.getManaProduceList(targetPlayer, rfi.colorOrType); - return possibleColors; - } - @Override - public boolean canPlay() { - ArrayList possibleColors = this.getPossibleColors(); - if (possibleColors.isEmpty()) { - // Can't use these cards if there are no mana-producing lands in play - return false; - } else { - //if(choices_made[0] == null) choices_made[0] = "0"; - return super.canPlay(); - } - } - - }; - theAbility.undoable=true; - //theAbility.choices_made = new String[1]; - theAbility.choices_made = new ReflectedManaInfo[1]; - ReflectedManaInfo rfi = new ReflectedManaInfo(); - rfi.colorChosen = new String("0"); - rfi.colorOrType = new String(colorOrType); - rfi.who = new String(who); - theAbility.choices_made[0] = rfi; + Ability_Reflected_Mana theAbility = new Ability_Reflected_Mana(card, abString, colorOrType, who); + return theAbility; //((ReflectedManaInfo)theAbility.choices_made[0]).colorChosen = new String("0"); //((ReflectedManaInfo)theAbility.choices_made[0]).colorOrType = new String(colorOrType); //((ReflectedManaInfo)theAbility.choices_made[0]).who = new String(who); - theAbility.setReflectedMana(true); - theAbility.setBeforePayMana(new Input() { - - private static final long serialVersionUID = -2106126894846529731L; - - @Override - public void showMessage() { - ArrayList possibleColors = theAbility.getPossibleColors(); - if (possibleColors.isEmpty()) { - // No mana available: card doesn't tap and nothing happens - ((ReflectedManaInfo)theAbility.choices_made[0]).colorChosen = "0"; - } else if (possibleColors.size() == 1) { - // Card taps for the only mana available - // If there's only one choice, we're not giving the option to cancel. - ((ReflectedManaInfo)theAbility.choices_made[0]).colorChosen = - Input_PayManaCostUtil.getShortColorString(possibleColors.get(0)); - } - else { - // Choose a color of mana to produce. If cancel is chosen, no mana is produced and the - // card doesn't tap. - Object o = AllZone.Display.getChoiceOptional("Select a Color of Mana to Produce", possibleColors.toArray()); - if (o == null) { - ((ReflectedManaInfo)theAbility.choices_made[0]).colorChosen = "0"; - } else { - ((ReflectedManaInfo)theAbility.choices_made[0]).colorChosen = - Input_PayManaCostUtil.getShortColorString((String) o); - } - } - AllZone.Stack.add(theAbility); - stop(); - } - }); - - return theAbility; } // End getReflectedManaAbility public static SpellAbility enPumpCurse_Enchant(final Card sourceCard, final int Power, final int Tough, final String[] extrinsicKeywords, diff --git a/src/forge/ComputerUtil.java b/src/forge/ComputerUtil.java index 974131d54e9..09cdbad89f2 100644 --- a/src/forge/ComputerUtil.java +++ b/src/forge/ComputerUtil.java @@ -284,8 +284,10 @@ public class ComputerUtil { ArrayList colors = new ArrayList(); if (land.isReflectedLand()){ + // Reflected lands (Exotic Orchard and Reflecting Pool) have one + // mana ability, and it has a method called 'getPossibleColors" ArrayList amList = land.getManaAbility(); - colors = amList.get(0).getPossibleColors(); + colors = ((Ability_Reflected_Mana)amList.get(0)).getPossibleColors(); } else { if (land.getKeyword().contains("tap: add B")) colors.add(Constant.Color.Black); diff --git a/src/forge/GameAction.java b/src/forge/GameAction.java index ff74377f13e..d96c8829fe3 100644 --- a/src/forge/GameAction.java +++ b/src/forge/GameAction.java @@ -1300,7 +1300,7 @@ public class GameAction { public void playSpellAbility(SpellAbility sa) { if(sa.getManaCost().equals("0") && sa.getBeforePayMana() == null) { AllZone.Stack.add(sa); - if(sa.isTapAbility()) sa.getSourceCard().tap(); + if(sa.isTapAbility() && !sa.wasCancelled()) sa.getSourceCard().tap(); if(sa.isUntapAbility()) sa.getSourceCard().untap(); return; } diff --git a/src/forge/GameActionUtil.java b/src/forge/GameActionUtil.java index ac117862f0d..db6f7723d5c 100644 --- a/src/forge/GameActionUtil.java +++ b/src/forge/GameActionUtil.java @@ -2688,121 +2688,6 @@ public class GameActionUtil { //END ENDOFTURN CARDS - // Return the list of mana types or colors that the target player's land can produce - // This is used by the mana abilities created by the abReflectedMana keyword - public static ArrayList getManaProduceList(String player, String colorOrType) { - ArrayList colorsPlayerCanProduce = new ArrayList(); - ArrayList colorsToLookFor = new ArrayList(); - - if (colorOrType.startsWith("Type")) { - // Includes colorless (like Reflecting Pool) - for (int ic = 0; ic < Constant.Color.Colors.length; ic++) { - colorsToLookFor.add(Constant.Color.Colors[ic]); - } - } else { - // Excludes colorless (like Exotic Orchard) - for (int ic = 0; ic < Constant.Color.onlyColors.length; ic++) { - colorsToLookFor.add(Constant.Color.onlyColors[ic]); - } - } - - // Build the list of cards to search for mana colors - // First, add all the cards owned by the target player - CardList cl = new CardList(); - cl.addAll(AllZone.getZone(Constant.Zone.Play,player).getCards()); - - // Narrow down the card list to only non-reflected lands - // If during this search we find another reflected land, and it targets a different player - // than this land, then we have to search that player's lands as well - boolean addOtherPlayerLands = false; - int ix = 0; - while (ix < cl.size()) { - Card otherCard = cl.get(ix); - if (otherCard.isLand()) { - if (otherCard.isReflectedLand() && !addOtherPlayerLands) { - ArrayList amList = otherCard.getManaAbility(); - // We assume reflected lands have only one mana ability - // Find out which player it targets - Ability_Mana am = amList.get(0); - String otherTargetPlayer = am.getTargetPlayer(); - - // If the target player of the other land isn't the same as the target player - // of this land, we need to search the sets of mana he can produce as well. - if (!otherTargetPlayer.equals(player)) { - addOtherPlayerLands = true; // We only need to record this decision once - } - // Don't keep reflected lands in the list of lands - cl.remove(ix); - } else { - // Other card is a land but not a reflected land - ix++; // leave in list & look at next card - } - } else { - // Other card is not a land -- remove it - cl.remove(ix); - } - } // while ix < cl.size - - GameActionUtil.getManaFromCardList(cl, colorsPlayerCanProduce, colorsToLookFor); - if (addOtherPlayerLands) { - cl.clear(); - cl.addAll(AllZone.getZone(Constant.Zone.Play,AllZone.GameAction.getOpponent(player)).getCards()); - cl.filter(new CardListFilter() { - public boolean addCard(Card c) { - return c.isLand() && !c.isReflectedLand(); - } - }); - - // Exotic Orchard, which is the only way to get colors from another - // player's lands, looks for colors. Therefore, we should not look - // through another player's lands for colorless mana. This is true - // even if the original card happens to have been a reflecting pool. - if (colorsToLookFor.contains(Constant.Color.Colorless)) { - colorsToLookFor.remove(Constant.Color.Colorless); - } - if (!colorsToLookFor.isEmpty()) { - GameActionUtil.getManaFromCardList(cl, colorsPlayerCanProduce, colorsToLookFor); - } - } - return colorsPlayerCanProduce; - } - - public static void getManaFromCardList(CardList cl, ArrayList colorsPlayerCanProduce, ArrayListcolorsToLookFor) { - int ix; - // In this routine, the list cl must be a list of lands that are not reflected lands - // Otherwise if both players had Exotic Orchards we might keep searching - // their lands forever. - for (ix = 0; ix < cl.size(); ix++) { - Card otherCard = cl.get(ix); - ArrayList amList = otherCard.getManaAbility(); - for (int im = 0; im < amList.size(); im++) { - // Search all the mana abilities and add colors of mana - Ability_Mana am = amList.get(im); - String newMana = am.mana(); // This call would break for a reflected mana ability - int ic = 0; - // Check if any of the remaining colors are in this mana ability - while (ic < colorsToLookFor.size()) { - if (newMana.contains(Input_PayManaCostUtil.getShortColorString(colorsToLookFor.get(ic)))) { - colorsPlayerCanProduce.add(colorsToLookFor.remove(ic)); - continue; // Don't increment index -- list got smaller - } - ic++; // Only increment if nothing was found - } - - // If the search list is empty stop - if (colorsToLookFor.isEmpty()) { - break; // No point in continuing - } - } // Loop over mana abilities - - if (colorsToLookFor.isEmpty()) { - break; - } - } // loop over list of lands - - } - - public static void removeAttackedBlockedThisTurn() { // resets the status of attacked/blocked this turn String player = AllZone.Phase.getActivePlayer(); diff --git a/src/forge/Input_PayManaCostUtil.java b/src/forge/Input_PayManaCostUtil.java index 917527cafb0..095e8a0a51f 100644 --- a/src/forge/Input_PayManaCostUtil.java +++ b/src/forge/Input_PayManaCostUtil.java @@ -4,7 +4,7 @@ import java.util.*; public class Input_PayManaCostUtil { //all mana abilities start with this and typical look like "tap: add G" - //mana abilities are Strings and are retreaved by calling card.getKeyword() + //mana abilities are Strings and are retrieved by calling card.getKeyword() //taps any card that has mana ability, not just land public static ManaCost tapCard(Card card, ManaCost manaCost) { @@ -15,7 +15,7 @@ public class Input_PayManaCostUtil for(String color : Constant.Color.ManaColors) if(manaCost.isNeeded(color)) cneeded.append(getShortColorString(color)); - Iterator it = abilities.iterator();//you can't remove unneded abilitie inside a for(am:abilities) loop :( + Iterator it = abilities.iterator();//you can't remove unneeded abilities inside a for(am:abilities) loop :( while(it.hasNext()) { Ability_Mana ma = it.next(); @@ -28,17 +28,39 @@ public class Input_PayManaCostUtil Ability_Mana chosen = abilities.get(0); if(1 < abilities.size()) { - HashMap ability = new HashMap(); - for(Ability_Mana am : abilities) - ability.put(am.toString(), am); - chosen = (Ability_Mana) AllZone.Display.getChoice("Choose mana ability", abilities.toArray()); + HashMap ability = new HashMap(); + for(Ability_Mana am : abilities) + ability.put(am.toString(), am); + chosen = (Ability_Mana) AllZone.Display.getChoice("Choose mana ability", abilities.toArray()); } - { - AllZone.GameAction.playSpellAbility(chosen); + { + if (chosen.isReflectedMana()) { + // Choose the mana color + Ability_Reflected_Mana arm = (Ability_Reflected_Mana) chosen; + arm.chooseManaColor(); + + // Only resolve if the choice wasn't cancelled and the mana was actually needed + if (arm.wasCancelled()) { + return manaCost; + } else { + String color = chosen.mana(); + if (!manaCost.isNeeded(color)) { + // Don't tap the card if the user chose something invalid + arm.reset(); // Invalidate the choice + return manaCost; + } + } + // A valid choice was made -- resolve the ability and tap the card + arm.resolve(); + arm.getSourceCard().tap(); + } else { + AllZone.GameAction.playSpellAbility(chosen); + } manaCost = AllZone.ManaPool.subtractMana(manaCost, chosen); AllZone.Human_Play.updateObservers();//DO NOT REMOVE THIS, otherwise the cards don't always tap (copied) - return manaCost; + return manaCost; } + } public static ArrayList getManaAbilities(Card card) { @@ -49,6 +71,14 @@ public class Input_PayManaCostUtil { if(mana.contains("1")) return true; if(mana.contains("S") && am.isSnow()) return true; + if(am.isReflectedMana()) { + for( String color:((Ability_Reflected_Mana)am).getPossibleColors()) { + if (mana.contains(getShortColorString(color))) { + return true; + } + } + return false; + } for(String color : ManaPool.getManaParts(am)) if(mana.contains(color)) return true; return false; diff --git a/src/forge/SpellAbility.java b/src/forge/SpellAbility.java index 75aabdec55f..568e4e11516 100644 --- a/src/forge/SpellAbility.java +++ b/src/forge/SpellAbility.java @@ -295,6 +295,11 @@ public abstract class SpellAbility { return flashBackAbility; } + // Only used by Ability_Reflected_Mana, because the user has an option to cancel the input. + // Most spell abilities and even most mana abilities do not need to use this. + public boolean wasCancelled() { + return false; + } public SpellAbility copy() { SpellAbility clone = null;