refactor AF: ZoneAffecting

some cleanup in BondEffect.java
This commit is contained in:
Maxmtg
2012-10-30 04:51:15 +00:00
parent 053434cb4a
commit 923c0ad42c
18 changed files with 1634 additions and 2298 deletions

11
.gitattributes vendored
View File

@@ -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

View File

@@ -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;
}
/**
* <p>
* Setter for the field <code>abTgt</code>.
* </p>
*
* @param target
* a target object.
*/
public final void setAbTgt(final Target target) {
this.abTgt = target;
}
/**
* <p>
@@ -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")) {

View File

@@ -23,5 +23,5 @@ public abstract class SpellAiLogic {
}
// consider safe
public boolean chkAIDrawback(Map<String, String> params, SpellAbility sa) { return true; }
public boolean chkAIDrawback(Map<String, String> params, SpellAbility sa, Player aiPlayer) { return true; }
}

View File

@@ -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();

View File

@@ -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<String,String> params, SpellAbility sa) {
public boolean chkAIDrawback(java.util.Map<String,String> params, SpellAbility sa, Player aiPlayer) {
return true;
}

View File

@@ -124,7 +124,7 @@ public class AnimateAi extends SpellAiLogic {
@Override
public boolean chkAIDrawback(Map<String, String> params, SpellAbility sa) {
public boolean chkAIDrawback(Map<String, String> params, SpellAbility sa, Player aiPlayer) {
boolean chance = true;
if (sa.getTarget() != null) {

View File

@@ -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 {
/**
* <p>
* discardCanPlayAI.
* </p>
*
* @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<String,String> 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<Player> 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()
/**
* <p>
* discardTargetAI.
* </p>
*
* @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()
/**
* <p>
* discardTriggerNoCost.
* </p>
*
* @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<String,String> 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()
/**
* <p>
* discardCheckDrawbackAI.
* </p>
* @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<String,String> 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()
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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;
/**
* <p>
* drawCanPlayAI.
* </p>
*
* @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<String, String> 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<Card> 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<Player> 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;
}
/**
* <p>
* drawTargetAI.
* </p>
*
* @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<String, String> 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()
/**
* <p>
* drawTriggerNoCost.
* </p>
*
* @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<String,String> 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;
}
}

View File

@@ -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<String,String> params, SpellAbility sa) { return false; }
public boolean chkAIDrawback(java.util.Map<String,String> 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)

View File

@@ -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 {
/**
* <p>
* millCanPlayAI.
* </p>
*
* @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<String,String> 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;
}
/**
* <p>
* millTargetAI.
* </p>
*
* @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<String, String> 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<Card> 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;
}
/**
* <p>
* millDrawback.
* </p>
*
* @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<String,String> params, SpellAbility sa, Player aiPlayer) {
return targetAI(aiPlayer, params, sa, true);
}
@Override
public boolean doTriggerAINoCost(Player aiPlayer, Map<String,String> 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;
}
}

View File

@@ -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 {
/**
* <p>
* shuffleCanPlayAI.
* </p>
*
* @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<String,String> 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;
*/
}
/**
* <p>
* shuffleTargetAI.
* </p>
* @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<String,String> 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()
/**
* <p>
* shuffleTrigger.
* </p>
*
* @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<String,String> 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;
}
}

View File

@@ -26,10 +26,6 @@ public class BondEffect extends SpellEffect {
*/
@Override
public void resolve(java.util.Map<String,String> params, SpellAbility sa) {
// final Card source = sa.getSourceCard();
// final Card host = af.getHostCard();
// final Map<String, String> svars = host.getSVars();
// find card that triggered pairing first
ArrayList<Card> trigCards;
trigCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa);
@@ -48,13 +44,13 @@ 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 (cards.size() > 1)
if ( sa.getActivatingPlayer().isHuman() ) {
Card o = GuiChoose.one("Select a card to pair with", cards);
if (o != null) {
partner = (Card) o;
partner = o;
}
} else if (cards.size() > 1) {
} else {
// TODO - Pick best creature instead of just the first on the list
partner = CardFactoryUtil.getBestCreatureAI(cards);
}
@@ -62,87 +58,8 @@ public class BondEffect extends SpellEffect {
// pair choices together
trigCards.get(0).setPairedWith(partner);
partner.setPairedWith(trigCards.get(0));
}
} // bondResolve
// /**
// * <p>
// * createSpellBond.
// * </p>
// *
// * @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;
// }
//
// /**
// * <p>
// * createDrawbackBond.
// * </p>
// *
// * @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;
// }
/**
* <p>
* bondStackDescription.
* </p>
*
* @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<String,String> params, SpellAbility sa) {
ArrayList<Card> tgts;
@@ -163,4 +80,4 @@ public class BondEffect extends SpellEffect {
return sb.toString();
} // end bondStackDescription()
} // end class AbilityFactoryBond
}

View File

@@ -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 {
/**
* <p>
* discardStackDescription.
* </p>
*
* @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<String,String> params, SpellAbility sa) {
final String mode = params.get("Mode");
final StringBuilder sb = new StringBuilder();
ArrayList<Player> 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()
/**
* <p>
* discardResolve.
* </p>
*
* @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<String,String> params, SpellAbility sa) {
final Card source = sa.getSourceCard();
final String mode = params.get("Mode");
ArrayList<Player> tgtPlayers;
final Target tgt = sa.getTarget();
if (tgt != null) {
tgtPlayers = tgt.getTargetPlayers();
} else {
tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
}
final List<Card> discarded = new ArrayList<Card>();
for (final Player p : tgtPlayers) {
if ((tgt == null) || p.canBeTargetedBy(sa)) {
if (mode.equals("Defined")) {
final ArrayList<Card> 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<Card> list = p.discardHand(sa);
if (params.containsKey("RememberDiscarded")) {
for (final Card c : list) {
source.addRemembered(c);
}
}
continue;
}
if (mode.equals("NotRemembered")) {
final List<Card> 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<Card> 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<Card> 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<Card> dPHand = new ArrayList<Card>(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<Card> dPChHand = new ArrayList<Card>(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<Card> 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<Card> goodChoices = CardLists.filter(dPChHand, new Predicate<Card>() {
@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<Card> dChoices = new ArrayList<Card>();
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<Card> dCs = new ArrayList<Card>();
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()
}

View File

@@ -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 {
/**
* <p>
* drawStackDescription.
* </p>
*
* @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<String,String> 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<Player> 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<Player> 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();
}
/**
* <p>
* drawResolve.
* </p>
*
* @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<String,String> 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<Player> 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<Card> 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 *********************************
// **********************************************************************

View File

@@ -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 {
/**
* <p>
* millResolve.
* </p>
*
* @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<String,String> 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<Player> 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<Card> 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);
}
}
}
}
}
/**
* <p>
* millStackDescription.
* </p>
*
* @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<String,String> params, SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
final int numCards = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("NumCards"), sa);
ArrayList<Player> 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();
}
}

View File

@@ -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;
/**
* <p>
* shuffleResolve.
* </p>
*
* @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<String,String> params, SpellAbility sa) {
final Card host = sa.getSourceCard();
final boolean optional = params.containsKey("Optional");
ArrayList<Player> 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<String,String> 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<Player> 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<Player> 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

View File

@@ -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;