mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
- Improved AI anticipating activated First Strike abilities.
This commit is contained in:
@@ -3,6 +3,6 @@ ManaCost:3 G G W W
|
|||||||
Types:Creature Wurm
|
Types:Creature Wurm
|
||||||
PT:7/7
|
PT:7/7
|
||||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDestroyAll | TriggerDescription$ Whenever CARDNAME attacks, destroy all other creatures.
|
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
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/novablast_wurm.jpg
|
||||||
Oracle:Whenever Novablast Wurm attacks, destroy all other creatures.
|
Oracle:Whenever Novablast Wurm attacks, destroy all other creatures.
|
||||||
@@ -170,7 +170,6 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
|||||||
final boolean evasive = (keyword.endsWith("Unblockable") || keyword.endsWith("Fear")
|
final boolean evasive = (keyword.endsWith("Unblockable") || keyword.endsWith("Fear")
|
||||||
|| keyword.endsWith("Intimidate") || keyword.endsWith("Shadow")
|
|| keyword.endsWith("Intimidate") || keyword.endsWith("Shadow")
|
||||||
|| keyword.startsWith("CantBeBlockedBy"));
|
|| keyword.startsWith("CantBeBlockedBy"));
|
||||||
final boolean combatRelevant = (keyword.endsWith("First Strike") || keyword.contains("Bushido"));
|
|
||||||
// give evasive keywords to creatures that can or do attack
|
// give evasive keywords to creatures that can or do attack
|
||||||
if (evasive) {
|
if (evasive) {
|
||||||
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|
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;
|
return false;
|
||||||
} else if (combatRelevant) {
|
} else if (keyword.equals("Bushido")) {
|
||||||
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|
||||||
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
||||||
|| opp.getCreaturesInPlay().size() < 1
|
|| opp.getCreaturesInPlay().isEmpty()
|
||||||
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) {
|
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) {
|
||||||
return false;
|
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")) {
|
} else if (keyword.equals("Double Strike")) {
|
||||||
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|
||||||
|| newPower <= 0
|
|| newPower <= 0
|
||||||
|
|||||||
@@ -1406,8 +1406,8 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
} // flanking
|
} // flanking
|
||||||
|
|
||||||
if (((attacker.hasKeyword("Indestructible") || (ComputerUtil.canRegenerate(ai, attacker) && !withoutAbilities)) && !(defender
|
if (((attacker.hasKeyword("Indestructible") || (ComputerUtil.canRegenerate(ai, attacker) && !withoutAbilities))
|
||||||
.hasKeyword("Wither") || defender.hasKeyword("Infect")))
|
&& !(defender.hasKeyword("Wither") || defender.hasKeyword("Infect")))
|
||||||
|| (attacker.hasKeyword("Persist") && !attacker.canReceiveCounters(CounterType.M1M1) && (attacker
|
|| (attacker.hasKeyword("Persist") && !attacker.canReceiveCounters(CounterType.M1M1) && (attacker
|
||||||
.getCounters(CounterType.M1M1) == 0))
|
.getCounters(CounterType.M1M1) == 0))
|
||||||
|| (attacker.hasKeyword("Undying") && !attacker.canReceiveCounters(CounterType.P1P1) && (attacker
|
|| (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
|
// Attacker may kill the blocker before he can deal normal
|
||||||
// (secondary) damage
|
// (secondary) damage
|
||||||
if ((attacker.hasKeyword("Double Strike") || attacker.hasKeyword("First Strike"))
|
if (dealsFirstStrikeDamage(attacker, withoutAbilities) && !defender.hasKeyword("Indestructible")) {
|
||||||
&& !defender.hasKeyword("Indestructible")) {
|
|
||||||
if (attackerDamage >= defenderLife) {
|
if (attackerDamage >= defenderLife) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1469,16 +1468,15 @@ public class ComputerUtilCombat {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (attackerLife <= (2 * defenderDamage)) {
|
if (attackerLife <= 2 * defenderDamage) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // defender double strike
|
} // defender double strike
|
||||||
|
|
||||||
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 ((attacker.hasKeyword("Double Strike") || attacker.hasKeyword("First Strike"))
|
if (dealsFirstStrikeDamage(attacker, withoutAbilities)
|
||||||
&& !defender.hasKeyword("Indestructible")
|
&& !defender.hasKeyword("Indestructible") && !defender.hasKeyword("First Strike")) {
|
||||||
&& !defender.hasKeyword("First Strike")) {
|
|
||||||
|
|
||||||
if (attackerDamage >= defenderLife) {
|
if (attackerDamage >= defenderLife) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1617,8 +1615,7 @@ 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 ((defender.hasKeyword("Double Strike") || defender.hasKeyword("First Strike"))
|
if (dealsFirstStrikeDamage(defender, withoutAbilities) && !attacker.hasKeyword("Indestructible")) {
|
||||||
&& !attacker.hasKeyword("Indestructible")) {
|
|
||||||
if (defenderDamage >= attackerLife) {
|
if (defenderDamage >= attackerLife) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1627,16 +1624,15 @@ public class ComputerUtilCombat {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (defenderLife <= (2 * attackerDamage)) {
|
if (defenderLife <= 2 * attackerDamage) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // attacker double strike
|
} // attacker double strike
|
||||||
|
|
||||||
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 (defender.hasKeyword("Double Strike")
|
if (dealsFirstStrikeDamage(defender, withoutAbilities) && !attacker.hasKeyword("Indestructible")
|
||||||
|| (defender.hasKeyword("First Strike") && !attacker.hasKeyword("Indestructible") && !attacker
|
&& !attacker.hasKeyword("First Strike")) {
|
||||||
.hasKeyword("First Strike"))) {
|
|
||||||
|
|
||||||
if (defenderDamage >= attackerLife) {
|
if (defenderDamage >= attackerLife) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1952,6 +1948,37 @@ public class ComputerUtilCombat {
|
|||||||
return restDamage;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user