From 60f3b788b4440457ec53687575a189bc14388316 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 1 Jun 2013 21:40:11 +0000 Subject: [PATCH] MagicStack - cleanup (made some methods private, inlined whatever is short and single-time used or was accessor to field) AbilityUtils.resolve does not need extra parameter usedStack - Stack class can call finishResolving from its own code HumanPlaySpellAbility - managed to simplify the code by groupping all prerequisites collection into a single exression --- .../java/forge/card/ability/AbilityUtils.java | 31 +- .../card/ability/SpellAbilityEffect.java | 2 +- .../ability/effects/ChooseGenericEffect.java | 2 +- .../card/ability/effects/ClashEffect.java | 4 +- .../ability/effects/CountersRemoveEffect.java | 2 +- .../card/ability/effects/FlipCoinEffect.java | 8 +- .../ability/effects/RepeatEachEffect.java | 6 +- .../card/ability/effects/RepeatEffect.java | 2 +- .../card/ability/effects/TwoPilesEffect.java | 4 +- .../spellability/HumanPlaySpellAbility.java | 88 ++--- src/main/java/forge/game/ai/ComputerUtil.java | 2 +- .../java/forge/game/ai/ComputerUtilMana.java | 2 +- .../java/forge/game/phase/PhaseHandler.java | 3 +- .../java/forge/game/player/HumanPlay.java | 6 +- src/main/java/forge/game/player/Player.java | 4 +- src/main/java/forge/game/zone/MagicStack.java | 350 ++++++------------ 16 files changed, 175 insertions(+), 341 deletions(-) diff --git a/src/main/java/forge/card/ability/AbilityUtils.java b/src/main/java/forge/card/ability/AbilityUtils.java index dd036c9553d..fff2e92e149 100644 --- a/src/main/java/forge/card/ability/AbilityUtils.java +++ b/src/main/java/forge/card/ability/AbilityUtils.java @@ -1020,7 +1020,7 @@ public class AbilityUtils { // BELOW ARE resove() METHOD AND ITS DEPENDANTS, CONSIDER MOVING TO DEDICATED CLASS // ///////////////////////////////////////////////////////////////////////////////////// - public static void resolve(final SpellAbility sa, final boolean usedStack) { + public static void resolve(final SpellAbility sa) { if (sa == null) { return; } @@ -1028,44 +1028,38 @@ public class AbilityUtils { if (api == null) { sa.resolve(); if (sa.getSubAbility() != null) { - resolve(sa.getSubAbility(), usedStack); + resolve(sa.getSubAbility()); } return; } - AbilityUtils.resolveApiAbility(sa, usedStack, sa.getActivatingPlayer().getGame()); + AbilityUtils.resolveApiAbility(sa, sa.getActivatingPlayer().getGame()); } - private static void resolveSubAbilities(final SpellAbility sa, boolean usedStack, final Game game) { + private static void resolveSubAbilities(final SpellAbility sa, final Game game) { final AbilitySub abSub = sa.getSubAbility(); if (abSub == null || sa.isWrapper()) { - // every resolving spellAbility will end here - if (usedStack) { - SpellAbility root = sa.getRootAbility(); - // static abilities will get refreshed from SBE check. - game.getStack().finishResolving(root, false); - } return; } game.getAction().checkStaticAbilities(); // this will refresh continuous abilities for players and permanents. - AbilityUtils.resolveApiAbility(abSub, usedStack, game); + AbilityUtils.resolveApiAbility(abSub, game); } - private static void resolveApiAbility(final SpellAbility sa, boolean usedStack, final Game game) { + private static void resolveApiAbility(final SpellAbility sa, final Game game) { // check conditions if (sa.getConditions().areMet(sa)) { if (sa.isWrapper() || StringUtils.isBlank(sa.getParam("UnlessCost"))) { sa.resolve(); } else { - handleUnlessCost(sa, usedStack, game); + handleUnlessCost(sa, game); return; } } - resolveSubAbilities(sa, usedStack, game); + resolveSubAbilities(sa, game); } - private static void handleUnlessCost(final SpellAbility sa, final boolean usedStack, final Game game) { + private static void handleUnlessCost(final SpellAbility sa, final Game game) { final Card source = sa.getSourceCard(); String unlessCost = sa.getParam("UnlessCost"); unlessCost = unlessCost.trim(); @@ -1084,7 +1078,7 @@ public class AbilityUtils { } else if (unlessCost.equals("RememberedCostMinus2")) { if (source.getRemembered().isEmpty() || !(source.getRemembered().get(0) instanceof Card)) { sa.resolve(); - resolveSubAbilities(sa, usedStack, game); + resolveSubAbilities(sa, game); } Card rememberedCard = (Card) source.getRemembered().get(0); unlessCost = rememberedCard.getManaCost().toString(); @@ -1124,10 +1118,7 @@ public class AbilityUtils { } if ( paid && execSubsWhenPaid || !paid && execSubsWhenNotPaid ) { // switched refers only to main ability! - resolveSubAbilities(sa, usedStack, game); - } else if (usedStack) { - SpellAbility root = sa.getRootAbility(); - game.getStack().finishResolving(root, false); + resolveSubAbilities(sa, game); } } diff --git a/src/main/java/forge/card/ability/SpellAbilityEffect.java b/src/main/java/forge/card/ability/SpellAbilityEffect.java index cd65df98967..78fe16a4c41 100644 --- a/src/main/java/forge/card/ability/SpellAbilityEffect.java +++ b/src/main/java/forge/card/ability/SpellAbilityEffect.java @@ -40,7 +40,7 @@ import forge.game.player.Player; final AbilitySub abSub = sa.getSubAbility(); if (abSub != null) { sa.setUndoable(false); - AbilityUtils.resolve(abSub, false); + AbilityUtils.resolve(abSub); } } diff --git a/src/main/java/forge/card/ability/effects/ChooseGenericEffect.java b/src/main/java/forge/card/ability/effects/ChooseGenericEffect.java index e1c469bca75..c0dedc6f317 100644 --- a/src/main/java/forge/card/ability/effects/ChooseGenericEffect.java +++ b/src/main/java/forge/card/ability/effects/ChooseGenericEffect.java @@ -62,7 +62,7 @@ public class ChooseGenericEffect extends SpellAbilityEffect { } chosenSA.setActivatingPlayer(sa.getSourceCard().getController()); ((AbilitySub) chosenSA).setParent(sa); - AbilityUtils.resolve(chosenSA, false); + AbilityUtils.resolve(chosenSA); } } diff --git a/src/main/java/forge/card/ability/effects/ClashEffect.java b/src/main/java/forge/card/ability/effects/ClashEffect.java index 4b3dbcbc54c..373b4bb8795 100644 --- a/src/main/java/forge/card/ability/effects/ClashEffect.java +++ b/src/main/java/forge/card/ability/effects/ClashEffect.java @@ -43,7 +43,7 @@ public class ClashEffect extends SpellAbilityEffect { win.setActivatingPlayer(sa.getSourceCard().getController()); ((AbilitySub) win).setParent(sa); - AbilityUtils.resolve(win, false); + AbilityUtils.resolve(win); } runParams.put("Won", "True"); } else { @@ -53,7 +53,7 @@ public class ClashEffect extends SpellAbilityEffect { otherwise.setActivatingPlayer(sa.getSourceCard().getController()); ((AbilitySub) otherwise).setParent(sa); - AbilityUtils.resolve(otherwise, false); + AbilityUtils.resolve(otherwise); } runParams.put("Won", "False"); } diff --git a/src/main/java/forge/card/ability/effects/CountersRemoveEffect.java b/src/main/java/forge/card/ability/effects/CountersRemoveEffect.java index 36c495b4eff..a20ed4d0f74 100644 --- a/src/main/java/forge/card/ability/effects/CountersRemoveEffect.java +++ b/src/main/java/forge/card/ability/effects/CountersRemoveEffect.java @@ -126,7 +126,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect { // better logic to pick a counter type and probably // an initial target // find first nonzero counter on target - for (Object key : tgtCounters.keySet()) { + for (CounterType key : tgtCounters.keySet()) { if (tgtCounters.get(key) > 0) { chosenType = (CounterType) key; break; diff --git a/src/main/java/forge/card/ability/effects/FlipCoinEffect.java b/src/main/java/forge/card/ability/effects/FlipCoinEffect.java index fcf4f2441e5..e01a33f23d4 100644 --- a/src/main/java/forge/card/ability/effects/FlipCoinEffect.java +++ b/src/main/java/forge/card/ability/effects/FlipCoinEffect.java @@ -76,7 +76,7 @@ public class FlipCoinEffect extends SpellAbilityEffect { heads.setActivatingPlayer(player); ((AbilitySub) heads).setParent(sa); - AbilityUtils.resolve(heads, false); + AbilityUtils.resolve(heads); } } else { if (sa.hasParam("TailsSubAbility")) { @@ -84,7 +84,7 @@ public class FlipCoinEffect extends SpellAbilityEffect { tails.setActivatingPlayer(player); ((AbilitySub) tails).setParent(sa); - AbilityUtils.resolve(tails, false); + AbilityUtils.resolve(tails); } } } else { @@ -97,7 +97,7 @@ public class FlipCoinEffect extends SpellAbilityEffect { win.setActivatingPlayer(player); ((AbilitySub) win).setParent(sa); - AbilityUtils.resolve(win, false); + AbilityUtils.resolve(win); } // runParams.put("Won","True"); } else { @@ -109,7 +109,7 @@ public class FlipCoinEffect extends SpellAbilityEffect { lose.setActivatingPlayer(player); ((AbilitySub) lose).setParent(sa); - AbilityUtils.resolve(lose, false); + AbilityUtils.resolve(lose); } // runParams.put("Won","False"); } diff --git a/src/main/java/forge/card/ability/effects/RepeatEachEffect.java b/src/main/java/forge/card/ability/effects/RepeatEachEffect.java index 75c0ed59cae..fe59138fdfa 100644 --- a/src/main/java/forge/card/ability/effects/RepeatEachEffect.java +++ b/src/main/java/forge/card/ability/effects/RepeatEachEffect.java @@ -70,7 +70,7 @@ public class RepeatEachEffect extends SpellAbilityEffect { source.addRemembered(card); } - AbilityUtils.resolve(repeat, false); + AbilityUtils.resolve(repeat); if (useImprinted) { source.removeImprinted(card); } else { @@ -84,7 +84,7 @@ public class RepeatEachEffect extends SpellAbilityEffect { for (Player player : repeatPlayers) { source.addRemembered(player); - AbilityUtils.resolve(repeat, false); + AbilityUtils.resolve(repeat); source.removeRemembered(player); } } @@ -100,7 +100,7 @@ public class RepeatEachEffect extends SpellAbilityEffect { sb.append("Number$").append(target.getCounters(type)); source.setSVar("RepeatSVarCounter", type.getName().toUpperCase()); source.setSVar("RepeatCounterAmount", sb.toString()); - AbilityUtils.resolve(repeat, false); + AbilityUtils.resolve(repeat); } } } diff --git a/src/main/java/forge/card/ability/effects/RepeatEffect.java b/src/main/java/forge/card/ability/effects/RepeatEffect.java index 1b18d4c472d..bebd647d694 100644 --- a/src/main/java/forge/card/ability/effects/RepeatEffect.java +++ b/src/main/java/forge/card/ability/effects/RepeatEffect.java @@ -40,7 +40,7 @@ public class RepeatEffect extends SpellAbilityEffect { //execute repeat ability at least once int count = 0; do { - AbilityUtils.resolve(repeat, false); + AbilityUtils.resolve(repeat); count++; if (maxRepeat != null && maxRepeat <= count) { // TODO Replace Infinite Loop Break with a game draw. Here are the scenarios that can cause this: diff --git a/src/main/java/forge/card/ability/effects/TwoPilesEffect.java b/src/main/java/forge/card/ability/effects/TwoPilesEffect.java index 58238b8d5be..a022b1dae4d 100644 --- a/src/main/java/forge/card/ability/effects/TwoPilesEffect.java +++ b/src/main/java/forge/card/ability/effects/TwoPilesEffect.java @@ -140,7 +140,7 @@ public class TwoPilesEffect extends SpellAbilityEffect { action.setActivatingPlayer(sa.getActivatingPlayer()); ((AbilitySub) action).setParent(sa); - AbilityUtils.resolve(action, false); + AbilityUtils.resolve(action); } // take action on the chosen pile @@ -160,7 +160,7 @@ public class TwoPilesEffect extends SpellAbilityEffect { action.setActivatingPlayer(sa.getActivatingPlayer()); ((AbilitySub) action).setParent(sa); - AbilityUtils.resolve(action, false); + AbilityUtils.resolve(action); } } } diff --git a/src/main/java/forge/card/spellability/HumanPlaySpellAbility.java b/src/main/java/forge/card/spellability/HumanPlaySpellAbility.java index fd373b58900..d177e9da286 100644 --- a/src/main/java/forge/card/spellability/HumanPlaySpellAbility.java +++ b/src/main/java/forge/card/spellability/HumanPlaySpellAbility.java @@ -64,59 +64,50 @@ public class HumanPlaySpellAbility { // freeze Stack. No abilities should go onto the stack while I'm filling requirements. game.getStack().freezeStack(); - // Announce things like how many times you want to Multikick or the value of X - if (!this.announceRequirements()) { + // This line makes use of short-circuit evaluation of boolean values, that is each subsequent argument + // is only executed or evaluated if the first argument does not suffice to determine the value of the expression + boolean prerequisitesMet = this.announceValuesLikeX() + && ( isAlreadyTargeted || setupTargets() ) + && ( isFree || this.payment.payCost(game) ); + + + if (!prerequisitesMet) { rollbackAbility(fromZone, zonePosition); return; } - // Skip to paying if parent ability doesn't target and has no - // subAbilities. - // (or trigger case where its already targeted) - if (!isAlreadyTargeted) { - - SpellAbility beingTargeted = ability; - do { - Target tgt = beingTargeted.getTarget(); - if( tgt != null && tgt.doesTarget()) { - clearTargets(beingTargeted); - final TargetSelection select = new TargetSelection(beingTargeted); - if (!select.chooseTargets() ) { - rollbackAbility(fromZone, zonePosition); - return; - } - } - beingTargeted = beingTargeted.getSubAbility(); - } while (beingTargeted != null); - - } - - // Payment - boolean paymentMade = isFree; - - if (!paymentMade) { - paymentMade = this.payment.payCost(game); - } - - if (!paymentMade) { - rollbackAbility(fromZone, zonePosition); - return; - } - else { - if (isFree || this.payment.isFullyPaid()) { - if (skipStack) { - AbilityUtils.resolve(this.ability, false); - } else { - this.enusureAbilityHasDescription(this.ability); - this.ability.getActivatingPlayer().getManaPool().clearManaPaid(this.ability, false); - game.getStack().addAndUnfreeze(this.ability); - } - - // no worries here. The same thread must resolve, and by this moment ability will have been resolved already - clearTargets(ability); - //game.getAction().checkStateEffects(); + + if (isFree || this.payment.isFullyPaid()) { + if (skipStack) { + AbilityUtils.resolve(this.ability); + } else { + this.enusureAbilityHasDescription(this.ability); + this.ability.getActivatingPlayer().getManaPool().clearManaPaid(this.ability, false); + game.getStack().addAndUnfreeze(this.ability); } + + // no worries here. The same thread must resolve, and by this moment ability will have been resolved already + clearTargets(ability); } + + } + + private final boolean setupTargets() { + // Skip to paying if parent ability doesn't target and has no subAbilities. + // (or trigger case where its already targeted) + SpellAbility beingTargeted = ability; + do { + Target tgt = beingTargeted.getTarget(); + if( tgt != null && tgt.doesTarget()) { + clearTargets(beingTargeted); + final TargetSelection select = new TargetSelection(beingTargeted); + if (!select.chooseTargets() ) { + return false; + } + } + beingTargeted = beingTargeted.getSubAbility(); + } while (beingTargeted != null); + return true; } public final void clearTargets(SpellAbility ability) { @@ -147,11 +138,10 @@ public class HumanPlaySpellAbility { this.ability.resetOnceResolved(); this.payment.refundPayment(); game.getStack().clearFrozen(); - // Singletons.getModel().getGame().getStack().removeFromFrozenStack(this.ability); } - private boolean announceRequirements() { + private boolean announceValuesLikeX() { // Announcing Requirements like Choosing X or Multikicker // SA Params as comma delimited list String announce = ability.getParam("Announce"); diff --git a/src/main/java/forge/game/ai/ComputerUtil.java b/src/main/java/forge/game/ai/ComputerUtil.java index ce40596f933..74703c4e77f 100644 --- a/src/main/java/forge/game/ai/ComputerUtil.java +++ b/src/main/java/forge/game/ai/ComputerUtil.java @@ -318,7 +318,7 @@ public class ComputerUtil { pay.payComputerCosts(ai, game); } - AbilityUtils.resolve(sa, false); + AbilityUtils.resolve(sa); // destroys creatures if they have lethal damage, etc.. //game.getAction().checkStateEffects(); diff --git a/src/main/java/forge/game/ai/ComputerUtilMana.java b/src/main/java/forge/game/ai/ComputerUtilMana.java index f294e008c92..88008e9afb4 100644 --- a/src/main/java/forge/game/ai/ComputerUtilMana.java +++ b/src/main/java/forge/game/ai/ComputerUtilMana.java @@ -185,7 +185,7 @@ public class ComputerUtilMana { saPayment.getSourceCard().tap(); } - AbilityUtils.resolve(saPayment, false); + AbilityUtils.resolve(saPayment); // subtract mana from mana pool manapool.payManaFromAbility(sa, cost, saPayment); diff --git a/src/main/java/forge/game/phase/PhaseHandler.java b/src/main/java/forge/game/phase/PhaseHandler.java index 0c09bb2cded..42f79b65868 100644 --- a/src/main/java/forge/game/phase/PhaseHandler.java +++ b/src/main/java/forge/game/phase/PhaseHandler.java @@ -477,8 +477,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable { */ private Player handleNextTurn() { - game.getStack().setCardsCastLastTurn(); - game.getStack().clearCardsCastThisTurn(); + game.getStack().onNextTurn(); for (final Player p1 : game.getPlayers()) { for (final ZoneType z : Player.ALL_ZONES) { diff --git a/src/main/java/forge/game/player/HumanPlay.java b/src/main/java/forge/game/player/HumanPlay.java index f33838ce8e7..d388543772d 100644 --- a/src/main/java/forge/game/player/HumanPlay.java +++ b/src/main/java/forge/game/player/HumanPlay.java @@ -34,7 +34,6 @@ import forge.card.cost.CostSacrifice; import forge.card.cost.CostTapType; import forge.card.mana.ManaCost; import forge.card.mana.ManaCostBeingPaid; -import forge.card.mana.ManaCostShard; import forge.card.spellability.Ability; import forge.card.spellability.HumanPlaySpellAbility; import forge.card.spellability.SpellAbility; @@ -210,8 +209,7 @@ public class HumanPlay { sa.setSourceCard(game.getAction().moveToStack(c)); } } - boolean x = sa.getSourceCard().getManaCost().getShardCount(ManaCostShard.X) > 0; - game.getStack().add(sa, x); + game.getStack().add(sa); } } @@ -238,7 +236,7 @@ public class HumanPlay { req.fillRequirements(useOldTargets, false, true); } else { if (payManaCostIfNeeded(player, sa)) { - AbilityUtils.resolve(sa, false); + AbilityUtils.resolve(sa); } } diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java index cf53009f017..f892b059a12 100644 --- a/src/main/java/forge/game/player/Player.java +++ b/src/main/java/forge/game/player/Player.java @@ -1313,14 +1313,14 @@ public class Player extends GameEntity implements Comparable { SpellAbility saMill = AbilityFactory.getAbility(c.getSVar("MillOne"), c); saMill.setActivatingPlayer(c.getController()); saMill.setTarget(target); - AbilityUtils.resolve(saMill, false); + AbilityUtils.resolve(saMill); return drawn; // Draw is cancelled } else { SpellAbility saDiscard = AbilityFactory.getAbility(c.getSVar("DiscardOne"), c); saDiscard.setActivatingPlayer(c.getController()); saDiscard.setTarget(target); - AbilityUtils.resolve(saDiscard, false); + AbilityUtils.resolve(saDiscard); } } } diff --git a/src/main/java/forge/game/zone/MagicStack.java b/src/main/java/forge/game/zone/MagicStack.java index d9e1b8bc129..b69cf840298 100644 --- a/src/main/java/forge/game/zone/MagicStack.java +++ b/src/main/java/forge/game/zone/MagicStack.java @@ -132,7 +132,7 @@ public class MagicStack extends MyObservable implements Iterable - * add. - *

- * - * @param sp - * a {@link forge.card.spellability.SpellAbility} object. - * @param useX - * a boolean. - */ - public final void add(final SpellAbility sp, final boolean useX) { - if (!useX) { - this.add(sp); - } else { - - // TODO: make working triggered abilities! - if (sp.isManaAbility() || (sp instanceof AbilityTriggered)) { - AbilityUtils.resolve(sp, false); - //sp.resolve(); - } else { - this.push(sp); - /* - * if (sp.getTargetCard() != null) - * CardFactoryUtil.checkTargetingEffects(sp, - * sp.getTargetCard()); - */ - } - } - } - - /** *

* add. @@ -309,7 +278,7 @@ public class MagicStack extends MyObservable implements Iterable creats = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.CREATURES); - final Ability haunterDiesWork = new Ability(source, ManaCost.ZERO) { - @Override - public void resolve() { - game.getAction().exile(source); - this.getTargetCard().addHauntedBy(source); - } - }; - for (int i = 0; i < creats.size(); i++) { - haunterDiesWork.setActivatingPlayer(sa.getActivatingPlayer()); - if (!creats.get(i).canBeTargetedBy(haunterDiesWork)) { - creats.remove(i); - i--; - } - } - if (!creats.isEmpty()) { - haunterDiesWork.setDescription(""); + if (source.hasStartOfKeyword("Haunt") && !source.isCreature() && game.getZoneOf(source).is(ZoneType.Graveyard)) { + handleHauntForNonPermanents(sa); + } + } - if (source.getController().isHuman()) { - final InputSelectCards targetHaunted = new InputSelectCardsFromList(1,1, creats); - targetHaunted.setMessage("Choose target creature to haunt."); - Singletons.getControl().getInputQueue().setInputAndWait(targetHaunted); - haunterDiesWork.setTargetCard(targetHaunted.getSelected().get(0)); - MagicStack.this.add(haunterDiesWork); - } else { - // AI choosing what to haunt - final List oppCreats = CardLists.filterControlledBy(creats, source.getController().getOpponents()); - haunterDiesWork.setTargetCard(ComputerUtilCard.getWorstCreatureAI(oppCreats.isEmpty() ? creats : oppCreats)); - this.add(haunterDiesWork); - } + private void handleHauntForNonPermanents(final SpellAbility sa) { + final Card source = sa.getSourceCard(); + final List creats = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.CREATURES); + final Ability haunterDiesWork = new Ability(source, ManaCost.ZERO) { + @Override + public void resolve() { + game.getAction().exile(source); + this.getTargetCard().addHauntedBy(source); + } + }; + for (int i = 0; i < creats.size(); i++) { + haunterDiesWork.setActivatingPlayer(sa.getActivatingPlayer()); + if (!creats.get(i).canBeTargetedBy(haunterDiesWork)) { + creats.remove(i); + i--; + } + } + if (!creats.isEmpty()) { + haunterDiesWork.setDescription(""); + + if (source.getController().isHuman()) { + final InputSelectCards targetHaunted = new InputSelectCardsFromList(1,1, creats); + targetHaunted.setMessage("Choose target creature to haunt."); + Singletons.getControl().getInputQueue().setInputAndWait(targetHaunted); + haunterDiesWork.setTargetCard(targetHaunted.getSelected().get(0)); + MagicStack.this.add(haunterDiesWork); + } else { + // AI choosing what to haunt + final List oppCreats = CardLists.filterControlledBy(creats, source.getController().getOpponents()); + haunterDiesWork.setTargetCard(ComputerUtilCard.getWorstCreatureAI(oppCreats.isEmpty() ? creats : oppCreats)); + this.add(haunterDiesWork); } } } - /** - *

- * removeCardFromStack. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param fizzle - * a boolean. - * @since 1.0.15 - */ - public final void removeCardFromStack(final SpellAbility sa, final boolean fizzle) { + + private final void finishResolving(final SpellAbility sa, final boolean fizzle) { + + // remove SA and card from the stack + this.removeCardFromStack(sa, fizzle); + // SpellAbility is removed from the stack here + // temporarily removed removing SA after resolution + final SpellAbilityStackInstance si = this.getInstanceFromSpellAbility(sa); + + if (si != null) { + this.remove(si); + } + + // After SA resolves we have to do a handful of things + this.setResolving(false); + this.unfreezeStack(); + sa.resetOnceResolved(); + + game.getAction().checkStateEffects(); + + game.getPhaseHandler().onStackResolved(); + + this.curResolvingCard = null; + + this.updateObservers(); + + // TODO: this is a huge hack. Why is this necessary? + // hostCard in AF is not the same object that's on the battlefield + // verified by System.identityHashCode(card); + final Card tmp = sa.getSourceCard(); + tmp.setCanCounter(true); // reset mana pumped counter magic flag + if (tmp.getClones().size() > 0) { + for (final Card c : game.getCardsIn(ZoneType.Battlefield)) { + if (c.equals(tmp)) { + c.setClones(tmp.getClones()); + } + } + } + + sa.getSourceCard().setXManaCostPaid(0); + } + + private final void removeCardFromStack(final SpellAbility sa, final boolean fizzle) { Card source = sa.getSourceCard(); // do nothing @@ -644,54 +643,6 @@ public class MagicStack extends MyObservable implements Iterable - * finishResolving. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param fizzle - * a boolean. - * @since 1.0.15 - */ - public final void finishResolving(final SpellAbility sa, final boolean fizzle) { - - // remove SA and card from the stack - this.removeCardFromStack(sa, fizzle); - // SpellAbility is removed from the stack here - // temporarily removed removing SA after resolution - this.remove(sa); - - // After SA resolves we have to do a handful of things - this.setResolving(false); - this.unfreezeStack(); - sa.resetOnceResolved(); - - game.getAction().checkStateEffects(); - - game.getPhaseHandler().onStackResolved(); - - this.curResolvingCard = null; - - // TODO: change to use forge.view.FView? - //GuiDisplayUtil.updateGUI(); - this.updateObservers(); - - // TODO: this is a huge hack. Why is this necessary? - // hostCard in AF is not the same object that's on the battlefield - // verified by System.identityHashCode(card); - final Card tmp = sa.getSourceCard(); - tmp.setCanCounter(true); // reset mana pumped counter magic flag - if (tmp.getClones().size() > 0) { - for (final Card c : game.getCardsIn(ZoneType.Battlefield)) { - if (c.equals(tmp)) { - c.setClones(tmp.getClones()); - } - } - - } - } /** *

@@ -704,7 +655,7 @@ public class MagicStack extends MyObservable implements Iterable - * peekAbility. - *

- * - * @return a {@link forge.card.spellability.SpellAbility} object. - */ public final SpellAbility peekAbility() { return this.stack.peekFirst().getSpellAbility(); } - /** - *

- * remove. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - */ - public final void remove(final SpellAbility sa) { - final SpellAbilityStackInstance si = this.getInstanceFromSpellAbility(sa); - - if (si == null) { - return; - } - - this.remove(si); - } - - /** - *

- * remove. - *

- * - * @param si - * a {@link forge.card.spellability.SpellAbilityStackInstance} - * object. - */ public final void remove(final SpellAbilityStackInstance si) { this.stack.remove(si); - this.getFrozenStack().remove(si); + this.frozenStack.remove(si); this.updateObservers(); } - /** - *

- * getInstanceFromSpellAbility. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @return a {@link forge.card.spellability.SpellAbilityStackInstance} - * object. - */ public final SpellAbilityStackInstance getInstanceFromSpellAbility(final SpellAbility sa) { // TODO: Confirm this works! for (final SpellAbilityStackInstance si : this.stack) { @@ -834,38 +741,19 @@ public class MagicStack extends MyObservable implements Iterable - * hasSimultaneousStackEntries. - *

- * - * @return a boolean. - */ public final boolean hasSimultaneousStackEntries() { - return this.getSimultaneousStackEntryList().size() > 0; + return !this.simultaneousStackEntryList.isEmpty(); } public final void clearSimultaneousStack() { this.simultaneousStackEntryList.clear(); } - /** - *

- * addSimultaneousStackEntry. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - */ public final void addSimultaneousStackEntry(final SpellAbility sa) { - this.getSimultaneousStackEntryList().add(sa); + this.simultaneousStackEntryList.add(sa); } - /** - *

- * chooseOrderOfSimultaneousStackEntryAll. - *

- */ + public final void chooseOrderOfSimultaneousStackEntryAll() { final Player playerTurn = game.getPhaseHandler().getPlayerTurn(); @@ -879,33 +767,26 @@ public class MagicStack extends MyObservable implements Iterable - * chooseOrderOfSimultaneousStackEntry. - *

- * - * @param activePlayer - * a {@link forge.game.player.Player} object. - */ - public final void chooseOrderOfSimultaneousStackEntry(final Player activePlayer) { - if (this.getSimultaneousStackEntryList().isEmpty()) { + + private final void chooseOrderOfSimultaneousStackEntry(final Player activePlayer) { + if (this.simultaneousStackEntryList.isEmpty()) { return; } final List activePlayerSAs = new ArrayList(); - for (int i = 0; i < this.getSimultaneousStackEntryList().size(); i++) { - SpellAbility sa = this.getSimultaneousStackEntryList().get(i); + for (int i = 0; i < this.simultaneousStackEntryList.size(); i++) { + SpellAbility sa = this.simultaneousStackEntryList.get(i); Player activator = sa.getActivatingPlayer(); if (activator == null) { if (sa.getSourceCard().getController().equals(activePlayer)) { activePlayerSAs.add(sa); - this.getSimultaneousStackEntryList().remove(i); + this.simultaneousStackEntryList.remove(i); i--; } } else { if (activator.equals(activePlayer)) { activePlayerSAs.add(sa); - this.getSimultaneousStackEntryList().remove(i); + this.simultaneousStackEntryList.remove(i); i--; } } @@ -966,24 +847,6 @@ public class MagicStack extends MyObservable implements Iterable getSimultaneousStackEntryList() { - return this.simultaneousStackEntryList; - } - - /** - * Gets the frozen stack. - * - * @return the frozenStack - */ - public final Stack getFrozenStack() { - return this.frozenStack; - } - /** * Accessor for the field thisTurnCast. * @@ -996,16 +859,9 @@ public class MagicStack extends MyObservable implements Iterable(this.thisTurnCast); + this.thisTurnCast.clear(); } /**