diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java index f91c0859d5b..2b6f3500335 100644 --- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java @@ -264,7 +264,6 @@ public class AiCostDecision extends CostDecisionMakerBase { return res.isEmpty() ? null : PaymentDecision.card(res); } - @Override public PaymentDecision visit(CostGainLife cost) { final List oppsThatCanGainLife = Lists.newArrayList(); @@ -282,7 +281,6 @@ public class AiCostDecision extends CostDecisionMakerBase { return PaymentDecision.players(oppsThatCanGainLife); } - @Override public PaymentDecision visit(CostMill cost) { int c = cost.getAbilityAmount(ability); @@ -681,7 +679,6 @@ public class AiCostDecision extends CostDecisionMakerBase { toRemove += removeCounter(table, prefs, CounterEnumType.LORE, c - toRemove); } - // TODO add logic to remove positive counters? if (c > toRemove && cost.counter != null) { // TODO add logic for Ooze Flux, should probably try to make a token as big as possible diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index a295b5fd928..b198cca6f5c 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -977,7 +977,7 @@ public class ComputerUtilMana { * @param manaSpentToPay list of mana spent * @return whether the floating mana is sufficient to pay the cost fully */ - private static boolean payManaCostFromPool(final ManaCostBeingPaid cost, final SpellAbility sa, final Player ai, + public static boolean payManaCostFromPool(final ManaCostBeingPaid cost, final SpellAbility sa, final Player ai, final boolean test, List manaSpentToPay) { final boolean hasConverge = sa.getHostCard().hasConverge(); List unpaidShards = cost.getUnpaidShards(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java index 87316c9e959..18aae6692eb 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java @@ -325,6 +325,10 @@ public class PlayEffect extends SpellAbilityEffect { tgtSA = tgtSA.copyWithDefinedCost(abCost); } + if (!optional) { + tgtSA.getPayCosts().setMandatory(true); + } + if (sa.hasParam("PlayReduceCost")) { // for Kefnet only can reduce colorless cost String reduce = sa.getParam("PlayReduceCost"); diff --git a/forge-game/src/main/java/forge/game/cost/Cost.java b/forge-game/src/main/java/forge/game/cost/Cost.java index 47ba6109adf..7b194d31300 100644 --- a/forge-game/src/main/java/forge/game/cost/Cost.java +++ b/forge-game/src/main/java/forge/game/cost/Cost.java @@ -186,6 +186,9 @@ public class Cost implements Serializable { public final boolean isMandatory() { return this.isMandatory; } + public final void setMandatory(boolean b) { + isMandatory = b; + } public final boolean isAbility() { return this.isAbility; diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java index 87d9ae1866c..3a27c05e1d6 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java @@ -44,6 +44,7 @@ public abstract class InputPayMana extends InputSyncronizedBase { protected ManaCostBeingPaid manaCost; protected final SpellAbility saPaidFor; protected boolean effect; + protected boolean mandatory = false; private final boolean wasFloatingMana; private final Queue delaySelectCards = new LinkedList<>(); @@ -406,9 +407,9 @@ public abstract class InputPayMana extends InputSyncronizedBase { protected void updateButtons() { if (supportAutoPay()) { - getController().getGui().updateButtons(getOwner(), Localizer.getInstance().getMessage("lblAuto"), Localizer.getInstance().getMessage("lblCancel"), false, true, false); + getController().getGui().updateButtons(getOwner(), Localizer.getInstance().getMessage("lblAuto"), Localizer.getInstance().getMessage("lblCancel"), false, !mandatory, false); } else { - getController().getGui().updateButtons(getOwner(), "", Localizer.getInstance().getMessage("lblCancel"), false, true, false); + getController().getGui().updateButtons(getOwner(), "", Localizer.getInstance().getMessage("lblCancel"), false, !mandatory, false); } } @@ -430,7 +431,7 @@ public abstract class InputPayMana extends InputSyncronizedBase { canPayManaCost = proc.getResult(); } if (canPayManaCost) { //enabled Auto button if mana cost can be paid - getController().getGui().updateButtons(getOwner(), Localizer.getInstance().getMessage("lblAuto"), Localizer.getInstance().getMessage("lblCancel"), true, true, true); + getController().getGui().updateButtons(getOwner(), Localizer.getInstance().getMessage("lblAuto"), Localizer.getInstance().getMessage("lblCancel"), true, !mandatory, true); } } showMessage(getMessage(), saPaidFor.getView()); @@ -447,8 +448,7 @@ public abstract class InputPayMana extends InputSyncronizedBase { if (isAlreadyPaid()) { done(); stop(); - } - else { + } else { FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public void run() { diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java index b18a41c02dc..0f664faeb51 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java @@ -14,10 +14,11 @@ import forge.util.Localizer; public class InputPayManaOfCostPayment extends InputPayMana { - public InputPayManaOfCostPayment(final PlayerControllerHuman controller, ManaCostBeingPaid cost, SpellAbility spellAbility, Player payer, ManaConversionMatrix matrix, boolean effect) { + public InputPayManaOfCostPayment(final PlayerControllerHuman controller, ManaCostBeingPaid cost, SpellAbility spellAbility, Player payer, ManaConversionMatrix matrix, boolean effect, boolean mandatory) { super(controller, spellAbility, payer, effect); manaCost = cost; extraMatrix = matrix; + this.mandatory = mandatory; applyMatrix(); // Set Mana cost being paid for SA to be able to reference it later diff --git a/forge-gui/src/main/java/forge/player/HumanPlay.java b/forge-gui/src/main/java/forge/player/HumanPlay.java index 87a976a6ade..479eb3aed3b 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/player/HumanPlay.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; import forge.ImageKeys; +import forge.ai.ComputerUtilMana; import forge.game.cost.*; import forge.game.spellability.SpellAbilityStackInstance; import org.apache.commons.lang3.StringUtils; @@ -30,6 +31,7 @@ import forge.game.card.CardView; import forge.game.card.CardZoneTable; import forge.game.card.CounterEnumType; import forge.game.card.CounterType; +import forge.game.mana.Mana; import forge.game.mana.ManaConversionMatrix; import forge.game.mana.ManaCostBeingPaid; import forge.game.player.Player; @@ -677,7 +679,15 @@ public class HumanPlay { } if (!toPay.isPaid()) { // Input is somehow clearing out the offering card? - inpPayment = new InputPayManaOfCostPayment(controller, toPay, ability, activator, matrix, effect); + + // forced cast must use pool mana + // TODO this introduces a small risk to lock up the GUI if the human "wastes" enough mana for abilities like Doubling Cube + boolean mandatory = false; + if (matrix instanceof CostPayment && ((CostPayment) matrix).getCost().isMandatory()) { + mandatory = ComputerUtilMana.payManaCostFromPool(new ManaCostBeingPaid(toPay), ability, activator, true, new ArrayList()); + } + + inpPayment = new InputPayManaOfCostPayment(controller, toPay, ability, activator, matrix, effect, mandatory); inpPayment.setMessagePrefix(prompt); inpPayment.showAndWait(); if (!inpPayment.isPaid()) {