Implement /ready and basic objective mechanics
This commit is contained in:
		
							
								
								
									
										86
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								TODO.md
									
									
									
									
									
								
							| @@ -1,30 +1,78 @@ | ||||
| # TODO | ||||
| # Objective | ||||
|  | ||||
| [X] Mobs spawn in waves | ||||
| [X] Mobs move towards goal | ||||
| [ ] Mobs carry bomb to goal | ||||
| [X] Mobs arm bomb | ||||
| [X] Bomb explodes | ||||
|  | ||||
| # UX | ||||
|  | ||||
| [X] Wave boss bar | ||||
| [X] Mob count boss bar | ||||
| [X] Stage titles | ||||
| [ ] EXPLOSIONS | ||||
| [ ] Colored titles | ||||
| [ ] Clickable /ready in chat | ||||
| [ ] Sidebar | ||||
|  | ||||
| # Social | ||||
|  | ||||
| [ ] Automatic VC groups for games | ||||
| [ ] DiscordSRV | ||||
| [ ] Plan stats | ||||
| [ ] /invite friends to games | ||||
| [ ] /voterestart | ||||
|  | ||||
| # Mechanics | ||||
|  | ||||
| [ ] Coin drops | ||||
| [ ] Basic setup commands | ||||
| [ ] Config file | ||||
| [ ] Spectator mode | ||||
| [ ] Commands/tools to start warmup countdown/mark 'ready' | ||||
| [ ] Upgrades | ||||
| [ ] Plan stats | ||||
| [ ] Live map editing | ||||
| [ ] Instancing | ||||
| [ ] DiscordSRV | ||||
| [ ] Voice Chat | ||||
| [ ] Player readiness starts countdown | ||||
| [ ] Mob tracking should prioritize bomb | ||||
| [ ] Mobs recover dropped bombs | ||||
| [ ] Bomb carriers are slower | ||||
| [ ] Bonus coins for complete coin pickup | ||||
| [ ] Infinite weapons + armor | ||||
| [ ] Ammo/health spawns | ||||
|  | ||||
| # Scripted waves | ||||
|  | ||||
| [X] Spawn in batches | ||||
| [X] Randomized spawn locations | ||||
| [X] Weighted distributions | ||||
| [X] Batch overlap | ||||
| [ ] Scripted batch overlap/timings | ||||
| [ ] Scripted spawn locations | ||||
| [ ] Bosses | ||||
| [ ] Batch overlap/timing | ||||
|  | ||||
| # Mapping | ||||
|  | ||||
| [ ] Load arenas from config file | ||||
| [ ] Live map editing | ||||
|  | ||||
| # Game lifecycle | ||||
|  | ||||
| [ ] Return to lobby | ||||
| [ ] Join game via sign/commands/something | ||||
| [ ] Bonus coins for complete coin pickup | ||||
| [ ] /list arenas and games | ||||
| [ ] /start a game on an arena | ||||
| [ ] /join games | ||||
| [X] /ready | ||||
| [ ] /leave games | ||||
| [ ] /restart games | ||||
| [X] Spectator mode on death | ||||
| [X] Player readiness starts countdown | ||||
| [ ] Game is automatically closed some time after game over | ||||
| [ ] Return to lobby on leave/close | ||||
| [ ] Instancing | ||||
|  | ||||
| # Cleanup | ||||
| # Powerups | ||||
|  | ||||
| [ ] Generic countdown mechanic | ||||
| [ ]  | ||||
| [ ] Coin pickup range | ||||
| [ ] Coin boost | ||||
| [ ] Knockback on weapons | ||||
| [ ] Damage boost | ||||
| [ ] Speed boost | ||||
| [ ] Health boost | ||||
| [ ] Repair barriers | ||||
|  | ||||
| # Fantasy | ||||
|  | ||||
| [ ] Totems/turrets/stationary weapons | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import org.bukkit.event.Listener; | ||||
| import org.bukkit.event.entity.EntityDeathEvent; | ||||
| import org.bukkit.event.entity.EntityDamageEvent; | ||||
| import org.bukkit.event.entity.EntityCombustEvent; | ||||
| import org.bukkit.event.entity.EntityTargetEvent; | ||||
| import org.bukkit.event.player.PlayerQuitEvent; | ||||
| import org.bukkit.entity.Player; | ||||
|  | ||||
| @@ -32,6 +33,11 @@ public class GameEventHandler implements Listener { | ||||
|     evt.setCancelled(true); | ||||
|   } | ||||
|  | ||||
|   @EventHandler | ||||
|   public void onEntityTarget(EntityTargetEvent evt) { | ||||
|     m_runner.handleEntityRetargeting(evt); | ||||
|   } | ||||
|  | ||||
|   @EventHandler | ||||
|   public void onEntityDamage(EntityDamageEvent evt) { | ||||
|     if (evt.getEntity() instanceof Player) { | ||||
|   | ||||
| @@ -8,13 +8,15 @@ import org.bukkit.World; | ||||
| public class MemoryArena implements Arena { | ||||
|  | ||||
|   Spawnpoint[] m_spawnpoints; | ||||
|   Spawnpoint m_bombTarget; | ||||
|   World m_world; | ||||
|   String m_name; | ||||
|  | ||||
|   public MemoryArena(String name, World world, Spawnpoint[] spawnpoints) { | ||||
|   public MemoryArena(String name, World world, Spawnpoint[] spawnpoints, Spawnpoint bombTarget) { | ||||
|     m_world = world; | ||||
|     m_spawnpoints = spawnpoints; | ||||
|     m_name = name; | ||||
|     m_bombTarget = bombTarget; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
| @@ -31,4 +33,9 @@ public class MemoryArena implements Arena { | ||||
|   public World getWorld() { | ||||
|     return m_world; | ||||
|   } | ||||
|    | ||||
|   @Override | ||||
|   public Spawnpoint bombTarget() { | ||||
|     return m_bombTarget; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import org.bukkit.Location; | ||||
| import org.bukkit.entity.Entity; | ||||
| import org.bukkit.entity.EntityType; | ||||
| import org.bukkit.World; | ||||
| import org.bukkit.WorldCreator; | ||||
|  | ||||
| import java.util.logging.Logger; | ||||
| import java.util.logging.Level; | ||||
| @@ -24,6 +25,7 @@ import gg.malloc.defense.engine.GameRunner; | ||||
|  | ||||
| import gg.malloc.defense.commands.AddPlayerCommand; | ||||
| import gg.malloc.defense.commands.SetStageCommand; | ||||
| import gg.malloc.defense.commands.PlayerReadyCommand; | ||||
|  | ||||
| public class Plugin extends JavaPlugin { | ||||
|   ArrayList<Arena> m_arenas = new ArrayList<>(); | ||||
| @@ -65,6 +67,7 @@ public class Plugin extends JavaPlugin { | ||||
|     getCommand("setstage").setExecutor(new SetStageCommand(this)); | ||||
|     getCommand("addplayer").setExecutor(new AddPlayerCommand(this)); | ||||
|     getCommand("debuginfo").setExecutor(new DebuginfoCommand(this)); | ||||
|     getCommand("ready").setExecutor(new PlayerReadyCommand(this)); | ||||
|   } | ||||
|  | ||||
|   public GameRunner getRunnerForWorld(World world) { | ||||
| @@ -81,14 +84,16 @@ public class Plugin extends JavaPlugin { | ||||
|  | ||||
|   void setupDemoGame() { | ||||
|     getLogger().info("Setting up demo data'"); | ||||
|     World testWorld = getServer().getWorld("world"); | ||||
|     Spawnpoint[] spawnpoints = new Spawnpoint[4]; | ||||
|     Location spawnCenter = testWorld.getSpawnLocation(); | ||||
|     for(int i = 0; i < 4; i++) { | ||||
|       Location spawnLocation = spawnCenter.add(Math.random() * 3, 0, Math.random() * 3); | ||||
|       spawnpoints[i] = new TestSpawn(spawnLocation); | ||||
|     World testWorld = getServer().getWorld("quarry"); | ||||
|     if (testWorld == null) { | ||||
|       testWorld = new WorldCreator("quarry").generateStructures(false).createWorld(); | ||||
|     } | ||||
|     m_arenas.add(new MemoryArena("Test Arena", testWorld, spawnpoints)); | ||||
|     Spawnpoint[] spawnpoints = new Spawnpoint[3]; | ||||
|     spawnpoints[0] = new TestSpawn(new Location(testWorld, -15, 80, -46)); | ||||
|     spawnpoints[1] = new TestSpawn(new Location(testWorld, -1, 80, -45)); | ||||
|     spawnpoints[2] = new TestSpawn(new Location(testWorld, 12, 81, -42)); | ||||
|     Spawnpoint bombTarget = new TestSpawn(new Location(testWorld, -20, 80, 31)); | ||||
|     m_arenas.add(new MemoryArena("Test Arena", testWorld, spawnpoints, bombTarget)); | ||||
|     m_games.add(new ScaledWaves()); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,33 @@ | ||||
| package gg.malloc.defense.commands; | ||||
|  | ||||
| import org.bukkit.command.Command; | ||||
| import org.bukkit.command.CommandExecutor; | ||||
| import org.bukkit.command.CommandSender; | ||||
| import org.bukkit.entity.Player; | ||||
|  | ||||
| import gg.malloc.defense.engine.GameRunner; | ||||
|  | ||||
| import gg.malloc.defense.Plugin; | ||||
|  | ||||
| public class PlayerReadyCommand implements CommandExecutor { | ||||
|   Plugin m_plugin; | ||||
|  | ||||
|   public PlayerReadyCommand(Plugin plugin) { | ||||
|     m_plugin = plugin; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public boolean onCommand(CommandSender sender, Command command, String s, String[] args) { | ||||
|     if (sender instanceof Player) { | ||||
|       Player player = (Player)sender; | ||||
|       GameRunner runner = m_plugin.getRunnerForWorld(player.getLocation().getWorld()); | ||||
|       runner.addPlayer(player); | ||||
|       runner.togglePlayerReady(player); | ||||
|       return true; | ||||
|     } else { | ||||
|       sender.sendMessage("You must be a player to use this command."); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -10,14 +10,18 @@ import gg.malloc.defense.Plugin; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| import org.bukkit.Bukkit; | ||||
| import org.bukkit.Sound; | ||||
| import org.bukkit.World; | ||||
| import org.bukkit.boss.BarColor; | ||||
| import org.bukkit.boss.BarStyle; | ||||
| import org.bukkit.boss.BossBar; | ||||
| import org.bukkit.event.player.PlayerTeleportEvent; | ||||
| import org.bukkit.event.entity.EntityTargetEvent; | ||||
| import org.bukkit.event.entity.EntityDamageEvent; | ||||
| import org.bukkit.event.entity.EntityDamageByEntityEvent; | ||||
| import org.bukkit.entity.Entity; | ||||
| import org.bukkit.entity.LivingEntity; | ||||
| import org.bukkit.entity.ArmorStand; | ||||
| import org.bukkit.entity.EntityType; | ||||
| import org.bukkit.entity.Player; | ||||
| import org.bukkit.scheduler.BukkitTask; | ||||
| @@ -30,17 +34,23 @@ public class GameRunner { | ||||
|  | ||||
|   BossBar m_gameBar = Bukkit.createBossBar("Malloc Defense", BarColor.PURPLE, BarStyle.SOLID); | ||||
|   BossBar m_waveBar = Bukkit.createBossBar("Malloc Defense", BarColor.PURPLE, BarStyle.SOLID); | ||||
|   BossBar m_bombBar = Bukkit.createBossBar("Bomb HP", BarColor.RED, BarStyle.SOLID); | ||||
|  | ||||
|   BukkitTask m_countdownTask; | ||||
|  | ||||
|   MobManager m_mobs; | ||||
|   WaveManager m_waves; | ||||
|   PlayerManager m_players; | ||||
|  | ||||
|   LivingEntity m_bombTarget = null; | ||||
|   int m_bombHP = 100; | ||||
|  | ||||
|   Logger m_log; | ||||
|  | ||||
|   public enum Stage { | ||||
|     Idle, | ||||
|     Warmup, | ||||
|     Countdown, | ||||
|     Playing, | ||||
|     GameOver | ||||
|   } | ||||
| @@ -104,6 +114,7 @@ public class GameRunner { | ||||
|     m_stage = Stage.Idle; | ||||
|     m_gameBar.setVisible(true); | ||||
|     m_waveBar.setVisible(false); | ||||
|     m_bombBar.setVisible(false); | ||||
|     m_mobs = new MobManager(m_game); | ||||
|     m_waves = new WaveManager(m_game); | ||||
|     m_players = new PlayerManager(); | ||||
| @@ -112,8 +123,30 @@ public class GameRunner { | ||||
|  | ||||
|   int m_warmupCountdown = 0; | ||||
|  | ||||
|   public void handleEntityRetargeting(EntityTargetEvent evt) { | ||||
|     if (m_mobs.contains(evt.getEntity()) && evt.getReason() == EntityTargetEvent.TargetReason.FORGOT_TARGET) { | ||||
|       evt.setTarget(m_bombTarget); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public void handleEntityDamage(EntityDamageEvent evt) { | ||||
|     m_mobs.handleEntityDamage(evt); | ||||
|     if (evt.getEntity() == m_bombTarget && evt instanceof EntityDamageByEntityEvent) { | ||||
|       EntityDamageByEntityEvent entityEvt = (EntityDamageByEntityEvent)evt; | ||||
|       if (m_mobs.contains(entityEvt.getDamager())) { | ||||
|         entityEvt.getDamager().setGlowing(true); | ||||
|         m_bombHP -= 1; | ||||
|         broadcastMessage("The bomb has been struck!"); | ||||
|         m_arena.getWorld().playSound(m_bombTarget.getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 1.5f, 0.9f); | ||||
|         updateMobBars(); | ||||
|         if (m_bombHP <= 0) { | ||||
|           m_arena.getWorld().strikeLightningEffect(m_bombTarget.getLocation()); | ||||
|           requestTransition(Stage.GameOver); | ||||
|         } | ||||
|       } | ||||
|       evt.setCancelled(true); | ||||
|     } else { | ||||
|       m_mobs.handleEntityDamage(evt); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private void countdownTick() { | ||||
| @@ -130,9 +163,14 @@ public class GameRunner { | ||||
|   } | ||||
|  | ||||
|   private boolean enterIdle() { | ||||
|     m_bombHP = 100; | ||||
|     m_waves.reset(); | ||||
|     m_mobs.clear(); | ||||
|     m_players.requestTransitionForAll(PlayerManager.State.Idle); | ||||
|     if (m_bombTarget != null) { | ||||
|       m_bombTarget.remove(); | ||||
|       m_bombTarget = null; | ||||
|     } | ||||
|     if (m_countdownTask != null) { | ||||
|       m_countdownTask.cancel(); | ||||
|       m_countdownTask = null; | ||||
| @@ -142,25 +180,54 @@ public class GameRunner { | ||||
|  | ||||
|   private boolean enterWarmup() { | ||||
|     m_waves.next(); | ||||
|     m_warmupCountdown = 10; | ||||
|     for(Player p : m_players.getPlayers()) { | ||||
|         if (m_players.requestTransition(p, PlayerManager.State.Playing)) { | ||||
|           p.teleport(m_arena.getWorld().getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); | ||||
|         } | ||||
|         m_players.setReady(p, false); | ||||
|     } | ||||
|     broadcastTitle("Warmup", "Prepare yourself for wave " + m_waves.currentWaveNum()); | ||||
|     m_mobs.clear(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   public void togglePlayerReady(Player p) { | ||||
|     setPlayerReady(p, !m_players.isReady(p)); | ||||
|   } | ||||
|  | ||||
|   public void setPlayerReady(Player p, boolean isReady) { | ||||
|     m_players.setReady(p, isReady); | ||||
|     if (m_players.isEveryoneReady()) { | ||||
|       requestTransition(Stage.Countdown); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private boolean enterCountdown() { | ||||
|     m_warmupCountdown = 10; | ||||
|     countdownTick(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   private boolean enterPlaying() { | ||||
|     m_log.info("Starting wave " + m_waves.currentWaveNum()); | ||||
|     if (m_bombTarget == null) { | ||||
|       m_bombTarget = (LivingEntity)m_arena.getWorld().spawnEntity(m_arena.bombTarget().getLocation(), EntityType.ARMOR_STAND); | ||||
|     } | ||||
|     ArmorStand bombStand = (ArmorStand)m_bombTarget; | ||||
|     bombStand.setCustomName("Bomb Target"); | ||||
|     bombStand.setVisible(true); | ||||
|     bombStand.setCustomNameVisible(true); | ||||
|     bombStand.setGlowing(true); | ||||
|     for(Player p : m_players.getPlayers()) { | ||||
|         if (m_players.requestTransition(p, PlayerManager.State.Playing)) { | ||||
|           p.teleport(m_arena.getWorld().getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); | ||||
|         } | ||||
|     } | ||||
|     spawnNextBatch(); | ||||
|     broadcastTitle("Wave " + m_waves.currentWaveNum()); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|    | ||||
|   private boolean enterGameOver() { | ||||
|     broadcastTitle("Game Over!"); | ||||
|     if (m_countdownTask != null) { | ||||
| @@ -179,18 +246,30 @@ public class GameRunner { | ||||
|     switch(m_stage) { | ||||
|       case Idle: | ||||
|         m_gameBar.setProgress(1.0); | ||||
|         m_gameBar.setTitle("Waiting for playres..."); | ||||
|         m_gameBar.setTitle("Waiting for players..."); | ||||
|         m_gameBar.setColor(BarColor.PURPLE); | ||||
|         m_waveBar.setVisible(false); | ||||
|         m_bombBar.setVisible(false); | ||||
|         break; | ||||
|       case Warmup: | ||||
|         m_gameBar.setProgress(m_waves.progress()); | ||||
|         m_gameBar.setTitle("Wave " + m_waves.currentWaveNum() + " / " + m_game.getWaveCount()); | ||||
|         m_gameBar.setColor(BarColor.PURPLE); | ||||
|         m_waveBar.setVisible(true); | ||||
|         m_waveBar.setColor(BarColor.BLUE); | ||||
|         m_waveBar.setTitle("Warmup - Waiting for players to get ready..."); | ||||
|         m_waveBar.setProgress(m_players.readyProgress()); | ||||
|         m_bombBar.setVisible(false); | ||||
|         break; | ||||
|       case Countdown: | ||||
|         m_gameBar.setProgress(m_waves.progress()); | ||||
|         m_gameBar.setTitle("Wave " + m_waves.currentWaveNum() + " / " + m_game.getWaveCount()); | ||||
|         m_gameBar.setColor(BarColor.PURPLE); | ||||
|         m_waveBar.setVisible(true); | ||||
|         m_waveBar.setColor(BarColor.YELLOW); | ||||
|         m_waveBar.setTitle("Warmup"); | ||||
|         m_waveBar.setTitle("Wave starting!"); | ||||
|         m_waveBar.setProgress((double)m_warmupCountdown / (double)10); | ||||
|         m_bombBar.setVisible(false); | ||||
|         break; | ||||
|       case Playing: | ||||
|         m_gameBar.setProgress(m_waves.progress()); | ||||
| @@ -204,19 +283,22 @@ public class GameRunner { | ||||
|         } else { | ||||
|           m_waveBar.setVisible(false); | ||||
|         } | ||||
|         m_bombBar.setVisible(true); | ||||
|         m_bombBar.setProgress((double)m_bombHP / (double)100); | ||||
|         break; | ||||
|       case GameOver: | ||||
|         m_gameBar.setColor(BarColor.RED); | ||||
|         m_gameBar.setProgress(1.0); | ||||
|         m_gameBar.setTitle("Game Over!"); | ||||
|         m_waveBar.setVisible(false); | ||||
|         m_bombBar.setVisible(false); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private void spawnNextBatch() { | ||||
|     broadcastMessage("Spawning batch " + m_waves.currentBatchNum()); | ||||
|     Spawner spawner = new GameSpawner(m_arena, m_mobs); | ||||
|     Spawner spawner = new GameSpawner(m_arena, m_mobs, m_players, m_bombTarget); | ||||
|     m_waves.currentWave().spawnBatch(spawner, m_waves.currentBatchNum()); | ||||
|     updateMobBars(); | ||||
|   } | ||||
| @@ -265,6 +347,8 @@ public class GameRunner { | ||||
|         return enterIdle(); | ||||
|       case Warmup: | ||||
|         return enterWarmup(); | ||||
|       case Countdown: | ||||
|         return enterCountdown(); | ||||
|       case Playing: | ||||
|         return enterPlaying(); | ||||
|       case GameOver: | ||||
| @@ -278,7 +362,9 @@ public class GameRunner { | ||||
|       case Idle: | ||||
|         return to == Stage.Warmup; | ||||
|       case Warmup: | ||||
|         return to == Stage.Playing || to == Stage.Idle || to == Stage.GameOver; | ||||
|         return to == Stage.Playing || to == Stage.Idle || to == Stage.Countdown ; | ||||
|       case Countdown: | ||||
|         return to == Stage.Playing || to == Stage.Idle || to == Stage.Warmup; | ||||
|       case Playing: | ||||
|         return to == Stage.Warmup || to == Stage.GameOver || to == Stage.Idle; | ||||
|       case GameOver: | ||||
| @@ -306,6 +392,7 @@ public class GameRunner { | ||||
|     m_players.addPlayer(p); | ||||
|     m_gameBar.addPlayer(p); | ||||
|     m_waveBar.addPlayer(p); | ||||
|     m_bombBar.addPlayer(p); | ||||
|     if (m_stage == Stage.Idle || m_stage == Stage.Warmup) { | ||||
|       if (m_players.requestTransition(p, PlayerManager.State.Playing)) { | ||||
|         p.teleport(m_arena.getWorld().getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); | ||||
| @@ -346,5 +433,4 @@ public class GameRunner { | ||||
|   void registerSpawnedMob(Entity entity) { | ||||
|     m_mobs.addEntity(entity); | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -7,15 +7,20 @@ import gg.malloc.defense.model.Arena; | ||||
| import org.bukkit.entity.Entity; | ||||
| import org.bukkit.entity.LivingEntity; | ||||
| import org.bukkit.entity.EntityType; | ||||
| import org.bukkit.entity.Mob; | ||||
|  | ||||
| public class GameSpawner implements Spawner { | ||||
|   Arena m_arena; | ||||
|   MobManager m_manager; | ||||
|   PlayerManager m_players; | ||||
|   LivingEntity m_bombTarget; | ||||
|   int m_spawnIdx = 0; | ||||
|  | ||||
|   public GameSpawner(Arena arena, MobManager manager) { | ||||
|   public GameSpawner(Arena arena, MobManager manager, PlayerManager players, LivingEntity bombTarget) { | ||||
|     m_arena = arena; | ||||
|     m_manager = manager; | ||||
|     m_players = players; | ||||
|     m_bombTarget = bombTarget; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
| @@ -28,6 +33,7 @@ public class GameSpawner implements Spawner { | ||||
|     livingMob.setRemoveWhenFarAway(false); | ||||
|     m_manager.addEntity(newMob); | ||||
|     m_spawnIdx += 1; | ||||
|     ((Mob)newMob).setTarget(m_bombTarget); | ||||
|     return newMob; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -27,6 +27,10 @@ public class MobManager { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public boolean contains(Entity entity) { | ||||
|     return m_livingMobs.contains(entity); | ||||
|   } | ||||
|  | ||||
|   public boolean killMob(Entity entity) { | ||||
|     if (m_livingMobs.contains(entity)) { | ||||
|       m_killedMobs += 1; | ||||
|   | ||||
| @@ -11,6 +11,7 @@ import java.util.Collection; | ||||
|  | ||||
| public class PlayerManager { | ||||
|   HashMap<Player, State> m_playerStates = new HashMap<>(); | ||||
|   HashMap<Player, Boolean> m_playerReadyStates = new HashMap<>(); | ||||
|  | ||||
|   public enum State { | ||||
|     Idle, | ||||
| @@ -70,6 +71,34 @@ public class PlayerManager { | ||||
|   public void addPlayer(Player player) { | ||||
|     //m_log.info("Adding player " + player);  | ||||
|     m_playerStates.put(player, State.Idle); | ||||
|     m_playerReadyStates.put(player, false); | ||||
|   } | ||||
|  | ||||
|   public boolean isReady(Player player) { | ||||
|     return m_playerReadyStates.get(player); | ||||
|   } | ||||
|  | ||||
|   public void setReady(Player player, boolean ready) { | ||||
|     m_playerReadyStates.put(player, ready); | ||||
|   } | ||||
|  | ||||
|   public double readyProgress() { | ||||
|     int readyNum = 0; | ||||
|     for(boolean b : m_playerReadyStates.values()) { | ||||
|       if (b) { | ||||
|         readyNum += 1; | ||||
|       } | ||||
|     } | ||||
|     return (double)readyNum / (double)m_playerReadyStates.size(); | ||||
|   } | ||||
|  | ||||
|   public boolean isEveryoneReady() { | ||||
|     for(boolean b : m_playerReadyStates.values()) { | ||||
|       if (!b) { | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   public boolean removePlayer(Player player) { | ||||
|   | ||||
| @@ -6,4 +6,5 @@ public interface Arena { | ||||
|   World getWorld(); | ||||
|   String name(); | ||||
|   Spawnpoint[] spawnpoints(); | ||||
|   Spawnpoint bombTarget(); | ||||
| } | ||||
|   | ||||
| @@ -10,3 +10,5 @@ commands: | ||||
|     description: Adds a player to a game | ||||
|   debuginfo: | ||||
|     description: Unknowable powers | ||||
|   ready: | ||||
|     description: Mark yourself as ready for the next wave | ||||
|   | ||||
		Reference in New Issue
	
	Block a user