diff --git a/Mage.Client/src/main/java/mage/client/cards/CardGrid.java b/Mage.Client/src/main/java/mage/client/cards/CardGrid.java index 7a7547e5fbd..a602188b042 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardGrid.java +++ b/Mage.Client/src/main/java/mage/client/cards/CardGrid.java @@ -256,7 +256,13 @@ class CardRarityComparator implements Comparator { @Override public int compare(MageCard o1, MageCard o2) { - return o1.getOriginal().getRarity().compareTo(o2.getOriginal().getRarity()); + int val = o1.getOriginal().getRarity().compareTo(o2.getOriginal().getRarity()); + if (val == 0) { + return o1.getOriginal().getName().compareTo(o2.getOriginal().getName()); + } + else { + return val; + } } } @@ -265,7 +271,13 @@ class CardCostComparator implements Comparator { @Override public int compare(MageCard o1, MageCard o2) { - return Integer.valueOf(o1.getOriginal().getConvertedManaCost()).compareTo(Integer.valueOf(o2.getOriginal().getConvertedManaCost())); + int val = Integer.valueOf(o1.getOriginal().getConvertedManaCost()).compareTo(Integer.valueOf(o2.getOriginal().getConvertedManaCost())); + if (val == 0) { + return o1.getOriginal().getName().compareTo(o2.getOriginal().getName()); + } + else { + return val; + } } } @@ -274,7 +286,13 @@ class CardColorComparator implements Comparator { @Override public int compare(MageCard o1, MageCard o2) { - return o1.getOriginal().getColor().compareTo(o2.getOriginal().getColor()); + int val = o1.getOriginal().getColor().compareTo(o2.getOriginal().getColor()); + if (val == 0) { + return o1.getOriginal().getName().compareTo(o2.getOriginal().getName()); + } + else { + return val; + } } } \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/cards/CardsList.form b/Mage.Client/src/main/java/mage/client/cards/CardsList.form index 773addc57e4..38981bdff12 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardsList.form +++ b/Mage.Client/src/main/java/mage/client/cards/CardsList.form @@ -35,7 +35,7 @@ - + diff --git a/Mage.Client/src/main/java/mage/client/cards/CardsList.java b/Mage.Client/src/main/java/mage/client/cards/CardsList.java index 3b9ca08f000..60556eafef1 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardsList.java +++ b/Mage.Client/src/main/java/mage/client/cards/CardsList.java @@ -292,7 +292,13 @@ class CardViewRarityComparator implements Comparator { @Override public int compare(CardView o1, CardView o2) { - return o1.getRarity().compareTo(o2.getRarity()); + int val = o1.getRarity().compareTo(o2.getRarity()); + if (val == 0) { + return o1.getName().compareTo(o2.getName()); + } + else { + return val; + } } } @@ -301,7 +307,13 @@ class CardViewCostComparator implements Comparator { @Override public int compare(CardView o1, CardView o2) { - return Integer.valueOf(o1.getConvertedManaCost()).compareTo(Integer.valueOf(o2.getConvertedManaCost())); + int val = Integer.valueOf(o1.getConvertedManaCost()).compareTo(Integer.valueOf(o2.getConvertedManaCost())); + if (val == 0) { + return o1.getName().compareTo(o2.getName()); + } + else { + return val; + } } } @@ -310,7 +322,13 @@ class CardViewColorComparator implements Comparator { @Override public int compare(CardView o1, CardView o2) { - return o1.getColor().compareTo(o2.getColor()); + int val = o1.getColor().compareTo(o2.getColor()); + if (val == 0) { + return o1.getName().compareTo(o2.getName()); + } + else { + return val; + } } } \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java index ae7e3f079bc..56be4033ac8 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java @@ -276,7 +276,7 @@ public class NewTournamentDialog extends MageDialog { tOptions.setTournamentType(tournamentType.getName()); tOptions.getPlayerTypes().add("Human"); for (TournamentPlayerPanel player: players) { - tOptions.getPlayerTypes().add(player.getPlayerType()); + tOptions.getPlayerTypes().add((String) player.getPlayerType().getSelectedItem()); } if (tournamentType.isDraft()) { DraftOptions options = new DraftOptions(); @@ -347,12 +347,33 @@ public class NewTournamentDialog extends MageDialog { pack.setModel(new DefaultComboBoxModel(Sets.getInstance().values().toArray())); pnlPacks.add(pack); packs.add(pack); + pack.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + packActionPerformed(evt); + } + }); } this.pack(); this.revalidate(); this.repaint(); } + private void packActionPerformed(java.awt.event.ActionEvent evt) { + boolean start = false; + int selectedIndex = 0; + for (JComboBox pack: packs) { + if (!start) { + if (evt.getSource().equals(pack)) { + start = true; + selectedIndex = pack.getSelectedIndex(); + } + } + else { + pack.setSelectedIndex(selectedIndex); + } + } + } + private void createPlayers(int numPlayers) { if (numPlayers > players.size()) { while (players.size() != numPlayers) { @@ -373,12 +394,33 @@ public class NewTournamentDialog extends MageDialog { this.pnlOtherPlayers.removeAll(); for (TournamentPlayerPanel panel: players) { this.pnlOtherPlayers.add(panel); + panel.getPlayerType().addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + playerActionPerformed(evt); + } + }); } this.pack(); this.revalidate(); this.repaint(); } + private void playerActionPerformed(java.awt.event.ActionEvent evt) { + boolean start = false; + int selectedIndex = 0; + for (TournamentPlayerPanel player: players) { + if (!start) { + if (evt.getSource().equals(player.getPlayerType())) { + start = true; + selectedIndex = player.getPlayerType().getSelectedIndex(); + } + } + else { + player.getPlayerType().setSelectedIndex(selectedIndex); + } + } + } + public TableView getTable() { return table; } diff --git a/Mage.Client/src/main/java/mage/client/table/TournamentPlayerPanel.java b/Mage.Client/src/main/java/mage/client/table/TournamentPlayerPanel.java index d530406bdbf..466b08bd093 100644 --- a/Mage.Client/src/main/java/mage/client/table/TournamentPlayerPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TournamentPlayerPanel.java @@ -36,6 +36,7 @@ package mage.client.table; import java.util.UUID; import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; import mage.client.MageFrame; import mage.client.remote.Session; @@ -59,8 +60,8 @@ public class TournamentPlayerPanel extends javax.swing.JPanel { this.lblPlayerNum.setText("Player " + playerNum); } - public String getPlayerType() { - return (String) this.cbPlayerType.getSelectedItem(); + public JComboBox getPlayerType() { + return this.cbPlayerType; } public boolean joinTournamentTable(UUID roomId, UUID tableId) { 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 new file mode 100644 index 00000000000..340b290b97f --- /dev/null +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -0,0 +1,656 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.player.ai; + +import mage.Constants.Outcome; +import mage.Constants.PhaseStep; +import mage.Constants.RangeOfInfluence; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.effects.Effect; +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; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.StackAbility; +import mage.game.stack.StackObject; +import mage.game.turn.*; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetCard; +import mage.util.Logging; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author nantuko + */ +public class ComputerPlayer6 extends ComputerPlayer implements Player { + + private static final transient Logger logger = Logging.getLogger(ComputerPlayer6.class.getName()); + private static final ExecutorService pool = Executors.newFixedThreadPool(1); + + protected int maxDepth; + protected int maxNodes; + protected LinkedList actions = new LinkedList(); + protected List targets = new ArrayList(); + protected List choices = new ArrayList(); + protected Combat combat; + protected int currentScore; + protected SimulationNode2 root; + + public ComputerPlayer6(String name, RangeOfInfluence range) { + super(name, range); + maxDepth = Config2.maxDepth; + maxNodes = Config2.maxNodes; + } + + public ComputerPlayer6(final ComputerPlayer6 player) { + super(player); + this.maxDepth = player.maxDepth; + this.currentScore = player.currentScore; + if (player.combat != null) + this.combat = player.combat.copy(); + for (Ability ability: player.actions) { + actions.add(ability); + } + for (UUID targetId: player.targets) { + targets.add(targetId); + } + for (String choice: player.choices) { + choices.add(choice); + } + } + + @Override + public ComputerPlayer6 copy() { + return new ComputerPlayer6(this); + } + + @Override + public void priority(Game game) { + logState(game); + game.firePriorityEvent(playerId); + switch (game.getTurn().getStepType()) { + case UPKEEP: + case DRAW: + pass(); + break; + case PRECOMBAT_MAIN: + case POSTCOMBAT_MAIN: + if (game.getActivePlayerId().equals(playerId)) { + Player player = game.getPlayer(playerId); + System.out.println("Turn::"+game.getTurnNum()); + System.out.println("[" + game.getPlayer(playerId).getName() + "] " + game.getTurn().getStepType().name() +", life=" + player.getLife()); + String s = "["; + for (Card card : player.getHand().getCards(game)) { + s += card.getName() + ";"; + } + s += "]"; + System.out.println("Hand: " + s); + s = "["; + for (Permanent permanent : game.getBattlefield().getAllPermanents()) { + if (permanent.getOwnerId().equals(player.getId())) { + s += permanent.getName() + ";"; + } + } + s += "]"; + System.out.println("Permanents: " + s); + } + if (actions.size() == 0) { + calculateActions(game); + } + act(game); + break; + case BEGIN_COMBAT: + case DECLARE_ATTACKERS: + case DECLARE_BLOCKERS: + case COMBAT_DAMAGE: + case END_COMBAT: + case END_TURN: + pass(); + break; + case CLEANUP: + pass(); + break; + } + } + + protected void act(Game game) { + if (actions == null || actions.size() == 0) + pass(); + else { + boolean usedStack = false; + while (actions.peek() != null) { + Ability ability = actions.poll(); + System.out.println("[" + game.getPlayer(playerId).getName() + "] Action: " + ability.toString()); + this.activateAbility((ActivatedAbility) ability, game); + if (ability.isUsesStack()) + usedStack = true; + } + if (usedStack) + pass(); + } + } + + protected void calculateActions(Game game) { + currentScore = GameStateEvaluator2.evaluate(playerId, game); + if (!getNextAction(game)) { + Game sim = createSimulation(game); + SimulationNode2.resetCount(); + root = new SimulationNode2(sim, maxDepth, playerId); + logger.info("simulating actions"); + addActionsTimed(new FilterAbility()); + if (root.children.size() > 0) { + root = root.children.get(0); + int bestScore = GameStateEvaluator2.evaluate(playerId, root.getGame()); + if (bestScore > currentScore) { + actions = new LinkedList(root.abilities); + combat = root.combat; + } + } + } + } + + protected boolean getNextAction(Game game) { + if (root != null && root.children.size() > 0) { + SimulationNode2 test = root; + root = root.children.get(0); + while (root.children.size() > 0 && !root.playerId.equals(playerId)) { + test = root; + root = root.children.get(0); + } + logger.info("simlating -- game value:" + game.getState().getValue() + " test value:" + test.gameValue); + if (root.playerId.equals(playerId) && root.abilities != null && game.getState().getValue() == test.gameValue) { + logger.info("simulating -- continuing previous action chain"); + actions = new LinkedList(root.abilities); + combat = root.combat; + return true; + } + else { + return false; + } + } + return false; + } + + protected int minimaxAB(SimulationNode2 node, FilterAbility filter, int depth, int alpha, int beta) { + UUID currentPlayerId = node.getGame().getPlayerList().get(); + SimulationNode2 bestChild = null; + for (SimulationNode2 child: node.getChildren()) { + if (alpha >= beta) { + logger.info("alpha beta pruning"); + break; + } + if (SimulationNode2.nodeCount > maxNodes) { + logger.info("simulating -- reached end-state, count=" + SimulationNode2.nodeCount); + break; + } + int val = addActions(child, filter, depth-1, alpha, beta); + if (!currentPlayerId.equals(playerId)) { + if (val < beta) { + beta = val; + bestChild = child; + if (node.getCombat() == null) + node.setCombat(child.getCombat()); + } + } + else { + if (val > alpha) { + alpha = val; + bestChild = child; + if (node.getCombat() == null) + node.setCombat(child.getCombat()); + } + } + } + node.children.clear(); + if (bestChild != null) + node.children.add(bestChild); + if (!currentPlayerId.equals(playerId)) { + //logger.info("returning minimax beta: " + beta); + return beta; + } + else { + //logger.info("returning minimax alpha: " + alpha); + return alpha; + } + } + + protected SearchEffect getSearchEffect(StackAbility ability) { + for (Effect effect: ability.getEffects()) { + if (effect instanceof SearchEffect) { + return (SearchEffect) effect; + } + } + return null; + } + + protected void resolve(SimulationNode2 node, int depth, Game game) { + StackObject ability = game.getStack().pop(); + if (ability instanceof StackAbility) { + SearchEffect effect = getSearchEffect((StackAbility) ability); + if (effect != null && ability.getControllerId().equals(playerId)) { + Target target = effect.getTarget(); + if (!target.doneChosing()) { + for (UUID targetId: target.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) { + Game sim = game.copy(); + StackAbility newAbility = (StackAbility) ability.copy(); + SearchEffect newEffect = getSearchEffect((StackAbility) newAbility); + newEffect.getTarget().addTarget(targetId, newAbility, sim); + sim.getStack().push(newAbility); + SimulationNode2 newNode = new SimulationNode2(sim, depth, ability.getControllerId()); + node.children.add(newNode); + newNode.getTargets().add(targetId); + logger.fine("simulating search -- node#: " + SimulationNode2.getCount() + "for player: " + sim.getPlayer(ability.getControllerId()).getName()); + } + return; + } + } + } + //logger.info("simulating resolve "); + ability.resolve(game); + game.applyEffects(); + game.getPlayers().resetPassed(); + game.getPlayerList().setCurrent(game.getActivePlayerId()); + } + + protected void addActionsTimed(final FilterAbility filter) { + FutureTask task = new FutureTask(new Callable() { + public Integer call() throws Exception + { + return addActions(root, filter, maxDepth, Integer.MIN_VALUE, Integer.MAX_VALUE); + } + }); + pool.execute(task); + try { + task.get(Config2.maxThinkSeconds, TimeUnit.MINUTES); + } catch (TimeoutException e) { + logger.info("simulating - timed out"); + task.cancel(true); + } catch (ExecutionException e) { + e.printStackTrace(); + task.cancel(true); + } catch (InterruptedException e) { + e.printStackTrace(); + task.cancel(true); + } + } + + protected int addActions(SimulationNode2 node, FilterAbility filter, int depth, int alpha, int beta) { + logger.fine("addActions: " + depth + ", alpha=" + alpha + ", beta=" + beta); + Game game = node.getGame(); + int val; + if (Thread.interrupted()) { + Thread.currentThread().interrupt(); + logger.info("interrupted"); + val = GameStateEvaluator2.evaluate(playerId, game); + return val; + } + if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.isGameOver()) { + logger.fine("simulating -- reached end state, node count=" + SimulationNode2.nodeCount + ", depth=" + depth); + val = GameStateEvaluator2.evaluate(playerId, game); + return val; + } + else if (node.getChildren().size() > 0) { + logger.fine("simulating -- somthing added children:" + node.getChildren().size()); + val = minimaxAB(node, filter, depth-1, alpha, beta); + return val; + } + else { + if (logger.isLoggable(Level.FINE)) + logger.fine("simulating -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + (node.getPlayerId().equals(playerId) ? "yes" : "no")); + if (allPassed(game)) { + if (!game.getStack().isEmpty()) { + resolve(node, depth, game); + } + else { + game.getPlayers().resetPassed(); + playNext(game, game.getActivePlayerId(), node); + } + } + + if (game.isGameOver()) { + val = GameStateEvaluator2.evaluate(playerId, game); + } + else if (node.getChildren().size() > 0) { + //declared attackers or blockers or triggered abilities + logger.fine("simulating -- attack/block/trigger added children:" + node.getChildren().size()); + val = minimaxAB(node, filter, depth-1, alpha, beta); + } + else { + val = simulatePriority(node, game, filter, depth, alpha, beta); + } + } + + if (logger.isLoggable(Level.FINE)) + logger.fine("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName()); + return val; + + } + + protected int simulatePriority(SimulationNode2 node, Game game, FilterAbility filter, int depth, int alpha, int beta) { + if (Thread.interrupted()) { + Thread.currentThread().interrupt(); + logger.info("interrupted"); + return GameStateEvaluator2.evaluate(playerId, game); + } + node.setGameValue(game.getState().getValue()); + SimulatedPlayer2 currentPlayer = (SimulatedPlayer2) game.getPlayer(game.getPlayerList().get()); + //logger.info("simulating -- player " + currentPlayer.getName()); + SimulationNode2 bestNode = null; + List allActions = currentPlayer.simulatePriority(game, filter); + if (logger.isLoggable(Level.FINE)) + logger.fine("simulating -- adding " + allActions.size() + " children:" + allActions); + for (Ability action: allActions) { + Game sim = game.copy(); + if (sim.getPlayer(currentPlayer.getId()).activateAbility((ActivatedAbility) action.copy(), sim)) { + sim.applyEffects(); + if (!sim.isGameOver() && action.isUsesStack()) { + // only pass if the last action uses the stack + sim.getPlayer(currentPlayer.getId()).pass(); + sim.getPlayerList().getNext(); + } + SimulationNode2 newNode = new SimulationNode2(sim, action, depth, currentPlayer.getId()); + if (logger.isLoggable(Level.FINE)) + logger.fine("simulating -- node #:" + SimulationNode2.getCount() + " actions:" + action); + sim.checkStateAndTriggered(); + int val = addActions(newNode, filter, depth-1, alpha, beta); + if (!currentPlayer.getId().equals(playerId)) { + if (val < beta) { + beta = val; + bestNode = newNode; + node.setCombat(newNode.getCombat()); + } + } + else { + if (val > alpha) { + alpha = val; + bestNode = newNode; + node.setCombat(newNode.getCombat()); + if (node.getTargets().size() > 0) + targets = node.getTargets(); + if (node.getChoices().size() > 0) + choices = node.getChoices(); + } + } + if (alpha >= beta) { + //logger.info("simulating -- pruning"); + break; + } + if (SimulationNode2.nodeCount > maxNodes) { + logger.fine("simulating -- reached end-state"); + break; + } + } + } + if (bestNode != null) { + node.children.clear(); + node.children.add(bestNode); + } + if (!currentPlayer.getId().equals(playerId)) { + //logger.info("returning priority beta: " + beta); + return beta; + } + else { + //logger.info("returning priority alpha: " + alpha); + return alpha; + } + } + + protected boolean allPassed(Game game) { + for (Player player: game.getPlayers().values()) { + if (!player.isPassed() && !player.hasLost() && !player.hasLeft()) + return false; + } + return true; + } + + @Override + public boolean choose(Outcome outcome, Choice choice, Game game) { + if (choices.size() == 0) + return super.choose(outcome, choice, game); + if (!choice.isChosen()) { + for (String achoice: choices) { + choice.setChoice(achoice); + if (choice.isChosen()) { + choices.clear(); + return true; + } + } + return false; + } + return true; + } + + @Override + public boolean chooseTarget(Cards cards, TargetCard target, Ability source, Game game) { + if (targets.size() == 0) + return super.chooseTarget(cards, target, source, game); + if (!target.doneChosing()) { + for (UUID targetId: targets) { + target.addTarget(targetId, source, game); + if (target.doneChosing()) { + targets.clear(); + return true; + } + } + return false; + } + return true; + } + + @Override + public boolean choose(Cards cards, TargetCard target, Game game) { + if (targets.size() == 0) + return super.choose(cards, target, game); + if (!target.doneChosing()) { + for (UUID targetId: targets) { + target.add(targetId, game); + if (target.doneChosing()) { + targets.clear(); + return true; + } + } + return false; + } + return true; + } + + public void playNext(Game game, UUID activePlayerId, SimulationNode2 node) { + boolean skip = false; + while (true) { + Phase currentPhase = game.getPhase(); + if (!skip) + currentPhase.getStep().endStep(game, activePlayerId); + game.applyEffects(); + switch (currentPhase.getStep().getType()) { + case UNTAP: + game.getPhase().setStep(new UpkeepStep()); + break; + case UPKEEP: + game.getPhase().setStep(new DrawStep()); + break; + case DRAW: + game.getTurn().setPhase(new PreCombatMainPhase()); + game.getPhase().setStep(new PreCombatMainStep()); + break; + case PRECOMBAT_MAIN: + game.getTurn().setPhase(new CombatPhase()); + game.getPhase().setStep(new BeginCombatStep()); + break; + case BEGIN_COMBAT: + game.getPhase().setStep(new DeclareAttackersStep()); + break; + case DECLARE_ATTACKERS: + game.getPhase().setStep(new DeclareBlockersStep()); + break; + case DECLARE_BLOCKERS: + game.getPhase().setStep(new CombatDamageStep(true)); + break; + case COMBAT_DAMAGE: + if (((CombatDamageStep)currentPhase.getStep()).getFirst()) + game.getPhase().setStep(new CombatDamageStep(false)); + else + game.getPhase().setStep(new EndOfCombatStep()); + break; + case END_COMBAT: + game.getTurn().setPhase(new PostCombatMainPhase()); + game.getPhase().setStep(new PostCombatMainStep()); + break; + case POSTCOMBAT_MAIN: + game.getTurn().setPhase(new EndPhase()); + game.getPhase().setStep(new EndStep()); + break; + case END_TURN: + game.getPhase().setStep(new CleanupStep()); + break; + case CLEANUP: + game.getPhase().getStep().beginStep(game, activePlayerId); + if (!game.checkStateAndTriggered() && !game.isGameOver()) { + game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); + game.getTurn().setPhase(new BeginningPhase()); + game.getPhase().setStep(new UntapStep()); + } + } + if (!game.getStep().skipStep(game, game.getActivePlayerId())) { + if (game.getTurn().getStepType() == PhaseStep.DECLARE_ATTACKERS) { + game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE, null, null, activePlayerId)); + if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, activePlayerId, activePlayerId))) { + for (Combat engagement: ((SimulatedPlayer2)game.getPlayer(activePlayerId)).addAttackers(game)) { + Game sim = game.copy(); + UUID defenderId = game.getOpponents(playerId).iterator().next(); + for (CombatGroup group: engagement.getGroups()) { + for (UUID attackerId: group.getAttackers()) { + sim.getPlayer(activePlayerId).declareAttacker(attackerId, defenderId, sim); + } + } + sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId)); + SimulationNode2 newNode = new SimulationNode2(sim, node.getDepth()-1, activePlayerId); + logger.info("simulating -- node #:" + SimulationNode2.getCount() + " declare attakers"); + newNode.setCombat(sim.getCombat()); + node.children.add(newNode); + } + } + } + else if (game.getTurn().getStepType() == PhaseStep.DECLARE_BLOCKERS) { + game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_PRE, null, null, activePlayerId)); + if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_BLOCKERS, activePlayerId, activePlayerId))) { + for (UUID defenderId: game.getCombat().getDefenders()) { + //check if defender is being attacked + if (game.getCombat().isAttacked(defenderId, game)) { + for (Combat engagement: ((SimulatedPlayer2)game.getPlayer(defenderId)).addBlockers(game)) { + Game sim = game.copy(); + for (CombatGroup group: engagement.getGroups()) { + for (UUID blockerId: group.getBlockers()) { + group.addBlocker(blockerId, defenderId, sim); + } + } + sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId)); + SimulationNode2 newNode = new SimulationNode2(sim, node.getDepth()-1, defenderId); + logger.info("simulating -- node #:" + SimulationNode2.getCount() + " declare blockers"); + newNode.setCombat(sim.getCombat()); + node.children.add(newNode); + } + } + } + } + } + else { + game.getStep().beginStep(game, activePlayerId); + } + if (game.getStep().getHasPriority()) + break; + } + else { + skip = true; + } + } + game.checkStateAndTriggered(); + } + + @Override + public void selectAttackers(Game game) { + logger.info("selectAttackers"); + if (combat != null) { + UUID opponentId = game.getCombat().getDefenders().iterator().next(); + for (UUID attackerId: combat.getAttackers()) { + logger.info("declare attacker: " + game.getCard(attackerId).getName()); + this.declareAttacker(attackerId, opponentId, game); + } + } + } + + @Override + public void selectBlockers(Game game) { + logger.info("selectBlockers"); + if (combat != null && combat.getGroups().size() > 0) { + List groups = game.getCombat().getGroups(); + for (int i = 0; i < groups.size(); i++) { + if (i < combat.getGroups().size()) { + for (UUID blockerId: combat.getGroups().get(i).getBlockers()) { + this.declareBlocker(blockerId, groups.get(i).getAttackers().get(0), game); + } + } + } + } + } + + /** + * Copies game and replaces all players in copy with simulated players + * + * @param game + * @return a new game object with simulated players + */ + protected Game createSimulation(Game game) { + Game sim = game.copy(); + + for (Player copyPlayer: sim.getState().getPlayers().values()) { + Player origPlayer = game.getState().getPlayers().get(copyPlayer.getId()); + SimulatedPlayer2 newPlayer = new SimulatedPlayer2(copyPlayer.getId(), copyPlayer.getId().equals(playerId)); + newPlayer.restore(origPlayer); + sim.getState().getPlayers().put(copyPlayer.getId(), newPlayer); + } + return sim; + } + +} 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 d413c45283f..399f7348d5e 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 @@ -77,6 +77,7 @@ import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.Table; import mage.game.combat.CombatGroup; +import mage.game.match.Match; import mage.game.permanent.Permanent; import mage.game.tournament.Tournament; import mage.player.ai.utils.RateCard; @@ -795,9 +796,9 @@ public class ComputerPlayer> extends PlayerImpl i } @Override - public void sideboard(Table table, Deck deck) { + public void sideboard(Match match, Deck deck) { //TODO: improve this - table.fireSubmitDeckEvent(playerId, deck); + match.submitDeck(playerId, deck); } @Override diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml index 321eec47b4e..8e98cf01ebe 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml @@ -15,6 +15,12 @@ Mage Player AI Minimax + + log4j + log4j + 1.2.14 + jar + ${project.groupId} Mage 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 a3c3008bb02..ab15d6f8daa 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 @@ -39,8 +39,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; import mage.Constants.Outcome; import mage.Constants.PhaseStep; import mage.Constants.RangeOfInfluence; @@ -79,7 +77,7 @@ import mage.game.turn.UpkeepStep; import mage.players.Player; import mage.target.Target; import mage.target.TargetCard; -import mage.util.Logging; +import org.apache.log4j.Logger; /** * @@ -87,7 +85,7 @@ import mage.util.Logging; */ public class ComputerPlayer2 extends ComputerPlayer implements Player { - private static final transient Logger logger = Logging.getLogger(ComputerPlayer2.class.getName()); + private static final transient Logger logger = Logger.getLogger(ComputerPlayer2.class); private static final ExecutorService pool = Executors.newFixedThreadPool(1); protected int maxDepth; @@ -177,7 +175,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Game sim = createSimulation(game); SimulationNode.resetCount(); root = new SimulationNode(sim, maxDepth, playerId); - logger.fine("simulating actions"); + logger.debug("simulating actions"); addActionsTimed(new FilterAbility()); if (root.children.size() > 0) { root = root.children.get(0); @@ -195,9 +193,9 @@ public class ComputerPlayer2 extends ComputerPlayer implements test = root; root = root.children.get(0); } - logger.fine("simlating -- game value:" + game.getState().getValue() + " test value:" + test.gameValue); + logger.debug("simlating -- game value:" + game.getState().getValue() + " test value:" + test.gameValue); if (root.playerId.equals(playerId) && root.abilities != null && game.getState().getValue() == test.gameValue) { - logger.fine("simulating -- continuing previous action chain"); + logger.debug("simulating -- continuing previous action chain"); actions = new LinkedList(root.abilities); combat = root.combat; return true; @@ -214,11 +212,11 @@ public class ComputerPlayer2 extends ComputerPlayer implements SimulationNode bestChild = null; for (SimulationNode child: node.getChildren()) { if (alpha >= beta) { - logger.fine("alpha beta pruning"); + logger.debug("alpha beta pruning"); break; } if (SimulationNode.nodeCount > maxNodes) { - logger.fine("simulating -- reached end-state"); + logger.debug("simulating -- reached end-state"); break; } int val = addActions(child, filter, depth-1, alpha, beta); @@ -243,11 +241,11 @@ public class ComputerPlayer2 extends ComputerPlayer implements if (bestChild != null) node.children.add(bestChild); if (!currentPlayerId.equals(playerId)) { - logger.fine("returning minimax beta: " + beta); + logger.debug("returning minimax beta: " + beta); return beta; } else { - logger.fine("returning minimax alpha: " + alpha); + logger.debug("returning minimax alpha: " + alpha); return alpha; } } @@ -277,13 +275,13 @@ public class ComputerPlayer2 extends ComputerPlayer implements SimulationNode newNode = new SimulationNode(sim, depth, ability.getControllerId()); node.children.add(newNode); newNode.getTargets().add(targetId); - logger.fine("simulating search -- node#: " + SimulationNode.getCount() + "for player: " + sim.getPlayer(ability.getControllerId()).getName()); + logger.debug("simulating search -- node#: " + SimulationNode.getCount() + "for player: " + sim.getPlayer(ability.getControllerId()).getName()); } return; } } } - logger.fine("simulating resolve "); + logger.debug("simulating resolve "); ability.resolve(game); game.applyEffects(); game.getPlayers().resetPassed(); @@ -301,12 +299,14 @@ public class ComputerPlayer2 extends ComputerPlayer implements try { task.get(Config.maxThinkSeconds, TimeUnit.SECONDS); } catch (TimeoutException e) { - logger.fine("simulating - timed out"); + logger.debug("simulating - timed out"); task.cancel(true); } catch (ExecutionException e) { - + logger.fatal("Simulation error", e); + task.cancel(true); } catch (InterruptedException e) { - + logger.fatal("Simulation interrupted", e); + task.cancel(true); } } @@ -315,20 +315,20 @@ public class ComputerPlayer2 extends ComputerPlayer implements int val; if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return GameStateEvaluator.evaluate(playerId, game); } if (depth <= 0 || SimulationNode.nodeCount > maxNodes || game.isGameOver()) { - logger.fine("simulating -- reached end state"); + logger.debug("simulating -- reached end state"); val = GameStateEvaluator.evaluate(playerId, game); } else if (node.getChildren().size() > 0) { - logger.fine("simulating -- somthing added children:" + node.getChildren().size()); + logger.debug("simulating -- somthing added children:" + node.getChildren().size()); val = minimaxAB(node, filter, depth-1, alpha, beta); } else { - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + (node.getPlayerId().equals(playerId)?"yes":"no")); + if (logger.isDebugEnabled()) + logger.debug("simulating -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + (node.getPlayerId().equals(playerId)?"yes":"no")); if (allPassed(game)) { if (!game.getStack().isEmpty()) { resolve(node, depth, game); @@ -337,7 +337,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements // int testScore = GameStateEvaluator.evaluate(playerId, game); // if (testScore < currentScore) { // // if score at end of step is worse than original score don't check any further -// logger.fine("simulating -- abandoning current check, no immediate benefit"); +// logger.debug("simulating -- abandoning current check, no immediate benefit"); // return testScore; // } game.getPlayers().resetPassed(); @@ -350,7 +350,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements } else if (node.getChildren().size() > 0) { //declared attackers or blockers or triggered abilities - logger.fine("simulating -- attack/block/trigger added children:" + node.getChildren().size()); + logger.debug("simulating -- attack/block/trigger added children:" + node.getChildren().size()); val = minimaxAB(node, filter, depth-1, alpha, beta); } else { @@ -358,8 +358,8 @@ public class ComputerPlayer2 extends ComputerPlayer implements } } - if (logger.isLoggable(Level.FINE)) - logger.fine("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName()); + if (logger.isDebugEnabled()) + logger.debug("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName()); return val; } @@ -367,16 +367,16 @@ public class ComputerPlayer2 extends ComputerPlayer implements protected int simulatePriority(SimulationNode node, Game game, FilterAbility filter, int depth, int alpha, int beta) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return GameStateEvaluator.evaluate(playerId, game); } node.setGameValue(game.getState().getValue()); SimulatedPlayer currentPlayer = (SimulatedPlayer) game.getPlayer(game.getPlayerList().get()); - logger.fine("simulating -- player " + currentPlayer.getName()); + logger.debug("simulating -- player " + currentPlayer.getName()); SimulationNode bestNode = null; List allActions = currentPlayer.simulatePriority(game, filter); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- adding " + allActions.size() + " children:" + allActions); + if (logger.isDebugEnabled()) + logger.debug("simulating -- adding " + allActions.size() + " children:" + allActions); for (Ability action: allActions) { Game sim = game.copy(); if (sim.getPlayer(currentPlayer.getId()).activateAbility((ActivatedAbility) action.copy(), sim)) { @@ -387,8 +387,8 @@ public class ComputerPlayer2 extends ComputerPlayer implements sim.getPlayerList().getNext(); } SimulationNode newNode = new SimulationNode(sim, action, depth, currentPlayer.getId()); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- node #:" + SimulationNode.getCount() + " actions:" + action); + if (logger.isDebugEnabled()) + logger.debug("simulating -- node #:" + SimulationNode.getCount() + " actions:" + action); sim.checkStateAndTriggered(); int val = addActions(newNode, filter, depth-1, alpha, beta); if (!currentPlayer.getId().equals(playerId)) { @@ -410,11 +410,11 @@ public class ComputerPlayer2 extends ComputerPlayer implements } } if (alpha >= beta) { - logger.fine("simulating -- pruning"); + logger.debug("simulating -- pruning"); break; } if (SimulationNode.nodeCount > maxNodes) { - logger.fine("simulating -- reached end-state"); + logger.debug("simulating -- reached end-state"); break; } } @@ -424,11 +424,11 @@ public class ComputerPlayer2 extends ComputerPlayer implements node.children.add(bestNode); } if (!currentPlayer.getId().equals(playerId)) { - logger.fine("returning priority beta: " + beta); + logger.debug("returning priority beta: " + beta); return beta; } else { - logger.fine("returning priority alpha: " + alpha); + logger.debug("returning priority alpha: " + alpha); return alpha; } } @@ -562,7 +562,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId)); SimulationNode newNode = new SimulationNode(sim, node.getDepth()-1, activePlayerId); - logger.fine("simulating -- node #:" + SimulationNode.getCount() + " declare attakers"); + logger.debug("simulating -- node #:" + SimulationNode.getCount() + " declare attakers"); newNode.setCombat(sim.getCombat()); node.children.add(newNode); } @@ -583,7 +583,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId)); SimulationNode newNode = new SimulationNode(sim, node.getDepth()-1, defenderId); - logger.fine("simulating -- node #:" + SimulationNode.getCount() + " declare blockers"); + logger.debug("simulating -- node #:" + SimulationNode.getCount() + " declare blockers"); newNode.setCombat(sim.getCombat()); node.children.add(newNode); } @@ -606,7 +606,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements @Override public void selectAttackers(Game game) { - logger.fine("selectAttackers"); + logger.debug("selectAttackers"); if (combat != null) { UUID opponentId = game.getCombat().getDefenders().iterator().next(); for (UUID attackerId: combat.getAttackers()) { @@ -617,7 +617,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements @Override public void selectBlockers(Game game) { - logger.fine("selectBlockers"); + logger.debug("selectBlockers"); if (combat != null && combat.getGroups().size() > 0) { List groups = game.getCombat().getGroups(); for (int i = 0; i < groups.size(); i++) { 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 b3f41345278..2e8a2b2dad2 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 @@ -30,14 +30,11 @@ package mage.player.ai; import java.util.LinkedList; import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; import mage.Constants.AbilityType; import mage.Constants.PhaseStep; import mage.Constants.RangeOfInfluence; import mage.Constants.Zone; import mage.abilities.Ability; -import mage.cards.decks.Deck; import mage.filter.FilterAbility; import mage.game.Game; import mage.game.combat.Combat; @@ -60,7 +57,7 @@ import mage.game.turn.Step; import mage.game.turn.UntapStep; import mage.game.turn.UpkeepStep; import mage.players.Player; -import mage.util.Logging; +import org.apache.log4j.Logger; /** * @@ -68,7 +65,7 @@ import mage.util.Logging; */ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { - private static final transient Logger logger = Logging.getLogger(ComputerPlayer3.class.getName()); + private static final transient Logger logger = Logger.getLogger(ComputerPlayer3.class); private static FilterAbility filterLand = new FilterAbility(); private static FilterAbility filterNotLand = new FilterAbility(); @@ -158,7 +155,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { Game sim = createSimulation(game); SimulationNode.resetCount(); root = new SimulationNode(sim, maxDepth, playerId); - logger.fine("simulating pre combat actions -----------------------------------------------------------------------------------------"); + logger.debug("simulating pre combat actions -----------------------------------------------------------------------------------------"); addActionsTimed(new FilterAbility()); if (root.children.size() > 0) { @@ -175,7 +172,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { Game sim = createSimulation(game); SimulationNode.resetCount(); root = new SimulationNode(sim, maxDepth, playerId); - logger.fine("simulating post combat actions ----------------------------------------------------------------------------------------"); + logger.debug("simulating post combat actions ----------------------------------------------------------------------------------------"); addActionsTimed(new FilterAbility()); if (root.children.size() > 0) { root = root.children.get(0); @@ -192,20 +189,20 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { Game game = node.getGame(); if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return GameStateEvaluator.evaluate(playerId, game); } if (depth <= 0 || SimulationNode.nodeCount > maxNodes || game.isGameOver()) { - logger.fine("simulating -- reached end state"); + logger.debug("simulating -- reached end state"); val = GameStateEvaluator.evaluate(playerId, game); } else if (node.getChildren().size() > 0) { - logger.fine("simulating -- somthing added children:" + node.getChildren().size()); + logger.debug("simulating -- somthing added children:" + node.getChildren().size()); val = minimaxAB(node, filter, depth-1, alpha, beta); } else { - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(game.getPlayerList().get()).getName()); + if (logger.isDebugEnabled()) + logger.debug("simulating -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(game.getPlayerList().get()).getName()); if (allPassed(game)) { if (!game.getStack().isEmpty()) { resolve(node, depth, game); @@ -219,12 +216,12 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { val = GameStateEvaluator.evaluate(playerId, game); } else if (stepFinished) { - logger.fine("step finished"); + logger.debug("step finished"); int testScore = GameStateEvaluator.evaluate(playerId, game); if (game.getActivePlayerId().equals(playerId)) { if (testScore < currentScore) { // if score at end of step is worse than original score don't check further - logger.fine("simulating -- abandoning check, no immediate benefit"); + logger.debug("simulating -- abandoning check, no immediate benefit"); val = testScore; } else { @@ -249,7 +246,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { } } else if (node.getChildren().size() > 0) { - logger.fine("simulating -- trigger added children:" + node.getChildren().size()); + logger.debug("simulating -- trigger added children:" + node.getChildren().size()); val = minimaxAB(node, filter, depth, alpha, beta); } else { @@ -257,8 +254,8 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { } } - if (logger.isLoggable(Level.FINE)) - logger.fine("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName()); + if (logger.isDebugEnabled()) + logger.debug("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName()); return val; } @@ -267,7 +264,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { Integer val = null; if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return GameStateEvaluator.evaluate(playerId, game); } if (game.getTurn().getStepType() != PhaseStep.DECLARE_BLOCKERS) { @@ -303,8 +300,8 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { } if (val == null) val = GameStateEvaluator.evaluate(playerId, game); - if (logger.isLoggable(Level.FINE)) - logger.fine("returning -- combat score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); + if (logger.isDebugEnabled()) + logger.debug("returning -- combat score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); return val; } @@ -312,7 +309,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { protected int simulateAttackers(Game game, SimulationNode node, UUID attackerId, int depth, int alpha, int beta, boolean counter) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return GameStateEvaluator.evaluate(playerId, game); } Integer val = null; @@ -321,7 +318,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { for (Combat engagement: attacker.addAttackers(game)) { if (alpha >= beta) { - logger.fine("simulating -- pruning attackers"); + logger.debug("simulating -- pruning attackers"); break; } Game sim = game.copy(); @@ -333,12 +330,12 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId)); SimulationNode newNode = new SimulationNode(sim, depth, game.getActivePlayerId()); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating attack -- node#: " + SimulationNode.getCount()); + if (logger.isDebugEnabled()) + logger.debug("simulating attack -- node#: " + SimulationNode.getCount()); sim.checkStateAndTriggered(); while (!sim.getStack().isEmpty()) { sim.getStack().resolve(sim); - logger.fine("resolving triggered abilities"); + logger.debug("resolving triggered abilities"); sim.applyEffects(); } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); @@ -366,15 +363,15 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { node.children.clear(); node.children.add(bestNode); } - if (logger.isLoggable(Level.FINE)) - logger.fine("returning -- combat attacker score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); + if (logger.isDebugEnabled()) + logger.debug("returning -- combat attacker score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); return val; } protected int simulateBlockers(Game game, SimulationNode node, UUID defenderId, int depth, int alpha, int beta, boolean counter) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return GameStateEvaluator.evaluate(playerId, game); } Integer val = null; @@ -384,24 +381,26 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { SimulatedPlayer defender = (SimulatedPlayer) game.getPlayer(defenderId); for (Combat engagement: defender.addBlockers(game)) { if (alpha >= beta) { - logger.fine("simulating -- pruning blockers"); + logger.debug("simulating -- pruning blockers"); break; } Game sim = game.copy(); for (CombatGroup group: engagement.getGroups()) { - UUID attackerId = group.getAttackers().get(0); - for (UUID blockerId: group.getBlockers()) { - sim.getPlayer(defenderId).declareBlocker(blockerId, attackerId, sim); + if (group.getAttackers().size() > 0) { + UUID attackerId = group.getAttackers().get(0); + for (UUID blockerId: group.getBlockers()) { + sim.getPlayer(defenderId).declareBlocker(blockerId, attackerId, sim); + } } } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId)); SimulationNode newNode = new SimulationNode(sim, depth, defenderId); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating block -- node#: " + SimulationNode.getCount()); + if (logger.isDebugEnabled()) + logger.debug("simulating block -- node#: " + SimulationNode.getCount()); sim.checkStateAndTriggered(); while (!sim.getStack().isEmpty()) { sim.getStack().resolve(sim); - logger.fine("resolving triggered abilities"); + logger.debug("resolving triggered abilities"); sim.applyEffects(); } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); @@ -437,20 +436,20 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { node.children.clear(); node.children.add(bestNode); } - if (logger.isLoggable(Level.FINE)) - logger.fine("returning -- combat blocker score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); + if (logger.isDebugEnabled()) + logger.debug("returning -- combat blocker score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); return val; } protected int simulateCounterAttack(Game game, SimulationNode node, int depth, int alpha, int beta) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return GameStateEvaluator.evaluate(playerId, game); } Integer val = null; if (!game.isGameOver()) { - logger.fine("simulating -- counter attack"); + logger.debug("simulating -- counter attack"); simulateToEnd(game); game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); game.getTurn().setPhase(new BeginningPhase()); @@ -461,8 +460,8 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { game.getPhase().endPhase(game, game.getActivePlayerId()); } val = simulateCombat(game, node, depth-1, alpha, beta, true); - if (logger.isLoggable(Level.FINE)) - logger.fine("returning -- counter attack score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); + if (logger.isDebugEnabled()) + logger.debug("returning -- counter attack score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); } if (val == null) val = GameStateEvaluator.evaluate(playerId, game); @@ -472,7 +471,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { protected void simulateStep(Game game, Step step) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return; } if (!game.isGameOver()) { @@ -492,7 +491,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { protected void finishCombat(Game game) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return; } simulateStep(game, new CombatDamageStep(true)); @@ -503,10 +502,10 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { protected int simulatePostCombatMain(Game game, SimulationNode node, int depth, int alpha, int beta) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return GameStateEvaluator.evaluate(playerId, game); } - logger.fine("simulating -- post combat main"); + logger.debug("simulating -- post combat main"); game.getTurn().setPhase(new PostCombatMainPhase()); if (game.getPhase().beginPhase(game, game.getActivePlayerId())) { game.getPhase().setStep(new PostCombatMainStep()); @@ -520,7 +519,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { protected void simulateToEnd(Game game) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.fine("interrupted"); + logger.debug("interrupted"); return; } if (!game.isGameOver()) { diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/Config.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/Config.java index c0854286f46..a5ad2526d48 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/Config.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/Config.java @@ -33,9 +33,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.net.URISyntaxException; import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; -import mage.util.Logging; +import org.apache.log4j.Logger; /** * @@ -43,7 +41,7 @@ import mage.util.Logging; */ public class Config { - private final static Logger logger = Logging.getLogger(Config.class.getName()); + private final static Logger logger = Logger.getLogger(Config.class); public static final int maxDepth; public static final int maxNodes; @@ -59,9 +57,9 @@ public class Config { File file = new File(Config.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); p.load(new FileInputStream(new File(file.getParent() + File.separator + "AIMinimax.properties"))); } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); + logger.fatal("", ex); } catch (URISyntaxException ex) { - Logger.getLogger(Config.class.getName()).log(Level.SEVERE, null, ex); + logger.fatal("", ex); } maxDepth = Integer.parseInt(p.getProperty("maxDepth")); maxNodes = Integer.parseInt(p.getProperty("maxNodes")); 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 be3b0c762c7..48d4c979036 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 @@ -31,18 +31,11 @@ package mage.player.ai; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.logging.Level; -import java.util.logging.Logger; import mage.abilities.Ability; -import mage.abilities.ActivatedAbility; import mage.abilities.TriggeredAbility; import mage.abilities.common.PassAbility; import mage.abilities.mana.ManaOptions; @@ -54,8 +47,7 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.StackAbility; import mage.target.Target; -import mage.util.Copier; -import mage.util.Logging; +import org.apache.log4j.Logger; /** * @@ -63,7 +55,7 @@ import mage.util.Logging; */ public class SimulatedPlayer extends ComputerPlayer { - private final static transient Logger logger = Logging.getLogger(SimulatedPlayer.class.getName()); + private final static transient Logger logger = Logger.getLogger(SimulatedPlayer.class); private boolean isSimulatedPlayer; private FilterAbility filter; private transient ConcurrentLinkedQueue allActions; @@ -154,10 +146,10 @@ public class SimulatedPlayer extends ComputerPlayer { sim.getCombat().declareAttacker(attackersList.get(j).getId(), defenderId, sim); } if (engagements.put(sim.getCombat().getValue(sim), sim.getCombat()) != null) { - logger.fine("simulating -- found redundant attack combination"); + logger.debug("simulating -- found redundant attack combination"); } - else if (logger.isLoggable(Level.FINE)) { - logger.fine("simulating -- attack:" + sim.getCombat().getGroups().size()); + else if (logger.isDebugEnabled()) { + logger.debug("simulating -- attack:" + sim.getCombat().getGroups().size()); } } return new ArrayList(engagements.values()); @@ -185,15 +177,15 @@ public class SimulatedPlayer extends ComputerPlayer { int numGroups = game.getCombat().getGroups().size(); //try to block each attacker with each potential blocker Permanent blocker = blockers.get(0); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- block:" + blocker); + if (logger.isDebugEnabled()) + logger.debug("simulating -- block:" + blocker); List remaining = remove(blockers, blocker); for (int i = 0; i < numGroups; i++) { if (game.getCombat().getGroups().get(i).canBlock(blocker, game)) { Game sim = game.copy(); sim.getCombat().getGroups().get(i).addBlocker(blocker.getId(), playerId, sim); if (engagements.put(sim.getCombat().getValue(sim), sim.getCombat()) != null) - logger.fine("simulating -- found redundant block combination"); + logger.debug("simulating -- found redundant block combination"); addBlocker(sim, remaining, engagements); // and recurse minus the used blocker } } @@ -205,8 +197,8 @@ public class SimulatedPlayer extends ComputerPlayer { Ability ability = source.copy(); List options = getPlayableOptions(ability, game); if (options.size() == 0) { - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- triggered ability:" + ability); + if (logger.isDebugEnabled()) + logger.debug("simulating -- triggered ability:" + ability); game.getStack().push(new StackAbility(ability, playerId)); ability.activate(game, false); game.applyEffects(); @@ -216,7 +208,7 @@ public class SimulatedPlayer extends ComputerPlayer { SimulationNode parent = (SimulationNode) game.getCustomData(); int depth = parent.getDepth() - 1; if (depth == 0) return true; - logger.fine("simulating -- triggered ability - adding children:" + options.size()); + logger.debug("simulating -- triggered ability - adding children:" + options.size()); for (Ability option: options) { addAbilityNode(parent, option, depth, game); } @@ -230,7 +222,7 @@ public class SimulatedPlayer extends ComputerPlayer { ability.activate(sim, false); sim.applyEffects(); SimulationNode newNode = new SimulationNode(sim, depth, playerId); - logger.fine("simulating -- node #:" + SimulationNode.getCount() + " triggered ability option"); + logger.debug("simulating -- node #:" + SimulationNode.getCount() + " triggered ability option"); for (Target target: ability.getTargets()) { for (UUID targetId: target.getTargets()) { newNode.getTargets().add(targetId); diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 3c1d67d5bc1..9754d58fbe8 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -57,6 +57,7 @@ import mage.choices.ChoiceImpl; import mage.filter.common.FilterCreatureForCombat; import mage.game.Game; import mage.game.Table; +import mage.game.match.Match; import mage.game.permanent.Permanent; import mage.game.tournament.Tournament; import mage.target.Target; @@ -482,8 +483,8 @@ public class HumanPlayer extends PlayerImpl { } @Override - public void sideboard(Table table, Deck deck) { - table.fireSideboardEvent(playerId, deck); + public void sideboard(Match match, Deck deck) { + match.fireSideboardEvent(playerId, deck); } @Override diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/target/maven-archiver/pom.properties b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/target/maven-archiver/pom.properties deleted file mode 100644 index d3673d07638..00000000000 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/target/maven-archiver/pom.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Generated by Maven -#Sat Feb 12 23:42:53 MSK 2011 -version=0.6 -groupId=org.mage -artifactId=Mage-Tournament-BoosterDraft diff --git a/Mage.Server/plugins/mage-player-ai.jar b/Mage.Server/plugins/mage-player-ai.jar index 0d84511d774..5bdf67b3a46 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-human.jar b/Mage.Server/plugins/mage-player-human.jar index 049c58a1d7c..4d68195bead 100644 Binary files a/Mage.Server/plugins/mage-player-human.jar and b/Mage.Server/plugins/mage-player-human.jar differ diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index d3f8d017126..ddb34858b9e 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -33,8 +33,6 @@ import mage.server.util.PluginClassLoader; import java.io.File; import java.io.FilenameFilter; import java.net.InetAddress; -import java.util.logging.Level; -import java.util.logging.Logger; import mage.game.match.MatchType; import mage.game.tournament.TournamentType; import mage.server.game.DeckValidatorFactory; @@ -45,7 +43,7 @@ import mage.server.util.ConfigSettings; import mage.server.util.config.Plugin; import mage.server.util.config.GamePlugin; import mage.util.Copier; -import mage.util.Logging; +import org.apache.log4j.Logger; /** * @@ -53,7 +51,7 @@ import mage.util.Logging; */ public class Main { - private static Logger logger = Logging.getLogger(Main.class.getName()); + private static Logger logger = Logger.getLogger(Main.class); private final static String testModeArg = "-testMode="; private final static String pluginFolder = "plugins"; @@ -68,7 +66,7 @@ public class Main { public static void main(String[] args) { logger.info("Starting MAGE server version " + version); - logger.info("Logging level: " + Logging.getLevel(logger)); + logger.info("Logging level: " + logger.getLevel()); deleteSavedGames(); ConfigSettings config = ConfigSettings.getInstance(); for (GamePlugin plugin: config.getGameTypes()) { @@ -101,7 +99,7 @@ public class Main { ip = InetAddress.getLocalHost().getHostAddress(); } } catch (UnknownHostException ex) { - logger.log(Level.WARNING, "Could not get server address: ", ex); + logger.warn("Could not get server address: ", ex); } String ipParam = System.getProperty("server"); if (ipParam != null) { @@ -117,9 +115,9 @@ public class Main { logger.info("Loading plugin: " + plugin.getClassName()); return Class.forName(plugin.getClassName(), true, classLoader); } catch (ClassNotFoundException ex) { - logger.log(Level.SEVERE, "Plugin not Found:" + plugin.getJar() + " - check plugin folder"); + logger.warn("Plugin not Found:" + plugin.getJar() + " - check plugin folder"); } catch (Exception ex) { - logger.log(Level.SEVERE, "Error loading plugin " + plugin.getJar(), ex); + logger.fatal("Error loading plugin " + plugin.getJar(), ex); } return null; } @@ -130,9 +128,9 @@ public class Main { logger.info("Loading game type: " + plugin.getClassName()); return (MatchType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); } catch (ClassNotFoundException ex) { - logger.log(Level.SEVERE, "Game type not found:" + plugin.getJar() + " - check plugin folder"); + logger.warn("Game type not found:" + plugin.getJar() + " - check plugin folder"); } catch (Exception ex) { - logger.log(Level.SEVERE, "Error loading game type " + plugin.getJar(), ex); + logger.fatal("Error loading game type " + plugin.getJar(), ex); } return null; } @@ -143,9 +141,9 @@ public class Main { logger.info("Loading tournament type: " + plugin.getClassName()); return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); } catch (ClassNotFoundException ex) { - logger.log(Level.SEVERE, "Tournament type not found:" + plugin.getJar() + " - check plugin folder"); + logger.warn("Tournament type not found:" + plugin.getJar() + " - check plugin folder"); } catch (Exception ex) { - logger.log(Level.SEVERE, "Error loading game type " + plugin.getJar(), ex); + logger.fatal("Error loading game type " + plugin.getJar(), ex); } return null; } diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 7f707e2ea65..ff58f76c09c 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -66,7 +66,6 @@ import mage.game.match.MatchOptions; import mage.game.match.MatchPlayer; import mage.game.tournament.Tournament; import mage.game.tournament.TournamentOptions; -import mage.game.tournament.TournamentPlayer; import mage.players.Player; import mage.server.game.DeckValidatorFactory; import mage.server.game.GameFactory; @@ -85,15 +84,12 @@ public class TableController { private final static Logger logger = Logging.getLogger(TableController.class.getName()); - private static final int SIDEBOARD_TIME = 180; - private UUID sessionId; private UUID chatId; private Table table; private Match match; private MatchOptions options; private Tournament tournament; - private TournamentOptions tournamentOptions; private ConcurrentHashMap sessionPlayerMap = new ConcurrentHashMap(); public TableController(UUID sessionId, MatchOptions options) { @@ -108,24 +104,19 @@ public class TableController { public TableController(UUID sessionId, TournamentOptions options) { this.sessionId = sessionId; chatId = ChatManager.getInstance().createChatSession(); - this.tournamentOptions = options; tournament = TournamentFactory.getInstance().createTournament(options.getTournamentType(), options); table = new Table(options.getTournamentType(), options.getName(), DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), true); - init(); } private void init() { - table.addTableEventListener( + match.addTableEventListener( new Listener () { @Override public void event(TableEvent event) { switch (event.getEventType()) { case SIDEBOARD: - sideboard(event.getPlayerId(), event.getDeck()); + sideboard(event.getPlayerId(), event.getDeck(), event.getTimeout()); break; -// case CONSTRUCT: -// construct(event.getPlayerId(), event.getDeck()); -// break; case SUBMIT_DECK: submitDeck(event.getPlayerId(), event.getDeck()); break; @@ -209,8 +200,7 @@ public class TableController { private void submitDeck(UUID sessionId, Deck deck) { if (table.getState() == TableState.SIDEBOARDING) { - MatchPlayer player = match.getPlayer(sessionPlayerMap.get(sessionId)); - player.submitDeck(deck); + match.submitDeck(sessionPlayerMap.get(sessionId), deck); } else { TournamentManager.getInstance().submitDeck(tournament.getId(), sessionId, deck); @@ -262,7 +252,13 @@ public class TableController { } public synchronized void startMatch(UUID sessionId) { - if (sessionId.equals(this.sessionId) && table.getState() == TableState.STARTING) { + if (sessionId.equals(this.sessionId)) { + startMatch(); + } + } + + public synchronized void startMatch() { + if (table.getState() == TableState.STARTING) { try { match.startMatch(); startGame(null); @@ -284,7 +280,6 @@ public class TableController { public synchronized void startTournament(UUID sessionId) { if (sessionId.equals(this.sessionId) && table.getState() == TableState.STARTING) { - table.initTournament(); TournamentManager.getInstance().createTournamentSession(tournament, sessionPlayerMap, table.getId()); SessionManager sessionManager = SessionManager.getInstance(); for (Entry entry: sessionPlayerMap.entrySet()) { @@ -302,42 +297,19 @@ public class TableController { } } - private void sideboard() { - table.sideboard(); - for (MatchPlayer player: match.getPlayers()) { - player.setSideboarding(); - player.getPlayer().sideboard(table, player.getDeck()); - } - while (!match.isDoneSideboarding()){} - } - - private void sideboard(UUID playerId, Deck deck) { + private void sideboard(UUID playerId, Deck deck, int timeout) { SessionManager sessionManager = SessionManager.getInstance(); for (Entry entry: sessionPlayerMap.entrySet()) { if (entry.getValue().equals(playerId)) { - sessionManager.getSession(entry.getKey()).sideboard(deck, table.getId(), SIDEBOARD_TIME); + sessionManager.getSession(entry.getKey()).sideboard(deck, table.getId(), timeout); break; } } } -// public void construct() { -// table.construct(); -// for (TournamentPlayer player: tournament.getPlayers()) { -// player.setConstructing(); -// player.getPlayer().construct(table, player.getDeck()); -// } -// } - -// private void construct(UUID playerId, Deck deck) { -// SessionManager sessionManager = SessionManager.getInstance(); -// for (Entry entry: sessionPlayerMap.entrySet()) { -// if (entry.getValue().equals(playerId)) { -// sessionManager.getSession(entry.getKey()).construct(deck, table.getId(), CONSTRUCT_TIME); -// break; -// } -// } -// } + public void construct() { + table.construct(); + } public void endGame() { UUID choosingPlayerId = match.getChooser(); @@ -347,7 +319,8 @@ public class TableController { GameManager.getInstance().removeGame(match.getGame().getId()); try { if (!match.isMatchOver()) { - sideboard(); + table.sideboard(); + match.sideboard(); startGame(choosingPlayerId); } } catch (GameException ex) { @@ -433,4 +406,5 @@ public class TableController { public Match getMatch() { return match; } + } diff --git a/Mage.Server/src/main/java/mage/server/TableManager.java b/Mage.Server/src/main/java/mage/server/TableManager.java index 2a120a9a9ef..914c77039b6 100644 --- a/Mage.Server/src/main/java/mage/server/TableManager.java +++ b/Mage.Server/src/main/java/mage/server/TableManager.java @@ -67,6 +67,13 @@ public class TableManager { return tableController.getTable(); } + public Table createTable(MatchOptions options) { + TableController tableController = new TableController(UUID.randomUUID(), options); + controllers.put(tableController.getTable().getId(), tableController); + tables.put(tableController.getTable().getId(), tableController.getTable()); + return tableController.getTable(); + } + public Table createTournamentTable(UUID sessionId, TournamentOptions options) { TableController tableController = new TableController(sessionId, options); controllers.put(tableController.getTable().getId(), tableController); @@ -127,6 +134,10 @@ public class TableManager { controllers.get(tableId).startMatch(sessionId); } + public void startMatch(UUID roomId, UUID tableId) { + controllers.get(tableId).startMatch(); + } + public void startTournament(UUID sessionId, UUID roomId, UUID tableId) { controllers.get(tableId).startTournament(sessionId); } @@ -161,11 +172,12 @@ public class TableManager { } } -// public void construct(UUID tableId) { -// controllers.get(tableId).construct(); -// } + public void construct(UUID tableId) { + controllers.get(tableId).construct(); + } public void addPlayer(UUID sessionId, UUID tableId, Player player, String playerType, Deck deck) throws GameException { controllers.get(tableId).addPlayer(sessionId, player, playerType, deck); } + } diff --git a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java index 36ce1e3230d..9c18fefe560 100644 --- a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java +++ b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java @@ -66,8 +66,6 @@ public class TournamentController { private ConcurrentHashMap sessionPlayerMap = new ConcurrentHashMap(); private ConcurrentHashMap tournamentSessions = new ConcurrentHashMap(); - private static final int CONSTRUCT_TIME = 600; - public TournamentController(Tournament tournament, ConcurrentHashMap sessionPlayerMap, UUID tableId) { sessionId = UUID.randomUUID(); this.sessionPlayerMap = sessionPlayerMap; @@ -96,6 +94,9 @@ public class TournamentController { case SUBMIT_DECK: submitDeck(event.getPlayerId(), event.getDeck()); break; + case CONSTRUCT: + construct(); + break; } } } @@ -170,12 +171,12 @@ public class TournamentController { private void startMatch(TournamentPairing pair, MatchOptions matchOptions) { try { TableManager tableManager = TableManager.getInstance(); - Table table = tableManager.createTable(sessionId, matchOptions); + Table table = tableManager.createTable(matchOptions); TournamentPlayer player1 = pair.getPlayer1(); TournamentPlayer player2 = pair.getPlayer2(); tableManager.addPlayer(getPlayerSessionId(player1.getPlayer().getId()), table.getId(), player1.getPlayer(), player1.getPlayerType(), player1.getDeck()); tableManager.addPlayer(getPlayerSessionId(player2.getPlayer().getId()), table.getId(), player2.getPlayer(), player2.getPlayerType(), player2.getDeck()); - tableManager.startMatch(sessionId, null, table.getId()); + tableManager.startMatch(null, table.getId()); pair.setMatch(tableManager.getMatch(table.getId())); } catch (GameException ex) { Logger.getLogger(TournamentController.class.getName()).log(Level.SEVERE, null, ex); @@ -186,12 +187,15 @@ public class TournamentController { TableManager.getInstance().startDraft(tableId, draft); } + private void construct() { + TableManager.getInstance().construct(tableId); + } + private synchronized void construct(UUID sessionId, Deck deck, int timeout) { if (tournamentSessions.containsKey(sessionId)) tournamentSessions.get(sessionId).construct(deck, timeout); } - public void submitDeck(UUID sessionId, Deck deck) { tournamentSessions.get(sessionPlayerMap.get(sessionId)).submitDeck(deck); } diff --git a/Mage.Sets/src/mage/sets/alarareborn/CapturedSunlight.java b/Mage.Sets/src/mage/sets/alarareborn/CapturedSunlight.java new file mode 100644 index 00000000000..705e5eae196 --- /dev/null +++ b/Mage.Sets/src/mage/sets/alarareborn/CapturedSunlight.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.alarareborn; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.CascadeAbility; +import mage.cards.CardImpl; + +/** + * + * @author Loki + */ +public class CapturedSunlight extends CardImpl { + + public CapturedSunlight (UUID ownerId) { + super(ownerId, 66, "Captured Sunlight", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{G}{W}"); + this.expansionSetCode = "ARB"; + this.color.setGreen(true); + this.color.setWhite(true); + this.getSpellAbility().addEffect(new GainLifeEffect(4)); + this.addAbility(new CascadeAbility()); + } + + public CapturedSunlight (final CapturedSunlight card) { + super(card); + } + + @Override + public CapturedSunlight copy() { + return new CapturedSunlight(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/alarareborn/MagefireWings.java b/Mage.Sets/src/mage/sets/alarareborn/MagefireWings.java new file mode 100644 index 00000000000..ff6efa0593e --- /dev/null +++ b/Mage.Sets/src/mage/sets/alarareborn/MagefireWings.java @@ -0,0 +1,82 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.alarareborn; + +import java.util.UUID; + +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continious.BoostEnchantedEffect; +import mage.abilities.effects.common.continious.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Loki + */ +public class MagefireWings extends CardImpl { + + public MagefireWings (UUID ownerId) { + super(ownerId, 88, "Magefire Wings", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{U}{R}"); + this.expansionSetCode = "ARB"; + this.subtype.add("Aura"); + this.color.setBlue(true); + this.color.setRed(true); + + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Constants.Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 0, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), Constants.AttachmentType.AURA))); + } + + public MagefireWings (final MagefireWings card) { + super(card); + } + + @Override + public MagefireWings copy() { + return new MagefireWings(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/alarareborn/VithianRenegades.java b/Mage.Sets/src/mage/sets/alarareborn/VithianRenegades.java new file mode 100644 index 00000000000..4c621a774e9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/alarareborn/VithianRenegades.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.alarareborn; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.FilterPermanent; +import mage.target.TargetPermanent; + +/** + * + * @author Loki + */ +public class VithianRenegades extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("artifact"); + + static { + filter.getCardType().add(CardType.ARTIFACT); + filter.setScopeCardType(Filter.ComparisonScope.Any); + } + + public VithianRenegades (UUID ownerId) { + super(ownerId, 64, "Vithian Renegades", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + this.expansionSetCode = "ARB"; + this.subtype.add("Human"); + this.subtype.add("Shaman"); + this.color.setRed(true); + this.color.setGreen(true); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + public VithianRenegades (final VithianRenegades card) { + super(card); + } + + @Override + public VithianRenegades copy() { + return new VithianRenegades(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/planechase/BullCerodon.java b/Mage.Sets/src/mage/sets/planechase/BullCerodon.java new file mode 100644 index 00000000000..b6de07d254a --- /dev/null +++ b/Mage.Sets/src/mage/sets/planechase/BullCerodon.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.planechase; + +import java.util.UUID; + +/** + * + * @author Loki + */ +public class BullCerodon extends mage.sets.shardsofalara.BullCerodon { + + public BullCerodon (UUID ownerId) { + super(ownerId); + this.cardNumber = 84; + this.expansionSetCode = "HOP"; + } + + public BullCerodon (final BullCerodon card) { + super(card); + } + + @Override + public BullCerodon copy() { + return new BullCerodon(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/shardsofalara/BullCerodon.java b/Mage.Sets/src/mage/sets/shardsofalara/BullCerodon.java new file mode 100644 index 00000000000..639cb0bb824 --- /dev/null +++ b/Mage.Sets/src/mage/sets/shardsofalara/BullCerodon.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.shardsofalara; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; + +/** + * + * @author Loki + */ +public class BullCerodon extends CardImpl { + + public BullCerodon (UUID ownerId) { + super(ownerId, 161, "Bull Cerodon", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{R}{W}"); + this.expansionSetCode = "ALA"; + this.subtype.add("Beast"); + this.color.setRed(true); + this.color.setWhite(true); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + this.addAbility(VigilanceAbility.getInstance()); + this.addAbility(HasteAbility.getInstance()); + } + + public BullCerodon (final BullCerodon card) { + super(card); + } + + @Override + public BullCerodon copy() { + return new BullCerodon(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/shardsofalara/JhessianInfiltrator.java b/Mage.Sets/src/mage/sets/shardsofalara/JhessianInfiltrator.java new file mode 100644 index 00000000000..1e88aaa616c --- /dev/null +++ b/Mage.Sets/src/mage/sets/shardsofalara/JhessianInfiltrator.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.shardsofalara; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.keyword.UnblockableAbility; +import mage.cards.CardImpl; + +/** + * + * @author Loki + */ +public class JhessianInfiltrator extends CardImpl { + + public JhessianInfiltrator (UUID ownerId) { + super(ownerId, 174, "Jhessian Infiltrator", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{G}{U}"); + this.expansionSetCode = "ALA"; + this.subtype.add("Human"); + this.subtype.add("Rogue"); + this.color.setGreen(true); + this.color.setBlue(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + this.addAbility(UnblockableAbility.getInstance()); + } + + public JhessianInfiltrator (final JhessianInfiltrator card) { + super(card); + } + + @Override + public JhessianInfiltrator copy() { + return new JhessianInfiltrator(this); + } + +} diff --git a/Mage.Tests/config/config.xml b/Mage.Tests/config/config.xml index 763e09187a1..7af45388f85 100644 --- a/Mage.Tests/config/config.xml +++ b/Mage.Tests/config/config.xml @@ -4,7 +4,7 @@ - + diff --git a/Mage.Tests/plugins/mage-player-ai-ma.jar b/Mage.Tests/plugins/mage-player-ai-ma.jar index 8792f2746e5..6e895cae6c7 100644 Binary files a/Mage.Tests/plugins/mage-player-ai-ma.jar and b/Mage.Tests/plugins/mage-player-ai-ma.jar differ diff --git a/Mage.Tests/scenario1.txt b/Mage.Tests/scenario1.txt new file mode 100644 index 00000000000..cf7e85f73bf --- /dev/null +++ b/Mage.Tests/scenario1.txt @@ -0,0 +1,21 @@ +### ComputerA ### +# Battlefield +battlefield:ComputerA:Island:1 +# Hand +hand:ComputerA:Mountain:2 +hand:ComputerA:Lightning Bolt:5 +# Library +# from down to top +library:ComputerA:clear:0 +library:ComputerA:Lightning Bolt:10 + +### ComputerB ### +# Battlefield +battlefield:ComputerB:Plains:1 +# Hand +hand:ComputerB:Plains:2 +# Library +# from down to top +library:ComputerB:clear:0 +library:ComputerB:Plains:10 + diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java index e8fed69414d..2a63cfaeded 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java @@ -1,6 +1,8 @@ package org.mage.test.serverside; import mage.Constants; +import mage.cards.Card; +import mage.cards.ExpansionSet; import mage.cards.decks.Deck; import mage.game.Game; import mage.game.GameException; @@ -11,42 +13,137 @@ import mage.sets.Sets; import org.junit.Test; import org.mage.test.serverside.base.MageTestBase; +import java.io.File; import java.io.FileNotFoundException; +import java.util.*; +import java.util.regex.Matcher; /** * @author ayratn */ public class PlayGameTest extends MageTestBase { + private List handCardsA = new ArrayList(); + private List handCardsB = new ArrayList(); + private List battlefieldCardsA = new ArrayList(); + private List battlefieldCardsB = new ArrayList(); + private List graveyardCardsA = new ArrayList(); + private List graveyardCardsB = new ArrayList(); + private List libraryCardsA = new ArrayList(); + private List libraryCardsB = new ArrayList(); + + private Map commandsA = new HashMap(); + private Map commandsB = new HashMap(); + @Test public void playOneGame() throws GameException, FileNotFoundException, IllegalArgumentException { Game game = new TwoPlayerDuel(Constants.MultiplayerAttackOption.LEFT, Constants.RangeOfInfluence.ALL); - Player player = createPlayer("computer1", "Computer - mad"); + Player computerA = createPlayer("ComputerA", "Computer - mad"); Deck deck = Deck.load(Sets.loadDeck("RB Aggro.dck")); if (deck.getCards().size() < 40) { throw new IllegalArgumentException("Couldn't load deck, deck side=" + deck.getCards().size()); } - game.addPlayer(player, deck); - game.loadCards(deck.getCards(), player.getId()); + game.addPlayer(computerA, deck); + game.loadCards(deck.getCards(), computerA.getId()); - Player player2 = createPlayer("computer2", "Computer - mad"); + Player computerB = createPlayer("ComputerB", "Computer - mad"); Deck deck2 = Deck.load(Sets.loadDeck("RB Aggro.dck")); if (deck2.getCards().size() < 40) { throw new IllegalArgumentException("Couldn't load deck, deck side=" + deck2.getCards().size()); } - game.addPlayer(player2, deck2); - game.loadCards(deck2.getCards(), player2.getId()); + game.addPlayer(computerB, deck2); + game.loadCards(deck2.getCards(), computerB.getId()); + + parseScenario("scenario1.txt"); + game.cheat(computerA.getId(), commandsA); + game.cheat(computerA.getId(), libraryCardsA, handCardsA, battlefieldCardsA, graveyardCardsA); + game.cheat(computerB.getId(), commandsB); + game.cheat(computerB.getId(), libraryCardsB, handCardsB, battlefieldCardsB, graveyardCardsB); long t1 = System.nanoTime(); - game.start(player.getId()); + game.start(computerA.getId(), true); long t2 = System.nanoTime(); logger.info("Winner: " + game.getWinner()); logger.info("Time: " + (t2 - t1) / 1000000 + " ms"); } + private void addCard(List cards, String name, int count) { + for (int i = 0; i < count; i++) { + Card card = Sets.findCard(name, true); + if (card == null) { + throw new IllegalArgumentException("Couldn't find a card for test: " + name); + } + cards.add(card); + } + } + + private void parseScenario(String filename) throws FileNotFoundException { + File f = new File(filename); + Scanner scanner = new Scanner(f); + try { + while (scanner.hasNextLine()) { + String line = scanner.nextLine().trim(); + if (line.startsWith("#")) continue; + Matcher m = pattern.matcher(line); + if (m.matches()) { + + String zone = m.group(1); + String nickname = m.group(2); + + if (nickname.equals("ComputerA") || nickname.equals("ComputerB")) { + List cards; + Constants.Zone gameZone; + if ("hand".equalsIgnoreCase(zone)) { + gameZone = Constants.Zone.HAND; + cards = nickname.equals("ComputerA") ? handCardsA : handCardsB; + } else if ("battlefield".equalsIgnoreCase(zone)) { + gameZone = Constants.Zone.BATTLEFIELD; + cards = nickname.equals("ComputerA") ? battlefieldCardsA : battlefieldCardsB; + } else if ("graveyard".equalsIgnoreCase(zone)) { + gameZone = Constants.Zone.GRAVEYARD; + cards = nickname.equals("ComputerA") ? graveyardCardsA : graveyardCardsB; + } else if ("library".equalsIgnoreCase(zone)) { + gameZone = Constants.Zone.LIBRARY; + cards = nickname.equals("ComputerA") ? libraryCardsA : libraryCardsB; + } else { + continue; // go parse next line + } + + String cardName = m.group(3); + Integer amount = Integer.parseInt(m.group(4)); + + if (cardName.equals("clear")) { + if (nickname.equals("ComputerA")) { + commandsA.put(gameZone, "clear"); + } else { + commandsB.put(gameZone, "clear"); + } + } else { + for (int i = 0; i < amount; i++) { + Card card = Sets.findCard(cardName, true); + if (card != null) { + cards.add(card); + } else { + logger.fatal("Couldn't find a card: " + cardName); + logger.fatal("line: " + line); + } + } + } + } else { + logger.warn("Unknown player: " + nickname); + } + } else { + logger.warn("Init string wasn't parsed: " + line); + } + } + } finally { + scanner.close(); + } + } + private Player createPlayer(String name, String playerType) { return PlayerFactory.getInstance().createPlayer(playerType, name, Constants.RangeOfInfluence.ALL); } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java index 56e319cb6c3..2d4d6f4235f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java @@ -11,28 +11,31 @@ import mage.server.util.PluginClassLoader; import mage.server.util.config.GamePlugin; import mage.server.util.config.Plugin; import mage.util.Copier; -import mage.util.Logging; import org.junit.BeforeClass; import java.io.File; import java.io.FilenameFilter; -import java.util.logging.Level; -import java.util.logging.Logger; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import java.util.regex.Pattern; /** * @author ayratn */ public class MageTestBase { - protected static Logger logger = Logging.getLogger(MageTestBase.class.getName()); + protected static Logger logger = Logger.getLogger(MageTestBase.class); public static PluginClassLoader classLoader = new PluginClassLoader(); private final static String pluginFolder = "plugins"; + protected Pattern pattern = Pattern.compile("([a-zA-Z]*):([\\w]*):([a-zA-Z ,\\-.!'\\d]*):([\\d]*)"); + @BeforeClass public static void init() { + Logger.getRootLogger().setLevel(Level.DEBUG); logger.info("Starting MAGE tests"); - logger.info("Logging level: " + Logging.getLevel(logger)); + logger.info("Logging level: " + logger.getLevel()); deleteSavedGames(); ConfigSettings config = ConfigSettings.getInstance(); for (GamePlugin plugin : config.getGameTypes()) { @@ -56,9 +59,9 @@ public class MageTestBase { logger.info("Loading plugin: " + plugin.getClassName()); return Class.forName(plugin.getClassName(), true, classLoader); } catch (ClassNotFoundException ex) { - logger.log(Level.SEVERE, "Plugin not Found:" + plugin.getJar() + " - check plugin folder"); + logger.warn("Plugin not Found:" + plugin.getJar() + " - check plugin folder"); } catch (Exception ex) { - logger.log(Level.SEVERE, "Error loading plugin " + plugin.getJar(), ex); + logger.fatal("Error loading plugin " + plugin.getJar(), ex); } return null; } @@ -69,9 +72,9 @@ public class MageTestBase { logger.info("Loading game type: " + plugin.getClassName()); return (MatchType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); } catch (ClassNotFoundException ex) { - logger.log(Level.SEVERE, "Game type not found:" + plugin.getJar() + " - check plugin folder"); + logger.warn("Game type not found:" + plugin.getJar() + " - check plugin folder"); } catch (Exception ex) { - logger.log(Level.SEVERE, "Error loading game type " + plugin.getJar(), ex); + logger.fatal("Error loading game type " + plugin.getJar(), ex); } return null; } @@ -82,9 +85,9 @@ public class MageTestBase { logger.info("Loading tournament type: " + plugin.getClassName()); return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); } catch (ClassNotFoundException ex) { - logger.log(Level.SEVERE, "Tournament type not found:" + plugin.getJar() + " - check plugin folder"); + logger.warn("Tournament type not found:" + plugin.getJar() + " - check plugin folder"); } catch (Exception ex) { - logger.log(Level.SEVERE, "Error loading game type " + plugin.getJar(), ex); + logger.fatal("Error loading game type " + plugin.getJar(), ex); } return null; } diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index 50550e934df..b0b18e30d33 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -28,15 +28,14 @@ package mage.game; +import mage.Constants; import mage.game.match.MatchType; import mage.cards.Card; import mage.game.stack.SpellStack; import mage.MageObject; import java.io.Serializable; -import java.util.Collection; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; + import mage.Constants.MultiplayerAttackOption; import mage.Constants.RangeOfInfluence; import mage.Constants.Zone; @@ -61,6 +60,7 @@ import mage.game.permanent.Permanent; import mage.game.turn.Phase; import mage.game.turn.Step; import mage.game.turn.Turn; +import mage.players.Library; import mage.players.Player; import mage.players.PlayerList; import mage.players.Players; @@ -136,8 +136,9 @@ public interface Game extends MageItem, Serializable { public boolean replaceEvent(GameEvent event); //game play methods -// public void init(UUID choosingPlayerId); + //public void init(UUID choosingPlayerId); public void start(UUID choosingPlayerId); + public void start(UUID choosingPlayerId, boolean testMode); public void end(); public void mulligan(UUID playerId); public void quit(UUID playerId); @@ -156,4 +157,7 @@ public interface Game extends MageItem, Serializable { public void restoreState(); public void removeLastBookmark(); + // game cheats (for tests only) + public void cheat(UUID ownerId, Map commands); + public void cheat(UUID ownerId, List library, List hand, List battlefield, List graveyard); } diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index c841c089cee..09a801fe5ce 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -47,11 +47,13 @@ import mage.game.events.*; import mage.game.events.TableEvent.EventType; import mage.game.permanent.Battlefield; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; import mage.game.stack.SpellStack; import mage.game.stack.StackObject; import mage.game.turn.Phase; import mage.game.turn.Step; import mage.game.turn.Turn; +import mage.players.Library; import mage.players.Player; import mage.players.PlayerList; import mage.players.Players; @@ -289,7 +291,12 @@ public abstract class GameImpl> implements Game, Serializa @Override public void start(UUID choosingPlayerId) { - init(choosingPlayerId); + start(choosingPlayerId, false); + } + + @Override + public void start(UUID choosingPlayerId, boolean testMode) { + init(choosingPlayerId, testMode); PlayerList players = state.getPlayerList(startingPlayerId); Player player = getPlayer(players.get()); while (!isGameOver()) { @@ -311,8 +318,12 @@ public abstract class GameImpl> implements Game, Serializa } protected void init(UUID choosingPlayerId) { + init(choosingPlayerId, false); + } + + protected void init(UUID choosingPlayerId, boolean testMode) { for (Player player: state.getPlayers().values()) { - player.init(this); + player.init(this, testMode); } fireInformEvent("game has started"); saveState(); @@ -347,7 +358,9 @@ public abstract class GameImpl> implements Game, Serializa for (UUID playerId: state.getPlayerList(startingPlayerId)) { Player player = getPlayer(playerId); player.setLife(this.getLife(), this); - player.drawCards(7, this); + if (!testMode) { + player.drawCards(7, this); + } } //20091005 - 103.4 @@ -918,4 +931,100 @@ public abstract class GameImpl> implements Game, Serializa public void resetLKI() { lki.clear(); } + + public void cheat(UUID ownerId, Map commands) { + if (commands != null) { + Player player = getPlayer(ownerId); + if (player != null) { + for (Map.Entry command : commands.entrySet()) { + switch (command.getKey()) { + case HAND: + if (command.getValue().equals("clear")) { + removeCards(player.getHand()); + } + break; + case LIBRARY: + if (command.getValue().equals("clear")) { + for (UUID card : player.getLibrary().getCardList()) { + gameCards.remove(card); + } + player.getLibrary().clear(); + } + break; + } + } + } + } + } + + private void removeCards(Cards cards) { + for (UUID card : cards) { + gameCards.remove(card); + } + cards.clear(); + } + + public void cheat(UUID ownerId, List library, List hand, List battlefield, List graveyard) { + Player player = getPlayer(ownerId); + if (player != null) { + loadCards(ownerId, library); + loadCards(ownerId, hand); + loadCards(ownerId, battlefield); + loadCards(ownerId, graveyard); + + for (Card card : library) { + setZone(card.getId(), Zone.LIBRARY); + player.getLibrary().putOnTop(card, this); + } + for (Card card : hand) { + setZone(card.getId(), Zone.HAND); + player.getHand().add(card); + } + for (Card card : graveyard) { + setZone(card.getId(), Zone.GRAVEYARD); + player.getGraveyard().add(card); + } + List permanents = new ArrayList(); + for (Card card : battlefield) { + card.setOwnerId(ownerId); + PermanentCard permanent = new PermanentCard(card, ownerId); + getBattlefield().addPermanent(permanent); + } + applyEffects(); + } + } + + private void loadCards(UUID ownerId, List cards) { + if (cards == null) { + return; + } + Set set = new HashSet(); + for (Card card : cards) { + set.add(card); + } + loadCards(set, ownerId); + } + + public void replaceLibrary(List cardsDownToTop, UUID ownerId) { + Player player = getPlayer(ownerId); + if (player != null) { + for (UUID card : player.getLibrary().getCardList()) { + gameCards.remove(card); + } + player.getLibrary().clear(); + Set cards = new HashSet(); + for (Card card : cardsDownToTop) { + cards.add(card); + } + loadCards(cards, ownerId); + + for (Card card : cards) { + player.getLibrary().putOnTop(card, this); + } + } + } + + public void clearGraveyard(UUID playerId) { + + } } diff --git a/Mage/src/mage/game/Table.java b/Mage/src/mage/game/Table.java index 93bf40f2a4a..8a244c67d69 100644 --- a/Mage/src/mage/game/Table.java +++ b/Mage/src/mage/game/Table.java @@ -84,10 +84,18 @@ public class Table implements Serializable { state = TableState.DUELING; } + public void initTournament() { + state = TableState.DUELING; + } + public void initDraft() { state = TableState.DRAFTING; } + public void construct() { + state = TableState.CONSTRUCTING; + } + public void endGame() { state = TableState.FINISHED; } @@ -157,24 +165,8 @@ public class Table implements Serializable { return this.name; } - public void fireSideboardEvent(UUID playerId, Deck deck) { - tableEventSource.fireTableEvent(EventType.SIDEBOARD, playerId, deck); - } - - public void fireConstructEvent(UUID playerId, Deck deck) { - tableEventSource.fireTableEvent(EventType.CONSTRUCT, playerId, deck); - } - - public void fireSubmitDeckEvent(UUID playerId, Deck deck) { - tableEventSource.fireTableEvent(EventType.SUBMIT_DECK, playerId, deck); - } - public void addTableEventListener(Listener listener) { tableEventSource.addListener(listener); } - public void initTournament() { - state = TableState.CONSTRUCTING; - } - } diff --git a/Mage/src/mage/game/events/TableEvent.java b/Mage/src/mage/game/events/TableEvent.java index 4d17710e19f..aea35cadeb8 100644 --- a/Mage/src/mage/game/events/TableEvent.java +++ b/Mage/src/mage/game/events/TableEvent.java @@ -56,6 +56,7 @@ public class TableEvent extends EventObject implements ExternalEvent, Serializab private Deck deck; private TournamentPairing pair; private MatchOptions options; + private int timeout; public TableEvent(EventType eventType) { super(eventType); @@ -70,11 +71,12 @@ public class TableEvent extends EventObject implements ExternalEvent, Serializab this.eventType = eventType; } - public TableEvent(EventType eventType, UUID playerId, Deck deck) { + public TableEvent(EventType eventType, UUID playerId, Deck deck, int timeout) { super(playerId); this.playerId = playerId; this.deck = deck; this.eventType = eventType; + this.timeout = timeout; } public TableEvent(EventType eventType, String message, Draft draft) { @@ -126,4 +128,8 @@ public class TableEvent extends EventObject implements ExternalEvent, Serializab public MatchOptions getMatchOptions() { return options; } + + public int getTimeout() { + return timeout; + } } diff --git a/Mage/src/mage/game/events/TableEventSource.java b/Mage/src/mage/game/events/TableEventSource.java index acd66a3184a..bfb1bf00010 100644 --- a/Mage/src/mage/game/events/TableEventSource.java +++ b/Mage/src/mage/game/events/TableEventSource.java @@ -67,8 +67,8 @@ public class TableEventSource implements EventSource, Serializable { dispatcher.fireEvent(new TableEvent(eventType, message, cards, game)); } - public void fireTableEvent(EventType eventType, UUID playerId, Deck deck) { - dispatcher.fireEvent(new TableEvent(eventType, playerId, deck)); + public void fireTableEvent(EventType eventType, UUID playerId, Deck deck, int timeout) { + dispatcher.fireEvent(new TableEvent(eventType, playerId, deck, timeout)); } public void fireTableEvent(EventType eventType, TournamentPairing pair, MatchOptions options) { diff --git a/Mage/src/mage/game/match/Match.java b/Mage/src/mage/game/match/Match.java index 032edac9ea2..64ae80b3439 100644 --- a/Mage/src/mage/game/match/Match.java +++ b/Mage/src/mage/game/match/Match.java @@ -33,6 +33,8 @@ import java.util.UUID; import mage.cards.decks.Deck; import mage.game.Game; import mage.game.GameException; +import mage.game.events.Listener; +import mage.game.events.TableEvent; import mage.players.Player; /** @@ -46,8 +48,10 @@ public interface Match { public List getPlayers(); public MatchPlayer getPlayer(UUID playerId); public void addPlayer(Player player, Deck deck); + public void submitDeck(UUID playerId, Deck deck); public void startMatch() throws GameException; public void startGame() throws GameException; + public void sideboard(); public void endGame(); public Game getGame(); public List getGames(); @@ -56,4 +60,7 @@ public interface Match { public boolean isDoneSideboarding(); public UUID getChooser(); + public void addTableEventListener(Listener listener); + public void fireSideboardEvent(UUID playerId, Deck deck); + } diff --git a/Mage/src/mage/game/match/MatchImpl.java b/Mage/src/mage/game/match/MatchImpl.java index 01c3988e481..c6b5370a78f 100644 --- a/Mage/src/mage/game/match/MatchImpl.java +++ b/Mage/src/mage/game/match/MatchImpl.java @@ -35,6 +35,10 @@ import java.util.logging.Logger; import mage.cards.decks.Deck; import mage.game.Game; import mage.game.GameException; +import mage.game.events.Listener; +import mage.game.events.TableEvent; +import mage.game.events.TableEvent.EventType; +import mage.game.events.TableEventSource; import mage.players.Player; import mage.util.Logging; @@ -45,11 +49,14 @@ import mage.util.Logging; public abstract class MatchImpl implements Match { private final static Logger logger = Logging.getLogger(MatchImpl.class.getName()); + private static final int SIDEBOARD_TIME = 180; protected UUID id = UUID.randomUUID(); protected List players = new ArrayList(); protected List games = new ArrayList(); protected MatchOptions options; + + protected TableEventSource tableEventSource = new TableEventSource(); public MatchImpl(MatchOptions options) { this.options = options; @@ -151,6 +158,26 @@ public abstract class MatchImpl implements Match { return loserId; } + @Override + public void addTableEventListener(Listener listener) { + tableEventSource.addListener(listener); + } + + @Override + public void sideboard() { + for (MatchPlayer player: this.players) { + player.setSideboarding(); + player.getPlayer().sideboard(this, player.getDeck()); + } + synchronized(this) { + while (!isDoneSideboarding()) { + try { + this.wait(); + } catch (InterruptedException ex) { } + } + } + } + @Override public boolean isDoneSideboarding() { for (MatchPlayer player: this.players) { @@ -160,4 +187,23 @@ public abstract class MatchImpl implements Match { return true; } + @Override + public void fireSideboardEvent(UUID playerId, Deck deck) { + MatchPlayer player = getPlayer(playerId); + if (player != null) { + tableEventSource.fireTableEvent(EventType.SIDEBOARD, playerId, deck, SIDEBOARD_TIME); + } + } + + @Override + public void submitDeck(UUID playerId, Deck deck) { + MatchPlayer player = getPlayer(playerId); + if (player != null) { + player.submitDeck(deck); + } + synchronized (this) { + this.notifyAll(); + } + } + } diff --git a/Mage/src/mage/game/tournament/TournamentImpl.java b/Mage/src/mage/game/tournament/TournamentImpl.java index 979d247627c..fd75633b11b 100644 --- a/Mage/src/mage/game/tournament/TournamentImpl.java +++ b/Mage/src/mage/game/tournament/TournamentImpl.java @@ -41,6 +41,7 @@ import java.util.logging.Logger; import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.decks.Deck; +import mage.game.Table; import mage.game.events.Listener; import mage.game.events.PlayerQueryEvent; import mage.game.events.PlayerQueryEventSource; @@ -63,8 +64,10 @@ public abstract class TournamentImpl implements Tournament { protected String matchName; protected TournamentOptions options; - protected transient TableEventSource tableEventSource = new TableEventSource(); - protected transient PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource(); + protected TableEventSource tableEventSource = new TableEventSource(); + protected PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource(); + + private static final int CONSTRUCT_TIME = 600; public TournamentImpl(TournamentOptions options) { this.options = options; @@ -209,7 +212,7 @@ public abstract class TournamentImpl implements Tournament { @Override public void fireSubmitDeckEvent(UUID playerId, Deck deck) { - tableEventSource.fireTableEvent(EventType.SUBMIT_DECK, playerId, deck); + tableEventSource.fireTableEvent(EventType.SUBMIT_DECK, playerId, deck, 0); } @Override @@ -220,10 +223,11 @@ public abstract class TournamentImpl implements Tournament { @Override public void fireConstructEvent(UUID playerId, Deck deck) { TournamentPlayer player = players.get(playerId); - playerQueryEventSource.construct(playerId, "Construct", deck, 600); + playerQueryEventSource.construct(playerId, "Construct", deck, CONSTRUCT_TIME); } public void construct() { + tableEventSource.fireTableEvent(EventType.CONSTRUCT); for (TournamentPlayer player: players.values()) { player.setConstructing(); player.getPlayer().construct(this, player.getDeck()); diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index 850752feac0..a3fe979ca7c 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -56,6 +56,7 @@ import mage.game.events.GameEvent; import mage.game.Game; import mage.game.Table; import mage.game.draft.Draft; +import mage.game.match.Match; import mage.game.permanent.Permanent; import mage.game.tournament.Tournament; import mage.target.Target; @@ -96,6 +97,7 @@ public interface Player extends MageItem, Copyable { public Set getInRange(); public void init(Game game); + public void init(Game game, boolean testMode); public void useDeck(Deck deck, Game game); public void reset(); public void shuffleLibrary(Game game); @@ -154,7 +156,7 @@ public interface Player extends MageItem, Copyable { public abstract void selectBlockers(Game game); public abstract void assignDamage(int damage, List targets, UUID sourceId, Game game); public abstract int getAmount(int min, int max, String message, Game game); - public abstract void sideboard(Table table, Deck deck); + public abstract void sideboard(Match match, Deck deck); public abstract void construct(Tournament tournament, Deck deck); public abstract void pickCard(List cards, Deck deck, Draft draft); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 48d1152861b..f1b12a0adb3 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -152,9 +152,16 @@ public abstract class PlayerImpl> implements Player, Ser @Override public void init(Game game) { + init(game, false); + } + + @Override + public void init(Game game, boolean testMode) { this.abort = false; - this.hand.clear(); - this.graveyard.clear(); + if (!testMode) { + this.hand.clear(); + this.graveyard.clear(); + } this.abilities.clear(); this.wins = false; this.loses = false; diff --git a/Mage/src/mage/target/common/TargetCreatureOrPlayer.java b/Mage/src/mage/target/common/TargetCreatureOrPlayer.java index 3a126ff9138..3be19022111 100644 --- a/Mage/src/mage/target/common/TargetCreatureOrPlayer.java +++ b/Mage/src/mage/target/common/TargetCreatureOrPlayer.java @@ -90,13 +90,18 @@ public class TargetCreatureOrPlayer extends TargetImpl { @Override public boolean canTarget(UUID id, Ability source, Game game) { + return canTarget(null, id, source, game); + } + + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { Permanent permanent = game.getPermanent(id); MageObject targetSource = game.getObject(source.getSourceId()); if (permanent != null) { if (source != null) - return permanent.canBeTargetedBy(targetSource) && filter.match(permanent, source.getControllerId(), game); + //TODO: check for replacement effects + return permanent.canBeTargetedBy(game.getObject(source.getSourceId())) && filter.match(permanent, controllerId, game); else - return filter.match(permanent); + return filter.match(permanent, controllerId, game); } Player player = game.getPlayer(id); if (player != null)