From 1b26d6677b569f6d6312611e6c09e6616e9c0af9 Mon Sep 17 00:00:00 2001 From: drdev Date: Fri, 22 Aug 2014 04:23:22 +0000 Subject: [PATCH] Ensure creatures that must attack do so even if you End Turn before combat --- .../java/forge/game/combat/CombatUtil.java | 32 +++++++++++++++++++ .../java/forge/match/input/InputAttack.java | 30 ++++------------- .../forge/player/PlayerControllerHuman.java | 21 ++++++++++-- 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/forge-game/src/main/java/forge/game/combat/CombatUtil.java b/forge-game/src/main/java/forge/game/combat/CombatUtil.java index 5cfce30d06d..3a19a23f559 100644 --- a/forge-game/src/main/java/forge/game/combat/CombatUtil.java +++ b/forge-game/src/main/java/forge/game/combat/CombatUtil.java @@ -17,7 +17,9 @@ */ package forge.game.combat; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; + import forge.card.CardType; import forge.card.MagicColor; import forge.card.mana.ManaCost; @@ -29,6 +31,7 @@ import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardFactoryUtil; import forge.game.card.CardLists; +import forge.game.card.CardPredicates; import forge.game.cost.Cost; import forge.game.phase.PhaseType; import forge.game.phase.Untap; @@ -41,7 +44,9 @@ import forge.game.zone.ZoneType; import forge.util.Expressions; import forge.util.Lang; import forge.util.TextUtil; + import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.HashMap; @@ -1039,4 +1044,31 @@ public class CombatUtil { } } + public static List> getMandatoryAttackers(Player attackingPlayer, Combat combat, List defenders) { + List> attackers = new ArrayList>(); + List possibleAttackers = attackingPlayer.getCardsIn(ZoneType.Battlefield); + for (Card c : Iterables.filter(possibleAttackers, CardPredicates.Presets.CREATURES)) { + GameEntity mustAttack = c.getController().getMustAttackEntity() ; + if (c.hasStartOfKeyword("CARDNAME attacks specific player each combat if able")) { + final int i = c.getKeywordPosition("CARDNAME attacks specific player each combat if able"); + final String defined = c.getKeyword().get(i).split(":")[1]; + mustAttack = AbilityUtils.getDefinedPlayers(c, defined, null).get(0); + } + if (mustAttack != null && CombatUtil.canAttack(c, mustAttack, combat)) { + attackers.add(Pair.of(c, mustAttack)); + continue; + } + if (c.hasKeyword("CARDNAME attacks each combat if able.") || + (c.hasKeyword("CARDNAME attacks each turn if able.") && !c.getDamageHistory().getCreatureAttackedThisTurn())) { + for (GameEntity def : defenders) { + if (CombatUtil.canAttack(c, def, combat)) { + attackers.add(Pair.of(c, def)); + break; + } + } + } + } + return attackers; + } + } // end class CombatUtil diff --git a/forge-gui/src/main/java/forge/match/input/InputAttack.java b/forge-gui/src/main/java/forge/match/input/InputAttack.java index 9f204d0c170..893022ab8e5 100644 --- a/forge-gui/src/main/java/forge/match/input/InputAttack.java +++ b/forge-gui/src/main/java/forge/match/input/InputAttack.java @@ -22,7 +22,6 @@ import com.google.common.collect.Iterables; import forge.GuiBase; import forge.events.UiEventAttackerDeclared; import forge.game.GameEntity; -import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardLists; import forge.game.card.CardPredicates; @@ -37,6 +36,8 @@ import forge.util.ITriggerEvent; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.tuple.Pair; + /** *

* InputAttack class. @@ -73,29 +74,10 @@ public class InputAttack extends InputSyncronizedBase { return; // should even throw here! } - List possibleAttackers = playerAttacks.getCardsIn(ZoneType.Battlefield); - for (Card c : Iterables.filter(possibleAttackers, CardPredicates.Presets.CREATURES)) { - GameEntity mustAttack = c.getController().getMustAttackEntity() ; - if (c.hasStartOfKeyword("CARDNAME attacks specific player each combat if able")) { - final int i = c.getKeywordPosition("CARDNAME attacks specific player each combat if able"); - final String defined = c.getKeyword().get(i).split(":")[1]; - mustAttack = AbilityUtils.getDefinedPlayers(c, defined, null).get(0); - } - if (mustAttack != null && CombatUtil.canAttack(c, mustAttack, combat)) { - combat.addAttacker(c, mustAttack); - GuiBase.getInterface().fireEvent(new UiEventAttackerDeclared(c, mustAttack)); - continue; - } - if (c.hasKeyword("CARDNAME attacks each combat if able.") || - (c.hasKeyword("CARDNAME attacks each turn if able.") && !c.getDamageHistory().getCreatureAttackedThisTurn())) { - for (GameEntity def : defenders) { - if (CombatUtil.canAttack(c, def, combat)) { - combat.addAttacker(c, def); - GuiBase.getInterface().fireEvent(new UiEventAttackerDeclared(c, currentDefender)); - break; - } - } - } + List> mandatoryAttackers = CombatUtil.getMandatoryAttackers(playerAttacks, combat, defenders); + for (Pair attacker : mandatoryAttackers) { + combat.addAttacker(attacker.getLeft(), attacker.getRight()); + GuiBase.getInterface().fireEvent(new UiEventAttackerDeclared(attacker.getLeft(), attacker.getRight())); } updateMessage(); } diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index d8bc9d10224..c53aa6f26aa 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -17,6 +17,7 @@ import forge.control.FControlGamePlayback; import forge.deck.CardPool; import forge.deck.Deck; import forge.deck.DeckSection; +import forge.events.UiEventAttackerDeclared; import forge.game.Game; import forge.game.GameEntity; import forge.game.GameLogEntryType; @@ -27,6 +28,7 @@ import forge.game.card.Card; import forge.game.card.CardShields; import forge.game.card.CounterType; import forge.game.combat.Combat; +import forge.game.combat.CombatUtil; import forge.game.cost.Cost; import forge.game.cost.CostPart; import forge.game.cost.CostPartMana; @@ -620,13 +622,28 @@ public class PlayerControllerHuman extends PlayerController { } @Override - public void declareAttackers(Player attacker, Combat combat) { + public void declareAttackers(Player attackingPlayer, Combat combat) { if (mayAutoPass()) { + List> mandatoryAttackers = CombatUtil.getMandatoryAttackers(attackingPlayer, combat, combat.getDefenders()); + if (!mandatoryAttackers.isEmpty()) { + //even if auto-passing attack phase, if there are any mandatory attackers, + //ensure they're declared and then delay slightly so user can see as much + for (Pair attacker : mandatoryAttackers) { + combat.addAttacker(attacker.getLeft(), attacker.getRight()); + GuiBase.getInterface().fireEvent(new UiEventAttackerDeclared(attacker.getLeft(), attacker.getRight())); + } + try { + Thread.sleep(FControlGamePlayback.combatDelay); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + } return; //don't prompt to declare attackers if user chose to end the turn } // This input should not modify combat object itself, but should return user choice - InputAttack inpAttack = new InputAttack(attacker, combat); + InputAttack inpAttack = new InputAttack(attackingPlayer, combat); inpAttack.showAndWait(); }