From a08d455312d02513c01b165795b596d1d934c4c4 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Wed, 31 Oct 2012 07:41:23 +0000 Subject: [PATCH] AF: Combat refactored (17800 get!) --- .gitattributes | 9 +- .../card/abilityfactory/AbilityFactory.java | 36 +- .../abilityfactory/AbilityFactoryCombat.java | 1144 ----------------- .../card/abilityfactory/SpellAiLogic.java | 2 + .../forge/card/abilityfactory/ai/FogAi.java | 110 ++ .../card/abilityfactory/ai/MustAttackAi.java | 44 + .../card/abilityfactory/ai/MustBlockAi.java | 109 ++ .../card/abilityfactory/ai/RegenerateAi.java | 3 - .../abilityfactory/ai/RegenerateAllAi.java | 9 +- .../abilityfactory/ai/RemoveFromCombatAi.java | 44 + .../abilityfactory/effects/FogEffect.java | 38 + .../effects/MustAttackEffect.java | 93 ++ .../effects/MustBlockEffect.java | 89 ++ .../effects/RegenerateAllEffect.java | 1 - .../effects/RemoveFromCombatEffect.java | 72 ++ .../java/forge/game/phase/CombatUtil.java | 4 +- .../forge/game/player/ComputerUtilAttack.java | 4 +- src/main/java/forge/game/player/Player.java | 12 + 18 files changed, 635 insertions(+), 1188 deletions(-) delete mode 100644 src/main/java/forge/card/abilityfactory/AbilityFactoryCombat.java create mode 100644 src/main/java/forge/card/abilityfactory/ai/FogAi.java create mode 100644 src/main/java/forge/card/abilityfactory/ai/MustAttackAi.java create mode 100644 src/main/java/forge/card/abilityfactory/ai/MustBlockAi.java create mode 100644 src/main/java/forge/card/abilityfactory/ai/RemoveFromCombatAi.java create mode 100644 src/main/java/forge/card/abilityfactory/effects/FogEffect.java create mode 100644 src/main/java/forge/card/abilityfactory/effects/MustAttackEffect.java create mode 100644 src/main/java/forge/card/abilityfactory/effects/MustBlockEffect.java create mode 100644 src/main/java/forge/card/abilityfactory/effects/RemoveFromCombatEffect.java diff --git a/.gitattributes b/.gitattributes index 0d51c9596e3..6048afb6489 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12466,7 +12466,6 @@ src/main/java/forge/card/abilityfactory/AbilityFactoryCharm.java svneol=native#t src/main/java/forge/card/abilityfactory/AbilityFactoryClash.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/AbilityFactoryCleanup.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/AbilityFactoryClone.java -text -src/main/java/forge/card/abilityfactory/AbilityFactoryCombat.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/AbilityFactoryCopy.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/AbilityFactoryDealDamage.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/AbilityFactoryDelayedTrigger.java svneol=native#text/plain @@ -12511,17 +12510,21 @@ src/main/java/forge/card/abilityfactory/ai/DrainManaAi.java -text src/main/java/forge/card/abilityfactory/ai/DrawAi.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/ai/EffectAi.java -text src/main/java/forge/card/abilityfactory/ai/EndTurnAi.java -text +src/main/java/forge/card/abilityfactory/ai/FogAi.java -text src/main/java/forge/card/abilityfactory/ai/LifeExchangeAi.java -text src/main/java/forge/card/abilityfactory/ai/LifeGainAi.java -text src/main/java/forge/card/abilityfactory/ai/LifeLoseAi.java -text src/main/java/forge/card/abilityfactory/ai/LifeSetAi.java -text src/main/java/forge/card/abilityfactory/ai/MillAi.java -text +src/main/java/forge/card/abilityfactory/ai/MustAttackAi.java -text +src/main/java/forge/card/abilityfactory/ai/MustBlockAi.java -text src/main/java/forge/card/abilityfactory/ai/PlayAi.java -text src/main/java/forge/card/abilityfactory/ai/PoisonAi.java -text src/main/java/forge/card/abilityfactory/ai/ProtectAi.java -text src/main/java/forge/card/abilityfactory/ai/ProtectAllAi.java -text src/main/java/forge/card/abilityfactory/ai/RegenerateAi.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/ai/RegenerateAllAi.java -text +src/main/java/forge/card/abilityfactory/ai/RemoveFromCombatAi.java -text src/main/java/forge/card/abilityfactory/ai/ShuffleAi.java -text src/main/java/forge/card/abilityfactory/ai/TokenAi.java -text src/main/java/forge/card/abilityfactory/effects/AddTurnEffect.java -text @@ -12551,18 +12554,22 @@ src/main/java/forge/card/abilityfactory/effects/DrainManaEffect.java -text src/main/java/forge/card/abilityfactory/effects/DrawEffect.java -text src/main/java/forge/card/abilityfactory/effects/EffectEffect.java -text src/main/java/forge/card/abilityfactory/effects/EndTurnEffect.java -text +src/main/java/forge/card/abilityfactory/effects/FogEffect.java -text src/main/java/forge/card/abilityfactory/effects/HelperAnimate.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/effects/LifeExchangeEffect.java -text src/main/java/forge/card/abilityfactory/effects/LifeGainEffect.java -text src/main/java/forge/card/abilityfactory/effects/LifeLoseEffect.java -text src/main/java/forge/card/abilityfactory/effects/LifeSetEffect.java -text src/main/java/forge/card/abilityfactory/effects/MillEffect.java -text +src/main/java/forge/card/abilityfactory/effects/MustAttackEffect.java -text +src/main/java/forge/card/abilityfactory/effects/MustBlockEffect.java -text src/main/java/forge/card/abilityfactory/effects/PlayEffect.java -text src/main/java/forge/card/abilityfactory/effects/PoisonEffect.java -text src/main/java/forge/card/abilityfactory/effects/ProtectAllEffect.java -text src/main/java/forge/card/abilityfactory/effects/ProtectEffect.java -text src/main/java/forge/card/abilityfactory/effects/RegenerateAllEffect.java -text src/main/java/forge/card/abilityfactory/effects/RegenerateEffect.java -text +src/main/java/forge/card/abilityfactory/effects/RemoveFromCombatEffect.java -text src/main/java/forge/card/abilityfactory/effects/ShuffleEffect.java -text src/main/java/forge/card/abilityfactory/effects/TokenEffect.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/package-info.java svneol=native#text/plain diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactory.java b/src/main/java/forge/card/abilityfactory/AbilityFactory.java index 81ea6f999db..1bb86d66cdc 100644 --- a/src/main/java/forge/card/abilityfactory/AbilityFactory.java +++ b/src/main/java/forge/card/abilityfactory/AbilityFactory.java @@ -729,13 +729,8 @@ public class AbilityFactory { } else if (this.api.equals("Fog")) { - if (this.isAb) { - spellAbility = AbilityFactoryCombat.createAbilityFog(this); - } else if (this.isSp) { - spellAbility = AbilityFactoryCombat.createSpellFog(this); - } else if (this.isDb) { - spellAbility = AbilityFactoryCombat.createDrawbackFog(this); - } + ai = new FogAi(); + se = new FogEffect(); } else if (this.api.equals("GainControl")) { @@ -809,23 +804,13 @@ public class AbilityFactory { } else if (this.api.equals("MustAttack")) { - if (this.isAb) { - spellAbility = AbilityFactoryCombat.createAbilityMustAttack(this); - } else if (this.isSp) { - spellAbility = AbilityFactoryCombat.createSpellMustAttack(this); - } else if (this.isDb) { - spellAbility = AbilityFactoryCombat.createDrawbackMustAttack(this); - } + ai = new MustAttackAi(); + se = new MustAttackEffect(); } else if (this.api.equals("MustBlock")) { - if (this.isAb) { - spellAbility = AbilityFactoryCombat.createAbilityMustBlock(this); - } else if (this.isSp) { - spellAbility = AbilityFactoryCombat.createSpellMustBlock(this); - } else if (this.isDb) { - spellAbility = AbilityFactoryCombat.createDrawbackMustBlock(this); - } + ai = new MustBlockAi(); + se = new MustBlockEffect(); } else if (this.api.equals("NameCard")) { @@ -943,13 +928,8 @@ public class AbilityFactory { } else if (this.api.equals("RemoveFromCombat")) { - if (this.isAb) { - spellAbility = AbilityFactoryCombat.createAbilityRemoveFromCombat(this); - } else if (this.isSp) { - spellAbility = AbilityFactoryCombat.createSpellRemoveFromCombat(this); - } else if (this.isDb) { - spellAbility = AbilityFactoryCombat.createDrawbackRemoveFromCombat(this); - } + ai = new RemoveFromCombatAi(); + se = new RemoveFromCombatEffect(); } else if (this.api.equals("Repeat")) { diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryCombat.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryCombat.java deleted file mode 100644 index 159a9a44fa1..00000000000 --- a/src/main/java/forge/card/abilityfactory/AbilityFactoryCombat.java +++ /dev/null @@ -1,1144 +0,0 @@ -/* - * Forge: Play Magic: the Gathering. - * Copyright (C) 2011 Forge Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package forge.card.abilityfactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import com.google.common.base.Predicate; - -import forge.Card; - -import forge.CardLists; -import forge.CardPredicates; -import forge.GameEntity; -import forge.Singletons; -import forge.card.cardfactory.CardFactoryUtil; -import forge.card.spellability.AbilityActivated; -import forge.card.spellability.AbilitySub; -import forge.card.spellability.Spell; -import forge.card.spellability.SpellAbility; -import forge.card.spellability.Target; -import forge.card.cost.Cost; -import forge.game.phase.CombatUtil; -import forge.game.phase.PhaseType; -import forge.game.player.ComputerUtil; -import forge.game.player.Player; -import forge.game.zone.ZoneType; - - -/** - *

- * AbilityFactory_Combat class. - *

- * - * @author Forge - * @version $Id$ - */ -public final class AbilityFactoryCombat { - - private AbilityFactoryCombat() { - throw new AssertionError(); - } - - // ************************************************************** - // ****************************** FOG ************************** - // ************************************************************** - - /** - *

- * createAbilityFog. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - */ - public static SpellAbility createAbilityFog(final AbilityFactory af) { - class AbilityFog extends AbilityActivated { - public AbilityFog(final Card ca, final Cost co, final Target t) { - super(ca, co, t); - } - - @Override - public AbilityActivated getCopy() { - AbilityActivated res = new AbilityFog(getSourceCard(), - getPayCosts(), getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = -1933592438783630254L; - - @Override - public String getStackDescription() { - // when getStackDesc is called, just build exactly what is - // happening - return AbilityFactoryCombat.fogStackDescription(af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryCombat.fogCanPlayAI(getActivatingPlayer(), af, this); - } - - @Override - public void resolve() { - AbilityFactoryCombat.fogResolve(af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryCombat.fogDoTriggerAI(getActivatingPlayer(), af, this, mandatory); - } - } - final SpellAbility abFog = new AbilityFog(af.getHostCard(), af.getAbCost(), af.getAbTgt()); - - return abFog; - } - - /** - *

- * createSpellFog. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - */ - public static SpellAbility createSpellFog(final AbilityFactory af) { - final SpellAbility spFog = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) { - private static final long serialVersionUID = -5141246507533353605L; - - @Override - public String getStackDescription() { - // when getStackDesc is called, just build exactly what is - // happening - return AbilityFactoryCombat.fogStackDescription(af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryCombat.fogCanPlayAI(getActivatingPlayer(), af, this); - } - - @Override - public void resolve() { - AbilityFactoryCombat.fogResolve(af, this); - } - - }; - return spFog; - } - - /** - *

- * createDrawbackFog. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - */ - public static SpellAbility createDrawbackFog(final AbilityFactory af) { - class DrawbackFog extends AbilitySub { - public DrawbackFog(final Card ca, final Target t) { - super(ca, t); - } - - @Override - public AbilitySub getCopy() { - AbilitySub res = new DrawbackFog(getSourceCard(), - getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = -5141246507533353605L; - - @Override - public void resolve() { - AbilityFactoryCombat.fogResolve(af, this); - } - - @Override - public boolean chkAIDrawback() { - return AbilityFactoryCombat.fogPlayDrawbackAI(af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryCombat.fogCanPlayAI(getActivatingPlayer(), af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryCombat.fogDoTriggerAI(getActivatingPlayer(), af, this, mandatory); - } - } - final SpellAbility dbFog = new DrawbackFog(af.getHostCard(), af.getAbTgt()); - - return dbFog; - } - - /** - *

- * fogStackDescription. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @return a {@link java.lang.String} object. - */ - public static String fogStackDescription(final AbilityFactory af, final SpellAbility sa) { - final StringBuilder sb = new StringBuilder(); - - if (!(sa instanceof AbilitySub)) { - sb.append(sa.getSourceCard().getName()).append(" - "); - } else { - sb.append(" "); - } - - sb.append(sa.getSourceCard().getController()); - sb.append(" prevents all combat damage this turn."); - - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - sb.append(abSub.getStackDescription()); - } - - return sb.toString(); - } - - /** - *

- * fogCanPlayAI. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @return a boolean. - */ - public static boolean fogCanPlayAI(final Player ai, final AbilityFactory af, final SpellAbility sa) { - // AI should only activate this during Human's Declare Blockers phase - if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) { - return false; - } - if (!Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { - return false; - } - - // Only cast when Stack is empty, so Human uses spells/abilities first - if (Singletons.getModel().getGame().getStack().size() != 0) { - return false; - } - - // Don't cast it, if the effect is already in place - if (Singletons.getModel().getGame().getPhaseHandler().isPreventCombatDamageThisTurn()) { - return false; - } - - final AbilitySub subAb = sa.getSubAbility(); - if (subAb != null) { - if (!subAb.chkAIDrawback()) { - return false; - } - } - - // Cast it if life is in danger - return CombatUtil.lifeInDanger(ai, Singletons.getModel().getGame().getCombat()); - } - - /** - *

- * fogPlayDrawbackAI. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @return a boolean. - */ - public static boolean fogPlayDrawbackAI(final AbilityFactory af, final SpellAbility sa) { - // AI should only activate this during Human's turn - boolean chance; - if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer().getOpponent())) { - chance = Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_FIRST_STRIKE_DAMAGE); - } else { - chance = Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE); - } - - final AbilitySub subAb = sa.getSubAbility(); - if (subAb != null) { - chance &= subAb.chkAIDrawback(); - } - - return chance; - } - - /** - *

- * fogDoTriggerAI. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param mandatory - * a boolean. - * @return a boolean. - */ - public static boolean fogDoTriggerAI(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) { - // If there is a cost payment it's usually not mandatory - if (!ComputerUtil.canPayCost(sa, ai) && !mandatory) { - return false; - } - - boolean chance; - if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer().getOpponent())) { - chance = Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_FIRST_STRIKE_DAMAGE); - } else { - chance = Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE); - } - - // check SubAbilities DoTrigger? - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - return chance && abSub.doTrigger(mandatory); - } - - return chance; - } - - /** - *

- * fogResolve. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - */ - public static void fogResolve(final AbilityFactory af, final SpellAbility sa) { - - // Expand Fog keyword here depending on what we need out of it. - Singletons.getModel().getGame().getPhaseHandler().setPreventCombatDamageThisTurn(true); - } - - // ************************************************************** - // *********************** MUSTATTACK *************************** - // ************************************************************** - - // AB$ MustAttack | Cost$ R T | ValidTgts$ Opponent | TgtPrompt$ Select - // target opponent | Defender$ Self | SpellDescription$ ... - - /** - *

- * createAbilityMustAttack. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - * - * @since 1.1.01 - */ - public static SpellAbility createAbilityMustAttack(final AbilityFactory af) { - class AbilityMustAttack extends AbilityActivated { - public AbilityMustAttack(final Card ca, final Cost co, final Target t) { - super(ca, co, t); - } - - @Override - public AbilityActivated getCopy() { - AbilityActivated res = new AbilityMustAttack(getSourceCard(), - getPayCosts(), getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = 4559154732470225755L; - - @Override - public String getStackDescription() { - return AbilityFactoryCombat.mustAttackStackDescription(af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryCombat.mustAttackCanPlayAI(af, this); - } - - @Override - public void resolve() { - AbilityFactoryCombat.mustAttackResolve(af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryCombat.mustAttackDoTriggerAI(getActivatingPlayer(), af, this, mandatory); - } - } - final SpellAbility abMustAttack = new AbilityMustAttack(af.getHostCard(), af.getAbCost(), af.getAbTgt()); - - return abMustAttack; - } - - /** - *

- * createSpellMustAttack. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - */ - public static SpellAbility createSpellMustAttack(final AbilityFactory af) { - final SpellAbility spMustAttack = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) { - private static final long serialVersionUID = 4103945257601008403L; - - @Override - public String getStackDescription() { - return AbilityFactoryCombat.mustAttackStackDescription(af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryCombat.mustAttackCanPlayAI(af, this); - } - - @Override - public void resolve() { - AbilityFactoryCombat.mustAttackResolve(af, this); - } - - }; - return spMustAttack; - } - - /** - *

- * createDrawbackMustAttack. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - */ - public static SpellAbility createDrawbackMustAttack(final AbilityFactory af) { - class DrawbackMustAttack extends AbilitySub { - public DrawbackMustAttack(final Card ca, final Target t) { - super(ca, t); - } - - @Override - public AbilitySub getCopy() { - AbilitySub res = new DrawbackMustAttack(getSourceCard(), - getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = 1294949210616598158L; - - @Override - public void resolve() { - AbilityFactoryCombat.mustAttackResolve(af, this); - } - - @Override - public boolean chkAIDrawback() { - return AbilityFactoryCombat.mustAttackPlayDrawbackAI(af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryCombat.mustAttackDoTriggerAI(getActivatingPlayer(), af, this, mandatory); - } - } - final SpellAbility dbMustAttack = new DrawbackMustAttack(af.getHostCard(), af.getAbTgt()); - - return dbMustAttack; - } - - private static String mustAttackStackDescription(final AbilityFactory af, final SpellAbility sa) { - final HashMap params = af.getMapParams(); - final Card host = sa.getSourceCard(); - final StringBuilder sb = new StringBuilder(); - - if (sa instanceof AbilitySub) { - sb.append(" "); - } else { - sb.append(sa.getSourceCard()).append(" - "); - } - - // end standard pre- - - ArrayList tgtPlayers; - - final Target tgt = sa.getTarget(); - if (tgt != null) { - tgtPlayers = tgt.getTargetPlayers(); - } else { - tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa); - } - - String defender = null; - if (params.get("Defender").equals("Self")) { - defender = host.toString(); - } else { - // TODO - if more needs arise in the future - } - - for (final Player player : tgtPlayers) { - sb.append("Creatures ").append(player).append(" controls attack "); - sb.append(defender).append(" during his or her next turn."); - } - - // begin standard post- - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - sb.append(abSub.getStackDescription()); - } - - return sb.toString(); - } - - private static boolean mustAttackCanPlayAI(final AbilityFactory af, final SpellAbility sa) { - // disabled for the AI for now. Only for Gideon Jura at this time. - return false; - } - - private static boolean mustAttackPlayDrawbackAI(final AbilityFactory af, final SpellAbility sa) { - // AI should only activate this during Human's turn - boolean chance; - - // TODO - implement AI - chance = false; - - final AbilitySub subAb = sa.getSubAbility(); - if (subAb != null) { - chance &= subAb.chkAIDrawback(); - } - - return chance; - } - - private static boolean mustAttackDoTriggerAI(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) { - // If there is a cost payment it's usually not mandatory - if (!ComputerUtil.canPayCost(sa, ai) && !mandatory) { - return false; - } - - boolean chance; - - // TODO - implement AI - chance = false; - - // check SubAbilities DoTrigger? - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - return chance && abSub.doTrigger(mandatory); - } - - return chance; - } - - private static void mustAttackResolve(final AbilityFactory af, final SpellAbility sa) { - final HashMap params = af.getMapParams(); - - ArrayList tgtPlayers; - - final Target tgt = sa.getTarget(); - if ((tgt != null) && !params.containsKey("Defined")) { - tgtPlayers = tgt.getTargetPlayers(); - } else { - tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa); - } - - for (final Player p : tgtPlayers) { - if ((tgt == null) || p.canBeTargetedBy(sa)) { - GameEntity entity; - if (params.get("Defender").equals("Self")) { - entity = sa.getSourceCard(); - } else { - entity = p.getOpponent(); - } - // System.out.println("Setting mustAttackEntity to: "+entity); - p.setMustAttackEntity(entity); - } - } - - } // mustAttackResolve() - - // ************************************************************** - // ********************* RemoveFromCombat *********************** - // ************************************************************** - - /** - *

- * createAbilityRemoveFromCombat. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - * - * @since 1.1.6 - */ - public static SpellAbility createAbilityRemoveFromCombat(final AbilityFactory af) { - class AbilityRemoveFromCombat extends AbilityActivated { - public AbilityRemoveFromCombat(final Card ca, final Cost co, final Target t) { - super(ca, co, t); - } - - @Override - public AbilityActivated getCopy() { - AbilityActivated res = new AbilityRemoveFromCombat(getSourceCard(), - getPayCosts(), getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = -2472319390656924874L; - - @Override - public String getStackDescription() { - return AbilityFactoryCombat.removeFromCombatStackDescription(af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryCombat.removeFromCombatCanPlayAI(af, this); - } - - @Override - public void resolve() { - AbilityFactoryCombat.removeFromCombatResolve(af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryCombat.removeFromCombatDoTriggerAI(getActivatingPlayer(), af, this, mandatory); - } - } - final SpellAbility abRemCombat = new AbilityRemoveFromCombat(af.getHostCard(), af.getAbCost(), af.getAbTgt()); - - return abRemCombat; - } - - /** - *

- * createSpellRemoveFeomCombat. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - */ - public static SpellAbility createSpellRemoveFromCombat(final AbilityFactory af) { - final SpellAbility spRemCombat = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) { - private static final long serialVersionUID = 4086879057558760897L; - - @Override - public String getStackDescription() { - return AbilityFactoryCombat.removeFromCombatStackDescription(af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryCombat.removeFromCombatCanPlayAI(af, this); - } - - @Override - public void resolve() { - AbilityFactoryCombat.removeFromCombatResolve(af, this); - } - - }; - return spRemCombat; - } - - /** - *

- * createDrawbackRemoveFromCombat. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - */ - public static SpellAbility createDrawbackRemoveFromCombat(final AbilityFactory af) { - class DrawbackRemoveFromCombat extends AbilitySub { - public DrawbackRemoveFromCombat(final Card ca, final Target t) { - super(ca, t); - } - - @Override - public AbilitySub getCopy() { - AbilitySub res = new DrawbackRemoveFromCombat(getSourceCard(), - getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = 5080737903616292224L; - - @Override - public void resolve() { - AbilityFactoryCombat.removeFromCombatResolve(af, this); - } - - @Override - public boolean chkAIDrawback() { - return AbilityFactoryCombat.removeFromCombatPlayDrawbackAI(af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryCombat.removeFromCombatDoTriggerAI(getActivatingPlayer(), af, this, mandatory); - } - } - final SpellAbility dbRemCombat = new DrawbackRemoveFromCombat(af.getHostCard(), af.getAbTgt()); - - return dbRemCombat; - } - - private static String removeFromCombatStackDescription(final AbilityFactory af, final SpellAbility sa) { - final HashMap params = af.getMapParams(); - final StringBuilder sb = new StringBuilder(); - - if (sa instanceof AbilitySub) { - sb.append(" "); - } else { - sb.append(sa.getSourceCard()).append(" - "); - } - - // end standard pre- - - ArrayList tgtCards; - - final Target tgt = sa.getTarget(); - if (tgt != null) { - tgtCards = tgt.getTargetCards(); - } else { - tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa); - } - - sb.append("Remove "); - - for (final Card c : tgtCards) { - sb.append(c); - } - - sb.append(" from combat."); - - // begin standard post- - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - sb.append(abSub.getStackDescription()); - } - - return sb.toString(); - } - - private static boolean removeFromCombatCanPlayAI(final AbilityFactory af, final SpellAbility sa) { - // disabled for the AI for now. Only for Gideon Jura at this time. - return false; - } - - private static boolean removeFromCombatPlayDrawbackAI(final AbilityFactory af, final SpellAbility sa) { - // AI should only activate this during Human's turn - boolean chance; - - // TODO - implement AI - chance = false; - - final AbilitySub subAb = sa.getSubAbility(); - if (subAb != null) { - chance &= subAb.chkAIDrawback(); - } - - return chance; - } - - private static boolean removeFromCombatDoTriggerAI(final Player ai, final AbilityFactory af, final SpellAbility sa, - final boolean mandatory) { - // If there is a cost payment it's usually not mandatory - if (!ComputerUtil.canPayCost(sa, ai) && !mandatory) { - return false; - } - - boolean chance; - - // TODO - implement AI - chance = false; - - // check SubAbilities DoTrigger? - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - return chance && abSub.doTrigger(mandatory); - } - - return chance; - } - - private static void removeFromCombatResolve(final AbilityFactory af, final SpellAbility sa) { - final HashMap params = af.getMapParams(); - - ArrayList tgtCards; - - final Target tgt = sa.getTarget(); - if ((tgt != null) && !params.containsKey("Defined")) { - tgtCards = tgt.getTargetCards(); - } else { - tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa); - } - - for (final Card c : tgtCards) { - if ((tgt == null) || c.canBeTargetedBy(sa)) { - Singletons.getModel().getGame().getCombat().removeFromCombat(c); - } - } - - } // mustAttackResolve() - - // ************************************************************** - // *********************** MustBlock **************************** - // ************************************************************** - - // AB$ MustBlock | Cost$ R T | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ - // Select target creature defending player controls | DefinedAttacker$ Self - // | SpellDescription$ ... - - /** - *

- * createAbilityMustBlock. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - * - * @since 1.1.6 - */ - public static SpellAbility createAbilityMustBlock(final AbilityFactory af) { - class AbilityMustBlock extends AbilityActivated { - public AbilityMustBlock(final Card ca, final Cost co, final Target t) { - super(ca, co, t); - } - - @Override - public AbilityActivated getCopy() { - AbilityActivated res = new AbilityMustBlock(getSourceCard(), - getPayCosts(), getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = 4237190949098526123L; - - @Override - public String getStackDescription() { - return AbilityFactoryCombat.mustBlockStackDescription(af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryCombat.mustBlockCanPlayAI(af, this); - } - - @Override - public void resolve() { - AbilityFactoryCombat.mustBlockResolve(af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryCombat.mustBlockDoTriggerAI(getActivatingPlayer(), af, this, mandatory); - } - } - final SpellAbility abMustBlock = new AbilityMustBlock(af.getHostCard(), af.getAbCost(), af.getAbTgt()); - - return abMustBlock; - } - - /** - *

- * createSpellMustBlock. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - * - * @since 1.1.6 - */ - public static SpellAbility createSpellMustBlock(final AbilityFactory af) { - final SpellAbility spMustBlock = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) { - private static final long serialVersionUID = 6758785067306305860L; - - @Override - public String getStackDescription() { - return AbilityFactoryCombat.mustBlockStackDescription(af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryCombat.mustBlockCanPlayAI(af, this); - } - - @Override - public void resolve() { - AbilityFactoryCombat.mustBlockResolve(af, this); - } - - }; - return spMustBlock; - } - - /** - *

- * createDrawbackMustBlock. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - * - * @since 1.1.6 - */ - public static SpellAbility createDrawbackMustBlock(final AbilityFactory af) { - class DrawbackMustBlock extends AbilitySub { - public DrawbackMustBlock(final Card ca, final Target t) { - super(ca, t); - } - - @Override - public AbilitySub getCopy() { - AbilitySub res = new DrawbackMustBlock(getSourceCard(), - getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = -815813765448972775L; - - @Override - public void resolve() { - AbilityFactoryCombat.mustBlockResolve(af, this); - } - - @Override - public boolean chkAIDrawback() { - return AbilityFactoryCombat.mustBlockPlayDrawbackAI(af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryCombat.mustBlockDoTriggerAI(getActivatingPlayer(), af, this, mandatory); - } - } - final SpellAbility dbMustBlock = new DrawbackMustBlock(af.getHostCard(), af.getAbTgt()); - - return dbMustBlock; - } - - private static String mustBlockStackDescription(final AbilityFactory af, final SpellAbility sa) { - final HashMap params = af.getMapParams(); - final Card host = sa.getSourceCard(); - final StringBuilder sb = new StringBuilder(); - - if (sa instanceof AbilitySub) { - sb.append(" "); - } else { - sb.append(sa.getSourceCard()).append(" - "); - } - - // end standard pre- - - ArrayList tgtCards; - - final Target tgt = sa.getTarget(); - if (tgt != null) { - tgtCards = tgt.getTargetCards(); - } else { - tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa); - } - - String attacker = null; - if (params.containsKey("DefinedAttacker")) { - final ArrayList cards = AbilityFactory.getDefinedCards(sa.getSourceCard(), - params.get("DefinedAttacker"), sa); - attacker = cards.get(0).toString(); - } else { - attacker = host.toString(); - } - - for (final Card c : tgtCards) { - sb.append(c).append(" must block ").append(attacker).append(" if able."); - } - - // begin standard post- - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - sb.append(abSub.getStackDescription()); - } - - return sb.toString(); - } - - private static boolean mustBlockCanPlayAI(final AbilityFactory af, final SpellAbility sa) { - // disabled for the AI until he/she can make decisions about who to make - // block - return false; - } - - private static boolean mustBlockPlayDrawbackAI(final AbilityFactory af, final SpellAbility sa) { - // AI should only activate this during Human's turn - boolean chance; - - // TODO - implement AI - chance = false; - - final AbilitySub subAb = sa.getSubAbility(); - if (subAb != null) { - chance &= subAb.chkAIDrawback(); - } - - return chance; - } - - private static boolean mustBlockDoTriggerAI(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) { - final HashMap params = af.getMapParams(); - final Card source = sa.getSourceCard(); - final Target abTgt = sa.getTarget(); - - // If there is a cost payment it's usually not mandatory - if (!ComputerUtil.canPayCost(sa, ai) && !mandatory) { - return false; - } - - // only use on creatures that can attack - if (!Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)) { - return false; - } - - Card attacker = null; - if (params.containsKey("DefinedAttacker")) { - final ArrayList cards = AbilityFactory.getDefinedCards(sa.getSourceCard(), - params.get("DefinedAttacker"), sa); - if (cards.isEmpty()) { - return false; - } - - attacker = cards.get(0); - } - - if (attacker == null) { - attacker = source; - } - - final Card definedAttacker = attacker; - - boolean chance = false; - - if (abTgt != null) { - List list = CardLists.filter(ai.getOpponent().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES); - list = CardLists.getTargetableCards(list, sa); - list = CardLists.getValidCards(list, abTgt.getValidTgts(), source.getController(), source); - list = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card c) { - boolean tapped = c.isTapped(); - c.setTapped(false); - if (!CombatUtil.canBlock(definedAttacker, c)) { - return false; - } - if (CombatUtil.canDestroyAttacker(definedAttacker, c, null, false)) { - return false; - } - if (!CombatUtil.canDestroyBlocker(c, definedAttacker, null, false)) { - return false; - } - c.setTapped(tapped); - return true; - } - }); - if (list.isEmpty()) { - return false; - } - final Card blocker = CardFactoryUtil.getBestCreatureAI(list); - if (blocker == null) { - return false; - } - abTgt.addTarget(blocker); - chance = true; - } else { - return false; - } - - // check SubAbilities DoTrigger? - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - return chance && abSub.doTrigger(mandatory); - } - - return chance; - } - - private static void mustBlockResolve(final AbilityFactory af, final SpellAbility sa) { - final HashMap params = af.getMapParams(); - final Card host = sa.getSourceCard(); - - ArrayList tgtCards; - - final Target tgt = sa.getTarget(); - if (tgt != null) { - tgtCards = tgt.getTargetCards(); - } else { - tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa); - } - - ArrayList cards; - if (params.containsKey("DefinedAttacker")) { - cards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("DefinedAttacker"), sa); - } else { - cards = new ArrayList(); - cards.add(host); - } - - for (final Card c : tgtCards) { - if ((tgt == null) || c.canBeTargetedBy(sa)) { - final Card attacker = cards.get(0); - c.addMustBlockCard(attacker); - System.out.println(c + " is adding " + attacker + " to mustBlockCards: " + c.getMustBlockCards()); - } - } - - } // mustBlockResolve() - -} // end class AbilityFactory_Combat diff --git a/src/main/java/forge/card/abilityfactory/SpellAiLogic.java b/src/main/java/forge/card/abilityfactory/SpellAiLogic.java index 7ffcc0adb7a..6567ad39354 100644 --- a/src/main/java/forge/card/abilityfactory/SpellAiLogic.java +++ b/src/main/java/forge/card/abilityfactory/SpellAiLogic.java @@ -18,10 +18,12 @@ public abstract class SpellAiLogic { return doTriggerAINoCost(aiPlayer, params, sa, mandatory); } + @SuppressWarnings("unused") // 'unused' parameters are used by overloads public boolean doTriggerAINoCost(final Player aiPlayer, final Map params, final SpellAbility sa, final boolean mandatory) { return canPlayAI(aiPlayer, params, sa); } // consider safe + @SuppressWarnings("unused") // 'unused' parameters are used by overloads public boolean chkAIDrawback(final Map params, final SpellAbility sa, final Player aiPlayer) { return true; } } \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/ai/FogAi.java b/src/main/java/forge/card/abilityfactory/ai/FogAi.java new file mode 100644 index 00000000000..f975fb9e8ab --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/ai/FogAi.java @@ -0,0 +1,110 @@ +package forge.card.abilityfactory.ai; + +import java.util.Map; + +import forge.Singletons; +import forge.card.abilityfactory.SpellAiLogic; +import forge.card.spellability.AbilitySub; +import forge.card.spellability.SpellAbility; +import forge.game.phase.CombatUtil; +import forge.game.phase.PhaseType; +import forge.game.player.Player; + +public class FogAi extends SpellAiLogic { + + /* (non-Javadoc) + * @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + public boolean canPlayAI(Player ai, Map params, SpellAbility sa) { + // AI should only activate this during Human's Declare Blockers phase + if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) { + return false; + } + if (!Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { + return false; + } + + // Only cast when Stack is empty, so Human uses spells/abilities first + if (!Singletons.getModel().getGame().getStack().isEmpty()) { + return false; + } + + // Don't cast it, if the effect is already in place + if (Singletons.getModel().getGame().getPhaseHandler().isPreventCombatDamageThisTurn()) { + return false; + } + + final AbilitySub subAb = sa.getSubAbility(); + if (subAb != null) { + if (!subAb.chkAIDrawback()) { + return false; + } + } + + // Cast it if life is in danger + return CombatUtil.lifeInDanger(ai, Singletons.getModel().getGame().getCombat()); + } + + /** + *

+ * fogPlayDrawbackAI. + *

+ * + * @param af + * a {@link forge.card.abilityfactory.AbilityFactory} object. + * @param sa + * a {@link forge.card.spellability.SpellAbility} object. + * @return a boolean. + */ + @Override + public boolean chkAIDrawback(java.util.Map params, SpellAbility sa, Player ai) { + // AI should only activate this during Human's turn + boolean chance; + + // should really check if other player is attacking this player + if (ai.isHostileTo(Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn())) { + chance = Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_FIRST_STRIKE_DAMAGE); + } else { + chance = Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE); + } + + final AbilitySub subAb = sa.getSubAbility(); + if (subAb != null) { + chance &= subAb.chkAIDrawback(); + } + + return chance; + } + + /** + *

+ * fogDoTriggerAI. + *

+ * + * @param af + * a {@link forge.card.abilityfactory.AbilityFactory} object. + * @param sa + * a {@link forge.card.spellability.SpellAbility} object. + * @param mandatory + * a boolean. + * @return a boolean. + */ + @Override + public boolean doTriggerAINoCost(Player aiPlayer, java.util.Map params, SpellAbility sa, boolean mandatory) { + boolean chance; + if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer().getOpponent())) { + chance = Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_FIRST_STRIKE_DAMAGE); + } else { + chance = Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE); + } + + // check SubAbilities DoTrigger? + final AbilitySub abSub = sa.getSubAbility(); + if (abSub != null) { + return chance && abSub.doTrigger(mandatory); + } + + return chance; + } +} \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/ai/MustAttackAi.java b/src/main/java/forge/card/abilityfactory/ai/MustAttackAi.java new file mode 100644 index 00000000000..e00f77f6c0d --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/ai/MustAttackAi.java @@ -0,0 +1,44 @@ +package forge.card.abilityfactory.ai; + +import java.util.Map; + +import forge.card.abilityfactory.SpellAiLogic; +import forge.card.spellability.AbilitySub; +import forge.card.spellability.SpellAbility; +import forge.game.player.Player; + +public class MustAttackAi extends SpellAiLogic { + + @Override + public boolean canPlayAI(Player aiPlayer, java.util.Map params, SpellAbility sa) { + // disabled for the AI for now. Only for Gideon Jura at this time. + return false; + } + + @Override + public boolean chkAIDrawback(java.util.Map params, SpellAbility sa, Player aiPlayer) { + // AI should only activate this during Human's turn + // TODO - implement AI + return false; + } + + /* (non-Javadoc) + * @see forge.card.abilityfactory.SpellAiLogic#doTriggerAINoCost(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility, boolean) + */ + @Override + public boolean doTriggerAINoCost(Player aiPlayer, Map params, SpellAbility sa, boolean mandatory) { + + boolean chance; + + // TODO - implement AI + chance = false; + + // check SubAbilities DoTrigger? + final AbilitySub abSub = sa.getSubAbility(); + if (abSub != null) { + return chance && abSub.doTrigger(mandatory); + } + + return chance; + } +} \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/ai/MustBlockAi.java b/src/main/java/forge/card/abilityfactory/ai/MustBlockAi.java new file mode 100644 index 00000000000..1528ffd5add --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/ai/MustBlockAi.java @@ -0,0 +1,109 @@ +package forge.card.abilityfactory.ai; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.base.Predicate; + +import forge.Card; +import forge.CardLists; +import forge.CardPredicates; +import forge.Singletons; +import forge.card.abilityfactory.AbilityFactory; +import forge.card.abilityfactory.SpellAiLogic; +import forge.card.cardfactory.CardFactoryUtil; +import forge.card.spellability.AbilitySub; +import forge.card.spellability.SpellAbility; +import forge.card.spellability.Target; +import forge.game.phase.CombatUtil; +import forge.game.phase.PhaseType; +import forge.game.player.Player; +import forge.game.zone.ZoneType; + +public class MustBlockAi extends SpellAiLogic { + + @Override + public boolean canPlayAI(Player aiPlayer, java.util.Map params, SpellAbility sa) { + // disabled for the AI until he/she can make decisions about who to make + // block + return false; + } + + @Override + public boolean chkAIDrawback(java.util.Map params, SpellAbility sa, Player aiPlayer) { + return false; + } + + @Override + public boolean doTriggerAINoCost(Player ai, java.util.Map params, SpellAbility sa, boolean mandatory) { + final Card source = sa.getSourceCard(); + final Target abTgt = sa.getTarget(); + + // only use on creatures that can attack + if (!Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)) { + return false; + } + + Card attacker = null; + if (params.containsKey("DefinedAttacker")) { + final ArrayList cards = AbilityFactory.getDefinedCards(sa.getSourceCard(), + params.get("DefinedAttacker"), sa); + if (cards.isEmpty()) { + return false; + } + + attacker = cards.get(0); + } + + if (attacker == null) { + attacker = source; + } + + final Card definedAttacker = attacker; + + boolean chance = false; + + if (abTgt != null) { + List list = CardLists.filter(ai.getOpponent().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES); + list = CardLists.getTargetableCards(list, sa); + list = CardLists.getValidCards(list, abTgt.getValidTgts(), source.getController(), source); + list = CardLists.filter(list, new Predicate() { + @Override + public boolean apply(final Card c) { + boolean tapped = c.isTapped(); + c.setTapped(false); + if (!CombatUtil.canBlock(definedAttacker, c)) { + return false; + } + if (CombatUtil.canDestroyAttacker(definedAttacker, c, null, false)) { + return false; + } + if (!CombatUtil.canDestroyBlocker(c, definedAttacker, null, false)) { + return false; + } + c.setTapped(tapped); + return true; + } + }); + if (list.isEmpty()) { + return false; + } + final Card blocker = CardFactoryUtil.getBestCreatureAI(list); + if (blocker == null) { + return false; + } + abTgt.addTarget(blocker); + chance = true; + } else { + return false; + } + + // check SubAbilities DoTrigger? + final AbilitySub abSub = sa.getSubAbility(); + if (abSub != null) { + return chance && abSub.doTrigger(mandatory); + } + + return chance; + } +} \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/ai/RegenerateAi.java b/src/main/java/forge/card/abilityfactory/ai/RegenerateAi.java index 799591dcc8c..ecb9ecfda84 100644 --- a/src/main/java/forge/card/abilityfactory/ai/RegenerateAi.java +++ b/src/main/java/forge/card/abilityfactory/ai/RegenerateAi.java @@ -18,7 +18,6 @@ package forge.card.abilityfactory.ai; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import forge.Card; @@ -31,9 +30,7 @@ import forge.card.abilityfactory.SpellAiLogic; import forge.card.cardfactory.CardFactoryUtil; import forge.card.cost.Cost; import forge.card.cost.CostUtil; -import forge.card.spellability.AbilityActivated; import forge.card.spellability.AbilitySub; -import forge.card.spellability.Spell; import forge.card.spellability.SpellAbility; import forge.card.spellability.Target; import forge.game.phase.CombatUtil; diff --git a/src/main/java/forge/card/abilityfactory/ai/RegenerateAllAi.java b/src/main/java/forge/card/abilityfactory/ai/RegenerateAllAi.java index 93ff3d54539..5d5cc384790 100644 --- a/src/main/java/forge/card/abilityfactory/ai/RegenerateAllAi.java +++ b/src/main/java/forge/card/abilityfactory/ai/RegenerateAllAi.java @@ -15,7 +15,6 @@ import forge.card.spellability.AbilitySub; import forge.card.spellability.SpellAbility; import forge.game.phase.CombatUtil; import forge.game.phase.PhaseType; -import forge.game.player.ComputerUtil; import forge.game.player.Player; import forge.game.zone.ZoneType; @@ -107,14 +106,10 @@ public class RegenerateAllAi extends SpellAiLogic { * a boolean. * @return a boolean. */ - private static boolean regenerateAllDoTriggerAI(final Player ai, final AbilityFactory af, final SpellAbility sa, - final boolean mandatory) { + @Override + public boolean doTriggerAINoCost(Player aiPlayer, java.util.Map params, SpellAbility sa, boolean mandatory) { boolean chance = true; - if (!ComputerUtil.canPayCost(sa, ai)) { - return false; - } - final AbilitySub subAb = sa.getSubAbility(); if (subAb != null) { chance &= subAb.doTrigger(mandatory); diff --git a/src/main/java/forge/card/abilityfactory/ai/RemoveFromCombatAi.java b/src/main/java/forge/card/abilityfactory/ai/RemoveFromCombatAi.java new file mode 100644 index 00000000000..b4f3efb61f5 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/ai/RemoveFromCombatAi.java @@ -0,0 +1,44 @@ +package forge.card.abilityfactory.ai; + +import java.util.Map; + +import forge.card.abilityfactory.SpellAiLogic; +import forge.card.spellability.AbilitySub; +import forge.card.spellability.SpellAbility; +import forge.game.player.Player; + +public class RemoveFromCombatAi extends SpellAiLogic { + + @Override + public boolean canPlayAI(Player aiPlayer, java.util.Map params, SpellAbility sa) { + // disabled for the AI for now. Only for Gideon Jura at this time. + return false; + } + + @Override + public boolean chkAIDrawback(java.util.Map params, SpellAbility sa, Player aiPlayer) { + // AI should only activate this during Human's turn + + // TODO - implement AI + return false; + } + + /* (non-Javadoc) + * @see forge.card.abilityfactory.SpellAiLogic#doTriggerAINoCost(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility, boolean) + */ + @Override + public boolean doTriggerAINoCost(Player aiPlayer, Map params, SpellAbility sa, boolean mandatory) { + boolean chance; + + // TODO - implement AI + chance = false; + + // check SubAbilities DoTrigger? + final AbilitySub abSub = sa.getSubAbility(); + if (abSub != null) { + return chance && abSub.doTrigger(mandatory); + } + + return chance; + } +} \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/effects/FogEffect.java b/src/main/java/forge/card/abilityfactory/effects/FogEffect.java new file mode 100644 index 00000000000..0e8aa79c5b2 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/effects/FogEffect.java @@ -0,0 +1,38 @@ +package forge.card.abilityfactory.effects; + +import forge.Singletons; +import forge.card.abilityfactory.SpellEffect; +import forge.card.spellability.AbilitySub; +import forge.card.spellability.SpellAbility; + +public class FogEffect extends SpellEffect { + + + @Override + public String getStackDescription(java.util.Map params, SpellAbility sa) { + final StringBuilder sb = new StringBuilder(); + + if (!(sa instanceof AbilitySub)) { + sb.append(sa.getSourceCard().getName()).append(" - "); + } else { + sb.append(" "); + } + + sb.append(sa.getSourceCard().getController()); + sb.append(" prevents all combat damage this turn."); + + final AbilitySub abSub = sa.getSubAbility(); + if (abSub != null) { + sb.append(abSub.getStackDescription()); + } + + return sb.toString(); + } + + + @Override + public void resolve(java.util.Map params, SpellAbility sa) { + // Expand Fog keyword here depending on what we need out of it. + Singletons.getModel().getGame().getPhaseHandler().setPreventCombatDamageThisTurn(true); + } +} \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/effects/MustAttackEffect.java b/src/main/java/forge/card/abilityfactory/effects/MustAttackEffect.java new file mode 100644 index 00000000000..f6c2d4964ed --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/effects/MustAttackEffect.java @@ -0,0 +1,93 @@ +package forge.card.abilityfactory.effects; + +import java.util.ArrayList; +import java.util.Map; + +import forge.Card; +import forge.GameEntity; +import forge.card.abilityfactory.AbilityFactory; +import forge.card.abilityfactory.SpellEffect; +import forge.card.spellability.AbilitySub; +import forge.card.spellability.SpellAbility; +import forge.card.spellability.Target; +import forge.game.player.Player; + +public class MustAttackEffect extends SpellEffect { + + /* (non-Javadoc) + * @see forge.card.abilityfactory.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + public String getStackDescription(Map params, SpellAbility sa) { + final Card host = sa.getSourceCard(); + final StringBuilder sb = new StringBuilder(); + + if (sa instanceof AbilitySub) { + sb.append(" "); + } else { + sb.append(sa.getSourceCard()).append(" - "); + } + + // end standard pre- + + ArrayList tgtPlayers; + + final Target tgt = sa.getTarget(); + if (tgt != null) { + tgtPlayers = tgt.getTargetPlayers(); + } else { + tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa); + } + + String defender = null; + if (params.get("Defender").equals("Self")) { + defender = host.toString(); + } else { + // TODO - if more needs arise in the future + } + + for (final Player player : tgtPlayers) { + sb.append("Creatures ").append(player).append(" controls attack "); + sb.append(defender).append(" during his or her next turn."); + } + + // begin standard post- + final AbilitySub abSub = sa.getSubAbility(); + if (abSub != null) { + sb.append(abSub.getStackDescription()); + } + + return sb.toString(); + } + + @Override + public void resolve(java.util.Map params, SpellAbility sa) { + ArrayList tgtPlayers; + + final Target tgt = sa.getTarget(); + if ((tgt != null) && !params.containsKey("Defined")) { + tgtPlayers = tgt.getTargetPlayers(); + } else { + tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa); + } + + for (final Player p : tgtPlayers) { + if ((tgt == null) || p.canBeTargetedBy(sa)) { + GameEntity entity; + if (params.get("Defender").equals("Self")) { + entity = sa.getSourceCard(); + } else { + entity = p.getOpponent(); + } + // System.out.println("Setting mustAttackEntity to: "+entity); + p.setMustAttackEntity(entity); + } + } + + } // mustAttackResolve() + + // ************************************************************** + // ********************* RemoveFromCombat *********************** + // ************************************************************** + +} \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/effects/MustBlockEffect.java b/src/main/java/forge/card/abilityfactory/effects/MustBlockEffect.java new file mode 100644 index 00000000000..2db0cc75123 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/effects/MustBlockEffect.java @@ -0,0 +1,89 @@ +package forge.card.abilityfactory.effects; + +import java.util.ArrayList; + +import forge.Card; +import forge.card.abilityfactory.AbilityFactory; +import forge.card.abilityfactory.SpellEffect; +import forge.card.spellability.AbilitySub; +import forge.card.spellability.SpellAbility; +import forge.card.spellability.Target; + +public class MustBlockEffect extends SpellEffect { + + @Override + public void resolve(java.util.Map params, SpellAbility sa) { + final Card host = sa.getSourceCard(); + + ArrayList tgtCards; + + final Target tgt = sa.getTarget(); + if (tgt != null) { + tgtCards = tgt.getTargetCards(); + } else { + tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa); + } + + ArrayList cards; + if (params.containsKey("DefinedAttacker")) { + cards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("DefinedAttacker"), sa); + } else { + cards = new ArrayList(); + cards.add(host); + } + + for (final Card c : tgtCards) { + if ((tgt == null) || c.canBeTargetedBy(sa)) { + final Card attacker = cards.get(0); + c.addMustBlockCard(attacker); + System.out.println(c + " is adding " + attacker + " to mustBlockCards: " + c.getMustBlockCards()); + } + } + + } // mustBlockResolve() + + @Override + public String getStackDescription(java.util.Map params, SpellAbility sa) { + final Card host = sa.getSourceCard(); + final StringBuilder sb = new StringBuilder(); + + if (sa instanceof AbilitySub) { + sb.append(" "); + } else { + sb.append(sa.getSourceCard()).append(" - "); + } + + // end standard pre- + + ArrayList tgtCards; + + final Target tgt = sa.getTarget(); + if (tgt != null) { + tgtCards = tgt.getTargetCards(); + } else { + tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa); + } + + String attacker = null; + if (params.containsKey("DefinedAttacker")) { + final ArrayList cards = AbilityFactory.getDefinedCards(sa.getSourceCard(), + params.get("DefinedAttacker"), sa); + attacker = cards.get(0).toString(); + } else { + attacker = host.toString(); + } + + for (final Card c : tgtCards) { + sb.append(c).append(" must block ").append(attacker).append(" if able."); + } + + // begin standard post- + final AbilitySub abSub = sa.getSubAbility(); + if (abSub != null) { + sb.append(abSub.getStackDescription()); + } + + return sb.toString(); + } + +} // end class AbilityFactory_Combat \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/effects/RegenerateAllEffect.java b/src/main/java/forge/card/abilityfactory/effects/RegenerateAllEffect.java index 7137b192e4c..e5bea6e9e22 100644 --- a/src/main/java/forge/card/abilityfactory/effects/RegenerateAllEffect.java +++ b/src/main/java/forge/card/abilityfactory/effects/RegenerateAllEffect.java @@ -6,7 +6,6 @@ import forge.Card; import forge.CardLists; import forge.Command; import forge.Singletons; -import forge.card.abilityfactory.AbilityFactory; import forge.card.abilityfactory.SpellEffect; import forge.card.spellability.AbilitySub; import forge.card.spellability.SpellAbility; diff --git a/src/main/java/forge/card/abilityfactory/effects/RemoveFromCombatEffect.java b/src/main/java/forge/card/abilityfactory/effects/RemoveFromCombatEffect.java new file mode 100644 index 00000000000..0eb89b8f46a --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/effects/RemoveFromCombatEffect.java @@ -0,0 +1,72 @@ +package forge.card.abilityfactory.effects; + +import java.util.ArrayList; + +import forge.Card; +import forge.Singletons; +import forge.card.abilityfactory.AbilityFactory; +import forge.card.abilityfactory.SpellEffect; +import forge.card.spellability.AbilitySub; +import forge.card.spellability.SpellAbility; +import forge.card.spellability.Target; + +public class RemoveFromCombatEffect extends SpellEffect { + + @Override + public String getStackDescription(java.util.Map params, SpellAbility sa) { + final StringBuilder sb = new StringBuilder(); + + if (sa instanceof AbilitySub) { + sb.append(" "); + } else { + sb.append(sa.getSourceCard()).append(" - "); + } + + // end standard pre- + + ArrayList tgtCards; + + final Target tgt = sa.getTarget(); + if (tgt != null) { + tgtCards = tgt.getTargetCards(); + } else { + tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa); + } + + sb.append("Remove "); + + for (final Card c : tgtCards) { + sb.append(c); + } + + sb.append(" from combat."); + + // begin standard post- + final AbilitySub abSub = sa.getSubAbility(); + if (abSub != null) { + sb.append(abSub.getStackDescription()); + } + + return sb.toString(); + } + + @Override + public void resolve(java.util.Map params, SpellAbility sa) { + + ArrayList tgtCards; + + final Target tgt = sa.getTarget(); + if ((tgt != null) && !params.containsKey("Defined")) { + tgtCards = tgt.getTargetCards(); + } else { + tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa); + } + + for (final Card c : tgtCards) { + if ((tgt == null) || c.canBeTargetedBy(sa)) { + Singletons.getModel().getGame().getCombat().removeFromCombat(c); + } + } + + } +} \ No newline at end of file diff --git a/src/main/java/forge/game/phase/CombatUtil.java b/src/main/java/forge/game/phase/CombatUtil.java index 41eaa134cdd..715e1693076 100644 --- a/src/main/java/forge/game/phase/CombatUtil.java +++ b/src/main/java/forge/game/phase/CombatUtil.java @@ -1042,7 +1042,7 @@ public class CombatUtil { * a {@link forge.game.phase.Combat} object. * @return a int. */ - public static int poisonIfUnblocked(final Card attacker, final Player attacked, final Combat combat) { + public static int poisonIfUnblocked(final Card attacker, final Player attacked) { int damage = attacker.getNetCombatDamage(); int poison = 0; damage += CombatUtil.predictPowerBonusOfAttacker(attacker, null, null); @@ -1093,7 +1093,7 @@ public class CombatUtil { public static int sumPoisonIfUnblocked(final List attackers, final Player attacked) { int sum = 0; for (final Card attacker : attackers) { - sum += CombatUtil.poisonIfUnblocked(attacker, attacked, null); + sum += CombatUtil.poisonIfUnblocked(attacker, attacked); } return sum; } diff --git a/src/main/java/forge/game/player/ComputerUtilAttack.java b/src/main/java/forge/game/player/ComputerUtilAttack.java index 98595e1a7a4..4a46a093ca3 100644 --- a/src/main/java/forge/game/player/ComputerUtilAttack.java +++ b/src/main/java/forge/game/player/ComputerUtilAttack.java @@ -138,7 +138,7 @@ public class ComputerUtilAttack { if (CombatUtil.damageIfUnblocked(attacker, opp, combat) > 0) { return true; } - if (CombatUtil.poisonIfUnblocked(attacker, opp, combat) > 0) { + if (CombatUtil.poisonIfUnblocked(attacker, opp) > 0) { return true; } if (this.attackers.size() == 1 && attacker.hasKeyword("Exalted")) { @@ -341,7 +341,7 @@ public class ComputerUtilAttack { continue; } totalAttack += CombatUtil.damageIfUnblocked(attacker, ai, null); - totalPoison += CombatUtil.poisonIfUnblocked(attacker, ai, null); + totalPoison += CombatUtil.poisonIfUnblocked(attacker, ai); } if (ai.getLife() <= totalAttack diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java index f8b953346e2..06e6739f7ba 100644 --- a/src/main/java/forge/game/player/Player.java +++ b/src/main/java/forge/game/player/Player.java @@ -2887,5 +2887,17 @@ public abstract class Player extends GameEntity implements Comparable { } return false; } + + /** + * TODO: Write javadoc for this method. + * @param playerTurn + * @return + */ + public boolean isHostileTo(Player other) { + if ( other.equals(getOpponent()) ) + return true; + + return other.getType() != this.getType(); + } }