From 8f9356533d45bf32ff45f58a07905183fa3b8a61 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Wed, 10 Jan 2018 19:44:48 +0000 Subject: [PATCH] Fixed undoing individual blocker declarations for multi-blockers One more #4172 fix --- .../main/java/mage/game/combat/Combat.java | 199 +++++++++++++++++- 1 file changed, 193 insertions(+), 6 deletions(-) diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 159f950b76..ea592fb47b 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -678,6 +678,82 @@ public class Combat implements Serializable, Copyable { potentialBlockers.add(creature.getId()); } } + // check the mustBlockAllAttackers requirement (Blaze of Glory) ------------------------------- + if (effect.mustBlockAllAttackers(game)) { + Set attackersToBlock = new HashSet<>(); + // check that it can block at least one of the attackers + // and no restictions prevent this + boolean mayBlock = false; + for (UUID attackingCreatureId : getAttackers()) { + if (creature.canBlock(attackingCreatureId, game)) { + Permanent attackingCreature = game.getPermanent(attackingCreatureId); + if (attackingCreature != null) { + // check if the attacker is already blocked by a max of blockers, so blocker can't block it also + if (attackingCreature.getMaxBlockedBy() != 0) { // 0 = no restriction about the number of possible blockers + int alreadyBlockingCreatures = 0; + for (CombatGroup group : getGroups()) { + if (group.getAttackers().contains(attackingCreatureId)) { + alreadyBlockingCreatures = group.getBlockers().size(); + break; + } + } + if (attackingCreature.getMaxBlockedBy() <= alreadyBlockingCreatures) { + // Attacker can't be blocked by more blockers so check next attacker + continue; + } + } + // check restrictions of the creature to block that prevent it can be blocked + + if (attackingCreature.getMinBlockedBy() > 1) { + // TODO: check if enough possible blockers are available, if true, mayBlock can be set to true + + } else { + attackersToBlock.add(attackingCreatureId); + } + } + } + } + //~ // remove creatures already blocked by affected creature + //~ for (CombatGroup group : getBlockingGroups()) { + //~ if (group.getAttackers().contains(attackingCreatureId)) { + //~ for (UUID attackingCreatureId : group.getAttackers()) { + //~ CombatGroup attackersGroup = findGroup(attackingCreatureId); + //~ if (attackersGroup != null) { + //~ if (attackersGroup.getBlockers().contains(creature.getId())) { + //~ attackersToBlock.remove(attackingCreatureId); + //~ } + //~ } + //~ } + //~ } + //~ } + if (!attackersToBlock.isEmpty()) { + if (attackersToBlock.size() > creature.getBlocking()) { + mayBlock = true; + } + } + // if so inform human player or set block for AI player + if (mayBlock) { + if (controller.isHuman()) { + if (!game.isSimulation()) { + game.informPlayer(controller, "Creature should block all attackers it's able to this turn: " + creature.getIdName()); + } + } else { + Player defender = game.getPlayer(creature.getControllerId()); + if (defender != null) { + for (UUID attackingCreatureId : getAttackers()) { + if (creature.canBlock(attackingCreatureId, game)) { + // ??? + if (attackersToBlock.contains(attackingCreatureId)) { + //~ defender.declareBlocker(defender.getId(), creature.getId(), attackingCreatureId, game); + addBlockingGroup(creature.getId(), creature.getId(), defender.getId(), game); + } + } + } + } + } + return false; + } + } } } @@ -701,8 +777,8 @@ public class Combat implements Serializable, Copyable { } } - // check the mustBlockAny requirement ---------------------------------------- - if (effect.mustBlockAny(game)) { + // check the mustBlockAny requirement ---------------------------------------- (and mustBlockAllAttackers for AI) + if (effect.mustBlockAny(game) || effect.mustBlockAllAttackers(game)) { // check that it can block at least one of the attackers // and no restictions prevent this boolean mayBlock = false; @@ -740,15 +816,28 @@ public class Combat implements Serializable, Copyable { if (mayBlock) { if (controller.isHuman()) { if (!game.isSimulation()) { - game.informPlayer(controller, "Creature should block this turn: " + creature.getIdName()); + if (!effect.mustBlockAllAttackers(game)) { + game.informPlayer(controller, "Creature should block this turn: " + creature.getIdName()); + } else { + game.informPlayer(controller, "Creature should block all attackers it's able to this turn: " + creature.getIdName()); + } } } else { Player defender = game.getPlayer(creature.getControllerId()); if (defender != null) { for (UUID attackingCreatureId : getAttackers()) { if (creature.canBlock(attackingCreatureId, game)) { - defender.declareBlocker(defender.getId(), creature.getId(), attackingCreatureId, game); - break; + if (!effect.mustBlockAllAttackers(game)) { + defender.declareBlocker(defender.getId(), creature.getId(), attackingCreatureId, game); + break; + } else { + // this might be buggy with additional restriction effects + if (creature.getBlocking() == 0) { + defender.declareBlocker(defender.getId(), creature.getId(), attackingCreatureId, game); + } else { + addBlockingGroup(creature.getId(), creature.getId(), defender.getId(), game); + } + } } } } @@ -756,6 +845,82 @@ public class Combat implements Serializable, Copyable { return false; } } + /* + // check the mustBlockAllAttackers requirement ------------------------------- + if (effect.mustBlockAllAttackers(game)) { + Set attackersToBlock = new HashSet<>(); + // check that it can block at least one of the attackers + // and no restictions prevent this + boolean mayBlock = false; + for (UUID attackingCreatureId : getAttackers()) { + if (creature.canBlock(attackingCreatureId, game)) { + Permanent attackingCreature = game.getPermanent(attackingCreatureId); + if (attackingCreature != null) { + // check if the attacker is already blocked by a max of blockers, so blocker can't block it also + if (attackingCreature.getMaxBlockedBy() != 0) { // 0 = no restriction about the number of possible blockers + int alreadyBlockingCreatures = 0; + for (CombatGroup group : getGroups()) { + if (group.getAttackers().contains(attackingCreatureId)) { + alreadyBlockingCreatures = group.getBlockers().size(); + break; + } + } + if (attackingCreature.getMaxBlockedBy() <= alreadyBlockingCreatures) { + // Attacker can't be blocked by more blockers so check next attacker + continue; + } + } + // check restrictions of the creature to block that prevent it can be blocked + + if (attackingCreature.getMinBlockedBy() > 1) { + // TODO: check if enough possible blockers are available, if true, mayBlock can be set to true + + } else { + attackersToBlock.add(attackingCreatureId); + } + } + } + } + if (!attackersToBlock.isEmpty()) { + //~ CombatGroup group = findGroupOfBlocker(creature.getId()); + //~ if (group == null) { + //~ mayBlock = true; + //~ } else { + //~ for (UUID attackingCreatureId : attackersToBlock) { + //~ if (!group.getAttackers().contains(attackingCreatureId)) { + //~ mayBlock = true; + //~ break; + //~ } + //~ } + game.informPlayers(attackersToBlock.size() + " and " + creature.getBlocking()); + if (attackersToBlock.size() > creature.getBlocking()) { + mayBlock = true; + } + //~ } + } + // if so inform human player or set block for AI player + if (mayBlock) { + if (controller.isHuman()) { + if (!game.isSimulation()) { + game.informPlayer(controller, "Creature should block all attackers if able this turn: " + creature.getIdName()); + } + } else { + Player defender = game.getPlayer(creature.getControllerId()); + if (defender != null) { + for (UUID attackingCreatureId : getAttackers()) { + if (creature.canBlock(attackingCreatureId, game)) { + // ??? + if (attackersToBlock.contains(attackingCreatureId)) { + defender.declareBlocker(defender.getId(), creature.getId(), attackingCreatureId, game); + } + } + } + } + } + return false; + } + } + */ } } @@ -1180,6 +1345,7 @@ public class Combat implements Serializable, Copyable { //TODO: handle banding blockingGroups.get(blockerId).attackers.add(attackerId); } + // "blocker.setBlocking(blocker.getBlocking() + 1)" is handled by the attacking combat group } } @@ -1392,6 +1558,7 @@ public class Combat implements Serializable, Copyable { } public void removeBlockerGromGroup(UUID blockerId, CombatGroup groupToUnblock, Game game) { + // Manual player action for undoing one declared blocker (used for multi-blocker creatures) Permanent creature = game.getPermanent(blockerId); if (creature != null) { for (CombatGroup group : groups) { @@ -1404,7 +1571,26 @@ public class Combat implements Serializable, Copyable { if (creature.getBlocking() > 0) { creature.setBlocking(creature.getBlocking() - 1); } else { - throw new UnsupportedOperationException("Tryinging creature to unblock, but blocking number value of creature < 1"); + throw new UnsupportedOperationException("Trying to unblock creature, but blocking number value of creature < 1"); + } + boolean canRemove = false; + for (CombatGroup blockGroup : getBlockingGroups()) { + if (blockGroup.blockers.contains(blockerId)) { + for (UUID attackerId : group.getAttackers()) { + blockGroup.attackers.remove(attackerId); + blockGroup.attackerOrder.remove(attackerId); + } + if (creature.getBlocking() == 0) { + blockGroup.blockers.remove(blockerId); + blockGroup.attackerOrder.clear(); + } + } + if (blockGroup.blockers.isEmpty()) { + canRemove = true; + } + } + if (canRemove) { + blockingGroups.remove(blockerId); } } } @@ -1412,6 +1598,7 @@ public class Combat implements Serializable, Copyable { } public void removeBlocker(UUID blockerId, Game game) { + // Manual player action for undoing all declared blockers (used for single-blocker creatures and multi-blockers exceeding blocking limit) for (CombatGroup group : groups) { if (group.blockers.contains(blockerId)) { group.blockers.remove(blockerId);