From a373047c58ad7690d83e32db4a1f4200bd7fbe38 Mon Sep 17 00:00:00 2001 From: magenoxx Date: Wed, 19 Jun 2013 15:14:21 +0400 Subject: [PATCH 1/2] Fix for error: unmappable character for encoding Cp1251 --- .../mage/sets/scarsofmirrodin/KothOfTheHammer.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/KothOfTheHammer.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/KothOfTheHammer.java index 16d2ed2d2f..1192ed8a0b 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/KothOfTheHammer.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/KothOfTheHammer.java @@ -28,12 +28,6 @@ package mage.sets.scarsofmirrodin; -import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.*; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; @@ -51,6 +45,7 @@ import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continious.BecomesCreatureTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -62,6 +57,8 @@ import mage.game.permanent.token.Token; import mage.target.common.TargetCreatureOrPlayer; import mage.target.common.TargetLandPermanent; +import java.util.UUID; + /** * * @author Loki, North @@ -95,7 +92,7 @@ public class KothOfTheHammer extends CardImpl { // -2: Add {R} to your mana pool for each Mountain you control. this.addAbility(new LoyaltyAbility(new DynamicManaEffect(Mana.RedMana, new PermanentsOnBattlefieldCount(filterCount)), -2)); - // -5: You get an emblem with "Mountains you control have ‘{T}: This land deals 1 damage to target creature or player.' + // -5: You get an emblem with "Mountains you control have '{T}: This land deals 1 damage to target creature or player.' this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new KothOfTheHammerEmblem()), -5)); } From 42dd9d81b493071ec10907bebe0b1c37760e9530 Mon Sep 17 00:00:00 2001 From: magenoxx Date: Wed, 19 Jun 2013 17:12:31 +0400 Subject: [PATCH 2/2] Timers (In progress) --- .../mage/client/components/HoverButton.java | 29 +++++ .../java/mage/client/game/PlayerPanelExt.java | 7 ++ Mage.Common/src/mage/view/PlayerView.java | 6 + .../src/mage/player/human/HumanPlayer.java | 80 +++++++------- .../java/mage/server/game/GameController.java | 60 +++++++++- .../mage/server/game/timer/PriorityTimer.java | 103 ++++++++++++++++++ Mage/src/mage/game/Game.java | 13 ++- Mage/src/mage/game/GameImpl.java | 22 +++- Mage/src/mage/game/events/TableEvent.java | 3 +- Mage/src/mage/players/Player.java | 14 +++ Mage/src/mage/players/PlayerImpl.java | 23 ++-- 11 files changed, 302 insertions(+), 58 deletions(-) create mode 100644 Mage.Server/src/main/java/mage/server/game/timer/PriorityTimer.java diff --git a/Mage.Client/src/main/java/mage/client/components/HoverButton.java b/Mage.Client/src/main/java/mage/client/components/HoverButton.java index 4d78bbc3c1..fc8ac09de2 100644 --- a/Mage.Client/src/main/java/mage/client/components/HoverButton.java +++ b/Mage.Client/src/main/java/mage/client/components/HoverButton.java @@ -26,8 +26,11 @@ public class HoverButton extends JPanel implements MouseListener { private int textOffsetY = 0; private int textOffsetButtonY = 2; private int textOffsetX = -1; + private int topTextOffsetX = -1; private Dimension overlayImageSize; + private String topText; + private boolean isHovered = false; private boolean isSelected = false; private boolean drawSet = false; @@ -36,6 +39,7 @@ public class HoverButton extends JPanel implements MouseListener { private Command observer = null; private Command onHover = null; private Color textColor = Color.white; + private Color textBGColor = Color.black; static final Font textFont = new Font("Arial", Font.PLAIN, 12); static final Font textFontMini = new Font("Arial", Font.PLAIN, 11); @@ -100,6 +104,18 @@ public class HoverButton extends JPanel implements MouseListener { } else { g.drawImage(disabledImage, 0, 0, imageSize.width, imageSize.height, this); } + if (topText != null) { + if (useMiniFont) { + g2d.setFont(textFontMini); + } else { + g2d.setFont(textFont); + } + topTextOffsetX = calculateOffsetForTop(g2d, topText); + g2d.setColor(textBGColor); + g2d.drawString(topText, topTextOffsetX+1, 13); + g2d.setColor(textColor); + g2d.drawString(topText, topTextOffsetX, 12); + } if (overlayImage != null) { g.drawImage(overlayImage, (imageSize.width - overlayImageSize.width) / 2, 10, this); } else if (set != null) { @@ -136,6 +152,15 @@ public class HoverButton extends JPanel implements MouseListener { return textOffsetX; } + private int calculateOffsetForTop(Graphics2D g2d, String text) { + if (topTextOffsetX == -1) { // calculate once + FontRenderContext frc = g2d.getFontRenderContext(); + int textWidth = (int) textFont.getStringBounds(text, frc).getWidth(); + topTextOffsetX = (imageSize.width - textWidth) / 2; + } + return topTextOffsetX; + } + public void setTextColor(Color textColor) { this.textColor = textColor; } @@ -242,4 +267,8 @@ public class HoverButton extends JPanel implements MouseListener { observer.execute(); } } + + public void setTopText(String topText) { + this.topText = topText; + } } diff --git a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java index 24d97a1b96..a67210205d 100644 --- a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java +++ b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java @@ -182,6 +182,8 @@ public class PlayerPanelExt extends javax.swing.JPanel { } } this.avatar.setText(player.getName()); + String priorityTimeValue = getPriorityTimeLeftString(player); + this.avatar.setTopText(priorityTimeValue); this.btnPlayer.setText(player.getName()); if (player.isActive()) { this.avatar.setBorder(greenBorder); @@ -216,6 +218,11 @@ public class PlayerPanelExt extends javax.swing.JPanel { update(player.getManaPool()); } + private String getPriorityTimeLeftString(PlayerView player) { + int priorityTimeLeft = player.getPriorityTimeLeft(); + return priorityTimeLeft / 3600 + ":" + (priorityTimeLeft % 3600) / 60 + ":" + priorityTimeLeft % 60; + } + protected void update(ManaPoolView pool) { manaLabels.get("B").setText(Integer.toString(pool.getBlack())); manaLabels.get("R").setText(Integer.toString(pool.getRed())); diff --git a/Mage.Common/src/mage/view/PlayerView.java b/Mage.Common/src/mage/view/PlayerView.java index a7cad2dfda..f0e46419ea 100644 --- a/Mage.Common/src/mage/view/PlayerView.java +++ b/Mage.Common/src/mage/view/PlayerView.java @@ -63,6 +63,7 @@ public class PlayerView implements Serializable { private List emblemList = new ArrayList(); private List attachments = new ArrayList(); private int statesSavedSize; + private int priorityTimeLeft; public PlayerView(Player player, GameState state, Game game) { this.playerId = player.getId(); @@ -108,6 +109,7 @@ public class PlayerView implements Serializable { } this.statesSavedSize = player.getStoredBookmark(); + this.priorityTimeLeft = player.getPriorityTimeLeft(); } private boolean showInBattlefield(Permanent permanent, GameState state) { @@ -191,4 +193,8 @@ public class PlayerView implements Serializable { public int getStatesSavedSize() { return statesSavedSize; } + + public int getPriorityTimeLeft() { + return priorityTimeLeft; + } } 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 79165bf6b9..ce64108b87 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 @@ -28,11 +28,6 @@ package mage.player.human; -import java.io.Serializable; -import java.util.*; -import mage.constants.Outcome; -import mage.constants.RangeOfInfluence; -import mage.constants.Zone; import mage.MageObject; import mage.abilities.*; import mage.abilities.costs.common.SacrificeSourceCost; @@ -46,6 +41,9 @@ import mage.cards.Cards; import mage.cards.decks.Deck; import mage.choices.Choice; import mage.choices.ChoiceImpl; +import mage.constants.Outcome; +import mage.constants.RangeOfInfluence; +import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterBlockingCreature; import mage.filter.common.FilterCreatureForCombat; @@ -67,6 +65,9 @@ import mage.target.common.TargetDefender; import mage.util.ManaUtil; import org.apache.log4j.Logger; +import java.io.Serializable; +import java.util.*; + /** * @@ -98,40 +99,43 @@ public class HumanPlayer extends PlayerImpl { super(player); } - protected void waitForResponse() { + protected void waitForResponse(Game game) { response.clear(); log.debug("Waiting response from player: " + getId()); + game.resumeTimer(playerId); synchronized(response) { try { response.wait(); log.debug("Got response from player: " + getId()); } catch (InterruptedException ex) { ex.printStackTrace(); + } finally { + game.pauseTimer(playerId); } } } - protected void waitForBooleanResponse() { + protected void waitForBooleanResponse(Game game) { do { - waitForResponse(); + waitForResponse(game); } while (response.getBoolean() == null && !abort); } - protected void waitForUUIDResponse() { + protected void waitForUUIDResponse(Game game) { do { - waitForResponse(); + waitForResponse(game); } while (response.getUUID() == null && !abort); } - protected void waitForStringResponse() { + protected void waitForStringResponse(Game game) { do { - waitForResponse(); + waitForResponse(game); } while (response.getString() == null && !abort); } - protected void waitForIntegerResponse() { + protected void waitForIntegerResponse(Game game) { do { - waitForResponse(); + waitForResponse(game); } while (response.getInteger() == null && !abort); } @@ -143,7 +147,7 @@ public class HumanPlayer extends PlayerImpl { .append(getHand().size() > nextHandSize?"down to ":"for free, draw ") .append(nextHandSize) .append(nextHandSize == 1?" card?":" cards?").toString()); - waitForBooleanResponse(); + waitForBooleanResponse(game); if (!abort) { return response.getBoolean(); } @@ -154,7 +158,7 @@ public class HumanPlayer extends PlayerImpl { public boolean chooseUse(Outcome outcome, String message, Game game) { updateGameStatePriority("chooseUse", game); game.fireAskPlayerEvent(playerId, message); - waitForBooleanResponse(); + waitForBooleanResponse(game); if (!abort) { return response.getBoolean(); } @@ -175,7 +179,7 @@ public class HumanPlayer extends PlayerImpl { } while (!abort) { game.fireChooseEvent(playerId, replacementEffectChoice); - waitForResponse(); + waitForResponse(game); log.debug("Choose effect: " + response.getString()); if (response.getString() != null) { replacementEffectChoice.setChoice(response.getString()); @@ -196,7 +200,7 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("choose(3)", game); while (!abort) { game.fireChooseEvent(playerId, choice); - waitForResponse(); + waitForResponse(game); if (response.getString() != null) { choice.setChoice(response.getString()); return true; @@ -218,7 +222,7 @@ public class HumanPlayer extends PlayerImpl { while (!abort) { Set cards = target.possibleTargets(null, playerId, game); game.fireSelectTargetEvent(playerId, target.getMessage(), cards, target.isRequired(), options); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { if (target instanceof TargetPermanent) { if (((TargetPermanent)target).canTarget(playerId, response.getUUID(), sourceId, game, false)) { @@ -267,7 +271,7 @@ public class HumanPlayer extends PlayerImpl { Set possibleTargets = target.possibleTargets(source==null?null:source.getSourceId(), playerId, game); boolean required = possibleTargets.isEmpty() ? false : target.isRequired(); game.fireSelectTargetEvent(playerId, target.getMessage(), possibleTargets, required, getOptions(target)); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { if (possibleTargets.contains(response.getUUID())) { if (target instanceof TargetPermanent) { @@ -323,7 +327,7 @@ public class HumanPlayer extends PlayerImpl { options.put("chosen", (Serializable)chosen); } game.fireSelectTargetEvent(playerId, target.getMessage(), cards, required, options); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { if (target.canTarget(response.getUUID(), cards, game)) { target.add(response.getUUID(), game); @@ -358,7 +362,7 @@ public class HumanPlayer extends PlayerImpl { } } game.fireSelectTargetEvent(playerId, target.getMessage(), cards, target.isRequired(), null); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { if (target.canTarget(response.getUUID(), cards, game)) { target.addTarget(response.getUUID(), source, game); @@ -383,7 +387,7 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("chooseTargetAmount", game); while (!abort) { game.fireSelectTargetEvent(playerId, target.getMessage() + "\n Amount remaining:" + target.getAmountRemaining(), target.possibleTargets(source==null?null:source.getId(), playerId, game), target.isRequired(), null); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { if (target.canTarget(response.getUUID(), source, game)) { UUID targetId = response.getUUID(); @@ -412,7 +416,7 @@ public class HumanPlayer extends PlayerImpl { } updateGameStatePriority("priority", game); game.firePriorityEvent(playerId); - waitForResponse(); + waitForResponse(game); if (response.getBoolean() != null) { pass(game); return false; @@ -450,7 +454,7 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("chooseTriggeredAbility", game); while (!abort) { game.fireSelectTargetEvent(playerId, "Pick triggered ability (goes to the stack first)", abilities); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { for (TriggeredAbility ability: abilities) { if (ability.getId().equals(response.getUUID())) { @@ -466,7 +470,7 @@ public class HumanPlayer extends PlayerImpl { public boolean playMana(ManaCost unpaid, Game game) { updateGameStatePriority("playMana", game); game.firePlayManaEvent(playerId, "Pay " + unpaid.getText()); - waitForResponse(); + waitForResponse(game); if (response.getBoolean() != null) { return false; } else if (response.getUUID() != null) { @@ -500,7 +504,7 @@ public class HumanPlayer extends PlayerImpl { public int announceXMana(int min, int max, String message, Game game, Ability ability) { updateGameStatePriority("announceXMana", game); game.fireGetAmountEvent(playerId, message, min, max); - waitForIntegerResponse(); + waitForIntegerResponse(game); return response.getInteger(); } @@ -530,7 +534,7 @@ public class HumanPlayer extends PlayerImpl { return; } game.fireSelectEvent(playerId, "Select attackers"); - waitForResponse(); + waitForResponse(game); if (response.getBoolean() != null) { return; } else if (response.getInteger() != null) { @@ -593,7 +597,7 @@ public class HumanPlayer extends PlayerImpl { filter.add(new ControllerIdPredicate(defendingPlayerId)); while (!abort) { game.fireSelectEvent(playerId, "Select blockers"); - waitForResponse(); + waitForResponse(game); if (response.getBoolean() != null) { return; } else if (response.getInteger() != null) { @@ -622,7 +626,7 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("chooseAttackerOrder", game); while (!abort) { game.fireSelectTargetEvent(playerId, "Pick attacker", attackers, true); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { for (Permanent perm: attackers) { if (perm.getId().equals(response.getUUID())) { @@ -640,7 +644,7 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("chooseBlockerOrder", game); while (!abort) { game.fireSelectTargetEvent(playerId, "Pick blocker", blockers, true); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { for (Permanent perm: blockers) { if (perm.getId().equals(response.getUUID())) { @@ -656,7 +660,7 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("selectCombatGroup", game); TargetAttackingCreature target = new TargetAttackingCreature(); game.fireSelectTargetEvent(playerId, "Select attacker to block", target.possibleTargets(null, playerId, game), target.isRequired(), null); - waitForResponse(); + waitForResponse(game); if (response.getBoolean() != null) { // do nothing } else if (response.getUUID() != null) { @@ -696,7 +700,7 @@ public class HumanPlayer extends PlayerImpl { public int getAmount(int min, int max, String message, Game game) { updateGameStatePriority("getAmount", game); game.fireGetAmountEvent(playerId, message, min, max); - waitForIntegerResponse(); + waitForIntegerResponse(game); return response.getInteger(); } @@ -719,7 +723,7 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("specialAction", game); LinkedHashMap specialActions = game.getState().getSpecialActions().getControlledBy(playerId); game.fireGetChoiceEvent(playerId, name, new ArrayList(specialActions.values())); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { if (specialActions.containsKey(response.getUUID())) { activateAbility(specialActions.get(response.getUUID()), game); @@ -737,7 +741,7 @@ public class HumanPlayer extends PlayerImpl { } } game.fireGetChoiceEvent(playerId, name, new ArrayList(abilities.values())); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { if (abilities.containsKey(response.getUUID())) { activateAbility(abilities.get(response.getUUID()), game); @@ -757,7 +761,7 @@ public class HumanPlayer extends PlayerImpl { return (SpellAbility) useableAbilities.values().iterator().next(); } else if (useableAbilities != null && useableAbilities.size() > 0) { game.fireGetChoiceEvent(playerId, name, new ArrayList(useableAbilities.values())); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { if (useableAbilities.containsKey(response.getUUID())) { return (SpellAbility) useableAbilities.get(response.getUUID()); @@ -785,7 +789,7 @@ public class HumanPlayer extends PlayerImpl { modeMap.put(mode.getId(), modeText); } game.fireGetModeEvent(playerId, "Choose Mode", modeMap); - waitForResponse(); + waitForResponse(game); if (response.getUUID() != null) { for (Mode mode: modes.values()) { if (mode.getId().equals(response.getUUID())) { @@ -802,7 +806,7 @@ public class HumanPlayer extends PlayerImpl { public boolean choosePile(Outcome outcome, String message, List pile1, List pile2, Game game) { updateGameStatePriority("choosePile", game); game.fireChoosePileEvent(playerId, message, pile1, pile2); - waitForBooleanResponse(); + waitForBooleanResponse(game); if (!abort) { return response.getBoolean(); } diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index bd8c491074..cc0e26fedb 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -28,7 +28,6 @@ package mage.server.game; -import mage.constants.Zone; import mage.MageException; import mage.abilities.Ability; import mage.cards.Card; @@ -37,6 +36,7 @@ import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; +import mage.constants.Zone; import mage.game.Game; import mage.game.GameException; import mage.game.events.Listener; @@ -45,14 +45,12 @@ import mage.game.events.TableEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.server.*; +import mage.server.game.timer.PriorityTimer; import mage.server.util.Splitter; import mage.server.util.SystemUtil; import mage.server.util.ThreadExecutor; -import mage.view.AbilityPickerView; -import mage.view.CardsView; +import mage.view.*; import mage.view.ChatMessage.MessageColor; -import mage.view.GameView; -import mage.view.PermanentView; import org.apache.log4j.Logger; import java.io.*; @@ -75,6 +73,13 @@ public class GameController implements GameCallback { private ConcurrentHashMap gameSessions = new ConcurrentHashMap(); private ConcurrentHashMap watchers = new ConcurrentHashMap(); + private ConcurrentHashMap timers = new ConcurrentHashMap(); + + /** + * Time each player has during the game to play using his\her priority. + */ + private static final int PRIORITY_TIME_SEC = 62; + private ConcurrentHashMap userPlayerMap; private UUID gameSessionId; private Game game; @@ -106,6 +111,8 @@ public class GameController implements GameCallback { @Override public void event(TableEvent event) { try { + PriorityTimer timer; + UUID playerId; switch (event.getEventType()) { case UPDATE: updateGame(); @@ -124,6 +131,43 @@ public class GameController implements GameCallback { case ERROR: error(event.getMessage(), event.getException()); break; + case INIT_TIMER: + final UUID initPlayerId = event.getPlayerId(); + if (initPlayerId == null) { + throw new IllegalStateException("INIT_TIMER: playerId can't be null"); + } + long delay = 250L; // run each 250 ms + timer = new PriorityTimer(PRIORITY_TIME_SEC, delay, new Runnable() { + public void run() { + game.concede(initPlayerId); + logger.info("Game timeout for player: " + initPlayerId + ". Conceding."); + } + }); + timers.put(initPlayerId, timer); + timer.init(); + break; + case RESUME_TIMER: + playerId = event.getPlayerId(); + if (playerId == null) { + throw new IllegalStateException("RESUME_TIMER: playerId can't be null"); + } + timer = timers.get(playerId); + if (timer == null) { + throw new IllegalStateException("RESUME_TIMER: couldn't find timer for player: " + playerId); + } + timer.resume(); + break; + case PAUSE_TIMER: + playerId = event.getPlayerId(); + if (playerId == null) { + throw new IllegalStateException("PAUSE_TIMER: playerId can't be null"); + } + timer = timers.get(playerId); + if (timer == null) { + throw new IllegalStateException("PAUSE_TIMER: couldn't find timer for player: " + playerId); + } + timer.pause(); + break; } } catch (MageException ex) { logger.fatal("Table event listener error ", ex); @@ -388,6 +432,12 @@ public class GameController implements GameCallback { } private synchronized void updateGame() { + for (Player player: game.getState().getPlayers().values()) { + PriorityTimer timer = timers.get(player.getId()); + if (timer != null) { + player.setPriorityTimeLeft(timer.getCount()); + } + } for (final GameSession gameSession: gameSessions.values()) { gameSession.update(); } diff --git a/Mage.Server/src/main/java/mage/server/game/timer/PriorityTimer.java b/Mage.Server/src/main/java/mage/server/game/timer/PriorityTimer.java new file mode 100644 index 0000000000..7398e74ab0 --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/game/timer/PriorityTimer.java @@ -0,0 +1,103 @@ +package mage.server.game.timer; + +import org.apache.log4j.Logger; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * @author noxx + */ +public class PriorityTimer extends TimerTask { + + private static final Logger logger = Logger.getLogger(PriorityTimer.class); + + private int count; + + private long delay; + + private Runnable taskOnTimeout; + + private States state = States.NONE; + + enum States { + NONE, + INIT, + RUNNING, + PAUSED, + FINISHED + } + + public PriorityTimer(int count, long delay, Runnable taskOnTimeout) { + this.count = count; + this.delay = delay; + this.taskOnTimeout = taskOnTimeout; + } + + public void init() { + state = States.INIT; + Timer timer = new Timer("Priority Timer", false); + long delayMs = delay * (int) (1000L / delay); + timer.scheduleAtFixedRate(this, delayMs, delayMs); + } + + public void start() { + if (state == States.NONE) { + throw new IllegalStateException("Timer should have been initialized first"); + } + if (state == States.FINISHED) { + throw new IllegalStateException("Timer has already finished its work"); + } + state = States.RUNNING; + } + + public void pause() { + state = States.PAUSED; + } + + public void stop() { + state = States.FINISHED; + count = 0; + } + + public void resume() { + if (state == States.FINISHED) { + throw new IllegalStateException("Timer has already finished its work"); + } + state = States.RUNNING; + } + + public int getCount() { + return count; + } + + @Override + public void run() { + if (state == States.RUNNING) { + count--; + } + if (logger.isDebugEnabled()) logger.debug("Count is: " + count); + //System.out.println("Count is: " + count); + if (count <= 0) { + cancel(); + taskOnTimeout.run(); + } + } + + public static void main(String[] args) throws Exception { + long delay = 250L; + int count = 5; + PriorityTimer timer = new PriorityTimer(count, delay, new Runnable() { + public void run() { + System.out.println("Exit"); + System.exit(0); + } + }); + timer.init(); + timer.start(); + Thread.sleep(2000); + timer.pause(); + Thread.sleep(3000); + timer.resume(); + } +} diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index c4f2b06bd8..df3a256a24 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -28,9 +28,6 @@ package mage.game; -import mage.constants.MultiplayerAttackOption; -import mage.constants.RangeOfInfluence; -import mage.constants.Zone; import mage.MageItem; import mage.MageObject; import mage.abilities.Ability; @@ -44,6 +41,10 @@ import mage.cards.Card; import mage.cards.Cards; import mage.cards.decks.Deck; import mage.choices.Choice; +import mage.constants.Duration; +import mage.constants.MultiplayerAttackOption; +import mage.constants.RangeOfInfluence; +import mage.constants.Zone; import mage.game.combat.Combat; import mage.game.command.Emblem; import mage.game.events.GameEvent; @@ -65,7 +66,6 @@ import mage.util.functions.ApplyToPermanent; import java.io.Serializable; import java.util.*; -import mage.constants.Duration; public interface Game extends MageItem, Serializable { @@ -225,4 +225,9 @@ public interface Game extends MageItem, Serializable { // controlling the behaviour of replacement effects void setScopeRelevant(boolean scopeRelevant); public boolean getScopeRelevant(); + + // players' timers + void initTimer(UUID playerId); + void resumeTimer(UUID playerId); + void pauseTimer(UUID playerId); } diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index f7fa2fc975..1212595fe4 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -29,7 +29,6 @@ package mage.game; import mage.Constants; -import mage.constants.CardType; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; @@ -49,12 +48,14 @@ import mage.actions.impl.MageAction; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.cards.SplitCard; import mage.cards.decks.Deck; import mage.choices.Choice; import mage.constants.*; import mage.counters.CounterType; import mage.filter.Filter; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterPlaneswalkerPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.NamePredicate; @@ -89,8 +90,6 @@ import java.io.IOException; import java.io.Serializable; import java.util.*; import java.util.Map.Entry; -import mage.cards.SplitCard; -import mage.filter.common.FilterControlledCreaturePermanent; public abstract class GameImpl> implements Game, Serializable { @@ -590,6 +589,7 @@ public abstract class GameImpl> implements Game, Serializa protected void init(UUID choosingPlayerId, GameOptions gameOptions) { for (Player player: state.getPlayers().values()) { player.beginTurn(this); + initTimer(player.getId()); } if (startMessage == null || startMessage.isEmpty()) { startMessage = "Game has started"; @@ -1946,4 +1946,20 @@ public abstract class GameImpl> implements Game, Serializa public void setStartMessage(String startMessage) { this.startMessage = startMessage; } + + @Override + public void initTimer(UUID playerId) { + tableEventSource.fireTableEvent(EventType.INIT_TIMER, playerId, null, this); + } + + @Override + public void resumeTimer(UUID playerId) { + tableEventSource.fireTableEvent(EventType.RESUME_TIMER, playerId, null, this); + } + + @Override + public void pauseTimer(UUID playerId) { + tableEventSource.fireTableEvent(EventType.PAUSE_TIMER, playerId, null, this); + } + } diff --git a/Mage/src/mage/game/events/TableEvent.java b/Mage/src/mage/game/events/TableEvent.java index b9c9041cea..6d6637b422 100644 --- a/Mage/src/mage/game/events/TableEvent.java +++ b/Mage/src/mage/game/events/TableEvent.java @@ -46,7 +46,8 @@ import java.util.UUID; public class TableEvent extends EventObject implements ExternalEvent, Serializable { public enum EventType { - UPDATE, INFO, STATUS, REVEAL, LOOK, START_DRAFT, START_MATCH, SIDEBOARD, CONSTRUCT, SUBMIT_DECK, END, ERROR + UPDATE, INFO, STATUS, REVEAL, LOOK, START_DRAFT, START_MATCH, SIDEBOARD, CONSTRUCT, SUBMIT_DECK, END, ERROR, + INIT_TIMER, RESUME_TIMER, PAUSE_TIMER } private Game game; diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index b755ad8cc6..4513492675 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -299,4 +299,18 @@ public interface Player extends MageItem, Copyable { * */ void revealFaceDownCard(Card card, Game game); + + /** + * Set seconds left to play the game. + * + * @return + */ + void setPriorityTimeLeft(int timeLeft); + + /** + * Returns seconds left to play the game. + * + * @return + */ + int getPriorityTimeLeft(); } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 9ba6065ec4..ded8742beb 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -28,8 +28,6 @@ package mage.players; -import mage.constants.*; -import mage.constants.Zone; import mage.MageObject; import mage.Mana; import mage.abilities.*; @@ -46,10 +44,13 @@ import mage.actions.MageDrawAction; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.cards.SplitCard; import mage.cards.decks.Deck; +import mage.constants.*; import mage.counters.Counter; import mage.counters.CounterType; import mage.counters.Counters; +import mage.filter.FilterCard; import mage.filter.common.FilterCreatureForCombat; import mage.game.ExileZone; import mage.game.Game; @@ -59,11 +60,13 @@ import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; +import mage.game.stack.Spell; import mage.game.stack.StackAbility; import mage.game.stack.StackObject; import mage.players.net.UserData; import mage.target.Target; import mage.target.TargetAmount; +import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetDiscard; import mage.watchers.common.BloodthirstWatcher; @@ -72,11 +75,6 @@ import org.apache.log4j.Logger; import java.io.Serializable; import java.util.*; -import mage.cards.SplitCard; -import mage.filter.FilterCard; -import mage.game.stack.Spell; -import mage.target.TargetCard; - public abstract class PlayerImpl> implements Player, Serializable { @@ -108,6 +106,7 @@ public abstract class PlayerImpl> implements Player, Ser protected boolean passedTurn; protected int turns; protected int storedBookmark = -1; + protected int priorityTimeLeft; /** * This indicates that player passed all turns until his own turn starts. @@ -1793,4 +1792,14 @@ public abstract class PlayerImpl> implements Player, Ser this.revealCards(name, cards, game); } } + + @Override + public void setPriorityTimeLeft(int timeLeft) { + priorityTimeLeft = timeLeft; + } + + @Override + public int getPriorityTimeLeft() { + return priorityTimeLeft; + } }