diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index c5ba2b18efd..14a201dabb8 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -1388,5 +1388,55 @@ public class ComputerPlayer6 extends ComputerPlayer implements Player { super.cleanUpOnMatchEnd(); } + @Override + public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { + if (combatGroup.getAttackers().size() == 1) { + Permanent attacker = game.getPermanent(combatGroup.getAttackers().get(0)); + boolean attackerDeathtouch = attacker.getAbilities().containsKey(DeathtouchAbility.getInstance().getId()); + // boolean attackerFirstStrike = attacker.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId()); + List blockerAlreadySet = getAlreadyBlockingPermanents(blockerOrder, game); + int powerAlreadyNeeded = getPowerAlreadyNeeded(blockerAlreadySet, attackerDeathtouch); + int powerLeftToKill = attacker.getPower().getValue() - powerAlreadyNeeded; + // no possible damage left, order doesn't matter + if (powerLeftToKill <= 0) { + return blockers.iterator().next().getId(); + } + for (Permanent blocker: blockers) { + if (attackerDeathtouch || powerLeftToKill >= blocker.getToughness().getValue()) { + if (!blocker.getAbilities().containsKey(IndestructibleAbility.getInstance().getId())) { + return blocker.getId(); + } + } + } + // Can't kill a blocker so it doesn't matter + return blockers.iterator().next().getId(); + } else { // multiple attackers (like banding) + //TODO: improve this + return blockers.iterator().next().getId(); + } + } + + private List getAlreadyBlockingPermanents(List blockerOrder, Game game) { + List blockerAlreadySet = new ArrayList<>(); + for (UUID uuid :blockerOrder) { + Permanent permanent = game.getPermanent(uuid); + if (permanent != null) { + blockerAlreadySet.add(permanent); + } + } + return blockerAlreadySet; + } + + private int getPowerAlreadyNeeded(List blockerAlreadySet, boolean attackerDeathtouch) { + int toughnessAlreadyNeeded = 0; + if (attackerDeathtouch) { + return blockerAlreadySet.size(); + } + for (Permanent creature : blockerAlreadySet) { + toughnessAlreadyNeeded += creature.getToughness().getValue(); + } + return toughnessAlreadyNeeded; + } + } 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 621b2befe1a..d3f35976b19 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 @@ -82,6 +82,7 @@ import java.util.*; import java.util.HashSet; import java.util.Map.Entry; import mage.abilities.costs.VariableCost; +import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.FlashAbility; import mage.cards.repository.ExpansionInfo; import mage.cards.repository.ExpansionRepository; @@ -1388,7 +1389,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } @Override - public UUID chooseBlockerOrder(List blockers, Game game) { + public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { //TODO: improve this return blockers.iterator().next().getId(); } diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java index 9694ee8445e..55fcc4b86a9 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java @@ -353,8 +353,9 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { @Override public boolean choosePile(Outcome outcome, String message, List pile1, List pile2, Game game) { - if (this.isHuman()) + if (this.isHuman()) { return rnd.nextBoolean(); + } return super.choosePile(outcome, message, pile1, pile2, game); } @@ -408,16 +409,18 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { @Override public UUID chooseAttackerOrder(List attackers, Game game) { - if (this.isHuman()) + if (this.isHuman()) { return attackers.get(rnd.nextInt(attackers.size())).getId(); + } return super.chooseAttackerOrder(attackers, game); } @Override - public UUID chooseBlockerOrder(List blockers, Game game) { - if (this.isHuman()) + public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { + if (this.isHuman()) { return blockers.get(rnd.nextInt(blockers.size())).getId(); - return super.chooseBlockerOrder(blockers, game); + } + return super.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game); } @Override @@ -450,14 +453,16 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { targets.remove(targetId); } } - else + else { super.assignDamage(damage, targets, singleTargetName, sourceId, game); + } } @Override public int getAmount(int min, int max, String message, Game game) { - if (this.isHuman()) + if (this.isHuman()) { return rnd.nextInt(max - min) + min; + } return super.getAmount(min, max, message, game); } 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 851c1f69f94..0fe59731bd7 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 @@ -764,7 +764,7 @@ public class HumanPlayer extends PlayerImpl { @Override - public UUID chooseBlockerOrder(List blockers, Game game) { + public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { updateGameStatePriority("chooseBlockerOrder", game); while (!abort) { game.fireSelectTargetEvent(playerId, "Pick blocker", blockers, true); diff --git a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java index 6dafa1d3572..d9e6ebf6050 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java @@ -384,7 +384,7 @@ public class RandomPlayer extends ComputerPlayer { } @Override - public UUID chooseBlockerOrder(List blockers, Game game) { + public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { return blockers.get(rnd.nextInt(blockers.size())).getId(); } diff --git a/Mage/src/mage/game/combat/CombatGroup.java b/Mage/src/mage/game/combat/CombatGroup.java index 832cf4a04e2..50d903e0d91 100644 --- a/Mage/src/mage/game/combat/CombatGroup.java +++ b/Mage/src/mage/game/combat/CombatGroup.java @@ -304,12 +304,16 @@ public class CombatGroup implements Serializable, Copyable { } if (damage > 0 && hasTrample(attacker)) { defenderDamage(attacker, damage, game); + } else { + // Assign the damge left to first blocker + int alreadyAssigned = assigned.get(blockerOrder.get(0)); + assigned.replace(blockerOrder.get(0), damage + alreadyAssigned); } } for (UUID blockerId: blockerOrder) { Integer power = blockerPower.get(blockerId); if (power != null) { - attacker.markDamage(power.intValue(), blockerId, game, true, true); + attacker.markDamage(power, blockerId, game, true, true); } } for (Map.Entry entry : assigned.entrySet()) { @@ -448,7 +452,7 @@ public class CombatGroup implements Serializable, Copyable { for (UUID blockerId: blockerList) { blockerPerms.add(game.getPermanent(blockerId)); } - UUID blockerId = player.chooseBlockerOrder(blockerPerms, game); + UUID blockerId = player.chooseBlockerOrder(blockerPerms, this, blockerOrder, game); blockerOrder.add(blockerId); blockerList.remove(blockerId); } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index 0cbbabf86de..882656cf2ad 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -59,6 +59,7 @@ import mage.util.Copyable; import java.io.Serializable; import java.util.*; +import mage.game.combat.CombatGroup; /** * @@ -312,7 +313,15 @@ public interface Player extends MageItem, Copyable { void selectAttackers(Game game, UUID attackingPlayerId); void selectBlockers(Game game, UUID defendingPlayerId); UUID chooseAttackerOrder(List attacker, Game game); - UUID chooseBlockerOrder(List blockers, Game game); + /** + * Choose the order in which blockers get damage assigned to + * @param blockers list of blockers where to choose the next one from + * @param combatGroup the concerning combat group + * @param blockerOrder the already set order of blockers + * @param game + * @return blocker next to add to the blocker order + */ + UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game); void assignDamage(int damage, List targets, String singleTargetName, UUID sourceId, Game game); int getAmount(int min, int max, String message, Game game); void sideboard(Match match, Deck deck);