diff --git a/res/cardsfolder/n/novablast_wurm.txt b/res/cardsfolder/n/novablast_wurm.txt index ded3b783772..de1016ed7ec 100644 --- a/res/cardsfolder/n/novablast_wurm.txt +++ b/res/cardsfolder/n/novablast_wurm.txt @@ -3,6 +3,6 @@ ManaCost:3 G G W W Types:Creature Wurm PT:7/7 T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDestroyAll | TriggerDescription$ Whenever CARDNAME attacks, destroy all other creatures. -SVar:TrigDestroyAll:AB$DestroyAll | Cost$ 0 | ValidCards$ Creature.Other +SVar:TrigDestroyAll:AB$ DestroyAll | Cost$ 0 | ValidCards$ Creature.Other SVar:Picture:http://www.wizards.com/global/images/magic/general/novablast_wurm.jpg Oracle:Whenever Novablast Wurm attacks, destroy all other creatures. \ No newline at end of file diff --git a/src/main/java/forge/card/ability/ai/PumpAiBase.java b/src/main/java/forge/card/ability/ai/PumpAiBase.java index c71015c742a..54d6cf416bc 100644 --- a/src/main/java/forge/card/ability/ai/PumpAiBase.java +++ b/src/main/java/forge/card/ability/ai/PumpAiBase.java @@ -170,7 +170,6 @@ public abstract class PumpAiBase extends SpellAbilityAi { final boolean evasive = (keyword.endsWith("Unblockable") || keyword.endsWith("Fear") || keyword.endsWith("Intimidate") || keyword.endsWith("Shadow") || keyword.startsWith("CantBeBlockedBy")); - final boolean combatRelevant = (keyword.endsWith("First Strike") || keyword.contains("Bushido")); // give evasive keywords to creatures that can or do attack if (evasive) { if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) @@ -241,13 +240,30 @@ public abstract class PumpAiBase extends SpellAbilityAi { } } return false; - } else if (combatRelevant) { + } else if (keyword.equals("Bushido")) { if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS) - || opp.getCreaturesInPlay().size() < 1 + || opp.getCreaturesInPlay().isEmpty() || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { return false; } + } else if (keyword.equals("First Strike")) { + if (ph.isPlayerTurn(ai) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) + && newPower > 0 + && ph.getPhase().isBefore(PhaseType.COMBAT_DAMAGE) + && !CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { + return true; + } + if (combat != null && combat.isBlocking(card) && !combat.getAttackersBlockedBy(card).isEmpty()) { + Card attacker = combat.getAttackersBlockedBy(card).get(0); + if (!ComputerUtilCombat.canDestroyAttacker(ai, attacker, card, combat, true) + && ComputerUtilCombat.canDestroyAttacker(ai, attacker, card, combat, false)) + return true; + if (ComputerUtilCombat.canDestroyBlocker(ai, card, attacker, combat, true) + && !ComputerUtilCombat.canDestroyBlocker(ai, card, attacker, combat, false)) + return true; + } + return false; } else if (keyword.equals("Double Strike")) { if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || newPower <= 0 diff --git a/src/main/java/forge/game/ai/ComputerUtilCombat.java b/src/main/java/forge/game/ai/ComputerUtilCombat.java index d7846921abb..21599811f35 100644 --- a/src/main/java/forge/game/ai/ComputerUtilCombat.java +++ b/src/main/java/forge/game/ai/ComputerUtilCombat.java @@ -1406,8 +1406,8 @@ public class ComputerUtilCombat { } } // flanking - if (((attacker.hasKeyword("Indestructible") || (ComputerUtil.canRegenerate(ai, attacker) && !withoutAbilities)) && !(defender - .hasKeyword("Wither") || defender.hasKeyword("Infect"))) + if (((attacker.hasKeyword("Indestructible") || (ComputerUtil.canRegenerate(ai, attacker) && !withoutAbilities)) + && !(defender.hasKeyword("Wither") || defender.hasKeyword("Infect"))) || (attacker.hasKeyword("Persist") && !attacker.canReceiveCounters(CounterType.M1M1) && (attacker .getCounters(CounterType.M1M1) == 0)) || (attacker.hasKeyword("Undying") && !attacker.canReceiveCounters(CounterType.P1P1) && (attacker @@ -1459,8 +1459,7 @@ public class ComputerUtilCombat { // Attacker may kill the blocker before he can deal normal // (secondary) damage - if ((attacker.hasKeyword("Double Strike") || attacker.hasKeyword("First Strike")) - && !defender.hasKeyword("Indestructible")) { + if (dealsFirstStrikeDamage(attacker, withoutAbilities) && !defender.hasKeyword("Indestructible")) { if (attackerDamage >= defenderLife) { return false; } @@ -1469,16 +1468,15 @@ public class ComputerUtilCombat { return false; } } - if (attackerLife <= (2 * defenderDamage)) { + if (attackerLife <= 2 * defenderDamage) { return true; } } // defender double strike else { // no double strike for defender // Attacker may kill the blocker before he can deal any damage - if ((attacker.hasKeyword("Double Strike") || attacker.hasKeyword("First Strike")) - && !defender.hasKeyword("Indestructible") - && !defender.hasKeyword("First Strike")) { + if (dealsFirstStrikeDamage(attacker, withoutAbilities) + && !defender.hasKeyword("Indestructible") && !defender.hasKeyword("First Strike")) { if (attackerDamage >= defenderLife) { return false; @@ -1617,8 +1615,7 @@ public class ComputerUtilCombat { // Attacker may kill the blocker before he can deal normal // (secondary) damage - if ((defender.hasKeyword("Double Strike") || defender.hasKeyword("First Strike")) - && !attacker.hasKeyword("Indestructible")) { + if (dealsFirstStrikeDamage(defender, withoutAbilities) && !attacker.hasKeyword("Indestructible")) { if (defenderDamage >= attackerLife) { return false; } @@ -1627,16 +1624,15 @@ public class ComputerUtilCombat { return false; } } - if (defenderLife <= (2 * attackerDamage)) { + if (defenderLife <= 2 * attackerDamage) { return true; } } // attacker double strike else { // no double strike for attacker // Defender may kill the attacker before he can deal any damage - if (defender.hasKeyword("Double Strike") - || (defender.hasKeyword("First Strike") && !attacker.hasKeyword("Indestructible") && !attacker - .hasKeyword("First Strike"))) { + if (dealsFirstStrikeDamage(defender, withoutAbilities) && !attacker.hasKeyword("Indestructible") + && !attacker.hasKeyword("First Strike")) { if (defenderDamage >= attackerLife) { return false; @@ -1952,6 +1948,37 @@ public class ComputerUtilCombat { return restDamage; } + public final static boolean dealsFirstStrikeDamage(final Card combatant, final boolean withoutAbilities) { + + if (combatant.hasKeyword("Double Strike") || combatant.hasKeyword("First Strike")) { + return true; + } + + if (!withoutAbilities) { + for (SpellAbility ability : combatant.getAllSpellAbilities()) { + if (!(ability instanceof AbilityActivated) || ability.getPayCosts() == null) { + continue; + } + if (ability.getApi() != ApiType.Pump) { + continue; + } + + if (ability.hasParam("ActivationPhases") || ability.hasParam("SorcerySpeed")) { + continue; + } + + if (!ability.hasParam("KW")) { + continue; + } + + if (ability.getParam("KW").contains("First Strike") && ComputerUtilCost.canPayCost(ability, combatant.getController())) { + return true; + } + } + } + + return false; + } }