mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
Ensure creatures that must attack do so even if you End Turn before combat
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user