From 974e5f52821d75f1bb7d030d52fc7d7e1f3baf04 Mon Sep 17 00:00:00 2001 From: Sol Date: Fri, 27 Jul 2012 01:41:11 +0000 Subject: [PATCH] - Simplified handling of hasFizzled - Fizzling will now remove Targets that don't have the same timestamp in their current form as the one that was targeted --- .../card/spellability/TargetChoices.java | 57 ++++++++++++ src/main/java/forge/game/zone/MagicStack.java | 87 ++++++++++--------- 2 files changed, 104 insertions(+), 40 deletions(-) diff --git a/src/main/java/forge/card/spellability/TargetChoices.java b/src/main/java/forge/card/spellability/TargetChoices.java index 204acf3c88e..4099b8804ba 100644 --- a/src/main/java/forge/card/spellability/TargetChoices.java +++ b/src/main/java/forge/card/spellability/TargetChoices.java @@ -124,6 +124,63 @@ public class TargetChoices { return false; } + /** + *

+ * removeTarget. + *

+ * + * @param card + * a {@link forge.Card} object. + * @return a boolean. + */ + public final boolean removeTarget(final Card card) { + // Do I decrement numTargeted for fizzling targets? + if (!this.targetCards.contains(card)) { + this.targetCards.remove(card); + //this.numTargeted--; + return true; + } + return false; + } + + /** + *

+ * removeTarget. + *

+ * + * @param pl + * a {@link forge.game.player.Player} object. + * @return a boolean. + */ + public final boolean removeTarget(final Player pl) { + // Do I decrement numTargeted for fizzling targets? + if (!this.targetPlayers.contains(pl)) { + this.targetPlayers.remove(pl); + //this.numTargeted--; + return true; + } + return false; + } + + /** + *

+ * removeTarget. + *

+ * + * @param sa + * a {@link forge.card.spellability.SpellAbility} object. + * @return a boolean. + */ + public final boolean removeTarget(final SpellAbility sa) { + // Do I decrement numTargeted for fizzling targets? + if (!this.targetSAs.contains(sa)) { + this.targetSAs.remove(sa); + //this.numTargeted--; + return true; + } + return false; + } + /** *

* Getter for the field targetCards. diff --git a/src/main/java/forge/game/zone/MagicStack.java b/src/main/java/forge/game/zone/MagicStack.java index 84429d6330a..7a0936d6ee4 100644 --- a/src/main/java/forge/game/zone/MagicStack.java +++ b/src/main/java/forge/game/zone/MagicStack.java @@ -1171,61 +1171,68 @@ public class MagicStack extends MyObservable { * @return a boolean. */ public final boolean hasFizzled(final SpellAbility sa, final Card source) { - // By default this has not fizzled + // Can't fizzle unless there are some targets boolean fizzle = false; - - boolean firstTarget = true; - - SpellAbility fizzSA = sa; - - while (true) { - final Target tgt = fizzSA.getTarget(); - if ((tgt != null) && (tgt.getMinTargets(source, fizzSA) == 0) && (tgt.getNumTargeted() == 0)) { - // Don't assume fizzled for minTargets == 0 and nothing is - // targeted - } else if (firstTarget - && ((tgt != null) || (fizzSA.getTargetCard() != null) || (fizzSA.getTargetPlayer() != null))) { - // If there is at least 1 target, fizzle switches because ALL - // targets need to be invalid - fizzle = true; - firstTarget = false; + + Target tgt = sa.getTarget(); + if (tgt != null) { + if (tgt.getMinTargets(source, sa) == 0 && tgt.getNumTargeted() == 0) { + // Nothing targeted, and nothing needs to be targeted. } - - if (tgt != null) { + else { + // Some targets were chosen, fizzling for this subability is now possible + fizzle = true; // With multi-targets, as long as one target is still legal, // we'll try to go through as much as possible final ArrayList tgts = tgt.getTargets(); + final TargetChoices choices = tgt.getTargetChoices(); for (final Object o : tgts) { + boolean invalidTarget = false; if (o instanceof Player) { final Player p = (Player) o; - fizzle &= !(p.canBeTargetedBy(fizzSA)); + invalidTarget = !(p.canBeTargetedBy(sa)); + // TODO Remove target? + if (invalidTarget) { + choices.removeTarget(p); + } } - if (o instanceof Card) { + else if (o instanceof Card) { final Card card = (Card) o; - fizzle &= !(CardFactoryUtil.isTargetStillValid(fizzSA, card)); + Card current = AllZoneUtil.getCardState(card); + + invalidTarget = current.getTimestamp() != card.getTimestamp(); + + invalidTarget |= !(CardFactoryUtil.isTargetStillValid(sa, card)); + + if (invalidTarget) { + choices.removeTarget(card); + } + // Remove targets } - if (o instanceof SpellAbility) { + else if (o instanceof SpellAbility) { final SpellAbility tgtSA = (SpellAbility) o; - fizzle &= !(TargetSelection.matchSpellAbility(fizzSA, tgtSA, tgt)); + invalidTarget = !(TargetSelection.matchSpellAbility(sa, tgtSA, tgt)); + // TODO Remove target? + if (invalidTarget) { + choices.removeTarget(tgtSA); + } } - } - } else if (fizzSA.getTargetCard() != null) { - // Fizzling will only work for Abilities that use the Target - // class, - // since the info isn't available otherwise - fizzle &= !CardFactoryUtil.isTargetStillValid(fizzSA, fizzSA.getTargetCard()); - } else if (fizzSA.getTargetPlayer() != null) { - fizzle &= !fizzSA.getTargetPlayer().canBeTargetedBy(fizzSA); - } - - if (fizzSA.getSubAbility() != null) { - fizzSA = fizzSA.getSubAbility(); - } else { - break; + fizzle &= invalidTarget; + } } } - - return fizzle; + else if (sa.getTargetCard() != null) { + fizzle = !CardFactoryUtil.isTargetStillValid(sa, sa.getTargetCard()); + } + else if (sa.getTargetPlayer() != null) { + fizzle = !sa.getTargetPlayer().canBeTargetedBy(sa); + } + + if (sa.getSubAbility() == null) { + return fizzle; + } + + return hasFizzled(sa.getSubAbility(), source) && fizzle; } /**