diff --git a/.gitattributes b/.gitattributes index 71338dfc37b..7362b551887 100644 --- a/.gitattributes +++ b/.gitattributes @@ -100,6 +100,7 @@ forge-ai/src/main/java/forge/ai/ability/LifeGainAi.java -text forge-ai/src/main/java/forge/ai/ability/LifeLoseAi.java -text forge-ai/src/main/java/forge/ai/ability/LifeSetAi.java -text forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java -text +forge-ai/src/main/java/forge/ai/ability/ManifestAi.java -text forge-ai/src/main/java/forge/ai/ability/MillAi.java -text forge-ai/src/main/java/forge/ai/ability/MustAttackAi.java -text forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java -text diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index c34f95279e6..9f557afc61c 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -78,6 +78,7 @@ public enum SpellApiToAi { apiToClass.put(ApiType.LosesGame, GameLossAi.class); apiToClass.put(ApiType.Mana, ManaEffectAi.class); apiToClass.put(ApiType.ManaReflected, CannotPlayAi.class); + apiToClass.put(ApiType.Manifest, ManifestAi.class); apiToClass.put(ApiType.Mill, MillAi.class); apiToClass.put(ApiType.MoveCounter, CountersMoveAi.class); apiToClass.put(ApiType.MultiplePiles, CannotPlayAi.class); diff --git a/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java b/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java new file mode 100644 index 00000000000..5ef2d5fc45a --- /dev/null +++ b/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java @@ -0,0 +1,122 @@ +package forge.ai.ability; + +import com.google.common.base.Predicate; +import forge.ai.*; +import forge.game.Game; +import forge.game.ability.AbilityUtils; +import forge.game.ability.ApiType; +import forge.game.card.Card; +import forge.game.card.CardCollection; +import forge.game.card.CardLists; +import forge.game.card.CardPredicates; +import forge.game.cost.Cost; +import forge.game.phase.PhaseHandler; +import forge.game.phase.PhaseType; +import forge.game.player.Player; +import forge.game.player.PlayerActionConfirmMode; +import forge.game.spellability.SpellAbility; +import forge.game.spellability.TargetRestrictions; +import forge.game.zone.ZoneType; +import forge.util.MyRandom; + +/** + * Created by friarsol on 1/23/15. + */ +public class ManifestAi extends SpellAbilityAi { + + @Override + protected boolean canPlayAI(Player ai, SpellAbility sa) { + final Cost cost = sa.getPayCosts(); + final Game game = ai.getGame(); + + if (ComputerUtil.preventRunAwayActivations(sa)) { + return false; + } + + if (sa.hasParam("AILogic")) { + if ("Never".equals(sa.getParam("AILogic"))) { + return false; + } + } + + PhaseHandler ph = game.getPhaseHandler(); + // Only manifest things on your turn if sorcery speed, or would pump one of my creatures + if (ph.isPlayerTurn(ai)) { + if (ph.getPhase().isBefore(PhaseType.MAIN2) + && !sa.hasParam("ActivationPhases") + && !ComputerUtil.castSpellInMain1(ai, sa)) { + boolean buff = false; + for (Card c : ai.getCardsIn(ZoneType.Battlefield)) { + if ("Creature".equals(c.getSVar("BuffedBy"))) { + buff = true; + } + } + if (!buff) { + return false; + } + } else if (!SpellAbilityAi.isSorcerySpeed(sa)) { + return false; + } + } + + final Card source = sa.getHostCard(); + + if (cost != null) { + // Sacrifice is the only cost Manifest actually has, but i'll leave these others for now + if (!ComputerUtilCost.checkLifeCost(ai, cost, source, 4, null)) { + return false; + } + + if (!ComputerUtilCost.checkDiscardCost(ai, cost, source)) { + return false; + } + + if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source)) { + return false; + } + + if (!ComputerUtilCost.checkRemoveCounterCost(cost, source)) { + return false; + } + } + + if (source.getSVar("X").equals("Count$xPaid")) { + // Handle either Manifest X cards, or Manifest 1 card and give it X P1P1s + // Set PayX here to maximum value. + int x = ComputerUtilMana.determineLeftoverMana(sa, ai); + source.setSVar("PayX", Integer.toString(x)); + if (x <= 0) { + return false; + } + } + + // Probably should be a little more discerning on playing during OPPs turn + if (SpellAbilityAi.playReusable(ai, sa)) { + return true; + } + if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS)) { + // Add blockers? + return true; + } + if (sa.isAbility()) { + return true; + } + + return MyRandom.getRandom().nextFloat() < .8; + } + + @Override + protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) { + // Manifest doesn't have any "Pay X to manifest X triggers" + + return true; + } + /* (non-Javadoc) + * @see forge.card.ability.SpellAbilityAi#confirmAction(forge.game.player.Player, forge.card.spellability.SpellAbility, forge.game.player.PlayerActionConfirmMode, java.lang.String) + */ + @Override + public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) { + return true; + } + +}