diff --git a/.gitattributes b/.gitattributes index dddde9f0a2d..a97a30088a3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12463,8 +12463,7 @@ src/main/java/forge/card/abilityfactory/AbilityFactory.java svneol=native#text/p src/main/java/forge/card/abilityfactory/AbilityFactoryAttach.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/AbilityFactoryChangeZone.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/AbilityFactoryCharm.java svneol=native#text/plain -src/main/java/forge/card/abilityfactory/AbilityFactoryCleanup.java svneol=native#text/plain -src/main/java/forge/card/abilityfactory/AbilityFactoryStoreSVar.java -text +src/main/java/forge/card/abilityfactory/CleanUpEffect.java -text src/main/java/forge/card/abilityfactory/CommonAbility.java -text src/main/java/forge/card/abilityfactory/CommonDrawback.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/CommonSpell.java -text @@ -12477,6 +12476,7 @@ src/main/java/forge/card/abilityfactory/ai/AnimateAllAi.java -text src/main/java/forge/card/abilityfactory/ai/BondAi.java -text src/main/java/forge/card/abilityfactory/ai/CanPlayAsDrawbackAi.java -text src/main/java/forge/card/abilityfactory/ai/CannotPlayAi.java -text +src/main/java/forge/card/abilityfactory/ai/ChangeZoneAllAi.java -text src/main/java/forge/card/abilityfactory/ai/ChooseCardAi.java -text src/main/java/forge/card/abilityfactory/ai/ChooseCardNameAi.java -text src/main/java/forge/card/abilityfactory/ai/ChooseColorAi.java -text @@ -12544,12 +12544,14 @@ src/main/java/forge/card/abilityfactory/ai/ScryAi.java -text src/main/java/forge/card/abilityfactory/ai/SetStateAi.java -text src/main/java/forge/card/abilityfactory/ai/SetStateAllAi.java -text src/main/java/forge/card/abilityfactory/ai/ShuffleAi.java -text +src/main/java/forge/card/abilityfactory/ai/StoreSVarAi.java -text src/main/java/forge/card/abilityfactory/ai/TapAi.java -text src/main/java/forge/card/abilityfactory/ai/TapAiBase.java -text src/main/java/forge/card/abilityfactory/ai/TapAllAi.java -text src/main/java/forge/card/abilityfactory/ai/TapOrUntapAi.java -text src/main/java/forge/card/abilityfactory/ai/TokenAi.java -text src/main/java/forge/card/abilityfactory/ai/TwoPilesAi.java -text +src/main/java/forge/card/abilityfactory/ai/UnattachAllAi.java -text src/main/java/forge/card/abilityfactory/ai/UntapAi.java -text src/main/java/forge/card/abilityfactory/ai/UntapAllAi.java -text src/main/java/forge/card/abilityfactory/effects/AddTurnEffect.java -text @@ -12557,6 +12559,7 @@ src/main/java/forge/card/abilityfactory/effects/AnimateAllEffect.java -text src/main/java/forge/card/abilityfactory/effects/AnimateEffect.java -text src/main/java/forge/card/abilityfactory/effects/AnimateEffectBase.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/effects/BondEffect.java -text +src/main/java/forge/card/abilityfactory/effects/ChangeZoneAllEffect.java -text src/main/java/forge/card/abilityfactory/effects/ChooseCardEffect.java -text src/main/java/forge/card/abilityfactory/effects/ChooseCardNameEffect.java -text src/main/java/forge/card/abilityfactory/effects/ChooseColorEffect.java -text @@ -12629,11 +12632,13 @@ src/main/java/forge/card/abilityfactory/effects/ScryEffect.java -text src/main/java/forge/card/abilityfactory/effects/SetStateAllEffect.java -text src/main/java/forge/card/abilityfactory/effects/SetStateEffect.java -text src/main/java/forge/card/abilityfactory/effects/ShuffleEffect.java -text +src/main/java/forge/card/abilityfactory/effects/StoreSVarEffect.java -text src/main/java/forge/card/abilityfactory/effects/TapAllEffect.java -text src/main/java/forge/card/abilityfactory/effects/TapEffect.java -text src/main/java/forge/card/abilityfactory/effects/TapOrUntapEffect.java -text src/main/java/forge/card/abilityfactory/effects/TokenEffect.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/effects/TwoPilesEffect.java -text +src/main/java/forge/card/abilityfactory/effects/UnattachAllEffect.java -text src/main/java/forge/card/abilityfactory/effects/UntapAllEffect.java -text src/main/java/forge/card/abilityfactory/effects/UntapEffect.java -text 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 6283174714c..8da1d58d223 100644 --- a/src/main/java/forge/card/abilityfactory/AbilityFactory.java +++ b/src/main/java/forge/card/abilityfactory/AbilityFactory.java @@ -471,9 +471,8 @@ public class AbilityFactory { } else if (this.api.equals("Cleanup")) { - if (this.isDb) { - spellAbility = AbilityFactoryCleanup.getDrawback(this); - } + ai = new AlwaysPlayAi(); + se = new CleanUpEffect(); } else if (this.api.equals("Clone")) { @@ -810,13 +809,8 @@ public class AbilityFactory { } else if (this.api.equals("StoreSVar")) { - if (this.isAb) { - spellAbility = AbilityFactoryStoreSVar.createAbilityStoreSVar(this); - } else if (this.isSp) { - spellAbility = AbilityFactoryStoreSVar.createSpellStoreSVar(this); - } else if (this.isDb) { - spellAbility = AbilityFactoryStoreSVar.createDrawbackStoreSVar(this); - } + ai = new StoreSVarAi(); + se = new StoreSVarEffect(); } else if (this.api.equals("Tap")) { @@ -845,13 +839,8 @@ public class AbilityFactory { } else if (this.api.equals("UnattachAll")) { - if (this.isAb) { - spellAbility = AbilityFactoryAttach.createAbilityUnattachAll(this); - } else if (this.isSp) { - spellAbility = AbilityFactoryAttach.createSpellUnattachAll(this); - } else if (this.isDb) { - spellAbility = AbilityFactoryAttach.createDrawbackUnattachAll(this); - } + ai = new UnattachAllAi(); + se = new UnattachAllEffect(); } else if (this.api.equals("Untap")) { diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryAttach.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryAttach.java index 708f26efc06..630eb32c2d7 100644 --- a/src/main/java/forge/card/abilityfactory/AbilityFactoryAttach.java +++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryAttach.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Random; + import com.google.common.base.Predicate; import com.google.common.base.Predicates; @@ -1446,402 +1447,5 @@ public class AbilityFactoryAttach { // ************************ UnattachAll ************************* // ************************************************************** - /** - * Creates the ability unattachAll. - * - * @param af - * the aF - * @return the spell ability - */ - public static SpellAbility createAbilityUnattachAll(final AbilityFactory af) { - class AbilityUnattachAll extends AbilityActivated { - public AbilityUnattachAll(final Card ca, final Cost co, final Target t) { - super(ca, co, t); - } - - @Override - public AbilityActivated getCopy() { - AbilityActivated res = new AbilityUnattachAll(getSourceCard(), - getPayCosts(), getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = 5946312226232487294L; - - @Override - public boolean canPlayAI() { - return AbilityFactoryAttach.unattachAllCanPlayAI(getActivatingPlayer(), af, this); - } - - @Override - public void resolve() { - AbilityFactoryAttach.unattachAllResolve(af, this); - } - - @Override - public String getStackDescription() { - return AbilityFactoryAttach.unattachAllStackDescription(af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryAttach.unattachAllDoTriggerAI(getActivatingPlayer(), af, this, mandatory); - } - } - final SpellAbility abUnattachAll = new AbilityUnattachAll(af.getHostCard(), af.getAbCost(), af.getAbTgt()); - - return abUnattachAll; - } - - /** - * Creates the spell unattachAll. - * - * @param af - * the AbilityFactory - * @return the spell ability - */ - public static SpellAbility createSpellUnattachAll(final AbilityFactory af) { - final SpellAbility spUnattachAll = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) { - private static final long serialVersionUID = 5531073401713526341L; - - @Override - public boolean canPlayAI() { - return AbilityFactoryAttach.unattachAllCanPlayAI(getActivatingPlayer(), af, this); - } - - @Override - public void resolve() { - AbilityFactoryAttach.unattachAllResolve(af, this); - } - - @Override - public String getStackDescription() { - return AbilityFactoryAttach.unattachAllStackDescription(af, this); - } - }; - return spUnattachAll; - } - - // Attach Drawback - /** - * Creates the drawback unattachAll. - * - * @param af - * the aF - * @return the spell ability - */ - public static SpellAbility createDrawbackUnattachAll(final AbilityFactory af) { - class DrawbackUnattachAll extends AbilitySub { - public DrawbackUnattachAll(final Card ca, final Target t) { - super(ca, t); - } - - @Override - public AbilitySub getCopy() { - AbilitySub res = new DrawbackUnattachAll(getSourceCard(), - getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = 9007743612927046143L; - - @Override - public void resolve() { - AbilityFactoryAttach.unattachAllResolve(af, this); - } - - @Override - public boolean chkAIDrawback() { - return AbilityFactoryAttach.unattachAllPlayDrawbackAI(getActivatingPlayer(), af, this); - } - - @Override - public String getStackDescription() { - return AbilityFactoryAttach.unattachAllStackDescription(af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryAttach.unattachAllDoTriggerAI(getActivatingPlayer(), af, this, mandatory); - } - } - final SpellAbility dbUnattachAll = new DrawbackUnattachAll(af.getHostCard(), af.getAbTgt()); - - return dbUnattachAll; - } - - /** - * UnattachAll stack description. - * - * @param af - * the af - * @param sa - * the sa - * @return the string - */ - private static String unattachAllStackDescription(final AbilityFactory af, final SpellAbility sa) { - final StringBuilder sb = new StringBuilder(); - - if (sa instanceof AbilitySub) { - sb.append(" "); - } else { - sb.append(sa.getSourceCard()).append(" - "); - } - - sb.append("Unattach all valid Equipment and Auras from "); - - ArrayList targets; - - // Should never allow more than one Attachment per card - final Target tgt = sa.getTarget(); - if (tgt != null) { - targets = tgt.getTargets(); - } else { - targets = AbilityFactory.getDefinedObjects(sa.getSourceCard(), af.getMapParams().get("Defined"), sa); - } - - for (final Object o : targets) { - sb.append(o).append(" "); - } - - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - sb.append(abSub.getStackDescription()); - } - - return sb.toString(); - } - - private static boolean unattachAllCanPlayAI(final Player ai, final AbilityFactory af, final SpellAbility sa) { - final Random r = MyRandom.getRandom(); - final Cost abCost = sa.getPayCosts(); - final Card source = sa.getSourceCard(); - - if (abCost != null) { - // No Aura spells have Additional Costs - } - - // prevent run-away activations - first time will always return true - boolean chance = r.nextFloat() <= .9; - - // Attach spells always have a target - final Target tgt = sa.getTarget(); - if (tgt != null) { - tgt.resetTargets(); - } - - if (abCost != null && abCost.getTotalMana().contains("X") && source.getSVar("X").equals("Count$xPaid")) { - final int xPay = ComputerUtil.determineLeftoverMana(sa, ai); - - if (xPay == 0) { - return false; - } - - source.setSVar("PayX", Integer.toString(xPay)); - } - - if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) - && !"Curse".equals(af.getMapParams().get("AILogic"))) { - return false; - } - - return chance; - } - - private static boolean unattachAllDoTriggerAI(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) { - final Map params = af.getMapParams(); - final Card card = sa.getSourceCard(); - - if (!ComputerUtil.canPayCost(sa, ai)) { - // usually not mandatory - return false; - } - - final Player opp = ai.getOpponent(); - // Check if there are any valid targets - ArrayList targets = new ArrayList(); - final Target tgt = sa.getTarget(); - if (tgt == null) { - targets = AbilityFactory.getDefinedObjects(sa.getSourceCard(), params.get("Defined"), sa); - } - - if (!mandatory && card.isEquipment() && !targets.isEmpty()) { - Card newTarget = (Card) targets.get(0); - //don't equip human creatures - if (newTarget.getController().equals(opp)) { - return false; - } - - //don't equip a worse creature - if (card.isEquipping()) { - Card oldTarget = card.getEquipping().get(0); - if (CardFactoryUtil.evaluateCreature(oldTarget) > CardFactoryUtil.evaluateCreature(newTarget)) { - return false; - } - } - } - - // check SubAbilities DoTrigger? - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - return abSub.doTrigger(mandatory); - } - - return true; - } - - private static void unattachAllResolve(final AbilityFactory af, final SpellAbility sa) { - final Map params = af.getMapParams(); - Card source = sa.getSourceCard(); - - ArrayList targets; - - final Target tgt = sa.getTarget(); - if (tgt != null) { - targets = tgt.getTargets(); - } else { - targets = AbilityFactory.getDefinedObjects(source, params.get("Defined"), sa); - } - - // If Cast Targets will be checked on the Stack - for (final Object o : targets) { - String valid = params.get("UnattachValid"); - List unattachList = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield); - unattachList = CardLists.getValidCards(unattachList, valid.split(","), source.getController(), source); - for (final Card c : unattachList) { - AbilityFactoryAttach.handleUnattachment(o, c, af); - } - } - } - - private static void handleUnattachment(final Object o, final Card cardToUnattach, final AbilityFactory af) { - - if (o instanceof Card) { - final Card c = (Card) o; - if (cardToUnattach.isAura()) { - //final boolean gainControl = "GainControl".equals(af.getMapParams().get("AILogic")); - //AbilityFactoryAttach.handleUnattachAura(cardToUnattach, c, gainControl); - } else if (cardToUnattach.isEquipment()) { - if (cardToUnattach.isEquipping() && c.getEquippedBy().contains(cardToUnattach)) { - cardToUnattach.unEquipCard(cardToUnattach.getEquipping().get(0)); - } - //TODO - unfortify would also be handled here - } - } else if (o instanceof Player) { - final Player p = (Player) o; - if (cardToUnattach.isAura() && p.getEnchantedBy().contains(cardToUnattach)) { - //AbilityFactoryAttach.handleUnattachAura(cardToUnattach, p, false); - } - } - } - - /* this isn't modifed to handled unattach yet, but should be for things like Remove Enchantments, etc. - private static void handleUnattachAura(final Card card, final GameEntity tgt, final boolean gainControl) { - if (card.isEnchanting()) { - // If this Card is already Enchanting something - // Need to unenchant it, then clear out the commands - final GameEntity oldEnchanted = card.getEnchanting(); - card.removeEnchanting(oldEnchanted); - card.clearEnchantCommand(); - card.clearUnEnchantCommand(); - card.clearTriggers(); // not sure if cleartriggers is needed? - } - - if (gainControl) { - // Handle GainControl Auras - final Player[] pl = new Player[1]; - - if (tgt instanceof Card) { - pl[0] = ((Card) tgt).getController(); - } else { - pl[0] = (Player) tgt; - } - - final Command onEnchant = new Command() { - private static final long serialVersionUID = -2519887209491512000L; - - @Override - public void execute() { - final Card crd = card.getEnchantingCard(); - if (crd == null) { - return; - } - - pl[0] = crd.getController(); - - crd.addController(card); - - } // execute() - }; // Command - - final Command onUnEnchant = new Command() { - private static final long serialVersionUID = 3426441132121179288L; - - @Override - public void execute() { - final Card crd = card.getEnchantingCard(); - if (crd == null) { - return; - } - - if (AllZoneUtil.isCardInPlay(crd)) { - crd.removeController(card); - } - - } // execute() - }; // Command - - final Command onChangesControl = new Command() { - private static final long serialVersionUID = -65903786170234039L; - - @Override - public void execute() { - final Card crd = card.getEnchantingCard(); - if (crd == null) { - return; - } - crd.removeController(card); // This looks odd, but will - // simply refresh controller - crd.addController(card); - } // execute() - }; // Command - - // Add Enchant Commands for Control changers - card.addEnchantCommand(onEnchant); - card.addUnEnchantCommand(onUnEnchant); - card.addChangeControllerCommand(onChangesControl); - } - - final Command onLeavesPlay = new Command() { - private static final long serialVersionUID = -639204333673364477L; - - @Override - public void execute() { - final GameEntity entity = card.getEnchanting(); - if (entity == null) { - return; - } - - card.unEnchantEntity(entity); - } - }; // Command - - card.addLeavesPlayCommand(onLeavesPlay); - card.enchantEntity(tgt); - } - */ - - private static boolean unattachAllPlayDrawbackAI(final Player ai, final AbilityFactory af, final SpellAbility sa) { - // AI should only activate this during Human's turn - boolean chance = AbilityFactoryAttach.unattachAllCanPlayAI(ai, af, sa); - - final AbilitySub subAb = sa.getSubAbility(); - if (subAb != null) { - chance &= subAb.chkAIDrawback(); - } - - return chance; - } + } diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryCleanup.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryCleanup.java deleted file mode 100644 index 7197a4e6c8c..00000000000 --- a/src/main/java/forge/card/abilityfactory/AbilityFactoryCleanup.java +++ /dev/null @@ -1,124 +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.Map; - -import forge.Card; -import forge.Singletons; -import forge.card.cardfactory.CardFactoryUtil; -import forge.card.spellability.AbilitySub; -import forge.card.spellability.SpellAbility; -import forge.card.spellability.Target; - -// Cleanup is not the same as other AFs, it is only used as a Drawback, and only used to Cleanup particular card states -// That need to be reset. I'm creating this to clear Remembered Cards at the -// end of an Effect so they don't get shown on a card -// After the effect finishes resolving. -/** - *

- * AbilityFactory_Cleanup class. - *

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

- * getDrawback. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.AbilitySub} object. - */ - public static AbilitySub getDrawback(final AbilityFactory af) { - class DrawbackCleanup extends AbilitySub { - public DrawbackCleanup(final Card ca, final Target t) { - super(ca, t); - } - - @Override - public AbilitySub getCopy() { - AbilitySub res = new DrawbackCleanup(getSourceCard(), - getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = 6192972525033429820L; - - @Override - public boolean chkAIDrawback() { - return true; - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return true; - } - - @Override - public void resolve() { - AbilityFactoryCleanup.doResolve(af, this); - } - } - final AbilitySub drawback = new DrawbackCleanup(af.getHostCard(), af.getAbTgt()); - - return drawback; - } - - /** - *

- * doResolve. - *

- * - * @param AF - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - */ - private static void doResolve(final AbilityFactory af, final SpellAbility sa) { - final Map params = af.getMapParams(); - Card source = sa.getSourceCard(); - - if (params.containsKey("ClearRemembered")) { - source.clearRemembered(); - Singletons.getModel().getGame().getCardState(source).clearRemembered(); - } - if (params.containsKey("ClearImprinted")) { - source.clearImprinted(); - } - if (params.containsKey("ClearChosenX")) { - source.setSVar("ChosenX", ""); - } - if (params.containsKey("ClearChosenY")) { - source.setSVar("ChosenY", ""); - } - if (params.containsKey("ClearTriggered")) { - Singletons.getModel().getGame().getTriggerHandler().clearDelayedTrigger(source); - } - } - -} // end class AbilityFactory_Cleanup diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryStoreSVar.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryStoreSVar.java deleted file mode 100644 index 4455814f59d..00000000000 --- a/src/main/java/forge/card/abilityfactory/AbilityFactoryStoreSVar.java +++ /dev/null @@ -1,352 +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.Map; - -import forge.Card; -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.cost.Cost; -import forge.card.spellability.Target; -import forge.game.phase.CombatUtil; -import forge.game.player.ComputerUtil; -import forge.game.player.Player; - -/** - *

- * AbilityFactoryStoreSVar class. - *

- * - * @author Forge - * @version $Id: AbilityFactoryStoreSVar.java 15090 2012-04-07 12:50:31Z Max mtg $ - */ -public class AbilityFactoryStoreSVar { - /** - *

- * createAbilityStoreSVar. - *

- * - * @param abilityFactory - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - */ - public static SpellAbility createAbilityStoreSVar(final AbilityFactory abilityFactory) { - class AbilityStoreSVar extends AbilityActivated { - public AbilityStoreSVar(final Card ca, final Cost co, final Target t) { - super(ca, co, t); - } - - @Override - public AbilityActivated getCopy() { - AbilityActivated res = new AbilityStoreSVar(getSourceCard(), - getPayCosts(), getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = -7299561150243337080L; - private final AbilityFactory af = abilityFactory; - - @Override - public String getStackDescription() { - return AbilityFactoryStoreSVar.storeSVarStackDescription(this.af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryStoreSVar.storeSVarCanPlayAI(this.af, this); - } - - @Override - public void resolve() { - AbilityFactoryStoreSVar.storeSVarResolve(this.af, this); - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryStoreSVar.storeSVarDoTriggerAI(getActivatingPlayer(), this.af, this, mandatory); - } - } - final SpellAbility abStoreSVar = new AbilityStoreSVar(abilityFactory.getHostCard(), abilityFactory.getAbCost(), - abilityFactory.getAbTgt()); - return abStoreSVar; - } - - /** - *

- * createSpellStoreSVar. - *

- * - * @param abilityFactory - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - */ - public static SpellAbility createSpellStoreSVar(final AbilityFactory abilityFactory) { - final SpellAbility spStoreSVar = new Spell(abilityFactory.getHostCard(), abilityFactory.getAbCost(), - abilityFactory.getAbTgt()) { - private static final long serialVersionUID = 6631124959690157874L; - - private final AbilityFactory af = abilityFactory; - - @Override - public String getStackDescription() { - // when getStackDesc is called, just build exactly what is - // happening - return AbilityFactoryStoreSVar.storeSVarStackDescription(this.af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryStoreSVar.storeSVarCanPlayAI(this.af, this); - } - - @Override - public void resolve() { - AbilityFactoryStoreSVar.storeSVarResolve(this.af, this); - } - - }; - return spStoreSVar; - } - - /** - *

- * createDrawbackStoreSVar. - *

- * - * @param abilityFactory - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @return a {@link forge.card.spellability.SpellAbility} object. - */ - public static SpellAbility createDrawbackStoreSVar(final AbilityFactory abilityFactory) { - class DrawbackStoreSVar extends AbilitySub { - public DrawbackStoreSVar(final Card ca, final Target t) { - super(ca, t); - } - - @Override - public AbilitySub getCopy() { - AbilitySub res = new DrawbackStoreSVar(getSourceCard(), - getTarget() == null ? null : new Target(getTarget())); - CardFactoryUtil.copySpellAbility(this, res); - return res; - } - - private static final long serialVersionUID = 6631124959690157874L; - - private final AbilityFactory af = abilityFactory; - - @Override - public String getStackDescription() { - // when getStackDesc is called, just build exactly what is - // happening - return AbilityFactoryStoreSVar.storeSVarStackDescription(this.af, this); - } - - @Override - public boolean canPlayAI() { - return AbilityFactoryStoreSVar.storeSVarCanPlayAI(this.af, this); - } - - @Override - public void resolve() { - AbilityFactoryStoreSVar.storeSVarResolve(this.af, this); - } - - @Override - public boolean chkAIDrawback() { - boolean randomReturn = true; - final AbilitySub subAb = this.getSubAbility(); - if (subAb != null) { - randomReturn &= subAb.chkAIDrawback(); - } - - return randomReturn; - } - - @Override - public boolean doTrigger(final boolean mandatory) { - return AbilityFactoryStoreSVar.storeSVarDoTriggerAI(getActivatingPlayer(), this.af, this, mandatory); - } - } - final SpellAbility dbStoreSVar = new DrawbackStoreSVar(abilityFactory.getHostCard(), abilityFactory.getAbTgt()); - - return dbStoreSVar; - } - - /** - *

- * storeSVarStackDescription. - *

- * - * @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 storeSVarStackDescription(final AbilityFactory af, final SpellAbility sa) { - final Map params = af.getMapParams(); - - final StringBuilder sb = new StringBuilder(); - - if (sa instanceof AbilitySub) { - sb.append(" "); - } else { - sb.append(sa.getSourceCard().getName()).append(" - "); - } - - if (params.containsKey("StackDescription")) { - sb.append(params.get("StackDescription").replaceAll("CARDNAME", sa.getSourceCard().getName())); - return sb.toString(); - } - - sb.append(sa.getDescription()); - - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - sb.append(abSub.getStackDescription()); - } - - return sb.toString(); - } - - /** - *

- * storeSVarCanPlayAI. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @return a boolean. - */ - public static boolean storeSVarCanPlayAI(final AbilityFactory af, final SpellAbility sa) { - //Tree of Redemption - final Player ai = sa.getActivatingPlayer(); - final Card source = sa.getSourceCard(); - if (ComputerUtil.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetDefense() - || (ai.getLife() > 5 && !CombatUtil.lifeInSeriousDanger(ai, Singletons.getModel().getGame().getCombat()))) { - return false; - } - final AbilitySub subAb = sa.getSubAbility(); - if (subAb != null && !subAb.chkAIDrawback()) { - return false; - } - - return true; - } - - /** - *

- * storeSVarDoTriggerAI. - *

- * - * @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 storeSVarDoTriggerAI(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) { - if (!ComputerUtil.canPayCost(sa, ai) && !mandatory) { - // payment it's usually - // not mandatory - return false; - } - - // check SubAbilities DoTrigger? - final AbilitySub abSub = sa.getSubAbility(); - if (abSub != null) { - return abSub.doTrigger(mandatory); - } - - return true; - } - - /** - *

- * storeSVarResolve. - *

- * - * @param af - * a {@link forge.card.abilityfactory.AbilityFactory} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - */ - public static void storeSVarResolve(final AbilityFactory af, final SpellAbility sa) { - //SVar$ OldToughness | Type$ Count | Expression$ CardToughness - final Map params = af.getMapParams(); - Card source = sa.getSourceCard(); - - String key = null; - String type = null; - String expr = null; - - if (params.containsKey("SVar")) { - key = params.get("SVar"); - } - - if (params.containsKey("Type")) { - type = params.get("Type"); - } - - if (params.containsKey("Expression")) { - expr = params.get("Expression"); - } - - if (key == null || type == null || expr == null) { - System.out.println("SVar, Type and Expression paramaters required for StoreSVar. They are missing for " + source.getName()); - return; - } - - int value = 0; - - if (type.equals("Count")) { - value = CardFactoryUtil.xCount(source, expr); - } - else if (type.equals("Number")) { - value = Integer.valueOf(expr); - } - else if (type.equals("CountSVar")) { - value = CardFactoryUtil.xCount(source, "SVar$" + expr); - } - //TODO For other types call a different function - - StringBuilder numBuilder = new StringBuilder(); - numBuilder.append("Number$"); - numBuilder.append(value); - - source.setSVar(key, numBuilder.toString()); - - SpellAbility root = sa.getRootSpellAbility(); - while(root != null) { - root.setSVar(key, numBuilder.toString()); - root = root.getSubAbility(); - } - } - -} // end class AbilityFactorystoreSVar diff --git a/src/main/java/forge/card/abilityfactory/CleanUpEffect.java b/src/main/java/forge/card/abilityfactory/CleanUpEffect.java new file mode 100644 index 00000000000..9dba5c79450 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/CleanUpEffect.java @@ -0,0 +1,36 @@ +package forge.card.abilityfactory; + +import java.util.Map; + +import forge.Card; +import forge.Singletons; +import forge.card.spellability.SpellAbility; + +public class CleanUpEffect extends SpellEffect { + + /* (non-Javadoc) + * @see forge.card.abilityfactory.SpellEffect#resolve(java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + public void resolve(Map params, SpellAbility sa) { + Card source = sa.getSourceCard(); + + if (params.containsKey("ClearRemembered")) { + source.clearRemembered(); + Singletons.getModel().getGame().getCardState(source).clearRemembered(); + } + if (params.containsKey("ClearImprinted")) { + source.clearImprinted(); + } + if (params.containsKey("ClearChosenX")) { + source.setSVar("ChosenX", ""); + } + if (params.containsKey("ClearChosenY")) { + source.setSVar("ChosenY", ""); + } + if (params.containsKey("ClearTriggered")) { + Singletons.getModel().getGame().getTriggerHandler().clearDelayedTrigger(source); + } + } + +} // end class AbilityFactory_Cleanup \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/CommonAbility.java b/src/main/java/forge/card/abilityfactory/CommonAbility.java index 1f4cd49d68a..36b807379a0 100644 --- a/src/main/java/forge/card/abilityfactory/CommonAbility.java +++ b/src/main/java/forge/card/abilityfactory/CommonAbility.java @@ -58,11 +58,10 @@ public class CommonAbility extends AbilityActivated { @Override public boolean canPlayAI() { return ai.canPlayAI(getActivatingPlayer(), params, this); - } + } @Override public boolean doTrigger(final boolean mandatory) { return ai.doTriggerAI(this.getActivatingPlayer(), params, this, mandatory); } - } \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/ai/ChangeZoneAllAi.java b/src/main/java/forge/card/abilityfactory/ai/ChangeZoneAllAi.java new file mode 100644 index 00000000000..9e80c738a92 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/ai/ChangeZoneAllAi.java @@ -0,0 +1,297 @@ +package forge.card.abilityfactory.ai; + +import java.util.List; +import java.util.Map; +import java.util.Random; + +import forge.Card; +import forge.CardLists; +import forge.Singletons; +import forge.card.abilityfactory.AbilityFactory; +import forge.card.abilityfactory.SpellAiLogic; +import forge.card.cardfactory.CardFactoryUtil; +import forge.card.cost.Cost; +import forge.card.cost.CostUtil; +import forge.card.spellability.AbilitySub; +import forge.card.spellability.SpellAbility; +import forge.card.spellability.Target; +import forge.game.phase.PhaseType; +import forge.game.player.Player; +import forge.game.zone.ZoneType; +import forge.util.MyRandom; + +public class ChangeZoneAllAi 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) { + // Change Zone All, can be any type moving from one zone to another + final Cost abCost = sa.getAbilityFactory().getAbCost(); + final Card source = sa.getSourceCard(); + final ZoneType destination = ZoneType.smartValueOf(params.get("Destination")); + final ZoneType origin = ZoneType.smartValueOf(params.get("Origin")); + + if (abCost != null) { + // AI currently disabled for these costs + if (!CostUtil.checkLifeCost(ai, abCost, source, 4, null)) { + return false; + } + + if (!CostUtil.checkDiscardCost(ai, abCost, source)) { + return false; + } + + } + + final Random r = MyRandom.getRandom(); + // prevent run-away activations - first time will always return true + boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); + + // TODO targeting with ChangeZoneAll + // really two types of targeting. + // Target Player has all their types change zones + // or target permanent and do something relative to that permanent + // ex. "Return all Auras attached to target" + // ex. "Return all blocking/blocked by target creature" + + final Player opp = ai.getOpponent(); + final List humanType = AbilityFactory.filterListByType(opp.getCardsIn(origin), params.get("ChangeType"), sa); + List computerType = ai.getCardsIn(origin); + computerType = AbilityFactory.filterListByType(computerType, params.get("ChangeType"), sa); + final Target tgt = sa.getTarget(); + + // TODO improve restrictions on when the AI would want to use this + // spBounceAll has some AI we can compare to. + if (origin.equals(ZoneType.Hand) || origin.equals(ZoneType.Library)) { + if (tgt != null) { + if (opp.getCardsIn(ZoneType.Hand).isEmpty() + || !opp.canBeTargetedBy(sa)) { + return false; + } + tgt.resetTargets(); + tgt.addTarget(opp); + } + } else if (origin.equals(ZoneType.Battlefield)) { + // this statement is assuming the AI is trying to use this spell + // offensively + // if the AI is using it defensively, then something else needs to + // occur + // if only creatures are affected evaluate both lists and pass only + // if human creatures are more valuable + if (tgt != null) { + if (opp.getCardsIn(ZoneType.Hand).isEmpty() + || !opp.canBeTargetedBy(sa)) { + return false; + } + tgt.resetTargets(); + tgt.addTarget(opp); + computerType.clear(); + } + if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) { + if ((CardFactoryUtil.evaluateCreatureList(computerType) + 200) >= CardFactoryUtil + .evaluateCreatureList(humanType)) { + return false; + } + } // otherwise evaluate both lists by CMC and pass only if human + // permanents are more valuable + else if ((CardFactoryUtil.evaluatePermanentList(computerType) + 3) >= CardFactoryUtil + .evaluatePermanentList(humanType)) { + return false; + } + + // Don't cast during main1? + if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.MAIN1, ai)) { + return false; + } + } else if (origin.equals(ZoneType.Graveyard)) { + if (tgt != null) { + if (opp.getCardsIn(ZoneType.Graveyard).isEmpty() + || !opp.canBeTargetedBy(sa)) { + return false; + } + tgt.resetTargets(); + tgt.addTarget(opp); + } + } else if (origin.equals(ZoneType.Exile)) { + + } else if (origin.equals(ZoneType.Stack)) { + // time stop can do something like this: + // Origin$ Stack | Destination$ Exile | SubAbility$ DBSkip + // DBSKipToPhase | DB$SkipToPhase | Phase$ Cleanup + // otherwise, this situation doesn't exist + return false; + } + + if (destination.equals(ZoneType.Battlefield)) { + if (params.get("GainControl") != null) { + // Check if the cards are valuable enough + if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) { + if ((CardFactoryUtil.evaluateCreatureList(computerType) + CardFactoryUtil + .evaluateCreatureList(humanType)) < 400) { + return false; + } + } // otherwise evaluate both lists by CMC and pass only if human + // permanents are less valuable + else if ((CardFactoryUtil.evaluatePermanentList(computerType) + CardFactoryUtil + .evaluatePermanentList(humanType)) < 6) { + return false; + } + } else { + // don't activate if human gets more back than AI does + if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) { + if (CardFactoryUtil.evaluateCreatureList(computerType) <= (CardFactoryUtil + .evaluateCreatureList(humanType) + 100)) { + return false; + } + } // otherwise evaluate both lists by CMC and pass only if human + // permanents are less valuable + else if (CardFactoryUtil.evaluatePermanentList(computerType) <= (CardFactoryUtil + .evaluatePermanentList(humanType) + 2)) { + return false; + } + } + } + + final AbilitySub subAb = sa.getSubAbility(); + if (subAb != null) { + chance &= subAb.chkAIDrawback(); + } + + return (((r.nextFloat() < .8) || sa.isTrigger()) && chance); + } + + /** + *

+ * changeZoneAllPlayDrawbackAI. + *

+ * + * @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 aiPlayer) { + // if putting cards from hand to library and parent is drawing cards + // make sure this will actually do something: + + return true; + } + + + /** + *

+ * gainLifeDoTriggerAINoCost. + *

+ * + * @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 ai, java.util.Map params, SpellAbility sa, boolean mandatory) { + // Change Zone All, can be any type moving from one zone to another + + final ZoneType destination = ZoneType.smartValueOf(params.get("Destination")); + final ZoneType origin = ZoneType.smartValueOf(params.get("Origin")); + + final Player opp = ai.getOpponent(); + final List humanType = AbilityFactory.filterListByType(opp.getCardsIn(origin), params.get("ChangeType"), sa); + List computerType = ai.getCardsIn(origin); + computerType = AbilityFactory.filterListByType(computerType, params.get("ChangeType"), sa); + + // TODO improve restrictions on when the AI would want to use this + // spBounceAll has some AI we can compare to. + if (origin.equals(ZoneType.Hand) || origin.equals(ZoneType.Library)) { + final Target tgt = sa.getTarget(); + if (tgt != null) { + if (opp.getCardsIn(ZoneType.Hand).isEmpty() + || !opp.canBeTargetedBy(sa)) { + return false; + } + tgt.resetTargets(); + tgt.addTarget(opp); + } + } else if (origin.equals(ZoneType.Battlefield)) { + // this statement is assuming the AI is trying to use this spell offensively + // if the AI is using it defensively, then something else needs to occur + // if only creatures are affected evaluate both lists and pass only + // if human creatures are more valuable + if ((CardLists.getNotType(humanType, "Creature").isEmpty()) && (CardLists.getNotType(computerType, "Creature").isEmpty())) { + if (CardFactoryUtil.evaluateCreatureList(computerType) >= CardFactoryUtil + .evaluateCreatureList(humanType)) { + return false; + } + } // otherwise evaluate both lists by CMC and pass only if human + // permanents are more valuable + else if (CardFactoryUtil.evaluatePermanentList(computerType) >= CardFactoryUtil + .evaluatePermanentList(humanType)) { + return false; + } + } else if (origin.equals(ZoneType.Graveyard)) { + final Target tgt = sa.getTarget(); + if (tgt != null) { + if (opp.getCardsIn(ZoneType.Graveyard).isEmpty() + || !opp.canBeTargetedBy(sa)) { + return false; + } + tgt.resetTargets(); + tgt.addTarget(opp); + } + } else if (origin.equals(ZoneType.Exile)) { + + } else if (origin.equals(ZoneType.Stack)) { + // time stop can do something like this: + // Origin$ Stack | Destination$ Exile | SubAbility$ DBSkip + // DBSKipToPhase | DB$SkipToPhase | Phase$ Cleanup + // otherwise, this situation doesn't exist + return false; + } + + if (destination.equals(ZoneType.Battlefield)) { + if (params.get("GainControl") != null) { + // Check if the cards are valuable enough + if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) { + if ((CardFactoryUtil.evaluateCreatureList(computerType) + CardFactoryUtil + .evaluateCreatureList(humanType)) < 1) { + return false; + } + } // otherwise evaluate both lists by CMC and pass only if human + // permanents are less valuable + else if ((CardFactoryUtil.evaluatePermanentList(computerType) + CardFactoryUtil + .evaluatePermanentList(humanType)) < 1) { + return false; + } + } else { + // don't activate if human gets more back than AI does + if ((CardLists.getNotType(humanType, "Creature").isEmpty()) && (CardLists.getNotType(computerType, "Creature").isEmpty())) { + if (CardFactoryUtil.evaluateCreatureList(computerType) <= CardFactoryUtil + .evaluateCreatureList(humanType)) { + return false; + } + } // otherwise evaluate both lists by CMC and pass only if human + // permanents are less valuable + else if (CardFactoryUtil.evaluatePermanentList(computerType) <= CardFactoryUtil + .evaluatePermanentList(humanType)) { + return false; + } + } + } + + boolean chance = true; + final AbilitySub subAb = sa.getSubAbility(); + if (subAb != null) { + chance &= subAb.chkAIDrawback(); + } + + return chance; + } + +} \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/ai/StoreSVarAi.java b/src/main/java/forge/card/abilityfactory/ai/StoreSVarAi.java new file mode 100644 index 00000000000..b0a2b0b5d37 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/ai/StoreSVarAi.java @@ -0,0 +1,50 @@ +package forge.card.abilityfactory.ai; + +import forge.Card; +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.player.ComputerUtil; +import forge.game.player.Player; + +public class StoreSVarAi extends SpellAiLogic { + + @Override + public boolean canPlayAI(Player ai, java.util.Map params, SpellAbility sa) { + //Tree of Redemption + + final Card source = sa.getSourceCard(); + if (ComputerUtil.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetDefense() + || (ai.getLife() > 5 && !CombatUtil.lifeInSeriousDanger(ai, Singletons.getModel().getGame().getCombat()))) { + return false; + } + final AbilitySub subAb = sa.getSubAbility(); + if (subAb != null && !subAb.chkAIDrawback()) { + return false; + } + + return true; + } + + @Override + public boolean chkAIDrawback(java.util.Map params, SpellAbility sa, Player aiPlayer) { + return true; + }; + + + + @Override + public boolean doTriggerAINoCost(Player aiPlayer, java.util.Map params, SpellAbility sa, boolean mandatory) { + + // check SubAbilities DoTrigger? + final AbilitySub abSub = sa.getSubAbility(); + if (abSub != null) { + return abSub.doTrigger(mandatory); + } + + return true; + } + +} \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/ai/UnattachAllAi.java b/src/main/java/forge/card/abilityfactory/ai/UnattachAllAi.java new file mode 100644 index 00000000000..d87f237eb94 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/ai/UnattachAllAi.java @@ -0,0 +1,124 @@ +package forge.card.abilityfactory.ai; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Random; + +import forge.Card; +import forge.Singletons; +import forge.card.abilityfactory.AbilityFactory; +import forge.card.abilityfactory.SpellAiLogic; +import forge.card.cardfactory.CardFactoryUtil; +import forge.card.cost.Cost; +import forge.card.spellability.AbilitySub; +import forge.card.spellability.SpellAbility; +import forge.card.spellability.Target; +import forge.game.phase.PhaseType; +import forge.game.player.ComputerUtil; +import forge.game.player.Player; +import forge.util.MyRandom; + +public class UnattachAllAi 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) { + final Random r = MyRandom.getRandom(); + final Cost abCost = sa.getPayCosts(); + final Card source = sa.getSourceCard(); + + if (abCost != null) { + // No Aura spells have Additional Costs + } + + // prevent run-away activations - first time will always return true + boolean chance = r.nextFloat() <= .9; + + // Attach spells always have a target + final Target tgt = sa.getTarget(); + if (tgt != null) { + tgt.resetTargets(); + } + + if (abCost != null && abCost.getTotalMana().contains("X") && source.getSVar("X").equals("Count$xPaid")) { + final int xPay = ComputerUtil.determineLeftoverMana(sa, ai); + + if (xPay == 0) { + return false; + } + + source.setSVar("PayX", Integer.toString(xPay)); + } + + if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) + && !"Curse".equals(params.get("AILogic"))) { + return false; + } + + return chance; + } + + + /* (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 ai, Map params, SpellAbility sa, boolean mandatory) { + final Card card = sa.getSourceCard(); + final Player opp = ai.getOpponent(); + // Check if there are any valid targets + ArrayList targets = new ArrayList(); + final Target tgt = sa.getTarget(); + if (tgt == null) { + targets = AbilityFactory.getDefinedObjects(sa.getSourceCard(), params.get("Defined"), sa); + } + + if (!mandatory && card.isEquipment() && !targets.isEmpty()) { + Card newTarget = (Card) targets.get(0); + //don't equip human creatures + if (newTarget.getController().equals(opp)) { + return false; + } + + //don't equip a worse creature + if (card.isEquipping()) { + Card oldTarget = card.getEquipping().get(0); + if (CardFactoryUtil.evaluateCreature(oldTarget) > CardFactoryUtil.evaluateCreature(newTarget)) { + return false; + } + } + } + + // check SubAbilities DoTrigger? + final AbilitySub abSub = sa.getSubAbility(); + if (abSub != null) { + return abSub.doTrigger(mandatory); + } + + return true; + } + + + + + + @Override + public boolean chkAIDrawback(java.util.Map params, SpellAbility sa, Player ai) { + // AI should only activate this during Human's turn + return canPlayAI(ai, params, sa); + } + + /** + * UnattachAll stack description. + * + * @param af + * the af + * @param sa + * the sa + * @return the string + */ + +} \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/effects/ChangeZoneAllEffect.java b/src/main/java/forge/card/abilityfactory/effects/ChangeZoneAllEffect.java new file mode 100644 index 00000000000..a895d7c9880 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/effects/ChangeZoneAllEffect.java @@ -0,0 +1,134 @@ +package forge.card.abilityfactory.effects; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.Iterables; + +import forge.Card; +import forge.CardCharacteristicName; +import forge.CardPredicates; +import forge.Singletons; +import forge.card.abilityfactory.AbilityFactory; +import forge.card.abilityfactory.AbilityFactoryAttach; +import forge.card.abilityfactory.SpellEffect; +import forge.card.spellability.SpellAbility; +import forge.card.spellability.Target; +import forge.game.player.Player; +import forge.game.zone.ZoneType; + +public class ChangeZoneAllEffect extends SpellEffect { + + + /** + *

+ * changeZoneAllStackDescription. + *

+ * + * @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. + */ + @Override + protected String getStackDescription(java.util.Map params, SpellAbility sa) { + // TODO build Stack Description will need expansion as more cards are added + + final String[] desc = sa.getDescription().split(":"); + + if (desc.length > 1) { + return desc[1]; + } else { + return desc[0]; + } + } + + /** + *

+ * changeZoneAllResolve. + *

+ * + * @param af + * a {@link forge.card.abilityfactory.AbilityFactory} object. + * @param sa + * a {@link forge.card.spellability.SpellAbility} object. + */ + @Override + public void resolve(java.util.Map params, SpellAbility sa) { + final ZoneType destination = ZoneType.smartValueOf(params.get("Destination")); + final List origin = ZoneType.listValueOf(params.get("Origin")); + + List cards = null; + + ArrayList tgtPlayers = null; + + final Target tgt = sa.getTarget(); + if (tgt != null) { + tgtPlayers = tgt.getTargetPlayers(); + } else if (params.containsKey("Defined")) { + tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa); + } + + if ((tgtPlayers == null) || tgtPlayers.isEmpty()) { + cards = Singletons.getModel().getGame().getCardsIn(origin); + } else { + cards = tgtPlayers.get(0).getCardsIn(origin); + } + + cards = AbilityFactory.filterListByType(cards, params.get("ChangeType"), sa); + + if (params.containsKey("ForgetOtherRemembered")) { + sa.getSourceCard().clearRemembered(); + } + + final String remember = params.get("RememberChanged"); + + // I don't know if library position is necessary. It's here if it is, + // just in case + final int libraryPos = params.containsKey("LibraryPosition") ? Integer.parseInt(params.get("LibraryPosition")) + : 0; + for (final Card c : cards) { + if (destination.equals(ZoneType.Battlefield)) { + // Auras without Candidates stay in their current location + if (c.isAura()) { + final SpellAbility saAura = AbilityFactoryAttach.getAttachSpellAbility(c); + if (!saAura.getTarget().hasCandidates(saAura, false)) { + continue; + } + } + if (params.containsKey("Tapped")) { + c.setTapped(true); + } + } + + if (params.containsKey("GainControl")) { + c.addController(sa.getSourceCard()); + Singletons.getModel().getGame().getAction().moveToPlay(c, sa.getActivatingPlayer()); + } else { + final Card movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, c, libraryPos); + if (params.containsKey("ExileFaceDown")) { + movedCard.setState(CardCharacteristicName.FaceDown); + } + if (params.containsKey("Tapped")) { + movedCard.setTapped(true); + } + } + + if (remember != null) { + Singletons.getModel().getGame().getCardState(sa.getSourceCard()).addRemembered(c); + } + } + + // if Shuffle parameter exists, and any amount of cards were owned by + // that player, then shuffle that library + if (params.containsKey("Shuffle")) { + for( Player p : Singletons.getModel().getGame().getPlayers()) { + if (Iterables.any(cards, CardPredicates.isOwner(p))) { + p.shuffle(); + } + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/effects/StoreSVarEffect.java b/src/main/java/forge/card/abilityfactory/effects/StoreSVarEffect.java new file mode 100644 index 00000000000..8dd04cc213d --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/effects/StoreSVarEffect.java @@ -0,0 +1,73 @@ +package forge.card.abilityfactory.effects; + +import forge.Card; +import forge.card.abilityfactory.AbilityFactory; +import forge.card.abilityfactory.SpellEffect; +import forge.card.cardfactory.CardFactoryUtil; +import forge.card.spellability.SpellAbility; + +public class StoreSVarEffect extends SpellEffect { + + /** + *

+ * storeSVarResolve. + *

+ * + * @param af + * a {@link forge.card.abilityfactory.AbilityFactory} object. + * @param sa + * a {@link forge.card.spellability.SpellAbility} object. + */ + @Override + public void resolve(java.util.Map params, SpellAbility sa) { + //SVar$ OldToughness | Type$ Count | Expression$ CardToughness + Card source = sa.getSourceCard(); + + String key = null; + String type = null; + String expr = null; + + if (params.containsKey("SVar")) { + key = params.get("SVar"); + } + + if (params.containsKey("Type")) { + type = params.get("Type"); + } + + if (params.containsKey("Expression")) { + expr = params.get("Expression"); + } + + if (key == null || type == null || expr == null) { + System.out.println("SVar, Type and Expression paramaters required for StoreSVar. They are missing for " + source.getName()); + return; + } + + int value = 0; + + if (type.equals("Count")) { + value = CardFactoryUtil.xCount(source, expr); + } + else if (type.equals("Number")) { + value = Integer.valueOf(expr); + } + else if (type.equals("CountSVar")) { + value = CardFactoryUtil.xCount(source, "SVar$" + expr); + } + //TODO For other types call a different function + + StringBuilder numBuilder = new StringBuilder(); + numBuilder.append("Number$"); + numBuilder.append(value); + + source.setSVar(key, numBuilder.toString()); + + SpellAbility root = sa.getRootSpellAbility(); + while(root != null) { + root.setSVar(key, numBuilder.toString()); + root = root.getSubAbility(); + } + } + +} // end class AbilityFactorystoreSVar \ No newline at end of file diff --git a/src/main/java/forge/card/abilityfactory/effects/UnattachAllEffect.java b/src/main/java/forge/card/abilityfactory/effects/UnattachAllEffect.java new file mode 100644 index 00000000000..2d5041f86b3 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/effects/UnattachAllEffect.java @@ -0,0 +1,173 @@ +package forge.card.abilityfactory.effects; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +import forge.Card; +import forge.CardLists; +import forge.GameEntity; +import forge.Singletons; +import forge.card.abilityfactory.SpellEffect; +import forge.card.spellability.SpellAbility; +import forge.card.spellability.Target; +import forge.game.player.Player; +import forge.game.zone.ZoneType; + +public class UnattachAllEffect extends SpellEffect { + + private void handleUnattachment(final GameEntity o, final Card cardToUnattach) { + + if (o instanceof Card) { + final Card c = (Card) o; + if (cardToUnattach.isAura()) { + //final boolean gainControl = "GainControl".equals(af.getMapParams().get("AILogic")); + //AbilityFactoryAttach.handleUnattachAura(cardToUnattach, c, gainControl); + } else if (cardToUnattach.isEquipment()) { + if (cardToUnattach.isEquipping() && c.getEquippedBy().contains(cardToUnattach)) { + cardToUnattach.unEquipCard(cardToUnattach.getEquipping().get(0)); + } + //TODO - unfortify would also be handled here + } + } else if (o instanceof Player) { + final Player p = (Player) o; + if (cardToUnattach.isAura() && p.getEnchantedBy().contains(cardToUnattach)) { + //AbilityFactoryAttach.handleUnattachAura(cardToUnattach, p, false); + } + } + } + + /* this isn't modifed to handled unattach yet, but should be for things like Remove Enchantments, etc. + private static void handleUnattachAura(final Card card, final GameEntity tgt, final boolean gainControl) { + if (card.isEnchanting()) { + // If this Card is already Enchanting something + // Need to unenchant it, then clear out the commands + final GameEntity oldEnchanted = card.getEnchanting(); + card.removeEnchanting(oldEnchanted); + card.clearEnchantCommand(); + card.clearUnEnchantCommand(); + card.clearTriggers(); // not sure if cleartriggers is needed? + } + + if (gainControl) { + // Handle GainControl Auras + final Player[] pl = new Player[1]; + + if (tgt instanceof Card) { + pl[0] = ((Card) tgt).getController(); + } else { + pl[0] = (Player) tgt; + } + + final Command onEnchant = new Command() { + private static final long serialVersionUID = -2519887209491512000L; + + @Override + public void execute() { + final Card crd = card.getEnchantingCard(); + if (crd == null) { + return; + } + + pl[0] = crd.getController(); + + crd.addController(card); + + } // execute() + }; // Command + + final Command onUnEnchant = new Command() { + private static final long serialVersionUID = 3426441132121179288L; + + @Override + public void execute() { + final Card crd = card.getEnchantingCard(); + if (crd == null) { + return; + } + + if (AllZoneUtil.isCardInPlay(crd)) { + crd.removeController(card); + } + + } // execute() + }; // Command + + final Command onChangesControl = new Command() { + private static final long serialVersionUID = -65903786170234039L; + + @Override + public void execute() { + final Card crd = card.getEnchantingCard(); + if (crd == null) { + return; + } + crd.removeController(card); // This looks odd, but will + // simply refresh controller + crd.addController(card); + } // execute() + }; // Command + + // Add Enchant Commands for Control changers + card.addEnchantCommand(onEnchant); + card.addUnEnchantCommand(onUnEnchant); + card.addChangeControllerCommand(onChangesControl); + } + + final Command onLeavesPlay = new Command() { + private static final long serialVersionUID = -639204333673364477L; + + @Override + public void execute() { + final GameEntity entity = card.getEnchanting(); + if (entity == null) { + return; + } + + card.unEnchantEntity(entity); + } + }; // Command + + card.addLeavesPlayCommand(onLeavesPlay); + card.enchantEntity(tgt); + } + */ + + /* (non-Javadoc) + * @see forge.card.abilityfactory.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + protected String getStackDescription(Map params, SpellAbility sa) { + final StringBuilder sb = new StringBuilder(); + sb.append("Unattach all valid Equipment and Auras from "); + final List targets = getTargetObjects(sa, params); + sb.append(StringUtils.join(targets, " ")); + return sb.toString(); + } + + /* (non-Javadoc) + * @see forge.card.abilityfactory.SpellEffect#resolve(java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + public void resolve(Map params, SpellAbility sa) { + Card source = sa.getSourceCard(); + + final Target tgt = sa.getTarget(); + final List targets = getTargetObjects(sa, params); + + + + // If Cast Targets will be checked on the Stack + for (final Object o : targets) { + if (!( o instanceof GameEntity )) continue; + + String valid = params.get("UnattachValid"); + List unattachList = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield); + unattachList = CardLists.getValidCards(unattachList, valid.split(","), source.getController(), source); + for (final Card c : unattachList) { + handleUnattachment((GameEntity)o, c); + } + } + } +} \ No newline at end of file