diff --git a/src/forge/AbilityFactory.java b/src/forge/AbilityFactory.java index f90dfae5ef6..737382b9df9 100644 --- a/src/forge/AbilityFactory.java +++ b/src/forge/AbilityFactory.java @@ -143,6 +143,9 @@ public class AbilityFactory { abTgt = new Target("TgtV", mapParams.get("TgtPrompt"), mapParams.get("ValidTgts").split(",")); else abTgt = new Target(mapParams.get("Tgt")); + + if (mapParams.containsKey("TgtZone")) // if Targeting something not in play, this Key should be set + abTgt.setZone(mapParams.get("TgtZone")); } hasSubAb = mapParams.containsKey("SubAbility"); diff --git a/src/forge/CardFactoryUtil.java b/src/forge/CardFactoryUtil.java index 5dafc4463a2..25d48d54606 100644 --- a/src/forge/CardFactoryUtil.java +++ b/src/forge/CardFactoryUtil.java @@ -3293,6 +3293,29 @@ public class CardFactoryUtil { return result; } + public static boolean isTargetStillValid(SpellAbility ability, Card target) { + Card source = ability.getSourceCard(); + Target tgt = ability.getTarget(); + if (tgt != null){ + // Reconfirm the Validity of a TgtValid, or if the Creature is still a Creature + if (tgt.canTgtValid() && !target.isValidCard(tgt.getValidTgts(), ability.getActivatingPlayer())) + return false; + else if (tgt.canTgtCreature() && !target.isCreature()) + return false; + + // Check if the target is in the zone it needs to be in to be targeted + if (!AllZone.getZone(target).is(tgt.getZone())) + return false; + } + + // If an Aura's target is removed before it resolves, the Aura fizzles + if (source.isAura() && !AllZone.getZone(target).is(Constant.Zone.Play)) + return false; + + // Make sure it's still targetable as well + return canTarget(source, target); + } + public static boolean canTarget(SpellAbility ability, Card target) { return canTarget(ability.getSourceCard(), target); } @@ -3302,6 +3325,11 @@ public class CardFactoryUtil { return c.isWhite() || c.isBlue() || c.isBlack() || c.isRed() || c.isGreen(); } + public static boolean canTarget(Card spell, String player) { + Card c = player.equals(Constant.Player.Computer) ? AllZone.CardFactory.ComputerNullCard : AllZone.CardFactory.HumanNullCard; + return canTarget(spell, c); + } + public static boolean canTarget(Card spell, Card target) { if(target == null) return true; //System.out.println("Target:" + target); diff --git a/src/forge/GameAction.java b/src/forge/GameAction.java index 9725e375046..c7e534bf524 100644 --- a/src/forge/GameAction.java +++ b/src/forge/GameAction.java @@ -3083,10 +3083,6 @@ public class GameAction { return false; }//isAttached(Card c) - public boolean canTarget(String targetPlayer) { - return true; - } - public void playCard(Card c) { HashMap map = new HashMap(); SpellAbility[] abilities = canPlaySpellAbility(c.getSpellAbility()); diff --git a/src/forge/Input_StackNotEmpty.java b/src/forge/Input_StackNotEmpty.java index b1ed26dbc96..b3b644993a1 100644 --- a/src/forge/Input_StackNotEmpty.java +++ b/src/forge/Input_StackNotEmpty.java @@ -1,6 +1,8 @@ package forge; +import com.esotericsoftware.minlog.Log; + public class Input_StackNotEmpty extends Input implements java.io.Serializable { private static final long serialVersionUID = -3015125043127874730L; @@ -22,53 +24,68 @@ public class Input_StackNotEmpty extends Input implements java.io.Serializable { SpellAbility sa = AllZone.Stack.pop(); Card c = sa.getSourceCard(); + boolean fizzle = false; - final Card crd = c; - if(sa.isBuyBackAbility()) { - c.addReplaceMoveToGraveyardCommand(new Command() { - private static final long serialVersionUID = -2559488318473330418L; - - public void execute() { - PlayerZone hand = AllZone.getZone(Constant.Zone.Hand, crd.getController()); - AllZone.GameAction.moveTo(hand, crd); - } - }); + if (sa.getTargetCard() != null){ + fizzle = !CardFactoryUtil.isTargetStillValid(sa, sa.getTargetCard()); + } + else if (sa.getTargetPlayer() != "") { + fizzle = !CardFactoryUtil.canTarget(c, sa.getTargetPlayer()); } - // To stop Copied Spells from going into the graveyard. - if(sa.getSourceCard().isCopiedSpell()) { - c.addReplaceMoveToGraveyardCommand(new Command() { - private static final long serialVersionUID = -2559488318473330418L; - public void execute() { - } - }); + if (!fizzle){ + final Card crd = c; + if(sa.isBuyBackAbility()) { + c.addReplaceMoveToGraveyardCommand(new Command() { + private static final long serialVersionUID = -2559488318473330418L; + + public void execute() { + PlayerZone hand = AllZone.getZone(Constant.Zone.Hand, crd.getController()); + AllZone.GameAction.moveTo(hand, crd); + } + }); + } + + // To stop Copied Spells from going into the graveyard. + if(sa.getSourceCard().isCopiedSpell()) { + c.addReplaceMoveToGraveyardCommand(new Command() { + private static final long serialVersionUID = -2559488318473330418L; + public void execute() { + } + }); + } + sa.resolve(); + + if(sa.getSourceCard().getKeyword().contains("Draw a card.") + && !(sa.getSourceCard().getKeyword().contains("Ripple:4") && sa.isAbility())) + AllZone.GameAction.drawCard(sa.getSourceCard().getController()); + + if(sa.getSourceCard().getKeyword().contains("Proliferate")) + AllZone.GameAction.getProliferateAbility(sa.getSourceCard(), "0").resolve(); + + for(int i = 0; i < sa.getSourceCard().getKeyword().size(); i++) { + String k = sa.getSourceCard().getKeyword().get(i); + if(k.startsWith("Scry")) { + String kk[] = k.split(" "); + AllZone.GameAction.scry(sa.getSourceCard().getController(), Integer.parseInt(kk[1])); + } + } + } - sa.resolve(); - - if(sa.getSourceCard().getKeyword().contains("Draw a card.") - && !(sa.getSourceCard().getKeyword().contains("Ripple:4") && sa.isAbility())) - AllZone.GameAction.drawCard(sa.getSourceCard().getController()); - - if(sa.getSourceCard().getKeyword().contains("Proliferate")) - AllZone.GameAction.getProliferateAbility(sa.getSourceCard(), "0").resolve(); - - for(int i = 0; i < sa.getSourceCard().getKeyword().size(); i++) { - String k = sa.getSourceCard().getKeyword().get(i); - if(k.startsWith("Scry")) { - String kk[] = k.split(" "); - AllZone.GameAction.scry(sa.getSourceCard().getController(), Integer.parseInt(kk[1])); - } + else{ + // Spell fizzles, alert player? + Log.debug(c.getName() + " ability fizzles."); } + AllZone.GameAction.checkStateEffects(); //special consideration for "Beacon of Unrest" and other "Beacon" cards - if((c.isInstant() || c.isSorcery()) && (!c.getName().startsWith("Beacon")) + if((c.isInstant() || c.isSorcery() || (c.isAura() && fizzle)) && (!c.getName().startsWith("Beacon")) && (!c.getName().startsWith("Pulse")) && !AllZone.GameAction.isCardRemovedFromGame(c)) //hack to make flashback work { if(c.getReplaceMoveToGraveyard().size() == 0) AllZone.GameAction.moveToGraveyard(c); else c.replaceMoveToGraveyard(); } - //update all zones, something things arent' updated for some reason AllZone.Human_Hand.updateObservers(); diff --git a/src/forge/Target.java b/src/forge/Target.java index 07fe34a5d6e..5d411087d42 100644 --- a/src/forge/Target.java +++ b/src/forge/Target.java @@ -18,6 +18,10 @@ public class Target { public String getVTSelection() { return vtSelection; } public void setVTSelection(String vtSelStr) { vtSelection = vtSelStr; } + private String tgtZone = Constant.Zone.Play; + public void setZone(String tZone) { tgtZone = tZone; } + public String getZone() { return tgtZone; } + private int minTargets = 0; public int getMinTargets() { return minTargets; } private int maxTargets = 0;