diff --git a/forge-gui/src/main/java/forge/Card.java b/forge-gui/src/main/java/forge/Card.java index 9d018324fea..ea2fee73d8d 100644 --- a/forge-gui/src/main/java/forge/Card.java +++ b/forge-gui/src/main/java/forge/Card.java @@ -2658,8 +2658,8 @@ public class Card extends GameEntity implements Comparable { * @return a {@link java.util.ArrayList} object. */ public final ArrayList getSpellAbilities() { - final ArrayList res = new ArrayList(this.getCharacteristics().getSpellAbility()); - res.addAll(this.getManaAbility()); + final ArrayList res = new ArrayList(this.getManaAbility()); + res.addAll(this.getCharacteristics().getSpellAbility()); return res; } @@ -8669,7 +8669,7 @@ public class Card extends GameEntity implements Comparable { * @param player * @return */ - public List getAllPossibleAbilities(Player player) { + public List getAllPossibleAbilities(Player player, boolean removeUnplayable) { // this can only be called by the Human final List abilities = new ArrayList(); @@ -8678,14 +8678,16 @@ public class Card extends GameEntity implements Comparable { abilities.add(sa); abilities.addAll(GameActionUtil.getAlternativeCosts(sa)); } - - for (int iSa = 0; iSa < abilities.size();) { - SpellAbility sa = abilities.get(iSa); + + for (int i = abilities.size() - 1; i >= 0; i--) { + SpellAbility sa = abilities.get(i); sa.setActivatingPlayer(player); - if (!sa.canPlay()) - abilities.remove(iSa); - else - iSa++; + if (removeUnplayable && !sa.canPlay()) { + abilities.remove(i); + } + else if (!sa.isPossible()) { + abilities.remove(i); + } } if (isLand() && player.canPlayLand(this)) { diff --git a/forge-gui/src/main/java/forge/card/spellability/AbilityActivated.java b/forge-gui/src/main/java/forge/card/spellability/AbilityActivated.java index 8a762b9fbc9..6ae8714dc08 100644 --- a/forge-gui/src/main/java/forge/card/spellability/AbilityActivated.java +++ b/forge-gui/src/main/java/forge/card/spellability/AbilityActivated.java @@ -117,8 +117,19 @@ public abstract class AbilityActivated extends SpellAbility implements java.io.S return CostPayment.canPayAdditionalCosts(this.getPayCosts(), this); } - - /* (non-Javadoc) - * @see forge.card.spellability.SpellAbility#resolve() - */ + + /** {@inheritDoc} */ + @Override + public boolean isPossible() { + //consider activated abilities possible always and simply disable if not currently playable + //the exception is to consider them not possible if there's a zone or activator restriction that's not met + return this.getRestrictions().checkZoneRestrictions(this.getSourceCard(), this) && + this.getRestrictions().checkActivatorRestrictions(this.getSourceCard(), this); + } + + /** {@inheritDoc} */ + @Override + public boolean promptIfOnlyPossibleAbility() { + return !this.isManaAbility(); //prompt user for non-mana activated abilities even is only possible ability + } } diff --git a/forge-gui/src/main/java/forge/card/spellability/Spell.java b/forge-gui/src/main/java/forge/card/spellability/Spell.java index 747a3c12808..ee2a1269c8a 100644 --- a/forge-gui/src/main/java/forge/card/spellability/Spell.java +++ b/forge-gui/src/main/java/forge/card/spellability/Spell.java @@ -68,16 +68,18 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable /** {@inheritDoc} */ @Override public boolean canPlay() { - final Game game = getActivatingPlayer().getGame(); - if (game.getStack().isSplitSecondOnStack()) { - return false; - } - final Card card = this.getSourceCard(); - Player activator = this.getActivatingPlayer(); if (activator == null) { - activator = this.getSourceCard().getController(); + activator = card.getController(); + if (activator == null) { + return false; + } + } + + final Game game = activator.getGame(); + if (game.getStack().isSplitSecondOnStack()) { + return false; } if (!(card.isInstant() || activator.canCastSorcery() || card.hasKeyword("Flash") diff --git a/forge-gui/src/main/java/forge/card/spellability/SpellAbility.java b/forge-gui/src/main/java/forge/card/spellability/SpellAbility.java index 39652d8c338..3c526a441df 100644 --- a/forge-gui/src/main/java/forge/card/spellability/SpellAbility.java +++ b/forge-gui/src/main/java/forge/card/spellability/SpellAbility.java @@ -180,6 +180,28 @@ public abstract class SpellAbility extends GameObject implements ISpellAbility { * @return a boolean. */ public abstract boolean canPlay(); + + /** + *

+ * isPossible. + *

+ * + * @return a boolean. + */ + public boolean isPossible() { + return canPlay(); //by default, ability is only possible if it can be played + } + + /** + *

+ * promptIfOnlyPossibleAbility. + *

+ * + * @return a boolean. + */ + public boolean promptIfOnlyPossibleAbility() { + return false; //by default, don't prompt user if ability is only possible ability + } // all Spell's and Abilities must override this method /** diff --git a/forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java index 52978f59ae8..06cc79d04d5 100644 --- a/forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java @@ -85,29 +85,42 @@ public class PlayerControllerHuman extends PlayerController { * Uses GUI to learn which spell the player (human in our case) would like to play */ public SpellAbility getAbilityToPlay(List abilities, MouseEvent triggerEvent) { + if (triggerEvent == null) { + List playableAbilities = new ArrayList(); + for (SpellAbility ab : abilities) { + if (ab.canPlay()) { + playableAbilities.add(ab); + } + } + if (playableAbilities.isEmpty()) { + return null; + } + if (playableAbilities.size() == 1 && !playableAbilities.get(0).promptIfOnlyPossibleAbility()) { + return playableAbilities.get(0); + } + return GuiChoose.oneOrNone("Choose ability to play", playableAbilities); + } + if (abilities.isEmpty()) { return null; } - if (abilities.size() == 1) { + if (abilities.size() == 1 && !abilities.get(0).promptIfOnlyPossibleAbility()) { return abilities.get(0); } - if (triggerEvent == null) { - return GuiChoose.oneOrNone("Choose ability to play", abilities); - } - //show menu if mouse triggered ability + //show menu if mouse was trigger for ability final JPopupMenu menu = new JPopupMenu("Abilities"); int shortcut = KeyEvent.VK_1; //use number keys as shortcuts for abilities 1-9 for (final SpellAbility ab : abilities) { - GuiUtils.addMenuItem(menu, ab.toString(), + GuiUtils.addMenuItem(menu, ab.toString(), shortcut > 0 ? KeyStroke.getKeyStroke(shortcut, 0) : null, new Runnable() { @Override public void run() { CMessage.SINGLETON_INSTANCE.getInputControl().selectAbility(ab); } - }); + }, ab.getActivatingPlayer() == null || ab.canPlay()); //check getActivatingPlayer() to account for playing lands shortcut++; if (shortcut > KeyEvent.VK_9) { shortcut = 0; //stop adding shortcuts after 9 diff --git a/forge-gui/src/main/java/forge/gui/input/InputPassPriority.java b/forge-gui/src/main/java/forge/gui/input/InputPassPriority.java index 5e06b43c83b..9c2c5c7c0a1 100644 --- a/forge-gui/src/main/java/forge/gui/input/InputPassPriority.java +++ b/forge-gui/src/main/java/forge/gui/input/InputPassPriority.java @@ -63,7 +63,7 @@ public class InputPassPriority extends InputSyncronizedBase { @Override protected void onCardSelected(final Card card, final MouseEvent triggerEvent) { - List abilities = card.getAllPossibleAbilities(player); + List abilities = card.getAllPossibleAbilities(player, false); if (abilities.isEmpty()) { flashIncorrectAction(); return; diff --git a/forge-gui/src/main/java/forge/gui/match/nonsingleton/CField.java b/forge-gui/src/main/java/forge/gui/match/nonsingleton/CField.java index ce7d2a4faae..20491b24549 100644 --- a/forge-gui/src/main/java/forge/gui/match/nonsingleton/CField.java +++ b/forge-gui/src/main/java/forge/gui/match/nonsingleton/CField.java @@ -102,7 +102,7 @@ public class CField implements ICDoc { // TODO: "can play" check needed! // should I check for who owns these cards? Are there any abilities to be played from opponent's graveyard? - final SpellAbility ab = player.getController().getAbilityToPlay(c.getAllPossibleAbilities(player)); + final SpellAbility ab = player.getController().getAbilityToPlay(c.getAllPossibleAbilities(player, true)); if ( null != ab) { game.getAction().invoke(new Runnable(){ @Override public void run(){ HumanPlay.playSpellAbility(player, ab);