diff --git a/forge-ai/src/main/java/forge/ai/AiAttackController.java b/forge-ai/src/main/java/forge/ai/AiAttackController.java index 695bb7c6755..c4f8d7554de 100644 --- a/forge-ai/src/main/java/forge/ai/AiAttackController.java +++ b/forge-ai/src/main/java/forge/ai/AiAttackController.java @@ -35,6 +35,7 @@ import forge.game.card.CardLists; import forge.game.card.CounterType; import forge.game.combat.Combat; import forge.game.combat.CombatUtil; +import forge.game.combat.GlobalAttackRestrictions; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.trigger.Trigger; @@ -524,27 +525,39 @@ public class AiAttackController { // Determine who will be attacked GameEntity defender = this.chooseDefender(combat, bAssault); List attackersLeft = new ArrayList(this.attackers); + + // TODO probably use AttackConstraints instead of only GlobalAttackRestrictions? + GlobalAttackRestrictions restrict = GlobalAttackRestrictions.getGlobalRestrictions(ai, combat.getDefenders()); + final int attackMax = restrict.getMax(); + + if (attackMax == 0) { + // can't attack anymore + return; + } + // Attackers that don't really have a choice for (final Card attacker : this.attackers) { if (!CombatUtil.canAttack(attacker, defender)) { + attackersLeft.remove(attacker); continue; } boolean mustAttack = false; - for (String s : attacker.getKeywords()) { - if (s.equals("CARDNAME attacks each turn if able.") - || s.startsWith("CARDNAME attacks specific player each combat if able") - || s.equals("CARDNAME attacks each combat if able.")) { - mustAttack = true; - break; - } - if (attacker.getSVar("EndOfTurnLeavePlay").equals("True") - && isEffectiveAttacker(ai, attacker, combat)) { - mustAttack = true; - break; + if (attacker.getSVar("MustAttack").equals("True")) { + mustAttack = true; + } else if (attacker.getSVar("EndOfTurnLeavePlay").equals("True") + && isEffectiveAttacker(ai, attacker, combat)) { + mustAttack = true; + } else { + for (String s : attacker.getKeywords()) { + if (s.equals("CARDNAME attacks each turn if able.") + || s.startsWith("CARDNAME attacks specific player each combat if able") + || s.equals("CARDNAME attacks each combat if able.")) { + mustAttack = true; + break; + } } } - if (mustAttack || attacker.getController().getMustAttackEntity() != null - || attacker.getSVar("MustAttack").equals("True")) { + if (mustAttack || attacker.getController().getMustAttackEntity() != null) { combat.addAttacker(attacker, defender); attackersLeft.remove(attacker); } @@ -557,10 +570,15 @@ public class AiAttackController { System.out.println("Assault"); CardLists.sortByPowerDesc(attackersLeft); for (Card attacker : attackersLeft) { + // reached max, breakup + if (attackMax != -1 && combat.getAttackers().size() >= attackMax) + return; + if (CombatUtil.canAttack(attacker, defender) && this.isEffectiveAttacker(ai, attacker, combat)) { combat.addAttacker(attacker, defender); } } + // no more creatures to attack return; } @@ -611,6 +629,23 @@ public class AiAttackController { } } + if (attackMax != -1) { + // should attack with only max if able. + CardLists.sortByPowerDesc(this.attackers); + this.aiAggression = 6; + for (Card attacker : this.attackers) { + // reached max, breakup + if (attackMax != -1 && combat.getAttackers().size() >= attackMax) + break; + if (CombatUtil.canAttack(attacker, defender) && this.shouldAttack(ai, attacker, this.blockers, combat)) { + combat.addAttacker(attacker, defender); + } + } + // no more creatures to attack + return; + } + + // ******************* // Evaluate the creature forces // *******************