diff --git a/resources/plugin.yml b/resources/plugin.yml index d4f45c0..5acd310 100644 --- a/resources/plugin.yml +++ b/resources/plugin.yml @@ -1,7 +1,7 @@ name: MobArena author: garbagemule main: com.garbagemule.MobArena.MobArena -version: 0.96.2.11 +version: 0.96.2.12 softdepend: [Multiverse-Core,Towny,Heroes,MagicSpells,Vault] commands: ma: diff --git a/resources/res/settings.yml b/resources/res/settings.yml index 7c6b3d4..0778a0b 100644 --- a/resources/res/settings.yml +++ b/resources/res/settings.yml @@ -30,6 +30,7 @@ lock-food-level: true player-time-in-arena: world auto-ignite-tnt: false auto-start-timer: 0 +start-delay-timer: 0 auto-ready: false use-class-chests: false display-waves-as-level: false diff --git a/src/com/garbagemule/MobArena/ArenaImpl.java b/src/com/garbagemule/MobArena/ArenaImpl.java index 4da8506..dbf2375 100644 --- a/src/com/garbagemule/MobArena/ArenaImpl.java +++ b/src/com/garbagemule/MobArena/ArenaImpl.java @@ -35,6 +35,7 @@ import com.garbagemule.MobArena.util.*; import com.garbagemule.MobArena.util.inventory.InventoryManager; import com.garbagemule.MobArena.util.inventory.InventoryUtils; import com.garbagemule.MobArena.util.timer.AutoStartTimer; +import com.garbagemule.MobArena.util.timer.StartDelayTimer; import com.garbagemule.MobArena.waves.*; import com.garbagemule.MobArena.ScoreboardManager.NullScoreboardManager; @@ -92,6 +93,7 @@ public class ArenaImpl implements Arena private List entryFee; private TimeStrategy timeStrategy; private AutoStartTimer autoStartTimer; + private StartDelayTimer startDelayTimer; private boolean isolatedChat; // Scoreboards @@ -159,6 +161,7 @@ public class ArenaImpl implements Arena this.allowAnimals = world.getAllowAnimals(); this.autoStartTimer = new AutoStartTimer(this); + this.startDelayTimer = new StartDelayTimer(this, autoStartTimer); this.isolatedChat = settings.getBoolean("isolated-chat", false); @@ -384,7 +387,12 @@ public class ArenaImpl implements Arena return false; } - // Stop the auto-start-timer + // Check if start-delay is over + if (startDelayTimer.isRunning()) { + return false; + } + + // Stop the auto-start-timer regardless autoStartTimer.stop(); // Fire the event and check if it's been cancelled. @@ -545,6 +553,8 @@ public class ArenaImpl implements Arena Messenger.tell(p, Msg.LEAVE_NOT_READY); } + // Stop start-delay-timer and start arena + startDelayTimer.stop(); startArena(); } @@ -591,14 +601,18 @@ public class ArenaImpl implements Arena arenaPlayerMap.put(p, new ArenaPlayer(p, this, plugin)); - // Start the auto-start-timer - autoStartTimer.start(); + // Start the start-delay-timer if applicable + if (!autoStartTimer.isRunning()) { + startDelayTimer.start(); + } // Notify player of joining Messenger.tell(p, Msg.JOIN_PLAYER_JOINED); // Notify player of time left - if (autoStartTimer.isRunning()) { + if (startDelayTimer.isRunning()) { + Messenger.tell(p, Msg.ARENA_START_DELAY, "" + startDelayTimer.getRemaining() / 20l); + } else if (autoStartTimer.isRunning()) { Messenger.tell(p, Msg.ARENA_AUTO_START, "" + autoStartTimer.getRemaining() / 20l); } diff --git a/src/com/garbagemule/MobArena/Msg.java b/src/com/garbagemule/MobArena/Msg.java index 3cfa9f4..61186c1 100644 --- a/src/com/garbagemule/MobArena/Msg.java +++ b/src/com/garbagemule/MobArena/Msg.java @@ -12,6 +12,7 @@ public enum Msg { ARENA_JOIN_GLOBAL("Arena &e%&r is about to start! Type &e/ma j %&r to join!"), ARENA_LBOARD_NOT_FOUND("That arena does not have a leaderboard set up."), ARENA_AUTO_START("Arena will auto-start in &c%&r seconds."), + ARENA_START_DELAY("Arena can start in &e%&r seconds."), JOIN_NOT_ENABLED("MobArena is not enabled."), JOIN_IN_OTHER_ARENA("You are already in an arena! Leave that one first."), JOIN_ARENA_NOT_ENABLED("This arena is not enabled."), diff --git a/src/com/garbagemule/MobArena/util/timer/StartDelayTimer.java b/src/com/garbagemule/MobArena/util/timer/StartDelayTimer.java new file mode 100644 index 0000000..b63ff5b --- /dev/null +++ b/src/com/garbagemule/MobArena/util/timer/StartDelayTimer.java @@ -0,0 +1,107 @@ +package com.garbagemule.MobArena.util.timer; + +import com.garbagemule.MobArena.Messenger; +import com.garbagemule.MobArena.Msg; +import com.garbagemule.MobArena.framework.Arena; + +/** + * The StartDelayTimer is a self-contained CountdownTimer (i.e. it is its own + * callback), which prevents an arena from starting until the timer finishes. + * It contains an instance of the arena's auto-start-timer, and will start it + * when the start-delay is over. + *

+ * The timer is preprogrammed with a series of tick interval triggers, such + * that the timer only ticks when the time remaining matches one of these + * triggers. When the timer ticks, the lobby players are informed about the + * time remaining, and when the timer finishes, the arena's auto-start-timer + * is started. If the {@code display-timer-as-level} flag is set, the timer + * will tick once per second, updating the player levels. + *

+ * The timer realizes a semi-"Null Object" pattern if the duration (i.e. the + * value of the start-delay-timer setting) is 0, where calling the timer's + * {@link #start()} method only starts the auto-start-timer. + */ +public class StartDelayTimer extends CountdownTimer implements TimerCallback { + private Arena arena; + private CountdownTimer autoStartTimer; + private TimerCallback internalCallback; + + /** + * Create a StartDelayTimer for the given arena. + *

+ * The duration is determined from the {@code start-delay-timer} arena + * setting. If the value is non-positive, the timer acts as a type of + * Null Object, allowing it to be safely used for arenas that do not + * have a start-delay-timer, skipping the start-delay and going directly + * to the auto-start-timer. + * + * @param arena the arena the timer is responsible for + * @param autoStartTimer the auto-start-timer of the arena + */ + public StartDelayTimer(Arena arena, CountdownTimer autoStartTimer) { + super(arena.getPlugin()); + super.setCallback(this); + + this.arena = arena; + this.autoStartTimer = autoStartTimer; + + // Set the duration + long duration = arena.getSettings().getInt("start-delay-timer", 0) * 20l; + setDuration(Math.max(0l, duration)); + + // Choose level- or chat-callback + boolean level = arena.getSettings().getBoolean("display-timer-as-level", false); + if (level) { + internalCallback = new LevelCallback(arena, this); + } else { + int[] triggers = {30, 10, 5, 4, 3, 2, 1}; + internalCallback = new ChatCallback(arena, Msg.ARENA_START_DELAY, this, triggers); + } + } + + @Override + public synchronized void start() { + // Start auto-start-timer if arena has no start-delay + if (super.getDuration() > 0) { + super.start(); + } else { + autoStartTimer.start(); + } + } + + @Override + public void onStart() { + internalCallback.onStart(); + } + + @Override + public void onStop() { + internalCallback.onStop(); + } + + @Override + public void onTick() { + // TODO: Remove this if no one reports issues + if (arena.isRunning() || arena.getPlayersInLobby().isEmpty()) { + Messenger.severe("START DELAY TIMER WAS NOT STOPPED!"); + Messenger.severe(" Please make a ticket and inform me about this at:"); + Messenger.severe(" http://dev.bukkit.org/bukkit-plugins/mobarena/tickets/"); + stop(); + return; + } + internalCallback.onTick(); + } + + @Override + public void onFinish() { + // Start either the arena or the auto-start-timer + if (!arena.startArena()) { + autoStartTimer.start(); + + // Notify players of auto-start-timer duration + if (autoStartTimer.isRunning()) { + Messenger.announce(arena, Msg.ARENA_AUTO_START, "" + autoStartTimer.getRemaining() / 20l); + } + } + } +}