From 29eda88dcf902b77b39225a736e1c0103b45e252 Mon Sep 17 00:00:00 2001 From: Grath <1895280+Grath@users.noreply.github.com> Date: Sun, 22 Dec 2024 22:29:06 -0500 Subject: [PATCH] Break deadlock for one must/can't be blocked pair. Handle the case where a 'must be blocked if able' creature is attacking but there aren't enough available creatures to block it. --- .../main/java/mage/game/combat/Combat.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index bcb47f1f5ea7..a5c7829a8f49 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -858,6 +858,7 @@ public boolean checkBlockRequirementsAfter(Player player, Player controller, Gam // map with attackers (UUID) that must be blocked by at least one blocker and a set of all creatures that can block it and don't block yet Map> mustBeBlockedByAtLeastX = new HashMap<>(); Map minNumberOfBlockersMap = new HashMap<>(); + Map minPossibleBlockersMap = new HashMap<>(); // check mustBlock requirements of creatures from opponents of attacking player for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED, player.getId(), game)) { @@ -876,6 +877,12 @@ public boolean checkBlockRequirementsAfter(Player player, Player controller, Gam CombatGroup toBeBlockedGroup = findGroup(toBeBlockedCreature); if (toBeBlockedGroup != null && toBeBlockedGroup.getDefendingPlayerId().equals(creature.getControllerId())) { minNumberOfBlockersMap.put(toBeBlockedCreature, effect.getMinNumberOfBlockers()); + Permanent toBeBlockedCreaturePermanent = game.getPermanent(toBeBlockedCreature); + if (toBeBlockedCreaturePermanent != null) { + minPossibleBlockersMap.put(toBeBlockedCreature, toBeBlockedCreaturePermanent.getMinBlockedBy()); + } else { + minPossibleBlockersMap.put(toBeBlockedCreature, 1); + } Set potentialBlockers; if (mustBeBlockedByAtLeastX.containsKey(toBeBlockedCreature)) { potentialBlockers = mustBeBlockedByAtLeastX.get(toBeBlockedCreature); @@ -973,6 +980,12 @@ public boolean checkBlockRequirementsAfter(Player player, Player controller, Gam CombatGroup toBeBlockedGroup = findGroup(toBeBlockedCreature); if (toBeBlockedGroup != null && toBeBlockedGroup.getDefendingPlayerId().equals(creature.getControllerId())) { minNumberOfBlockersMap.put(toBeBlockedCreature, effect.getMinNumberOfBlockers()); + Permanent toBeBlockedCreaturePermanent = game.getPermanent(toBeBlockedCreature); + if (toBeBlockedCreaturePermanent != null) { + minPossibleBlockersMap.put(toBeBlockedCreature, toBeBlockedCreaturePermanent.getMinBlockedBy()); + } else { + minPossibleBlockersMap.put(toBeBlockedCreature, 1); + } Set potentialBlockers; if (mustBeBlockedByAtLeastX.containsKey(toBeBlockedCreature)) { potentialBlockers = mustBeBlockedByAtLeastX.get(toBeBlockedCreature); @@ -1059,6 +1072,13 @@ public boolean checkBlockRequirementsAfter(Player player, Player controller, Gam for (UUID toBeBlockedCreatureId : mustBeBlockedByAtLeastX.keySet()) { for (CombatGroup combatGroup : game.getCombat().getGroups()) { if (combatGroup.getAttackers().contains(toBeBlockedCreatureId)) { + // Neyith of the Dire Hunt: If the target creature has menace, two creatures must block it if able. + // (2020-06-23) + // This is a basic check to avoid deadlocking on one blocker plus 'must be blocked if able' with menace; + // a full solution is more complicated but this prevents the most common case. + if (mustBeBlockedByAtLeastX.get(toBeBlockedCreatureId).size() < minPossibleBlockersMap.get(toBeBlockedCreatureId)) { + continue; + } boolean requirementFulfilled = false; // Check whether an applicable creature is blocking. for (UUID blockerId : combatGroup.getBlockers()) {