- Expanded the canGainKeyword AI function to take targeted abilities into account.

This commit is contained in:
Sloth
2014-10-28 13:23:27 +00:00
parent be7511c6b7
commit d52f8a6de7
2 changed files with 63 additions and 49 deletions

View File

@@ -335,7 +335,7 @@ public class AiBlockController {
// Try to block an attacker without first strike with a gang of first strikers // Try to block an attacker without first strike with a gang of first strikers
for (final Card attacker : attackersLeft) { for (final Card attacker : attackersLeft) {
if (!ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false)) { if (!ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false, combat)) {
blockers = getPossibleBlockers(combat, attacker, blockersLeft, false); blockers = getPossibleBlockers(combat, attacker, blockersLeft, false);
final List<Card> firstStrikeBlockers = new ArrayList<Card>(); final List<Card> firstStrikeBlockers = new ArrayList<Card>();
final List<Card> blockGang = new ArrayList<Card>(); final List<Card> blockGang = new ArrayList<Card>();
@@ -391,8 +391,8 @@ public class AiBlockController {
usableBlockers = CardLists.filter(blockers, new Predicate<Card>() { usableBlockers = CardLists.filter(blockers, new Predicate<Card>() {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
if (ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false) if (ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false, combat)
&& !ComputerUtilCombat.dealsFirstStrikeDamage(c, false)) { && !ComputerUtilCombat.dealsFirstStrikeDamage(c, false, combat)) {
return false; return false;
} }
return lifeInDanger || (ComputerUtilCard.evaluateCreature(c) + diff) < ComputerUtilCard.evaluateCreature(attacker); return lifeInDanger || (ComputerUtilCard.evaluateCreature(c) + diff) < ComputerUtilCard.evaluateCreature(attacker);
@@ -640,7 +640,7 @@ public class AiBlockController {
// than the attacker // than the attacker
// Don't use blockers without First Strike or Double Strike if // Don't use blockers without First Strike or Double Strike if
// attacker has it // attacker has it
if (ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false)) { if (ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false, combat)) {
safeBlockers = CardLists.getKeyword(blockers, "First Strike"); safeBlockers = CardLists.getKeyword(blockers, "First Strike");
safeBlockers.addAll(CardLists.getKeyword(blockers, "Double Strike")); safeBlockers.addAll(CardLists.getKeyword(blockers, "Double Strike"));
} else { } else {

View File

@@ -786,9 +786,9 @@ public class ComputerUtilCombat {
// if the attacker has first strike and wither the blocker will deal // if the attacker has first strike and wither the blocker will deal
// less damage than expected // less damage than expected
if (dealsFirstStrikeDamage(attacker, withoutAbilities) if (dealsFirstStrikeDamage(attacker, withoutAbilities, null)
&& (attacker.hasKeyword("Wither") || attacker.hasKeyword("Infect")) && (attacker.hasKeyword("Wither") || attacker.hasKeyword("Infect"))
&& !dealsFirstStrikeDamage(blocker, withoutAbilities) && !dealsFirstStrikeDamage(blocker, withoutAbilities, null)
&& !blocker.hasKeyword("CARDNAME can't have counters placed on it.")) { && !blocker.hasKeyword("CARDNAME can't have counters placed on it.")) {
power -= attacker.getNetCombatDamage(); power -= attacker.getNetCombatDamage();
} }
@@ -1074,8 +1074,7 @@ public class ComputerUtilCombat {
* a {@link forge.game.combat.Combat} object. * a {@link forge.game.combat.Combat} object.
* @return a int. * @return a int.
*/ */
public static int predictPowerBonusOfAttacker(final Card attacker, final Card blocker, final Combat combat public static int predictPowerBonusOfAttacker(final Card attacker, final Card blocker, final Combat combat , boolean withoutAbilities) {
, boolean withoutAbilities) {
int power = 0; int power = 0;
power += attacker.getKeywordMagnitude("Bushido"); power += attacker.getKeywordMagnitude("Bushido");
@@ -1104,9 +1103,9 @@ public class ComputerUtilCombat {
// if the defender has first strike and wither the attacker will deal // if the defender has first strike and wither the attacker will deal
// less damage than expected // less damage than expected
if (null != blocker) { if (null != blocker) {
if (ComputerUtilCombat.dealsFirstStrikeDamage(blocker, withoutAbilities) if (ComputerUtilCombat.dealsFirstStrikeDamage(blocker, withoutAbilities, combat)
&& (blocker.hasKeyword("Wither") || blocker.hasKeyword("Infect")) && (blocker.hasKeyword("Wither") || blocker.hasKeyword("Infect"))
&& !ComputerUtilCombat.dealsFirstStrikeDamage(attacker, withoutAbilities) && !ComputerUtilCombat.dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
&& !attacker.hasKeyword("CARDNAME can't have counters placed on it.")) { && !attacker.hasKeyword("CARDNAME can't have counters placed on it.")) {
power -= blocker.getNetCombatDamage(); power -= blocker.getNetCombatDamage();
} }
@@ -1644,7 +1643,7 @@ public class ComputerUtilCombat {
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, defender, combat, withoutAbilities); + ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, defender, combat, withoutAbilities);
if (defender.hasKeyword("Double Strike")) { if (defender.hasKeyword("Double Strike")) {
if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities) || attacker.hasSVar("DestroyWhenDamaged"))) { if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities, combat) || attacker.hasSVar("DestroyWhenDamaged"))) {
return true; return true;
} }
if (defenderDamage >= attackerLife) { if (defenderDamage >= attackerLife) {
@@ -1653,11 +1652,11 @@ public class ComputerUtilCombat {
// Attacker may kill the blocker before he can deal normal // Attacker may kill the blocker before he can deal normal
// (secondary) damage // (secondary) damage
if (dealsFirstStrikeDamage(attacker, withoutAbilities) && !defender.hasKeyword("Indestructible")) { if (dealsFirstStrikeDamage(attacker, withoutAbilities, combat) && !defender.hasKeyword("Indestructible")) {
if (attackerDamage >= defenderLife) { if (attackerDamage >= defenderLife) {
return false; return false;
} }
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities) || defender.hasSVar("DestroyWhenDamaged"))) { if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities, combat) || defender.hasSVar("DestroyWhenDamaged"))) {
return false; return false;
} }
} }
@@ -1668,19 +1667,19 @@ public class ComputerUtilCombat {
else { // no double strike for defender else { // no double strike for defender
// Attacker may kill the blocker before he can deal any damage // Attacker may kill the blocker before he can deal any damage
if (dealsFirstStrikeDamage(attacker, withoutAbilities) if (dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
&& !defender.hasKeyword("Indestructible") && !defender.hasKeyword("Indestructible")
&& !dealsFirstStrikeDamage(defender, withoutAbilities)) { && !dealsFirstStrikeDamage(defender, withoutAbilities, combat)) {
if (attackerDamage >= defenderLife) { if (attackerDamage >= defenderLife) {
return false; return false;
} }
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities) || defender.hasSVar("DestroyWhenDamaged"))) { if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities, combat) || defender.hasSVar("DestroyWhenDamaged"))) {
return false; return false;
} }
} }
if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities) || attacker.hasSVar("DestroyWhenDamaged"))) { if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities, combat) || attacker.hasSVar("DestroyWhenDamaged"))) {
return true; return true;
} }
@@ -1814,7 +1813,7 @@ public class ComputerUtilCombat {
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, defender, combat, withoutAbilities); + ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, defender, combat, withoutAbilities);
if (attacker.hasKeyword("Double Strike")) { if (attacker.hasKeyword("Double Strike")) {
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities) || defender.hasSVar("DestroyWhenDamaged"))) { if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities, combat) || defender.hasSVar("DestroyWhenDamaged"))) {
return true; return true;
} }
if (attackerDamage >= defenderLife) { if (attackerDamage >= defenderLife) {
@@ -1823,11 +1822,11 @@ public class ComputerUtilCombat {
// Attacker may kill the blocker before he can deal normal // Attacker may kill the blocker before he can deal normal
// (secondary) damage // (secondary) damage
if (dealsFirstStrikeDamage(defender, withoutAbilities) && !attacker.hasKeyword("Indestructible")) { if (dealsFirstStrikeDamage(defender, withoutAbilities, combat) && !attacker.hasKeyword("Indestructible")) {
if (defenderDamage >= attackerLife) { if (defenderDamage >= attackerLife) {
return false; return false;
} }
if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities) || attacker.hasSVar("DestroyWhenDamaged"))) { if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities, combat) || attacker.hasSVar("DestroyWhenDamaged"))) {
return false; return false;
} }
} }
@@ -1838,18 +1837,18 @@ public class ComputerUtilCombat {
else { // no double strike for attacker else { // no double strike for attacker
// Defender may kill the attacker before he can deal any damage // Defender may kill the attacker before he can deal any damage
if (dealsFirstStrikeDamage(defender, withoutAbilities) && !attacker.hasKeyword("Indestructible") if (dealsFirstStrikeDamage(defender, withoutAbilities, combat) && !attacker.hasKeyword("Indestructible")
&& !dealsFirstStrikeDamage(attacker, withoutAbilities)) { && !dealsFirstStrikeDamage(attacker, withoutAbilities, combat)) {
if (defenderDamage >= attackerLife) { if (defenderDamage >= attackerLife) {
return false; return false;
} }
if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities) || attacker.hasSVar("DestroyWhenDamaged"))) { if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities, combat) || attacker.hasSVar("DestroyWhenDamaged"))) {
return false; return false;
} }
} }
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities) || defender.hasSVar("DestroyWhenDamaged"))) { if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities, combat) || defender.hasSVar("DestroyWhenDamaged"))) {
return true; return true;
} }
@@ -2152,7 +2151,7 @@ public class ComputerUtilCombat {
return restDamage; return restDamage;
} }
public final static boolean dealsFirstStrikeDamage(final Card combatant, final boolean withoutAbilities) { public final static boolean dealsFirstStrikeDamage(final Card combatant, final boolean withoutAbilities, final Combat combat) {
if (combatant.hasKeyword("Double Strike") || combatant.hasKeyword("First Strike")) { if (combatant.hasKeyword("Double Strike") || combatant.hasKeyword("First Strike")) {
return true; return true;
@@ -2162,7 +2161,7 @@ public class ComputerUtilCombat {
List<String> keywords = new ArrayList<String>(); List<String> keywords = new ArrayList<String>();
keywords.add("Double Strike"); keywords.add("Double Strike");
keywords.add("First Strike"); keywords.add("First Strike");
return canGainKeyword(combatant, keywords); return canGainKeyword(combatant, keywords, combat);
} }
return false; return false;
@@ -2176,41 +2175,56 @@ public class ComputerUtilCombat {
* @param withoutAbilities flag that determines if activated abilities are to be considered * @param withoutAbilities flag that determines if activated abilities are to be considered
* @return * @return
*/ */
public final static boolean hasKeyword(final Card combatant, final String keyword, final boolean withoutAbilities) { public final static boolean hasKeyword(final Card combatant, final String keyword, final boolean withoutAbilities, final Combat combat) {
if (combatant.hasKeyword(keyword)) { if (combatant.hasKeyword(keyword)) {
return true; return true;
} }
if (!withoutAbilities) { if (!withoutAbilities) {
List<String> keywords = new ArrayList<String>(); List<String> keywords = new ArrayList<String>();
keywords.add(keyword); keywords.add(keyword);
return canGainKeyword(combatant, keywords); return canGainKeyword(combatant, keywords, combat);
} else { } else {
return false; return false;
} }
} }
public final static boolean canGainKeyword(final Card combatant, final List<String> keywords) { public final static boolean canGainKeyword(final Card combatant, final List<String> keywords, final Combat combat) {
for (SpellAbility ability : combatant.getAllSpellAbilities()) { final Player controller = combatant.getController();
if (!(ability instanceof AbilityActivated) || ability.getPayCosts() == null) { for (Card c : controller.getCardsIn(ZoneType.Battlefield)) {
continue; for (SpellAbility ability : c.getAllSpellAbilities()) {
} if (!(ability instanceof AbilityActivated) || ability.getPayCosts() == null) {
if (ability.getApi() != ApiType.Pump) { continue;
continue; }
} if (ability.getApi() != ApiType.Pump) {
continue;
}
if (ability.hasParam("ActivationPhases") || ability.hasParam("SorcerySpeed")) {
continue;
}
if (!ability.hasParam("KW") || !ComputerUtilCost.canPayCost(ability, controller)) {
continue;
}
if (c != combatant) {
if (ability.getTargetRestrictions() == null || !ability.canTarget(combatant)) {
continue;
}
//the AI will will fail to predict tapping of attackers
if (controller.getGame().getPhaseHandler().isPlayerTurn(controller)) {
if (combat == null || !combat.isAttacking(combatant) || combat.isAttacking(c)) {
continue;
}
}
if (ability.hasParam("ActivationPhases") || ability.hasParam("SorcerySpeed")) { }
continue; for (String keyword : keywords) {
} if (ability.getParam("KW").contains(keyword)) {
return true;
if (!ability.hasParam("KW") || !ComputerUtilCost.canPayCost(ability, combatant.getController())) { }
continue; }
} }
for (String keyword : keywords) { }
if (ability.getParam("KW").contains(keyword)) {
return true;
}
}
}
return false; return false;
} }