Logic for evaluating fight effects @param ai controlling player @param sa host SpellAbility @param toughness bonus to toughness @param power bonus to power @return true if fight effect should be played, false otherwise
(final Player ai, final SpellAbility sa, int power, int toughness)
| 181 | * @return true if fight effect should be played, false otherwise |
| 182 | */ |
| 183 | public static AiAbilityDecision canFight(final Player ai, final SpellAbility sa, int power, int toughness) { |
| 184 | final Card source = sa.getHostCard(); |
| 185 | final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa); |
| 186 | AbilitySub tgtFight = sa.getSubAbility(); |
| 187 | while (tgtFight != null && tgtFight.getApi() != ApiType.Fight && tgtFight.getApi() != ApiType.DealDamage && tgtFight.getApi() != ApiType.EachDamage) { |
| 188 | // Search for the Fight/DealDamage subability (matters e.g. for Ent's Fury where the Fight SA is not an immediate child of Pump) |
| 189 | tgtFight = tgtFight.getSubAbility(); |
| 190 | } |
| 191 | if (tgtFight == null) { |
| 192 | System.out.println("Warning: couldn't find a Fight/DealDamage subability from FightAi.canFightAi for card " + source.toString()); |
| 193 | tgtFight = sa.getSubAbility(); // at least avoid a NPE, although this will most likely fail |
| 194 | } |
| 195 | final boolean isChandrasIgnition = "Chandra's Ignition".equals(sourceName); // TODO: generalize this for other "fake Fight" cases that do not target |
| 196 | if ("Savage Punch".equals(sourceName) && !ai.hasFerocious()) { |
| 197 | power = 0; |
| 198 | toughness = 0; |
| 199 | } |
| 200 | // Get sorted creature lists |
| 201 | CardCollection aiCreatures = ai.getCreaturesInPlay(); |
| 202 | CardCollection humCreatures = ai.getOpponents().getCreaturesInPlay(); |
| 203 | if ("Time to Feed".equals(sourceName)) { // flip sa |
| 204 | aiCreatures = CardLists.getTargetableCards(aiCreatures, tgtFight); |
| 205 | aiCreatures = ComputerUtil.getSafeTargets(ai, tgtFight, aiCreatures); |
| 206 | humCreatures = CardLists.getTargetableCards(humCreatures, sa); |
| 207 | } else { |
| 208 | aiCreatures = CardLists.getTargetableCards(aiCreatures, sa); |
| 209 | aiCreatures = ComputerUtil.getSafeTargets(ai, sa, aiCreatures); |
| 210 | humCreatures = CardLists.getTargetableCards(humCreatures, tgtFight); |
| 211 | } |
| 212 | ComputerUtilCard.sortByEvaluateCreature(aiCreatures); |
| 213 | ComputerUtilCard.sortByEvaluateCreature(humCreatures); |
| 214 | if (humCreatures.isEmpty() || aiCreatures.isEmpty()) { |
| 215 | return new AiAbilityDecision(0, AiPlayDecision.MissingNeededCards); |
| 216 | } |
| 217 | // Evaluate creature pairs |
| 218 | for (Card humanCreature : humCreatures) { |
| 219 | for (Card aiCreature : aiCreatures) { |
| 220 | if (source.isSpell()) { // heroic triggers adding counters and prowess |
| 221 | final int bonus = getSpellBonus(aiCreature); |
| 222 | power += bonus; |
| 223 | toughness += bonus; |
| 224 | } |
| 225 | if ("PowerDmg".equals(sa.getParam("AILogic"))) { |
| 226 | if ("2".equals(sa.getParam("TargetMax"))) { |
| 227 | // Band Together, uses up to two targets to deal damage to a single target |
| 228 | // TODO: Generalize this so that other TargetMax values can be properly accounted for |
| 229 | CardCollection aiCreaturesByPower = new CardCollection(aiCreatures); |
| 230 | CardLists.sortByPowerDesc(aiCreaturesByPower); |
| 231 | Card maxPower = aiCreaturesByPower.getFirst(); |
| 232 | if (maxPower != aiCreature) { |
| 233 | power += maxPower.getNetPower(); // potential bonus from adding a second target |
| 234 | } |
| 235 | else if ("2".equals(sa.getParam("TargetMin"))) { |
| 236 | continue; |
| 237 | } |
| 238 | if (canKill(aiCreature, humanCreature, power)) { |
| 239 | sa.getTargets().add(aiCreature); |
| 240 | sa.getTargets().add(maxPower); |
no test coverage detected