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();
}
/**