- Improved AI anticipating activated First Strike abilities.

This commit is contained in:
Sloth
2013-07-20 10:25:20 +00:00
parent f839c1c41c
commit f83c4a36b5
3 changed files with 61 additions and 18 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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;
}
}