diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java index fb3d65475b9..98bd477e405 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java @@ -7,6 +7,7 @@ import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardLists; +import forge.game.card.CounterType; import forge.game.cost.Cost; import forge.game.player.Player; import forge.game.spellability.SpellAbility; @@ -21,27 +22,63 @@ public class DamageAllAi extends SpellAbilityAi { protected boolean canPlayAI(Player ai, SpellAbility sa) { // AI needs to be expanded, since this function can be pretty complex // based on what the expected targets could be - final Random r = MyRandom.getRandom(); - final Cost abCost = sa.getPayCosts(); final Card source = sa.getHostCard(); - String validP = ""; - + // prevent run-away activations - first time will always return true + final Random r = MyRandom.getRandom(); + if (r.nextFloat() > Math.pow(.9, sa.getActivationsThisTurn())) { + return false; + } + // abCost stuff that should probably be centralized... + final Cost abCost = sa.getPayCosts(); + if (abCost != null) { + // AI currently disabled for some costs + if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, null)) { + return false; + } + } + // wait until stack is empty (prevents duplicate kills) + if (!ai.getGame().getStack().isEmpty()) { + return false; + } + + int x = -1; final String damage = sa.getParam("NumDmg"); int dmg = AbilityUtils.calculateAmount(sa.getHostCard(), damage, sa); if (damage.equals("X") && sa.getSVar(damage).equals("Count$Converge")) { dmg = ComputerUtilMana.getConvergeCount(sa, ai); } if (damage.equals("X") && sa.getSVar(damage).equals("Count$xPaid")) { - // Set PayX here to maximum value. - dmg = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(dmg)); + x = ComputerUtilMana.determineLeftoverMana(sa, ai); } - - if (sa.hasParam("ValidPlayers")) { - validP = sa.getParam("ValidPlayers"); + if (damage.equals("ChosenX")) { + x = source.getCounters(CounterType.LOYALTY); } + if (x == -1) { + return evaluateDamageAll(ai, sa, source, dmg) > 0; + } else { + int best = -1, best_x = -1; + for (int i = 0; i < x; i++) { + final int value = evaluateDamageAll(ai, sa, source, i); + if (value > best) { + best = value; + best_x = i; + } + } + if (best_x > 0) { + if (sa.getSVar(damage).equals("Count$xPaid")) { + source.setSVar("PayX", Integer.toString(best_x)); + } + if (damage.equals("ChosenX")) { + source.setSVar("ChosenX", "Number$" + best_x); + } + return true; + } + return false; + } + } + private int evaluateDamageAll(Player ai, SpellAbility sa, final Card source, int dmg) { Player opp = ai.getOpponent(); final CardCollection humanList = getKillableCreatures(sa, opp, dmg); CardCollection computerList = getKillableCreatures(sa, ai, dmg); @@ -53,34 +90,17 @@ public class DamageAllAi extends SpellAbilityAi { computerList.clear(); } - // abCost stuff that should probably be centralized... - if (abCost != null) { - // AI currently disabled for some costs - if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, null)) { - return false; - } - } - + final String validP = sa.hasParam("ValidPlayers") ? sa.getParam("ValidPlayers") : ""; // TODO: if damage is dependant on mana paid, maybe have X be human's max life // Don't kill yourself if (validP.equals("Player") && (ai.getLife() <= ComputerUtilCombat.predictDamageTo(ai, dmg, source, false))) { - return false; - } - - // prevent run-away activations - first time will always return true - if (r.nextFloat() > Math.pow(.9, sa.getActivationsThisTurn())) { - return false; + return -1; } // if we can kill human, do it if ((validP.equals("Player") || validP.contains("Opponent")) && (opp.getLife() <= ComputerUtilCombat.predictDamageTo(opp, dmg, source, false))) { - return true; - } - - // wait until stack is empty (prevents duplicate kills) - if (!ai.getGame().getStack().isEmpty()) { - return false; + return 1; } int minGain = 200; // The minimum gain in destroyed creatures @@ -95,13 +115,8 @@ public class DamageAllAi extends SpellAbilityAi { minGain = 126; // prepare for attack } - // evaluate both lists and pass only if human creatures are more valuable - if ((ComputerUtilCard.evaluateCreatureList(computerList) + minGain) >= ComputerUtilCard - .evaluateCreatureList(humanList)) { - return false; - } - - return true; + return ComputerUtilCard.evaluateCreatureList(humanList) - ComputerUtilCard.evaluateCreatureList(computerList) + - minGain; } @Override diff --git a/forge-ai/src/main/java/forge/ai/ability/DiscardAi.java b/forge-ai/src/main/java/forge/ai/ability/DiscardAi.java index 25a388cfd42..7b7d990a562 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DiscardAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DiscardAi.java @@ -45,6 +45,11 @@ public class DiscardAi extends SpellAbilityAi { } } + + if ("Chandra, Flamecaller".equals(source.getName())) { + final int hand = ai.getCardsIn(ZoneType.Hand).size(); + return MyRandom.getRandom().nextFloat() < (1.0 / (1 + hand)); + } final boolean humanHasHand = ai.getOpponent().getCardsIn(ZoneType.Hand).size() > 0; diff --git a/forge-gui/res/cardsfolder/c/chandra_flamecaller.txt b/forge-gui/res/cardsfolder/c/chandra_flamecaller.txt index 078c247e101..b1f39a4b9bd 100644 --- a/forge-gui/res/cardsfolder/c/chandra_flamecaller.txt +++ b/forge-gui/res/cardsfolder/c/chandra_flamecaller.txt @@ -12,6 +12,6 @@ SVar:DBDraw:DB$ Draw | NumCards$ Y | Defined$ You | SubAbility$ DBCleanup | Spel SVar:Y:Remembered$Amount.Plus.1 A:AB$ DamageAll | Cost$ SubCounter | NumDmg$ ChosenX | References$ X | ValidCards$ Creature | Planeswalker$ True | Ultimate$ True | ValidDescription$ each creature. | SpellDescription$ CARDNAME deals X damage to each creature. SVar:X:XChoice -SVar:PlayMain1:TRUE +SVar:PlayMain1:ALWAYS SVar:Picture:http://www.wizards.com/global/images/magic/general/chandra_flamecaller.jpg Oracle:[+1] Put two 3/1 red Elemental creature tokens with haste onto the battlefield. Exile them at the beginning of the next end step.\n[0] Discard all the cards in your hand, then draw that many cards plus one.\n[-X] Chandra, Flamecaller deals X damage to each creature. \ No newline at end of file