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 9276dd1e0ff..a07ef825857 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 @@ -50,10 +50,7 @@ import mage.players.net.UserData; import mage.players.net.UserGroup; import mage.target.*; import mage.target.common.*; -import mage.util.Copier; -import mage.util.RandomUtil; -import mage.util.TournamentUtil; -import mage.util.TreeNode; +import mage.util.*; import org.apache.log4j.Logger; import java.io.IOException; @@ -1666,8 +1663,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { @Override public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variablCost) { log.debug("announceXCost"); - //TODO: improve this - int value = RandomUtil.nextInt(max + 1); + int value = RandomUtil.nextInt(CardUtil.overflowInc(max, 1)); if (value < min) { value = min; } @@ -1964,9 +1960,8 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (message.startsWith("Assign damage to ")) { return min; } - //TODO: improve this if (min < max && min == 0) { - return RandomUtil.nextInt(max + 1); + return RandomUtil.nextInt(CardUtil.overflowInc(max, 1)); } return min; } diff --git a/Mage.Sets/src/mage/cards/c/ChoiceOfDamnations.java b/Mage.Sets/src/mage/cards/c/ChoiceOfDamnations.java index ab962db6e2e..4ab2e64b8df 100644 --- a/Mage.Sets/src/mage/cards/c/ChoiceOfDamnations.java +++ b/Mage.Sets/src/mage/cards/c/ChoiceOfDamnations.java @@ -1,14 +1,12 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; @@ -18,14 +16,15 @@ import mage.target.Target; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ChoiceOfDamnations extends CardImpl { public ChoiceOfDamnations(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{5}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{B}"); this.subtype.add(SubType.ARCANE); // Target opponent chooses a number. You may have that player lose that much life. If you don't, that player sacrifices all but that many permanents. @@ -63,13 +62,40 @@ class ChoiceOfDamnationsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); if (targetPlayer != null) { - int amount = targetPlayer.getAmount(0, Integer.MAX_VALUE, "Chooses a number", game); + int numberPermanents = game.getState().getBattlefield().countAll(new FilterPermanent(), targetPlayer.getId(), game); + + // AI hint + int amount; + if (!targetPlayer.isHuman() && !targetPlayer.isTestMode()) { + // AI as defender + int safeLifeToLost = Math.max(0, targetPlayer.getLife() / 2); + amount = Math.min(numberPermanents, safeLifeToLost); + } else { + // Human must choose + amount = targetPlayer.getAmount(0, Integer.MAX_VALUE, "Chooses a number", game); + } + Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.chooseUse(outcome, "Shall " + targetPlayer.getLogName() + " lose " + amount + " life?", source, game)) { + + // AI hint + boolean chooseLoseLife; + if (!targetPlayer.isHuman() && !targetPlayer.isTestMode()) { + // AI as attacker + chooseLoseLife = (numberPermanents == 0 || amount <= numberPermanents || targetPlayer.getLife() < amount); + } else { + // Human must choose + chooseLoseLife = controller.chooseUse(outcome, "Shall " + targetPlayer.getLogName() + " lose " + amount + " life?", source, game); + } + + if (chooseLoseLife) { targetPlayer.loseLife(amount, game, source, false); } else { - int numberPermanents = game.getState().getBattlefield().countAll(new FilterPermanent(), targetPlayer.getId(), game); + // rules: + // If the opponent must sacrifice all but a number of permanents, that opponent chooses that many + // permanents and then sacrifices the rest. If the number chosen is greater than the number of + // permanents the opponent controls, the player sacrifices nothing. + // (2005-06-01) if (numberPermanents > amount) { int numberToSacrifice = numberPermanents - amount; Target target = new TargetControlledPermanent(numberToSacrifice, numberToSacrifice, new FilterControlledPermanent("permanent you control to sacrifice"), false); diff --git a/Mage.Sets/src/mage/cards/p/PainsReward.java b/Mage.Sets/src/mage/cards/p/PainsReward.java index 1871ca7ca93..9e379ccff6e 100644 --- a/Mage.Sets/src/mage/cards/p/PainsReward.java +++ b/Mage.Sets/src/mage/cards/p/PainsReward.java @@ -1,8 +1,5 @@ - package mage.cards.p; -import java.util.Objects; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -13,15 +10,16 @@ import mage.game.Game; import mage.players.Player; import mage.players.PlayerList; +import java.util.Objects; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class PainsReward extends CardImpl { public PainsReward(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); // Each player may bid life. You start the bidding with a bid of any number. In turn order, each player may top the high bid. The bidding ends if the high bid stands. The high bidder loses life equal to the high bid and draws four cards. this.getSpellAbility().addEffect(new PainsRewardEffect()); @@ -62,14 +60,19 @@ class PainsRewardEffect extends OneShotEffect { playerList.setCurrent(controller.getId()); Player winner = game.getPlayer(controller.getId()); - int highBid = controller.getAmount(0, Integer.MAX_VALUE, "Choose amount of life to bid", game); + int highBid = chooseLifeAmountToBid(controller, -1, game); // -1 for start with 0 min big game.informPlayers(winner.getLogName() + " has bet " + highBid + " lifes"); Player currentPlayer = playerList.getNextInRange(controller, game); while (currentPlayer != null && !Objects.equals(currentPlayer, winner)) { String text = winner.getLogName() + " has bet " + highBid + " life" + (highBid > 1 ? "s" : "") + ". Top the bid?"; - if (currentPlayer.chooseUse(Outcome.Detriment, text, source, game)) { - int newBid = currentPlayer.getAmount(highBid + 1, Integer.MAX_VALUE, "Choose amount of life to bid", game); + + // AI hint + int safeLifeToLost = Math.min(6, currentPlayer.getLife() / 2); + Outcome aiOutcome = (highBid + 1 <= safeLifeToLost) ? Outcome.Benefit : Outcome.Detriment; + + if (currentPlayer.chooseUse(aiOutcome, text, source, game)) { + int newBid = chooseLifeAmountToBid(currentPlayer, highBid, game); if (newBid > highBid) { highBid = newBid; winner = currentPlayer; @@ -86,4 +89,16 @@ class PainsRewardEffect extends OneShotEffect { } return false; } + + private int chooseLifeAmountToBid(Player player, int currentBig, Game game) { + int newBid; + if (!player.isHuman() && !player.isTestMode()) { + // AI choose + newBid = currentBig + 1; + } else { + // Human choose + newBid = player.getAmount(currentBig + 1, Integer.MAX_VALUE, "Choose amount of life to bid", game); + } + return newBid; + } } diff --git a/Mage.Sets/src/mage/cards/v/VolcanoHellion.java b/Mage.Sets/src/mage/cards/v/VolcanoHellion.java index 7fd1d599bc5..66e5ff2148f 100644 --- a/Mage.Sets/src/mage/cards/v/VolcanoHellion.java +++ b/Mage.Sets/src/mage/cards/v/VolcanoHellion.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,15 +9,16 @@ import mage.abilities.keyword.EchoAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class VolcanoHellion extends CardImpl { @@ -54,7 +53,7 @@ public final class VolcanoHellion extends CardImpl { class VolcanoHellionEffect extends OneShotEffect { public VolcanoHellionEffect() { - super(Outcome.AIDontUseIt); + super(Outcome.Damage); this.staticText = "it deals an amount of damage of your choice to you and target creature. The damage can't be prevented"; } @@ -72,7 +71,20 @@ class VolcanoHellionEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getFirstTarget()); if (controller != null) { - int amount = controller.getAmount(0, Integer.MAX_VALUE, "Choose the amount of damage to deliver to you and a target creature. The damage can't be prevented.", game); + int amount; + if (!controller.isHuman() && !controller.isTestMode()) { + // AI hint: have much life and can destroy target permanent + int safeLifeToLost = Math.min(6, controller.getLife() / 2); + if (permanent != null && permanent.getToughness().getValue() <= safeLifeToLost) { + amount = permanent.getToughness().getValue(); + } else { + amount = 0; + } + } else { + //Human choose + amount = controller.getAmount(0, Integer.MAX_VALUE, "Choose the amount of damage to deliver to you and a target creature. The damage can't be prevented.", game); + } + if (amount > 0) { controller.damage(amount, source.getSourceId(), source, game, false, false); if (permanent != null) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsInCommanderTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsInCommanderTest.java index 8d0ce5fd6d8..9e1df5fe11c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsInCommanderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsInCommanderTest.java @@ -46,10 +46,6 @@ public class ModalDoubleFacesCardsInCommanderTest extends CardTestCommanderDuelB addCard(Zone.LIBRARY, playerA, "Forest"); addCard(Zone.LIBRARY, playerA, "Grizzly Bears"); addCard(Zone.LIBRARY, playerA, "Forest"); - // - // Exile target artifact or enchantment. - addCard(Zone.HAND, playerB, "Ironwright's Cleansing"); // {2}{W} - addCard(Zone.BATTLEFIELD, playerB, "Plains"); // prepare mdf castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "The Prismatic Bridge");