mirror of
https://github.com/correl/mage.git
synced 2024-11-15 03:00:16 +00:00
* Choice of Damnations - improved AI support, fixed rollback error in AI games;
* Pain's Reward - improved AI support, fixed rollback error in AI games; * Volcano Hellion - improved AI support, fixed rollback error in AI games;
This commit is contained in:
parent
ac98a3a31a
commit
f692a1f097
5 changed files with 79 additions and 35 deletions
|
@ -50,10 +50,7 @@ import mage.players.net.UserData;
|
||||||
import mage.players.net.UserGroup;
|
import mage.players.net.UserGroup;
|
||||||
import mage.target.*;
|
import mage.target.*;
|
||||||
import mage.target.common.*;
|
import mage.target.common.*;
|
||||||
import mage.util.Copier;
|
import mage.util.*;
|
||||||
import mage.util.RandomUtil;
|
|
||||||
import mage.util.TournamentUtil;
|
|
||||||
import mage.util.TreeNode;
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -1666,8 +1663,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
@Override
|
@Override
|
||||||
public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variablCost) {
|
public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variablCost) {
|
||||||
log.debug("announceXCost");
|
log.debug("announceXCost");
|
||||||
//TODO: improve this
|
int value = RandomUtil.nextInt(CardUtil.overflowInc(max, 1));
|
||||||
int value = RandomUtil.nextInt(max + 1);
|
|
||||||
if (value < min) {
|
if (value < min) {
|
||||||
value = min;
|
value = min;
|
||||||
}
|
}
|
||||||
|
@ -1964,9 +1960,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
if (message.startsWith("Assign damage to ")) {
|
if (message.startsWith("Assign damage to ")) {
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
//TODO: improve this
|
|
||||||
if (min < max && min == 0) {
|
if (min < max && min == 0) {
|
||||||
return RandomUtil.nextInt(max + 1);
|
return RandomUtil.nextInt(CardUtil.overflowInc(max, 1));
|
||||||
}
|
}
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
|
|
||||||
package mage.cards.c;
|
package mage.cards.c;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubType;
|
||||||
import mage.filter.FilterPermanent;
|
import mage.filter.FilterPermanent;
|
||||||
import mage.filter.common.FilterControlledPermanent;
|
import mage.filter.common.FilterControlledPermanent;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
@ -18,14 +16,15 @@ import mage.target.Target;
|
||||||
import mage.target.common.TargetControlledPermanent;
|
import mage.target.common.TargetControlledPermanent;
|
||||||
import mage.target.common.TargetOpponent;
|
import mage.target.common.TargetOpponent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public final class ChoiceOfDamnations extends CardImpl {
|
public final class ChoiceOfDamnations extends CardImpl {
|
||||||
|
|
||||||
public ChoiceOfDamnations(UUID ownerId, CardSetInfo setInfo) {
|
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);
|
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.
|
// 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) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source));
|
Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source));
|
||||||
if (targetPlayer != null) {
|
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());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null) {
|
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);
|
targetPlayer.loseLife(amount, game, source, false);
|
||||||
} else {
|
} 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) {
|
if (numberPermanents > amount) {
|
||||||
int numberToSacrifice = numberPermanents - amount;
|
int numberToSacrifice = numberPermanents - amount;
|
||||||
Target target = new TargetControlledPermanent(numberToSacrifice, numberToSacrifice, new FilterControlledPermanent("permanent you control to sacrifice"), false);
|
Target target = new TargetControlledPermanent(numberToSacrifice, numberToSacrifice, new FilterControlledPermanent("permanent you control to sacrifice"), false);
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
|
|
||||||
package mage.cards.p;
|
package mage.cards.p;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -13,15 +10,16 @@ import mage.game.Game;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.players.PlayerList;
|
import mage.players.PlayerList;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public final class PainsReward extends CardImpl {
|
public final class PainsReward extends CardImpl {
|
||||||
|
|
||||||
public PainsReward(UUID ownerId, CardSetInfo setInfo) {
|
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.
|
// 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());
|
this.getSpellAbility().addEffect(new PainsRewardEffect());
|
||||||
|
@ -62,14 +60,19 @@ class PainsRewardEffect extends OneShotEffect {
|
||||||
playerList.setCurrent(controller.getId());
|
playerList.setCurrent(controller.getId());
|
||||||
Player winner = game.getPlayer(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");
|
game.informPlayers(winner.getLogName() + " has bet " + highBid + " lifes");
|
||||||
|
|
||||||
Player currentPlayer = playerList.getNextInRange(controller, game);
|
Player currentPlayer = playerList.getNextInRange(controller, game);
|
||||||
while (currentPlayer != null && !Objects.equals(currentPlayer, winner)) {
|
while (currentPlayer != null && !Objects.equals(currentPlayer, winner)) {
|
||||||
String text = winner.getLogName() + " has bet " + highBid + " life" + (highBid > 1 ? "s" : "") + ". Top the bid?";
|
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) {
|
if (newBid > highBid) {
|
||||||
highBid = newBid;
|
highBid = newBid;
|
||||||
winner = currentPlayer;
|
winner = currentPlayer;
|
||||||
|
@ -86,4 +89,16 @@ class PainsRewardEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
package mage.cards.v;
|
package mage.cards.v;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
|
@ -11,15 +9,16 @@ import mage.abilities.keyword.EchoAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubType;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.common.TargetCreaturePermanent;
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author jeffwadsworth
|
* @author jeffwadsworth
|
||||||
*/
|
*/
|
||||||
public final class VolcanoHellion extends CardImpl {
|
public final class VolcanoHellion extends CardImpl {
|
||||||
|
@ -54,7 +53,7 @@ public final class VolcanoHellion extends CardImpl {
|
||||||
class VolcanoHellionEffect extends OneShotEffect {
|
class VolcanoHellionEffect extends OneShotEffect {
|
||||||
|
|
||||||
public VolcanoHellionEffect() {
|
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";
|
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());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
Permanent permanent = game.getPermanent(source.getFirstTarget());
|
Permanent permanent = game.getPermanent(source.getFirstTarget());
|
||||||
if (controller != null) {
|
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) {
|
if (amount > 0) {
|
||||||
controller.damage(amount, source.getSourceId(), source, game, false, false);
|
controller.damage(amount, source.getSourceId(), source, game, false, false);
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
|
|
|
@ -46,10 +46,6 @@ public class ModalDoubleFacesCardsInCommanderTest extends CardTestCommanderDuelB
|
||||||
addCard(Zone.LIBRARY, playerA, "Forest");
|
addCard(Zone.LIBRARY, playerA, "Forest");
|
||||||
addCard(Zone.LIBRARY, playerA, "Grizzly Bears");
|
addCard(Zone.LIBRARY, playerA, "Grizzly Bears");
|
||||||
addCard(Zone.LIBRARY, playerA, "Forest");
|
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
|
// prepare mdf
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "The Prismatic Bridge");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "The Prismatic Bridge");
|
||||||
|
|
Loading…
Reference in a new issue