private Card chooseCardOnStack(SpellAbility sa, Player ai, Game game) { for (SpellAbilityStackInstance si : game.getStack()) { final Card source = si.getSourceCard(); final SpellAbility abilityOnStack = si.getSpellAbility(true); if (sa.hasParam("Choices") && !abilityOnStack.getHostCard().isValid(sa.getParam("Choices"), ai, sa.getHostCard())) { continue; } final ApiType threatApi = abilityOnStack.getApi(); if (threatApi != ApiType.DealDamage && threatApi != ApiType.DamageAll) { continue; } List<? extends GameObject> objects = getTargets(abilityOnStack); if (!abilityOnStack.usesTargeting() && !abilityOnStack.hasParam("Defined") && abilityOnStack.hasParam("ValidPlayers")) objects = AbilityUtils.getDefinedPlayers( source, abilityOnStack.getParam("ValidPlayers"), abilityOnStack); if (!objects.contains(ai) || abilityOnStack.hasParam("NoPrevention")) { continue; } int dmg = AbilityUtils.calculateAmount(source, abilityOnStack.getParam("NumDmg"), abilityOnStack); if (ComputerUtilCombat.predictDamageTo(ai, dmg, source, false) <= 0) { continue; } return source; } return null; }
/* (non-Javadoc) * @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility) */ @Override protected boolean canPlayAI(final Player ai, SpellAbility sa) { // TODO: AI Support! Currently this is copied from AF ChooseCard. // When implementing AI, I believe AI also needs to be made aware of the damage sources // chosen // to be prevented (e.g. so the AI doesn't attack with a creature that will not deal any // damage // to the player because a CoP was pre-activated on it - unless, of course, there's // another // possible reason to attack with that creature). final Card host = sa.getHostCard(); final Cost abCost = sa.getPayCosts(); final Card source = sa.getHostCard(); if (abCost != null) { // AI currently disabled for these costs if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, null)) { return false; } if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) { return false; } if (!ComputerUtilCost.checkSacrificeCost(ai, abCost, source)) { return false; } if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source)) { return false; } } final TargetRestrictions tgt = sa.getTargetRestrictions(); if (tgt != null) { sa.resetTargets(); if (sa.canTarget(ai.getOpponent())) { sa.getTargets().add(ai.getOpponent()); } else { return false; } } if (sa.hasParam("AILogic")) { final Game game = ai.getGame(); if (sa.getParam("AILogic").equals("NeedsPrevention")) { if (!game.getStack().isEmpty()) { final SpellAbility topStack = game.getStack().peekAbility(); if (sa.hasParam("Choices") && !topStack.getHostCard().isValid(sa.getParam("Choices"), ai, source)) { return false; } final ApiType threatApi = topStack.getApi(); if (threatApi != ApiType.DealDamage && threatApi != ApiType.DamageAll) { return false; } final Card threatSource = topStack.getHostCard(); List<? extends GameObject> objects = getTargets(topStack); if (!topStack.usesTargeting() && topStack.hasParam("ValidPlayers") && !topStack.hasParam("Defined")) { objects = AbilityUtils.getDefinedPlayers( threatSource, topStack.getParam("ValidPlayers"), topStack); } if (!objects.contains(ai) || topStack.hasParam("NoPrevention")) { return false; } int dmg = AbilityUtils.calculateAmount(threatSource, topStack.getParam("NumDmg"), topStack); if (ComputerUtilCombat.predictDamageTo(ai, dmg, threatSource, false) <= 0) { return false; } return true; } if (game.getPhaseHandler().getPhase() != PhaseType.COMBAT_DECLARE_BLOCKERS) { return false; } CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield); if (sa.hasParam("Choices")) { choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host); } final Combat combat = game.getCombat(); choices = CardLists.filter( choices, new Predicate<Card>() { @Override public boolean apply(final Card c) { if (combat == null || !combat.isAttacking(c, ai) || !combat.isUnblocked(c)) { return false; } return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > 0; } }); if (choices.isEmpty()) { return false; } } } return true; }