Skip to content

Commit

Permalink
Break deadlock for one must/can't be blocked pair. (#13182)
Browse files Browse the repository at this point in the history
Handle the case where a 'must be blocked if able' creature is attacking but there aren't enough available creatures to block it.
  • Loading branch information
Grath authored Dec 25, 2024
1 parent f4572fa commit 8de9fb0
Showing 1 changed file with 20 additions and 0 deletions.
20 changes: 20 additions & 0 deletions Mage/src/main/java/mage/game/combat/Combat.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<UUID, Set<UUID>> mustBeBlockedByAtLeastX = new HashMap<>();
Map<UUID, Integer> minNumberOfBlockersMap = new HashMap<>();
Map<UUID, Integer> 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)) {
Expand All @@ -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<UUID> potentialBlockers;
if (mustBeBlockedByAtLeastX.containsKey(toBeBlockedCreature)) {
potentialBlockers = mustBeBlockedByAtLeastX.get(toBeBlockedCreature);
Expand Down Expand Up @@ -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<UUID> potentialBlockers;
if (mustBeBlockedByAtLeastX.containsKey(toBeBlockedCreature)) {
potentialBlockers = mustBeBlockedByAtLeastX.get(toBeBlockedCreature);
Expand Down Expand Up @@ -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()) {
Expand Down

0 comments on commit 8de9fb0

Please sign in to comment.