diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index f28ecbc75cd..ec4db352e47 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -1659,11 +1659,23 @@ public class GameAction { private boolean stateBasedAction_Battle(Card c, CardCollection removeList) { boolean checkAgain = false; - if (!c.getType().isBattle()) { - return false; + if (!c.isBattle()) { + return checkAgain; + } + if (((c.getProtectingPlayer() == null || !c.getProtectingPlayer().isInGame()) && + (game.getCombat() == null || game.getCombat().getAttackersOf(c).isEmpty())) || + (c.getType().hasStringType("Siege") && c.getController().equals(c.getProtectingPlayer()))) { + Player newProtector = c.getController().getController().chooseSingleEntityForEffect(c.getController().getOpponents(), null, "Choose an opponent to protect this battle", null); + // seems unlikely unless range of influence gets implemented + if (newProtector == null) { + removeList.add(c); + } else { + c.setProtectingPlayer(newProtector); + } + checkAgain = true; } if (c.getCounters(CounterEnumType.DEFENSE) > 0) { - return false; + return checkAgain; } // 704.5v If a battle has defense 0 and it isn't the source of an ability that has triggered but not yet left the stack, // it’s put into its owner’s graveyard. diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 8c707bffef3..c8a300d918f 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -519,14 +519,6 @@ public class CardFactoryUtil { return filteredkw; } - public static int getCardTypesFromList(final CardCollectionView list) { - EnumSet types = EnumSet.noneOf(CardType.CoreType.class); - for (Card c1 : list) { - c1.getType().getCoreTypes().forEach(types::add); - } - return types.size(); - } - /** * Adds the ability factory abilities. * 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 794bfdf891a..a25282f0e9a 100644 --- a/forge-game/src/main/java/forge/game/combat/CombatUtil.java +++ b/forge-game/src/main/java/forge/game/combat/CombatUtil.java @@ -201,6 +201,10 @@ public class CombatUtil { private static boolean canAttack(final Card attacker, final GameEntity defender, final boolean forNextTurn) { final Game game = attacker.getGame(); + if (attacker.isBattle()) { + return false; + } + // Basic checks (unless is for next turn) if (!forNextTurn && ( !attacker.isCreature() @@ -480,6 +484,10 @@ public class CombatUtil { return false; } + if (blocker.isBattle()) { + return false; + } + if (!nextTurn && blocker.isTapped() && !blocker.hasKeyword("CARDNAME can block as though it were untapped.")) { return false; } diff --git a/forge-game/src/main/java/forge/game/cost/CostExile.java b/forge-game/src/main/java/forge/game/cost/CostExile.java index 4ed187d3a46..3ba45612da6 100644 --- a/forge-game/src/main/java/forge/game/cost/CostExile.java +++ b/forge-game/src/main/java/forge/game/cost/CostExile.java @@ -222,7 +222,7 @@ public class CostExile extends CostPartWithList { int amount = this.getAbilityAmount(ability); if (nTypes > -1) { - if (CardFactoryUtil.getCardTypesFromList(list) < nTypes) return false; + if (AbilityUtils.countCardTypesFromList(list, false) < nTypes) return false; } if (sharedType) { // will need more logic if cost ever wants more than 2 that share a type diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index a7504cc58d2..8527c6ec441 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -26,6 +26,7 @@ import forge.card.mana.ManaCostShard; import forge.game.*; import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityKey; +import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.ability.effects.DetachedCardEffect; import forge.game.ability.effects.RollDiceEffect; @@ -2176,7 +2177,7 @@ public class Player extends GameEntity implements Comparable { } public final boolean hasDelirium() { - return CardFactoryUtil.getCardTypesFromList(getCardsIn(ZoneType.Graveyard)) >= 4; + return AbilityUtils.countCardTypesFromList(getCardsIn(ZoneType.Graveyard), false) >= 4; } public final boolean hasLandfall() { diff --git a/forge-gui/src/main/java/forge/player/HumanCostDecision.java b/forge-gui/src/main/java/forge/player/HumanCostDecision.java index bbf350381a9..6df9bc03e8d 100644 --- a/forge-gui/src/main/java/forge/player/HumanCostDecision.java +++ b/forge-gui/src/main/java/forge/player/HumanCostDecision.java @@ -303,7 +303,7 @@ public class HumanCostDecision extends CostDecisionMakerBase { inp.setCancelAllowed(true); inp.showAndWait(); if (inp.hasCancelled() || - !Expressions.compare(CardFactoryUtil.getCardTypesFromList(list), "GE", nTypes)) { + !Expressions.compare(AbilityUtils.countCardTypesFromList(list, false), "GE", nTypes)) { return null; } return PaymentDecision.card(inp.getSelected());