From 865624eacdb3e28eccb93749b65fcab3fd995c43 Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 19 May 2018 05:21:09 +0000 Subject: [PATCH 1/6] Some combat fixes --- Mage/src/main/java/mage/players/Player.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index efb73fff230..b2510b262fb 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -627,6 +627,8 @@ public interface Player extends MageItem, Copyable { void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game); + void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game, boolean allowUndo); + List getAvailableAttackers(Game game); List getAvailableAttackers(UUID defenderId, Game game); From 0512558c60d3e1cf8d3991a58d935160e7e18ece Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 19 May 2018 05:22:50 +0000 Subject: [PATCH 2/6] Some combat fixes --- Mage/src/main/java/mage/players/PlayerImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index a2be32c19e4..bdb8a60a3e1 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -2353,7 +2353,12 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game) { - if (isHuman()) { + declareBlocker(defenderId, blockerId, attackerId, game, true); + } + + @Override + public void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game, boolean allowUndo) { + if (isHuman() && allowUndo) { setStoredBookmark(game.bookmarkState()); } Permanent blocker = game.getPermanent(blockerId); From 1be4379cbddb46f0b6f12b9aebb0d1d2938337af Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 19 May 2018 05:30:11 +0000 Subject: [PATCH 3/6] Some combat fixes --- .../main/java/mage/game/combat/Combat.java | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 8abc77f1c81..31b7fdd76e3 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -412,19 +412,19 @@ public class Combat implements Serializable, Copyable { creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack); // No need to attack a special defender if (defendersForcedToAttack.isEmpty()) { - if (defendersForcedToAttack.isEmpty()) { - if (defendersCostlessAttackable.size() >= 1) { - if (defenders.size() == 1) { - player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false); - } else { - TargetDefender target = new TargetDefender(defenders, creature.getId()); - target.setRequired(true); - target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack"); - if (player.chooseTarget(Outcome.Damage, target, null, game)) { - player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false); - } - } + if (defenders.size() == 1) { + player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false); + } else { + TargetDefender target = new TargetDefender(defenders, creature.getId()); + target.setRequired(true); + target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack"); + if (player.chooseTarget(Outcome.Damage, target, null, game)) { + player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false); } + } + } else { + if (defenders.size() == 1) { + player.declareAttacker(creature.getId(), defendersForcedToAttack.iterator().next(), game, false); } else { TargetDefender target = new TargetDefender(defendersCostlessAttackable, creature.getId()); target.setRequired(true); @@ -432,8 +432,6 @@ public class Combat implements Serializable, Copyable { player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false); } } - } else { - player.declareAttacker(creature.getId(), defendersForcedToAttack.iterator().next(), game, false); } } @@ -684,7 +682,7 @@ public class Combat implements Serializable, Copyable { forcingAttackers.add(attackingCreatureId); creatureMustBlockAttackers.put(possibleBlocker.getId(), forcingAttackers); // assign block to the first forcing attacker automatically - defender.declareBlocker(defender.getId(), possibleBlocker.getId(), attackingCreatureId, game); + defender.declareBlocker(defender.getId(), possibleBlocker.getId(), attackingCreatureId, game, false); } } } @@ -985,26 +983,26 @@ public class Combat implements Serializable, Copyable { // Check if blocker is really able to block one or more attackers (maybe not if the attacker has menace) - if not continue with the next forced blocker // TODO: Probably there is some potential to abuse the check if forced blockers are assigned to differnt attackers with e.g. menace. // While if assigned all to one the block is possible - if (creatureForcedToBlock.getBlocking() == 0) { - boolean validBlockPossible = false; - for (UUID possibleAttackerId : entry.getValue()) { - CombatGroup attackersGroup = findGroup(possibleAttackerId); - if (attackersGroup.getBlockers().contains(creatureForcedToBlock.getId())) { - // forcedBlocker blocks a valid blocker, so no problem break check if valid block option exists - validBlockPossible = true; - break; - } - Permanent attackingCreature = game.getPermanent(possibleAttackerId); - if (attackingCreature.getMinBlockedBy() > 1) { // e.g. Menace - if (attackersGroup.getBlockers().size() + 1 >= attackingCreature.getMinBlockedBy()) { - validBlockPossible = true; - } - } - } - if (!validBlockPossible) { - continue; - } - } +// if (creatureForcedToBlock.getBlocking() = 0) { +// boolean validBlockPossible = false; +// for (UUID possibleAttackerId : entry.getValue()) { +// CombatGroup attackersGroup = findGroup(possibleAttackerId); +// if (attackersGroup.getBlockers().contains(creatureForcedToBlock.getId())) { +// // forcedBlocker blocks a valid blocker, so no problem break check if valid block option exists +// validBlockPossible = true; +// break; +// } +// Permanent attackingCreature = game.getPermanent(possibleAttackerId); +// if (attackingCreature.getMinBlockedBy() > 1) { // e.g. Menace +// if (attackersGroup.getBlockers().size() + 1 >= attackingCreature.getMinBlockedBy()) { +// validBlockPossible = true; +// } +// } +// } +// if (!validBlockPossible) { +// continue; +// } +// } // // check if creature has to pay a cost to block so it's not mandatory to block // boolean removedAttacker = false; @@ -1242,19 +1240,21 @@ public class Combat implements Serializable, Copyable { } } } - + @SuppressWarnings("deprecation") public boolean declareAttacker(UUID creatureId, UUID defenderId, UUID playerId, Game game) { Permanent attacker = game.getPermanent(creatureId); if (attacker != null) { - if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId()) && !attacker.getAbilities().containsKey(JohanVigilanceAbility.getInstance().getId())) { - if (!attacker.isTapped()) { - attacker.setTapped(true); - attackersTappedByAttack.add(attacker.getId()); - } - } if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKER, defenderId, creatureId, playerId))) { - return addAttackerToCombat(creatureId, defenderId, game); + if (addAttackerToCombat(creatureId, defenderId, game)) { + if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId()) && !attacker.getAbilities().containsKey(JohanVigilanceAbility.getInstance().getId())) { + if (!attacker.isTapped()) { + attacker.setTapped(true); + attackersTappedByAttack.add(attacker.getId()); + } + } + return true; + } } } return false; From a7d662d73e1c861b37f9915f34b1e4e1d3ef545d Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 19 May 2018 08:24:42 +0000 Subject: [PATCH 4/6] Changes to menace & Lure interaction --- .../main/java/mage/game/combat/Combat.java | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 31b7fdd76e3..de1bf60ec63 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -970,7 +970,7 @@ public class Combat implements Serializable, Copyable { // check if creatures are forced to block but do not block at all or block creatures they are not forced to block StringBuilder sb = new StringBuilder(); for (Map.Entry> entry : creatureMustBlockAttackers.entrySet()) { - boolean blockIsValid; + boolean blockIsValid = true; Permanent creatureForcedToBlock = game.getPermanent(entry.getKey()); if (creatureForcedToBlock == null) { break; @@ -980,29 +980,6 @@ public class Combat implements Serializable, Copyable { continue; } - // Check if blocker is really able to block one or more attackers (maybe not if the attacker has menace) - if not continue with the next forced blocker - // TODO: Probably there is some potential to abuse the check if forced blockers are assigned to differnt attackers with e.g. menace. - // While if assigned all to one the block is possible -// if (creatureForcedToBlock.getBlocking() = 0) { -// boolean validBlockPossible = false; -// for (UUID possibleAttackerId : entry.getValue()) { -// CombatGroup attackersGroup = findGroup(possibleAttackerId); -// if (attackersGroup.getBlockers().contains(creatureForcedToBlock.getId())) { -// // forcedBlocker blocks a valid blocker, so no problem break check if valid block option exists -// validBlockPossible = true; -// break; -// } -// Permanent attackingCreature = game.getPermanent(possibleAttackerId); -// if (attackingCreature.getMinBlockedBy() > 1) { // e.g. Menace -// if (attackersGroup.getBlockers().size() + 1 >= attackingCreature.getMinBlockedBy()) { -// validBlockPossible = true; -// } -// } -// } -// if (!validBlockPossible) { -// continue; -// } -// } // // check if creature has to pay a cost to block so it's not mandatory to block // boolean removedAttacker = false; @@ -1019,8 +996,24 @@ public class Combat implements Serializable, Copyable { // continue; // } // creature does not block -> not allowed + + // Check if blocker is really able to block one or more attackers (maybe not if the attacker has menace) - if not continue with the next forced blocker + // TODO: Probably there is some potential to abuse the check if forced blockers are assigned to differnt attackers with e.g. menace. + // While if assigned all to one the block is possible if (creatureForcedToBlock.getBlocking() == 0) { - blockIsValid = false; + blockIsValid = entry.getValue().isEmpty(); + for (UUID possibleAttackerId : entry.getValue()) { + CombatGroup attackersGroup = game.getCombat().findGroup(possibleAttackerId); + Permanent attackingCreature = game.getPermanent(possibleAttackerId); + if (attackersGroup == null || attackingCreature == null) { + continue; + } + if (attackingCreature.getMinBlockedBy() > 1) { // e.g. Menace + if (attackersGroup.getBlockers().size() + 1 < attackingCreature.getMinBlockedBy()) { + blockIsValid = true; + } + } + } } else { blockIsValid = false; // which attacker is he blocking From bd2a2eebf495a3730620f6e16df353b59d7b6315 Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 19 May 2018 08:42:07 +0000 Subject: [PATCH 5/6] TestPlayer declareBlocker fix --- .../src/test/java/org/mage/test/player/TestPlayer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 4582e497d63..627f0930642 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -2007,6 +2007,11 @@ public class TestPlayer implements Player { computerPlayer.declareBlocker(defenderId, blockerId, attackerId, game); } + @Override + public void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game, boolean allowUndo) { + computerPlayer.declareBlocker(defenderId, blockerId, attackerId, game, allowUndo); + } + @Override public boolean searchLibrary(TargetCardInLibrary target, Game game) { return computerPlayer.searchLibrary(target, game); From 994771049c6625beb55ad4a5dfcc8c2d965dc675 Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 19 May 2018 08:43:42 +0000 Subject: [PATCH 6/6] PlayerStub declareBlocker fix --- Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index e6cdc6f7bcc..79da1b98fa8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -993,6 +993,11 @@ public class PlayerStub implements Player { } + @Override + public void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game, boolean allowUndo) { + + } + @Override public List getAvailableAttackers(Game game) { return null;