Ensure creatures that must attack do so even if you End Turn before combat

This commit is contained in:
drdev
2014-08-22 04:23:22 +00:00
parent 7a98346356
commit 1b26d6677b
3 changed files with 57 additions and 26 deletions

View File

@@ -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<Pair<Card, GameEntity>> getMandatoryAttackers(Player attackingPlayer, Combat combat, List<GameEntity> defenders) {
List<Pair<Card, GameEntity>> attackers = new ArrayList<Pair<Card, GameEntity>>();
List<Card> 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

View File

@@ -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;
/**
* <p>
* InputAttack class.
@@ -73,29 +74,10 @@ public class InputAttack extends InputSyncronizedBase {
return; // should even throw here!
}
List<Card> 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<Pair<Card, GameEntity>> mandatoryAttackers = CombatUtil.getMandatoryAttackers(playerAttacks, combat, defenders);
for (Pair<Card, GameEntity> attacker : mandatoryAttackers) {
combat.addAttacker(attacker.getLeft(), attacker.getRight());
GuiBase.getInterface().fireEvent(new UiEventAttackerDeclared(attacker.getLeft(), attacker.getRight()));
}
updateMessage();
}

View File

@@ -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<Pair<Card, GameEntity>> 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<Card, GameEntity> 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();
}