001package fr.aumgn.dac2.game;
002
003import org.bukkit.Bukkit;
004import org.bukkit.entity.Player;
005import org.bukkit.event.Listener;
006import org.bukkit.event.player.PlayerMoveEvent;
007
008import fr.aumgn.bukkitutils.playerref.set.PlayersRefHashSet;
009import fr.aumgn.bukkitutils.playerref.set.PlayersRefSet;
010import fr.aumgn.dac2.DAC;
011import fr.aumgn.dac2.arena.Arena;
012import fr.aumgn.dac2.game.start.GameStartData;
013import fr.aumgn.dac2.shape.column.Column;
014
015/**
016 * Common implementations of most game mode.
017 */
018public abstract class AbstractGame implements Game {
019
020    protected final DAC dac;
021    protected final Arena arena;
022    protected final Listener listener;
023    protected final PlayersRefSet spectators;
024
025    public AbstractGame(DAC dac, GameStartData data) {
026        this.dac = dac;
027        this.arena = data.getArena();
028        this.listener = new GameListener(this);
029        this.spectators = new PlayersRefHashSet();
030        spectators.addAll(data.getSpectators());
031    }
032
033    @Override
034    public Arena getArena() {
035        return arena;
036    }
037
038    @Override
039    public Listener[] getListeners() {
040        return new Listener[] { listener };
041    }
042
043    /**
044     * Send a message which is recorded in the main PluginMessages instance.
045     */
046    protected void send(String key, Object... arguments) {
047        sendMessage(dac.getMessages().get(key, arguments));
048    }
049
050    @Override
051    public boolean isSpectator(Player player) {
052        return spectators.contains(player);
053    }
054
055    @Override
056    public void addSpectator(Player player) {
057        spectators.add(player);
058    }
059
060    @Override
061    public void removeSpectator(Player player) {
062        spectators.remove(player);
063    }
064
065    @Override
066    public void onNewTurn() {
067    }
068
069    /**
070     * Check if it's the given player turn.
071     *
072     * This is used by {@link GameListener} to check if events need to be
073     * processed. So this method should be optimized as much as possible
074     * because some events (like {@link PlayerMoveEvent}) are heavy.
075     */
076    public abstract boolean isPlayerTurn(Player player);
077
078    /**
079     * Callback called when a player succeed.
080     */
081    public abstract void onJumpSuccess(Player player);
082
083    /**
084     * Callback called when a player failed.
085     */
086    public abstract void onJumpFail(Player player);
087
088    /**
089     * Sends a message to this game's spectators by prefixing
090     * the message with the arena's name as specified in the config.
091     */
092    protected void sendSpectators(String message) {
093        String spectatorMessage = dac.getConfig().getSpectatorsMsg()
094                .format(new String[] { arena.getName(), message });
095        for (Player spectator : spectators.players()) {
096            spectator.sendMessage(spectatorMessage);
097        }
098    }
099
100    /**
101     * Resets the pool if configured to do so on game start.
102     */
103    protected void resetPoolOnStart() {
104        if (dac.getConfig().getResetOnStart()) {
105            arena.getPool().reset(arena.getWorld());
106        }
107    }
108
109    /**
110     * Resets the pool if configured to do so on game end.
111     */
112    protected void resetPoolOnEnd() {
113        if (dac.getConfig().getResetOnEnd()) {
114            arena.getPool().reset(arena.getWorld());
115        }
116    }
117
118    /**
119     * Teleport the player if configured to do so on player's turn.
120     */
121    protected void tpBeforeJump(GamePlayer player) {
122        if (dac.getConfig().getTpBeforeJump()) {
123            player.teleport(arena.getDiving().toLocation(arena.getWorld()));
124        }
125    }
126
127    /**
128     * Teleport the player if configured to do so after player's success.
129     */
130    protected void tpAfterJumpSuccess(final GamePlayer player, Column column) {
131        int delay = dac.getConfig().getTpAfterJumpSuccessDelay();
132        if (delay == 0) {
133            player.tpToStart();
134            return;
135        }
136
137        player.teleport(arena.getWorld(), column.getTop().addY(1));
138        if (delay > 0) {
139            Bukkit.getScheduler().scheduleSyncDelayedTask(dac.getPlugin(),
140                    player.delayedTpToStart(), delay);
141        }
142    }
143
144    /**
145     * Teleport the player if configured to do so after player's failed jump.
146     */
147    protected void tpAfterJumpFail(final GamePlayer player) {
148        int delay = dac.getConfig().getTpAfterJumpFailDelay();
149        if (delay == 0) {
150            player.tpToStart();
151        } else if (delay > 0) {
152            Bukkit.getScheduler().scheduleSyncDelayedTask(dac.getPlugin(),
153                    player.delayedTpToStart(), delay);
154        }
155    }
156}