diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index 51209bf93b6..d7c923a9417 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -43,7 +43,6 @@ import mage.abilities.effects.SearchEffect; import mage.cards.Card; import mage.cards.Cards; import mage.choices.Choice; -import mage.filter.FilterAbility; import mage.game.Game; import mage.game.combat.Combat; import mage.game.combat.CombatGroup; @@ -218,7 +217,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements logger.info("simulating actions"); //int bestScore = addActionsTimed(new FilterAbility()); currentScore = GameStateEvaluator2.evaluate(playerId, game); - addActionsTimed(new FilterAbility()); + addActionsTimed(); if (root.children.size() > 0) { root = root.children.get(0); //GameStateEvaluator2.evaluate(playerId, root.getGame()); @@ -268,7 +267,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements return false; } - protected int minimaxAB(SimulationNode2 node, FilterAbility filter, int depth, int alpha, int beta) { + protected int minimaxAB(SimulationNode2 node, int depth, int alpha, int beta) { UUID currentPlayerId = node.getGame().getPlayerList().get(); SimulationNode2 bestChild = null; for (SimulationNode2 child: node.getChildren()) { @@ -281,7 +280,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements //logger.info("simulating -- reached end-state, count=" + SimulationNode2.nodeCount); break; } - int val = addActions(child, filter, depth-1, alpha, beta); + int val = addActions(child, depth-1, alpha, beta); if (!currentPlayerId.equals(playerId)) { if (val < beta) { beta = val; @@ -364,12 +363,12 @@ public class ComputerPlayer6 extends ComputerPlayer implements game.getPlayerList().setCurrent(game.getActivePlayerId()); } - protected Integer addActionsTimed(final FilterAbility filter) { + protected Integer addActionsTimed() { FutureTask task = new FutureTask(new Callable() { @Override public Integer call() throws Exception { - return addActions(root, filter, maxDepth, Integer.MIN_VALUE, Integer.MAX_VALUE); + return addActions(root, maxDepth, Integer.MIN_VALUE, Integer.MAX_VALUE); } }); pool.execute(task); @@ -392,7 +391,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements return 0; } - protected int addActions(SimulationNode2 node, FilterAbility filter, int depth, int alpha, int beta) { + protected int addActions(SimulationNode2 node, int depth, int alpha, int beta) { logger.debug("addActions: " + depth + ", alpha=" + alpha + ", beta=" + beta); Game game = node.getGame(); int val; @@ -411,7 +410,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements } else if (node.getChildren().size() > 0) { logger.debug("simulating -- somthing added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, depth-1, alpha, beta); + val = minimaxAB(node, depth-1, alpha, beta); return val; } else { @@ -431,10 +430,10 @@ public class ComputerPlayer6 extends ComputerPlayer implements } else if (node.getChildren().size() > 0) { //declared attackers or blockers or triggered abilities logger.debug("simulating -- attack/block/trigger added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, depth-1, alpha, beta); + val = minimaxAB(node, depth-1, alpha, beta); } else { - val = simulatePriority(node, game, filter, depth, alpha, beta); + val = simulatePriority(node, game, depth, alpha, beta); } } @@ -443,7 +442,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements } - protected int simulatePriority(SimulationNode2 node, Game game, FilterAbility filter, int depth, int alpha, int beta) { + protected int simulatePriority(SimulationNode2 node, Game game, int depth, int alpha, int beta) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); logger.info("interrupted"); @@ -453,7 +452,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements SimulatedPlayer2 currentPlayer = (SimulatedPlayer2) game.getPlayer(game.getPlayerList().get()); //logger.info("simulating -- player " + currentPlayer.getName()); SimulationNode2 bestNode = null; - List allActions = currentPlayer.simulatePriority(game, filter); + List allActions = currentPlayer.simulatePriority(game); logger.debug("simulating -- adding " + allActions.size() + " children:" + allActions); for (Ability action: allActions) { if (Thread.interrupted()) { @@ -477,7 +476,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements if (depth == 20) { logger.info("*** Action *** " + action.toString()); } - int val = addActions(newNode, filter, depth-1, alpha, beta); + int val = addActions(newNode, depth-1, alpha, beta); if (depth == 20) { logger.info("*** Value *** " + val); } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java index dd520e39744..8d44881aca9 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java @@ -151,7 +151,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { root = new SimulationNode2(null, sim, maxDepth, playerId); logger.debug("simulating pre combat actions -----------------------------------------------------------------------------------------"); - addActionsTimed(new FilterAbility()); + addActionsTimed(); if (root.children.size() > 0) { root = root.children.get(0); int bestScore = root.getScore(); @@ -171,7 +171,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { root = new SimulationNode2(null, sim, maxDepth, playerId); logger.debug("simulating post combat actions ----------------------------------------------------------------------------------------"); - addActionsTimed(new FilterAbility()); + addActionsTimed(); if (root.children.size() > 0) { root = root.children.get(0); int bestScore = root.getScore(); @@ -184,7 +184,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { } @Override - protected int addActions(SimulationNode2 node, FilterAbility filter, int depth, int alpha, int beta) { + protected int addActions(SimulationNode2 node, int depth, int alpha, int beta) { boolean stepFinished = false; int val; Game game = node.getGame(); @@ -199,7 +199,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { } else if (node.getChildren().size() > 0) { logger.debug("simulating -- somthing added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, depth-1, alpha, beta); + val = minimaxAB(node, depth-1, alpha, beta); } else { if (logger.isDebugEnabled()) @@ -248,10 +248,10 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { } else if (node.getChildren().size() > 0) { logger.debug("simulating -- trigger added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, depth, alpha, beta); + val = minimaxAB(node, depth, alpha, beta); } else { - val = simulatePriority(node, game, filter, depth, alpha, beta); + val = simulatePriority(node, game, depth, alpha, beta); } } @@ -520,7 +520,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { game.getPhase().setStep(new PostCombatMainStep()); game.getStep().beginStep(game, playerId); game.getPlayers().resetPassed(); - return addActions(node, new FilterAbility(), depth, alpha, beta); + return addActions(node, depth, alpha, beta); } return simulateCounterAttack(game, node, depth, alpha, beta); } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java index 0fe76573852..cefc7288dc7 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java @@ -28,7 +28,6 @@ package mage.player.ai; -import java.io.File; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; import mage.abilities.Ability; @@ -38,18 +37,14 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.VariableManaCost; -import mage.abilities.mana.ManaOptions; import mage.cards.Card; import mage.choices.Choice; -import mage.filter.FilterAbility; import mage.game.Game; import mage.game.combat.Combat; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.StackAbility; -import mage.sets.innistrad.UnholyFiend; import mage.target.Target; -import mage.util.Logging; import org.apache.log4j.Logger; /** @@ -60,7 +55,6 @@ public class SimulatedPlayer2 extends ComputerPlayer { private final static transient Logger logger = Logger.getLogger(SimulatedPlayer2.class); private boolean isSimulatedPlayer; - private FilterAbility filter; private transient ConcurrentLinkedQueue allActions; private static PassAbility pass = new PassAbility(); @@ -76,8 +70,6 @@ public class SimulatedPlayer2 extends ComputerPlayer { public SimulatedPlayer2(final SimulatedPlayer2 player) { super(player); this.isSimulatedPlayer = player.isSimulatedPlayer; - if (player.filter != null) - this.filter = player.filter.copy(); } @Override @@ -85,10 +77,9 @@ public class SimulatedPlayer2 extends ComputerPlayer { return new SimulatedPlayer2(this); } - public List simulatePriority(Game game, FilterAbility filter) { + public List simulatePriority(Game game) { allActions = new ConcurrentLinkedQueue(); Game sim = game.copy(); - this.filter = filter; simulateOptions(sim, pass); @@ -99,13 +90,11 @@ public class SimulatedPlayer2 extends ComputerPlayer { protected void simulateOptions(Game game, Ability previousActions) { allActions.add(previousActions); - ManaOptions available = getManaAvailable(game); - available.addMana(manaPool.getMana()); - List playables = game.getPlayer(playerId).getPlayable(game, filter, available, isSimulatedPlayer); + List playables = game.getPlayer(playerId).getPlayable(game, isSimulatedPlayer); playables = filterAbilities(game, playables, suggested); for (Ability ability: playables) { List options = game.getPlayer(playerId).getPlayableOptions(ability, game); - if (options.size() == 0) { + if (options.isEmpty()) { if (ability.getManaCosts().getVariableCosts().size() > 0) { simulateVariableCosts(ability, game); } @@ -237,7 +226,7 @@ public class SimulatedPlayer2 extends ComputerPlayer { } protected void addBlocker(Game game, List blockers, Map engagements) { - if (blockers.size() == 0) + if (blockers.isEmpty()) return; int numGroups = game.getCombat().getGroups().size(); //try to block each attacker with each potential blocker @@ -260,7 +249,7 @@ public class SimulatedPlayer2 extends ComputerPlayer { public boolean triggerAbility(TriggeredAbility source, Game game) { Ability ability = source.copy(); List options = getPlayableOptions(ability, game); - if (options.size() == 0) { + if (options.isEmpty()) { logger.debug("simulating -- triggered ability:" + ability); game.getStack().push(new StackAbility(ability, playerId)); ability.activate(game, false); diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index eea3de3612e..fa2d05990fd 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -235,8 +235,6 @@ public class ComputerPlayer> extends PlayerImpl i return true; } } - if (!target.isRequired()) - return false; return false; } if (target instanceof TargetDiscard || target instanceof TargetCardInHand) { @@ -266,8 +264,6 @@ public class ComputerPlayer> extends PlayerImpl i } } } - if (!target.isRequired()) - return false; return false; } if (target instanceof TargetControlledPermanent) { @@ -281,8 +277,6 @@ public class ComputerPlayer> extends PlayerImpl i return true; } } - if (!target.isRequired()) - return false; return false; } if (target instanceof TargetPermanent) { @@ -299,8 +293,6 @@ public class ComputerPlayer> extends PlayerImpl i return true; } } - if (!target.isRequired()) - return false; return false; } if (target instanceof TargetCreatureOrPlayer) { @@ -333,8 +325,6 @@ public class ComputerPlayer> extends PlayerImpl i return true; } } - if (!target.isRequired()) - return false; return false; } if (target instanceof TargetCardInGraveyard) { @@ -357,8 +347,6 @@ public class ComputerPlayer> extends PlayerImpl i target.addTarget(card.getId(), source, game); return true; } - if (!target.isRequired()) - return false; return false; } if (target instanceof TargetCardInYourGraveyard) { @@ -368,8 +356,6 @@ public class ComputerPlayer> extends PlayerImpl i target.addTarget(card.getId(), source, game); return true; } - if (!target.isRequired()) - return false; return false; } throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString()); @@ -641,13 +627,14 @@ public class ComputerPlayer> extends PlayerImpl i log.debug("findPlayables: " + playableInstant.toString() + "---" + playableNonInstant.toString() + "---" + playableAbilities.toString() ); } - @Override - protected ManaOptions getManaAvailable(Game game) { - return super.getManaAvailable(game); - } +// @Override +// protected ManaOptions getManaAvailable(Game game) { +// return super.getManaAvailable(game); +// } @Override public boolean playMana(ManaCost unpaid, Game game) { +// log.info("paying for " + unpaid.getText()); ManaCost cost; List producers; if (unpaid instanceof ManaCosts) { @@ -657,10 +644,11 @@ public class ComputerPlayer> extends PlayerImpl i else { cost = unpaid; producers = this.getAvailableManaProducers(game); + producers.addAll(this.getAvailableManaProducersWithCost(game)); } for (Permanent perm: producers) { // pay all colored costs first - for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { + for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof ColoredManaCost) { if (cost.testPay(ability.getNetMana(game))) { if (activateAbility(ability, game)) @@ -669,7 +657,7 @@ public class ComputerPlayer> extends PlayerImpl i } } // then pay hybrid - for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { + for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof HybridManaCost) { if (cost.testPay(ability.getNetMana(game))) { if (activateAbility(ability, game)) @@ -678,7 +666,7 @@ public class ComputerPlayer> extends PlayerImpl i } } // then pay mono hybrid - for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { + for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof MonoHybridManaCost) { if (cost.testPay(ability.getNetMana(game))) { if (activateAbility(ability, game)) @@ -687,7 +675,7 @@ public class ComputerPlayer> extends PlayerImpl i } } // finally pay generic - for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { + for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof GenericManaCost) { if (cost.testPay(ability.getNetMana(game))) { if (activateAbility(ability, game)) @@ -713,11 +701,12 @@ public class ComputerPlayer> extends PlayerImpl i */ private List getSortedProducers(ManaCosts unpaid, Game game) { List unsorted = this.getAvailableManaProducers(game); + unsorted.addAll(this.getAvailableManaProducersWithCost(game)); Map scored = new HashMap(); for (Permanent permanent: unsorted) { int score = 0; for (ManaCost cost: unpaid) { - for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { + for (ManaAbility ability: permanent.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { if (cost.testPay(ability.getNetMana(game))) { score++; break; @@ -725,7 +714,7 @@ public class ComputerPlayer> extends PlayerImpl i } } if (score > 0) { // score mana producers that produce other mana types and have other uses higher - score += permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD).size(); + score += permanent.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game).size(); score += permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD).size(); if (!permanent.getCardType().contains(CardType.LAND)) score+=2; @@ -758,7 +747,7 @@ public class ComputerPlayer> extends PlayerImpl i log.debug("playXMana"); //put everything into X for (Permanent perm: this.getAvailableManaProducers(game)) { - for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { + for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { activateAbility(ability, game); } } diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java index d1bfa4e69ed..080567c5777 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java @@ -93,19 +93,19 @@ import org.apache.log4j.Logger; public class ComputerPlayer2 extends ComputerPlayer implements Player { private static final transient Logger logger = Logger.getLogger(ComputerPlayer2.class); - private static final ExecutorService pool = Executors.newFixedThreadPool(1); + private static final transient ExecutorService pool = Executors.newFixedThreadPool(1); protected int maxDepth; protected int maxNodes; protected int maxThink; protected int nodeCount = 0; protected long thinkTime = 0; - protected LinkedList actions = new LinkedList(); - protected List targets = new ArrayList(); - protected List choices = new ArrayList(); - protected Combat combat; + protected transient LinkedList actions = new LinkedList(); + protected transient List targets = new ArrayList(); + protected transient List choices = new ArrayList(); + protected transient Combat combat; protected int currentScore; - protected SimulationNode root; + protected transient SimulationNode root; public ComputerPlayer2(String name, RangeOfInfluence range, int skill) { super(name, range); @@ -192,9 +192,9 @@ public class ComputerPlayer2 extends ComputerPlayer implements root = new SimulationNode(null, sim, playerId); logger.debug("simulating actions"); if (!isTestMode) - addActionsTimed(new FilterAbility()); + addActionsTimed(); else - addActions(root, new FilterAbility(), Integer.MIN_VALUE, Integer.MAX_VALUE); + addActions(root, Integer.MIN_VALUE, Integer.MAX_VALUE); logger.info(name + " simulated " + nodeCount + " nodes in " + thinkTime/1000000000.0 + "s - average " + nodeCount/(thinkTime/1000000000.0) + " nodes/s"); if (root.children.size() > 0) { root = root.children.get(0); @@ -230,7 +230,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements return false; } - protected int minimaxAB(SimulationNode node, FilterAbility filter, int alpha, int beta) { + protected int minimaxAB(SimulationNode node, int alpha, int beta) { UUID currentPlayerId = node.getGame().getPlayerList().get(); SimulationNode bestChild = null; boolean isSimulatedPlayer = currentPlayerId.equals(playerId); @@ -243,7 +243,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements // logger.debug(indent(node.depth) + "simulating -- reached end-state"); // break; // } - int val = addActions(child, filter, alpha, beta); + int val = addActions(child, alpha, beta); if (!isSimulatedPlayer) { if (val < beta) { beta = val; @@ -318,12 +318,12 @@ public class ComputerPlayer2 extends ComputerPlayer implements game.getPlayerList().setCurrent(game.getActivePlayerId()); } - protected void addActionsTimed(final FilterAbility filter) { + protected void addActionsTimed() { FutureTask task = new FutureTask(new Callable() { @Override public Integer call() throws Exception { - return addActions(root, filter, Integer.MIN_VALUE, Integer.MAX_VALUE); + return addActions(root, Integer.MIN_VALUE, Integer.MAX_VALUE); } }); long startTime = System.nanoTime(); @@ -358,7 +358,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements } } - protected int addActions(SimulationNode node, FilterAbility filter, int alpha, int beta) { + protected int addActions(SimulationNode node, int alpha, int beta) { Game game = node.getGame(); if (Thread.interrupted()) { Thread.currentThread().interrupt(); @@ -372,7 +372,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements } else if (node.getChildren().size() > 0) { logger.debug(indent(node.depth) + "simulating -- somthing added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, alpha, beta); + val = minimaxAB(node, alpha, beta); } else { if (logger.isDebugEnabled()) @@ -399,10 +399,10 @@ public class ComputerPlayer2 extends ComputerPlayer implements else if (node.getChildren().size() > 0) { //declared attackers or blockers or triggered abilities logger.debug(indent(node.depth) + "simulating -- attack/block/trigger added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, alpha, beta); + val = minimaxAB(node, alpha, beta); } else { - val = simulatePriority(node, game, filter, alpha, beta); + val = simulatePriority(node, game, alpha, beta); } } @@ -412,7 +412,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements } - protected int simulatePriority(SimulationNode node, Game game, FilterAbility filter, int alpha, int beta) { + protected int simulatePriority(SimulationNode node, Game game, int alpha, int beta) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug(indent(node.depth) + "interrupted"); @@ -423,7 +423,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements boolean isSimulatedPlayer = currentPlayer.getId().equals(playerId); logger.debug(indent(node.depth) + "simulating priority -- player " + currentPlayer.getName()); SimulationNode bestNode = null; - List allActions = currentPlayer.simulatePriority(game, filter); + List allActions = currentPlayer.simulatePriority(game); if (logger.isDebugEnabled()) logger.debug(indent(node.depth) + "simulating -- adding " + allActions.size() + " children:" + allActions); for (Ability action: allActions) { @@ -448,7 +448,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements if (logger.isDebugEnabled()) logger.debug(indent(newNode.depth) + "simulating -- node #:" + SimulationNode.getCount() + " actions:" + action); sim.checkStateAndTriggered(); - int val = addActions(newNode, filter, alpha, beta); + int val = addActions(newNode, alpha, beta); if (!isSimulatedPlayer) { if (val < beta) { beta = val; diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java index ad38ef95df3..f44232a1d8b 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java @@ -161,9 +161,9 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { logger.debug("simulating pre combat actions -----------------------------------------------------------------------------------------"); if (!isTestMode) - addActionsTimed(new FilterAbility()); + addActionsTimed(); else - addActions(root, new FilterAbility(), Integer.MIN_VALUE, Integer.MAX_VALUE); + addActions(root, Integer.MIN_VALUE, Integer.MAX_VALUE); logger.info(name + " simulated " + nodeCount + " nodes in " + thinkTime/1000000000.0 + "s - average " + nodeCount/(thinkTime/1000000000.0) + " nodes/s"); if (root.children.size() > 0) { root = root.children.get(0); @@ -185,9 +185,9 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { root = new SimulationNode(null, sim, playerId); logger.debug("simulating post combat actions ----------------------------------------------------------------------------------------"); if (!isTestMode) - addActionsTimed(new FilterAbility()); + addActionsTimed(); else - addActions(root, new FilterAbility(), Integer.MIN_VALUE, Integer.MAX_VALUE); + addActions(root, Integer.MIN_VALUE, Integer.MAX_VALUE); logger.info(name + " simulated " + nodeCount + " nodes in " + thinkTime/1000000000.0 + "s - average " + nodeCount/(thinkTime/1000000000.0) + " nodes/s"); if (root.children.size() > 0) { root = root.children.get(0); @@ -202,7 +202,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { } @Override - protected int addActions(SimulationNode node, FilterAbility filter, int alpha, int beta) { + protected int addActions(SimulationNode node, int alpha, int beta) { boolean stepFinished = false; int val; Game game = node.getGame(); @@ -217,7 +217,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { } else if (node.getChildren().size() > 0) { logger.debug(indent(node.depth) + "simulating -- somthing added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, alpha, beta); + val = minimaxAB(node, alpha, beta); } else { if (logger.isDebugEnabled()) @@ -266,10 +266,10 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { } else if (node.getChildren().size() > 0) { logger.debug(indent(node.depth) + "simulating -- trigger added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, alpha, beta); + val = minimaxAB(node, alpha, beta); } else { - val = simulatePriority(node, game, filter, alpha, beta); + val = simulatePriority(node, game, alpha, beta); } } @@ -535,7 +535,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { game.getPhase().setStep(new PostCombatMainStep()); game.getStep().beginStep(game, playerId); game.getPlayers().resetPassed(); - return addActions(node, new FilterAbility(), alpha, beta); + return addActions(node, alpha, beta); } return simulateCounterAttack(game, node, alpha, beta); } diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulatedPlayer.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulatedPlayer.java index 7dc1a557f53..e9bb049c604 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulatedPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulatedPlayer.java @@ -44,9 +44,7 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.VariableManaCost; -import mage.abilities.mana.ManaOptions; import mage.choices.Choice; -import mage.filter.FilterAbility; import mage.game.Game; import mage.game.combat.Combat; import mage.game.events.GameEvent; @@ -63,7 +61,6 @@ public class SimulatedPlayer extends ComputerPlayer { private final static transient Logger logger = Logger.getLogger(SimulatedPlayer.class); private boolean isSimulatedPlayer; - private FilterAbility filter; private transient ConcurrentLinkedQueue allActions; private static PassAbility pass = new PassAbility(); protected int maxDepth; @@ -78,8 +75,6 @@ public class SimulatedPlayer extends ComputerPlayer { public SimulatedPlayer(final SimulatedPlayer player) { super(player); this.isSimulatedPlayer = player.isSimulatedPlayer; - if (player.filter != null) - this.filter = player.filter.copy(); } @Override @@ -87,10 +82,9 @@ public class SimulatedPlayer extends ComputerPlayer { return new SimulatedPlayer(this); } - public List simulatePriority(Game game, FilterAbility filter) { + public List simulatePriority(Game game) { allActions = new ConcurrentLinkedQueue(); Game sim = game.copy(); - this.filter = filter; simulateOptions(sim, pass); @@ -102,12 +96,10 @@ public class SimulatedPlayer extends ComputerPlayer { protected void simulateOptions(Game game, Ability previousActions) { allActions.add(previousActions); - ManaOptions available = getManaAvailable(game); - available.addMana(manaPool.getMana()); - List playables = game.getPlayer(playerId).getPlayable(game, filter, available, isSimulatedPlayer); + List playables = game.getPlayer(playerId).getPlayable(game, isSimulatedPlayer); for (Ability ability: playables) { List options = game.getPlayer(playerId).getPlayableOptions(ability, game); - if (options.size() == 0) { + if (options.isEmpty()) { if (ability.getManaCosts().getVariableCosts().size() > 0) { simulateVariableCosts(ability, game); } @@ -147,7 +139,7 @@ public class SimulatedPlayer extends ComputerPlayer { //add a generic mana cost for each amount possible protected void simulateVariableCosts(Ability ability, Game game) { - int numAvailable = getAvailableManaProducers(game).size(); + int numAvailable = getAvailableManaProducers(game).size() - ability.getManaCosts().convertedManaCost(); int start = 0; if (!(ability instanceof SpellAbility)) { //only use x=0 on spell abilities @@ -158,7 +150,7 @@ public class SimulatedPlayer extends ComputerPlayer { } for (int i = start; i < numAvailable; i++) { Ability newAbility = ability.copy(); - newAbility.addManaCost(new GenericManaCost(i)); + newAbility.addCost(new GenericManaCost(i)); allActions.add(newAbility); } } @@ -223,7 +215,7 @@ public class SimulatedPlayer extends ComputerPlayer { } protected void addBlocker(Game game, List blockers, Map engagements) { - if (blockers.size() == 0) + if (blockers.isEmpty()) return; int numGroups = game.getCombat().getGroups().size(); //try to block each attacker with each potential blocker @@ -247,7 +239,7 @@ public class SimulatedPlayer extends ComputerPlayer { public boolean triggerAbility(TriggeredAbility source, Game game) { Ability ability = source.copy(); List options = getPlayableOptions(ability, game); - if (options.size() == 0) { + if (options.isEmpty()) { if (logger.isDebugEnabled()) logger.debug("simulating -- triggered ability:" + ability); game.getStack().push(new StackAbility(ability, playerId)); diff --git a/Mage.Server/plugins/mage-player-ai-ma.jar b/Mage.Server/plugins/mage-player-ai-ma.jar index 0e4bd9abc17..906117badc1 100644 Binary files a/Mage.Server/plugins/mage-player-ai-ma.jar and b/Mage.Server/plugins/mage-player-ai-ma.jar differ diff --git a/Mage.Server/plugins/mage-player-ai.jar b/Mage.Server/plugins/mage-player-ai.jar index 52e8882750e..171bdc2d5ea 100644 Binary files a/Mage.Server/plugins/mage-player-ai.jar and b/Mage.Server/plugins/mage-player-ai.jar differ diff --git a/Mage.Server/plugins/mage-player-aiminimax.jar b/Mage.Server/plugins/mage-player-aiminimax.jar index 5dfb2d61573..a88f33c3dae 100644 Binary files a/Mage.Server/plugins/mage-player-aiminimax.jar and b/Mage.Server/plugins/mage-player-aiminimax.jar differ diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 83408474ce3..43513551518 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -406,7 +406,8 @@ public class TableController { UUID choosingPlayerId = match.getChooser(); match.endGame(); table.endGame(); - GameManager.getInstance().saveGame(match.getGame().getId()); + if (!match.getGame().isSimulation()) + GameManager.getInstance().saveGame(match.getGame().getId()); GameManager.getInstance().removeGame(match.getGame().getId()); try { if (!match.isMatchOver()) { diff --git a/Mage.Sets/src/mage/sets/eventide/CascadeBluffs.java b/Mage.Sets/src/mage/sets/eventide/CascadeBluffs.java index f22c16cb00f..e95c4095eba 100644 --- a/Mage.Sets/src/mage/sets/eventide/CascadeBluffs.java +++ b/Mage.Sets/src/mage/sets/eventide/CascadeBluffs.java @@ -67,7 +67,7 @@ class CascadeBluffsFirstManaAbility extends BasicManaAbility extends List, Serializable { public Abilities getManaAbilities(Zone zone); /** + * Retrieves all {@link ManaAbility mana abilities} in the given {@link Zone} that can be used. + * + * @param zone The {@link Zone} to search for {@link ManaAbility mana abilities}. + * @return All {@link ManaAbility mana abilities} for the given {@link Zone} that can be used. + * + * @see mage.cards.CardImpl#getMana() + * @see mage.players.PlayerImpl#getManaAvailable(mage.game.Game) + * @see mage.players.PlayerImpl#getAvailableManaProducers(mage.game.Game) + */ + public Abilities getAvailableManaAbilities(Zone zone, Game game); + + /** * Retrieves all {@link StaticAbility static abilities} in the given {@link Zone}. * * @param zone The {@link Zone} to search for {@link StaticAbility} @@ -241,4 +257,6 @@ public interface Abilities extends List, Serializable { * @return */ public Abilities copy(); + + public Map getReplacementEffects(Zone zone); } diff --git a/Mage/src/mage/abilities/AbilitiesImpl.java b/Mage/src/mage/abilities/AbilitiesImpl.java index f05952d47db..0a674be8c97 100644 --- a/Mage/src/mage/abilities/AbilitiesImpl.java +++ b/Mage/src/mage/abilities/AbilitiesImpl.java @@ -29,14 +29,20 @@ package mage.abilities; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; +import mage.Constants.EffectType; import mage.Constants.Zone; import mage.abilities.common.ZoneChangeTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.ReplacementEffect; import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.ProtectionAbility; import mage.abilities.mana.ManaAbility; import mage.filter.FilterAbility; +import mage.game.Game; /** * @@ -103,6 +109,18 @@ public class AbilitiesImpl extends ArrayList implements Ab } @Override + public Abilities getAvailableManaAbilities(Zone zone, Game game) { + Abilities abilities = new AbilitiesImpl(); + for (T ability: this) { + if (ability instanceof ManaAbility && ability.getZone().match(zone)) { + if ((((ManaAbility)ability).canActivate(ability.getControllerId(), game))) + abilities.add((ManaAbility)ability); + } + } + return abilities; + } + + @Override public Abilities getEvasionAbilities() { Abilities abilities = new AbilitiesImpl(); for (T ability: this) { @@ -140,7 +158,22 @@ public class AbilitiesImpl extends ArrayList implements Ab } return zonedAbilities; } - + + @Override + public Map getReplacementEffects(Zone zone) { + Map effects = new HashMap(); + for (T ability: this) { + if (ability instanceof StaticAbility && ability.getZone().match(zone)) { + for (Effect effect: ability.getEffects()) { + if (effect.getEffectType() == EffectType.REPLACEMENT || effect.getEffectType() == EffectType.PREVENTION) { + effects.put((ReplacementEffect)effect, ability); + } + } + } + } + return effects; + } + @Override public Abilities getProtectionAbilities() { Abilities abilities = new AbilitiesImpl(); diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index 922e5a21d80..2a04e6aa0e8 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -46,6 +46,7 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.PostResolveEffect; +import mage.abilities.mana.ManaAbility; import mage.choices.Choice; import mage.choices.Choices; import mage.game.Game; @@ -194,6 +195,12 @@ public abstract class AbilityImpl> implements Ability { } } + // this is a hack to prevent mana abilities with mana costs from causing endless loops - pay other costs first + if (this instanceof ManaAbility && !costs.pay(this, game, sourceId, controllerId, noMana)) { + logger.debug("activate mana ability failed - non mana costs"); + return false; + } + if (!useAlternativeCost(game)) { //20101001 - 601.2e game.getContinuousEffects().costModification(this, game); diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 2fe0e8c6875..27ec0be04c8 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -209,8 +209,9 @@ public class ContinuousEffects implements Serializable { private List getLayeredEffects(Game game) { List layerEffects = new ArrayList(layeredEffects); for (Card card: game.getCards()) { - if (game.getZone(card.getId()) == Zone.HAND || game.getZone(card.getId()) == Zone.GRAVEYARD) { - for (Ability ability: card.getAbilities().getStaticAbilities(game.getZone(card.getId()))) { + Zone zone = game.getZone(card.getId()); + if (zone == Zone.HAND || zone == Zone.GRAVEYARD) { + for (Ability ability: card.getAbilities().getStaticAbilities(zone)) { for (Effect effect: ability.getEffects(game, EffectType.CONTINUOUS)) { layerEffects.add((ContinuousEffect) effect); abilityMap.put(effect.getId(), ability); @@ -291,62 +292,33 @@ public class ContinuousEffects implements Serializable { replaceEffects.add(planeswalkerRedirectionEffect); //get all applicable Replacement effects in each players hand and graveyard for (Card card: game.getCards()) { - if (game.getZone(card.getId()) == Zone.HAND || game.getZone(card.getId()) == Zone.GRAVEYARD) { - for (Ability ability: card.getAbilities().getStaticAbilities(game.getZone(card.getId()))) { - for (Effect effect: ability.getEffects(game, EffectType.REPLACEMENT)) { - ReplacementEffect rEffect = (ReplacementEffect) effect; - if (rEffect.applies(event, ability, game)) { - replaceEffects.add(rEffect); - abilityMap.put(rEffect.getId(), ability); - } - } - for (Effect effect: ability.getEffects(game, EffectType.PREVENTION)) { - ReplacementEffect rEffect = (ReplacementEffect) effect; - if (rEffect.applies(event, ability, game)) { - replaceEffects.add(rEffect); - abilityMap.put(rEffect.getId(), ability); - } - } - } + Zone zone = game.getZone(card.getId()); + if (zone == Zone.HAND || zone == Zone.GRAVEYARD) { + for (Entry entry: card.getAbilities().getReplacementEffects(zone).entrySet()) { + if (entry.getKey().applies(event, entry.getValue(), game)) { + replaceEffects.add(entry.getKey()); + abilityMap.put(entry.getKey().getId(), entry.getValue()); + } + } } } //get all applicable Replacement effects on the battlefield for (Permanent permanent: game.getBattlefield().getAllPermanents()) { - for (Ability ability: permanent.getAbilities().getStaticAbilities(Zone.BATTLEFIELD)) { - for (Effect effect: ability.getEffects(game, EffectType.REPLACEMENT)) { - ReplacementEffect rEffect = (ReplacementEffect) effect; - if (rEffect.applies(event, ability, game)) { - replaceEffects.add(rEffect); - abilityMap.put(rEffect.getId(), ability); - } - } - for (Effect effect: ability.getEffects(game, EffectType.PREVENTION)) { - ReplacementEffect rEffect = (ReplacementEffect) effect; - if (rEffect.applies(event, ability, game)) { - replaceEffects.add(rEffect); - abilityMap.put(rEffect.getId(), ability); - } - } - } + for (Entry entry: permanent.getAbilities().getReplacementEffects(Zone.BATTLEFIELD).entrySet()) { + if (entry.getKey().applies(event, entry.getValue(), game)) { + replaceEffects.add(entry.getKey()); + abilityMap.put(entry.getKey().getId(), entry.getValue()); + } + } } //get all applicable Replacement effects on players for (Player player: game.getPlayers().values()) { - for (Ability ability: player.getAbilities().getStaticAbilities(Zone.BATTLEFIELD)) { - for (Effect effect: ability.getEffects(game, EffectType.REPLACEMENT)) { - ReplacementEffect rEffect = (ReplacementEffect) effect; - if (rEffect.applies(event, ability, game)) { - replaceEffects.add(rEffect); - abilityMap.put(rEffect.getId(), ability); - } - } - for (Effect effect: ability.getEffects(game, EffectType.PREVENTION)) { - ReplacementEffect rEffect = (ReplacementEffect) effect; - if (rEffect.applies(event, ability, game)) { - replaceEffects.add(rEffect); - abilityMap.put(rEffect.getId(), ability); - } - } - } + for (Entry entry: player.getAbilities().getReplacementEffects(Zone.BATTLEFIELD).entrySet()) { + if (entry.getKey().applies(event, entry.getValue(), game)) { + replaceEffects.add(entry.getKey()); + abilityMap.put(entry.getKey().getId(), entry.getValue()); + } + } } //get all applicable transient Replacement effects for (ReplacementEffect effect: replacementEffects) { diff --git a/Mage/src/mage/abilities/effects/common/PassEffect.java b/Mage/src/mage/abilities/effects/common/PassEffect.java index 175897c1c0e..5963330a012 100644 --- a/Mage/src/mage/abilities/effects/common/PassEffect.java +++ b/Mage/src/mage/abilities/effects/common/PassEffect.java @@ -32,6 +32,7 @@ import mage.Constants.Outcome; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.game.Game; +import mage.players.Player; /** * @@ -49,6 +50,8 @@ public class PassEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + player.pass(); return true; } diff --git a/Mage/src/mage/abilities/keyword/SplitSecondAbility.java b/Mage/src/mage/abilities/keyword/SplitSecondAbility.java index a011052c73b..a00174fd218 100644 --- a/Mage/src/mage/abilities/keyword/SplitSecondAbility.java +++ b/Mage/src/mage/abilities/keyword/SplitSecondAbility.java @@ -9,7 +9,7 @@ import mage.game.events.GameEvent; /** * Split Second - * As long as this spell is on the stack, players can’t cast other spells or activate abilities that aren’t mana abilities. + * As long as this spell is on the stack, players can't cast other spells or activate abilities that aren't mana abilities. */ public class SplitSecondAbility extends SimpleStaticAbility { private static final SplitSecondAbility ability = new SplitSecondAbility(); diff --git a/Mage/src/mage/abilities/mana/ManaOptions.java b/Mage/src/mage/abilities/mana/ManaOptions.java index 6ed9e882ed1..7994ef0f7b9 100644 --- a/Mage/src/mage/abilities/mana/ManaOptions.java +++ b/Mage/src/mage/abilities/mana/ManaOptions.java @@ -76,6 +76,49 @@ public class ManaOptions extends ArrayList { } } + public void addManaWithCost(List abilities, Game game) { + if (isEmpty()) + this.add(new Mana()); + if (!abilities.isEmpty()) { + if (abilities.size() == 1) { + //if there is only one mana option available add it to all the existing options + ManaAbility ability = abilities.get(0); + if (ability.getManaCosts().isEmpty()) { + addMana(ability.getNetMana(game)); + } + else { + addMana(ability.getManaCosts().getMana(), ability.getNetMana(game)); + } + } + else if (abilities.size() > 1) { + //perform a union of all existing options and the new options + List copy = copy(); + this.clear(); + for (ManaAbility ability: abilities) { + if (ability.getManaCosts().isEmpty()) { + for (Mana mana: copy) { + Mana newMana = new Mana(); + newMana.add(mana); + newMana.add(ability.getNetMana(game)); + this.add(newMana); + } + } + else { + for (Mana mana: copy) { + Mana newMana = new Mana(); + newMana.add(mana); + if (mana.contains(ability.getManaCosts().getMana())) { + newMana.subtract(ability.getManaCosts().getMana()); + newMana.add(ability.getNetMana(game)); + } + this.add(newMana); + } + } + } + } + } + } + public void addMana(Mana addMana) { if (isEmpty()) this.add(new Mana()); @@ -112,4 +155,15 @@ public class ManaOptions extends ArrayList { return new ManaOptions(this); } + public void addMana(Mana cost, Mana addMana) { + if (isEmpty()) + this.add(new Mana()); + for (Mana mana: this) { + if (mana.contains(cost)) { + mana.subtract(cost); + mana.add(addMana); + } + } + } + } \ No newline at end of file diff --git a/Mage/src/mage/cards/CardsImpl.java b/Mage/src/mage/cards/CardsImpl.java index bfad6acdc7f..055109ce10d 100644 --- a/Mage/src/mage/cards/CardsImpl.java +++ b/Mage/src/mage/cards/CardsImpl.java @@ -170,9 +170,10 @@ public class CardsImpl extends LinkedHashSet implements Cards, Serializabl @Override public Collection getUniqueCards(Game game) { Map cards = new HashMap(); - for(UUID card: this) { - if (!cards.containsKey(game.getCard(card).getName())) { - cards.put(game.getCard(card).getName(), game.getCard(card)); + for(UUID cardId: this) { + Card card = game.getCard(cardId); + if (!cards.containsKey(card.getName())) { + cards.put(card.getName(), card); } } return cards.values(); diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index 643664733b1..0f80469ae1f 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -144,6 +144,7 @@ public interface Game extends MageItem, Serializable { //game play methods public void start(UUID choosingPlayerId); public void start(UUID choosingPlayerId, GameOptions options); + public void resume(); public void end(); public void mulligan(UUID playerId); public void quit(UUID playerId); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 99d313f1652..de4f196f364 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -124,6 +124,7 @@ public abstract class GameImpl> implements Game, Serializa this.state = game.state.copy(); this.gameCards = game.gameCards; this.simulation = game.simulation; + this.gameOptions = game.gameOptions; } @Override @@ -235,8 +236,6 @@ public abstract class GameImpl> implements Game, Serializa @Override public Permanent getPermanent(UUID permanentId) { - if (permanentId == null) - return null; return state.getPermanent(permanentId); } @@ -249,8 +248,6 @@ public abstract class GameImpl> implements Game, Serializa @Override public Zone getZone(UUID objectId) { - if (objectId == null) - return null; return state.getZone(objectId); } @@ -271,7 +268,7 @@ public abstract class GameImpl> implements Game, Serializa @Override public void saveState() { - if (gameStates != null) + if (!simulation && gameStates != null) gameStates.save(state); } @@ -350,13 +347,26 @@ public abstract class GameImpl> implements Game, Serializa @Override public void start(UUID choosingPlayerId, GameOptions options) { startTime = new Date(); + this.gameOptions = options; init(choosingPlayerId, options.testMode); - PlayerList players = state.getPlayerList(startingPlayerId); + play(startingPlayerId); + saveState(); + } + + @Override + public void resume() { + play(state.getActivePlayerId()); + } + + protected void play(UUID nextPlayerId) { + PlayerList players = state.getPlayerList(nextPlayerId); Player player = getPlayer(players.get()); while (!isGameOver()) { state.setTurnNum(state.getTurnNum() + 1); + if (simulation) + logger.info("Turn " + Integer.toString(state.getTurnNum())); fireInformEvent("Turn " + Integer.toString(state.getTurnNum())); - if (checkStopOnTurnOption(options)) return; + if (checkStopOnTurnOption()) return; state.setActivePlayerId(player.getId()); state.getTurn().play(this, player.getId()); if (isGameOver()) @@ -366,13 +376,11 @@ public abstract class GameImpl> implements Game, Serializa } winnerId = findWinnersAndLosers(); - - saveState(); - } - - private boolean checkStopOnTurnOption(GameOptions options) { - if (options.stopOnTurn != null) { - if (options.stopOnTurn.equals(state.getTurnNum())) { + } + + private boolean checkStopOnTurnOption() { + if (gameOptions.stopOnTurn != null) { + if (gameOptions.stopOnTurn.equals(state.getTurnNum())) { winnerId = null; //DRAW saveState(); return true; @@ -852,6 +860,7 @@ public abstract class GameImpl> implements Game, Serializa @Override public synchronized void firePriorityEvent(UUID playerId) { + if (simulation) return; String message = this.state.getTurn().getStepType().toString(); if (this.canPlaySorcery(playerId)) message += " - play spells and abilities."; @@ -863,71 +872,85 @@ public abstract class GameImpl> implements Game, Serializa @Override public synchronized void fireSelectEvent(UUID playerId, String message) { + if (simulation) return; playerQueryEventSource.select(playerId, message); } @Override public void firePlayManaEvent(UUID playerId, String message) { + if (simulation) return; playerQueryEventSource.playMana(playerId, message); } @Override public void firePlayXManaEvent(UUID playerId, String message) { + if (simulation) return; playerQueryEventSource.playXMana(playerId, message); } @Override public void fireAskPlayerEvent(UUID playerId, String message) { + if (simulation) return; playerQueryEventSource.ask(playerId, message); } @Override public void fireGetChoiceEvent(UUID playerId, String message, Collection choices) { + if (simulation) return; playerQueryEventSource.chooseAbility(playerId, message, choices); } @Override public void fireGetModeEvent(UUID playerId, String message, Map modes) { + if (simulation) return; playerQueryEventSource.chooseMode(playerId, message, modes); } @Override public void fireSelectTargetEvent(UUID playerId, String message, Set targets, boolean required, Map options) { + if (simulation) return; playerQueryEventSource.target(playerId, message, targets, required, options); } @Override public void fireSelectTargetEvent(UUID playerId, String message, Cards cards, boolean required, Map options) { + if (simulation) return; playerQueryEventSource.target(playerId, message, cards, required, options); } @Override public void fireSelectTargetEvent(UUID playerId, String message, TriggeredAbilities abilities, boolean required) { + if (simulation) return; playerQueryEventSource.target(playerId, message, abilities, required); } @Override public void fireSelectTargetEvent(UUID playerId, String message, List perms, boolean required) { + if (simulation) return; playerQueryEventSource.target(playerId, message, perms, required); } @Override public void fireLookAtCardsEvent(UUID playerId, String message, Cards cards) { + if (simulation) return; playerQueryEventSource.target(playerId, message, cards); } @Override public void fireGetAmountEvent(UUID playerId, String message, int min, int max) { + if (simulation) return; playerQueryEventSource.amount(playerId, message, min, max); } @Override public void fireChooseEvent(UUID playerId, Choice choice) { + if (simulation) return; playerQueryEventSource.choose(playerId, choice.getMessage(), choice.getChoices()); } @Override public void informPlayers(String message) { + if (simulation) return; // state.addMessage(message); fireInformEvent(message); } @@ -939,11 +962,13 @@ public abstract class GameImpl> implements Game, Serializa @Override public void fireInformEvent(String message) { + if (simulation) return; tableEventSource.fireTableEvent(EventType.INFO, message, this); } @Override public void fireUpdatePlayersEvent() { + if (simulation) return; tableEventSource.fireTableEvent(EventType.UPDATE, null, this); } @@ -1054,13 +1079,11 @@ public abstract class GameImpl> implements Game, Serializa @Override public void fireEvent(GameEvent event) { - applyEffects(); state.handleEvent(event, this); } @Override public boolean replaceEvent(GameEvent event) { - applyEffects(); return state.replaceEvent(event, this); } diff --git a/Mage/src/mage/game/GameOptions.java b/Mage/src/mage/game/GameOptions.java index c4fe621afa1..07cb50b0198 100644 --- a/Mage/src/mage/game/GameOptions.java +++ b/Mage/src/mage/game/GameOptions.java @@ -1,12 +1,14 @@ package mage.game; +import java.io.Serializable; + /** * Game options for Mage game. * Mainly used in tests to configure {@link GameImpl} with specific params. * * @author ayratn */ -public class GameOptions { +public class GameOptions implements Serializable { private static GameOptions defInstance = new GameOptions(); diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java index 262bc50ee0e..49ed499527e 100644 --- a/Mage/src/mage/game/GameState.java +++ b/Mage/src/mage/game/GameState.java @@ -314,17 +314,16 @@ public class GameState implements Serializable, Copyable { } public Permanent getPermanent(UUID permanentId) { - Permanent permanent; - if (battlefield.containsPermanent(permanentId)) { - permanent = battlefield.getPermanent(permanentId); - setZone(permanent.getId(), Zone.BATTLEFIELD); - return permanent; - } + if (permanentId != null && battlefield.containsPermanent(permanentId)) { + Permanent permanent = battlefield.getPermanent(permanentId); + setZone(permanent.getId(), Zone.BATTLEFIELD); + return permanent; + } return null; } public Zone getZone(UUID id) { - if (zones.containsKey(id)) + if (id != null && zones.containsKey(id)) return zones.get(id); return null; } diff --git a/Mage/src/mage/game/permanent/PermanentCard.java b/Mage/src/mage/game/permanent/PermanentCard.java index 689a7dabf2a..68de9720162 100644 --- a/Mage/src/mage/game/permanent/PermanentCard.java +++ b/Mage/src/mage/game/permanent/PermanentCard.java @@ -50,16 +50,18 @@ import mage.players.Player; */ public class PermanentCard extends PermanentImpl { - protected String art; protected List levelerRules; + protected Card card; public PermanentCard(Card card, UUID controllerId) { super(card.getId(), card.getOwnerId(), controllerId, card.getName()); + this.card = card.copy(); init(card); } protected PermanentCard(UUID id, Card card, UUID controllerId) { super(card.getId(), card.getOwnerId(), controllerId, card.getName()); + this.card = card.copy(); init(card); } @@ -75,27 +77,28 @@ public class PermanentCard extends PermanentImpl { public PermanentCard(final PermanentCard permanent) { super(permanent); - this.art = permanent.art; + this.card = permanent.card; } @Override public void reset(Game game) { // when the permanent is reset copy all original values from the card // must copy card each reset so that the original values don't get modified - Card copy = game.getCard(objectId).copy(); - copyFromCard(copy); + copyFromCard(card); super.reset(game); } protected void copyFromCard(Card card) { this.name = card.getName(); - this.abilities = card.getAbilities(); + this.abilities.clear(); + this.abilities.addAll(card.getAbilities()); this.abilities.setControllerId(this.controllerId); - this.cardType = card.getCardType(); - this.color = card.getColor(); - this.manaCost = card.getManaCost(); - this.power = card.getPower(); - this.toughness = card.getToughness(); + this.cardType.clear(); + this.cardType.addAll(card.getCardType()); + this.color = card.getColor().copy(); + this.manaCost = card.getManaCost().copy(); + this.power = card.getPower().copy(); + this.toughness = card.getToughness().copy(); if (card instanceof LevelerCard) { LevelAbility level = ((LevelerCard)card).getLevel(this.getCounters().getCount(CounterType.LEVEL)); if (level != null) { @@ -106,8 +109,10 @@ public class PermanentCard extends PermanentImpl { } } } - this.subtype = card.getSubtype(); - this.supertype = card.getSupertype(); + this.subtype.clear(); + this.subtype.addAll(card.getSubtype()); + this.supertype.clear(); + this.supertype.addAll(card.getSupertype()); this.expansionSetCode = card.getExpansionSetCode(); this.rarity = card.getRarity(); this.cardNumber = card.getCardNumber(); @@ -124,7 +129,6 @@ public class PermanentCard extends PermanentImpl { // or we want to trigger abilities that only trigger on leaving the battlefield // card abilities will get triggered later when the card hits the new zone List triggered = new ArrayList(); - Card card = game.getCard(objectId).copy(); for (TriggeredAbility ability: abilities.getTriggeredAbilities(event.getFromZone())) { if (!card.getAbilities().containsKey(ability.getId())) { if (ability.checkTrigger(event, game)) { @@ -158,7 +162,6 @@ public class PermanentCard extends PermanentImpl { if (controller != null && controller.removeFromBattlefield(this, game)) { ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, controllerId, fromZone, toZone); if (!game.replaceEvent(event)) { - Card card = game.getCard(objectId); Player owner = game.getPlayer(ownerId); game.rememberLKI(objectId, Zone.BATTLEFIELD, this); if (owner != null) { @@ -199,7 +202,6 @@ public class PermanentCard extends PermanentImpl { if (controller != null && controller.removeFromBattlefield(this, game)) { ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, ownerId, fromZone, Zone.EXILED); if (!game.replaceEvent(event)) { - Card card = game.getCard(this.objectId); if (exileId == null) { game.getExile().getPermanentExile().add(card); } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index df7c5fbcba4..fe564978c96 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -34,6 +34,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import mage.Constants.Outcome; +import mage.Constants.RangeOfInfluence; import mage.MageItem; import mage.MageObject; import mage.abilities.Abilities; @@ -77,7 +78,8 @@ public interface Player extends MageItem, Copyable { public boolean isHuman(); public String getName(); - public Library getLibrary(); + public RangeOfInfluence getRange(); + public Library getLibrary(); public Cards getGraveyard(); public Abilities getAbilities(); public void addAbility(Ability ability); @@ -240,7 +242,7 @@ public interface Player extends MageItem, Copyable { public void phasing(Game game); public void untap(Game game); - public List getPlayable(Game game, FilterAbility filter, ManaOptions available, boolean hidden); + public List getPlayable(Game game, boolean hidden); public List getPlayableOptions(Ability ability, Game game); public void addCounters(Counter counter, Game game); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 76afaca509e..43f08988a73 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -211,6 +211,11 @@ public abstract class PlayerImpl> implements Player, Ser findRange(game); } + @Override + public RangeOfInfluence getRange() { + return range; + } + protected void findRange(Game game) { //20100423 - 801.2c inRange.clear(); @@ -615,6 +620,7 @@ public abstract class PlayerImpl> implements Player, Ser return false; if (ability instanceof PassAbility) { + pass(); return true; } else if (ability instanceof PlayLandAbility) { @@ -968,6 +974,7 @@ public abstract class PlayerImpl> implements Player, Ser this.inRange = player.getInRange(); this.landsPlayed = player.getLandsPlayed(); this.name = player.getName(); + this.range = player.getRange(); this.passed = player.isPassed(); } @@ -1129,20 +1136,46 @@ public abstract class PlayerImpl> implements Player, Ser } protected ManaOptions getManaAvailable(Game game) { - List manaPerms = this.getAvailableManaProducers(game); - ManaOptions available = new ManaOptions(); + + List manaPerms = this.getAvailableManaProducers(game); for (Permanent perm: manaPerms) { - available.addMana(perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD), game); + available.addMana(perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game), game); + } + + List manaPermsWithCost = this.getAvailableManaProducersWithCost(game); + for (Permanent perm: manaPermsWithCost) { + available.addManaWithCost(perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game), game); } return available; } + // returns only mana producers that don't require mana payment protected List getAvailableManaProducers(Game game) { List result = new ArrayList(); for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { + boolean canAdd = false; for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { if (ability.canActivate(playerId, game)) { + canAdd = true; + } + if (!ability.getManaCosts().isEmpty()) { + canAdd = false; + break; + } + } + if (canAdd) + result.add(permanent); + } + return result; + } + + // returns only mana producers that require mana payment + protected List getAvailableManaProducersWithCost(Game game) { + List result = new ArrayList(); + for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { + for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { + if (ability.canActivate(playerId, game) && !ability.getManaCosts().isEmpty()) { result.add(permanent); break; } @@ -1150,7 +1183,7 @@ public abstract class PlayerImpl> implements Player, Ser } return result; } - + protected boolean canPlay(ActivatedAbility ability, ManaOptions available, Game game) { if (!(ability instanceof ManaAbility) && ability.canActivate(playerId, game)) { ManaOptions abilityOptions = ability.getManaCosts().getOptions(); @@ -1172,28 +1205,28 @@ public abstract class PlayerImpl> implements Player, Ser } @Override - public List getPlayable(Game game, FilterAbility filter, ManaOptions available, boolean hidden) { + public List getPlayable(Game game, boolean hidden) { List playable = new ArrayList(); -// ManaOptions available = getManaAvailable(game); -// available.addMana(manaPool.getMana()); + ManaOptions available = getManaAvailable(game); + available.addMana(manaPool.getMana()); if (hidden) { for (Card card: hand.getUniqueCards(game)) { - for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.HAND, filter)) { + for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.HAND)) { if (canPlay(ability, available, game)) playable.add(ability); } } } for (Card card: graveyard.getUniqueCards(game)) { - for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.GRAVEYARD, filter)) { + for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.GRAVEYARD)) { if (canPlay(ability, available, game)) playable.add(ability); } } for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { - for (ActivatedAbility ability: permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD, filter)) { + for (ActivatedAbility ability: permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { if (canPlay(ability, available, game)) playable.add(ability); }