diff --git a/.gitattributes b/.gitattributes
index 9e4f96746d8..df9a911a856 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -12490,7 +12490,6 @@ src/main/java/forge/card/abilityfactory/AbilityFactoryReveal.java svneol=native#
src/main/java/forge/card/abilityfactory/AbilityFactorySacrifice.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/AbilityFactorySetState.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/AbilityFactoryStoreSVar.java -text
-src/main/java/forge/card/abilityfactory/AbilityFactoryZoneAffecting.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/SpellAiLogic.java -text
src/main/java/forge/card/abilityfactory/SpellEffect.java -text
src/main/java/forge/card/abilityfactory/UniversalAbility.java -text
@@ -12500,24 +12499,32 @@ src/main/java/forge/card/abilityfactory/ai/AddTurnAi.java svneol=native#text/pla
src/main/java/forge/card/abilityfactory/ai/AnimateAi.java -text
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/DiscardAi.java -text
+src/main/java/forge/card/abilityfactory/ai/DrawAi.java svneol=native#text/plain
+src/main/java/forge/card/abilityfactory/ai/EndTurnAi.java -text
src/main/java/forge/card/abilityfactory/ai/ExchangeLifeAi.java -text
src/main/java/forge/card/abilityfactory/ai/GainLifeAi.java -text
src/main/java/forge/card/abilityfactory/ai/LoseLifeAi.java -text
+src/main/java/forge/card/abilityfactory/ai/MillAi.java -text
src/main/java/forge/card/abilityfactory/ai/PoisonAi.java -text
src/main/java/forge/card/abilityfactory/ai/SetLifeAi.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
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/BondEffect.java -text
-src/main/java/forge/card/abilityfactory/effects/EndTurnAi.java -text
+src/main/java/forge/card/abilityfactory/effects/DiscardEffect.java -text
+src/main/java/forge/card/abilityfactory/effects/DrawEffect.java -text
src/main/java/forge/card/abilityfactory/effects/EndTurnEffect.java -text
src/main/java/forge/card/abilityfactory/effects/ExchangeLifeEffect.java -text
src/main/java/forge/card/abilityfactory/effects/GainLifeEffect.java -text
src/main/java/forge/card/abilityfactory/effects/HelperAnimate.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/effects/LoseLifeEffect.java -text
+src/main/java/forge/card/abilityfactory/effects/MillEffect.java -text
src/main/java/forge/card/abilityfactory/effects/PoisonEffect.java -text
src/main/java/forge/card/abilityfactory/effects/SetLifeEffect.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
src/main/java/forge/card/cardfactory/CardFactory.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 23d3c39e3d3..9858fca7580 100644
--- a/src/main/java/forge/card/abilityfactory/AbilityFactory.java
+++ b/src/main/java/forge/card/abilityfactory/AbilityFactory.java
@@ -21,8 +21,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import org.apache.tools.ant.types.resources.Tokens;
-
import forge.Card;
import forge.CardLists;
@@ -215,17 +213,6 @@ public class AbilityFactory {
return this.abTgt;
}
- /**
- *
- * Setter for the field abTgt.
- *
- *
- * @param target
- * a target object.
- */
- public final void setAbTgt(final Target target) {
- this.abTgt = target;
- }
/**
*
@@ -707,13 +694,8 @@ public class AbilityFactory {
}
else if (this.api.equals("Discard")) {
- if (this.isAb) {
- spellAbility = AbilityFactoryZoneAffecting.createAbilityDiscard(this);
- } else if (this.isSp) {
- spellAbility = AbilityFactoryZoneAffecting.createSpellDiscard(this);
- } else if (this.isDb) {
- spellAbility = AbilityFactoryZoneAffecting.createDrawbackDiscard(this);
- }
+ ai = new DiscardAi();
+ se = new DiscardEffect();
}
else if (this.api.equals("DrainMana")) {
@@ -727,13 +709,8 @@ public class AbilityFactory {
}
else if (this.api.equals("Draw")) {
- if (this.isAb) {
- spellAbility = AbilityFactoryZoneAffecting.createAbilityDraw(this);
- } else if (this.isSp) {
- spellAbility = AbilityFactoryZoneAffecting.createSpellDraw(this);
- } else if (this.isDb) {
- spellAbility = AbilityFactoryZoneAffecting.createDrawbackDraw(this);
- }
+ ai = new DrawAi();
+ se = new DrawEffect();
}
else if (this.api.equals("EachDamage")) {
@@ -875,13 +852,8 @@ public class AbilityFactory {
}
else if (this.api.equals("Mill")) {
- if (this.isAb) {
- spellAbility = AbilityFactoryZoneAffecting.createAbilityMill(this);
- } else if (this.isSp) {
- spellAbility = AbilityFactoryZoneAffecting.createSpellMill(this);
- } else if (this.isDb) {
- spellAbility = AbilityFactoryZoneAffecting.createDrawbackMill(this);
- }
+ ai = new MillAi();
+ se = new MillEffect();
}
else if (this.api.equals("MoveCounter")) {
@@ -1189,13 +1161,8 @@ public class AbilityFactory {
}
else if (this.api.equals("Shuffle")) {
- if (this.isAb) {
- spellAbility = AbilityFactoryZoneAffecting.createAbilityShuffle(this);
- } else if (this.isSp) {
- spellAbility = AbilityFactoryZoneAffecting.createSpellShuffle(this);
- } else if (this.isDb) {
- spellAbility = AbilityFactoryZoneAffecting.createDrawbackShuffle(this);
- }
+ ai = new ShuffleAi();
+ se = new ShuffleEffect();
}
else if (this.api.equals("StoreSVar")) {
diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryZoneAffecting.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryZoneAffecting.java
deleted file mode 100644
index 972a7b7cdae..00000000000
--- a/src/main/java/forge/card/abilityfactory/AbilityFactoryZoneAffecting.java
+++ /dev/null
@@ -1,2122 +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.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Random;
-
-import com.google.common.base.Predicate;
-
-import forge.Card;
-
-import forge.CardLists;
-import forge.CardUtil;
-import forge.GameActionUtil;
-import forge.Singletons;
-import forge.card.cardfactory.CardFactoryUtil;
-import forge.card.cost.Cost;
-import forge.card.cost.CostDiscard;
-import forge.card.cost.CostPart;
-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.PhaseType;
-import forge.game.player.ComputerUtil;
-import forge.game.player.Player;
-import forge.game.zone.ZoneType;
-import forge.gui.GuiChoose;
-import forge.util.MyRandom;
-
-/**
- *
- * AbilityFactory_ZoneAffecting class.
- *
- *
- * @author Forge
- * @version $Id$
- */
-public class AbilityFactoryZoneAffecting {
-
- // **********************************************************************
- // ******************************* DRAW *********************************
- // **********************************************************************
- /**
- *
- * createAbilityDraw.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createAbilityDraw(final AbilityFactory af) {
- class AbilityDraw extends AbilityActivated {
- public AbilityDraw(final Card ca, final Cost co, final Target t) {
- super(ca, co, t);
- }
-
- @Override
- public AbilityActivated getCopy() {
- AbilityActivated res = new AbilityDraw(getSourceCard(),
- getPayCosts(), getTarget() == null ? null : new Target(getTarget()));
- CardFactoryUtil.copySpellAbility(this, res);
- return res;
- }
-
- private static final long serialVersionUID = 5445572699000471299L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.drawStackDescription(af, this);
- }
-
- @Override
- public boolean canPlayAI() {
- return AbilityFactoryZoneAffecting.drawCanPlayAI(getActivatingPlayer(), af, this);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.drawResolve(af, this);
- }
-
- @Override
- public boolean doTrigger(final boolean mandatory) {
- return AbilityFactoryZoneAffecting.drawTrigger(getActivatingPlayer(), af, this, mandatory);
- }
- }
- final SpellAbility abDraw = new AbilityDraw(af.getHostCard(), af.getAbCost(), af.getAbTgt());
-
- return abDraw;
- }
-
- /**
- *
- * createSpellDraw.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createSpellDraw(final AbilityFactory af) {
- final SpellAbility spDraw = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
- private static final long serialVersionUID = -4990932993654533449L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.drawStackDescription(af, this);
- }
-
- @Override
- public boolean canPlayAI() {
- return AbilityFactoryZoneAffecting.drawCanPlayAI(getActivatingPlayer(), af, this);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.drawResolve(af, this);
- }
-
- @Override
- public boolean canPlayFromEffectAI(final boolean mandatory, final boolean withOutManaCost) {
- if (withOutManaCost) {
- return AbilityFactoryZoneAffecting.drawTriggerNoCost(getActivatingPlayer(), af, this, mandatory);
- }
- return AbilityFactoryZoneAffecting.drawTrigger(getActivatingPlayer(), af, this, mandatory);
- }
-
- };
- return spDraw;
- }
-
- /**
- *
- * createDrawbackDraw.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createDrawbackDraw(final AbilityFactory af) {
- class DrawbackDraw extends AbilitySub {
- public DrawbackDraw(final Card ca, final Target t) {
- super(ca, t);
- }
-
- @Override
- public AbilitySub getCopy() {
- AbilitySub res = new DrawbackDraw(getSourceCard(),
- getTarget() == null ? null : new Target(getTarget()));
- CardFactoryUtil.copySpellAbility(this, res);
- return res;
- }
-
- private static final long serialVersionUID = -4990932993654533449L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.drawStackDescription(af, this);
- }
-
- @Override
- public boolean canPlayAI() {
- return AbilityFactoryZoneAffecting.drawCanPlayAI(getActivatingPlayer(), af, this);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.drawResolve(af, this);
- }
-
- @Override
- public boolean chkAIDrawback() {
- return AbilityFactoryZoneAffecting.drawTargetAI(getActivatingPlayer(), af, this, false, false);
- }
-
- @Override
- public boolean doTrigger(final boolean mandatory) {
- return AbilityFactoryZoneAffecting.drawTrigger(getActivatingPlayer(), af, this, mandatory);
- }
- }
- final SpellAbility dbDraw = new DrawbackDraw(af.getHostCard(), af.getAbTgt());
-
- return dbDraw;
- }
-
- /**
- *
- * drawStackDescription.
- *
- *
- * @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.
- */
- private static String drawStackDescription(final AbilityFactory af, final SpellAbility sa) {
- final HashMap params = af.getMapParams();
- final StringBuilder sb = new StringBuilder();
-
- if (!(sa instanceof AbilitySub)) {
- sb.append(sa.getSourceCard().getName()).append(" - ");
- } else {
- sb.append(" ");
- }
-
- final String conditionDesc = params.get("ConditionDescription");
- if (conditionDesc != null) {
- sb.append(conditionDesc).append(" ");
- }
-
- ArrayList tgtPlayers;
-
- final Target tgt = sa.getTarget();
- if (!params.containsKey("Defined") && tgt != null) {
- tgtPlayers = tgt.getTargetPlayers();
- } else {
- tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
- }
-
- if (tgtPlayers.size() > 0) {
- final Iterator it = tgtPlayers.iterator();
- while (it.hasNext()) {
- sb.append(it.next().toString());
- if (it.hasNext()) {
- sb.append(" and ");
- }
- }
-
- int numCards = 1;
- if (params.containsKey("NumCards")) {
- numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
- }
-
- if (tgtPlayers.size() > 1) {
- sb.append(" each");
- }
- sb.append(" draw");
- if (tgtPlayers.size() == 1) {
- sb.append("s");
- }
- sb.append(" (").append(numCards).append(")");
-
- if (params.containsKey("NextUpkeep")) {
- sb.append(" at the beginning of the next upkeep");
- }
-
- sb.append(".");
- }
-
- final AbilitySub abSub = sa.getSubAbility();
- if (abSub != null) {
- sb.append(abSub.getStackDescription());
- }
-
- return sb.toString();
- }
-
- /**
- *
- * drawCanPlayAI.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- * @return a boolean.
- */
- private static boolean drawCanPlayAI(final Player ai, final AbilityFactory af, final SpellAbility sa) {
- final HashMap params = af.getMapParams();
-
- final Target tgt = sa.getTarget();
- final Card source = sa.getSourceCard();
- final Cost abCost = sa.getPayCosts();
-
- if (abCost != null) {
- // AI currently disabled for these costs
- if (!CostUtil.checkCreatureSacrificeCost(ai, abCost, source)) {
- return false;
- }
-
- if (!CostUtil.checkLifeCost(ai, abCost, source, 4, null)) {
- return false;
- }
-
- if (!CostUtil.checkDiscardCost(ai, abCost, source)) {
- for (final CostPart part : abCost.getCostParts()) {
- if (part instanceof CostDiscard) {
- CostDiscard cd = (CostDiscard) part;
- cd.decideAIPayment(ai, sa, sa.getSourceCard(), null);
- List discards = cd.getList();
- for (Card discard : discards) {
- if (!ComputerUtil.isWorseThanDraw(ai, discard)) {
- return false;
- }
- }
- }
- }
- }
-
- if (!CostUtil.checkRemoveCounterCost(abCost, source)) {
- return false;
- }
-
- }
-
- final boolean bFlag = AbilityFactoryZoneAffecting.drawTargetAI(ai, af, sa, true, false);
-
- if (!bFlag) {
- return false;
- }
-
- if (tgt != null) {
- final ArrayList players = tgt.getTargetPlayers();
- if ((players.size() > 0) && players.get(0).isHuman()) {
- return true;
- }
- }
-
- // Don't use draw abilities before main 2 if possible
- if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
- && !params.containsKey("ActivationPhases")) {
- return false;
- }
-
- // Don't tap creatures that may be able to block
- if (ComputerUtil.waitForBlocking(sa)) {
- return false;
- }
-
- double chance = .4; // 40 percent chance of drawing with instant speed
- // stuff
- final Random r = MyRandom.getRandom();
- boolean randomReturn = r.nextFloat() <= Math.pow(chance, sa.getActivationsThisTurn() + 1);
- if (AbilityFactory.isSorcerySpeed(sa)) {
- randomReturn = true;
- }
- if ((Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)
- && Singletons.getModel().getGame().getPhaseHandler().getNextTurn().equals(ai))) {
- randomReturn = true;
- }
-
- if (AbilityFactory.playReusable(ai, sa)) {
- randomReturn = true;
- }
-
- final AbilitySub subAb = sa.getSubAbility();
- if (subAb != null) {
- randomReturn &= subAb.chkAIDrawback();
- }
- return randomReturn;
- }
-
- /**
- *
- * drawTargetAI.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- * @param primarySA
- * a boolean.
- * @param mandatory
- * a boolean.
- * @return a boolean.
- */
- private static boolean drawTargetAI(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean primarySA,
- final boolean mandatory) {
- final Target tgt = sa.getTarget();
- final HashMap params = af.getMapParams();
- final Card source = sa.getSourceCard();
-
- Player opp = ai.getOpponent();
-
- int computerHandSize = ai.getCardsIn(ZoneType.Hand).size();
- final int humanLibrarySize = opp.getCardsIn(ZoneType.Library).size();
- final int computerLibrarySize = ai.getCardsIn(ZoneType.Library).size();
- final int computerMaxHandSize = ai.getMaxHandSize();
-
- //if a spell is used don't count the card
- if (sa.isSpell() && source.isInZone(ZoneType.Hand)) {
- computerHandSize -= 1;
- }
-
- int numCards = 1;
- if (params.containsKey("NumCards")) {
- numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
- }
-
- boolean xPaid = false;
- final String num = params.get("NumCards");
- if ((num != null) && num.equals("X") && source.getSVar(num).equals("Count$xPaid")) {
- // Set PayX here to maximum value.
- if (sa instanceof AbilitySub) {
- numCards = Integer.parseInt(source.getSVar("PayX"));
- } else {
- numCards = ComputerUtil.determineLeftoverMana(sa, ai);
- source.setSVar("PayX", Integer.toString(numCards));
- }
- xPaid = true;
- }
- //if (n)
-
- // TODO: if xPaid and one of the below reasons would fail, instead of
- // bailing
- // reduce toPay amount to acceptable level
-
- if (tgt != null) {
- // ability is targeted
- tgt.resetTargets();
-
- final boolean canTgtHuman = sa.canTarget(opp);
- final boolean canTgtComp = sa.canTarget(ai);
- boolean tgtHuman = false;
-
- if (!canTgtHuman && !canTgtComp) {
- return false;
- }
-
- if (canTgtHuman && !opp.cantLose() && (numCards >= humanLibrarySize)) {
- // Deck the Human? DO IT!
- tgt.addTarget(opp);
- return true;
- }
-
- if (numCards >= computerLibrarySize) {
- if (xPaid) {
- numCards = computerLibrarySize - 1;
- source.setSVar("PayX", Integer.toString(numCards));
- } else {
- // Don't deck your self
- if (!mandatory) {
- return false;
- }
- tgtHuman = true;
- }
- }
-
- if (((computerHandSize + numCards) > computerMaxHandSize)
- && Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().isComputer()) {
- if (xPaid) {
- numCards = computerMaxHandSize - computerHandSize;
- source.setSVar("PayX", Integer.toString(numCards));
- } else {
- // Don't draw too many cards and then risk discarding cards
- // at EOT
- if (!(params.containsKey("NextUpkeep") || (sa instanceof AbilitySub)) && !mandatory) {
- return false;
- }
- }
- }
-
- if (numCards == 0 && !mandatory) {
- return false;
- }
-
- if ((!tgtHuman || !canTgtHuman) && canTgtComp) {
- tgt.addTarget(ai);
- } else if (mandatory && canTgtHuman) {
- tgt.addTarget(opp);
- } else {
- return false;
- }
- } else {
- // TODO: consider if human is the defined player
-
- // ability is not targeted
- if (numCards >= computerLibrarySize) {
- // Don't deck yourself
- if (!mandatory) {
- return false;
- }
- }
-
- if (numCards == 0 && !mandatory) {
- return false;
- }
-
- if (((computerHandSize + numCards) > computerMaxHandSize)
- && Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().isComputer()
- && !sa.isTrigger()) {
- // Don't draw too many cards and then risk discarding cards at
- // EOT
- if (!(params.containsKey("NextUpkeep") || (sa instanceof AbilitySub)) && !mandatory) {
- return false;
- }
- }
- }
- return true;
- } // drawTargetAI()
-
- /**
- *
- * drawTrigger.
- *
- *
- * @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.
- */
- private static boolean drawTrigger(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) {
- if (!ComputerUtil.canPayCost(sa, ai)) {
- return false;
- }
- return drawTriggerNoCost(ai, af, sa, mandatory);
- }
-
- /**
- *
- * drawTriggerNoCost.
- *
- *
- * @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.
- */
- private static boolean drawTriggerNoCost(final Player ai,final AbilityFactory af, final SpellAbility sa, final boolean mandatory) {
-
- if (!AbilityFactoryZoneAffecting.drawTargetAI(ai, af, sa, false, mandatory)) {
- return false;
- }
-
- // check SubAbilities DoTrigger?
- final AbilitySub abSub = sa.getSubAbility();
- if (abSub != null) {
- return abSub.doTrigger(mandatory);
- }
-
- return true;
- }
-
- /**
- *
- * drawResolve.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- */
- private static void drawResolve(final AbilityFactory af, final SpellAbility sa) {
- final HashMap params = af.getMapParams();
-
- final Card source = sa.getSourceCard();
- int numCards = 1;
- if (params.containsKey("NumCards")) {
- numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
- }
-
- ArrayList tgtPlayers;
-
- final Target tgt = sa.getTarget();
- if (!params.containsKey("Defined") && tgt != null) {
- tgtPlayers = tgt.getTargetPlayers();
- } else {
- tgtPlayers = AbilityFactory.getDefinedPlayers(source, params.get("Defined"), sa);
- }
-
- final boolean optional = params.containsKey("OptionalDecider");
- final boolean slowDraw = params.containsKey("NextUpkeep");
-
- for (final Player p : tgtPlayers) {
- if ((tgt == null) || p.canBeTargetedBy(sa)) {
- if (optional) {
- if (p.isComputer()) {
- if (numCards >= p.getCardsIn(ZoneType.Library).size()) {
- // AI shouldn't itself
- continue;
- }
- } else {
- final StringBuilder sb = new StringBuilder();
- sb.append("Do you want to draw ").append(numCards).append(" cards(s)");
-
- if (slowDraw) {
- sb.append(" next upkeep");
- }
-
- sb.append("?");
-
- if (!GameActionUtil.showYesNoDialog(sa.getSourceCard(), sb.toString())) {
- continue;
- }
- }
- }
-
- if (slowDraw) {
- for (int i = 0; i < numCards; i++) {
- p.addSlowtripList(source);
- }
- } else {
- final List drawn = p.drawCards(numCards);
- if (params.containsKey("Reveal")) {
- GuiChoose.one("Revealing drawn cards", drawn);
- }
- if (params.containsKey("RememberDrawn")) {
- for (final Card c : drawn) {
- source.addRemembered(c);
- }
- }
-
- }
-
- }
- }
- } // drawResolve()
-
- // **********************************************************************
- // ******************************* MILL *********************************
- // **********************************************************************
-
- /**
- *
- * createAbilityMill.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createAbilityMill(final AbilityFactory af) {
- class AbilityMill extends AbilityActivated {
- public AbilityMill(final Card ca, final Cost co, final Target t) {
- super(ca, co, t);
- }
-
- @Override
- public AbilityActivated getCopy() {
- AbilityActivated res = new AbilityMill(getSourceCard(),
- getPayCosts(), getTarget() == null ? null : new Target(getTarget()));
- CardFactoryUtil.copySpellAbility(this, res);
- return res;
- }
-
- private static final long serialVersionUID = 5445572699000471299L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.millStackDescription(this, af);
- }
-
- @Override
- public boolean canPlayAI() {
- return AbilityFactoryZoneAffecting.millCanPlayAI(getActivatingPlayer(), af, this);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.millResolve(af, this);
- }
-
- @Override
- public boolean doTrigger(final boolean mandatory) {
- return AbilityFactoryZoneAffecting.millTrigger(getActivatingPlayer(), af, this, mandatory);
- }
- }
- final SpellAbility abMill = new AbilityMill(af.getHostCard(), af.getAbCost(), af.getAbTgt());
-
- return abMill;
- }
-
- /**
- *
- * createSpellMill.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createSpellMill(final AbilityFactory af) {
- final SpellAbility spMill = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
- private static final long serialVersionUID = -4990932993654533449L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.millStackDescription(this, af);
- }
-
- @Override
- public boolean canPlayAI() {
- return AbilityFactoryZoneAffecting.millCanPlayAI(getActivatingPlayer(), af, this);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.millResolve(af, this);
- }
-
- @Override
- public boolean canPlayFromEffectAI(final boolean mandatory, final boolean withOutManaCost) {
- if (withOutManaCost) {
- return AbilityFactoryZoneAffecting.millTriggerNoCost(getActivatingPlayer(), af, this, mandatory);
- }
- return AbilityFactoryZoneAffecting.millTrigger(getActivatingPlayer(), af, this, mandatory);
- }
- };
- return spMill;
- }
-
- /**
- *
- * createDrawbackMill.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createDrawbackMill(final AbilityFactory af) {
- class DrawbackMill extends AbilitySub {
- public DrawbackMill(final Card ca, final Target t) {
- super(ca, t);
- }
-
- @Override
- public AbilitySub getCopy() {
- AbilitySub res = new DrawbackMill(getSourceCard(),
- getTarget() == null ? null : new Target(getTarget()));
- CardFactoryUtil.copySpellAbility(this, res);
- return res;
- }
-
- private static final long serialVersionUID = -4990932993654533449L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.millStackDescription(this, af);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.millResolve(af, this);
- }
-
- @Override
- public boolean chkAIDrawback() {
- return AbilityFactoryZoneAffecting.millDrawback(getActivatingPlayer(), af, this);
- }
-
- @Override
- public boolean doTrigger(final boolean mandatory) {
- return AbilityFactoryZoneAffecting.millTrigger(getActivatingPlayer(), af, this, mandatory);
- }
- }
- final SpellAbility dbMill = new DrawbackMill(af.getHostCard(), af.getAbTgt());
-
- return dbMill;
- }
-
- /**
- *
- * millStackDescription.
- *
- *
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link java.lang.String} object.
- */
- private static String millStackDescription(final SpellAbility sa, final AbilityFactory af) {
- final HashMap params = af.getMapParams();
- final StringBuilder sb = new StringBuilder();
- final int numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
-
- ArrayList tgtPlayers;
-
- final Target tgt = sa.getTarget();
- if (tgt != null) {
- tgtPlayers = tgt.getTargetPlayers();
- } else {
- tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
- }
-
- if (!(sa instanceof AbilitySub)) {
- sb.append(sa.getSourceCard().getName()).append(" - ");
- } else {
- sb.append(" ");
- }
-
- final String conditionDesc = params.get("ConditionDescription");
- if (conditionDesc != null) {
- sb.append(conditionDesc).append(" ");
- }
-
- if (params.containsKey("StackDescription")) {
- if (params.get("StackDescription").equals("None")) {
- sb.append("");
- } else {
- sb.append(params.get("StackDescription"));
- }
- } else {
- for (final Player p : tgtPlayers) {
- sb.append(p.toString()).append(" ");
- }
-
- final ZoneType dest = ZoneType.smartValueOf(params.get("Destination"));
- if ((dest == null) || dest.equals(ZoneType.Graveyard)) {
- sb.append("mills ");
- } else if (dest.equals(ZoneType.Exile)) {
- sb.append("exiles ");
- } else if (dest.equals(ZoneType.Ante)) {
- sb.append("antes ");
- }
- sb.append(numCards);
- sb.append(" card");
- if (numCards != 1) {
- sb.append("s");
- }
- final String millPosition = params.containsKey("FromBottom") ? "bottom" : "top";
- sb.append(" from the " + millPosition + " of his or her library.");
- }
-
- final AbilitySub abSub = sa.getSubAbility();
- if (abSub != null) {
- sb.append(abSub.getStackDescription());
- }
-
- return sb.toString();
- }
-
- /**
- *
- * millCanPlayAI.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- * @return a boolean.
- */
- private static boolean millCanPlayAI(final Player ai, final AbilityFactory af, final SpellAbility sa) {
- final HashMap params = af.getMapParams();
-
- final Card source = sa.getSourceCard();
- final Cost abCost = af.getAbCost();
-
- 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;
- }
-
- if (!CostUtil.checkSacrificeCost(ai, abCost, source)) {
- return false;
- }
-
- if (!CostUtil.checkRemoveCounterCost(abCost, source)) {
- return false;
- }
-
- }
-
- if (!AbilityFactoryZoneAffecting.millTargetAI(ai, af, sa, false)) {
- return false;
- }
-
- final Random r = MyRandom.getRandom();
-
- // Don't use draw abilities before main 2 if possible
- if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) && !params.containsKey("ActivationPhases")) {
- return false;
- }
-
- // Don't tap creatures that may be able to block
- if (ComputerUtil.waitForBlocking(sa)) {
- return false;
- }
-
- double chance = .4; // 40 percent chance of milling with instant speed
- // stuff
- if (AbilityFactory.isSorcerySpeed(sa)) {
- chance = .667; // 66.7% chance for sorcery speed
- }
-
- if ((Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)
- && Singletons.getModel().getGame().getPhaseHandler().getNextTurn().equals(ai))) {
- chance = .9; // 90% for end of opponents turn
- }
-
- boolean randomReturn = r.nextFloat() <= Math.pow(chance, sa.getActivationsThisTurn() + 1);
-
- if (params.get("NumCards").equals("X") && source.getSVar("X").startsWith("Count$xPaid")) {
- // Set PayX here to maximum value.
- final int cardsToDiscard =
- Math.min(ComputerUtil.determineLeftoverMana(sa, ai), ai.getOpponent().getCardsIn(ZoneType.Library).size());
- source.setSVar("PayX", Integer.toString(cardsToDiscard));
- if (cardsToDiscard <= 0) {
- return false;
- }
- }
-
- if (AbilityFactory.playReusable(ai, sa)) {
- randomReturn = true;
- // some other variables here, like deck size, and phase and other fun stuff
- }
-
- return randomReturn;
- }
-
- /**
- *
- * millTargetAI.
- *
- *
- * @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.
- */
- private static boolean millTargetAI(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) {
- final Target tgt = sa.getTarget();
- final HashMap params = af.getMapParams();
- Player opp = ai.getOpponent();
-
- if (tgt != null) {
- tgt.resetTargets();
- if (!sa.canTarget(opp)) {
- if (mandatory && sa.canTarget(ai)) {
- tgt.addTarget(ai);
- return true;
- }
- return false;
- }
-
- final int numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
-
- final List pLibrary = opp.getCardsIn(ZoneType.Library);
-
- if (pLibrary.size() == 0) { // deck already empty, no need to mill
- if (!mandatory) {
- return false;
- }
-
- tgt.addTarget(opp);
- return true;
- }
-
- if (numCards >= pLibrary.size()) {
- // Can Mill out Human's deck? Do it!
- tgt.addTarget(opp);
- return true;
- }
-
- // Obscure case when you know what your top card is so you might?
- // want to mill yourself here
- // if (AI wants to mill self)
- // tgt.addTarget(AllZone.getComputerPlayer());
- // else
- tgt.addTarget(opp);
- }
- return true;
- }
-
- /**
- *
- * millDrawback.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- * @return a boolean.
- */
- private static boolean millDrawback(final Player ai, final AbilityFactory af, final SpellAbility sa) {
- if (!AbilityFactoryZoneAffecting.millTargetAI(ai, af, sa, true)) {
- return false;
- }
-
- // check SubAbilities DoTrigger?
- final AbilitySub abSub = sa.getSubAbility();
- if (abSub != null) {
- return abSub.chkAIDrawback();
- }
-
- return true;
- }
-
- private static boolean millTrigger(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) {
- if (!ComputerUtil.canPayCost(sa, ai)) {
- return false;
- }
-
- return millTriggerNoCost(ai, af, sa, mandatory);
- }
-
- private static boolean millTriggerNoCost(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) {
- if (!AbilityFactoryZoneAffecting.millTargetAI(ai, af, sa, mandatory)) {
- return false;
- }
-
- final HashMap params = af.getMapParams();
-
- final Card source = sa.getSourceCard();
- if (params.get("NumCards").equals("X") && source.getSVar("X").equals("Count$xPaid")) {
- // Set PayX here to maximum value.
- final int cardsToDiscard = Math.min(ComputerUtil.determineLeftoverMana(sa, ai), ai.getOpponent()
- .getCardsIn(ZoneType.Library).size());
- source.setSVar("PayX", Integer.toString(cardsToDiscard));
- }
-
- // check SubAbilities DoTrigger?
- final AbilitySub abSub = sa.getSubAbility();
- if (abSub != null) {
- return abSub.doTrigger(mandatory);
- }
-
- return true;
- }
-
- /**
- *
- * millResolve.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- */
- private static void millResolve(final AbilityFactory af, final SpellAbility sa) {
- final HashMap params = af.getMapParams();
- final Card source = sa.getSourceCard();
- final int numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
- final boolean bottom = params.containsKey("FromBottom");
-
- if (params.containsKey("ForgetOtherRemembered")) {
- source.clearRemembered();
- }
-
- ArrayList tgtPlayers;
-
- final Target tgt = sa.getTarget();
- if (tgt != null) {
- tgtPlayers = tgt.getTargetPlayers();
- } else {
- tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
- }
-
- ZoneType destination = ZoneType.smartValueOf(params.get("Destination"));
- if (destination == null) {
- destination = ZoneType.Graveyard;
- }
-
- for (final Player p : tgtPlayers) {
- if ((tgt == null) || p.canBeTargetedBy(sa)) {
- final List milled = p.mill(numCards, destination, bottom);
- if (params.containsKey("RememberMilled")) {
- for (final Card c : milled) {
- source.addRemembered(c);
- }
- }
- if (params.containsKey("Imprint")) {
- for (final Card c : milled) {
- source.addImprinted(c);
- }
- }
- }
- }
- }
-
- // ////////////////////
- //
- // Discard stuff
- //
- // ////////////////////
-
- // NumCards - the number of cards to be discarded (may be integer or X)
- // Mode - the mode of discard - should match spDiscard
- // -Random
- // -TgtChoose
- // -RevealYouChoose
- // -RevealOppChoose
- // -RevealDiscardAll (defaults to Card if DiscardValid is missing)
- // -Hand
- // DiscardValid - a ValidCards syntax for acceptable cards to discard
- // UnlessType - a ValidCards expression for
- // "discard x unless you discard a ..."
-
- // Examples:
- // A:SP$Discard | Cost$B | Tgt$TgtP | NumCards$2 | Mode$Random |
- // SpellDescription$<...>
- // A:AB$Discard | Cost$U | ValidTgts$ Opponent | Mode$RevealYouChoose |
- // NumCards$X | SpellDescription$<...>
-
- /**
- *
- * createAbilityDiscard.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createAbilityDiscard(final AbilityFactory af) {
- class AbilityDiscard extends AbilityActivated {
- public AbilityDiscard(final Card ca, final Cost co, final Target t) {
- super(ca, co, t);
- }
-
- @Override
- public AbilityActivated getCopy() {
- AbilityActivated res = new AbilityDiscard(getSourceCard(),
- getPayCosts(), getTarget() == null ? null : new Target(getTarget()));
- CardFactoryUtil.copySpellAbility(this, res);
- return res;
- }
-
- private static final long serialVersionUID = 4348585353456736817L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.discardStackDescription(af, this);
- }
-
- @Override
- public boolean canPlayAI() {
- return AbilityFactoryZoneAffecting.discardCanPlayAI(getActivatingPlayer(), af, this);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.discardResolve(af, this);
- }
-
- @Override
- public boolean doTrigger(final boolean mandatory) {
- return AbilityFactoryZoneAffecting.discardTrigger(getActivatingPlayer(), af, this, mandatory);
- }
- }
-
- final SpellAbility abDiscard = new AbilityDiscard(af.getHostCard(), af.getAbCost(), af.getAbTgt());
-
- return abDiscard;
- }
-
- /**
- *
- * createSpellDiscard.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createSpellDiscard(final AbilityFactory af) {
- final SpellAbility spDiscard = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
- private static final long serialVersionUID = 4348585353456736817L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.discardStackDescription(af, this);
- }
-
- @Override
- public boolean canPlayAI() {
- return AbilityFactoryZoneAffecting.discardCanPlayAI(getActivatingPlayer(), af, this) && super.canPlayAI();
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.discardResolve(af, this);
- }
-
- @Override
- public boolean canPlayFromEffectAI(final boolean mandatory, final boolean withOutManaCost) {
- if (withOutManaCost) {
- return AbilityFactoryZoneAffecting.discardTriggerNoCost(getActivatingPlayer(), af, this, mandatory);
- }
- return AbilityFactoryZoneAffecting.discardTrigger(getActivatingPlayer(), af, this, mandatory);
- }
-
- };
- return spDiscard;
- }
-
- /**
- *
- * createDrawbackDiscard.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createDrawbackDiscard(final AbilityFactory af) {
- class DrawbackDiscard extends AbilitySub {
- public DrawbackDiscard(final Card ca, final Target t) {
- super(ca, t);
- }
-
- @Override
- public AbilitySub getCopy() {
- AbilitySub res = new DrawbackDiscard(getSourceCard(),
- getTarget() == null ? null : new Target(getTarget()));
- CardFactoryUtil.copySpellAbility(this, res);
- return res;
- }
-
- private static final long serialVersionUID = 4348585353456736817L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.discardStackDescription(af, this);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.discardResolve(af, this);
- }
-
- @Override
- public boolean canPlayAI() {
- return AbilityFactoryZoneAffecting.discardCanPlayAI(getActivatingPlayer(), af, this);
- }
-
- @Override
- public boolean chkAIDrawback() {
- return AbilityFactoryZoneAffecting.discardCheckDrawbackAI(getActivatingPlayer(), af, this);
- }
-
- @Override
- public boolean doTrigger(final boolean mandatory) {
- return AbilityFactoryZoneAffecting.discardTrigger(getActivatingPlayer(), af, this, mandatory);
- }
- }
- final SpellAbility dbDiscard = new DrawbackDiscard(af.getHostCard(), af.getAbTgt());
-
- return dbDiscard;
- }
-
- /**
- *
- * discardResolve.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- */
- private static void discardResolve(final AbilityFactory af, final SpellAbility sa) {
- final Card source = sa.getSourceCard();
- final Card host = af.getHostCard();
- final HashMap params = af.getMapParams();
- final String mode = params.get("Mode");
-
- ArrayList tgtPlayers;
-
- final Target tgt = sa.getTarget();
- if (tgt != null) {
- tgtPlayers = tgt.getTargetPlayers();
- } else {
- tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
- }
-
- final List discarded = new ArrayList();
-
- for (final Player p : tgtPlayers) {
- if ((tgt == null) || p.canBeTargetedBy(sa)) {
- if (mode.equals("Defined")) {
- final ArrayList toDiscard = AbilityFactory.getDefinedCards(host, params.get("DefinedCards"),
- sa);
- for (final Card c : toDiscard) {
- discarded.addAll(p.discard(c, sa));
- }
- if (params.containsKey("RememberDiscarded")) {
- for (final Card c : discarded) {
- source.addRemembered(c);
- }
- }
- continue;
- }
-
- if (mode.equals("Hand")) {
- final List list = p.discardHand(sa);
- if (params.containsKey("RememberDiscarded")) {
- for (final Card c : list) {
- source.addRemembered(c);
- }
- }
- continue;
- }
-
- if (mode.equals("NotRemembered")) {
- final List dPHand =
- CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), "Card.IsNotRemembered", source.getController(), source);
- for (final Card c : dPHand) {
- p.discard(c, sa);
- discarded.add(c);
- }
- }
-
- int numCards = 1;
- if (params.containsKey("NumCards")) {
- numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
- if (p.getCardsIn(ZoneType.Hand).size() > 0
- && p.getCardsIn(ZoneType.Hand).size() < numCards) {
- // System.out.println("Scale down discard from " + numCards + " to " + p.getCardsIn(ZoneType.Hand).size());
- numCards = p.getCardsIn(ZoneType.Hand).size();
- }
- }
-
- if (mode.equals("Random")) {
- boolean runDiscard = true;
- if (params.containsKey("Optional")) {
- if (p.isHuman()) {
- // TODO Ask if Human would like to discard a card at Random
- StringBuilder sb = new StringBuilder("Would you like to discard ");
- sb.append(numCards).append(" random card(s)?");
- runDiscard = GameActionUtil.showYesNoDialog(source, sb.toString());
- }
- else {
- // TODO For now AI will always discard Random used currently with:
- // Balduvian Horde and similar cards
- }
- }
-
- if (runDiscard) {
- final String valid = params.containsKey("DiscardValid") ? params.get("DiscardValid") : "Card";
- discarded.addAll(p.discardRandom(numCards, sa, valid));
- }
- } else if (mode.equals("TgtChoose") && params.containsKey("UnlessType")) {
- p.discardUnless(numCards, params.get("UnlessType"), sa);
- } else if (mode.equals("RevealDiscardAll")) {
- // Reveal
- final List dPHand = p.getCardsIn(ZoneType.Hand);
-
- if (p.isHuman()) {
- // "reveal to computer" for information gathering
- } else {
- GuiChoose.oneOrNone("Revealed computer hand", dPHand);
- }
-
- String valid = params.get("DiscardValid");
- if (valid == null) {
- valid = "Card";
- }
-
- if (valid.contains("X")) {
- valid = valid.replace("X", Integer.toString(AbilityFactory.calculateAmount(source, "X", sa)));
- }
-
- final List dPChHand = CardLists.getValidCards(dPHand, valid.split(","), source.getController(), source);
- // Reveal cards that will be discarded?
- for (final Card c : dPChHand) {
- p.discard(c, sa);
- discarded.add(c);
- }
- } else if (mode.equals("RevealYouChoose") || mode.equals("RevealOppChoose") || mode.equals("TgtChoose")) {
- // Is Reveal you choose right? I think the wrong player is
- // being used?
- List dPHand = new ArrayList(p.getCardsIn(ZoneType.Hand));
- if (dPHand.size() != 0) {
- if (params.containsKey("RevealNumber")) {
- String amountString = params.get("RevealNumber");
- int amount = amountString.matches("[0-9][0-9]?") ? Integer.parseInt(amountString)
- : CardFactoryUtil.xCount(source, source.getSVar(amountString));
- dPHand = AbilityFactoryReveal.getRevealedList(p, dPHand, amount, false);
- }
- List dPChHand = new ArrayList(dPHand);
- String[] dValid = null;
- if (params.containsKey("DiscardValid")) { // Restrict card choices
- dValid = params.get("DiscardValid").split(",");
- dPChHand = CardLists.getValidCards(dPHand, dValid, source.getController(), source);
- }
- Player chooser = p;
- if (mode.equals("RevealYouChoose")) {
- chooser = source.getController();
- } else if (mode.equals("RevealOppChoose")) {
- chooser = source.getController().getOpponent();
- }
-
- if (chooser.isComputer()) {
- // AI
- if (p.isComputer()) { // discard AI cards
- int max = chooser.getCardsIn(ZoneType.Hand).size();
- max = Math.min(max, numCards);
- List list = ComputerUtil.discardNumTypeAI(p, max, dValid, sa);
- if (mode.startsWith("Reveal")) {
- GuiChoose.oneOrNone("Computer has chosen", list);
- }
- discarded.addAll(list);
- for (Card card : list) {
- p.discard(card, sa);
- }
- continue;
- }
- // discard human cards
- for (int i = 0; i < numCards; i++) {
- if (dPChHand.size() > 0) {
- List goodChoices = CardLists.filter(dPChHand, new Predicate() {
- @Override
- public boolean apply(final Card c) {
- if (c.hasKeyword("If a spell or ability an opponent controls causes you to discard CARDNAME," +
- " put it onto the battlefield instead of putting it into your graveyard.")
- || !c.getSVar("DiscardMe").equals("")) {
- return false;
- }
- return true;
- }
- });
- if (goodChoices.isEmpty()) {
- goodChoices = dPChHand;
- }
- final List dChoices = new ArrayList();
- if (params.containsKey("DiscardValid")) {
- final String validString = params.get("DiscardValid");
- if (validString.contains("Creature") && !validString.contains("nonCreature")) {
- final Card c = CardFactoryUtil.getBestCreatureAI(goodChoices);
- if (c != null) {
- dChoices.add(CardFactoryUtil.getBestCreatureAI(goodChoices));
- }
- }
- }
-
- Collections.sort(goodChoices, CardLists.TextLenReverseComparator);
-
- CardLists.sortCMC(goodChoices);
- dChoices.add(goodChoices.get(0));
-
- final Card dC = goodChoices.get(CardUtil.getRandomIndex(goodChoices));
- dPChHand.remove(dC);
-
- if (mode.startsWith("Reveal")) {
- final List dCs = new ArrayList();
- dCs.add(dC);
- GuiChoose.oneOrNone("Computer has chosen", dCs);
- }
- discarded.add(dC);
- p.discard(dC, sa);
- }
- }
- } else {
- // human
- if (mode.startsWith("Reveal")) {
- GuiChoose.oneOrNone("Revealed " + p + " hand", dPHand);
- }
-
- for (int i = 0; i < numCards; i++) {
- if (dPChHand.size() > 0) {
- Card dC = null;
- if (params.containsKey("Optional")) {
- dC = GuiChoose.oneOrNone("Choose a card to be discarded", dPChHand);
- } else {
- dC = GuiChoose.one("Choose a card to be discarded", dPChHand);
- } if (dC != null) {
- dPChHand.remove(dC);
- discarded.add(dC);
- p.discard(dC, sa);
- }
- }
- }
- }
- }
- }
- }
- }
-
- if (params.containsKey("RememberDiscarded")) {
- for (final Card c : discarded) {
- source.addRemembered(c);
- }
- }
-
- } // discardResolve()
-
- /**
- *
- * discardStackDescription.
- *
- *
- * @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.
- */
- private static String discardStackDescription(final AbilityFactory af, final SpellAbility sa) {
- final HashMap params = af.getMapParams();
- final String mode = params.get("Mode");
- final StringBuilder sb = new StringBuilder();
-
- ArrayList tgtPlayers;
-
- final Target tgt = sa.getTarget();
- if (tgt != null) {
- tgtPlayers = tgt.getTargetPlayers();
- } else {
- tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
- }
-
- if (!(sa instanceof AbilitySub)) {
- sb.append(sa.getSourceCard().getName()).append(" - ");
- } else {
- sb.append(" ");
- }
-
- final String conditionDesc = params.get("ConditionDescription");
- if (conditionDesc != null) {
- sb.append(conditionDesc).append(" ");
- }
-
- if (tgtPlayers.size() > 0) {
-
- for (final Player p : tgtPlayers) {
- sb.append(p.toString()).append(" ");
- }
-
- if (mode.equals("RevealYouChoose")) {
- sb.append("reveals his or her hand.").append(" You choose (");
- } else if (mode.equals("RevealDiscardAll")) {
- sb.append("reveals his or her hand. Discard (");
- } else {
- sb.append("discards (");
- }
-
- int numCards = 1;
- if (params.containsKey("NumCards")) {
- numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
- }
-
- if (mode.equals("Hand")) {
- sb.append("his or her hand");
- } else if (mode.equals("RevealDiscardAll")) {
- sb.append("All");
- } else {
- sb.append(numCards);
- }
-
- sb.append(")");
-
- if (mode.equals("RevealYouChoose")) {
- sb.append(" to discard");
- } else if (mode.equals("RevealDiscardAll")) {
- String valid = params.get("DiscardValid");
- if (valid == null) {
- valid = "Card";
- }
- sb.append(" of type: ").append(valid);
- }
-
- if (mode.equals("Defined")) {
- sb.append(" defined cards");
- }
-
- if (mode.equals("Random")) {
- sb.append(" at random.");
- } else {
- sb.append(".");
- }
- }
-
- final AbilitySub abSub = sa.getSubAbility();
- if (abSub != null) {
- sb.append(abSub.getStackDescription());
- }
-
- return sb.toString();
- } // discardStackDescription()
-
- /**
- *
- * discardCanPlayAI.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- * @return a boolean.
- */
- private static boolean discardCanPlayAI(final Player ai, final AbilityFactory af, final SpellAbility sa) {
- final HashMap params = af.getMapParams();
-
- final Target tgt = sa.getTarget();
- final Card source = sa.getSourceCard();
- final Cost abCost = sa.getPayCosts();
-
- if (abCost != null) {
- // AI currently disabled for these costs
- if (!CostUtil.checkSacrificeCost(ai, abCost, source)) {
- return false;
- }
-
- if (!CostUtil.checkLifeCost(ai, abCost, source, 4, null)) {
- return false;
- }
-
- if (!CostUtil.checkDiscardCost(ai, abCost, source)) {
- return false;
- }
-
- if (!CostUtil.checkRemoveCounterCost(abCost, source)) {
- return false;
- }
-
- }
-
- final boolean humanHasHand = ai.getOpponent().getCardsIn(ZoneType.Hand).size() > 0;
-
- if (tgt != null) {
- if (!AbilityFactoryZoneAffecting.discardTargetAI(ai, af, sa)) {
- return false;
- }
- } else {
- // TODO: Add appropriate restrictions
- final ArrayList players = AbilityFactory.getDefinedPlayers(sa.getSourceCard(),
- params.get("Defined"), sa);
-
- if (players.size() == 1) {
- if (players.get(0).isComputer()) {
- // the ai should only be using something like this if he has
- // few cards in hand,
- // cards like this better have a good drawback to be in the
- // AIs deck
- } else {
- // defined to the human, so that's fine as long the human
- // has cards
- if (!humanHasHand) {
- return false;
- }
- }
- } else {
- // Both players discard, any restrictions?
- }
- }
-
- if (!params.get("Mode").equals("Hand") && !params.get("Mode").equals("RevealDiscardAll")) {
- if (params.get("NumCards").equals("X") && source.getSVar("X").equals("Count$xPaid")) {
- // Set PayX here to maximum value.
- final int cardsToDiscard = Math.min(ComputerUtil.determineLeftoverMana(sa, ai), ai.getOpponent()
- .getCardsIn(ZoneType.Hand).size());
- source.setSVar("PayX", Integer.toString(cardsToDiscard));
- }
- }
-
- // Don't use draw abilities before main 2 if possible
- if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
- && !params.containsKey("ActivationPhases")) {
- return false;
- }
-
- // Don't tap creatures that may be able to block
- if (ComputerUtil.waitForBlocking(sa) && !params.containsKey("ActivationPhases")) {
- return false;
- }
-
- final Random r = MyRandom.getRandom();
- boolean randomReturn = r.nextFloat() <= Math.pow(0.9, sa.getActivationsThisTurn());
-
- // some other variables here, like handsize vs. maxHandSize
-
- final AbilitySub subAb = sa.getSubAbility();
- if (subAb != null) {
- randomReturn &= subAb.chkAIDrawback();
- }
- return randomReturn;
- } // discardCanPlayAI()
-
- /**
- *
- * discardTargetAI.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- * @return a boolean.
- */
- private static boolean discardTargetAI(final Player ai, final AbilityFactory af, final SpellAbility sa) {
- final Target tgt = sa.getTarget();
- Player opp = ai.getOpponent();
- if (opp.getCardsIn(ZoneType.Hand).isEmpty()) {
- return false;
- }
- if (tgt != null) {
- if (sa.canTarget(opp)) {
- tgt.addTarget(opp);
- return true;
- }
- }
- return false;
- } // discardTargetAI()
-
- /**
- *
- * discardTrigger.
- *
- *
- * @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.
- */
- private static boolean discardTrigger(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) {
- if (!ComputerUtil.canPayCost(sa, ai)) {
- return false;
- }
- return discardTriggerNoCost(ai, af, sa, mandatory);
- }
-
- /**
- *
- * discardTriggerNoCost.
- *
- *
- * @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.
- */
- private static boolean discardTriggerNoCost(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) {
-
- final Target tgt = sa.getTarget();
- if (tgt != null) {
- Player opp = ai.getOpponent();
- if (!AbilityFactoryZoneAffecting.discardTargetAI(ai, af, sa)) {
- if (mandatory && sa.canTarget(opp)) {
- tgt.addTarget(opp);
- } else if (mandatory && sa.canTarget(ai)) {
- tgt.addTarget(ai);
- } else {
- return false;
- }
- }
- }
-
- return true;
- } // discardTrigger()
-
- /**
- *
- * discardCheckDrawbackAI.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param subAb
- * a {@link forge.card.spellability.AbilitySub} object.
- * @return a boolean.
- */
- private static boolean discardCheckDrawbackAI(final Player ai, final AbilityFactory af, final AbilitySub subAb) {
- // Drawback AI improvements
- // if parent draws cards, make sure cards in hand + cards drawn > 0
- final Target tgt = af.getAbTgt();
- if (tgt != null) {
- return AbilityFactoryZoneAffecting.discardTargetAI(ai, af, subAb);
- }
- // TODO: check for some extra things
- return true;
- } // discardCheckDrawbackAI()
-
- // **********************************************************************
- // ******************************* Shuffle ******************************
- // **********************************************************************
-
- /**
- *
- * createAbilityShuffle.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createAbilityShuffle(final AbilityFactory af) {
- class AbilityShuffle extends AbilityActivated {
- public AbilityShuffle(final Card ca, final Cost co, final Target t) {
- super(ca, co, t);
- }
-
- @Override
- public AbilityActivated getCopy() {
- AbilityActivated res = new AbilityShuffle(getSourceCard(),
- getPayCosts(), getTarget() == null ? null : new Target(getTarget()));
- CardFactoryUtil.copySpellAbility(this, res);
- return res;
- }
-
- private static final long serialVersionUID = -1245185178904838198L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.shuffleStackDescription(af, this);
- }
-
- @Override
- public boolean canPlayAI() {
- return AbilityFactoryZoneAffecting.shuffleCanPlayAI(af, this);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.shuffleResolve(af, this);
- }
-
- @Override
- public boolean doTrigger(final boolean mandatory) {
- return AbilityFactoryZoneAffecting.shuffleTrigger(getActivatingPlayer(), af, this, mandatory);
- }
- }
- final SpellAbility abShuffle = new AbilityShuffle(af.getHostCard(), af.getAbCost(), af.getAbTgt());
-
- return abShuffle;
- }
-
- /**
- *
- * createSpellShuffle.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createSpellShuffle(final AbilityFactory af) {
- final SpellAbility spShuffle = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
- private static final long serialVersionUID = 589035800601547559L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.shuffleStackDescription(af, this);
- }
-
- @Override
- public boolean canPlayAI() {
- return AbilityFactoryZoneAffecting.shuffleCanPlayAI(af, this);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.shuffleResolve(af, this);
- }
-
- };
- return spShuffle;
- }
-
- /**
- *
- * createDrawbackShuffle.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @return a {@link forge.card.spellability.SpellAbility} object.
- */
- public static SpellAbility createDrawbackShuffle(final AbilityFactory af) {
- class DrawbackShuffle extends AbilitySub {
- public DrawbackShuffle(final Card ca, final Target t) {
- super(ca, t);
- }
-
- @Override
- public AbilitySub getCopy() {
- AbilitySub res = new DrawbackShuffle(getSourceCard(),
- getTarget() == null ? null : new Target(getTarget()));
- CardFactoryUtil.copySpellAbility(this, res);
- return res;
- }
-
- private static final long serialVersionUID = 5974307947494280639L;
-
- @Override
- public String getStackDescription() {
- return AbilityFactoryZoneAffecting.shuffleStackDescription(af, this);
- }
-
- @Override
- public void resolve() {
- AbilityFactoryZoneAffecting.shuffleResolve(af, this);
- }
-
- @Override
- public boolean chkAIDrawback() {
- return AbilityFactoryZoneAffecting.shuffleTargetAI(af, this, false, false);
- }
-
- @Override
- public boolean doTrigger(final boolean mandatory) {
- return AbilityFactoryZoneAffecting.shuffleTrigger(getActivatingPlayer(), af, this, mandatory);
- }
- }
- final SpellAbility dbShuffle = new DrawbackShuffle(af.getHostCard(), af.getAbTgt());
-
- return dbShuffle;
- }
-
- /**
- *
- * shuffleStackDescription.
- *
- *
- * @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.
- */
- private static String shuffleStackDescription(final AbilityFactory af, final SpellAbility sa) {
- final HashMap params = af.getMapParams();
- final StringBuilder sb = new StringBuilder();
-
- if (!(sa instanceof AbilitySub)) {
- sb.append(sa.getSourceCard().getName()).append(" - ");
- } else {
- sb.append(" ");
- }
-
- final String conditionDesc = params.get("ConditionDescription");
- if (conditionDesc != null) {
- sb.append(conditionDesc).append(" ");
- }
-
- ArrayList tgtPlayers;
-
- final Target tgt = sa.getTarget();
- if (tgt != null) {
- tgtPlayers = tgt.getTargetPlayers();
- } else {
- tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
- }
-
- if (tgtPlayers.size() > 0) {
- final Iterator it = tgtPlayers.iterator();
- while (it.hasNext()) {
- sb.append(it.next().getName());
- if (it.hasNext()) {
- sb.append(" and ");
- }
- }
- } else {
- sb.append("Error - no target players for Shuffle. ");
- }
- sb.append(" shuffle");
- if (tgtPlayers.size() > 1) {
- sb.append(" their libraries");
- } else {
- sb.append("s his or her library");
- }
- sb.append(".");
-
- final AbilitySub abSub = sa.getSubAbility();
- if (abSub != null) {
- sb.append(abSub.getStackDescription());
- }
-
- return sb.toString();
- }
-
- /**
- *
- * shuffleCanPlayAI.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- * @return a boolean.
- */
- private static boolean shuffleCanPlayAI(final AbilityFactory af, final SpellAbility sa) {
- // not really sure when the compy would use this; maybe only after a
- // human
- // deliberately put a card on top of their library
- return false;
- /*
- * if (!ComputerUtil.canPayCost(sa)) return false;
- *
- * Card source = sa.getSourceCard();
- *
- * Random r = MyRandom.random; boolean randomReturn = r.nextFloat() <=
- * Math.pow(.667, sa.getActivationsThisTurn()+1);
- *
- * if (AbilityFactory.playReusable(sa)) randomReturn = true;
- *
- * Ability_Sub subAb = sa.getSubAbility(); if (subAb != null)
- * randomReturn &= subAb.chkAI_Drawback(); return randomReturn;
- */
- }
-
- /**
- *
- * shuffleTargetAI.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- * @param primarySA
- * a boolean.
- * @param mandatory
- * a boolean.
- * @return a boolean.
- */
- private static boolean shuffleTargetAI(final AbilityFactory af, final SpellAbility sa, final boolean primarySA,
- final boolean mandatory) {
- return false;
- } // shuffleTargetAI()
-
- /**
- *
- * shuffleTrigger.
- *
- *
- * @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.
- */
- private static boolean shuffleTrigger(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) {
- if (!ComputerUtil.canPayCost(sa, ai)) {
- return false;
- }
-
- if (!AbilityFactoryZoneAffecting.shuffleTargetAI(af, sa, false, mandatory)) {
- return false;
- }
-
- // check SubAbilities DoTrigger?
- final AbilitySub abSub = sa.getSubAbility();
- if (abSub != null) {
- return abSub.doTrigger(mandatory);
- }
-
- return true;
- }
-
- /**
- *
- * shuffleResolve.
- *
- *
- * @param af
- * a {@link forge.card.abilityfactory.AbilityFactory} object.
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- */
- private static void shuffleResolve(final AbilityFactory af, final SpellAbility sa) {
- final Card host = af.getHostCard();
- final HashMap params = af.getMapParams();
- final boolean optional = params.containsKey("Optional");
-
- ArrayList tgtPlayers;
-
- final Target tgt = sa.getTarget();
- if (tgt != null) {
- tgtPlayers = tgt.getTargetPlayers();
- } else {
- tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
- }
-
- for (final Player p : tgtPlayers) {
- if ((tgt == null) || p.canBeTargetedBy(sa)) {
- if (optional && sa.getActivatingPlayer().isHuman()
- && !GameActionUtil.showYesNoDialog(host, "Have " + p + " shuffle?")) {
- } else {
- p.shuffle();
- }
- }
- }
- }
-
-} // end class AbilityFactory_ZoneAffecting
diff --git a/src/main/java/forge/card/abilityfactory/SpellAiLogic.java b/src/main/java/forge/card/abilityfactory/SpellAiLogic.java
index 9357d24489e..bc836fd8b79 100644
--- a/src/main/java/forge/card/abilityfactory/SpellAiLogic.java
+++ b/src/main/java/forge/card/abilityfactory/SpellAiLogic.java
@@ -23,5 +23,5 @@ public abstract class SpellAiLogic {
}
// consider safe
- public boolean chkAIDrawback(Map params, SpellAbility sa) { return true; }
+ public boolean chkAIDrawback(Map params, SpellAbility sa, Player aiPlayer) { return true; }
}
\ No newline at end of file
diff --git a/src/main/java/forge/card/abilityfactory/UniversalDrawback.java b/src/main/java/forge/card/abilityfactory/UniversalDrawback.java
index bfe57edcf32..508a9b0145d 100644
--- a/src/main/java/forge/card/abilityfactory/UniversalDrawback.java
+++ b/src/main/java/forge/card/abilityfactory/UniversalDrawback.java
@@ -67,7 +67,7 @@ class UniversalDrawback extends AbilitySub {
@Override
public boolean chkAIDrawback() {
- boolean chance = ai.chkAIDrawback(params, this);
+ boolean chance = ai.chkAIDrawback(params, this, getActivatingPlayer());
final AbilitySub subAb = getSubAbility();
if (subAb != null) {
chance &= subAb.chkAIDrawback();
diff --git a/src/main/java/forge/card/abilityfactory/ai/AddTurnAi.java b/src/main/java/forge/card/abilityfactory/ai/AddTurnAi.java
index ae7c8fd6865..16d345a29a1 100644
--- a/src/main/java/forge/card/abilityfactory/ai/AddTurnAi.java
+++ b/src/main/java/forge/card/abilityfactory/ai/AddTurnAi.java
@@ -18,25 +18,12 @@
package forge.card.abilityfactory.ai;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Map;
-import forge.Card;
-import forge.Singletons;
-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.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.SpellAiLogic;
-import forge.card.cardfactory.CardFactoryUtil;
-import forge.card.cost.Cost;
-import forge.game.GameState;
-import forge.game.phase.ExtraTurn;
-import forge.game.phase.PhaseType;
-import forge.game.player.AIPlayer;
-import forge.game.player.ComputerUtil;
import forge.game.player.Player;
/**
@@ -79,7 +66,7 @@ public class AddTurnAi extends SpellAiLogic {
}
@Override
- public boolean chkAIDrawback(java.util.Map params, SpellAbility sa) {
+ public boolean chkAIDrawback(java.util.Map params, SpellAbility sa, Player aiPlayer) {
return true;
}
diff --git a/src/main/java/forge/card/abilityfactory/ai/AnimateAi.java b/src/main/java/forge/card/abilityfactory/ai/AnimateAi.java
index b85e09d6106..ef95535d8a9 100644
--- a/src/main/java/forge/card/abilityfactory/ai/AnimateAi.java
+++ b/src/main/java/forge/card/abilityfactory/ai/AnimateAi.java
@@ -124,7 +124,7 @@ public class AnimateAi extends SpellAiLogic {
@Override
- public boolean chkAIDrawback(Map params, SpellAbility sa) {
+ public boolean chkAIDrawback(Map params, SpellAbility sa, Player aiPlayer) {
boolean chance = true;
if (sa.getTarget() != null) {
diff --git a/src/main/java/forge/card/abilityfactory/ai/DiscardAi.java b/src/main/java/forge/card/abilityfactory/ai/DiscardAi.java
new file mode 100644
index 00000000000..53887fbcb02
--- /dev/null
+++ b/src/main/java/forge/card/abilityfactory/ai/DiscardAi.java
@@ -0,0 +1,204 @@
+package forge.card.abilityfactory.ai;
+
+import java.util.List;
+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.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.ComputerUtil;
+import forge.game.player.Player;
+import forge.game.zone.ZoneType;
+import forge.util.MyRandom;
+
+public class DiscardAi extends SpellAiLogic {
+
+ /**
+ *
+ * discardCanPlayAI.
+ *
+ *
+ * @param af
+ * a {@link forge.card.abilityfactory.AbilityFactory} object.
+ * @param sa
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @return a boolean.
+ */
+ @Override
+ public boolean canPlayAI(Player ai, Map params, SpellAbility sa) {
+ final Target tgt = sa.getTarget();
+ final Card source = sa.getSourceCard();
+ final Cost abCost = sa.getPayCosts();
+
+ if (abCost != null) {
+ // AI currently disabled for these costs
+ if (!CostUtil.checkSacrificeCost(ai, abCost, source)) {
+ return false;
+ }
+
+ if (!CostUtil.checkLifeCost(ai, abCost, source, 4, null)) {
+ return false;
+ }
+
+ if (!CostUtil.checkDiscardCost(ai, abCost, source)) {
+ return false;
+ }
+
+ if (!CostUtil.checkRemoveCounterCost(abCost, source)) {
+ return false;
+ }
+
+ }
+
+ final boolean humanHasHand = ai.getOpponent().getCardsIn(ZoneType.Hand).size() > 0;
+
+ if (tgt != null) {
+ if (!discardTargetAI(ai, sa)) {
+ return false;
+ }
+ } else {
+ // TODO: Add appropriate restrictions
+ final List players = AbilityFactory.getDefinedPlayers(sa.getSourceCard(),
+ params.get("Defined"), sa);
+
+ if (players.size() == 1) {
+ if (players.get(0).isComputer()) {
+ // the ai should only be using something like this if he has
+ // few cards in hand,
+ // cards like this better have a good drawback to be in the
+ // AIs deck
+ } else {
+ // defined to the human, so that's fine as long the human
+ // has cards
+ if (!humanHasHand) {
+ return false;
+ }
+ }
+ } else {
+ // Both players discard, any restrictions?
+ }
+ }
+
+ if (!params.get("Mode").equals("Hand") && !params.get("Mode").equals("RevealDiscardAll")) {
+ if (params.get("NumCards").equals("X") && source.getSVar("X").equals("Count$xPaid")) {
+ // Set PayX here to maximum value.
+ final int cardsToDiscard = Math.min(ComputerUtil.determineLeftoverMana(sa, ai), ai.getOpponent()
+ .getCardsIn(ZoneType.Hand).size());
+ source.setSVar("PayX", Integer.toString(cardsToDiscard));
+ }
+ }
+
+ // Don't use draw abilities before main 2 if possible
+ if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
+ && !params.containsKey("ActivationPhases")) {
+ return false;
+ }
+
+ // Don't tap creatures that may be able to block
+ if (ComputerUtil.waitForBlocking(sa) && !params.containsKey("ActivationPhases")) {
+ return false;
+ }
+
+ final Random r = MyRandom.getRandom();
+ boolean randomReturn = r.nextFloat() <= Math.pow(0.9, sa.getActivationsThisTurn());
+
+ // some other variables here, like handsize vs. maxHandSize
+
+ final AbilitySub subAb = sa.getSubAbility();
+ if (subAb != null) {
+ randomReturn &= subAb.chkAIDrawback();
+ }
+ return randomReturn;
+ } // discardCanPlayAI()
+
+ /**
+ *
+ * discardTargetAI.
+ *
+ *
+ * @param af
+ * a {@link forge.card.abilityfactory.AbilityFactory} object.
+ * @param sa
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @return a boolean.
+ */
+ private boolean discardTargetAI(final Player ai, final SpellAbility sa) {
+ final Target tgt = sa.getTarget();
+ Player opp = ai.getOpponent();
+ if (opp.getCardsIn(ZoneType.Hand).isEmpty()) {
+ return false;
+ }
+ if (tgt != null) {
+ if (sa.canTarget(opp)) {
+ tgt.addTarget(opp);
+ return true;
+ }
+ }
+ return false;
+ } // discardTargetAI()
+
+
+
+ /**
+ *
+ * discardTriggerNoCost.
+ *
+ *
+ * @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, Map params, SpellAbility sa, boolean mandatory) {
+ final Target tgt = sa.getTarget();
+ if (tgt != null) {
+ Player opp = ai.getOpponent();
+ if (!discardTargetAI(ai, sa)) {
+ if (mandatory && sa.canTarget(opp)) {
+ tgt.addTarget(opp);
+ } else if (mandatory && sa.canTarget(ai)) {
+ tgt.addTarget(ai);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ } // discardTrigger()
+
+ /**
+ *
+ * discardCheckDrawbackAI.
+ *
+ * @param af
+ * a {@link forge.card.abilityfactory.AbilityFactory} object.
+ * @param subAb
+ * a {@link forge.card.spellability.AbilitySub} object.
+ *
+ * @return a boolean.
+ */
+ @Override
+ public boolean chkAIDrawback(Map params, SpellAbility sa, Player ai) {
+ // Drawback AI improvements
+ // if parent draws cards, make sure cards in hand + cards drawn > 0
+ final Target tgt = sa.getTarget();
+ if (tgt != null) {
+ return discardTargetAI(ai, sa);
+ }
+ // TODO: check for some extra things
+ return true;
+ } // discardCheckDrawbackAI()
+}
\ No newline at end of file
diff --git a/src/main/java/forge/card/abilityfactory/ai/DrawAi.java b/src/main/java/forge/card/abilityfactory/ai/DrawAi.java
new file mode 100644
index 00000000000..30cb714e337
--- /dev/null
+++ b/src/main/java/forge/card/abilityfactory/ai/DrawAi.java
@@ -0,0 +1,311 @@
+/*
+
+* 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.ai;
+
+import java.util.ArrayList;
+import java.util.List;
+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.cost.Cost;
+import forge.card.cost.CostDiscard;
+import forge.card.cost.CostPart;
+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.ComputerUtil;
+import forge.game.player.Player;
+import forge.game.zone.ZoneType;
+import forge.util.MyRandom;
+
+/**
+ *
+ * drawCanPlayAI.
+ *
+ *
+ * @param af
+ * a {@link forge.card.abilityfactory.AbilityFactory} object.
+ * @param sa
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @return a boolean.
+ */
+public class DrawAi 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 Target tgt = sa.getTarget();
+ final Card source = sa.getSourceCard();
+ final Cost abCost = sa.getPayCosts();
+
+ if (abCost != null) {
+ // AI currently disabled for these costs
+ if (!CostUtil.checkCreatureSacrificeCost(ai, abCost, source)) {
+ return false;
+ }
+
+ if (!CostUtil.checkLifeCost(ai, abCost, source, 4, null)) {
+ return false;
+ }
+
+ if (!CostUtil.checkDiscardCost(ai, abCost, source)) {
+ for (final CostPart part : abCost.getCostParts()) {
+ if (part instanceof CostDiscard) {
+ CostDiscard cd = (CostDiscard) part;
+ cd.decideAIPayment(ai, sa, sa.getSourceCard(), null);
+ List discards = cd.getList();
+ for (Card discard : discards) {
+ if (!ComputerUtil.isWorseThanDraw(ai, discard)) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if (!CostUtil.checkRemoveCounterCost(abCost, source)) {
+ return false;
+ }
+
+ }
+
+ final boolean bFlag = targetAI(ai, params, sa, false);
+
+ if (!bFlag) {
+ return false;
+ }
+
+ if (tgt != null) {
+ final ArrayList players = tgt.getTargetPlayers();
+ if ((players.size() > 0) && players.get(0).isHuman()) {
+ return true;
+ }
+ }
+
+ // Don't use draw abilities before main 2 if possible
+ if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
+ && !params.containsKey("ActivationPhases")) {
+ return false;
+ }
+
+ // Don't tap creatures that may be able to block
+ if (ComputerUtil.waitForBlocking(sa)) {
+ return false;
+ }
+
+ double chance = .4; // 40 percent chance of drawing with instant speed
+ // stuff
+ final Random r = MyRandom.getRandom();
+ boolean randomReturn = r.nextFloat() <= Math.pow(chance, sa.getActivationsThisTurn() + 1);
+ if (AbilityFactory.isSorcerySpeed(sa)) {
+ randomReturn = true;
+ }
+ if ((Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)
+ && Singletons.getModel().getGame().getPhaseHandler().getNextTurn().equals(ai))) {
+ randomReturn = true;
+ }
+
+ if (AbilityFactory.playReusable(ai, sa)) {
+ randomReturn = true;
+ }
+
+ final AbilitySub subAb = sa.getSubAbility();
+ if (subAb != null) {
+ randomReturn &= subAb.chkAIDrawback();
+ }
+ return randomReturn;
+ }
+
+ /**
+ *
+ * drawTargetAI.
+ *
+ *
+ * @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.
+ */
+ private boolean targetAI(final Player ai, final Map params, final SpellAbility sa, final boolean mandatory) {
+ final Target tgt = sa.getTarget();
+ final Card source = sa.getSourceCard();
+
+ Player opp = ai.getOpponent();
+
+ int computerHandSize = ai.getCardsIn(ZoneType.Hand).size();
+ final int humanLibrarySize = opp.getCardsIn(ZoneType.Library).size();
+ final int computerLibrarySize = ai.getCardsIn(ZoneType.Library).size();
+ final int computerMaxHandSize = ai.getMaxHandSize();
+
+ //if a spell is used don't count the card
+ if (sa.isSpell() && source.isInZone(ZoneType.Hand)) {
+ computerHandSize -= 1;
+ }
+
+ int numCards = 1;
+ if (params.containsKey("NumCards")) {
+ numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
+ }
+
+ boolean xPaid = false;
+ final String num = params.get("NumCards");
+ if ((num != null) && num.equals("X") && source.getSVar(num).equals("Count$xPaid")) {
+ // Set PayX here to maximum value.
+ if (sa instanceof AbilitySub) {
+ numCards = Integer.parseInt(source.getSVar("PayX"));
+ } else {
+ numCards = ComputerUtil.determineLeftoverMana(sa, ai);
+ source.setSVar("PayX", Integer.toString(numCards));
+ }
+ xPaid = true;
+ }
+ //if (n)
+
+ // TODO: if xPaid and one of the below reasons would fail, instead of
+ // bailing
+ // reduce toPay amount to acceptable level
+
+ if (tgt != null) {
+ // ability is targeted
+ tgt.resetTargets();
+
+ final boolean canTgtHuman = sa.canTarget(opp);
+ final boolean canTgtComp = sa.canTarget(ai);
+ boolean tgtHuman = false;
+
+ if (!canTgtHuman && !canTgtComp) {
+ return false;
+ }
+
+ if (canTgtHuman && !opp.cantLose() && (numCards >= humanLibrarySize)) {
+ // Deck the Human? DO IT!
+ tgt.addTarget(opp);
+ return true;
+ }
+
+ if (numCards >= computerLibrarySize) {
+ if (xPaid) {
+ numCards = computerLibrarySize - 1;
+ source.setSVar("PayX", Integer.toString(numCards));
+ } else {
+ // Don't deck your self
+ if (!mandatory) {
+ return false;
+ }
+ tgtHuman = true;
+ }
+ }
+
+ if (((computerHandSize + numCards) > computerMaxHandSize)
+ && Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().isComputer()) {
+ if (xPaid) {
+ numCards = computerMaxHandSize - computerHandSize;
+ source.setSVar("PayX", Integer.toString(numCards));
+ } else {
+ // Don't draw too many cards and then risk discarding cards
+ // at EOT
+ if (!(params.containsKey("NextUpkeep") || (sa instanceof AbilitySub)) && !mandatory) {
+ return false;
+ }
+ }
+ }
+
+ if (numCards == 0 && !mandatory) {
+ return false;
+ }
+
+ if ((!tgtHuman || !canTgtHuman) && canTgtComp) {
+ tgt.addTarget(ai);
+ } else if (mandatory && canTgtHuman) {
+ tgt.addTarget(opp);
+ } else {
+ return false;
+ }
+ } else {
+ // TODO: consider if human is the defined player
+
+ // ability is not targeted
+ if (numCards >= computerLibrarySize) {
+ // Don't deck yourself
+ if (!mandatory) {
+ return false;
+ }
+ }
+
+ if (numCards == 0 && !mandatory) {
+ return false;
+ }
+
+ if (((computerHandSize + numCards) > computerMaxHandSize)
+ && Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().isComputer()
+ && !sa.isTrigger()) {
+ // Don't draw too many cards and then risk discarding cards at
+ // EOT
+ if (!(params.containsKey("NextUpkeep") || (sa instanceof AbilitySub)) && !mandatory) {
+ return false;
+ }
+ }
+ }
+ return true;
+ } // drawTargetAI()
+
+
+ /**
+ *
+ * drawTriggerNoCost.
+ *
+ *
+ * @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) {
+ if (!targetAI(ai, params, sa, mandatory)) {
+ return false;
+ }
+
+ // check SubAbilities DoTrigger?
+ final AbilitySub abSub = sa.getSubAbility();
+ if (abSub != null) {
+ return abSub.doTrigger(mandatory);
+ }
+
+ return true;
+ }
+
+}
diff --git a/src/main/java/forge/card/abilityfactory/effects/EndTurnAi.java b/src/main/java/forge/card/abilityfactory/ai/EndTurnAi.java
similarity index 86%
rename from src/main/java/forge/card/abilityfactory/effects/EndTurnAi.java
rename to src/main/java/forge/card/abilityfactory/ai/EndTurnAi.java
index e145ac262c0..e93ba47baf2 100644
--- a/src/main/java/forge/card/abilityfactory/effects/EndTurnAi.java
+++ b/src/main/java/forge/card/abilityfactory/ai/EndTurnAi.java
@@ -1,4 +1,4 @@
-package forge.card.abilityfactory.effects;
+package forge.card.abilityfactory.ai;
import java.util.Map;
@@ -18,7 +18,7 @@ public class EndTurnAi extends SpellAiLogic {
}
@Override
- public boolean chkAIDrawback(java.util.Map params, SpellAbility sa) { return false; }
+ public boolean chkAIDrawback(java.util.Map params, SpellAbility sa, Player aiPlayer) { return false; }
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility)
diff --git a/src/main/java/forge/card/abilityfactory/ai/MillAi.java b/src/main/java/forge/card/abilityfactory/ai/MillAi.java
new file mode 100644
index 00000000000..783527bfd2d
--- /dev/null
+++ b/src/main/java/forge/card/abilityfactory/ai/MillAi.java
@@ -0,0 +1,203 @@
+package forge.card.abilityfactory.ai;
+
+import java.util.List;
+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.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.ComputerUtil;
+import forge.game.player.Player;
+import forge.game.zone.ZoneType;
+import forge.util.MyRandom;
+
+public class MillAi extends SpellAiLogic {
+
+
+ /**
+ *
+ * millCanPlayAI.
+ *
+ *
+ * @param af
+ * a {@link forge.card.abilityfactory.AbilityFactory} object.
+ * @param sa
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @return a boolean.
+ */
+ @Override
+ public boolean canPlayAI(Player ai, java.util.Map params, SpellAbility sa) {
+ final Card source = sa.getSourceCard();
+ final Cost abCost = sa.getPayCosts();
+
+ 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;
+ }
+
+ if (!CostUtil.checkSacrificeCost(ai, abCost, source)) {
+ return false;
+ }
+
+ if (!CostUtil.checkRemoveCounterCost(abCost, source)) {
+ return false;
+ }
+
+ }
+
+ if (!targetAI(ai, params, sa, false)) {
+ return false;
+ }
+
+ final Random r = MyRandom.getRandom();
+
+ // Don't use draw abilities before main 2 if possible
+ if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) && !params.containsKey("ActivationPhases")) {
+ return false;
+ }
+
+ // Don't tap creatures that may be able to block
+ if (ComputerUtil.waitForBlocking(sa)) {
+ return false;
+ }
+
+ double chance = .4; // 40 percent chance of milling with instant speed
+ // stuff
+ if (AbilityFactory.isSorcerySpeed(sa)) {
+ chance = .667; // 66.7% chance for sorcery speed
+ }
+
+ if ((Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)
+ && Singletons.getModel().getGame().getPhaseHandler().getNextTurn().equals(ai))) {
+ chance = .9; // 90% for end of opponents turn
+ }
+
+ boolean randomReturn = r.nextFloat() <= Math.pow(chance, sa.getActivationsThisTurn() + 1);
+
+ if (params.get("NumCards").equals("X") && source.getSVar("X").startsWith("Count$xPaid")) {
+ // Set PayX here to maximum value.
+ final int cardsToDiscard =
+ Math.min(ComputerUtil.determineLeftoverMana(sa, ai), ai.getOpponent().getCardsIn(ZoneType.Library).size());
+ source.setSVar("PayX", Integer.toString(cardsToDiscard));
+ if (cardsToDiscard <= 0) {
+ return false;
+ }
+ }
+
+ if (AbilityFactory.playReusable(ai, sa)) {
+ randomReturn = true;
+ // some other variables here, like deck size, and phase and other fun stuff
+ }
+
+ return randomReturn;
+ }
+
+ /**
+ *
+ * millTargetAI.
+ *
+ *
+ * @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.
+ */
+ private boolean targetAI(final Player ai, final Map params, final SpellAbility sa, final boolean mandatory) {
+ final Target tgt = sa.getTarget();
+ Player opp = ai.getOpponent();
+
+ if (tgt != null) {
+ tgt.resetTargets();
+ if (!sa.canTarget(opp)) {
+ if (mandatory && sa.canTarget(ai)) {
+ tgt.addTarget(ai);
+ return true;
+ }
+ return false;
+ }
+
+ final int numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
+
+ final List pLibrary = opp.getCardsIn(ZoneType.Library);
+
+ if (pLibrary.size() == 0) { // deck already empty, no need to mill
+ if (!mandatory) {
+ return false;
+ }
+
+ tgt.addTarget(opp);
+ return true;
+ }
+
+ if (numCards >= pLibrary.size()) {
+ // Can Mill out Human's deck? Do it!
+ tgt.addTarget(opp);
+ return true;
+ }
+
+ // Obscure case when you know what your top card is so you might?
+ // want to mill yourself here
+ // if (AI wants to mill self)
+ // tgt.addTarget(AllZone.getComputerPlayer());
+ // else
+ tgt.addTarget(opp);
+ }
+ return true;
+ }
+
+ /**
+ *
+ * millDrawback.
+ *
+ *
+ * @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(Map params, SpellAbility sa, Player aiPlayer) {
+ return targetAI(aiPlayer, params, sa, true);
+ }
+
+
+ @Override
+ public boolean doTriggerAINoCost(Player aiPlayer, Map params, SpellAbility sa, boolean mandatory) {
+ if (!targetAI(aiPlayer, params, sa, mandatory)) {
+ return false;
+ }
+
+ final Card source = sa.getSourceCard();
+ if (params.get("NumCards").equals("X") && source.getSVar("X").equals("Count$xPaid")) {
+ // Set PayX here to maximum value.
+ final int cardsToDiscard = Math.min(ComputerUtil.determineLeftoverMana(sa, aiPlayer), aiPlayer.getOpponent()
+ .getCardsIn(ZoneType.Library).size());
+ source.setSVar("PayX", Integer.toString(cardsToDiscard));
+ }
+
+ // 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/ShuffleAi.java b/src/main/java/forge/card/abilityfactory/ai/ShuffleAi.java
new file mode 100644
index 00000000000..e9970070ea1
--- /dev/null
+++ b/src/main/java/forge/card/abilityfactory/ai/ShuffleAi.java
@@ -0,0 +1,98 @@
+package forge.card.abilityfactory.ai;
+
+import forge.card.abilityfactory.SpellAiLogic;
+import forge.card.spellability.AbilitySub;
+import forge.card.spellability.SpellAbility;
+import forge.game.player.Player;
+
+public class ShuffleAi extends SpellAiLogic {
+ /**
+ *
+ * shuffleCanPlayAI.
+ *
+ *
+ * @param af
+ * a {@link forge.card.abilityfactory.AbilityFactory} object.
+ * @param sa
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @return a boolean.
+ */
+ @Override
+ public boolean canPlayAI(Player aiPlayer, java.util.Map params, SpellAbility sa) {
+ // not really sure when the compy would use this; maybe only after a
+ // human
+ // deliberately put a card on top of their library
+ return false;
+ /*
+ * if (!ComputerUtil.canPayCost(sa)) return false;
+ *
+ * Card source = sa.getSourceCard();
+ *
+ * Random r = MyRandom.random; boolean randomReturn = r.nextFloat() <=
+ * Math.pow(.667, sa.getActivationsThisTurn()+1);
+ *
+ * if (AbilityFactory.playReusable(sa)) randomReturn = true;
+ *
+ * Ability_Sub subAb = sa.getSubAbility(); if (subAb != null)
+ * randomReturn &= subAb.chkAI_Drawback(); return randomReturn;
+ */
+ }
+
+ /**
+ *
+ * shuffleTargetAI.
+ *
+ * @param sa
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @param af
+ * a {@link forge.card.abilityfactory.AbilityFactory} object.
+ * @param primarySA
+ * a boolean.
+ * @param mandatory
+ * a boolean.
+ *
+ * @return a boolean.
+ */
+ @Override
+ public boolean chkAIDrawback(java.util.Map params, SpellAbility sa, Player aiPlayer) {
+ return shuffleTargetAI(sa, false, false);
+ }
+
+
+
+ private boolean shuffleTargetAI(final SpellAbility sa, final boolean primarySA, final boolean mandatory) {
+ return false;
+
+
+
+
+ } // shuffleTargetAI()
+
+ /**
+ *
+ * shuffleTrigger.
+ *
+ *
+ * @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) {
+ if (!shuffleTargetAI(sa, false, mandatory)) {
+ return false;
+ }
+
+ // 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/effects/BondEffect.java b/src/main/java/forge/card/abilityfactory/effects/BondEffect.java
index 7a721348cc2..7325c75cf01 100644
--- a/src/main/java/forge/card/abilityfactory/effects/BondEffect.java
+++ b/src/main/java/forge/card/abilityfactory/effects/BondEffect.java
@@ -26,10 +26,6 @@ public class BondEffect extends SpellEffect {
*/
@Override
public void resolve(java.util.Map params, SpellAbility sa) {
-// final Card source = sa.getSourceCard();
-// final Card host = af.getHostCard();
-// final Map svars = host.getSVars();
-
// find card that triggered pairing first
ArrayList trigCards;
trigCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa);
@@ -48,119 +44,40 @@ public class BondEffect extends SpellEffect {
Card partner = cards.get(0);
// skip choice if only one card on list
- if (cards.size() > 1 && sa.getActivatingPlayer().isHuman()) {
- Object o = GuiChoose.one("Select a card to pair with", cards);
-
- if (o != null) {
- partner = (Card) o;
+ if (cards.size() > 1)
+ if ( sa.getActivatingPlayer().isHuman() ) {
+ Card o = GuiChoose.one("Select a card to pair with", cards);
+ if (o != null) {
+ partner = o;
+ }
+ } else {
+ // TODO - Pick best creature instead of just the first on the list
+ partner = CardFactoryUtil.getBestCreatureAI(cards);
}
- } else if (cards.size() > 1) {
- // TODO - Pick best creature instead of just the first on the list
- partner = CardFactoryUtil.getBestCreatureAI(cards);
- }
// pair choices together
trigCards.get(0).setPairedWith(partner);
partner.setPairedWith(trigCards.get(0));
+ }
- } // bondResolve
-
- // /**
- // *
- // * createSpellBond.
- // *
- // *
- // * @param af
- // * a {@link forge.card.abilityfactory.AbilityFactory} object.
- // * @return a {@link forge.card.spellability.SpellAbility} object.
- // */
- // public static SpellAbility createSpellBond(final AbilityFactory af) {
- // final SpellAbility spBond = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
- // private static final long serialVersionUID = -4047747186919390147L;
- //
- // @Override
- // public boolean canPlayAI() {
- // return AbilityFactoryBond.bondCanPlayAI(af, this);
- // }
- //
- // @Override
- // public void resolve() {
- // AbilityFactoryBond.bondResolve(af, this);
- // }
- //
- // @Override
- // public String getStackDescription() {
- // return AbilityFactoryBond.bondStackDescription(af, this);
- // }
- // };
- // return spBond;
- // }
- //
- // /**
- // *
- // * createDrawbackBond.
- // *
- // *
- // * @param af
- // * a {@link forge.card.abilityfactory.AbilityFactory} object.
- // * @return a {@link forge.card.spellability.SpellAbility} object.
- // */
- // public static SpellAbility createDrawbackBond(final AbilityFactory af) {
- // final SpellAbility dbBond = new AbilitySub(af.getHostCard(), af.getAbTgt()) {
- // private static final long serialVersionUID = -8659938411460952874L;
- //
- // @Override
- // public void resolve() {
- // AbilityFactoryBond.bondResolve(af, this);
- // }
- //
- // @Override
- // public boolean chkAIDrawback() {
- // return AbilityFactoryBond.bondPlayDrawbackAI(af, this);
- // }
- //
- // @Override
- // public String getStackDescription() {
- // return AbilityFactoryBond.bondStackDescription(af, this);
- // }
- //
- // @Override
- // public boolean doTrigger(final boolean mandatory) {
- // return AbilityFactoryBond.bondTriggerAI(af, this, mandatory);
- // }
- // };
- // return dbBond;
- // }
-
- /**
- *
- * bondStackDescription.
- *
- *
- * @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
public String getStackDescription(java.util.Map params, SpellAbility sa) {
- ArrayList tgts;
- tgts = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa);
-
- final StringBuilder sb = new StringBuilder();
-
- for (final Card c : tgts) {
- sb.append(c).append(" ");
- }
- sb.append("pairs with another unpaired creature you control.");
-
- final AbilitySub abSub = sa.getSubAbility();
- if (abSub != null) {
- sb.append(abSub.getStackDescription());
- }
-
- return sb.toString();
- } // end bondStackDescription()
+ ArrayList tgts;
+ tgts = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa);
-} // end class AbilityFactoryBond
\ No newline at end of file
+ final StringBuilder sb = new StringBuilder();
+
+ for (final Card c : tgts) {
+ sb.append(c).append(" ");
+ }
+ sb.append("pairs with another unpaired creature you control.");
+
+ final AbilitySub abSub = sa.getSubAbility();
+ if (abSub != null) {
+ sb.append(abSub.getStackDescription());
+ }
+
+ return sb.toString();
+ } // end bondStackDescription()
+
+}
\ No newline at end of file
diff --git a/src/main/java/forge/card/abilityfactory/effects/DiscardEffect.java b/src/main/java/forge/card/abilityfactory/effects/DiscardEffect.java
new file mode 100644
index 00000000000..ac7758fc307
--- /dev/null
+++ b/src/main/java/forge/card/abilityfactory/effects/DiscardEffect.java
@@ -0,0 +1,355 @@
+package forge.card.abilityfactory.effects;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.google.common.base.Predicate;
+
+import forge.Card;
+import forge.CardLists;
+import forge.CardUtil;
+import forge.GameActionUtil;
+import forge.card.abilityfactory.AbilityFactory;
+import forge.card.abilityfactory.AbilityFactoryReveal;
+import forge.card.abilityfactory.SpellEffect;
+import forge.card.cardfactory.CardFactoryUtil;
+import forge.card.spellability.AbilitySub;
+import forge.card.spellability.SpellAbility;
+import forge.card.spellability.Target;
+import forge.game.player.ComputerUtil;
+import forge.game.player.Player;
+import forge.game.zone.ZoneType;
+import forge.gui.GuiChoose;
+
+public class DiscardEffect extends SpellEffect {
+ /**
+ *
+ * discardStackDescription.
+ *
+ *
+ * @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
+ public String getStackDescription(java.util.Map params, SpellAbility sa) {
+ final String mode = params.get("Mode");
+ final StringBuilder sb = new StringBuilder();
+
+ ArrayList tgtPlayers;
+
+ final Target tgt = sa.getTarget();
+ if (tgt != null) {
+ tgtPlayers = tgt.getTargetPlayers();
+ } else {
+ tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
+ }
+
+ if (!(sa instanceof AbilitySub)) {
+ sb.append(sa.getSourceCard().getName()).append(" - ");
+ } else {
+ sb.append(" ");
+ }
+
+ final String conditionDesc = params.get("ConditionDescription");
+ if (conditionDesc != null) {
+ sb.append(conditionDesc).append(" ");
+ }
+
+ if (tgtPlayers.size() > 0) {
+
+ for (final Player p : tgtPlayers) {
+ sb.append(p.toString()).append(" ");
+ }
+
+ if (mode.equals("RevealYouChoose")) {
+ sb.append("reveals his or her hand.").append(" You choose (");
+ } else if (mode.equals("RevealDiscardAll")) {
+ sb.append("reveals his or her hand. Discard (");
+ } else {
+ sb.append("discards (");
+ }
+
+ int numCards = 1;
+ if (params.containsKey("NumCards")) {
+ numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
+ }
+
+ if (mode.equals("Hand")) {
+ sb.append("his or her hand");
+ } else if (mode.equals("RevealDiscardAll")) {
+ sb.append("All");
+ } else {
+ sb.append(numCards);
+ }
+
+ sb.append(")");
+
+ if (mode.equals("RevealYouChoose")) {
+ sb.append(" to discard");
+ } else if (mode.equals("RevealDiscardAll")) {
+ String valid = params.get("DiscardValid");
+ if (valid == null) {
+ valid = "Card";
+ }
+ sb.append(" of type: ").append(valid);
+ }
+
+ if (mode.equals("Defined")) {
+ sb.append(" defined cards");
+ }
+
+ if (mode.equals("Random")) {
+ sb.append(" at random.");
+ } else {
+ sb.append(".");
+ }
+ }
+
+ final AbilitySub abSub = sa.getSubAbility();
+ if (abSub != null) {
+ sb.append(abSub.getStackDescription());
+ }
+
+ return sb.toString();
+ } // discardStackDescription()
+
+ /**
+ *
+ * discardResolve.
+ *
+ *
+ * @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 Card source = sa.getSourceCard();
+ final String mode = params.get("Mode");
+
+ ArrayList tgtPlayers;
+
+ final Target tgt = sa.getTarget();
+ if (tgt != null) {
+ tgtPlayers = tgt.getTargetPlayers();
+ } else {
+ tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
+ }
+
+ final List discarded = new ArrayList();
+
+ for (final Player p : tgtPlayers) {
+ if ((tgt == null) || p.canBeTargetedBy(sa)) {
+ if (mode.equals("Defined")) {
+ final ArrayList toDiscard = AbilityFactory.getDefinedCards(source, params.get("DefinedCards"),
+ sa);
+ for (final Card c : toDiscard) {
+ discarded.addAll(p.discard(c, sa));
+ }
+ if (params.containsKey("RememberDiscarded")) {
+ for (final Card c : discarded) {
+ source.addRemembered(c);
+ }
+ }
+ continue;
+ }
+
+ if (mode.equals("Hand")) {
+ final List list = p.discardHand(sa);
+ if (params.containsKey("RememberDiscarded")) {
+ for (final Card c : list) {
+ source.addRemembered(c);
+ }
+ }
+ continue;
+ }
+
+ if (mode.equals("NotRemembered")) {
+ final List dPHand =
+ CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), "Card.IsNotRemembered", source.getController(), source);
+ for (final Card c : dPHand) {
+ p.discard(c, sa);
+ discarded.add(c);
+ }
+ }
+
+ int numCards = 1;
+ if (params.containsKey("NumCards")) {
+ numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
+ if (p.getCardsIn(ZoneType.Hand).size() > 0
+ && p.getCardsIn(ZoneType.Hand).size() < numCards) {
+ // System.out.println("Scale down discard from " + numCards + " to " + p.getCardsIn(ZoneType.Hand).size());
+ numCards = p.getCardsIn(ZoneType.Hand).size();
+ }
+ }
+
+ if (mode.equals("Random")) {
+ boolean runDiscard = true;
+ if (params.containsKey("Optional")) {
+ if (p.isHuman()) {
+ // TODO Ask if Human would like to discard a card at Random
+ StringBuilder sb = new StringBuilder("Would you like to discard ");
+ sb.append(numCards).append(" random card(s)?");
+ runDiscard = GameActionUtil.showYesNoDialog(source, sb.toString());
+ }
+ else {
+ // TODO For now AI will always discard Random used currently with:
+ // Balduvian Horde and similar cards
+ }
+ }
+
+ if (runDiscard) {
+ final String valid = params.containsKey("DiscardValid") ? params.get("DiscardValid") : "Card";
+ discarded.addAll(p.discardRandom(numCards, sa, valid));
+ }
+ } else if (mode.equals("TgtChoose") && params.containsKey("UnlessType")) {
+ p.discardUnless(numCards, params.get("UnlessType"), sa);
+ } else if (mode.equals("RevealDiscardAll")) {
+ // Reveal
+ final List dPHand = p.getCardsIn(ZoneType.Hand);
+
+ if (p.isHuman()) {
+ // "reveal to computer" for information gathering
+ } else {
+ GuiChoose.oneOrNone("Revealed computer hand", dPHand);
+ }
+
+ String valid = params.get("DiscardValid");
+ if (valid == null) {
+ valid = "Card";
+ }
+
+ if (valid.contains("X")) {
+ valid = valid.replace("X", Integer.toString(AbilityFactory.calculateAmount(source, "X", sa)));
+ }
+
+ final List dPChHand = CardLists.getValidCards(dPHand, valid.split(","), source.getController(), source);
+ // Reveal cards that will be discarded?
+ for (final Card c : dPChHand) {
+ p.discard(c, sa);
+ discarded.add(c);
+ }
+ } else if (mode.equals("RevealYouChoose") || mode.equals("RevealOppChoose") || mode.equals("TgtChoose")) {
+ // Is Reveal you choose right? I think the wrong player is
+ // being used?
+ List dPHand = new ArrayList(p.getCardsIn(ZoneType.Hand));
+ if (dPHand.size() != 0) {
+ if (params.containsKey("RevealNumber")) {
+ String amountString = params.get("RevealNumber");
+ int amount = amountString.matches("[0-9][0-9]?") ? Integer.parseInt(amountString)
+ : CardFactoryUtil.xCount(source, source.getSVar(amountString));
+ dPHand = AbilityFactoryReveal.getRevealedList(p, dPHand, amount, false);
+ }
+ List dPChHand = new ArrayList(dPHand);
+ String[] dValid = null;
+ if (params.containsKey("DiscardValid")) { // Restrict card choices
+ dValid = params.get("DiscardValid").split(",");
+ dPChHand = CardLists.getValidCards(dPHand, dValid, source.getController(), source);
+ }
+ Player chooser = p;
+ if (mode.equals("RevealYouChoose")) {
+ chooser = source.getController();
+ } else if (mode.equals("RevealOppChoose")) {
+ chooser = source.getController().getOpponent();
+ }
+
+ if (chooser.isComputer()) {
+ // AI
+ if (p.isComputer()) { // discard AI cards
+ int max = chooser.getCardsIn(ZoneType.Hand).size();
+ max = Math.min(max, numCards);
+ List list = ComputerUtil.discardNumTypeAI(p, max, dValid, sa);
+ if (mode.startsWith("Reveal")) {
+ GuiChoose.oneOrNone("Computer has chosen", list);
+ }
+ discarded.addAll(list);
+ for (Card card : list) {
+ p.discard(card, sa);
+ }
+ continue;
+ }
+ // discard human cards
+ for (int i = 0; i < numCards; i++) {
+ if (dPChHand.size() > 0) {
+ List goodChoices = CardLists.filter(dPChHand, new Predicate() {
+ @Override
+ public boolean apply(final Card c) {
+ if (c.hasKeyword("If a spell or ability an opponent controls causes you to discard CARDNAME," +
+ " put it onto the battlefield instead of putting it into your graveyard.")
+ || !c.getSVar("DiscardMe").equals("")) {
+ return false;
+ }
+ return true;
+ }
+ });
+ if (goodChoices.isEmpty()) {
+ goodChoices = dPChHand;
+ }
+ final List dChoices = new ArrayList();
+ if (params.containsKey("DiscardValid")) {
+ final String validString = params.get("DiscardValid");
+ if (validString.contains("Creature") && !validString.contains("nonCreature")) {
+ final Card c = CardFactoryUtil.getBestCreatureAI(goodChoices);
+ if (c != null) {
+ dChoices.add(CardFactoryUtil.getBestCreatureAI(goodChoices));
+ }
+ }
+ }
+
+ Collections.sort(goodChoices, CardLists.TextLenReverseComparator);
+
+ CardLists.sortCMC(goodChoices);
+ dChoices.add(goodChoices.get(0));
+
+ final Card dC = goodChoices.get(CardUtil.getRandomIndex(goodChoices));
+ dPChHand.remove(dC);
+
+ if (mode.startsWith("Reveal")) {
+ final List dCs = new ArrayList();
+ dCs.add(dC);
+ GuiChoose.oneOrNone("Computer has chosen", dCs);
+ }
+ discarded.add(dC);
+ p.discard(dC, sa);
+ }
+ }
+ } else {
+ // human
+ if (mode.startsWith("Reveal")) {
+ GuiChoose.oneOrNone("Revealed " + p + " hand", dPHand);
+ }
+
+ for (int i = 0; i < numCards; i++) {
+ if (dPChHand.size() > 0) {
+ Card dC = null;
+ if (params.containsKey("Optional")) {
+ dC = GuiChoose.oneOrNone("Choose a card to be discarded", dPChHand);
+ } else {
+ dC = GuiChoose.one("Choose a card to be discarded", dPChHand);
+ } if (dC != null) {
+ dPChHand.remove(dC);
+ discarded.add(dC);
+ p.discard(dC, sa);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (params.containsKey("RememberDiscarded")) {
+ for (final Card c : discarded) {
+ source.addRemembered(c);
+ }
+ }
+
+ } // discardResolve()
+
+}
\ No newline at end of file
diff --git a/src/main/java/forge/card/abilityfactory/effects/DrawEffect.java b/src/main/java/forge/card/abilityfactory/effects/DrawEffect.java
new file mode 100644
index 00000000000..94424cd0aca
--- /dev/null
+++ b/src/main/java/forge/card/abilityfactory/effects/DrawEffect.java
@@ -0,0 +1,169 @@
+package forge.card.abilityfactory.effects;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import forge.Card;
+import forge.GameActionUtil;
+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;
+import forge.game.zone.ZoneType;
+import forge.gui.GuiChoose;
+
+public class DrawEffect extends SpellEffect {
+ /**
+ *
+ * drawStackDescription.
+ *
+ *
+ * @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
+ 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(" ");
+ }
+
+ final String conditionDesc = params.get("ConditionDescription");
+ if (conditionDesc != null) {
+ sb.append(conditionDesc).append(" ");
+ }
+
+ ArrayList tgtPlayers;
+
+ final Target tgt = sa.getTarget();
+ if (!params.containsKey("Defined") && tgt != null) {
+ tgtPlayers = tgt.getTargetPlayers();
+ } else {
+ tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
+ }
+
+ if (tgtPlayers.size() > 0) {
+ final Iterator it = tgtPlayers.iterator();
+ while (it.hasNext()) {
+ sb.append(it.next().toString());
+ if (it.hasNext()) {
+ sb.append(" and ");
+ }
+ }
+
+ int numCards = 1;
+ if (params.containsKey("NumCards")) {
+ numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
+ }
+
+ if (tgtPlayers.size() > 1) {
+ sb.append(" each");
+ }
+ sb.append(" draw");
+ if (tgtPlayers.size() == 1) {
+ sb.append("s");
+ }
+ sb.append(" (").append(numCards).append(")");
+
+ if (params.containsKey("NextUpkeep")) {
+ sb.append(" at the beginning of the next upkeep");
+ }
+
+ sb.append(".");
+ }
+
+ final AbilitySub abSub = sa.getSubAbility();
+ if (abSub != null) {
+ sb.append(abSub.getStackDescription());
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ *
+ * drawResolve.
+ *
+ *
+ * @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 Card source = sa.getSourceCard();
+ int numCards = 1;
+ if (params.containsKey("NumCards")) {
+ numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
+ }
+
+ ArrayList tgtPlayers;
+
+ final Target tgt = sa.getTarget();
+ if (!params.containsKey("Defined") && tgt != null) {
+ tgtPlayers = tgt.getTargetPlayers();
+ } else {
+ tgtPlayers = AbilityFactory.getDefinedPlayers(source, params.get("Defined"), sa);
+ }
+
+ final boolean optional = params.containsKey("OptionalDecider");
+ final boolean slowDraw = params.containsKey("NextUpkeep");
+
+ for (final Player p : tgtPlayers) {
+ if ((tgt == null) || p.canBeTargetedBy(sa)) {
+ if (optional) {
+ if (p.isComputer()) {
+ if (numCards >= p.getCardsIn(ZoneType.Library).size()) {
+ // AI shouldn't itself
+ continue;
+ }
+ } else {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Do you want to draw ").append(numCards).append(" cards(s)");
+
+ if (slowDraw) {
+ sb.append(" next upkeep");
+ }
+
+ sb.append("?");
+
+ if (!GameActionUtil.showYesNoDialog(sa.getSourceCard(), sb.toString())) {
+ continue;
+ }
+ }
+ }
+
+ if (slowDraw) {
+ for (int i = 0; i < numCards; i++) {
+ p.addSlowtripList(source);
+ }
+ } else {
+ final List drawn = p.drawCards(numCards);
+ if (params.containsKey("Reveal")) {
+ GuiChoose.one("Revealing drawn cards", drawn);
+ }
+ if (params.containsKey("RememberDrawn")) {
+ for (final Card c : drawn) {
+ source.addRemembered(c);
+ }
+ }
+
+ }
+
+ }
+ }
+ } // drawResolve()
+}
+ // **********************************************************************
+ // ******************************* MILL *********************************
+ // **********************************************************************
\ No newline at end of file
diff --git a/src/main/java/forge/card/abilityfactory/effects/MillEffect.java b/src/main/java/forge/card/abilityfactory/effects/MillEffect.java
new file mode 100644
index 00000000000..1d7bc2d37a7
--- /dev/null
+++ b/src/main/java/forge/card/abilityfactory/effects/MillEffect.java
@@ -0,0 +1,140 @@
+package forge.card.abilityfactory.effects;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+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;
+import forge.game.player.Player;
+import forge.game.zone.ZoneType;
+
+public class MillEffect extends SpellEffect {
+
+ /**
+ *
+ * millResolve.
+ *
+ *
+ * @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 Card source = sa.getSourceCard();
+ final int numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
+ final boolean bottom = params.containsKey("FromBottom");
+
+ if (params.containsKey("ForgetOtherRemembered")) {
+ source.clearRemembered();
+ }
+
+ ArrayList tgtPlayers;
+
+ final Target tgt = sa.getTarget();
+ if (tgt != null) {
+ tgtPlayers = tgt.getTargetPlayers();
+ } else {
+ tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
+ }
+
+ ZoneType destination = ZoneType.smartValueOf(params.get("Destination"));
+ if (destination == null) {
+ destination = ZoneType.Graveyard;
+ }
+
+ for (final Player p : tgtPlayers) {
+ if ((tgt == null) || p.canBeTargetedBy(sa)) {
+ final List milled = p.mill(numCards, destination, bottom);
+ if (params.containsKey("RememberMilled")) {
+ for (final Card c : milled) {
+ source.addRemembered(c);
+ }
+ }
+ if (params.containsKey("Imprint")) {
+ for (final Card c : milled) {
+ source.addImprinted(c);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ * millStackDescription.
+ *
+ *
+ * @param sa
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @param af
+ * a {@link forge.card.abilityfactory.AbilityFactory} object.
+ * @return a {@link java.lang.String} object.
+ */
+ @Override
+ public String getStackDescription(Map params, SpellAbility sa) {
+ final StringBuilder sb = new StringBuilder();
+ final int numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
+
+ ArrayList tgtPlayers;
+
+ final Target tgt = sa.getTarget();
+ if (tgt != null) {
+ tgtPlayers = tgt.getTargetPlayers();
+ } else {
+ tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
+ }
+
+ if (!(sa instanceof AbilitySub)) {
+ sb.append(sa.getSourceCard().getName()).append(" - ");
+ } else {
+ sb.append(" ");
+ }
+
+ final String conditionDesc = params.get("ConditionDescription");
+ if (conditionDesc != null) {
+ sb.append(conditionDesc).append(" ");
+ }
+
+ if (params.containsKey("StackDescription")) {
+ if (params.get("StackDescription").equals("None")) {
+ sb.append("");
+ } else {
+ sb.append(params.get("StackDescription"));
+ }
+ } else {
+ for (final Player p : tgtPlayers) {
+ sb.append(p.toString()).append(" ");
+ }
+
+ final ZoneType dest = ZoneType.smartValueOf(params.get("Destination"));
+ if ((dest == null) || dest.equals(ZoneType.Graveyard)) {
+ sb.append("mills ");
+ } else if (dest.equals(ZoneType.Exile)) {
+ sb.append("exiles ");
+ } else if (dest.equals(ZoneType.Ante)) {
+ sb.append("antes ");
+ }
+ sb.append(numCards);
+ sb.append(" card");
+ if (numCards != 1) {
+ sb.append("s");
+ }
+ final String millPosition = params.containsKey("FromBottom") ? "bottom" : "top";
+ sb.append(" from the " + millPosition + " of his or her library.");
+ }
+
+ final AbilitySub abSub = sa.getSubAbility();
+ if (abSub != null) {
+ sb.append(abSub.getStackDescription());
+ }
+
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/forge/card/abilityfactory/effects/ShuffleEffect.java b/src/main/java/forge/card/abilityfactory/effects/ShuffleEffect.java
new file mode 100644
index 00000000000..37804bd5d07
--- /dev/null
+++ b/src/main/java/forge/card/abilityfactory/effects/ShuffleEffect.java
@@ -0,0 +1,103 @@
+package forge.card.abilityfactory.effects;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import forge.Card;
+import forge.GameActionUtil;
+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;
+
+/**
+ *
+ * shuffleResolve.
+ *
+ *
+ * @param af
+ * a {@link forge.card.abilityfactory.AbilityFactory} object.
+ * @param sa
+ * a {@link forge.card.spellability.SpellAbility} object.
+ */
+
+public class ShuffleEffect extends SpellEffect {
+ @Override
+ public void resolve(java.util.Map params, SpellAbility sa) {
+ final Card host = sa.getSourceCard();
+ final boolean optional = params.containsKey("Optional");
+
+ ArrayList tgtPlayers;
+
+ final Target tgt = sa.getTarget();
+ if (tgt != null) {
+ tgtPlayers = tgt.getTargetPlayers();
+ } else {
+ tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
+ }
+
+ for (final Player p : tgtPlayers) {
+ if ((tgt == null) || p.canBeTargetedBy(sa)) {
+ if (optional && sa.getActivatingPlayer().isHuman()
+ && !GameActionUtil.showYesNoDialog(host, "Have " + p + " shuffle?")) {
+ } else {
+ p.shuffle();
+ }
+ }
+ }
+ }
+
+ @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(" ");
+ }
+
+ final String conditionDesc = params.get("ConditionDescription");
+ if (conditionDesc != null) {
+ sb.append(conditionDesc).append(" ");
+ }
+
+ ArrayList tgtPlayers;
+
+ final Target tgt = sa.getTarget();
+ if (tgt != null) {
+ tgtPlayers = tgt.getTargetPlayers();
+ } else {
+ tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
+ }
+
+ if (tgtPlayers.size() > 0) {
+ final Iterator it = tgtPlayers.iterator();
+ while (it.hasNext()) {
+ sb.append(it.next().getName());
+ if (it.hasNext()) {
+ sb.append(" and ");
+ }
+ }
+ } else {
+ sb.append("Error - no target players for Shuffle. ");
+ }
+ sb.append(" shuffle");
+ if (tgtPlayers.size() > 1) {
+ sb.append(" their libraries");
+ } else {
+ sb.append("s his or her library");
+ }
+ sb.append(".");
+
+ final AbilitySub abSub = sa.getSubAbility();
+ if (abSub != null) {
+ sb.append(abSub.getStackDescription());
+ }
+
+ return sb.toString();
+ }
+
+} // end class AbilityFactory_ZoneAffecting
\ No newline at end of file
diff --git a/src/main/java/forge/card/abilityfactory/effects/TokenEffect.java b/src/main/java/forge/card/abilityfactory/effects/TokenEffect.java
index 8edf5b40d77..a4ddcf92058 100644
--- a/src/main/java/forge/card/abilityfactory/effects/TokenEffect.java
+++ b/src/main/java/forge/card/abilityfactory/effects/TokenEffect.java
@@ -18,7 +18,6 @@
package forge.card.abilityfactory.effects;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -28,9 +27,7 @@ import forge.Singletons;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.SpellEffect;
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.trigger.Trigger;
import forge.card.trigger.TriggerHandler;