@Override public Card chooseSingleCard( final Player aiChoser, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer) { if ("NeedsPrevention".equals(sa.getParam("AILogic"))) { final Player ai = sa.getActivatingPlayer(); final Game game = ai.getGame(); if (!game.getStack().isEmpty()) { Card choseCard = chooseCardOnStack(sa, ai, game); if (choseCard != null) { return choseCard; } } final Combat combat = game.getCombat(); List<Card> permanentSources = CardLists.filter( options, new Predicate<Card>() { @Override public boolean apply(final Card c) { if (c == null || c.getZone() == null || c.getZone().getZoneType() != ZoneType.Battlefield || combat == null || !combat.isAttacking(c, ai) || !combat.isUnblocked(c)) { return false; } return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > 0; } }); return ComputerUtilCard.getBestCreatureAI(permanentSources); } else { return ComputerUtilCard.getBestAI(options); } }
/* (non-Javadoc) * @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility) */ @Override protected boolean canPlayAI(Player ai, final SpellAbility sa) { Card object1 = null; Card object2 = null; final Card source = sa.getHostCard(); final String type = sa.getParam("Type"); if (sa.hasParam("Object")) { object1 = AbilityUtils.getDefinedCards(source, sa.getParam("Object"), sa).get(0); } else { object1 = source; } final ZoneType zone1 = sa.hasParam("Zone1") ? ZoneType.smartValueOf(sa.getParam("Zone1")) : ZoneType.Battlefield; final ZoneType zone2 = sa.hasParam("Zone2") ? ZoneType.smartValueOf(sa.getParam("Zone2")) : ZoneType.Hand; CardCollection list = new CardCollection(ai.getCardsIn(zone2)); if (type != null) { list = CardLists.getValidCards(list, type, ai, source); } object2 = ComputerUtilCard.getBestAI(list); if (object1 == null || object2 == null || !object1.isInZone(zone1) || !object1.getOwner().equals(ai)) { return false; } if (type.equals("Aura")) { Card c = object1.getEnchantingCard(); if (!c.canBeEnchantedBy(object2)) { return false; } } if (object2.getCMC() > object1.getCMC()) { return MyRandom.getRandom().nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); } return false; }
private boolean pumpTgtAI( final Player ai, final SpellAbility sa, final int defense, final int attack, final boolean mandatory) { final List<String> keywords = sa.hasParam("KW") ? Arrays.asList(sa.getParam("KW").split(" & ")) : new ArrayList<String>(); final Game game = ai.getGame(); final Card source = sa.getHostCard(); if (!mandatory && !sa.isTrigger() && game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS) && !(sa.isCurse() && defense < 0) && !this.containsNonCombatKeyword(keywords) && !sa.hasParam("UntilYourNextTurn")) { return false; } final Player opp = ai.getOpponent(); final TargetRestrictions tgt = sa.getTargetRestrictions(); sa.resetTargets(); if (sa.hasParam("TargetingPlayer") && sa.getActivatingPlayer().equals(ai) && !sa.isTrigger()) { Player targetingPlayer = AbilityUtils.getDefinedPlayers(source, sa.getParam("TargetingPlayer"), sa).get(0); sa.setTargetingPlayer(targetingPlayer); return targetingPlayer.getController().chooseTargetsFor(sa); } List<Card> list = new ArrayList<Card>(); if (sa.hasParam("AILogic")) { if (sa.getParam("AILogic").equals("HighestPower")) { list = CardLists.getValidCards( CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.CREATURES), tgt.getValidTgts(), ai, source); list = CardLists.getTargetableCards(list, sa); CardLists.sortByPowerDesc(list); if (!list.isEmpty()) { sa.getTargets().add(list.get(0)); return true; } else { return false; } } if (sa.getParam("AILogic").equals("Fight") || sa.getParam("AILogic").equals("PowerDmg")) { final AbilitySub tgtFight = sa.getSubAbility(); List<Card> aiCreatures = ai.getCreaturesInPlay(); aiCreatures = CardLists.getTargetableCards(aiCreatures, sa); aiCreatures = ComputerUtil.getSafeTargets(ai, sa, aiCreatures); ComputerUtilCard.sortByEvaluateCreature(aiCreatures); // sort is suboptimal due to conflicting needs depending on game state: // -deathtouch for deal damage // -max power for damage to player // -survivability for generic "fight" // -no support for "heroic" List<Card> humCreatures = ai.getOpponent().getCreaturesInPlay(); humCreatures = CardLists.getTargetableCards(humCreatures, tgtFight); ComputerUtilCard.sortByEvaluateCreature(humCreatures); if (humCreatures.isEmpty() || aiCreatures.isEmpty()) { return false; } int buffedAtk = attack, buffedDef = defense; for (Card humanCreature : humCreatures) { for (Card aiCreature : aiCreatures) { if (sa.isSpell()) { // heroic triggers adding counters for (Trigger t : aiCreature.getTriggers()) { if (t.getMode() == TriggerType.SpellCast) { final Map<String, String> params = t.getMapParams(); if ("Card.Self".equals(params.get("TargetsValid")) && "You".equals(params.get("ValidActivatingPlayer")) && params.containsKey("Execute")) { SpellAbility heroic = AbilityFactory.getAbility( aiCreature.getSVar(params.get("Execute")), aiCreature); if ("Self".equals(heroic.getParam("Defined")) && "P1P1".equals(heroic.getParam("CounterType"))) { int amount = AbilityUtils.calculateAmount( aiCreature, heroic.getParam("CounterNum"), heroic); buffedAtk += amount; buffedDef += amount; } break; } } } } if (sa.getParam("AILogic").equals("PowerDmg")) { if (FightAi.canKill(aiCreature, humanCreature, buffedAtk)) { sa.getTargets().add(aiCreature); tgtFight.getTargets().add(humanCreature); return true; } } else { if (FightAi.shouldFight(aiCreature, humanCreature, buffedAtk, buffedDef)) { sa.getTargets().add(aiCreature); tgtFight.getTargets().add(humanCreature); return true; } } } } } return false; } else if (sa.isCurse()) { if (sa.canTarget(opp)) { sa.getTargets().add(opp); return true; } list = this.getCurseCreatures(ai, sa, defense, attack, keywords); } else { if (!tgt.canTgtCreature()) { ZoneType zone = tgt.getZone().get(0); list = game.getCardsIn(zone); } else { list = this.getPumpCreatures(ai, sa, defense, attack, keywords); } if (sa.canTarget(ai)) { sa.getTargets().add(ai); return true; } } list = CardLists.getValidCards(list, tgt.getValidTgts(), ai, source); if (game.getStack().isEmpty()) { // If the cost is tapping, don't activate before declare // attack/block if (sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()) { if (game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) && game.getPhaseHandler().isPlayerTurn(ai)) { list.remove(sa.getHostCard()); } if (game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS) && game.getPhaseHandler().isPlayerTurn(opp)) { list.remove(sa.getHostCard()); } } } if (list.isEmpty()) { return mandatory && this.pumpMandatoryTarget(ai, sa, mandatory); } if (!sa.isCurse()) { // Don't target cards that will die. list = ComputerUtil.getSafeTargets(ai, sa, list); } while (sa.getTargets().getNumTargeted() < tgt.getMaxTargets(source, sa)) { Card t = null; // boolean goodt = false; if (list.isEmpty()) { if ((sa.getTargets().getNumTargeted() < tgt.getMinTargets(source, sa)) || (sa.getTargets().getNumTargeted() == 0)) { if (mandatory) { return this.pumpMandatoryTarget(ai, sa, mandatory); } sa.resetTargets(); return false; } else { // TODO is this good enough? for up to amounts? break; } } t = ComputerUtilCard.getBestAI(list); // option to hold removal instead only applies for single targeted removal if (!sa.isTrigger() && tgt.getMaxTargets(source, sa) == 1 && sa.isCurse()) { if (!ComputerUtilCard.useRemovalNow(sa, t, -defense, ZoneType.Graveyard)) { return false; } } sa.getTargets().add(t); list.remove(t); } return true; } // pumpTgtAI()