mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
- Expanded the canGainKeyword AI function to take targeted abilities into account.
This commit is contained in:
@@ -335,7 +335,7 @@ public class AiBlockController {
|
||||
|
||||
// Try to block an attacker without first strike with a gang of first strikers
|
||||
for (final Card attacker : attackersLeft) {
|
||||
if (!ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false)) {
|
||||
if (!ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false, combat)) {
|
||||
blockers = getPossibleBlockers(combat, attacker, blockersLeft, false);
|
||||
final List<Card> firstStrikeBlockers = new ArrayList<Card>();
|
||||
final List<Card> blockGang = new ArrayList<Card>();
|
||||
@@ -391,8 +391,8 @@ public class AiBlockController {
|
||||
usableBlockers = CardLists.filter(blockers, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
if (ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false)
|
||||
&& !ComputerUtilCombat.dealsFirstStrikeDamage(c, false)) {
|
||||
if (ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false, combat)
|
||||
&& !ComputerUtilCombat.dealsFirstStrikeDamage(c, false, combat)) {
|
||||
return false;
|
||||
}
|
||||
return lifeInDanger || (ComputerUtilCard.evaluateCreature(c) + diff) < ComputerUtilCard.evaluateCreature(attacker);
|
||||
@@ -640,7 +640,7 @@ public class AiBlockController {
|
||||
// than the attacker
|
||||
// Don't use blockers without First Strike or Double Strike if
|
||||
// attacker has it
|
||||
if (ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false)) {
|
||||
if (ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false, combat)) {
|
||||
safeBlockers = CardLists.getKeyword(blockers, "First Strike");
|
||||
safeBlockers.addAll(CardLists.getKeyword(blockers, "Double Strike"));
|
||||
} else {
|
||||
|
||||
@@ -786,9 +786,9 @@ public class ComputerUtilCombat {
|
||||
|
||||
// if the attacker has first strike and wither the blocker will deal
|
||||
// less damage than expected
|
||||
if (dealsFirstStrikeDamage(attacker, withoutAbilities)
|
||||
if (dealsFirstStrikeDamage(attacker, withoutAbilities, null)
|
||||
&& (attacker.hasKeyword("Wither") || attacker.hasKeyword("Infect"))
|
||||
&& !dealsFirstStrikeDamage(blocker, withoutAbilities)
|
||||
&& !dealsFirstStrikeDamage(blocker, withoutAbilities, null)
|
||||
&& !blocker.hasKeyword("CARDNAME can't have counters placed on it.")) {
|
||||
power -= attacker.getNetCombatDamage();
|
||||
}
|
||||
@@ -1074,8 +1074,7 @@ public class ComputerUtilCombat {
|
||||
* a {@link forge.game.combat.Combat} object.
|
||||
* @return a int.
|
||||
*/
|
||||
public static int predictPowerBonusOfAttacker(final Card attacker, final Card blocker, final Combat combat
|
||||
, boolean withoutAbilities) {
|
||||
public static int predictPowerBonusOfAttacker(final Card attacker, final Card blocker, final Combat combat , boolean withoutAbilities) {
|
||||
int power = 0;
|
||||
|
||||
power += attacker.getKeywordMagnitude("Bushido");
|
||||
@@ -1104,9 +1103,9 @@ public class ComputerUtilCombat {
|
||||
// if the defender has first strike and wither the attacker will deal
|
||||
// less damage than expected
|
||||
if (null != blocker) {
|
||||
if (ComputerUtilCombat.dealsFirstStrikeDamage(blocker, withoutAbilities)
|
||||
if (ComputerUtilCombat.dealsFirstStrikeDamage(blocker, withoutAbilities, combat)
|
||||
&& (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.")) {
|
||||
power -= blocker.getNetCombatDamage();
|
||||
}
|
||||
@@ -1644,7 +1643,7 @@ public class ComputerUtilCombat {
|
||||
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, defender, combat, withoutAbilities);
|
||||
|
||||
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;
|
||||
}
|
||||
if (defenderDamage >= attackerLife) {
|
||||
@@ -1653,11 +1652,11 @@ public class ComputerUtilCombat {
|
||||
|
||||
// Attacker may kill the blocker before he can deal normal
|
||||
// (secondary) damage
|
||||
if (dealsFirstStrikeDamage(attacker, withoutAbilities) && !defender.hasKeyword("Indestructible")) {
|
||||
if (dealsFirstStrikeDamage(attacker, withoutAbilities, combat) && !defender.hasKeyword("Indestructible")) {
|
||||
if (attackerDamage >= defenderLife) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1668,19 +1667,19 @@ public class ComputerUtilCombat {
|
||||
|
||||
else { // no double strike for defender
|
||||
// Attacker may kill the blocker before he can deal any damage
|
||||
if (dealsFirstStrikeDamage(attacker, withoutAbilities)
|
||||
if (dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
|
||||
&& !defender.hasKeyword("Indestructible")
|
||||
&& !dealsFirstStrikeDamage(defender, withoutAbilities)) {
|
||||
&& !dealsFirstStrikeDamage(defender, withoutAbilities, combat)) {
|
||||
|
||||
if (attackerDamage >= defenderLife) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities) || attacker.hasSVar("DestroyWhenDamaged"))) {
|
||||
if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities, combat) || attacker.hasSVar("DestroyWhenDamaged"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1814,7 +1813,7 @@ public class ComputerUtilCombat {
|
||||
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, defender, combat, withoutAbilities);
|
||||
|
||||
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;
|
||||
}
|
||||
if (attackerDamage >= defenderLife) {
|
||||
@@ -1823,11 +1822,11 @@ public class ComputerUtilCombat {
|
||||
|
||||
// Attacker may kill the blocker before he can deal normal
|
||||
// (secondary) damage
|
||||
if (dealsFirstStrikeDamage(defender, withoutAbilities) && !attacker.hasKeyword("Indestructible")) {
|
||||
if (dealsFirstStrikeDamage(defender, withoutAbilities, combat) && !attacker.hasKeyword("Indestructible")) {
|
||||
if (defenderDamage >= attackerLife) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1838,18 +1837,18 @@ public class ComputerUtilCombat {
|
||||
|
||||
else { // no double strike for attacker
|
||||
// Defender may kill the attacker before he can deal any damage
|
||||
if (dealsFirstStrikeDamage(defender, withoutAbilities) && !attacker.hasKeyword("Indestructible")
|
||||
&& !dealsFirstStrikeDamage(attacker, withoutAbilities)) {
|
||||
if (dealsFirstStrikeDamage(defender, withoutAbilities, combat) && !attacker.hasKeyword("Indestructible")
|
||||
&& !dealsFirstStrikeDamage(attacker, withoutAbilities, combat)) {
|
||||
|
||||
if (defenderDamage >= attackerLife) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities) || defender.hasSVar("DestroyWhenDamaged"))) {
|
||||
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities, combat) || defender.hasSVar("DestroyWhenDamaged"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2152,7 +2151,7 @@ public class ComputerUtilCombat {
|
||||
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")) {
|
||||
return true;
|
||||
@@ -2162,7 +2161,7 @@ public class ComputerUtilCombat {
|
||||
List<String> keywords = new ArrayList<String>();
|
||||
keywords.add("Double Strike");
|
||||
keywords.add("First Strike");
|
||||
return canGainKeyword(combatant, keywords);
|
||||
return canGainKeyword(combatant, keywords, combat);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -2176,41 +2175,56 @@ public class ComputerUtilCombat {
|
||||
* @param withoutAbilities flag that determines if activated abilities are to be considered
|
||||
* @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)) {
|
||||
return true;
|
||||
}
|
||||
if (!withoutAbilities) {
|
||||
List<String> keywords = new ArrayList<String>();
|
||||
keywords.add(keyword);
|
||||
return canGainKeyword(combatant, keywords);
|
||||
return canGainKeyword(combatant, keywords, combat);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public final static boolean canGainKeyword(final Card combatant, final List<String> keywords) {
|
||||
for (SpellAbility ability : combatant.getAllSpellAbilities()) {
|
||||
if (!(ability instanceof AbilityActivated) || ability.getPayCosts() == null) {
|
||||
continue;
|
||||
}
|
||||
if (ability.getApi() != ApiType.Pump) {
|
||||
continue;
|
||||
}
|
||||
public final static boolean canGainKeyword(final Card combatant, final List<String> keywords, final Combat combat) {
|
||||
final Player controller = combatant.getController();
|
||||
for (Card c : controller.getCardsIn(ZoneType.Battlefield)) {
|
||||
for (SpellAbility ability : c.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("ActivationPhases") || ability.hasParam("SorcerySpeed")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ability.hasParam("KW") || !ComputerUtilCost.canPayCost(ability, combatant.getController())) {
|
||||
continue;
|
||||
}
|
||||
for (String keyword : keywords) {
|
||||
if (ability.getParam("KW").contains(keyword)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for (String keyword : keywords) {
|
||||
if (ability.getParam("KW").contains(keyword)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user