├── src └── org │ └── inventivetalent │ └── murder │ ├── game │ ├── CountdownType.java │ ├── state │ │ ├── GameTask.java │ │ ├── executor │ │ │ ├── starting │ │ │ │ ├── StartingDelayExecutor.java │ │ │ │ ├── DisguiseExecutor.java │ │ │ │ ├── GiveItemsExecutor.java │ │ │ │ ├── TeleportExecutor.java │ │ │ │ ├── StartingExecutor.java │ │ │ │ └── AssignExecutor.java │ │ │ ├── init │ │ │ │ └── WaitingExecutor.java │ │ │ ├── ingame │ │ │ │ ├── StartedExecutor.java │ │ │ │ ├── DropLootExecutor.java │ │ │ │ └── IngameExecutor.java │ │ │ ├── ended │ │ │ │ ├── ResetExecutor.java │ │ │ │ └── EndedExecutor.java │ │ │ ├── lobby │ │ │ │ └── LobbyExecutor.java │ │ │ ├── LeavableExecutor.java │ │ │ └── CountdownExecutor.java │ │ ├── StateExecutor.java │ │ └── GameState.java │ ├── FootStep.java │ ├── GameManager.java │ └── Game.java │ ├── arena │ ├── spawn │ │ ├── SpawnType.java │ │ └── SpawnPoint.java │ ├── editor │ │ ├── ArenaEditorManager.java │ │ └── ArenaEditor.java │ ├── ArenaManager.java │ └── Arena.java │ ├── command │ ├── GameCommands.java │ ├── ToggleCommands.java │ ├── error │ │ └── MurderErrorHandler.java │ ├── CountdownCommands.java │ ├── PlayerCommands.java │ └── ArenaCommands.java │ ├── player │ ├── BasicPlayerData.java │ ├── PlayerData.java │ ├── PlayerManager.java │ └── StoredData.java │ ├── listener │ ├── GameListenerArrow.java │ ├── DataListener.java │ ├── ProtectionListener.java │ ├── EditorListener.java │ ├── SpectatorListener.java │ ├── CorpseListener.java │ ├── SignListener.java │ └── GameListener.java │ ├── projectile │ ├── GunProjectile.java │ ├── KnifeProjectile.java │ └── MurderProjectile.java │ ├── VectorFormatter.java │ ├── name │ ├── NameListener.java │ └── NameManager.java │ ├── corpse │ └── CorpseManager.java │ ├── Role.java │ ├── item │ └── ItemManager.java │ ├── spectate │ └── SpectateManager.java │ ├── packet │ └── PacketListener.java │ ├── task │ └── ArenaOutlineTask.java │ ├── skin │ └── SkinManager.java │ └── Murder.java ├── resources ├── plugin.yml ├── mineskin-index.json └── config.yml ├── README.md ├── ISSUE_TEMPLATE.md ├── settings.xml ├── LICENSE ├── .travis.yml └── pom.xml /src/org/inventivetalent/murder/game/CountdownType.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game; 2 | 3 | public enum CountdownType { 4 | LOBBY, 5 | START; 6 | } 7 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/arena/spawn/SpawnType.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.arena.spawn; 2 | 3 | public enum SpawnType { 4 | PLAYER, 5 | LOBBY, 6 | LOOT; 7 | } 8 | -------------------------------------------------------------------------------- /resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: Murder 2 | main: org.inventivetalent.murder.Murder 3 | author: inventivetalent 4 | version: ${project.version} 5 | 6 | softdepend: [PacketListenerApi, ItemBuilder, MessageBuilder, NPCLib, ResourcePackApi, TitleAPI, MenuBuilder] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Murder 2 | 3 | [![Build Status](http://ci.inventivetalent.org/job/Murder/badge/icon)](https://ci.inventivetalent.org/job/Murder/) 4 | 5 | Minecraft Minigame based on Murder from Garry's Mod. 6 | 7 | [SpigotMC page](https://www.spigotmc.org/resources/murder.1052/) 8 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/command/GameCommands.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.command; 2 | 3 | import org.inventivetalent.murder.Murder; 4 | 5 | public class GameCommands { 6 | 7 | private Murder plugin; 8 | 9 | public GameCommands(Murder plugin) { 10 | this.plugin = plugin; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /resources/mineskin-index.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": 8369, 3 | "ab": 8370, 4 | "b": 8371, 5 | "bb": 8373, 6 | "c": 8374, 7 | "cb": 8375, 8 | "d": 8376, 9 | "db": 8377, 10 | "e": 8378, 11 | "eb": 8379, 12 | "fb": 8342, 13 | "f": 8345, 14 | "1": 8346, 15 | "1b": 8347, 16 | "2": 8348, 17 | "2b": 8349, 18 | "3": 8350, 19 | "3b": 8352, 20 | "4": 5353, 21 | "4b": 8354, 22 | "5": 8355, 23 | "5b": 5356, 24 | "6": 8357, 25 | "6b": 8358, 26 | "7": 8359, 27 | "7b": 8363, 28 | "8": 8365, 29 | "8b": 8366, 30 | "9": 8367, 31 | "9b": 8368 32 | } -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/GameTask.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state; 2 | 3 | import org.bukkit.scheduler.BukkitRunnable; 4 | import org.inventivetalent.murder.Murder; 5 | import org.inventivetalent.murder.game.Game; 6 | 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | public class GameTask extends BukkitRunnable { 11 | 12 | private Murder plugin; 13 | 14 | public GameTask(Murder plugin) { 15 | this.plugin = plugin; 16 | } 17 | 18 | @Override 19 | public void run() { 20 | Set games = new HashSet<>(plugin.gameManager.gameMap.values()); 21 | for (Game game : games) { 22 | game.tick(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/starting/StartingDelayExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.starting; 2 | 3 | import org.inventivetalent.murder.game.CountdownType; 4 | import org.inventivetalent.murder.game.Game; 5 | import org.inventivetalent.murder.game.state.executor.CountdownExecutor; 6 | 7 | public class StartingDelayExecutor extends CountdownExecutor { 8 | 9 | public StartingDelayExecutor(Game game) { 10 | super(game, CountdownType.START); 11 | } 12 | 13 | @Override 14 | public void tick() { 15 | super.tick(); 16 | } 17 | 18 | @Override 19 | public boolean finished() { 20 | return super.finished(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## What steps will reproduce the problem? 2 | 1. 3 | 2. 4 | 3. 5 | 6 | ## What were you expecting to happen? What happened instead? 7 | 8 | ## What version of the plugin are you using? *Type /version <Plugin Name>* 9 | 10 | ## What Spigot version are you using? *Type /version* 11 | 12 | ## What plugins are you using? *Type /plugins* 13 | 14 | ## Do you have an error log? Use [pastebin.com](http://pastebin.com). *If you're not sure, upload your whole server log* 15 | 16 | ## Did your client crash? *Upload errors in .minecraft/logs/latest.log as well* 17 | 18 | ## Additional information? *(Are you using Bungeecord? Did it work in previous versions? etc.)* 19 | -------------------------------------------------------------------------------- /settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sonatype-nexus-releases 5 | ${env.CI_DEPLOY_USERNAME} 6 | ${env.CI_DEPLOY_PASSWORD} 7 | 8 | 9 | sonatype-nexus-snapshots 10 | ${env.CI_DEPLOY_USERNAME} 11 | ${env.CI_DEPLOY_PASSWORD} 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/init/WaitingExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.init; 2 | 3 | import org.inventivetalent.murder.game.Game; 4 | import org.inventivetalent.murder.game.state.executor.LeavableExecutor; 5 | 6 | public class WaitingExecutor extends LeavableExecutor { 7 | 8 | public WaitingExecutor(Game game) { 9 | super(game); 10 | } 11 | 12 | @Override 13 | public boolean finished() { 14 | //If there are players, go to LOBBY 15 | return !game.players.isEmpty() || !game.joiningPlayers.isEmpty(); 16 | } 17 | 18 | @Override 19 | public boolean revert() { 20 | //If no players are waiting, go "back" to DISPOSE 21 | return game.players.isEmpty() && game.joiningPlayers.isEmpty(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/player/BasicPlayerData.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.player; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.OfflinePlayer; 5 | import org.bukkit.entity.Player; 6 | 7 | import java.util.UUID; 8 | 9 | public class BasicPlayerData { 10 | 11 | public final UUID uuid; 12 | 13 | public BasicPlayerData(UUID uuid) { 14 | if (uuid == null) { throw new IllegalArgumentException("uuid cannot be null"); } 15 | this.uuid = uuid; 16 | } 17 | 18 | public Player getPlayer() { 19 | return Bukkit.getPlayer(uuid); 20 | } 21 | 22 | public OfflinePlayer getOfflinePlayer() { 23 | return Bukkit.getOfflinePlayer(uuid); 24 | } 25 | 26 | @Override 27 | public boolean equals(Object o) { 28 | if (this == o) { return true; } 29 | if (o == null || getClass() != o.getClass()) { return false; } 30 | 31 | BasicPlayerData that = (BasicPlayerData) o; 32 | 33 | return uuid.equals(that.uuid); 34 | 35 | } 36 | 37 | @Override 38 | public int hashCode() { 39 | return uuid.hashCode(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/listener/GameListenerArrow.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.listener; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.EventHandler; 5 | import org.bukkit.event.Listener; 6 | import org.bukkit.event.player.PlayerPickupArrowEvent; 7 | import org.inventivetalent.murder.Murder; 8 | import org.inventivetalent.murder.player.PlayerData; 9 | 10 | public class GameListenerArrow implements Listener { 11 | 12 | private Murder plugin; 13 | 14 | public GameListenerArrow(Murder plugin) { 15 | this.plugin = plugin; 16 | } 17 | 18 | @EventHandler 19 | public void on(PlayerPickupArrowEvent event) { 20 | Player player = event.getPlayer(); 21 | PlayerData data = plugin.playerManager.getData(player.getUniqueId()); 22 | if (data != null) { 23 | if (data.isInGame()) { 24 | if (event.getArrow() != null) { 25 | if (event.getArrow().hasMetadata("MURDER")) { 26 | event.setCancelled(true); 27 | event.getArrow().remove(); 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/arena/editor/ArenaEditorManager.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.arena.editor; 2 | 3 | import org.inventivetalent.murder.Murder; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.UUID; 8 | 9 | public class ArenaEditorManager { 10 | 11 | private Murder plugin; 12 | 13 | public Map editorMap = new HashMap<>(); 14 | 15 | public ArenaEditorManager(Murder plugin) { 16 | this.plugin = plugin; 17 | } 18 | 19 | public ArenaEditor getEditor(UUID uuid) { 20 | if (editorMap.containsKey(uuid)) { 21 | return editorMap.get(uuid); 22 | } 23 | return null; 24 | } 25 | 26 | public boolean isEditing(UUID uuid) { 27 | return editorMap.containsKey(uuid); 28 | } 29 | 30 | public ArenaEditor newEditor(UUID uuid) { 31 | removeEditor(uuid); 32 | 33 | ArenaEditor editor = new ArenaEditor(uuid); 34 | editorMap.put(uuid, editor); 35 | return editor; 36 | } 37 | 38 | public ArenaEditor removeEditor(UUID uuid) { 39 | return editorMap.remove(uuid); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/projectile/GunProjectile.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.projectile; 2 | 3 | import org.bukkit.Color; 4 | import org.bukkit.entity.Arrow; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.util.Vector; 7 | import org.inventivetalent.murder.game.Game; 8 | import org.inventivetalent.particle.ParticleEffect; 9 | 10 | import java.util.Collections; 11 | 12 | public class GunProjectile extends MurderProjectile { 13 | 14 | public GunProjectile(Game game, Player shooter, Vector direction) { 15 | super(Type.GUN, game, shooter, direction.clone()); 16 | initProjectile(shooter.launchProjectile(Arrow.class, this.direction.multiply(3))); 17 | } 18 | 19 | @Override 20 | public void tick() { 21 | super.tick(); 22 | projectile.setVelocity(direction); 23 | 24 | ParticleEffect.REDSTONE.sendColor(Collections.singleton(shooter), projectile.getLocation().getX(), projectile.getLocation().getY(), projectile.getLocation().getZ(), Color.BLUE); 25 | } 26 | 27 | @Override 28 | public boolean finished() { 29 | return super.finished(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/VectorFormatter.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder; 2 | 3 | import org.bukkit.util.Vector; 4 | import org.inventivetalent.pluginannotations.message.MessageFormatter; 5 | 6 | import java.util.concurrent.Callable; 7 | 8 | public class VectorFormatter extends MessageFormatter { 9 | 10 | private Callable callable; 11 | 12 | public VectorFormatter(Callable callable) { 13 | this.callable = callable; 14 | } 15 | 16 | public VectorFormatter(final Vector vector) { 17 | this.callable = new Callable() { 18 | @Override 19 | public Vector call() throws Exception { 20 | return vector; 21 | } 22 | }; 23 | } 24 | 25 | @Override 26 | public String format(String key, String message) { 27 | try { 28 | if (callable != null) { 29 | Vector vector = callable.call(); 30 | if (vector != null) { 31 | return String.format(message, vector.getX(), vector.getY(), vector.getZ()); 32 | } 33 | } 34 | } catch (Exception e) { 35 | throw new RuntimeException(e); 36 | } 37 | return super.format(key, message); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013 Haylee Schäfer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/name/NameListener.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.name; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.event.EventHandler; 5 | import org.bukkit.event.Listener; 6 | import org.inventivetalent.murder.Murder; 7 | import org.inventivetalent.nicknamer.api.INickNamer; 8 | import org.inventivetalent.nicknamer.api.NickManager; 9 | 10 | public class NameListener implements Listener { 11 | 12 | private Murder plugin; 13 | 14 | public NameListener(Murder plugin) { 15 | this.plugin = plugin; 16 | } 17 | 18 | @EventHandler 19 | public void on(org.inventivetalent.nicknamer.api.event.NickNamerUpdateEvent event) { 20 | // PlayerData data = plugin.playerManager.getData(event.getPlayer().getUniqueId()); 21 | // if (data != null) { 22 | // if (data.isInGame()) { 23 | // if (getNickManager().isNicked(event.getPlayer().getUniqueId())) { 24 | // event.setNick(getNickManager().getNick(event.getPlayer().getUniqueId())); 25 | // } 26 | // } 27 | // } 28 | } 29 | 30 | NickManager getNickManager() { 31 | return ((INickNamer) Bukkit.getPluginManager().getPlugin("NickNamer")).getAPI(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/starting/DisguiseExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.starting; 2 | 3 | import com.google.common.base.Predicate; 4 | import org.inventivetalent.murder.Murder; 5 | import org.inventivetalent.murder.game.CountdownType; 6 | import org.inventivetalent.murder.game.Game; 7 | import org.inventivetalent.murder.game.state.GameState; 8 | import org.inventivetalent.murder.game.state.executor.CountdownExecutor; 9 | import org.inventivetalent.murder.player.PlayerData; 10 | 11 | public class DisguiseExecutor extends CountdownExecutor { 12 | 13 | public boolean firstTick = true; 14 | 15 | public DisguiseExecutor(Game game) { 16 | super(game, CountdownType.START); 17 | } 18 | 19 | @Override 20 | public void tick() { 21 | super.tick(); 22 | if (firstTick) { 23 | firstTick = false; 24 | 25 | updatePlayerStates(GameState.DISGUISE, new Predicate() { 26 | @Override 27 | public boolean apply(PlayerData playerData) { 28 | Murder.instance.playerManager.disguisePlayer(playerData.getPlayer(), Murder.instance.nameManager.randomName()); 29 | return true; 30 | } 31 | }); 32 | } 33 | } 34 | 35 | @Override 36 | public boolean finished() { 37 | return super.finished() || !firstTick; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/listener/DataListener.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.listener; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.event.EventHandler; 5 | import org.bukkit.event.Listener; 6 | import org.bukkit.event.player.PlayerJoinEvent; 7 | import org.bukkit.event.player.PlayerQuitEvent; 8 | import org.inventivetalent.murder.Murder; 9 | import org.inventivetalent.murder.player.PlayerData; 10 | 11 | public class DataListener implements Listener { 12 | 13 | private Murder plugin; 14 | 15 | public DataListener(Murder plugin) { 16 | this.plugin = plugin; 17 | } 18 | 19 | @EventHandler 20 | public void onJoin(final PlayerJoinEvent event) { 21 | final PlayerData playerData = plugin.playerManager.loadFromFile(event.getPlayer().getUniqueId()); 22 | if (playerData.stored) { 23 | Bukkit.getScheduler().runTaskLater(plugin, new Runnable() { 24 | @Override 25 | public void run() { 26 | if (event.getPlayer().isOnline() && playerData.stored) { playerData.restoreData(); } 27 | } 28 | }, 10); 29 | } 30 | } 31 | 32 | @EventHandler 33 | public void onQuit(PlayerQuitEvent event) { 34 | PlayerData playerData = plugin.playerManager.getData(event.getPlayer().getUniqueId()); 35 | if (playerData != null && playerData.getGame() != null) { 36 | playerData.getGame().leavingPlayers.add(event.getPlayer().getUniqueId()); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/StateExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state; 2 | 3 | import com.google.common.base.Predicate; 4 | import org.inventivetalent.murder.Murder; 5 | import org.inventivetalent.murder.game.Game; 6 | import org.inventivetalent.murder.player.PlayerData; 7 | 8 | import java.util.UUID; 9 | 10 | public class StateExecutor { 11 | 12 | public final Game game; 13 | 14 | public StateExecutor(Game game) { 15 | this.game = game; 16 | } 17 | 18 | public void updatePlayerStates(GameState state, Predicate updatedPlayerCallback) { 19 | for (UUID uuid : game.players) { 20 | PlayerData data = Murder.instance.playerManager.getData(uuid); 21 | if (data != null) { 22 | if (data.gameState != state) { 23 | if (updatedPlayerCallback != null) { 24 | if (updatedPlayerCallback.apply(data)) { 25 | data.gameState = state; 26 | } 27 | } else { 28 | data.gameState = state; 29 | } 30 | } 31 | } 32 | } 33 | } 34 | 35 | public void tick() { 36 | } 37 | 38 | /** 39 | * @return true if state didn't finish and we need to go back to the previous state 40 | */ 41 | public boolean revert() { 42 | return false; 43 | } 44 | 45 | /** 46 | * @return true if this state finished and we can move on to the next state 47 | */ 48 | public boolean finished() { 49 | return false; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/listener/ProtectionListener.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.listener; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.EventHandler; 5 | import org.bukkit.event.Listener; 6 | import org.bukkit.event.block.BlockBreakEvent; 7 | import org.bukkit.event.block.BlockPlaceEvent; 8 | import org.inventivetalent.murder.Murder; 9 | import org.inventivetalent.murder.player.PlayerData; 10 | 11 | public class ProtectionListener implements Listener { 12 | 13 | private Murder plugin; 14 | 15 | public ProtectionListener(Murder plugin) { 16 | this.plugin = plugin; 17 | } 18 | 19 | @EventHandler 20 | public void onBlockBreak(BlockBreakEvent event) { 21 | Player player = event.getPlayer(); 22 | PlayerData playerData = plugin.playerManager.getData(player.getUniqueId()); 23 | if (playerData != null && playerData.getGame() != null) { 24 | if (playerData.getGame().arena.contains(event.getBlock().getLocation().toVector())) { 25 | event.setCancelled(true); 26 | } 27 | } 28 | } 29 | 30 | @EventHandler 31 | public void onBlockPlace(BlockPlaceEvent event) { 32 | Player player = event.getPlayer(); 33 | PlayerData playerData = plugin.playerManager.getData(player.getUniqueId()); 34 | if (playerData != null && playerData.getGame() != null) { 35 | if (playerData.getGame().arena.contains(event.getBlock().getLocation().toVector())) { 36 | event.setCancelled(true); 37 | } 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/projectile/KnifeProjectile.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.projectile; 2 | 3 | import org.bukkit.Color; 4 | import org.bukkit.entity.Arrow; 5 | import org.bukkit.entity.Item; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.util.Vector; 8 | import org.inventivetalent.murder.Murder; 9 | import org.inventivetalent.murder.game.Game; 10 | import org.inventivetalent.particle.ParticleEffect; 11 | 12 | import java.util.Collections; 13 | 14 | public class KnifeProjectile extends MurderProjectile { 15 | 16 | public KnifeProjectile(Game game, Player shooter, Vector direction) { 17 | super(Type.KNIFE, game, shooter, direction); 18 | initProjectile(shooter.launchProjectile(Arrow.class, this.direction.multiply(2))); 19 | } 20 | 21 | @Override 22 | public void tick() { 23 | super.tick(); 24 | 25 | direction.subtract(new Vector(0, 0.035, 0)); 26 | projectile.setVelocity(direction); 27 | 28 | ParticleEffect.REDSTONE.sendColor(Collections.singleton(shooter), projectile.getLocation().getX(), projectile.getLocation().getY(), projectile.getLocation().getZ(), Color.RED); 29 | } 30 | 31 | @Override 32 | public boolean finished() { 33 | if (super.finished()) { 34 | Item dropped = projectile.getLocation().getWorld().dropItemNaturally(projectile.getLocation(), Murder.instance.itemManager.getKnife()); 35 | game.droppedItems.add(dropped); 36 | projectile.remove(); 37 | return true; 38 | } 39 | return false; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | 5 | script: "mvn deploy --settings settings.xml" 6 | env: 7 | global: 8 | - secure: "aGuPS/JzHAxX1nKo6dlSPgekIdxzmcZDOtOGSJZRO8xkiht3Waay1GMFTFIOMjIxFM60N+CHT6uCFHqZUV1Esns+ctbvzE8q+IwaK1IdTAhVYDh69r50QxTS4wX4ASHIzHoXF37IjwS+p7As5BASGpppzvhnSqqLPR2wDqNhiTeXTnIXE8HanmA6Wg8lwXaM3IWi4JUfuC9kzcQELp4aGOu5y4da99bKbC+IpgQzOJMcMYDdZl4JCEQulB7BIiLhJOSAVlwFId0cT/0u45Miehfm+KkkNTlQVxsqgpvwNgLsCym1zHxgIhEwtZI1nsFiuhSPBE+PTK9/revRUUCjt8p56cdFFgPo6qrousMw8dNBLmXYX4VQa04c/FjkIuR9gmcXFwPkyD83jOOfjzy0pXiA2PWvLyLaUgwql/9tSU0MAEvAeoVBTn5/b5FoeEKrD+ZQCyMZM7+LIQSCs0bwihlJoBIqli8bPqxYSwWDuoHBuvCeMy9DPfAz8hfcBgCqrR76XSSvB2L0DXZyvvO/3UjlWg2i6twsnmqN9YuBU9eJRoCju84IbZ0kO5wPVPOPCV2+nF2oHy93f2hF6XHC63NRgnIvEnxXFh8Xi1QKiWza3zBktfoo0FhyhfxjsRc9wyq/OZHuhwIgyxgr3Xf5gUqDkq8ownungtBzXxjPz9U=" 9 | - secure: "UKToyC9WBZZcCBOI2/BwjmELuDggHxFozd4ay31E4LDAyd/SBml4v4Rgdx6Way43pByyk5c6dZGa98fZ3P3Ngk7+fMDjMCMdxjXHNUSIh2P2pRxTwx3bg60SJh7i3uCfqwcKbCfHI2s57tnNIAuF1TrGwPHsEdmQPG0lItjewV/RXZYJmTlQ952tsYdyVyegoXEk53dantcZBirb9hWyJekEIpP5fZoHQZkGN+eX382Hjj6qVeaU9qbVMq6fxokflfLP+2bFkzu3JhQVsmIEvNdGuDv44k1qphJDhD47diuX595OQ28tiLQQzVHvl6XAJw5viUgoDVAsvYJuWgN5+21HNMgeQQdjLlUJuZz/NHm/BCsQQEIJgeiV1Z9mvsMhZ7nax7SCOoazS27B/aMPF/y6cqo1gE6Ktc+yeaguAism1zPFZ5+RXiNfX5lqs3Dzgf2rSj8D+Cef0TLOVK47k4D9YoAgV8Jis52jpIS3VqN7d/ruEkcv7BWjVHzxcZ3T1Y/AODXbLoc18JjaYY3JEgjVLWiLKqZTDzlLlnwor0ZmVv9FMlT2WPy0ywb4oAp41dq0BfY7E4mVEaqQHw7c91zR4Uaetass3z8xDaumzX3jDNPTdqUz/0yFZf47i4Myijx06uNkyBO00RJ1cfRA+cZ4gm1LMBMW6ZGQB2RAAAs=" -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/ingame/StartedExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.ingame; 2 | 3 | import com.google.common.base.Predicate; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.potion.PotionEffect; 6 | import org.inventivetalent.murder.Role; 7 | import org.inventivetalent.murder.game.Game; 8 | import org.inventivetalent.murder.game.state.GameState; 9 | import org.inventivetalent.murder.player.PlayerData; 10 | 11 | import java.util.UUID; 12 | 13 | public class StartedExecutor extends IngameExecutor { 14 | 15 | boolean firstTick = true; 16 | 17 | public StartedExecutor(Game game) { 18 | super(game); 19 | } 20 | 21 | @Override 22 | public void tick() { 23 | super.tick(); 24 | 25 | if (firstTick) { 26 | firstTick = false; 27 | 28 | updatePlayerStates(GameState.STARTED, new Predicate() { 29 | @Override 30 | public boolean apply(PlayerData playerData) { 31 | Player player = playerData.getPlayer(); 32 | 33 | //Remove black screen 34 | player.getInventory().setHelmet(null); 35 | 36 | //Clear effects 37 | for (PotionEffect effect : player.getActivePotionEffects()) { 38 | player.removePotionEffect(effect.getType()); 39 | } 40 | for (UUID uuid1 : game.players) { 41 | Player player1 = game.getPlayer(uuid1); 42 | if (player1 != null) { player1.showPlayer(playerData.getPlayer()); } 43 | } 44 | 45 | player.setWalkSpeed(0.2f); 46 | if (playerData.role != Role.MURDERER) { 47 | player.setFoodLevel(6); 48 | } 49 | return true; 50 | } 51 | }); 52 | } 53 | } 54 | 55 | @Override 56 | public boolean finished() { 57 | return super.finished() || !firstTick; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/name/NameManager.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.name; 2 | 3 | import org.bukkit.OfflinePlayer; 4 | import org.inventivetalent.murder.Murder; 5 | import org.inventivetalent.murder.player.PlayerData; 6 | import org.inventivetalent.pluginannotations.PluginAnnotations; 7 | import org.inventivetalent.pluginannotations.config.ConfigValue; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Random; 12 | 13 | public class NameManager { 14 | 15 | private Murder plugin; 16 | 17 | public final Random random = new Random(); 18 | 19 | @ConfigValue(path = "name.tags") public List tags = new ArrayList<>(); 20 | @ConfigValue(path = "name.colors", colorChar = '&') public List colors = new ArrayList<>(); 21 | 22 | public NameManager(Murder plugin) { 23 | this.plugin = plugin; 24 | PluginAnnotations.CONFIG.loadValues(plugin, this); 25 | } 26 | 27 | public String randomTag() { 28 | return tags.get(random.nextInt(tags.size())); 29 | } 30 | 31 | public String randomColor() { 32 | return colors.get(random.nextInt(colors.size())); 33 | } 34 | 35 | public String randomName() { 36 | return randomColor() + randomTag(); 37 | } 38 | 39 | public void setNameTag(OfflinePlayer player, String nameTag) { 40 | if (nameTag == null || nameTag.isEmpty()) { 41 | plugin.getNickManager().removeNick(player.getUniqueId()); 42 | } else { 43 | plugin.getNickManager().setNick(player.getUniqueId(), nameTag); 44 | } 45 | PlayerData playerData = plugin.playerManager.getData(player.getUniqueId()); 46 | if (nameTag == null) { 47 | if (playerData == null) { return; } 48 | } 49 | if (playerData != null) { 50 | playerData.nameTag = nameTag; 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/FootStep.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game; 2 | 3 | import org.bukkit.Color; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.util.Vector; 6 | import org.inventivetalent.particle.ParticleEffect; 7 | 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | import java.util.UUID; 11 | 12 | public class FootStep { 13 | 14 | public final UUID uuid; 15 | public final Vector vector; 16 | public final Color color; 17 | 18 | int fadeTimeout = 20; 19 | 20 | public FootStep(UUID uuid, Vector vector, Color color) { 21 | this.uuid = uuid; 22 | this.vector = vector; 23 | this.color = color; 24 | } 25 | 26 | public void display(Player receiver) { 27 | if (receiver == null || !receiver.isOnline()) { return; } 28 | 29 | Collection singleton = Collections.singleton(receiver); 30 | ParticleEffect.REDSTONE.sendColor(singleton, vector.getX(), vector.getY() + .025, vector.getZ(), color); 31 | if (fadeTimeout++ >= 16) { 32 | fadeTimeout=0; 33 | ParticleEffect.FOOTSTEP.send(singleton, vector.getX(), vector.getY() + .01, vector.getZ(), 0, 0, 0, 0, 1); 34 | } 35 | } 36 | 37 | @Override 38 | public boolean equals(Object o) { 39 | if (this == o) { return true; } 40 | if (o == null || getClass() != o.getClass()) { return false; } 41 | 42 | FootStep footStep = (FootStep) o; 43 | 44 | if (vector != null ? !vector.equals(footStep.vector) : footStep.vector != null) { return false; } 45 | return color != null ? color.equals(footStep.color) : footStep.color == null; 46 | 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | int result = vector != null ? vector.hashCode() : 0; 52 | result = 31 * result + (color != null ? color.hashCode() : 0); 53 | return result; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/ended/ResetExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.ended; 2 | 3 | import com.google.common.base.Predicate; 4 | import org.bukkit.entity.Item; 5 | import org.inventivetalent.murder.Murder; 6 | import org.inventivetalent.murder.game.Game; 7 | import org.inventivetalent.murder.game.state.GameState; 8 | import org.inventivetalent.murder.game.state.executor.LeavableExecutor; 9 | import org.inventivetalent.murder.player.PlayerData; 10 | 11 | public class ResetExecutor extends LeavableExecutor { 12 | 13 | int ticks = 0; 14 | 15 | public ResetExecutor(Game game) { 16 | super(game); 17 | } 18 | 19 | @Override 20 | public void tick() { 21 | super.tick(); 22 | if (ticks == 0) { 23 | updatePlayerStates(GameState.RESET, new Predicate() { 24 | @Override 25 | public boolean apply(PlayerData playerData) { 26 | if (playerData.getOfflinePlayer().isOnline()) { 27 | game.leavingPlayers.add(playerData.uuid); 28 | // //Restore data and delete data file 29 | // playerData.restoreData(); 30 | //// Murder.instance.playerManager.deleteDataFile(playerData.uuid); 31 | // 32 | // //Reset resource pack 33 | // ResourcePackAPI.setResourcepack(playerData.getPlayer(), Murder.instance.resetPackUrl, Murder.instance.resetPackHash); 34 | } 35 | 36 | return true; 37 | } 38 | }); 39 | 40 | //Remove dropped items 41 | for (Item item : game.droppedItems) { 42 | item.remove(); 43 | } 44 | 45 | //Despawn corpses 46 | Murder.instance.corpseManager.removeCorpses(game); 47 | } 48 | ticks++; 49 | } 50 | 51 | @Override 52 | public boolean finished() { 53 | return super.finished() || ticks > 2; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/corpse/CorpseManager.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.corpse; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.Material; 5 | import org.bukkit.block.Block; 6 | import org.bukkit.block.BlockFace; 7 | import org.inventivetalent.murder.Murder; 8 | import org.inventivetalent.murder.game.Game; 9 | import org.inventivetalent.murder.player.PlayerData; 10 | import org.inventivetalent.npclib.npc.living.human.NPCPlayer; 11 | 12 | import java.util.UUID; 13 | 14 | public class CorpseManager { 15 | 16 | private Murder plugin; 17 | 18 | public CorpseManager(Murder plugin) { 19 | this.plugin = plugin; 20 | } 21 | 22 | public NPCPlayer spawnCorpse(Game game, PlayerData data, Location l) { 23 | if (data.isInGame() && data.nameTag != null) { 24 | Location location = l.clone(); 25 | 26 | Block block = location.getBlock(); 27 | while (block.getType() != Material.AIR) { 28 | block = block.getRelative(BlockFace.UP); 29 | } 30 | location.setY(block.getY() + .5); 31 | 32 | //Make sure there's enough room 33 | block = location.getBlock().getRelative(BlockFace.NORTH); 34 | while (block.getRelative(BlockFace.NORTH).getType() != Material.AIR) { 35 | block = block.getRelative(BlockFace.SOUTH); 36 | } 37 | location = block.getLocation(); 38 | 39 | NPCPlayer npc = plugin.npcRegistry.spawnPlayerNPC(location, NPCPlayer.class, UUID.randomUUID(), data.nameTag); 40 | npc.setSkin(data.nameTag.substring(1, 2) + "b"); 41 | npc.setLaying(true); 42 | npc.setPersistent(false); 43 | //TODO: collision 44 | //TODO: gravity 45 | game.corpses.add(npc); 46 | return npc; 47 | } 48 | return null; 49 | } 50 | 51 | public void removeCorpses(Game game) { 52 | for (NPCPlayer npc : game.corpses) { 53 | npc.despawn(); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/starting/GiveItemsExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.starting; 2 | 3 | import com.google.common.base.Predicate; 4 | import org.bukkit.entity.Player; 5 | import org.inventivetalent.murder.Murder; 6 | import org.inventivetalent.murder.Role; 7 | import org.inventivetalent.murder.game.CountdownType; 8 | import org.inventivetalent.murder.game.Game; 9 | import org.inventivetalent.murder.game.state.GameState; 10 | import org.inventivetalent.murder.game.state.executor.CountdownExecutor; 11 | import org.inventivetalent.murder.player.PlayerData; 12 | 13 | public class GiveItemsExecutor extends CountdownExecutor { 14 | 15 | boolean firstTick = true; 16 | 17 | public GiveItemsExecutor(Game game) { 18 | super(game, CountdownType.START); 19 | } 20 | 21 | @Override 22 | public void tick() { 23 | super.tick(); 24 | 25 | if (firstTick) { 26 | firstTick = false; 27 | 28 | updatePlayerStates(GameState.GIVE_ITEMS, new Predicate() { 29 | @Override 30 | public boolean apply(PlayerData data) { 31 | Player player = data.getPlayer(); 32 | 33 | if (data.role == Role.DEFAULT) { 34 | player.getInventory().setItem(8, Murder.instance.itemManager.getSpeedBoost()); 35 | } 36 | if (data.role == Role.WEAPON) { 37 | player.getInventory().setItem(4, Murder.instance.itemManager.getGun()); 38 | player.getInventory().setItem(8, Murder.instance.itemManager.getBullet()); 39 | } 40 | 41 | if (data.role == Role.MURDERER) { 42 | player.getInventory().setItem(4, Murder.instance.itemManager.getKnife()); 43 | } 44 | 45 | return true; 46 | } 47 | }); 48 | } 49 | } 50 | 51 | @Override 52 | public boolean finished() { 53 | return super.finished() && !firstTick; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/starting/TeleportExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.starting; 2 | 3 | import com.google.common.base.Predicate; 4 | import com.google.common.collect.Iterables; 5 | import org.bukkit.Location; 6 | import org.inventivetalent.murder.arena.spawn.SpawnPoint; 7 | import org.inventivetalent.murder.arena.spawn.SpawnType; 8 | import org.inventivetalent.murder.game.CountdownType; 9 | import org.inventivetalent.murder.game.Game; 10 | import org.inventivetalent.murder.game.state.GameState; 11 | import org.inventivetalent.murder.game.state.executor.CountdownExecutor; 12 | import org.inventivetalent.murder.player.PlayerData; 13 | 14 | import java.util.Iterator; 15 | import java.util.Random; 16 | import java.util.Set; 17 | 18 | public class TeleportExecutor extends CountdownExecutor { 19 | 20 | boolean firstTick = true; 21 | 22 | public TeleportExecutor(Game game) { 23 | super(game, CountdownType.START); 24 | } 25 | 26 | @Override 27 | public void tick() { 28 | super.tick(); 29 | if (firstTick) { 30 | firstTick = false; 31 | 32 | final Set spawnPoints = game.arena.getSpawnPoints(SpawnType.PLAYER); 33 | final Iterator iterator = Iterables.cycle(spawnPoints).iterator(); 34 | updatePlayerStates(GameState.TELEPORT, new Predicate() { 35 | @Override 36 | public boolean apply(PlayerData playerData) { 37 | Location location = iterator.next().getLocation(game.arena.getWorld()).clone(); 38 | Random random = new Random(); 39 | location.add(random.nextDouble(), random.nextDouble(), random.nextDouble()); 40 | playerData.getPlayer().teleport(location); 41 | return true; 42 | } 43 | }); 44 | } 45 | } 46 | 47 | @Override 48 | public boolean finished() { 49 | return super.finished() || !firstTick; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/listener/EditorListener.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.listener; 2 | 3 | import org.bukkit.event.EventHandler; 4 | import org.bukkit.event.EventPriority; 5 | import org.bukkit.event.Listener; 6 | import org.bukkit.event.block.BlockBreakEvent; 7 | import org.bukkit.event.block.BlockPlaceEvent; 8 | import org.bukkit.event.player.PlayerInteractEvent; 9 | import org.bukkit.event.player.PlayerQuitEvent; 10 | import org.inventivetalent.murder.Murder; 11 | 12 | public class EditorListener implements Listener { 13 | 14 | private Murder plugin; 15 | 16 | public EditorListener(Murder plugin) { 17 | this.plugin = plugin; 18 | } 19 | 20 | @EventHandler(priority = EventPriority.MONITOR) 21 | public void on(PlayerInteractEvent event) { 22 | // if (event.isCancelled()) { return; } 23 | if (plugin.arenaEditorManager.isEditing(event.getPlayer().getUniqueId())) { 24 | plugin.arenaEditorManager.getEditor(event.getPlayer().getUniqueId()).handleInteract(event); 25 | } 26 | } 27 | 28 | @EventHandler(priority = EventPriority.MONITOR) 29 | public void on(BlockPlaceEvent event) { 30 | if (event.isCancelled() || !event.canBuild()) { return; } 31 | if (plugin.arenaEditorManager.isEditing(event.getPlayer().getUniqueId())) { 32 | plugin.arenaEditorManager.getEditor(event.getPlayer().getUniqueId()).handleBlockPlace(event); 33 | } 34 | } 35 | 36 | @EventHandler(priority = EventPriority.MONITOR) 37 | public void on(BlockBreakEvent event) { 38 | if (event.isCancelled()) { return; } 39 | if (plugin.arenaEditorManager.isEditing(event.getPlayer().getUniqueId())) { 40 | plugin.arenaEditorManager.getEditor(event.getPlayer().getUniqueId()).handleBlockBreak(event); 41 | } 42 | } 43 | 44 | @EventHandler 45 | public void on(PlayerQuitEvent event) { 46 | plugin.arenaEditorManager.removeEditor(event.getPlayer().getUniqueId()); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/starting/StartingExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.starting; 2 | 3 | import com.google.common.base.Predicate; 4 | import org.bukkit.Material; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.inventory.ItemStack; 7 | import org.bukkit.potion.PotionEffect; 8 | import org.bukkit.potion.PotionEffectType; 9 | import org.inventivetalent.murder.game.CountdownType; 10 | import org.inventivetalent.murder.game.Game; 11 | import org.inventivetalent.murder.game.state.GameState; 12 | import org.inventivetalent.murder.game.state.executor.CountdownExecutor; 13 | import org.inventivetalent.murder.player.PlayerData; 14 | 15 | public class StartingExecutor extends CountdownExecutor { 16 | 17 | boolean firstTick = true; 18 | 19 | public StartingExecutor(Game game) { 20 | super(game, CountdownType.START); 21 | resetTime(); 22 | } 23 | 24 | @Override 25 | public void tick() { 26 | super.tick(); 27 | if (firstTick) { 28 | firstTick = false; 29 | 30 | updatePlayerStates(GameState.STARTING, new Predicate() { 31 | @Override 32 | public boolean apply(PlayerData playerData) { 33 | Player player = playerData.getPlayer(); 34 | 35 | //Make the screen dark 36 | player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Integer.MAX_VALUE, 2, false, false)); 37 | player.getInventory().setHelmet(new ItemStack(Material.PUMPKIN)); 38 | 39 | //Prevent movement 40 | player.setWalkSpeed(0); 41 | player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, Integer.MAX_VALUE, 250, false, false)); 42 | player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, Integer.MAX_VALUE, 255, false, false)); 43 | 44 | return true; 45 | } 46 | }); 47 | } 48 | } 49 | 50 | @Override 51 | public boolean finished() { 52 | return super.finished() || !firstTick; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/lobby/LobbyExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.lobby; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.inventivetalent.murder.Murder; 5 | import org.inventivetalent.murder.arena.spawn.SpawnType; 6 | import org.inventivetalent.murder.game.CountdownType; 7 | import org.inventivetalent.murder.game.Game; 8 | import org.inventivetalent.murder.game.state.GameState; 9 | import org.inventivetalent.murder.game.state.executor.CountdownExecutor; 10 | import org.inventivetalent.murder.player.PlayerData; 11 | 12 | import java.util.UUID; 13 | 14 | public class LobbyExecutor extends CountdownExecutor { 15 | 16 | public LobbyExecutor(Game game) { 17 | super(game, CountdownType.LOBBY); 18 | resetTime(); 19 | } 20 | 21 | @Override 22 | public void tick() { 23 | super.tick(); 24 | if (!game.waitingForResourcepack.isEmpty()) { 25 | for (UUID uuid : game.waitingForResourcepack) { 26 | //Send the resource pack 27 | Player player = game.getPlayer(uuid); 28 | if (player != null) { 29 | player.setResourcePack(Murder.instance.gamePackUrl);//TODO: hash 30 | } 31 | } 32 | game.waitingForResourcepack.clear(); 33 | } 34 | if (!game.joiningPlayers.isEmpty()) { 35 | for (UUID uuid : game.joiningPlayers) { 36 | game.players.add(uuid); 37 | 38 | PlayerData data = Murder.instance.playerManager.getData(uuid); 39 | data.gameState = GameState.LOBBY; 40 | 41 | data.getPlayer().teleport(game.arena.getFirstSpawnPoint(SpawnType.LOBBY).getLocation(game.arena.getWorld())); 42 | game.broadcastJoin(uuid); 43 | 44 | game.waitingForResourcepack.add(uuid); 45 | } 46 | game.joiningPlayers.clear(); 47 | 48 | Murder.instance.gameManager.refreshSigns(game); 49 | } 50 | } 51 | 52 | @Override 53 | public boolean revert() { 54 | //All players left, go back to WAITING 55 | return game.players.isEmpty(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/listener/SpectatorListener.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.listener; 2 | 3 | import org.bukkit.GameMode; 4 | import org.bukkit.event.EventHandler; 5 | import org.bukkit.event.Listener; 6 | import org.bukkit.event.block.Action; 7 | import org.bukkit.event.player.PlayerInteractEvent; 8 | import org.bukkit.event.player.PlayerToggleSneakEvent; 9 | import org.bukkit.inventory.ItemStack; 10 | import org.inventivetalent.murder.Murder; 11 | import org.inventivetalent.murder.player.PlayerData; 12 | 13 | public class SpectatorListener implements Listener { 14 | 15 | private Murder plugin; 16 | 17 | public SpectatorListener(Murder plugin) { 18 | this.plugin = plugin; 19 | } 20 | 21 | @EventHandler 22 | public void on(PlayerInteractEvent event) { 23 | ItemStack itemStack = event.getItem(); 24 | if (itemStack != null && plugin.itemManager.getTeleporter().equals(itemStack)) { 25 | PlayerData data = Murder.instance.playerManager.getData(event.getPlayer().getUniqueId()); 26 | if (data != null) { 27 | if (data.isInGame() && data.isSpectator) { 28 | if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_BLOCK) { 29 | plugin.spectateManager.teleportToClosestPlayer(data); 30 | } else if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) { 31 | plugin.spectateManager.openSpectatorMenu(data); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | 38 | @EventHandler 39 | public void on(PlayerToggleSneakEvent event) { 40 | PlayerData playerData = plugin.playerManager.getData(event.getPlayer().getUniqueId()); 41 | if (playerData != null) { 42 | if (playerData.isInGame() && playerData.isSpectator) { 43 | //Reset the gamemode when the player "leaves" their target 44 | event.getPlayer().setGameMode(GameMode.ADVENTURE); 45 | event.getPlayer().setAllowFlight(true); 46 | event.getPlayer().setFlying(true); 47 | } 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/ingame/DropLootExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.ingame; 2 | 3 | import org.bukkit.entity.Item; 4 | import org.inventivetalent.murder.Murder; 5 | import org.inventivetalent.murder.arena.spawn.SpawnPoint; 6 | import org.inventivetalent.murder.arena.spawn.SpawnType; 7 | import org.inventivetalent.murder.game.Game; 8 | import org.inventivetalent.murder.game.state.GameState; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class DropLootExecutor extends IngameExecutor { 14 | 15 | boolean firstTick = true; 16 | int lootSeconds = 0; 17 | 18 | List lootSpawnPoints; 19 | int dropIndex = 0; 20 | 21 | public DropLootExecutor(Game game) { 22 | super(game); 23 | game.ticks = 0; 24 | lootSpawnPoints = new ArrayList<>(game.arena.getSpawnPoints(SpawnType.LOOT)); 25 | } 26 | 27 | @Override 28 | public void tick() { 29 | super.tick(); 30 | 31 | if (firstTick) { 32 | firstTick = false; 33 | updatePlayerStates(GameState.DROP_LOOT, null); 34 | } else { 35 | game.ticks++; 36 | if (game.ticks >= 20) { 37 | lootSeconds++; 38 | if (!game.droppingLoot) {// wait until the delay is over 39 | if (lootSeconds >= Murder.instance.lootDelay) { 40 | lootSeconds = 0; 41 | game.droppingLoot = true; 42 | } 43 | } else {// drop loot 44 | if (lootSeconds >= Murder.instance.lootInterval) { 45 | lootSeconds = 0; 46 | 47 | if (!lootSpawnPoints.isEmpty()) { 48 | if (dropIndex >= lootSpawnPoints.size()) { 49 | dropIndex = 0; 50 | } 51 | SpawnPoint point = lootSpawnPoints.get(dropIndex); 52 | Item dropped = game.arena.getWorld().dropItemNaturally(point.getLocation(game.arena.getWorld()), Murder.instance.itemManager.getLoot()); 53 | game.droppedItems.add(dropped); 54 | 55 | dropIndex++; 56 | } 57 | } 58 | } 59 | 60 | game.ticks = 0; 61 | } 62 | } 63 | } 64 | 65 | @Override 66 | public boolean finished() { 67 | return super.finished(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/LeavableExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.potion.PotionEffect; 5 | import org.inventivetalent.murder.Murder; 6 | import org.inventivetalent.murder.game.Game; 7 | import org.inventivetalent.murder.game.state.StateExecutor; 8 | import org.inventivetalent.murder.player.PlayerData; 9 | 10 | import java.util.UUID; 11 | 12 | public class LeavableExecutor extends StateExecutor { 13 | 14 | public LeavableExecutor(Game game) { 15 | super(game); 16 | } 17 | 18 | @Override 19 | public void tick() { 20 | if (!game.leavingPlayers.isEmpty()) { 21 | for (UUID uuid : game.leavingPlayers) { 22 | game.players.remove(uuid); 23 | game.broadcastLeave(uuid); 24 | 25 | PlayerData data = Murder.instance.playerManager.getData(uuid); 26 | if (data != null) { 27 | data.gameId = null; 28 | if (data.getOfflinePlayer().isOnline()) { 29 | //Remove black screen 30 | data.getPlayer().getInventory().setHelmet(null); 31 | 32 | //Clear effects 33 | for (PotionEffect effect : data.getPlayer().getActivePotionEffects()) { 34 | data.getPlayer().removePotionEffect(effect.getType()); 35 | } 36 | 37 | data.restoreData(); 38 | Murder.instance.playerManager.resetPlayer(data.getOfflinePlayer()); 39 | 40 | for (UUID uuid1 : game.players) { 41 | Player player = game.getPlayer(uuid1); 42 | if (player != null) { player.showPlayer(data.getPlayer()); } 43 | } 44 | 45 | //Reset resource pack 46 | data.getPlayer().setResourcePack(Murder.instance.resetPackUrl);//TODO: hash 47 | 48 | //Reset BossBar 49 | if (data.bossBar != null) { 50 | data.bossBar.removePlayer(data.getPlayer()); 51 | } 52 | 53 | Murder.instance.playerManager.removeData(uuid); 54 | } 55 | } 56 | } 57 | game.leavingPlayers.clear(); 58 | 59 | Murder.instance.gameManager.refreshSigns(game); 60 | } 61 | 62 | } 63 | 64 | @Override 65 | public boolean finished() { 66 | return super.finished(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/player/PlayerData.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.player; 2 | 3 | import org.bukkit.boss.BossBar; 4 | import org.inventivetalent.murder.Murder; 5 | import org.inventivetalent.murder.Role; 6 | import org.inventivetalent.murder.game.Game; 7 | import org.inventivetalent.murder.game.state.GameState; 8 | 9 | import javax.annotation.Nullable; 10 | import java.util.UUID; 11 | 12 | public class PlayerData extends StoredData { 13 | 14 | public UUID gameId; 15 | 16 | public String nameTag; 17 | public String disguiseTag;// Murderer only 18 | 19 | public GameState gameState = GameState.WAITING; 20 | public Role role; 21 | public boolean isSpectator; 22 | 23 | // public int damageAmount;// Determines when the player is "dead" 24 | public boolean killed = false; 25 | public UUID killer; 26 | 27 | public int reloadTimer;// Delay until the gun is reloaded 28 | public int gunTimeout;// Delay for players who killed innocent bystanders 29 | public int knifeTimout;// Backup delay for the murderer to get their knife back 30 | public int speedTimeout;// Speed-Boost timeout 31 | 32 | public int lootCount; 33 | 34 | public BossBar bossBar; 35 | 36 | public PlayerData(UUID uuid) { 37 | super(uuid); 38 | } 39 | 40 | @Override 41 | public void storeData(boolean clear) { 42 | super.storeData(clear); 43 | Murder.instance.playerManager.saveDataToFile(this); 44 | } 45 | 46 | public boolean isInGame() { 47 | return gameId != null && getGame() != null; 48 | } 49 | 50 | @Nullable 51 | public Game getGame() { 52 | if (gameId == null) { return null; } 53 | return Murder.instance.gameManager.getGame(gameId); 54 | } 55 | 56 | @Override 57 | public boolean equals(Object o) { 58 | if (this == o) { return true; } 59 | if (o == null || getClass() != o.getClass()) { return false; } 60 | if (!super.equals(o)) { return false; } 61 | 62 | PlayerData data = (PlayerData) o; 63 | 64 | if (nameTag != null ? !nameTag.equals(data.nameTag) : data.nameTag != null) { return false; } 65 | return gameState == data.gameState; 66 | 67 | } 68 | 69 | @Override 70 | public int hashCode() { 71 | int result = super.hashCode(); 72 | result = 31 * result + (nameTag != null ? nameTag.hashCode() : 0); 73 | result = 31 * result + (gameState != null ? gameState.hashCode() : 0); 74 | return result; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/arena/spawn/SpawnPoint.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.arena.spawn; 2 | 3 | import com.google.gson.JsonObject; 4 | import org.bukkit.Location; 5 | import org.bukkit.World; 6 | import org.bukkit.util.Vector; 7 | 8 | public class SpawnPoint { 9 | 10 | public final double x; 11 | public final double y; 12 | public final double z; 13 | public final SpawnType type; 14 | 15 | public SpawnPoint(double x, double y, double z, SpawnType type) { 16 | this.x = x; 17 | this.y = y; 18 | this.z = z; 19 | this.type = type; 20 | } 21 | 22 | public SpawnPoint(Vector vector, SpawnType type) { 23 | this(vector.getX(), vector.getY(), vector.getZ(), type); 24 | } 25 | 26 | public SpawnPoint(JsonObject jsonObject) { 27 | this.x = jsonObject.get("x").getAsDouble(); 28 | this.y = jsonObject.get("y").getAsDouble(); 29 | this.z = jsonObject.get("z").getAsDouble(); 30 | this.type = SpawnType.valueOf(jsonObject.get("type").getAsString()); 31 | } 32 | 33 | public Vector getVector() { 34 | return new Vector(x, y, z); 35 | } 36 | 37 | public Location getLocation(World world) { 38 | return new Location(world, x, y, z); 39 | } 40 | 41 | public JsonObject toJson() { 42 | JsonObject jsonObject = new JsonObject(); 43 | 44 | jsonObject.addProperty("x", x); 45 | jsonObject.addProperty("y", y); 46 | jsonObject.addProperty("z", z); 47 | jsonObject.addProperty("type", type.name()); 48 | 49 | return jsonObject; 50 | } 51 | 52 | @Override 53 | public boolean equals(Object o) { 54 | if (this == o) { return true; } 55 | if (o == null || getClass() != o.getClass()) { return false; } 56 | 57 | SpawnPoint that = (SpawnPoint) o; 58 | 59 | if (Double.compare(that.x, x) != 0) { return false; } 60 | if (Double.compare(that.y, y) != 0) { return false; } 61 | if (Double.compare(that.z, z) != 0) { return false; } 62 | return type == that.type; 63 | 64 | } 65 | 66 | @Override 67 | public int hashCode() { 68 | int result; 69 | long temp; 70 | temp = Double.doubleToLongBits(x); 71 | result = (int) (temp ^ (temp >>> 32)); 72 | temp = Double.doubleToLongBits(y); 73 | result = 31 * result + (int) (temp ^ (temp >>> 32)); 74 | temp = Double.doubleToLongBits(z); 75 | result = 31 * result + (int) (temp ^ (temp >>> 32)); 76 | result = 31 * result + (type != null ? type.hashCode() : 0); 77 | return result; 78 | } 79 | 80 | @Override 81 | public String toString() { 82 | return "SpawnPoint{" + 83 | "x=" + x + 84 | ", y=" + y + 85 | ", z=" + z + 86 | ", type=" + type + 87 | '}'; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/ended/EndedExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.ended; 2 | 3 | import org.inventivetalent.murder.Murder; 4 | import org.inventivetalent.murder.Role; 5 | import org.inventivetalent.murder.game.Game; 6 | import org.inventivetalent.murder.game.state.GameState; 7 | import org.inventivetalent.murder.game.state.executor.LeavableExecutor; 8 | import org.inventivetalent.murder.player.PlayerData; 9 | import org.inventivetalent.pluginannotations.PluginAnnotations; 10 | import org.inventivetalent.pluginannotations.message.MessageFormatter; 11 | import org.inventivetalent.pluginannotations.message.MessageLoader; 12 | 13 | public class EndedExecutor extends LeavableExecutor { 14 | 15 | static MessageLoader MESSAGE_LOADER = PluginAnnotations.MESSAGE.newMessageLoader(Murder.instance, "config.yml", "messages.game", null); 16 | 17 | boolean firstTick = true; 18 | int endSeconds = 0; 19 | 20 | public EndedExecutor(Game game) { 21 | super(game); 22 | game.ticks = 0; 23 | } 24 | 25 | @Override 26 | public void tick() { 27 | super.tick(); 28 | 29 | if (firstTick) { 30 | firstTick = false; 31 | updatePlayerStates(GameState.ENDED, null); 32 | 33 | MessageFormatter murdererFormatter = new MessageFormatter() { 34 | @Override 35 | public String format(String key, String message) { 36 | PlayerData murdererData = Murder.instance.playerManager.getData(game.getMurderer()); 37 | if (murdererData != null) { 38 | return String.format(message, murdererData.nameTag.substring(0, 2) + murdererData.getPlayer().getName(), murdererData.nameTag); 39 | } 40 | return String.format(message, "?", "?"); 41 | } 42 | }; 43 | 44 | if (game.winner == null) { 45 | game.broadcastMessage(MESSAGE_LOADER.getMessage("winner.draw", "winner.draw")); 46 | } else if (game.winner == Role.WEAPON) { 47 | game.broadcastMessage(MESSAGE_LOADER.getMessage("winner.bystander", "winner.bystander", murdererFormatter)); 48 | } else if (game.winner == Role.MURDERER) { 49 | game.broadcastMessage(MESSAGE_LOADER.getMessage("winner.murderer", "winner.murderer", murdererFormatter)); 50 | } else { 51 | Murder.instance.getLogger().warning("Invalid Winner: " + game.winner); 52 | } 53 | //TODO: print scoreboard 54 | } 55 | 56 | game.ticks++; 57 | if (game.ticks >= 20) { 58 | endSeconds++; 59 | game.ticks = 0; 60 | } 61 | 62 | } 63 | 64 | @Override 65 | public boolean finished() { 66 | return super.finished() || endSeconds >= Murder.instance.endDelay; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/GameManager.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game; 2 | 3 | import org.bukkit.block.Sign; 4 | import org.inventivetalent.murder.Murder; 5 | import org.inventivetalent.murder.arena.Arena; 6 | import org.inventivetalent.murder.game.state.GameState; 7 | import org.inventivetalent.murder.game.state.GameTask; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.UUID; 12 | 13 | public class GameManager { 14 | 15 | private Murder plugin; 16 | 17 | public final Map gameMap = new HashMap<>(); 18 | public GameTask gameTask; 19 | 20 | public GameManager(Murder plugin) { 21 | this.plugin = plugin; 22 | gameTask = new GameTask(plugin); 23 | gameTask.runTaskTimer(plugin, 1, 1); 24 | } 25 | 26 | public Game addGame(Game game) { 27 | if (gameMap.containsKey(game.gameId)) { throw new IllegalStateException("Game #" + game.gameId + " is already added"); } 28 | gameMap.put(game.gameId, game); 29 | return game; 30 | } 31 | 32 | public Game getGame(UUID uuid) { 33 | if (!gameMap.containsKey(uuid)) { return null; } 34 | return gameMap.get(uuid); 35 | } 36 | 37 | public Game getGameForArenaId(int id) { 38 | for (Game game : gameMap.values()) { 39 | if (id == game.arena.id) { return game; } 40 | } 41 | return null; 42 | } 43 | 44 | public Game getOrCreateGame(Arena arena) { 45 | Game game = getGameForArenaId(arena.id); 46 | if (game == null) { 47 | game = addGame(new Game(arena)); 48 | } 49 | return game; 50 | } 51 | 52 | public void refreshSigns(Game game) { 53 | for (Sign sign : plugin.arenaManager.getArenaSigns(game.arena.id)) { 54 | if (game.arena.disabled) { 55 | sign.setLine(plugin.signLineState, Game.MESSAGE_LOADER.getMessage("state.disabled.sign", "state.disabled.sign")); 56 | } else if (game.gameState == GameState.DISPOSE) { 57 | sign.setLine(plugin.signLineState, GameState.WAITING.getSignText()); 58 | } else { 59 | sign.setLine(plugin.signLineState, game.gameState.getSignText()); 60 | } 61 | if (game.arena.disabled) { 62 | sign.setLine(plugin.signLinePlayers, String.format(plugin.signFormatPlayers, "-", "-")); 63 | } else if (game.gameState == GameState.DISPOSE) { 64 | sign.setLine(plugin.signLinePlayers, String.format(plugin.signFormatPlayers, 0, game.arena.maxPlayers)); 65 | } else { 66 | sign.setLine(plugin.signLinePlayers, String.format(plugin.signFormatPlayers, game.players.size(), game.arena.maxPlayers)); 67 | } 68 | 69 | sign.update(); 70 | } 71 | } 72 | 73 | public void removeGame(UUID uuid) { 74 | gameMap.remove(uuid); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/command/ToggleCommands.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.command; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.inventivetalent.murder.Murder; 5 | import org.inventivetalent.murder.arena.Arena; 6 | import org.inventivetalent.murder.command.error.MurderErrorHandler; 7 | import org.inventivetalent.murder.game.Game; 8 | import org.inventivetalent.pluginannotations.PluginAnnotations; 9 | import org.inventivetalent.pluginannotations.command.Command; 10 | import org.inventivetalent.pluginannotations.command.JoinedArg; 11 | import org.inventivetalent.pluginannotations.command.Permission; 12 | import org.inventivetalent.pluginannotations.message.MessageLoader; 13 | 14 | public class ToggleCommands { 15 | 16 | static MessageLoader MESSAGE_LOADER = PluginAnnotations.MESSAGE.newMessageLoader(Murder.instance, "config.yml", "messages.command.arena.editor", null); 17 | 18 | private Murder plugin; 19 | 20 | public ToggleCommands(Murder plugin) { 21 | this.plugin = plugin; 22 | } 23 | 24 | @Command(name = "murderEnable", 25 | description = "Enable an arena", 26 | aliases = { 27 | "mEnable", 28 | "me" }, 29 | usage = "", 30 | errorHandler = MurderErrorHandler.class) 31 | @Permission("murder.arena.toggle") 32 | public void enable(Player sender, @JoinedArg String name) { 33 | Arena arena = plugin.arenaManager.getArenaByName(name); 34 | if (arena == null) { 35 | sender.sendMessage(MESSAGE_LOADER.getMessage("error.notFound", "error.notFound")); 36 | return; 37 | } 38 | plugin.arenaManager.removeArena(arena); 39 | arena.disabled = false; 40 | plugin.arenaManager.addArena(arena); 41 | 42 | sender.sendMessage(MESSAGE_LOADER.getMessage("toggle.enable", "toggle.enable")); 43 | } 44 | 45 | @Command(name = "murderDisable", 46 | description = "Disable an arena", 47 | aliases = { 48 | "mDisable", 49 | "md" }, 50 | usage = "", 51 | errorHandler = MurderErrorHandler.class) 52 | @Permission("murder.arena.toggle") 53 | public void disable(Player sender, @JoinedArg String name) { 54 | Arena arena = plugin.arenaManager.getArenaByName(name); 55 | if (arena == null) { 56 | sender.sendMessage(MESSAGE_LOADER.getMessage("error.notFound", "error.notFound")); 57 | return; 58 | } 59 | Game game = plugin.gameManager.getGameForArenaId(arena.id); 60 | if (game != null) { game.kickAllPlayers(); } 61 | 62 | plugin.arenaManager.removeArena(arena); 63 | arena.disabled = true; 64 | plugin.arenaManager.addArena(arena); 65 | sender.sendMessage(MESSAGE_LOADER.getMessage("toggle.disable", "toggle.disable")); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/CountdownExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor; 2 | 3 | import org.inventivetalent.murder.Murder; 4 | import org.inventivetalent.murder.game.CountdownType; 5 | import org.inventivetalent.murder.game.Game; 6 | import org.inventivetalent.pluginannotations.message.MessageFormatter; 7 | 8 | public class CountdownExecutor extends LeavableExecutor { 9 | 10 | public CountdownType type; 11 | 12 | public CountdownExecutor(Game game, CountdownType type) { 13 | super(game); 14 | this.type = type; 15 | // resetTime(); 16 | } 17 | 18 | protected void resetTime() { 19 | if (type == CountdownType.LOBBY) { 20 | game.lobbyCountdown = Murder.instance.lobbyTime; 21 | } 22 | if (type == CountdownType.START) { 23 | game.startCountdown = Murder.instance.startTime; 24 | } 25 | } 26 | 27 | @Override 28 | public void tick() { 29 | super.tick(); 30 | game.ticks++; 31 | if (game.ticks >= 20) { 32 | if (type == CountdownType.LOBBY) { 33 | if (game.players.size() >= game.arena.minPlayers) { 34 | game.lobbyCountdown--; 35 | if ((game.lobbyCountdown + 1) % 10 == 0 || game.lobbyCountdown < 5) { 36 | game.broadcastMessage(Game.MESSAGE_LOADER.getMessage("countdown.lobby.time", "countdown.lobby.time", new MessageFormatter() { 37 | @Override 38 | public String format(String key, String message) { 39 | return String.format(message, game.lobbyCountdown + 1); 40 | } 41 | })); 42 | } 43 | } else { 44 | //Not enough players 45 | if (game.lobbyCountdown < Murder.instance.lobbyTime) {//We actually started the countdown 46 | resetTime(); 47 | game.broadcastMessage(Game.MESSAGE_LOADER.getMessage("countdown.lobby.cancel", "countdown.lobby.cancel")); 48 | } 49 | } 50 | } 51 | if (type == CountdownType.START) { 52 | game.startCountdown--; 53 | if ((game.startCountdown + 1) % 10 == 0 || game.startCountdown < 5) { 54 | game.broadcastMessage(Game.MESSAGE_LOADER.getMessage("countdown.start.time", "countdown.start.time", new MessageFormatter() { 55 | @Override 56 | public String format(String key, String message) { 57 | return String.format(message, game.startCountdown + 1); 58 | } 59 | })); 60 | } 61 | } 62 | game.ticks = 0; 63 | } 64 | } 65 | 66 | @Override 67 | public boolean finished() { 68 | if (type == CountdownType.LOBBY) { return game.lobbyCountdown <= 0; } 69 | if (type == CountdownType.START) { return game.startCountdown <= 0; } 70 | return super.finished(); 71 | } 72 | 73 | @Override 74 | public boolean revert() { 75 | return false; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/Role.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder; 2 | 3 | import org.bukkit.boss.BarColor; 4 | import org.bukkit.boss.BarStyle; 5 | import org.inventivetalent.pluginannotations.PluginAnnotations; 6 | import org.inventivetalent.pluginannotations.message.MessageLoader; 7 | 8 | public enum Role { 9 | 10 | /* Default Bystander */ 11 | DEFAULT("default.name", "default.title", "default.subtitle", "default.objective", "default.bossbar.text", "default.bossbar.color", "default.bossbar.style"), 12 | MURDERER("murderer.name", "murderer.title", "murderer.subtitle", "murderer.objective", "murderer.bossbar.text", "murderer.bossbar.color", "murderer.bossbar.style"), 13 | WEAPON("weapon.name", "weapon.title", "weapon.subtitle", "weapon.objective", "weapon.bossbar.text", "weapon.bossbar.color", "weapon.bossbar.style") 14 | /*,SPECTATOR("spectator.name", null, null, null, null, null, null)*/; 15 | 16 | private String nameKey; 17 | private String titleKey; 18 | private String subTitleKey; 19 | private String objectiveKey; 20 | private String barTextKey; 21 | private String barColorKey; 22 | private String barStyleKey; 23 | 24 | private static final MessageLoader MESSAGE_LOADER = PluginAnnotations.MESSAGE.newMessageLoader(Murder.instance, "config.yml", "messages.role", null); 25 | 26 | Role(String nameKey, String titleKey, String subTitleKey, String objectiveKey, String barTextKey, String barColorKey, String barStyleKey) { 27 | this.nameKey = nameKey; 28 | this.titleKey = titleKey; 29 | this.subTitleKey = subTitleKey; 30 | this.objectiveKey = objectiveKey; 31 | this.barTextKey = barTextKey; 32 | this.barColorKey = barColorKey; 33 | this.barStyleKey = barStyleKey; 34 | } 35 | 36 | public String getName() { 37 | return MESSAGE_LOADER.getMessage(nameKey, nameKey); 38 | } 39 | 40 | public String getTitle() { 41 | return MESSAGE_LOADER.getMessage(titleKey, titleKey); 42 | } 43 | 44 | public String getSubTitle() { 45 | return MESSAGE_LOADER.getMessage(subTitleKey, subTitleKey); 46 | } 47 | 48 | public String getObjective() { 49 | return MESSAGE_LOADER.getMessage(objectiveKey, objectiveKey); 50 | } 51 | 52 | public String getBarText() { 53 | return MESSAGE_LOADER.getMessage(barTextKey, barTextKey); 54 | } 55 | 56 | public BarColor getBarColor() { 57 | String value = MESSAGE_LOADER.getMessage(barColorKey, null); 58 | if (value == null) { return BarColor.WHITE; } 59 | return BarColor.valueOf(value.toUpperCase()); 60 | } 61 | 62 | public BarStyle getBarStyle() { 63 | String value = MESSAGE_LOADER.getMessage(barStyleKey, null); 64 | if (value == null) { return BarStyle.SOLID; } 65 | return BarStyle.valueOf(value.toUpperCase()); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/game/state/executor/starting/AssignExecutor.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.game.state.executor.starting; 2 | 3 | import net.md_5.bungee.api.chat.TextComponent; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.boss.BarFlag; 6 | import org.inventivetalent.murder.Murder; 7 | import org.inventivetalent.murder.Role; 8 | import org.inventivetalent.murder.game.CountdownType; 9 | import org.inventivetalent.murder.game.Game; 10 | import org.inventivetalent.murder.game.state.GameState; 11 | import org.inventivetalent.murder.game.state.executor.CountdownExecutor; 12 | import org.inventivetalent.murder.player.PlayerData; 13 | import org.inventivetalent.title.TitleAPI; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Random; 18 | import java.util.UUID; 19 | 20 | public class AssignExecutor extends CountdownExecutor { 21 | 22 | int ticks = 0; 23 | Random random = new Random(); 24 | 25 | public AssignExecutor(Game game) { 26 | super(game, CountdownType.START); 27 | } 28 | 29 | @Override 30 | public void tick() { 31 | super.tick(); 32 | if (ticks == 0) { 33 | updatePlayerStates(GameState.ASSIGN, null); 34 | } 35 | if (ticks == 1) {//Assign 36 | List toAssign = new ArrayList<>(game.players); 37 | 38 | //Pick a murderer 39 | updateRole(toAssign.remove(random.nextInt(toAssign.size())), Role.MURDERER); 40 | 41 | //Pick a weapon bystander 42 | updateRole(toAssign.remove(random.nextInt(toAssign.size())), Role.WEAPON); 43 | 44 | //Make all other players bystanders 45 | while (!toAssign.isEmpty()) { 46 | updateRole(toAssign.remove(0), Role.DEFAULT); 47 | } 48 | } 49 | if (ticks == 2) {//Send role messages 50 | for (UUID uuid : game.players) { 51 | PlayerData data = Murder.instance.playerManager.getData(uuid); 52 | 53 | //Titles 54 | TitleAPI.reset(data.getPlayer()); 55 | TitleAPI.sendTimings(data.getPlayer(), 10, (Murder.instance.startTime * 20) - 5, 10); 56 | TitleAPI.sendSubTitle(data.getPlayer(), new TextComponent(data.role.getSubTitle())); 57 | TitleAPI.sendTitle(data.getPlayer(), new TextComponent(data.role.getTitle())); 58 | 59 | //BossBar 60 | TextComponent textComponent = new TextComponent(String.format(data.role.getBarText(), data.nameTag)); 61 | data.bossBar = Bukkit.createBossBar(textComponent.getText(), data.role.getBarColor(), data.role.getBarStyle(), BarFlag.DARKEN_SKY); 62 | data.bossBar.addPlayer(data.getPlayer()); 63 | } 64 | } 65 | ticks++; 66 | } 67 | 68 | void updateRole(UUID uuid, Role role) { 69 | PlayerData data = Murder.instance.playerManager.getData(uuid); 70 | data.role = role; 71 | } 72 | 73 | @Override 74 | public boolean finished() { 75 | return super.finished() || ticks >= 3; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/player/PlayerManager.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.player; 2 | 3 | import org.bukkit.OfflinePlayer; 4 | import org.inventivetalent.murder.Murder; 5 | 6 | import javax.annotation.Nonnull; 7 | import javax.annotation.Nullable; 8 | import java.io.File; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.UUID; 12 | 13 | public class PlayerManager { 14 | 15 | private Murder plugin; 16 | 17 | // @ConfigValue(path = "storePlayerData") public boolean storePlayerData; 18 | public File dataFolder; 19 | 20 | public final Map dataMap = new HashMap<>(); 21 | 22 | public PlayerManager(Murder plugin) { 23 | this.plugin = plugin; 24 | dataFolder = new File(plugin.getDataFolder(), "playerdata"); 25 | if (!dataFolder.exists()) { 26 | dataFolder.mkdirs(); 27 | } 28 | } 29 | 30 | public boolean contains(UUID uuid) { 31 | return dataMap.containsKey(uuid); 32 | } 33 | 34 | @Nullable 35 | public PlayerData getData(@Nullable UUID uuid) { 36 | if (uuid == null) { return null; } 37 | if (dataMap.containsKey(uuid)) { return dataMap.get(uuid); } 38 | return loadFromFile(uuid); 39 | } 40 | 41 | @Nonnull 42 | public PlayerData getOrCreateData(UUID uuid) { 43 | if (!dataMap.containsKey(uuid)) { 44 | dataMap.put(uuid, new PlayerData(uuid)); 45 | } 46 | return dataMap.get(uuid); 47 | } 48 | 49 | @Nullable 50 | public PlayerData removeData(UUID uuid) { 51 | deleteDataFile(uuid); 52 | if (dataMap.containsKey(uuid)) { 53 | return dataMap.remove(uuid); 54 | } 55 | return null; 56 | } 57 | 58 | @Nonnull 59 | public File saveDataToFile(PlayerData toSave) { 60 | try { 61 | File file = new File(dataFolder, toSave.uuid.toString()); 62 | if (!file.exists()) { 63 | file.createNewFile(); 64 | } 65 | toSave.saveToFile(file); 66 | return file; 67 | } catch (Exception e) { 68 | throw new RuntimeException(e); 69 | } 70 | } 71 | 72 | @Nonnull 73 | public PlayerData loadFromFile(@Nonnull UUID uuid) { 74 | try { 75 | File file = new File(dataFolder, uuid.toString()); 76 | PlayerData data = getOrCreateData(uuid); 77 | if (!file.exists()) { return data; } 78 | data.loadFromFile(file); 79 | data.stored = true; 80 | return data; 81 | } catch (Exception e) { 82 | throw new RuntimeException(e); 83 | } 84 | } 85 | 86 | public boolean deleteDataFile(UUID uuid) { 87 | File file = new File(dataFolder, uuid.toString()); 88 | return file.delete(); 89 | } 90 | 91 | public void disguisePlayer(@Nonnull OfflinePlayer player, @Nonnull String name) { 92 | plugin.nameManager.setNameTag(player, name); 93 | plugin.skinManager.setSkin(player, name.substring(1, 2)); 94 | } 95 | 96 | public void resetPlayer(@Nonnull OfflinePlayer player) { 97 | plugin.nameManager.setNameTag(player, null); 98 | plugin.skinManager.setSkin(player, null); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/item/ItemManager.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.item; 2 | 3 | import org.bukkit.Material; 4 | import org.bukkit.configuration.ConfigurationSection; 5 | import org.bukkit.inventory.ItemStack; 6 | import org.bukkit.inventory.meta.ItemMeta; 7 | import org.inventivetalent.itembuilder.ItemBuilder; 8 | import org.inventivetalent.murder.Murder; 9 | 10 | public class ItemManager { 11 | 12 | private Murder plugin; 13 | public ConfigurationSection itemSection; 14 | 15 | public ItemManager(Murder plugin) { 16 | this.plugin = plugin; 17 | itemSection = plugin.getConfig().getConfigurationSection("items"); 18 | } 19 | 20 | public boolean lazyEqual(ItemStack a, ItemStack b) { 21 | if (a == null || b == null) { return false; } 22 | if (a.getType() != b.getType()) { return false; } 23 | ItemMeta aMeta = a.getItemMeta(); 24 | ItemMeta bMeta = b.getItemMeta(); 25 | if (!aMeta.getDisplayName().equals(bMeta.getDisplayName())) { return false; } 26 | return true; 27 | } 28 | 29 | //Game Items 30 | 31 | public ItemStack getKnife() { 32 | return new ItemBuilder(Material.DIAMOND_AXE).fromConfig(itemSection.getConfigurationSection("knife")).build(); 33 | } 34 | 35 | public ItemStack getGun() { 36 | return new ItemBuilder(Material.DIAMOND_HOE).fromConfig(itemSection.getConfigurationSection("gun")).build(); 37 | } 38 | 39 | public ItemStack getBullet() { 40 | return new ItemBuilder(Material.ARROW).fromConfig(itemSection.getConfigurationSection("bullet")).build(); 41 | } 42 | 43 | public ItemStack getLoot() { 44 | return new ItemBuilder(Material.DIAMOND).fromConfig(itemSection.getConfigurationSection("loot")).build(); 45 | } 46 | 47 | public ItemStack getNameInfo(String name) { 48 | //noinspection ConstantConditions 49 | return new ItemBuilder(Material.NAME_TAG).fromConfig(itemSection.getConfigurationSection("nameInfo")).buildMeta().withFormat("%s", name).item().build(); 50 | } 51 | 52 | public ItemStack getSpeedBoost() { 53 | return new ItemBuilder(Material.SUGAR).fromConfig(itemSection.getConfigurationSection("speedBoost")).build(); 54 | } 55 | 56 | public ItemStack getTeleporter() { 57 | return new ItemBuilder(Material.COMPASS).fromConfig(itemSection.getConfigurationSection("teleporter")).build(); 58 | } 59 | 60 | //Editor Items 61 | 62 | public ItemStack getBoundsSelector() { 63 | return new ItemBuilder(Material.GOLD_AXE).fromConfig(itemSection.getConfigurationSection("editor.arena.boundsSelector")).build(); 64 | } 65 | 66 | public ItemStack getLobbySpawnSelector() { 67 | return new ItemBuilder(Material.REDSTONE_BLOCK).fromConfig(itemSection.getConfigurationSection("editor.arena.spawnSelector.lobby")).build(); 68 | } 69 | 70 | public ItemStack getPlayerSpawnSelector() { 71 | return new ItemBuilder(Material.EMERALD_BLOCK).fromConfig(itemSection.getConfigurationSection("editor.arena.spawnSelector.player")).build(); 72 | } 73 | 74 | public ItemStack getLootSpawnSelector() { 75 | return new ItemBuilder(Material.DIAMOND_BLOCK).fromConfig(itemSection.getConfigurationSection("editor.arena.spawnSelector.loot")).build(); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/command/error/MurderErrorHandler.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.command.error; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandSender; 5 | import org.inventivetalent.murder.Murder; 6 | import org.inventivetalent.pluginannotations.PluginAnnotations; 7 | import org.inventivetalent.pluginannotations.command.CommandErrorHandler; 8 | import org.inventivetalent.pluginannotations.command.exception.*; 9 | import org.inventivetalent.pluginannotations.message.MessageFormatter; 10 | import org.inventivetalent.pluginannotations.message.MessageLoader; 11 | 12 | import java.util.logging.Level; 13 | 14 | public class MurderErrorHandler extends CommandErrorHandler { 15 | 16 | static MessageLoader MESSAGE_LOADER = PluginAnnotations.MESSAGE.newMessageLoader(Murder.instance, "config.yml", "messages.command.error", null); 17 | 18 | @Override 19 | public void handleCommandException(CommandException exception, CommandSender sender, Command command, String[] args) { 20 | sender.sendMessage(MESSAGE_LOADER.getMessage("unknown", "unknown")); 21 | Murder.instance.getLogger().log(Level.SEVERE, "Unknown exception while executing '/" + command.getName() + "' for " + sender.getName(), exception); 22 | } 23 | 24 | @Override 25 | public void handlePermissionException(final PermissionException exception, CommandSender sender, Command command, String[] args) { 26 | sender.sendMessage(MESSAGE_LOADER.getMessage("permission", "permission", new MessageFormatter() { 27 | @Override 28 | public String format(String key, String message) { 29 | return String.format(message, exception.getPermission()); 30 | } 31 | })); 32 | } 33 | 34 | @Override 35 | public void handleIllegalSender(IllegalSenderException exception, CommandSender sender, Command command, String[] args) { 36 | sender.sendMessage(MESSAGE_LOADER.getMessage("illegalSender", "illegalSender")); 37 | } 38 | 39 | @Override 40 | public void handleUnhandled(UnhandledCommandException exception, CommandSender sender, Command command, String[] args) { 41 | sender.sendMessage(MESSAGE_LOADER.getMessage("unhandled", "unhandled")); 42 | Murder.instance.getLogger().log(Level.SEVERE, "Unhandled exception while executing '/" + command.getName() + "' for " + sender.getName(), exception); 43 | } 44 | 45 | @Override 46 | public void handleLength(InvalidLengthException exception, CommandSender sender, final Command command, String[] args) { 47 | MessageFormatter usageFormatter = new MessageFormatter() { 48 | @Override 49 | public String format(String key, String message) { 50 | return String.format(message, command.getUsage()); 51 | } 52 | }; 53 | if (exception.getGivenLength() > exception.getExpectedLength()) { 54 | sender.sendMessage(MESSAGE_LOADER.getMessage("length.long", "length.long", usageFormatter)); 55 | } else { 56 | sender.sendMessage(MESSAGE_LOADER.getMessage("length.short", "length.short", usageFormatter)); 57 | } 58 | } 59 | 60 | @Override 61 | public void handleArgumentParse(final ArgumentParseException exception, CommandSender sender, Command command, String[] args) { 62 | sender.sendMessage(MESSAGE_LOADER.getMessage("parse", "parse", new MessageFormatter() { 63 | @Override 64 | public String format(String key, String message) { 65 | return String.format(message, exception.getArgument(), exception.getParameterType().getSimpleName()); 66 | } 67 | })); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/listener/CorpseListener.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.listener; 2 | 3 | import net.md_5.bungee.api.chat.TextComponent; 4 | import org.bukkit.entity.Entity; 5 | import org.bukkit.entity.EntityType; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.player.PlayerInteractEvent; 10 | import org.inventivetalent.murder.Murder; 11 | import org.inventivetalent.murder.Role; 12 | import org.inventivetalent.murder.player.PlayerData; 13 | import org.inventivetalent.npclib.NPCLib; 14 | import org.inventivetalent.npclib.event.NPCCollisionEvent; 15 | import org.inventivetalent.pluginannotations.PluginAnnotations; 16 | import org.inventivetalent.pluginannotations.message.MessageFormatter; 17 | import org.inventivetalent.pluginannotations.message.MessageLoader; 18 | import org.inventivetalent.title.TitleAPI; 19 | 20 | public class CorpseListener implements Listener { 21 | 22 | static MessageLoader MESSAGE_LOADER = PluginAnnotations.MESSAGE.newMessageLoader(Murder.instance, "config.yml", "messages.game", null); 23 | 24 | private Murder plugin; 25 | 26 | public CorpseListener(Murder plugin) { 27 | this.plugin = plugin; 28 | } 29 | 30 | @EventHandler 31 | public void on(final NPCCollisionEvent event) { 32 | if (event.getEntity() != null && event.getEntity().getType() == EntityType.PLAYER) { 33 | Player player = (Player) event.getEntity(); 34 | PlayerData data = plugin.playerManager.getData(player.getUniqueId()); 35 | if (data != null) { 36 | if (data.isInGame() && data.getGame() != null) { 37 | if (!data.isSpectator && data.role == Role.MURDERER) { 38 | TitleAPI.sendTimings(player, 0, 10, 5); 39 | if (data.lootCount > 0) { 40 | TitleAPI.sendSubTitle(player, new TextComponent(MESSAGE_LOADER.getMessage("disguise.info", "disguise.info", new MessageFormatter() { 41 | @Override 42 | public String format(String key, String message) { 43 | return String.format(message, event.getNpc().getName()); 44 | } 45 | }))); 46 | } else { 47 | TitleAPI.sendSubTitle(player, new TextComponent(MESSAGE_LOADER.getMessage("disguise.error", "disguise.error"))); 48 | } 49 | TitleAPI.sendTitle(player, new TextComponent("")); 50 | } 51 | } 52 | } 53 | } 54 | } 55 | 56 | @EventHandler 57 | public void on(PlayerInteractEvent event) { 58 | Player player = event.getPlayer(); 59 | PlayerData data = plugin.playerManager.getData(player.getUniqueId()); 60 | if (data != null && data.isInGame() && data.getGame() != null) { 61 | if (!data.isSpectator && data.role == Role.MURDERER) { 62 | for (final Entity entity : player.getNearbyEntities(1, 2, 1)) { 63 | if (NPCLib.isNPC(entity)) { 64 | if (data.lootCount > 0) { 65 | data.lootCount--; 66 | player.setLevel(data.lootCount); 67 | 68 | String originalNametag = data.nameTag; 69 | data.disguiseTag = entity.getName(); 70 | plugin.playerManager.disguisePlayer(player, entity.getName()); 71 | data.nameTag = originalNametag; 72 | player.sendMessage(MESSAGE_LOADER.getMessage("disguise.disguised", "disguise.disguised", new MessageFormatter() { 73 | @Override 74 | public String format(String key, String message) { 75 | return String.format(message, entity.getName()); 76 | } 77 | })); 78 | } 79 | break; 80 | } 81 | } 82 | } 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/spectate/SpectateManager.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.spectate; 2 | 3 | import org.bukkit.GameMode; 4 | import org.bukkit.Material; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.event.inventory.ClickType; 7 | import org.bukkit.inventory.ItemStack; 8 | import org.inventivetalent.itembuilder.ItemBuilder; 9 | import org.inventivetalent.itembuilder.SkullMetaBuilder; 10 | import org.inventivetalent.menubuilder.inventory.InventoryMenuBuilder; 11 | import org.inventivetalent.menubuilder.inventory.ItemListener; 12 | import org.inventivetalent.murder.Murder; 13 | import org.inventivetalent.murder.game.Game; 14 | import org.inventivetalent.murder.player.PlayerData; 15 | import org.inventivetalent.pluginannotations.PluginAnnotations; 16 | import org.inventivetalent.pluginannotations.message.MessageLoader; 17 | 18 | import java.util.Set; 19 | import java.util.UUID; 20 | 21 | public class SpectateManager { 22 | 23 | static MessageLoader MESSAGE_LOADER = PluginAnnotations.MESSAGE.newMessageLoader(Murder.instance, "config.yml", "messages.game.spectate", null); 24 | 25 | private Murder plugin; 26 | 27 | public SpectateManager(Murder plugin) { 28 | this.plugin = plugin; 29 | } 30 | 31 | public boolean teleportToClosestPlayer(PlayerData who) { 32 | Game game = plugin.gameManager.getGame(who.gameId); 33 | if (game != null) { 34 | PlayerData closest = null; 35 | double closestDistance = Double.MAX_VALUE; 36 | for (UUID uuid : game.players) { 37 | if (uuid.equals(who.uuid)) { continue; } 38 | PlayerData data = plugin.playerManager.getData(uuid); 39 | if (data == null) { continue; } 40 | double distance = data.getPlayer().getLocation().distanceSquared(who.getPlayer().getLocation()); 41 | if (distance < closestDistance) { 42 | closestDistance = distance; 43 | closest = data; 44 | } 45 | } 46 | if (closest != null) { 47 | who.getPlayer().teleport(closest.getPlayer().getLocation()); 48 | return true; 49 | } 50 | } 51 | return false; 52 | } 53 | 54 | public void openSpectatorMenu(PlayerData data) { 55 | Game game = plugin.gameManager.getGame(data.gameId); 56 | if (game != null) { 57 | Set aliveIds = game.getAlivePlayers(); 58 | int aliveCount = aliveIds.size(); 59 | InventoryMenuBuilder menuBuilder = new InventoryMenuBuilder(aliveCount <= 9 ? 9 : aliveCount <= 18 ? 18 : aliveCount <= 27 ? 27 : 36, MESSAGE_LOADER.getMessage("menu.title", "menu.title")); 60 | 61 | int slot = 0; 62 | for (UUID uuid : aliveIds) { 63 | final PlayerData data1 = plugin.playerManager.getData(uuid); 64 | if (data1 != null) { 65 | ItemBuilder itemBuilder = new ItemBuilder(Material.SKULL_ITEM, 1, 3); 66 | SkullMetaBuilder metaBuilder = itemBuilder.buildMeta().withDisplayName(data1.nameTag).convertBuilder(SkullMetaBuilder.class); 67 | metaBuilder.withOwner(data1.getPlayer().getName()); 68 | metaBuilder.withLore("§7(" + data1.getPlayer().getName() + "§7)"); 69 | itemBuilder = metaBuilder.item(); 70 | 71 | menuBuilder.withItem(slot++, itemBuilder.build(), new ItemListener() { 72 | @Override 73 | public void onInteract(Player player, ClickType clickType, ItemStack itemStack) { 74 | if (player == null || data1.getPlayer() == null) { return; } 75 | player.teleport(data1.getPlayer().getLocation()); 76 | 77 | player.setGameMode(GameMode.SPECTATOR); 78 | player.setSpectatorTarget(data1.getPlayer()); 79 | } 80 | }, InventoryMenuBuilder.ALL_CLICK_TYPES); 81 | } 82 | } 83 | 84 | menuBuilder.show(data.getPlayer()); 85 | } 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/org/inventivetalent/murder/command/CountdownCommands.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.murder.command; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.inventivetalent.murder.Murder; 5 | import org.inventivetalent.murder.arena.Arena; 6 | import org.inventivetalent.murder.command.error.MurderErrorHandler; 7 | import org.inventivetalent.murder.game.Game; 8 | import org.inventivetalent.murder.game.state.GameState; 9 | import org.inventivetalent.murder.player.PlayerData; 10 | import org.inventivetalent.pluginannotations.PluginAnnotations; 11 | import org.inventivetalent.pluginannotations.command.Command; 12 | import org.inventivetalent.pluginannotations.command.OptionalArg; 13 | import org.inventivetalent.pluginannotations.command.Permission; 14 | import org.inventivetalent.pluginannotations.message.MessageFormatter; 15 | import org.inventivetalent.pluginannotations.message.MessageLoader; 16 | 17 | public class CountdownCommands { 18 | 19 | static MessageLoader MESSAGE_LOADER = PluginAnnotations.MESSAGE.newMessageLoader(Murder.instance, "config.yml", "messages.command", null); 20 | 21 | private Murder plugin; 22 | 23 | public CountdownCommands(Murder plugin) { 24 | this.plugin = plugin; 25 | } 26 | 27 | @Command(name = "murderCountdown", 28 | aliases = { 29 | "mCountdown", 30 | "mC" }, 31 | usage = "