mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 11:48:02 +00:00
- Improved AI handling Mishra's Factory.
This commit is contained in:
@@ -794,9 +794,9 @@ public class AiController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cast 0 mana cost spells first (might be a Mox)
|
// cast 0 mana cost spells first (might be a Mox)
|
||||||
if (a1 == 0 && b1 > 0) {
|
if (a1 == 0 && b1 > 0 && ApiType.Mana != a.getApi()) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (a1 > 0 && b1 == 0) {
|
} else if (a1 > 0 && b1 == 0 && ApiType.Mana != b.getApi()) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,6 +837,9 @@ public class AiController {
|
|||||||
if (ApiType.DestroyAll == sa.getApi()) {
|
if (ApiType.DestroyAll == sa.getApi()) {
|
||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
|
else if (ApiType.Mana == sa.getApi()) {
|
||||||
|
p -= 9;
|
||||||
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1780,7 +1780,7 @@ public class ComputerUtilCombat {
|
|||||||
* </p>
|
* </p>
|
||||||
* @param ai
|
* @param ai
|
||||||
*
|
*
|
||||||
* @param defender
|
* @param blocker
|
||||||
* a {@link forge.game.card.Card} object.
|
* a {@link forge.game.card.Card} object.
|
||||||
* @param attacker
|
* @param attacker
|
||||||
* a {@link forge.game.card.Card} object.
|
* a {@link forge.game.card.Card} object.
|
||||||
@@ -1790,7 +1790,7 @@ public class ComputerUtilCombat {
|
|||||||
* a boolean.
|
* a boolean.
|
||||||
* @return a boolean.
|
* @return a boolean.
|
||||||
*/
|
*/
|
||||||
public static boolean canDestroyBlocker(Player ai, final Card defender, final Card attacker, final Combat combat,
|
public static boolean canDestroyBlocker(Player ai, final Card blocker, final Card attacker, final Combat combat,
|
||||||
final boolean withoutAbilities) {
|
final boolean withoutAbilities) {
|
||||||
final Game game = ai.getGame();
|
final Game game = ai.getGame();
|
||||||
|
|
||||||
@@ -1803,76 +1803,76 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int flankingMagnitude = 0;
|
int flankingMagnitude = 0;
|
||||||
if (attacker.hasKeyword("Flanking") && !defender.hasKeyword("Flanking")) {
|
if (attacker.hasKeyword("Flanking") && !blocker.hasKeyword("Flanking")) {
|
||||||
|
|
||||||
flankingMagnitude = attacker.getAmountOfKeyword("Flanking");
|
flankingMagnitude = attacker.getAmountOfKeyword("Flanking");
|
||||||
|
|
||||||
if (flankingMagnitude >= defender.getNetToughness()) {
|
if (flankingMagnitude >= blocker.getNetToughness()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((flankingMagnitude >= ComputerUtilCombat.getDamageToKill(defender)) && !defender.hasKeyword("Indestructible")) {
|
if ((flankingMagnitude >= ComputerUtilCombat.getDamageToKill(blocker)) && !blocker.hasKeyword("Indestructible")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // flanking
|
} // flanking
|
||||||
|
|
||||||
if (((defender.hasKeyword("Indestructible") || (ComputerUtil.canRegenerate(ai, defender) && !withoutAbilities)) && !(attacker
|
if (((blocker.hasKeyword("Indestructible") || (ComputerUtil.canRegenerate(ai, blocker) && !withoutAbilities)) && !(attacker
|
||||||
.hasKeyword("Wither") || attacker.hasKeyword("Infect")))
|
.hasKeyword("Wither") || attacker.hasKeyword("Infect")))
|
||||||
|| (defender.hasKeyword("Persist") && !defender.canReceiveCounters(CounterType.M1M1) && (defender
|
|| (blocker.hasKeyword("Persist") && !blocker.canReceiveCounters(CounterType.M1M1) && (blocker
|
||||||
.getCounters(CounterType.M1M1) == 0))
|
.getCounters(CounterType.M1M1) == 0))
|
||||||
|| (defender.hasKeyword("Undying") && !defender.canReceiveCounters(CounterType.P1P1) && (defender
|
|| (blocker.hasKeyword("Undying") && !blocker.canReceiveCounters(CounterType.P1P1) && (blocker
|
||||||
.getCounters(CounterType.P1P1) == 0))) {
|
.getCounters(CounterType.P1P1) == 0))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkDestroyBlockerTrigger(attacker, defender) && !defender.hasKeyword("Indestructible")) {
|
if (checkDestroyBlockerTrigger(attacker, blocker) && !blocker.hasKeyword("Indestructible")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defender.isEquipped()) {
|
if (blocker.isEquipped()) {
|
||||||
for (Card equipment : defender.getEquippedBy(false)) {
|
for (Card equipment : blocker.getEquippedBy(false)) {
|
||||||
if (equipment.getName().equals("Godsend")) {
|
if (equipment.getName().equals("Godsend")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int defenderDamage = defender.getNetPower()
|
int defenderDamage = blocker.getNetPower()
|
||||||
+ ComputerUtilCombat.predictPowerBonusOfBlocker(attacker, defender, withoutAbilities);
|
+ ComputerUtilCombat.predictPowerBonusOfBlocker(attacker, blocker, withoutAbilities);
|
||||||
int attackerDamage = attacker.getNetPower()
|
int attackerDamage = attacker.getNetPower()
|
||||||
+ ComputerUtilCombat.predictPowerBonusOfAttacker(attacker, defender, combat, withoutAbilities);
|
+ ComputerUtilCombat.predictPowerBonusOfAttacker(attacker, blocker, combat, withoutAbilities);
|
||||||
if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.toughnessAssignsDamage)) {
|
if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.toughnessAssignsDamage)) {
|
||||||
defenderDamage = defender.getNetToughness()
|
defenderDamage = blocker.getNetToughness()
|
||||||
+ ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, defender, withoutAbilities);
|
+ ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
|
||||||
attackerDamage = attacker.getNetToughness()
|
attackerDamage = attacker.getNetToughness()
|
||||||
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, defender, combat, withoutAbilities);
|
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
int possibleDefenderPrevention = 0;
|
int possibleDefenderPrevention = 0;
|
||||||
int possibleAttackerPrevention = 0;
|
int possibleAttackerPrevention = 0;
|
||||||
if (!withoutAbilities) {
|
if (!withoutAbilities) {
|
||||||
possibleDefenderPrevention = ComputerUtil.possibleDamagePrevention(defender);
|
possibleDefenderPrevention = ComputerUtil.possibleDamagePrevention(blocker);
|
||||||
possibleAttackerPrevention = ComputerUtil.possibleDamagePrevention(attacker);
|
possibleAttackerPrevention = ComputerUtil.possibleDamagePrevention(attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
// consider Damage Prevention/Replacement
|
// consider Damage Prevention/Replacement
|
||||||
defenderDamage = predictDamageTo(attacker, defenderDamage, possibleAttackerPrevention, defender, true);
|
defenderDamage = predictDamageTo(attacker, defenderDamage, possibleAttackerPrevention, blocker, true);
|
||||||
attackerDamage = predictDamageTo(defender, attackerDamage, possibleDefenderPrevention, attacker, true);
|
attackerDamage = predictDamageTo(blocker, attackerDamage, possibleDefenderPrevention, attacker, true);
|
||||||
|
|
||||||
if (combat != null) {
|
if (combat != null) {
|
||||||
for (Card atkr : combat.getAttackersBlockedBy(defender)) {
|
for (Card atkr : combat.getAttackersBlockedBy(blocker)) {
|
||||||
if (!atkr.equals(attacker)) {
|
if (!atkr.equals(attacker)) {
|
||||||
attackerDamage += predictDamageTo(defender, atkr.getNetCombatDamage(), 0, atkr, true);
|
attackerDamage += predictDamageTo(blocker, atkr.getNetCombatDamage(), 0, atkr, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final int defenderLife = ComputerUtilCombat.getDamageToKill(defender)
|
final int defenderLife = ComputerUtilCombat.getDamageToKill(blocker)
|
||||||
+ ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, defender, withoutAbilities);
|
+ ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
|
||||||
final int attackerLife = ComputerUtilCombat.getDamageToKill(attacker)
|
final int attackerLife = ComputerUtilCombat.getDamageToKill(attacker)
|
||||||
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, defender, combat, withoutAbilities);
|
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities);
|
||||||
|
|
||||||
if (attacker.hasKeyword("Double Strike")) {
|
if (attacker.hasKeyword("Double Strike")) {
|
||||||
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities, combat) || defender.hasSVar("DestroyWhenDamaged"))) {
|
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities, combat) || blocker.hasSVar("DestroyWhenDamaged"))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (attackerDamage >= defenderLife) {
|
if (attackerDamage >= defenderLife) {
|
||||||
@@ -1881,11 +1881,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, combat) && !attacker.hasKeyword("Indestructible")) {
|
if (dealsFirstStrikeDamage(blocker, withoutAbilities, combat) && !attacker.hasKeyword("Indestructible")) {
|
||||||
if (defenderDamage >= attackerLife) {
|
if (defenderDamage >= attackerLife) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities, combat) || attacker.hasSVar("DestroyWhenDamaged"))) {
|
if (defenderDamage > 0 && (hasKeyword(blocker, "Deathtouch", withoutAbilities, combat) || attacker.hasSVar("DestroyWhenDamaged"))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1896,18 +1896,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, combat) && !attacker.hasKeyword("Indestructible")
|
if (dealsFirstStrikeDamage(blocker, withoutAbilities, combat) && !attacker.hasKeyword("Indestructible")
|
||||||
&& !dealsFirstStrikeDamage(attacker, withoutAbilities, combat)) {
|
&& !dealsFirstStrikeDamage(attacker, withoutAbilities, combat)) {
|
||||||
|
|
||||||
if (defenderDamage >= attackerLife) {
|
if (defenderDamage >= attackerLife) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (defenderDamage > 0 && (hasKeyword(defender, "Deathtouch", withoutAbilities, combat) || attacker.hasSVar("DestroyWhenDamaged"))) {
|
if (defenderDamage > 0 && (hasKeyword(blocker, "Deathtouch", withoutAbilities, combat) || attacker.hasSVar("DestroyWhenDamaged"))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities, combat) || defender.hasSVar("DestroyWhenDamaged"))) {
|
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities, combat) || blocker.hasSVar("DestroyWhenDamaged"))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ public class AnimateAi extends SpellAbilityAi {
|
|||||||
boolean givesHaste = sa.hasParam("Keywords") && sa.getParam("Keywords").contains("Haste");
|
boolean givesHaste = sa.hasParam("Keywords") && sa.getParam("Keywords").contains("Haste");
|
||||||
for (final Card c : defined) {
|
for (final Card c : defined) {
|
||||||
bFlag |= !c.isCreature() && !c.isTapped()
|
bFlag |= !c.isCreature() && !c.isTapped()
|
||||||
&& (c.getTurnInZone() != game.getPhaseHandler().getTurn() || givesHaste)
|
&& (c.getTurnInZone() != ph.getTurn() || givesHaste || ph.getPlayerTurn().isOpponentOf(aiPlayer))
|
||||||
&& !c.isEquipping();
|
&& !c.isEquipping();
|
||||||
|
|
||||||
// for creatures that could be improved (like Figure of Destiny)
|
// for creatures that could be improved (like Figure of Destiny)
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ public class PumpAi extends PumpAiBase {
|
|||||||
list.remove(sa.getHostCard());
|
list.remove(sa.getHostCard());
|
||||||
}
|
}
|
||||||
if (game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
if (game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
||||||
&& game.getPhaseHandler().isPlayerTurn(opp)) {
|
&& game.getPhaseHandler().getPlayerTurn().isOpponentOf(ai)) {
|
||||||
list.remove(sa.getHostCard());
|
list.remove(sa.getHostCard());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((c.getNetToughness() + defense) <= 0) {
|
if (c.getNetToughness() + defense <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -754,6 +754,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
|||||||
kws.add(kw);
|
kws.add(kw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pumped.addNewPT(c.getCurrentPower(), c.getCurrentPower(), timestamp);
|
||||||
pumped.addTempPowerBoost(c.getTempPowerBoost() + a);
|
pumped.addTempPowerBoost(c.getTempPowerBoost() + a);
|
||||||
pumped.addTempToughnessBoost(c.getTempToughnessBoost() + d);
|
pumped.addTempToughnessBoost(c.getTempToughnessBoost() + d);
|
||||||
pumped.addChangedCardKeywords(kws, new ArrayList<String>(), false, timestamp);
|
pumped.addChangedCardKeywords(kws, new ArrayList<String>(), false, timestamp);
|
||||||
|
|||||||
Reference in New Issue
Block a user