From 19cec963d2153b2edea7990e7d351c8ba02a2b57 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Fri, 17 Jan 2014 08:32:39 +0000 Subject: [PATCH] moved a gui reference out from costs --- .gitattributes | 1 + .../main/java/forge/ai/AiCostDecision.java | 83 ++++++------- .../src/main/java/forge/ai/ComputerUtil.java | 8 +- .../main/java/forge/ai/ComputerUtilMana.java | 2 +- .../main/java/forge/ai/ability/DrawAi.java | 2 +- .../src/main/java/forge/game/cost/Cost.java | 5 +- .../game/cost/CostDecisionMakerBase.java | 13 +++ .../java/forge/game/cost/CostPartMana.java | 7 +- .../java/forge/game/cost/CostPayment.java | 52 +++------ .../spellability/HumanPlaySpellAbility.java | 3 +- .../forge/gui/player/HumanCostDecision.java | 110 +++++++++--------- 11 files changed, 149 insertions(+), 137 deletions(-) create mode 100644 forge-gui/src/main/java/forge/game/cost/CostDecisionMakerBase.java diff --git a/.gitattributes b/.gitattributes index 18d0d9bff4b..abc8fef5983 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15013,6 +15013,7 @@ forge-gui/src/main/java/forge/game/cost/Cost.java svneol=native#text/plain forge-gui/src/main/java/forge/game/cost/CostAddMana.java -text forge-gui/src/main/java/forge/game/cost/CostChooseCreatureType.java -text forge-gui/src/main/java/forge/game/cost/CostDamage.java -text +forge-gui/src/main/java/forge/game/cost/CostDecisionMakerBase.java -text forge-gui/src/main/java/forge/game/cost/CostDiscard.java -text forge-gui/src/main/java/forge/game/cost/CostDraw.java -text forge-gui/src/main/java/forge/game/cost/CostExile.java -text diff --git a/forge-gui/src/main/java/forge/ai/AiCostDecision.java b/forge-gui/src/main/java/forge/ai/AiCostDecision.java index 96b0eee2e68..171ebf24328 100644 --- a/forge-gui/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-gui/src/main/java/forge/ai/AiCostDecision.java @@ -18,6 +18,7 @@ import forge.game.card.CardPredicates.Presets; import forge.game.cost.CostAddMana; import forge.game.cost.CostChooseCreatureType; import forge.game.cost.CostDamage; +import forge.game.cost.CostDecisionMakerBase; import forge.game.cost.CostDiscard; import forge.game.cost.CostDraw; import forge.game.cost.CostExile; @@ -47,19 +48,18 @@ import forge.game.player.PlayerControllerAi; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; -public class AiCostDecision implements ICostVisitor { +public class AiCostDecision extends CostDecisionMakerBase implements ICostVisitor { + - private final Player ai; private final SpellAbility ability; private final Card source; - public AiCostDecision(Player ai0, SpellAbility sa, Card source0) { - ai = ai0; + public AiCostDecision(Player ai0, SpellAbility sa) { + super(ai0); ability = sa; - source = source0; + source = ability.getSourceCard(); } - @Override public PaymentDecision visit(CostAddMana cost) { Integer c = cost.convertAmount(); @@ -74,7 +74,7 @@ public class AiCostDecision implements ICostVisitor { @Override public PaymentDecision visit(CostChooseCreatureType cost) { - String choice = ai.getController().chooseSomeType("Creature", ability, new ArrayList(CardType.getCreatureTypes()), new ArrayList()); + String choice = player.getController().chooseSomeType("Creature", ability, new ArrayList(CardType.getCreatureTypes()), new ArrayList()); return PaymentDecision.type(choice); } @@ -82,12 +82,12 @@ public class AiCostDecision implements ICostVisitor { public PaymentDecision visit(CostDiscard cost) { final String type = cost.getType(); - final List hand = ai.getCardsIn(ZoneType.Hand); + final List hand = player.getCardsIn(ZoneType.Hand); if (type.equals("LastDrawn")) { - if (!hand.contains(ai.getLastDrawnCard())) { + if (!hand.contains(player.getLastDrawnCard())) { return null; } - return PaymentDecision.card(ai.getLastDrawnCard()); + return PaymentDecision.card(player.getLastDrawnCard()); } else if (cost.payCostFromSource()) { if (!hand.contains(source)) { @@ -116,7 +116,7 @@ public class AiCostDecision implements ICostVisitor { return PaymentDecision.card(CardLists.getRandomSubList(hand, c)); } else { - final AiController aic = ((PlayerControllerAi)ai.getController()).getAi(); + final AiController aic = ((PlayerControllerAi)player.getController()).getAi(); return PaymentDecision.card(aic.getCardsToDiscard(c, type.split(";"), ability)); } } @@ -156,7 +156,7 @@ public class AiCostDecision implements ICostVisitor { } if (cost.getType().equals("All")) { - return PaymentDecision.card(ai.getCardsIn(cost.getFrom())); + return PaymentDecision.card(player.getCardsIn(cost.getFrom())); } else if (cost.getType().contains("FromTopGrave")) { return null; @@ -173,14 +173,14 @@ public class AiCostDecision implements ICostVisitor { } if (cost.getFrom().equals(ZoneType.Library)) { - return PaymentDecision.card(ai.getCardsIn(ZoneType.Library, c)); + return PaymentDecision.card(player.getCardsIn(ZoneType.Library, c)); } else if (cost.sameZone) { // TODO Determine exile from same zone for AI return null; } else { - List chosen = ComputerUtil.chooseExileFrom(ai, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c); + List chosen = ComputerUtil.chooseExileFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c); return null == chosen ? null : PaymentDecision.card(chosen); } } @@ -195,9 +195,9 @@ public class AiCostDecision implements ICostVisitor { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); } - List typeList = ai.getGame().getCardsIn(ZoneType.Exile); + List typeList = player.getGame().getCardsIn(ZoneType.Exile); - typeList = CardLists.getValidCards(typeList, cost.getType().split(";"), ai, source); + typeList = CardLists.getValidCards(typeList, cost.getType().split(";"), player, source); if (typeList.size() < c) { return null; @@ -237,7 +237,7 @@ public class AiCostDecision implements ICostVisitor { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); } - final List typeList = CardLists.getValidCards(ai.getGame().getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), ai, source); + final List typeList = CardLists.getValidCards(player.getGame().getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), player, source); if (typeList.size() < c) { @@ -258,7 +258,7 @@ public class AiCostDecision implements ICostVisitor { public PaymentDecision visit(CostGainLife cost) { final List oppsThatCanGainLife = new ArrayList(); - for (final Player opp : cost.getPotentialTargets(ai, source)) { + for (final Player opp : cost.getPotentialTargets(player, source)) { if (opp.canGainLife()) { oppsThatCanGainLife.add(opp); } @@ -285,7 +285,7 @@ public class AiCostDecision implements ICostVisitor { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); } - List topLib = ai.getCardsIn(ZoneType.Library, c); + List topLib = player.getCardsIn(ZoneType.Library, c); return topLib.size() < c ? null : PaymentDecision.card(topLib); } @@ -306,7 +306,7 @@ public class AiCostDecision implements ICostVisitor { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); } } - if (!ai.canPayLife(c)) { + if (!player.canPayLife(c)) { return null; } // activator.payLife(c, null); @@ -317,14 +317,14 @@ public class AiCostDecision implements ICostVisitor { @Override public PaymentDecision visit(CostPutCardToLib cost) { Integer c = cost.convertAmount(); - final Game game = ai.getGame(); + final Game game = player.getGame(); List chosen = new ArrayList(); List list; if (cost.isSameZone()) { list = new ArrayList(game.getCardsIn(cost.getFrom())); } else { - list = new ArrayList(ai.getCardsIn(cost.getFrom())); + list = new ArrayList(player.getCardsIn(cost.getFrom())); } if (c == null) { @@ -337,7 +337,7 @@ public class AiCostDecision implements ICostVisitor { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); } - list = CardLists.getValidCards(list, cost.getType().split(";"), ai, source); + list = CardLists.getValidCards(list, cost.getType().split(";"), player, source); if (cost.isSameZone()) { // Jotun Grunt @@ -352,7 +352,7 @@ public class AiCostDecision implements ICostVisitor { } chosen = chosen.subList(0, c); } else { - chosen = ComputerUtil.choosePutToLibraryFrom(ai, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c); + chosen = ComputerUtil.choosePutToLibraryFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c); } return chosen.isEmpty() ? null : PaymentDecision.card(chosen); } @@ -365,7 +365,7 @@ public class AiCostDecision implements ICostVisitor { } - final List typeList = CardLists.getValidCards(ai.getGame().getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), ai, source); + final List typeList = CardLists.getValidCards(player.getGame().getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), player, source); Card card = null; if (cost.getType().equals("Creature.YouCtrl")) { @@ -390,7 +390,7 @@ public class AiCostDecision implements ICostVisitor { final String sVar = ability.getSVar(amount); if (sVar.equals("XChoice")) { List typeList = - CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), ability.getActivatingPlayer(), ability.getSourceCard()); + CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), ability.getActivatingPlayer(), ability.getSourceCard()); typeList = CardLists.filter(typeList, Presets.UNTAPPED); c = typeList.size(); source.setSVar("ChosenX", "Number$" + Integer.toString(c)); @@ -402,7 +402,7 @@ public class AiCostDecision implements ICostVisitor { return null; } - List totap = ComputerUtil.chooseTapType(ai, cost.getType(), source, !cost.canTapSource, c); + List totap = ComputerUtil.chooseTapType(player, cost.getType(), source, !cost.canTapSource, c); if (totap == null) { @@ -437,7 +437,7 @@ public class AiCostDecision implements ICostVisitor { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); } - List list = ComputerUtil.chooseSacrificeType(ai, cost.getType(), source, ability.getTargetCard(), c); + List list = ComputerUtil.chooseSacrificeType(player, cost.getType(), source, ability.getTargetCard(), c); return PaymentDecision.card(list); } @@ -451,7 +451,7 @@ public class AiCostDecision implements ICostVisitor { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); } - List res = ComputerUtil.chooseReturnType(ai, cost.getType(), source, ability.getTargetCard(), c); + List res = ComputerUtil.chooseReturnType(player, cost.getType(), source, ability.getTargetCard(), c); return res.isEmpty() ? null : PaymentDecision.card(res); } @@ -459,7 +459,7 @@ public class AiCostDecision implements ICostVisitor { public PaymentDecision visit(CostReveal cost) { final String type = cost.getType(); - List hand = new ArrayList(ai.getCardsIn(ZoneType.Hand)); + List hand = new ArrayList(player.getCardsIn(ZoneType.Hand)); if (cost.payCostFromSource()) { if (!hand.contains(source)) { @@ -469,13 +469,13 @@ public class AiCostDecision implements ICostVisitor { } if (cost.getType().equals("Hand")) - return PaymentDecision.card(ai.getCardsIn(ZoneType.Hand)); + return PaymentDecision.card(player.getCardsIn(ZoneType.Hand)); if (cost.getType().equals("SameColor")) { return null; } - hand = CardLists.getValidCards(hand, type.split(";"), ai, source); + hand = CardLists.getValidCards(hand, type.split(";"), player, source); Integer c = cost.convertAmount(); if (c == null) { final String sVar = ability.getSVar(cost.getAmount()); @@ -486,7 +486,7 @@ public class AiCostDecision implements ICostVisitor { } } - final AiController aic = ((PlayerControllerAi)ai.getController()).getAi(); + final AiController aic = ((PlayerControllerAi)player.getController()).getAi(); return PaymentDecision.card(aic.getCardsToDiscard(c, type.split(";"), ability)); } @@ -496,7 +496,7 @@ public class AiCostDecision implements ICostVisitor { final int c = AbilityUtils.calculateAmount(source, amount, ability); final String type = cost.getType(); - List typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), ai, source); + List typeList = CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), type.split(";"), player, source); List hperms = CardLists.filter(typeList, new Predicate() { @Override public boolean apply(final Card crd) { @@ -536,7 +536,7 @@ public class AiCostDecision implements ICostVisitor { if (type.equals("OriginalHost")) { typeList = Lists.newArrayList(ability.getOriginalHost()); } else { - typeList = CardLists.getValidCards(ai.getCardsIn(cost.zone), type.split(";"), ai, source); + typeList = CardLists.getValidCards(player.getCardsIn(cost.zone), type.split(";"), player, source); } for (Card card : typeList) { if (card.getCounters(cost.counter) >= c) { @@ -563,8 +563,8 @@ public class AiCostDecision implements ICostVisitor { if (c == null) { final String sVar = ability.getSVar(amount); if (sVar.equals("XChoice")) { - List typeList = ai.getGame().getCardsIn(ZoneType.Battlefield); - typeList = CardLists.getValidCards(typeList, cost.getType().split(";"), ai, ability.getSourceCard()); + List typeList = player.getGame().getCardsIn(ZoneType.Battlefield); + typeList = CardLists.getValidCards(typeList, cost.getType().split(";"), player, ability.getSourceCard()); if (!cost.canUntapSource) { typeList.remove(source); } @@ -576,7 +576,7 @@ public class AiCostDecision implements ICostVisitor { } } - List list = ComputerUtil.chooseUntapType(ai, cost.getType(), source, cost.canUntapSource, c); + List list = ComputerUtil.chooseUntapType(player, cost.getType(), source, cost.canUntapSource, c); if (list == null) { System.out.println("Couldn't find a valid card to untap for: " + source.getName()); @@ -593,12 +593,17 @@ public class AiCostDecision implements ICostVisitor { @Override public PaymentDecision visit(CostUnattach cost) { - Card cardToUnattach = cost.findCardToUnattach(source, (Player) ai, ability); + Card cardToUnattach = cost.findCardToUnattach(source, (Player) player, ability); if (cardToUnattach == null) { // We really shouldn't be able to get here if there's nothing to unattach return null; } return PaymentDecision.card(cardToUnattach); } + + @Override + public boolean paysRightAfterDecision() { + return false; + } } diff --git a/forge-gui/src/main/java/forge/ai/ComputerUtil.java b/forge-gui/src/main/java/forge/ai/ComputerUtil.java index 15645f078cb..00585a55f4d 100644 --- a/forge-gui/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-gui/src/main/java/forge/ai/ComputerUtil.java @@ -116,7 +116,7 @@ public class ComputerUtil { } } else { final CostPayment pay = new CostPayment(cost, sa); - if (pay.payComputerCosts(ai, game)) { + if (pay.payComputerCosts(new AiCostDecision(ai, sa))) { game.getStack().addAndUnfreeze(sa); if (sa.getSplicedCards() != null && !sa.getSplicedCards().isEmpty()) { game.getAction().reveal(sa.getSplicedCards(), ai, true, "Computer reveals spliced cards from "); @@ -240,7 +240,7 @@ public class ComputerUtil { game.getStack().add(sa); } else { final CostPayment pay = new CostPayment(cost, sa); - if (pay.payComputerCosts(ai, game)) { + if (pay.payComputerCosts(new AiCostDecision(ai, sa))) { game.getStack().add(sa); } } @@ -287,7 +287,7 @@ public class ComputerUtil { } final CostPayment pay = new CostPayment(newSA.getPayCosts(), newSA); - pay.payComputerCosts(ai, game); + pay.payComputerCosts(new AiCostDecision(ai, sa)); game.getStack().add(newSA); } @@ -314,7 +314,7 @@ public class ComputerUtil { ComputerUtilMana.payManaCost(ai, sa); } else { final CostPayment pay = new CostPayment(cost, sa); - pay.payComputerCosts(ai, game); + pay.payComputerCosts(new AiCostDecision(ai, sa)); } AbilityUtils.resolve(sa); diff --git a/forge-gui/src/main/java/forge/ai/ComputerUtilMana.java b/forge-gui/src/main/java/forge/ai/ComputerUtilMana.java index 5998bc263b3..9a682f87e2f 100644 --- a/forge-gui/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-gui/src/main/java/forge/ai/ComputerUtilMana.java @@ -209,7 +209,7 @@ public class ComputerUtilMana { else { if (saPayment.getPayCosts() != null) { final CostPayment pay = new CostPayment(saPayment.getPayCosts(), saPayment); - if (!pay.payComputerCosts(ai, ai.getGame())) { + if (!pay.payComputerCosts(new AiCostDecision(ai, sa))) { continue; } } diff --git a/forge-gui/src/main/java/forge/ai/ability/DrawAi.java b/forge-gui/src/main/java/forge/ai/ability/DrawAi.java index b60a8bd6369..b1fedf3dbc3 100644 --- a/forge-gui/src/main/java/forge/ai/ability/DrawAi.java +++ b/forge-gui/src/main/java/forge/ai/ability/DrawAi.java @@ -66,7 +66,7 @@ public class DrawAi extends SpellAbilityAi { } if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) { - AiCostDecision aiDecisions = new AiCostDecision(ai, sa, source); + AiCostDecision aiDecisions = new AiCostDecision(ai, sa); for (final CostPart part : abCost.getCostParts()) { if (part instanceof CostDiscard) { PaymentDecision decision = part.accept(aiDecisions); diff --git a/forge-gui/src/main/java/forge/game/cost/Cost.java b/forge-gui/src/main/java/forge/game/cost/Cost.java index 5106056cee7..a7ca934c3b1 100644 --- a/forge-gui/src/main/java/forge/game/cost/Cost.java +++ b/forge-gui/src/main/java/forge/game/cost/Cost.java @@ -154,7 +154,10 @@ public class Cost { parsedMana = new CostPartMana(new ManaCost(new ManaCostParser(manaParts.toString())), xCantBe0 ? "XCantBe0" : null); } if (parsedMana != null) { - this.costParts.add(0, parsedMana); + if(parsedMana.shouldPayLast()) // back from the brink pays mana after 'exile' part is paid + this.costParts.add(parsedMana); + else + this.costParts.add(0, parsedMana); } // inspect parts to set Sac, {T} and {Q} flags diff --git a/forge-gui/src/main/java/forge/game/cost/CostDecisionMakerBase.java b/forge-gui/src/main/java/forge/game/cost/CostDecisionMakerBase.java new file mode 100644 index 00000000000..ab3630630c1 --- /dev/null +++ b/forge-gui/src/main/java/forge/game/cost/CostDecisionMakerBase.java @@ -0,0 +1,13 @@ +package forge.game.cost; + +import forge.game.player.Player; + +public abstract class CostDecisionMakerBase implements ICostVisitor { + + protected final Player player; + public CostDecisionMakerBase(Player player0) { + player = player0; + } + public Player getPlayer() { return player; } + public abstract boolean paysRightAfterDecision(); +} diff --git a/forge-gui/src/main/java/forge/game/cost/CostPartMana.java b/forge-gui/src/main/java/forge/game/cost/CostPartMana.java index d5022d85f09..c6568056f41 100644 --- a/forge-gui/src/main/java/forge/game/cost/CostPartMana.java +++ b/forge-gui/src/main/java/forge/game/cost/CostPartMana.java @@ -29,8 +29,12 @@ public class CostPartMana extends CostPart { // "Leftover" private final ManaCost cost; private boolean xCantBe0 = false; + private boolean isRememberedCreatureCost = false; private final String restriction; + public boolean shouldPayLast() { + return isRememberedCreatureCost; + } /** * Instantiates a new cost mana. * @@ -43,7 +47,8 @@ public class CostPartMana extends CostPart { public CostPartMana(final ManaCost cost, String restriction) { this.cost = cost; this.xCantBe0 = "XCantBe0".equals(restriction); - this.restriction = xCantBe0 ? null : restriction; + this.isRememberedCreatureCost = "Remembered".equalsIgnoreCase(restriction); + this.restriction = xCantBe0 || isRememberedCreatureCost ? null : restriction; } /** diff --git a/forge-gui/src/main/java/forge/game/cost/CostPayment.java b/forge-gui/src/main/java/forge/game/cost/CostPayment.java index 3abe0e1dbe0..1250da7bfc6 100644 --- a/forge-gui/src/main/java/forge/game/cost/CostPayment.java +++ b/forge-gui/src/main/java/forge/game/cost/CostPayment.java @@ -19,15 +19,12 @@ package forge.game.cost; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; -import forge.ai.AiCostDecision; -import forge.game.Game; + import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.gui.player.HumanCostDecision; /** *

@@ -134,20 +131,12 @@ public class CostPayment { this.ability.getActivatingPlayer().getManaPool().refundManaPaid(this.ability); } - /** - *

- * payCost. - *

- * - * @return a boolean. - */ - public boolean payCost(final Player payer) { - HumanCostDecision hcd = new HumanCostDecision(payer, ability, ability.getSourceCard()); + public boolean payCost(final CostDecisionMakerBase decisionMaker) { for (final CostPart part : this.cost.getCostParts()) { - PaymentDecision pd = part.accept(hcd); + PaymentDecision pd = part.accept(decisionMaker); - if ( null == pd || !part.payAsDecided(payer, pd, ability)) + if ( null == pd || !part.payAsDecided(decisionMaker.getPlayer(), pd, ability)) return false; // abilities care what was used to pay for them @@ -166,35 +155,26 @@ public class CostPayment { return true; } - /** - *

- * payComputerCosts. - *

- * - * @return a boolean. - */ - public final boolean payComputerCosts(final Player ai, final Game game) { - // canPayAdditionalCosts now Player Agnostic - + public final boolean payComputerCosts(final CostDecisionMakerBase decisionMaker) { // Just in case it wasn't set, but honestly it shouldn't have gotten // here without being set - this.ability.setActivatingPlayer(ai); - - final Card source = this.ability.getSourceCard(); - final List parts = this.cost.getCostParts(); + this.ability.setActivatingPlayer(decisionMaker.getPlayer()); Map, PaymentDecision> decisions = new HashMap, PaymentDecision>(); - AiCostDecision aiDecisions = new AiCostDecision(ai, ability, source); - + // Set all of the decisions before attempting to pay anything - for (final CostPart part : parts) { - PaymentDecision decision = part.accept(aiDecisions); - if ( null == decision ) return false; + for (final CostPart part : this.cost.getCostParts()) { + PaymentDecision decision = part.accept(decisionMaker); + if (null == decision) return false; + + if (decisionMaker.paysRightAfterDecision() && !part.payAsDecided(decisionMaker.getPlayer(), decision, ability)) + return false; + decisions.put(part.getClass(), decision); } - for (final CostPart part : parts) { - if (!part.payAsDecided(ai, decisions.get(part.getClass()), this.ability)) { + for (final CostPart part : this.cost.getCostParts()) { + if (!part.payAsDecided(decisionMaker.getPlayer(), decisions.get(part.getClass()), this.ability)) { return false; } // abilities care what was used to pay for them diff --git a/forge-gui/src/main/java/forge/game/spellability/HumanPlaySpellAbility.java b/forge-gui/src/main/java/forge/game/spellability/HumanPlaySpellAbility.java index 7190e23c98d..a0cef29fd44 100644 --- a/forge-gui/src/main/java/forge/game/spellability/HumanPlaySpellAbility.java +++ b/forge-gui/src/main/java/forge/game/spellability/HumanPlaySpellAbility.java @@ -33,6 +33,7 @@ import forge.game.cost.CostPayment; import forge.game.player.Player; import forge.game.player.PlayerController; import forge.game.zone.Zone; +import forge.gui.player.HumanCostDecision; /** *

@@ -74,7 +75,7 @@ public class HumanPlaySpellAbility { boolean prerequisitesMet = this.announceValuesLikeX() && this.announceType() && (!mayChooseTargets || setupTargets()) // if you can choose targets, then do choose them. - && (isFree || this.payment.payCost(human)); + && (isFree || this.payment.payCost(new HumanCostDecision(human, ability, ability.getSourceCard()))); if (!prerequisitesMet) { if (!ability.isTrigger()) { diff --git a/forge-gui/src/main/java/forge/gui/player/HumanCostDecision.java b/forge-gui/src/main/java/forge/gui/player/HumanCostDecision.java index a1a068b3dd3..497c027e93d 100644 --- a/forge-gui/src/main/java/forge/gui/player/HumanCostDecision.java +++ b/forge-gui/src/main/java/forge/gui/player/HumanCostDecision.java @@ -25,6 +25,7 @@ import forge.game.card.CardPredicates.Presets; import forge.game.cost.CostAddMana; import forge.game.cost.CostChooseCreatureType; import forge.game.cost.CostDamage; +import forge.game.cost.CostDecisionMakerBase; import forge.game.cost.CostDiscard; import forge.game.cost.CostDraw; import forge.game.cost.CostExile; @@ -47,7 +48,6 @@ import forge.game.cost.CostTapType; import forge.game.cost.CostUnattach; import forge.game.cost.CostUntap; import forge.game.cost.CostUntapType; -import forge.game.cost.ICostVisitor; import forge.game.cost.PaymentDecision; import forge.game.player.Player; import forge.game.spellability.SpellAbility; @@ -59,14 +59,13 @@ import forge.gui.input.InputSelectManyBase; import forge.util.Aggregates; import forge.util.Lang; -public class HumanCostDecision implements ICostVisitor { +public class HumanCostDecision extends CostDecisionMakerBase { - private final Player payer; private final SpellAbility ability; private final Card source; public HumanCostDecision(Player p, SpellAbility sa, Card source) { - payer = p; + super(p); ability = sa; this.source = source; } @@ -77,7 +76,7 @@ public class HumanCostDecision implements ICostVisitor { return AbilityFactory.calculateAmount(card, "ChosenX", null); }*/ - int chosenX = payer.getController().chooseNumber(ability, source.toString() + " - Choose a Value for X", 0, maxValue); + int chosenX = player.getController().chooseNumber(ability, source.toString() + " - Choose a Value for X", 0, maxValue); ability.setSVar("ChosenX", Integer.toString(chosenX)); source.setSVar("ChosenX", Integer.toString(chosenX)); return chosenX; @@ -94,7 +93,7 @@ public class HumanCostDecision implements ICostVisitor { @Override public PaymentDecision visit(CostChooseCreatureType cost) { - String choice = payer.getController().chooseSomeType("Creature", ability, new ArrayList(CardType.getCreatureTypes()), new ArrayList(), true); + String choice = player.getController().chooseSomeType("Creature", ability, new ArrayList(CardType.getCreatureTypes()), new ArrayList(), true); if( null == choice ) return null; return PaymentDecision.type(choice); @@ -102,7 +101,7 @@ public class HumanCostDecision implements ICostVisitor { @Override public PaymentDecision visit(CostDiscard cost) { - List handList = new ArrayList(payer.getCardsIn(ZoneType.Hand)); + List handList = new ArrayList(player.getCardsIn(ZoneType.Hand)); String discardType = cost.getType(); final String amount = cost.getAmount(); @@ -115,7 +114,7 @@ public class HumanCostDecision implements ICostVisitor { } if (discardType.equals("LastDrawn")) { - final Card lastDrawn = payer.getLastDrawnCard(); + final Card lastDrawn = player.getLastDrawnCard(); return handList.contains(lastDrawn) ? PaymentDecision.card(lastDrawn) : null; } @@ -137,7 +136,7 @@ public class HumanCostDecision implements ICostVisitor { } if (discardType.contains("+WithSameName")) { String type = discardType.replace("+WithSameName", ""); - handList = CardLists.getValidCards(handList, type.split(";"), payer, source); + handList = CardLists.getValidCards(handList, type.split(";"), player, source); final List landList2 = handList; handList = CardLists.filter(handList, new Predicate() { @Override @@ -171,7 +170,7 @@ public class HumanCostDecision implements ICostVisitor { String type = new String(discardType); final String[] validType = type.split(";"); - handList = CardLists.getValidCards(handList, validType, payer, source); + handList = CardLists.getValidCards(handList, validType, player, source); if (c == null) { final String sVar = ability.getSVar(amount); @@ -198,7 +197,7 @@ public class HumanCostDecision implements ICostVisitor { @Override public PaymentDecision visit(CostDamage cost) { final String amount = cost.getAmount(); - final int life = payer.getLife(); + final int life = player.getLife(); Integer c = cost.convertAmount(); if (c == null) { @@ -212,7 +211,7 @@ public class HumanCostDecision implements ICostVisitor { } } - if (payer.canPayLife(c) && payer.getController().confirmPayment(cost, "Pay " + c + " Life?")) { + if (player.canPayLife(c) && player.getController().confirmPayment(cost, "Pay " + c + " Life?")) { return PaymentDecision.number(c); } return null; @@ -227,7 +226,7 @@ public class HumanCostDecision implements ICostVisitor { c = AbilityUtils.calculateAmount(source, amount, ability); } - if (!payer.getController().confirmPayment(cost, "Draw " + c + " Card" + (c == 1 ? "" : "s"))) { + if (!player.getController().confirmPayment(cost, "Draw " + c + " Card" + (c == 1 ? "" : "s"))) { return null; } @@ -237,7 +236,7 @@ public class HumanCostDecision implements ICostVisitor { @Override public PaymentDecision visit(CostExile cost) { final String amount = cost.getAmount(); - final Game game = payer.getGame(); + final Game game = player.getGame(); Integer c = cost.convertAmount(); String type = cost.getType(); @@ -258,18 +257,18 @@ public class HumanCostDecision implements ICostVisitor { list = new ArrayList(game.getCardsIn(cost.from)); } else { - list = new ArrayList(payer.getCardsIn(cost.from)); + list = new ArrayList(player.getCardsIn(cost.from)); } if (cost.payCostFromSource()) { - return source.getZone() == payer.getZone(cost.from) && payer.getController().confirmPayment(cost, "Exile " + source.getName() + "?") ? PaymentDecision.card(source) : null; + return source.getZone() == player.getZone(cost.from) && player.getController().confirmPayment(cost, "Exile " + source.getName() + "?") ? PaymentDecision.card(source) : null; } if (type.equals("All")) { return PaymentDecision.card(list); } - list = CardLists.getValidCards(list, type.split(";"), payer, source); + list = CardLists.getValidCards(list, type.split(";"), player, source); if (c == null) { final String sVar = ability.getSVar(amount); // Generalize this @@ -290,7 +289,7 @@ public class HumanCostDecision implements ICostVisitor { } if (cost.from == ZoneType.Stack) { return exileFromStack(cost, ability, c); } - if (cost.from == ZoneType.Library) { return exileFromTop(cost, ability, payer, c); } + if (cost.from == ZoneType.Library) { return exileFromTop(cost, ability, player, c); } if (fromTopGrave) { return exileFromTopGraveType(ability, c, list); } if (!cost.sameZone) { return exileFromMiscZone(cost, ability, c, list); } @@ -383,12 +382,12 @@ public class HumanCostDecision implements ICostVisitor { return PaymentDecision.card(exiled); } - private PaymentDecision exileFromTop(final CostExile cost, final SpellAbility sa, final Player payer, final int nNeeded) { + private PaymentDecision exileFromTop(final CostExile cost, final SpellAbility sa, final Player player, final int nNeeded) { final StringBuilder sb = new StringBuilder(); sb.append("Exile ").append(nNeeded).append(" cards from the top of your library?"); - final List list = payer.getCardsIn(ZoneType.Library, nNeeded); + final List list = player.getCardsIn(ZoneType.Library, nNeeded); - if (list.size() > nNeeded || !payer.getController().confirmPayment(cost, "Exile " + Lang.nounWithAmount(nNeeded, "card") + " from the top of your library?")) { + if (list.size() > nNeeded || !player.getController().confirmPayment(cost, "Exile " + Lang.nounWithAmount(nNeeded, "card") + " from the top of your library?")) { return null; } @@ -463,8 +462,8 @@ public class HumanCostDecision implements ICostVisitor { if (c == null) { c = AbilityUtils.calculateAmount(source, amount, ability); } - final List list = payer.getCardsIn(ZoneType.Battlefield); - List validCards = CardLists.getValidCards(list, cost.getType().split(";"), payer, source); + final List list = player.getCardsIn(ZoneType.Battlefield); + List validCards = CardLists.getValidCards(list, cost.getType().split(";"), player, source); InputSelectCardsFromList inp = new InputSelectCardsFromList(c, validCards); final String desc = cost.getTypeDescription() == null ? cost.getType() : cost.getTypeDescription(); @@ -480,7 +479,7 @@ public class HumanCostDecision implements ICostVisitor { public PaymentDecision visit(CostGainLife cost) { final String amount = cost.getAmount(); - final int life = payer.getLife(); + final int life = player.getLife(); Integer c = cost.convertAmount(); if (c == null) { @@ -494,7 +493,7 @@ public class HumanCostDecision implements ICostVisitor { } final List oppsThatCanGainLife = new ArrayList(); - for (final Player opp : cost.getPotentialTargets(payer, source)) { + for (final Player opp : cost.getPotentialTargets(player, source)) { if (opp.canGainLife()) { oppsThatCanGainLife.add(opp); } @@ -528,16 +527,16 @@ public class HumanCostDecision implements ICostVisitor { } } - if (!payer.getController().confirmPayment(cost, "Mill " + c + " card" + (c == 1 ? "" : "s") + " from your library?")) { + if (!player.getController().confirmPayment(cost, "Mill " + c + " card" + (c == 1 ? "" : "s") + " from your library?")) { return null; } - return PaymentDecision.card(payer.getCardsIn(ZoneType.Library, c)); + return PaymentDecision.card(player.getCardsIn(ZoneType.Library, c)); } @Override public PaymentDecision visit(CostPayLife cost) { final String amount = cost.getAmount(); - final int life = payer.getLife(); + final int life = player.getLife(); Integer c = cost.convertAmount(); if (c == null) { @@ -555,7 +554,7 @@ public class HumanCostDecision implements ICostVisitor { } } - if (payer.canPayLife(c) && payer.getController().confirmPayment(cost, "Pay " + c + " Life?")) { + if (player.canPayLife(c) && player.getController().confirmPayment(cost, "Pay " + c + " Life?")) { return PaymentDecision.number(c); } return null; @@ -572,7 +571,7 @@ public class HumanCostDecision implements ICostVisitor { final String amount = cost.getAmount(); Integer c = cost.convertAmount(); - List list = cost.sameZone ? payer.getGame().getCardsIn(cost.getFrom()) : payer.getCardsIn(cost.getFrom()); + List list = cost.sameZone ? player.getGame().getCardsIn(cost.getFrom()) : player.getCardsIn(cost.getFrom()); if (c == null) { final String sVar = ability.getSVar(amount); @@ -584,7 +583,7 @@ public class HumanCostDecision implements ICostVisitor { } } - list = CardLists.getValidCards(list, cost.getType().split(";"), payer, source); + list = CardLists.getValidCards(list, cost.getType().split(";"), player, source); if (cost.from == ZoneType.Hand) { InputSelectCardsFromList inp = new InputSelectCardsFromList(c, c, list); @@ -595,7 +594,7 @@ public class HumanCostDecision implements ICostVisitor { } if (cost.sameZone){ - List players = payer.getGame().getPlayers(); + List players = player.getGame().getPlayers(); List payableZone = new ArrayList(); for (Player p : players) { List enoughType = CardLists.filter(list, CardPredicates.isOwner(p)); @@ -664,7 +663,7 @@ public class HumanCostDecision implements ICostVisitor { } // Cards to use this branch: Scarscale Ritual, Wandering Mage - each adds only one counter - List typeList = CardLists.getValidCards(payer.getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), payer, ability.getSourceCard()); + List typeList = CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), player, ability.getSourceCard()); InputSelectCardsFromList inp = new InputSelectCardsFromList(1, 1, typeList); inp.setMessage("Put " + Lang.nounWithAmount(c, cost.getCounter().getName() + " counter") + " on " +cost.getDescriptiveType()); @@ -682,7 +681,7 @@ public class HumanCostDecision implements ICostVisitor { final String amount = cost.getAmount(); Integer c = cost.convertAmount(); - final List list = payer.getCardsIn(ZoneType.Battlefield); + final List list = player.getCardsIn(ZoneType.Battlefield); if (c == null) { final String sVar = ability.getSVar(amount); // Generalize this @@ -694,8 +693,8 @@ public class HumanCostDecision implements ICostVisitor { } if (cost.payCostFromSource()) { final Card card = ability.getSourceCard(); - if (card.getController() == payer && card.isInPlay()) { - return payer.getController().confirmPayment(cost, "Return " + card.getName() + " to hand?") ? PaymentDecision.card(card) : null; + if (card.getController() == player && card.isInPlay()) { + return player.getController().confirmPayment(cost, "Return " + card.getName() + " to hand?") ? PaymentDecision.card(card) : null; } } else { @@ -721,12 +720,12 @@ public class HumanCostDecision implements ICostVisitor { return PaymentDecision.card(source); if (cost.getType().equals("Hand")) - return PaymentDecision.card(payer.getCardsIn(ZoneType.Hand)); + return PaymentDecision.card(player.getCardsIn(ZoneType.Hand)); InputSelectCardsFromList inp = null; if (cost.getType().equals("SameColor")) { Integer num = cost.convertAmount(); - List handList = payer.getCardsIn(ZoneType.Hand); + List handList = player.getCardsIn(ZoneType.Hand); final List handList2 = handList; handList = CardLists.filter(handList, new Predicate() { @Override @@ -758,8 +757,8 @@ public class HumanCostDecision implements ICostVisitor { } else { Integer num = cost.convertAmount(); - List handList = payer.getCardsIn(ZoneType.Hand); - handList = CardLists.getValidCards(handList, cost.getType().split(";"), payer, ability.getSourceCard()); + List handList = player.getCardsIn(ZoneType.Hand); + handList = CardLists.getValidCards(handList, cost.getType().split(";"), player, ability.getSourceCard()); if (num == null) { final String sVar = ability.getSVar(amount); @@ -792,8 +791,8 @@ public class HumanCostDecision implements ICostVisitor { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); } - List list = new ArrayList(payer.getCardsIn(ZoneType.Battlefield)); - list = CardLists.getValidCards(list, type.split(";"), payer, source); + List list = new ArrayList(player.getCardsIn(ZoneType.Battlefield)); + list = CardLists.getValidCards(list, type.split(";"), player, source); list = CardLists.filter(list, new Predicate() { @@ -930,7 +929,7 @@ public class HumanCostDecision implements ICostVisitor { return res; } - List validCards = CardLists.getValidCards(payer.getCardsIn(cost.zone), type.split(";"), payer, source); + List validCards = CardLists.getValidCards(player.getCardsIn(cost.zone), type.split(";"), player, source); if (cost.zone.equals(ZoneType.Battlefield)) { final InputSelectCardToRemoveCounter inp = new InputSelectCardToRemoveCounter(cntRemoved, cost.counter, validCards); inp.setMessage("Remove %d " + cost.counter.getName() + " counters from " + cost.getDescriptiveType()); @@ -969,15 +968,15 @@ public class HumanCostDecision implements ICostVisitor { final String amount = cost.getAmount(); final String type = cost.getType(); - List list = new ArrayList(payer.getCardsIn(ZoneType.Battlefield)); - list = CardLists.getValidCards(list, type.split(";"), payer, source); - if (payer.hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) { + List list = new ArrayList(player.getCardsIn(ZoneType.Battlefield)); + list = CardLists.getValidCards(list, type.split(";"), player, source); + if (player.hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) { list = CardLists.getNotType(list, "Creature"); } if (cost.payCostFromSource()) { if (source.getController() == ability.getActivatingPlayer() && source.isInPlay()) { - return payer.getController().confirmPayment(cost, "Sacrifice " + source.getName() + "?") ? PaymentDecision.card(source) : null; + return player.getController().confirmPayment(cost, "Sacrifice " + source.getName() + "?") ? PaymentDecision.card(source) : null; } else return null; } @@ -1020,7 +1019,7 @@ public class HumanCostDecision implements ICostVisitor { @Override public PaymentDecision visit(CostTapType cost) { - List typeList = new ArrayList(payer.getCardsIn(ZoneType.Battlefield)); + List typeList = new ArrayList(player.getCardsIn(ZoneType.Battlefield)); String type = cost.getType(); final String amount = cost.getAmount(); Integer c = cost.convertAmount(); @@ -1039,7 +1038,7 @@ public class HumanCostDecision implements ICostVisitor { type = type.replace("+withTotalPowerGE" + totalP, ""); } - typeList = CardLists.getValidCards(typeList, type.split(";"), payer, ability.getSourceCard()); + typeList = CardLists.getValidCards(typeList, type.split(";"), player, ability.getSourceCard()); typeList = CardLists.filter(typeList, Presets.UNTAPPED); if (c == null && !amount.equals("Any")) { final String sVar = ability.getSVar(amount); @@ -1113,8 +1112,8 @@ public class HumanCostDecision implements ICostVisitor { @Override public PaymentDecision visit(CostUntapType cost) { - List typeList = CardLists.getValidCards(payer.getGame().getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), - payer, ability.getSourceCard()); + List typeList = CardLists.getValidCards(player.getGame().getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), + player, ability.getSourceCard()); typeList = CardLists.filter(typeList, Presets.TAPPED); if (!cost.canUntapSource) { typeList.remove(source); @@ -1147,10 +1146,15 @@ public class HumanCostDecision implements ICostVisitor { public PaymentDecision visit(CostUnattach cost) { final Card source = ability.getSourceCard(); - Card cardToUnattach = cost.findCardToUnattach(source, payer, ability); - if (cardToUnattach != null && payer.getController().confirmPayment(cost, "Unattach " + cardToUnattach.getName() + "?")) { + Card cardToUnattach = cost.findCardToUnattach(source, player, ability); + if (cardToUnattach != null && player.getController().confirmPayment(cost, "Unattach " + cardToUnattach.getName() + "?")) { return PaymentDecision.card(cardToUnattach); } return null; } + + @Override + public boolean paysRightAfterDecision() { + return true; + } }