diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayerControllableProxy.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayerControllableProxy.java index e03ed1d623f..ea9981f8264 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayerControllableProxy.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayerControllableProxy.java @@ -2,7 +2,6 @@ package mage.player.ai; import mage.MageObject; import mage.abilities.*; -import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.ManaCost; import mage.cards.Card; import mage.cards.Cards; @@ -250,20 +249,11 @@ public class ComputerPlayerControllableProxy extends ComputerPlayer7 { } @Override - public int announceXMana(int min, int max, String message, Game game, Ability ability) { + public int announceX(int min, int max, String message, Game game, Ability source, boolean isManaPay) { if (isUnderMe(game)) { - return super.announceXMana(min, max, message, game, ability); + return super.announceX(min, max, message, game, source, isManaPay); } else { - return getControllingPlayer(game).announceXMana(min, max, message, game, ability); - } - } - - @Override - public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost) { - if (isUnderMe(game)) { - return super.announceXCost(min, max, message, game, ability, variableCost); - } else { - return getControllingPlayer(game).announceXCost(min, max, message, game, ability, variableCost); + return getControllingPlayer(game).announceX(min, max, message, game, source, isManaPay); } } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index b5503877d85..3fb11a77369 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -5,7 +5,6 @@ import mage.ConditionalMana; import mage.MageObject; import mage.Mana; import mage.abilities.*; -import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.*; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; @@ -2039,42 +2038,40 @@ public class ComputerPlayer extends PlayerImpl { } @Override - public int announceXMana(int min, int max, String message, Game game, Ability ability) { - // current logic - use max possible mana + public int announceX(int min, int max, String message, Game game, Ability source, boolean isManaPay) { + // fast calc on nothing to choose + if (min >= max) { + return min; + } // TODO: add good/bad effects support - // TODO: add simple game simulations like declare blocker? + // TODO: add simple game simulations like declare blocker (need to find only workable payment)? + // TODO: remove random logic or make it more stable (e.g. use same value in same game cycle) - int numAvailable = getAvailableManaProducers(game).size() - ability.getManaCosts().manaValue(); - if (numAvailable < 0) { - numAvailable = 0; + // protection from too big values + int realMin = min; + int realMax = max; + if (max == Integer.MAX_VALUE) { + realMax = Math.max(realMin, 10); // AI don't need huge values for X, cause can't use infinite combos + } + + int xValue; + if (isManaPay) { + // as X mana payment - due available mana + xValue = Math.max(0, getAvailableManaProducers(game).size() - source.getManaCostsToPay().getUnpaid().manaValue()); } else { - if (numAvailable < min) { - numAvailable = min; - } - if (numAvailable > max) { - numAvailable = max; - } + // as X actions + xValue = RandomUtil.nextInt(realMax + 1); } - return numAvailable; - } - @Override - public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variablCost) { - // current logic - use random non-zero value - - // TODO: add good/bad effects support - // TODO: remove random logic - - int value = RandomUtil.nextInt(CardUtil.overflowInc(max, 1)); - if (value < min) { - value = min; + if (xValue > realMax) { + xValue = realMax; } - if (value < max) { - // do not use zero values - value++; + if (xValue < realMin) { + xValue = realMin; } - return value; + + return xValue; } @Override diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 61f35a1cd2a..c50062e7393 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -1687,64 +1687,39 @@ public class HumanPlayer extends PlayerImpl { } /** - * Gets the amount of mana the player want to spent for a x spell - * - * @param min - * @param max - * @param message - * @param ability - * @param game - * @return + * Gets the amount of mana the player want to spend for an x spell */ @Override - public int announceXMana(int min, int max, String message, Game game, Ability ability) { + public int announceX(int min, int max, String message, Game game, Ability source, boolean isManaPay) { if (!canCallFeedback(game)) { return min; } - int xValue = 0; - while (canRespond()) { - prepareForResponse(game); - if (!isExecutingMacro()) { - game.fireGetAmountEvent(playerId, message + CardUtil.getSourceLogName(game, ability), min, max); - } - waitForResponse(game); - - if (response.getInteger() != null) { - break; - } - - // TODO: add response verify here - } - - if (response.getInteger() != null) { - xValue = response.getInteger(); - } - return xValue; - } - - @Override - public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost) { - if (!canCallFeedback(game)) { + // fast calc on nothing to choose + if (min >= max) { return min; } - int xValue = 0; + int xValue = min; while (canRespond()) { prepareForResponse(game); if (!isExecutingMacro()) { - game.fireGetAmountEvent(playerId, message, min, max); + game.fireGetAmountEvent(playerId, message + CardUtil.getSourceLogName(game, source), min, max); } waitForResponse(game); - if (response.getInteger() != null) { - break; + if (response.getInteger() == null) { + continue; } + + xValue = response.getInteger(); + if (xValue < min || xValue > max) { + continue; + } + + break; } - if (response.getInteger() != null) { - xValue = response.getInteger(); - } return xValue; } diff --git a/Mage.Sets/src/mage/cards/a/AzorTheLawbringer.java b/Mage.Sets/src/mage/cards/a/AzorTheLawbringer.java index 6159e195bbe..82467e4f9b8 100644 --- a/Mage.Sets/src/mage/cards/a/AzorTheLawbringer.java +++ b/Mage.Sets/src/mage/cards/a/AzorTheLawbringer.java @@ -163,7 +163,7 @@ class AzorTheLawbringerAttacksEffect extends OneShotEffect { if (controller != null) { ManaCosts cost = new ManaCostsImpl<>("{X}{W}{U}{U}"); if (controller.chooseUse(Outcome.Damage, "Pay " + cost.getText() + "? If you do, you gain X life and draw X cards.", source, game)) { - int costX = controller.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = controller.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (gain life and draw cards)", game, source,true); cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source, source.getControllerId(), false, null)) { controller.resetStoredBookmark(game); // otherwise you can undo the payment diff --git a/Mage.Sets/src/mage/cards/d/DepalaPilotExemplar.java b/Mage.Sets/src/mage/cards/d/DepalaPilotExemplar.java index 126338d0e63..1af7a79cc1e 100644 --- a/Mage.Sets/src/mage/cards/d/DepalaPilotExemplar.java +++ b/Mage.Sets/src/mage/cards/d/DepalaPilotExemplar.java @@ -86,7 +86,7 @@ class DepalaPilotExemplarEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { ManaCosts cost = new ManaCostsImpl<>("{X}"); - int xValue = controller.announceXMana(0, Integer.MAX_VALUE, "Choose the amount of mana to pay", game, source); + int xValue = controller.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to reveal)", game, source, true); cost.add(new GenericManaCost(xValue)); if (cost.pay(source, game, source, source.getControllerId(), false) && xValue > 0) { new RevealLibraryPutIntoHandEffect(xValue, filter, Zone.LIBRARY, false).apply(game, source); diff --git a/Mage.Sets/src/mage/cards/e/ElendaAndAzor.java b/Mage.Sets/src/mage/cards/e/ElendaAndAzor.java index 12d6d51fff6..5affdf40281 100644 --- a/Mage.Sets/src/mage/cards/e/ElendaAndAzor.java +++ b/Mage.Sets/src/mage/cards/e/ElendaAndAzor.java @@ -80,7 +80,7 @@ class ElendaAndAzorEffect extends OneShotEffect { if (controller != null) { ManaCosts cost = new ManaCostsImpl<>("{X}{W}{U}{B}"); if (controller.chooseUse(Outcome.Damage, "Pay " + cost.getText() + "? If you do, draw X cards.", source, game)) { - int costX = controller.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = controller.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to draw)", game, source, true); cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source, source.getControllerId(), false, null)) { controller.resetStoredBookmark(game); // otherwise you can undo the payment diff --git a/Mage.Sets/src/mage/cards/f/FlameblastDragon.java b/Mage.Sets/src/mage/cards/f/FlameblastDragon.java index 805dcde3cb1..1b889e3a381 100644 --- a/Mage.Sets/src/mage/cards/f/FlameblastDragon.java +++ b/Mage.Sets/src/mage/cards/f/FlameblastDragon.java @@ -68,7 +68,7 @@ class FlameblastDragonEffect extends OneShotEffect { ManaCosts cost = new ManaCostsImpl<>("{X}{R}"); if (player != null) { if (player.chooseUse(Outcome.Damage, "Pay " + cost.getText() + "? If you do, Flameblast Dragon deals X damage to any target", source, game)) { - int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to damage)", game, source, true); cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source, source.getControllerId(), false, null)) { Permanent permanent = game.getPermanent(source.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/h/HaloForager.java b/Mage.Sets/src/mage/cards/h/HaloForager.java index 53602eb6b58..f657cef2630 100644 --- a/Mage.Sets/src/mage/cards/h/HaloForager.java +++ b/Mage.Sets/src/mage/cards/h/HaloForager.java @@ -78,7 +78,7 @@ class HaloForagerPayEffect extends OneShotEffect { if (player == null || !player.chooseUse(outcome, "Pay " + cost.getText() + "?", source, game)) { return false; } - int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to free cast)", game, source, true); cost.add(new GenericManaCost(costX)); if (!cost.pay(source, game, source, source.getControllerId(), false, null)) { return false; diff --git a/Mage.Sets/src/mage/cards/h/HeroOfLeinaTower.java b/Mage.Sets/src/mage/cards/h/HeroOfLeinaTower.java index 499e959a430..f043b94587d 100644 --- a/Mage.Sets/src/mage/cards/h/HeroOfLeinaTower.java +++ b/Mage.Sets/src/mage/cards/h/HeroOfLeinaTower.java @@ -70,7 +70,7 @@ class HeroOfLeinaTowerEffect extends OneShotEffect { Player you = game.getPlayer(source.getControllerId()); ManaCosts cost = new ManaCostsImpl<>("{X}"); if (you != null && you.chooseUse(Outcome.BoostCreature, "Do you want to to pay {X}?", source, game)) { - int costX = you.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = you.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to add +1/+1 counters)", game, source, true); cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source, source.getControllerId(), false, null)) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/i/IncineratorOfTheGuilty.java b/Mage.Sets/src/mage/cards/i/IncineratorOfTheGuilty.java index da0c6f4a502..2c9e23f4abb 100644 --- a/Mage.Sets/src/mage/cards/i/IncineratorOfTheGuilty.java +++ b/Mage.Sets/src/mage/cards/i/IncineratorOfTheGuilty.java @@ -88,7 +88,7 @@ class IncineratorOfTheGuiltyEffect extends OneShotEffect { return false; } - int xValue = controller.announceXMana(0, Integer.MAX_VALUE, "Announce the value for X", game, source); + int xValue = controller.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (collect evidence)", game, source, false); CollectEvidenceCost cost = new CollectEvidenceCost(xValue); if (!cost.pay(source, game, source, source.getControllerId(), false, null)) { return false; diff --git a/Mage.Sets/src/mage/cards/i/IsarethTheAwakener.java b/Mage.Sets/src/mage/cards/i/IsarethTheAwakener.java index 95b2b0815dc..4b3c0afda9c 100644 --- a/Mage.Sets/src/mage/cards/i/IsarethTheAwakener.java +++ b/Mage.Sets/src/mage/cards/i/IsarethTheAwakener.java @@ -85,7 +85,7 @@ class IsarethTheAwakenerCreateReflexiveTriggerEffect extends OneShotEffect { || !player.chooseUse(Outcome.BoostCreature, "Pay " + cost.getText() + "?", source, game)) { return false; } - int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to return due mana value)", game, source, true); cost.add(new GenericManaCost(costX)); if (!cost.pay(source, game, source, source.getControllerId(), false, null)) { return false; diff --git a/Mage.Sets/src/mage/cards/l/LeylineTyrant.java b/Mage.Sets/src/mage/cards/l/LeylineTyrant.java index 79ea7dd9264..26b38cbb819 100644 --- a/Mage.Sets/src/mage/cards/l/LeylineTyrant.java +++ b/Mage.Sets/src/mage/cards/l/LeylineTyrant.java @@ -111,10 +111,8 @@ class LeylineTyrantDamageEffect extends OneShotEffect { if (player == null) { return false; } - int costX = player.announceXMana( - 0, Integer.MAX_VALUE, - "Announce the value for {X}", game, source - ); + // TODO: add some AI hints by min/max values + int costX = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source, true); String manaString; if (costX == 0) { manaString = "{0}"; diff --git a/Mage.Sets/src/mage/cards/n/NumaJoragaChieftain.java b/Mage.Sets/src/mage/cards/n/NumaJoragaChieftain.java index 04c6abef386..003c8eaae29 100644 --- a/Mage.Sets/src/mage/cards/n/NumaJoragaChieftain.java +++ b/Mage.Sets/src/mage/cards/n/NumaJoragaChieftain.java @@ -81,7 +81,8 @@ class NumaJoragaChieftainEffect extends OneShotEffect { if (!player.chooseUse(Outcome.BoostCreature, "Pay " + cost.getText() + "?", source, game)) { return false; } - int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + // TODO: add some AI hints by min/max values + int costX = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to distribute counters)", game, source,true); cost.add(new GenericManaCost(2 * costX)); if (!cost.pay(source, game, source, source.getControllerId(), false, null)) { return false; diff --git a/Mage.Sets/src/mage/cards/p/PowerLeak.java b/Mage.Sets/src/mage/cards/p/PowerLeak.java index 8acc101045c..82e7049363d 100644 --- a/Mage.Sets/src/mage/cards/p/PowerLeak.java +++ b/Mage.Sets/src/mage/cards/p/PowerLeak.java @@ -80,7 +80,7 @@ class PowerLeakEffect extends OneShotEffect { String message = "Pay {X} to prevent X damage from " + permanent.getLogName() + "?"; int xValue = 0; if (player.chooseUse(Outcome.Neutral, message, source, game)) { - xValue = player.announceXMana(0, Integer.MAX_VALUE, "Choose the amount of mana to pay", game, source); + xValue = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to prevent damage)", game, source, true); cost.add(new GenericManaCost(xValue)); if (cost.pay(source, game, source, player.getId(), false, null)) { game.informPlayers(player.getLogName() + " paid {" + xValue + "} for " + permanent.getLogName()); diff --git a/Mage.Sets/src/mage/cards/r/RemnantOfTheRisingStar.java b/Mage.Sets/src/mage/cards/r/RemnantOfTheRisingStar.java index a1a22a47838..dc9338acb2e 100644 --- a/Mage.Sets/src/mage/cards/r/RemnantOfTheRisingStar.java +++ b/Mage.Sets/src/mage/cards/r/RemnantOfTheRisingStar.java @@ -116,7 +116,7 @@ class RemnantOfTheRisingStarEffect extends OneShotEffect { )) { return false; } - int xValue = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int xValue = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to add counters)", game, source, true); cost.add(new GenericManaCost(xValue)); if (!cost.pay(source, game, source, source.getControllerId(), false, null)) { return false; diff --git a/Mage.Sets/src/mage/cards/r/RiseOfTheHobgoblins.java b/Mage.Sets/src/mage/cards/r/RiseOfTheHobgoblins.java index a425674fae7..d1a4c2bacd8 100644 --- a/Mage.Sets/src/mage/cards/r/RiseOfTheHobgoblins.java +++ b/Mage.Sets/src/mage/cards/r/RiseOfTheHobgoblins.java @@ -19,7 +19,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; @@ -87,7 +86,7 @@ class RiseOfTheHobgoblinsEffect extends OneShotEffect { Player you = game.getPlayer(source.getControllerId()); ManaCosts cost = new ManaCostsImpl<>("{X}"); if (you != null && you.chooseUse(Outcome.Neutral, "Do you want to to pay {X}?", source, game)) { - int costX = you.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = you.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to add counters)", game, source, true); cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source, source.getControllerId(), false, null)) { Token token = new GoblinSoldierToken(); diff --git a/Mage.Sets/src/mage/cards/r/RoseRoomTreasurer.java b/Mage.Sets/src/mage/cards/r/RoseRoomTreasurer.java index eaae8b13b14..bc18ac0f02e 100644 --- a/Mage.Sets/src/mage/cards/r/RoseRoomTreasurer.java +++ b/Mage.Sets/src/mage/cards/r/RoseRoomTreasurer.java @@ -80,7 +80,7 @@ class RoseRoomTreasurerEffect extends OneShotEffect { if (!player.chooseUse(Outcome.BoostCreature, "Pay {X}?", source, game)) { return false; } - int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to damage)", game, source, true); cost.add(new GenericManaCost(costX)); if (!cost.pay(source, game, source, source.getControllerId(), false)) { return false; diff --git a/Mage.Sets/src/mage/cards/s/SanctumPrelate.java b/Mage.Sets/src/mage/cards/s/SanctumPrelate.java index 04249ece695..b450095c96c 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumPrelate.java +++ b/Mage.Sets/src/mage/cards/s/SanctumPrelate.java @@ -62,7 +62,7 @@ class ChooseNumberEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - int numberChoice = controller.announceXMana(0, Integer.MAX_VALUE, "Choose a number.", game, source); + int numberChoice = controller.getAmount(0, Integer.MAX_VALUE, "Choose a number (mana cost to restrict)", game); game.getState().setValue(source.getSourceId().toString(), numberChoice); Permanent permanent = game.getPermanentEntering(source.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/s/SquealingDevil.java b/Mage.Sets/src/mage/cards/s/SquealingDevil.java index 3071f0108ee..556bc576a33 100644 --- a/Mage.Sets/src/mage/cards/s/SquealingDevil.java +++ b/Mage.Sets/src/mage/cards/s/SquealingDevil.java @@ -18,7 +18,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.constants.ColoredManaSymbol; import mage.constants.Duration; import mage.constants.Outcome; import mage.game.Game; @@ -80,7 +79,7 @@ class SquealingDevilEffect extends OneShotEffect { ManaCosts cost = new ManaCostsImpl<>("{X}"); if (player != null) { if (player.chooseUse(Outcome.BoostCreature, "Pay " + cost.getText() + "?", source, game)) { - int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to boost)", game, source, true); cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source, source.getControllerId(), false, null)) { Permanent permanent = game.getPermanent(source.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/s/SqueesRevenge.java b/Mage.Sets/src/mage/cards/s/SqueesRevenge.java index abcc430c0ac..acdbf4d1fc7 100644 --- a/Mage.Sets/src/mage/cards/s/SqueesRevenge.java +++ b/Mage.Sets/src/mage/cards/s/SqueesRevenge.java @@ -53,7 +53,7 @@ class SqueesRevengeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if(player != null) { - int number = player.announceXMana(0, Integer.MAX_VALUE, "Choose how many times to flip a coin", game, source); + int number = player.getAmount(0, Integer.MAX_VALUE, "Choose how many times to flip a coin", game); game.informPlayers(player.getLogName() + " chooses " + number + '.'); for(int i = 0; i < number; i++) { if(!player.flipCoin(source, game, true)) { diff --git a/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java b/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java index 3e2481b2b96..072b3afc92d 100644 --- a/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java +++ b/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java @@ -78,7 +78,7 @@ class TilonallisSummonerEffect extends OneShotEffect { if (controller != null) { ManaCosts cost = new ManaCostsImpl<>("{X}{R}"); if (controller.chooseUse(outcome, "Pay " + cost.getText() + "? If you do, you create X 1/1 red Elemental creature tokens that are tapped and attacking.", source, game)) { - int costX = controller.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = controller.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay for tokens)", game, source, true); cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source, source.getControllerId(), false, null)) { controller.resetStoredBookmark(game); // otherwise you can undo the payment diff --git a/Mage.Sets/src/mage/cards/v/VigilForTheLost.java b/Mage.Sets/src/mage/cards/v/VigilForTheLost.java index b1dea4e1a2c..5350f2c0c15 100644 --- a/Mage.Sets/src/mage/cards/v/VigilForTheLost.java +++ b/Mage.Sets/src/mage/cards/v/VigilForTheLost.java @@ -53,7 +53,7 @@ class VigilForTheLostEffect extends OneShotEffect { if (controller == null) { return false; } - int costX = controller.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = controller.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to gain life)", game, source, true); if (new GenericManaCost(costX).pay(source, game, source, source.getControllerId(), false, null)) { controller.gainLife(costX, game, source); return true; diff --git a/Mage.Sets/src/mage/cards/v/Void.java b/Mage.Sets/src/mage/cards/v/Void.java index 79062b8d7a4..20e380721ef 100644 --- a/Mage.Sets/src/mage/cards/v/Void.java +++ b/Mage.Sets/src/mage/cards/v/Void.java @@ -64,7 +64,7 @@ class VoidEffect extends OneShotEffect { return false; } - int number = controller.announceXMana(0, Integer.MAX_VALUE, this.staticText, game, source); + int number = controller.getAmount(0, Integer.MAX_VALUE, "Choose a number (mana cost to destroy)", game); game.informPlayers(controller.getLogName() + " chooses " + number + '.'); for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { diff --git a/Mage.Sets/src/mage/cards/w/WellOfLostDreams.java b/Mage.Sets/src/mage/cards/w/WellOfLostDreams.java index d21bdd918bd..cc808325600 100644 --- a/Mage.Sets/src/mage/cards/w/WellOfLostDreams.java +++ b/Mage.Sets/src/mage/cards/w/WellOfLostDreams.java @@ -59,7 +59,7 @@ class WellOfLostDreamsEffect extends OneShotEffect { if (controller != null) { int amount = SavedGainedLifeValue.MANY.calculate(game, source, this); if (amount > 0) { - int xValue = controller.announceXMana(0, amount, "Announce X Value", game, source); + int xValue = controller.announceX(0, amount, "Announce the value for {X} (pay for draw cards)", game, source, true); if (xValue > 0) { if (new GenericManaCost(xValue).pay(source, game, source, controller.getId(), false)) { game.informPlayers(controller.getLogName() + " payed {" + xValue + '}'); diff --git a/Mage.Sets/src/mage/cards/w/WildbornPreserver.java b/Mage.Sets/src/mage/cards/w/WildbornPreserver.java index 64cb4c6b4b3..a0401674991 100644 --- a/Mage.Sets/src/mage/cards/w/WildbornPreserver.java +++ b/Mage.Sets/src/mage/cards/w/WildbornPreserver.java @@ -94,7 +94,7 @@ class WildbornPreserverCreateReflexiveTriggerEffect extends OneShotEffect { if (!player.chooseUse(outcome, "Pay " + cost.getText() + "?", source, game)) { return false; } - int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + int costX = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay for counters)", game, source, true); cost.add(new GenericManaCost(costX)); if (!cost.pay(source, game, source, source.getControllerId(), false, null)) { return false; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java index 17a56f1223a..e776a7cab04 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java @@ -23,7 +23,7 @@ public class ProteanHydraTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Protean Hydra"); - setStrictChooseMode(false); // test AI use max for X + setStrictChooseMode(false); // TODO: good test for AI's announceX - duplicate it as AI test setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SoulBurnTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SoulBurnTest.java index 017d4715f69..f02ef2a7f41 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SoulBurnTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SoulBurnTest.java @@ -169,6 +169,7 @@ public class SoulBurnTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Soul Burn", "Craw Wurm"); + setStrictChooseMode(false); // TODO: good test for AI's announceX - duplicate it as AI test (few examples) setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerB, "Craw Wurm", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/IncreasingCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/IncreasingCardsTest.java index 7a5bb88a941..0d62b9fbc3c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/IncreasingCardsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/IncreasingCardsTest.java @@ -56,6 +56,7 @@ public class IncreasingCardsTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Increasing Confusion"); activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Flashback {X}{U}"); + setStrictChooseMode(false); // TODO: good test for AI's announceX - duplicate it as AI test setStopAt(3, PhaseStep.BEGIN_COMBAT); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/HELIOSOneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/HELIOSOneTest.java index cd19de6bbda..61d6e137bba 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/HELIOSOneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/HELIOSOneTest.java @@ -65,7 +65,7 @@ public class HELIOSOneTest extends CardTestPlayerBase { } catch (AssertionError e) { Assert.assertTrue( "X=0 is not a valid choice. Error message:\n" + e.getMessage(), - e.getMessage().contains("Message: Announce the number of {E} to pay") + e.getMessage().contains("Message: Announce the value for {X}") ); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/PostMortemLungeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/PostMortemLungeTest.java index f2af0ab763c..6ea6014bd60 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/PostMortemLungeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/PostMortemLungeTest.java @@ -29,6 +29,7 @@ public class PostMortemLungeTest extends CardTestPlayerBase { attack(1, playerA, "Elite Vanguard"); + setStrictChooseMode(false); // TODO: good test for AI's announceX - duplicate it as AI test setStopAt(1, PhaseStep.CLEANUP); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 34d1fd417ab..f3983b39d03 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -6,7 +6,6 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.AlternativeSourceCosts; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; -import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.effects.common.InfoEffect; @@ -2916,39 +2915,20 @@ public class TestPlayer implements Player { } @Override - public int announceXMana(int min, int max, String message, Game game, Ability ability) { - assertAliasSupportInChoices(false); - if (!choices.isEmpty()) { - for (String choice : new ArrayList<>(choices)) { - if (choice.startsWith("X=")) { - int xValue = Integer.parseInt(choice.substring(2)); - assertXMinMaxValue(game, ability, xValue, min, max); - choices.remove(choice); - return xValue; - } - } - } - - this.chooseStrictModeFailed("choice", game, getInfo(ability, game) - + "\nMessage: " + message + prepareXMaxInfo(min, max)); - return computerPlayer.announceXMana(min, max, message, game, ability); - } - - @Override - public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variablCost) { + public int announceX(int min, int max, String message, Game game, Ability source, boolean isManaPay) { assertAliasSupportInChoices(false); if (!choices.isEmpty()) { if (choices.get(0).startsWith("X=")) { int xValue = Integer.parseInt(choices.get(0).substring(2)); - assertXMinMaxValue(game, ability, xValue, min, max); + assertXMinMaxValue(game, source, xValue, min, max); choices.remove(0); return xValue; } } - this.chooseStrictModeFailed("choice", game, getInfo(ability, game) + this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\nMessage: " + message + prepareXMaxInfo(min, max)); - return computerPlayer.announceXCost(min, max, message, game, ability, null); + return computerPlayer.announceX(min, max, message, game, source, isManaPay); } private String prepareXMaxInfo(int min, int max) { diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 4a01534e11b..1b8223083ba 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -787,8 +787,8 @@ public abstract class AbilityImpl implements Ability { xValue = variableManaCost.getAmount(); } else { // announce by player - xValue = controller.announceXMana(variableManaCost.getMinX(), variableManaCost.getMaxX(), - "Announce the value for " + variableManaCost.getText(), game, this); + xValue = controller.announceX(variableManaCost.getMinX(), variableManaCost.getMaxX(), + "Announce the value for " + variableManaCost.getText(), game, this, true); } int amountMana = xValue * variableManaCost.getXInstancesCount(); diff --git a/Mage/src/main/java/mage/abilities/costs/VariableCostImpl.java b/Mage/src/main/java/mage/abilities/costs/VariableCostImpl.java index 8a1ccfde03c..d08ff68bfc7 100644 --- a/Mage/src/main/java/mage/abilities/costs/VariableCostImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/VariableCostImpl.java @@ -158,8 +158,8 @@ public abstract class VariableCostImpl implements Cost, VariableCost { if (controller != null && (source instanceof ManaAbility || stackObject != null)) { - xValue = controller.announceXCost(getMinValue(source, game), getMaxValue(source, game), - "Announce the number of " + actionText, game, source, this); + xValue = controller.announceX(getMinValue(source, game), getMaxValue(source, game), + "Announce the value for {X} (" + actionText + ")", game, source, false); } return xValue; } diff --git a/Mage/src/main/java/mage/abilities/keyword/AssistAbility.java b/Mage/src/main/java/mage/abilities/keyword/AssistAbility.java index 295361da40c..bb2e45721c7 100644 --- a/Mage/src/main/java/mage/abilities/keyword/AssistAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/AssistAbility.java @@ -173,8 +173,8 @@ class AssistEffect extends OneShotEffect { // AI can't assist other players, maybe for teammates only (but tests must work as normal) int amountToPay = 0; if (!targetPlayer.isComputer()) { - amountToPay = targetPlayer.announceXMana(0, unpaid.getMana().getGeneric(), - "How much mana to pay as assist for " + controller.getName() + "?", game, source); + amountToPay = targetPlayer.announceX(0, unpaid.getMana().getGeneric(), + "How much mana to pay as assist for " + controller.getName() + "?", game, source, true); } if (amountToPay > 0) { diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index ffa1ce89da7..f614a215990 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -5,7 +5,6 @@ import mage.abilities.*; import mage.abilities.costs.AlternativeSourceCosts; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; -import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.mana.ManaOptions; @@ -748,16 +747,12 @@ public interface Player extends MageItem, Copyable { boolean shuffleCardsToLibrary(Card card, Game game, Ability source); /** - * Set the value for X mana spells and abilities + * Set the value for X in spells and abilities + * @param isManaPay helper param for better AI logic */ - int announceXMana(int min, int max, String message, Game game, Ability ability); + int announceX(int min, int max, String message, Game game, Ability source, boolean isManaPay); - /** - * Set the value for non mana X costs - */ - int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost); - - // TODO: rework to use pair's list of effect + ability instead string's map + // TODO: rework to use pair's list of effect + ability instead string's map int chooseReplacementEffect(Map effectsMap, Map objectsMap, Game game); TriggeredAbility chooseTriggeredAbility(List abilities, Game game); diff --git a/Mage/src/main/java/mage/players/StubPlayer.java b/Mage/src/main/java/mage/players/StubPlayer.java index dd86c1d90f2..da47009b213 100644 --- a/Mage/src/main/java/mage/players/StubPlayer.java +++ b/Mage/src/main/java/mage/players/StubPlayer.java @@ -156,13 +156,8 @@ public class StubPlayer extends PlayerImpl { } @Override - public int announceXMana(int min, int max, String message, Game game, Ability ability) { - return 0; - } - - @Override - public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost) { - return 0; + public int announceX(int min, int max, String message, Game game, Ability source, boolean isManaPay) { + return min; } @Override diff --git a/Mage/src/main/java/mage/util/ManaUtil.java b/Mage/src/main/java/mage/util/ManaUtil.java index 816353e13e9..f86f376a1d0 100644 --- a/Mage/src/main/java/mage/util/ManaUtil.java +++ b/Mage/src/main/java/mage/util/ManaUtil.java @@ -710,7 +710,7 @@ public final class ManaUtil { int bookmark = game.bookmarkState(); player.resetStoredBookmark(game); - wantToPay = player.announceXMana(0, maxValue, "Choose how much mana to pay", game, source); + wantToPay = player.announceX(0, maxValue, "Choose how much mana to pay", game, source, true); if (wantToPay > 0) { Cost cost = ManaUtil.createManaCost(wantToPay, payAsX); payed = cost.pay(source, game, source, player.getId(), false, null);