Merge pull request #2325 from Dilnu/master

Fix the combat code to support Slayer's Cleaver
This commit is contained in:
LevelX2 2016-09-18 22:51:27 +02:00 committed by GitHub
commit ea38924b5a
3 changed files with 58 additions and 38 deletions

View file

@ -56,7 +56,6 @@ public class SlayersCleaver extends CardImpl {
// Equipped creature gets +3/+1 and must be blocked by an Eldrazi if able. // Equipped creature gets +3/+1 and must be blocked by an Eldrazi if able.
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(3, 1)); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(3, 1));
// TODO: The effect does not work correctly yet, we need to do some chnanges to combat handling to fix this
ability.addEffect(new SlayersCleaverEffect()); ability.addEffect(new SlayersCleaverEffect());
this.addAbility(ability); this.addAbility(ability);
// Equip {4} // Equip {4}

View file

@ -231,12 +231,12 @@ public class BlockRequirementTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
addCard(Zone.BATTLEFIELD, playerA, "Memnite"); // {1} 1/1 addCard(Zone.BATTLEFIELD, playerA, "Memnite"); // {1} 1/1
addCard(Zone.BATTLEFIELD, playerB, "Wretched Gryff"); // {7} Flying 3/4 - Eldrazi Hippogriff addCard(Zone.BATTLEFIELD, playerB, "Dimensional Infiltrator"); // 2/1 - Eldrazi
addCard(Zone.BATTLEFIELD, playerB, "Hill Giant"); // {3}{R} 3/3 addCard(Zone.BATTLEFIELD, playerB, "Llanowar Elves"); // 1/1
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Memnite"); // pumps to 4/2 activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Memnite"); // pumps to 4/2
attack(1, playerA, "Memnite"); // must be blocked by Wretched Gryff attack(1, playerA, "Memnite"); // must be blocked by Dimensional Infiltrator
block(1, playerB, "Hill Giant", "Memnite"); // should not be allowed as only blocker block(1, playerB, "Llanowar Elves", "Memnite"); // should not be allowed as only blocker
setStopAt(1, PhaseStep.END_COMBAT); setStopAt(1, PhaseStep.END_COMBAT);
execute(); execute();
@ -244,7 +244,7 @@ public class BlockRequirementTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Slayer's Cleaver", 1); assertPermanentCount(playerA, "Slayer's Cleaver", 1);
assertLife(playerB, 20); assertLife(playerB, 20);
assertGraveyardCount(playerA, "Memnite", 1); assertGraveyardCount(playerA, "Memnite", 1);
assertGraveyardCount(playerB, "Wretched Gryff", 1); assertGraveyardCount(playerB, "Dimensional Infiltrator", 1);
assertPermanentCount(playerB, "Hill Giant", 1); assertGraveyardCount(playerB, "Llanowar Elves", 1);
} }
} }

View file

@ -749,38 +749,50 @@ public class Combat implements Serializable, Copyable<Combat> {
// check if for attacking creatures with mustBeBlockedByAtLeastOne requirements are fulfilled // check if for attacking creatures with mustBeBlockedByAtLeastOne requirements are fulfilled
for (UUID toBeBlockedCreatureId : mustBeBlockedByAtLeastOne.keySet()) { for (UUID toBeBlockedCreatureId : mustBeBlockedByAtLeastOne.keySet()) {
for (CombatGroup combatGroup : game.getCombat().getGroups()) { for (CombatGroup combatGroup : game.getCombat().getGroups()) {
if (combatGroup.getBlockers().isEmpty() && combatGroup.getAttackers().contains(toBeBlockedCreatureId)) { if (combatGroup.getAttackers().contains(toBeBlockedCreatureId)) {
// creature is not blocked but has possible blockers boolean requirementFulfilled = false;
if (controller.isHuman()) { // Check whether an applicable creature is blocking.
Permanent toBeBlockedCreature = game.getPermanent(toBeBlockedCreatureId); for (UUID blockerId : combatGroup.getBlockers()) {
if (toBeBlockedCreature != null) { if (mustBeBlockedByAtLeastOne.get(toBeBlockedCreatureId).contains(blockerId)) {
// check if all possible blocker block other creatures they are forced to block requirementFulfilled = true;
// read through all possible blockers break;
for (UUID possibleBlockerId : mustBeBlockedByAtLeastOne.get(toBeBlockedCreatureId)) { }
String blockRequiredMessage = isCreatureDoingARequiredBlock(possibleBlockerId, mustBeBlockedByAtLeastOne, game); }
if (blockRequiredMessage != null) { // message means not required if (!requirementFulfilled) {
removeBlocker(possibleBlockerId, game); // creature is not blocked but has possible blockers
game.informPlayer(controller, blockRequiredMessage + " Existing block removed. It's a requirement to block " + toBeBlockedCreature.getIdName() + "."); if (controller.isHuman()) {
return false; Permanent toBeBlockedCreature = game.getPermanent(toBeBlockedCreatureId);
if (toBeBlockedCreature != null) {
// check if all possible blocker block other creatures they are forced to block
// read through all possible blockers
for (UUID possibleBlockerId : mustBeBlockedByAtLeastOne.get(toBeBlockedCreatureId)) {
String blockRequiredMessage = isCreatureDoingARequiredBlock(
possibleBlockerId, toBeBlockedCreatureId, mustBeBlockedByAtLeastOne, game);
if (blockRequiredMessage != null) { // message means not required
removeBlocker(possibleBlockerId, game);
game.informPlayer(controller, blockRequiredMessage + " Existing block removed. It's a requirement to block " + toBeBlockedCreature.getIdName() + ".");
return false;
}
} }
} }
}
} else { } else {
// take the first potential blocker from the set to block for the AI // take the first potential blocker from the set to block for the AI
for (UUID possibleBlockerId : mustBeBlockedByAtLeastOne.get(toBeBlockedCreatureId)) { for (UUID possibleBlockerId : mustBeBlockedByAtLeastOne.get(toBeBlockedCreatureId)) {
String blockRequiredMessage = isCreatureDoingARequiredBlock(possibleBlockerId, mustBeBlockedByAtLeastOne, game); String blockRequiredMessage = isCreatureDoingARequiredBlock(
if (blockRequiredMessage != null) { possibleBlockerId, toBeBlockedCreatureId, mustBeBlockedByAtLeastOne, game);
// set the block if (blockRequiredMessage != null) {
Permanent possibleBlocker = game.getPermanent(possibleBlockerId); // set the block
Player defender = game.getPlayer(possibleBlocker.getControllerId()); Permanent possibleBlocker = game.getPermanent(possibleBlockerId);
if (defender != null) { Player defender = game.getPlayer(possibleBlocker.getControllerId());
if (possibleBlocker.getBlocking() > 0) { if (defender != null) {
removeBlocker(possibleBlockerId, game); if (possibleBlocker.getBlocking() > 0) {
removeBlocker(possibleBlockerId, game);
}
defender.declareBlocker(defender.getId(), possibleBlockerId, toBeBlockedCreatureId, game);
} }
defender.declareBlocker(defender.getId(), possibleBlockerId, toBeBlockedCreatureId, game); break;
} }
break;
} }
} }
} }
@ -887,11 +899,12 @@ public class Combat implements Serializable, Copyable<Combat> {
* required block * required block
* *
* @param possibleBlockerId * @param possibleBlockerId
* @param toBeBlockedCreatureId
* @param mustBeBlockedByAtLeastOne * @param mustBeBlockedByAtLeastOne
* @param game * @param game
* @return null block is required otherwise message with reason why not * @return null block is required otherwise message with reason why not
*/ */
protected String isCreatureDoingARequiredBlock(UUID possibleBlockerId, Map<UUID, Set<UUID>> mustBeBlockedByAtLeastOne, Game game) { protected String isCreatureDoingARequiredBlock(UUID possibleBlockerId, UUID toBeBlockedCreatureId, Map<UUID, Set<UUID>> mustBeBlockedByAtLeastOne, Game game) {
Permanent possibleBlocker = game.getPermanent(possibleBlockerId); Permanent possibleBlocker = game.getPermanent(possibleBlockerId);
if (possibleBlocker != null) { if (possibleBlocker != null) {
if (possibleBlocker.getBlocking() == 0) { if (possibleBlocker.getBlocking() == 0) {
@ -908,9 +921,17 @@ public class Combat implements Serializable, Copyable<Combat> {
if (mustBeBlockedByAtLeastOne.containsKey(blockedAttackerId)) { if (mustBeBlockedByAtLeastOne.containsKey(blockedAttackerId)) {
// blocks a creature that has to be blocked by at least one // blocks a creature that has to be blocked by at least one
if (combatGroupOfPossibleBlocker.getBlockers().size() == 1) { if (combatGroupOfPossibleBlocker.getBlockers().size() == 1) {
// the creature blocks alone already a creature that has to be blocked by at least one, Set <UUID> blockedSet = mustBeBlockedByAtLeastOne.get(blockedAttackerId);
// so this is ok Set <UUID> toBlockSet = mustBeBlockedByAtLeastOne.get(toBeBlockedCreatureId);
return null; if (toBlockSet == null) {
// This should never happen.
return null;
} else if (toBlockSet.containsAll(blockedSet)) {
// the creature already blocks alone a creature that has to be blocked by at least one
// and has more possible blockers, so this is ok
return null;
}
} }
// TODO: Check if the attacker is already blocked by another creature // TODO: Check if the attacker is already blocked by another creature
// and despite there is need that this attacker blocks this attacker also // and despite there is need that this attacker blocks this attacker also