295 lines
7.8 KiB
Java
295 lines
7.8 KiB
Java
package gg.malloc.defense;
|
|
|
|
import gg.malloc.defense.model.Game;
|
|
import gg.malloc.defense.model.Arena;
|
|
import gg.malloc.defense.model.Spawnpoint;
|
|
import gg.malloc.defense.model.Spawner;
|
|
import gg.malloc.defense.model.Wave;
|
|
import java.util.ArrayList;
|
|
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.World;
|
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
|
import org.bukkit.scheduler.BukkitTask;
|
|
import org.bukkit.entity.Entity;
|
|
import org.bukkit.entity.LivingEntity;
|
|
import org.bukkit.entity.EntityType;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.boss.BarColor;
|
|
import org.bukkit.boss.BarStyle;
|
|
import org.bukkit.boss.BossBar;
|
|
import org.bukkit.GameMode;
|
|
import org.bukkit.attribute.Attribute;
|
|
|
|
public class GameRunner {
|
|
ArrayList<Entity> m_spawnedMobs = new ArrayList<Entity>();
|
|
int m_killedMobs = 0;
|
|
Arena m_arena;
|
|
Game m_game;
|
|
State m_state;
|
|
ArrayList<Player> m_players = new ArrayList<>();
|
|
ArrayList<Player> m_livingPlayers = new ArrayList<>();
|
|
Plugin m_plugin;
|
|
|
|
BossBar m_gameBar = Bukkit.createBossBar("Malloc Defense", BarColor.PURPLE, BarStyle.SOLID);
|
|
BukkitTask m_countdownTask;
|
|
|
|
int m_currentWaveNum = 0;
|
|
int m_currentBatch = 0;
|
|
Wave m_currentWave = null;
|
|
|
|
enum State {
|
|
Idle,
|
|
Warmup,
|
|
Playing,
|
|
GameOver
|
|
}
|
|
|
|
public GameRunner(Plugin plugin, Game game, Arena arena) {
|
|
m_plugin = plugin;
|
|
m_game = game;
|
|
m_arena = arena;
|
|
m_state = State.Idle;
|
|
m_gameBar.setVisible(true);
|
|
}
|
|
|
|
int m_warmupCountdown = 0;
|
|
|
|
private void countdownTick() {
|
|
if (m_warmupCountdown == 0) {
|
|
requestTransition(State.Playing);
|
|
} else {
|
|
m_gameBar.setProgress((double)m_warmupCountdown / (double)30);
|
|
broadcastMessage("Starting game in " + m_warmupCountdown);
|
|
m_warmupCountdown--;
|
|
m_countdownTask = m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> {
|
|
countdownTick();
|
|
}, 20);
|
|
}
|
|
}
|
|
|
|
private void clearMobs() {
|
|
for(Entity e : m_spawnedMobs) {
|
|
e.remove();
|
|
}
|
|
m_spawnedMobs.clear();
|
|
}
|
|
|
|
private boolean enterIdle() {
|
|
broadcastMessage("Game state: Idle");
|
|
m_currentWaveNum = 0;
|
|
m_gameBar.setColor(BarColor.PURPLE);
|
|
m_gameBar.setProgress(1.0);
|
|
m_gameBar.setTitle("Idle");
|
|
if (m_countdownTask != null) {
|
|
m_countdownTask.cancel();
|
|
m_countdownTask = null;
|
|
}
|
|
clearMobs();
|
|
return true;
|
|
}
|
|
|
|
private boolean enterWarmup() {
|
|
broadcastMessage("Game state: Warmup");
|
|
m_currentWaveNum += 1;
|
|
m_currentWave = m_game.getWave(m_currentWaveNum);
|
|
m_gameBar.setColor(BarColor.YELLOW);
|
|
m_gameBar.setProgress(1.0);
|
|
m_gameBar.setTitle("Warmup");
|
|
m_warmupCountdown = 30;
|
|
for(Player p : m_players) {
|
|
m_livingPlayers.add(p);
|
|
}
|
|
clearMobs();
|
|
countdownTick();
|
|
return true;
|
|
}
|
|
|
|
private boolean enterPlaying() {
|
|
broadcastMessage("Game state: Playing");
|
|
broadcastMessage("Starting wave " + m_currentWaveNum);
|
|
m_currentBatch = 1;
|
|
m_gameBar.setColor(BarColor.GREEN);
|
|
m_gameBar.setProgress(0.0);
|
|
m_gameBar.setTitle("Playing");
|
|
spawnNextBatch();
|
|
return true;
|
|
}
|
|
|
|
private boolean enterGameOver() {
|
|
broadcastMessage("Game state: Game Over!");
|
|
m_gameBar.setColor(BarColor.RED);
|
|
m_gameBar.setProgress(1.0);
|
|
m_gameBar.setTitle("Game Over!");
|
|
if (m_countdownTask != null) {
|
|
m_countdownTask.cancel();
|
|
m_countdownTask = null;
|
|
}
|
|
for(Player p : m_players) {
|
|
p.setGameMode(GameMode.ADVENTURE);
|
|
}
|
|
clearMobs();
|
|
return true;
|
|
}
|
|
|
|
private void updateMobBar() {
|
|
m_gameBar.setTitle("Mobs remaining: " + (m_currentWave.totalMobCount() - m_killedMobs));
|
|
m_gameBar.setProgress(m_killedMobs / m_currentWave.totalMobCount());
|
|
}
|
|
|
|
private void spawnNextBatch() {
|
|
broadcastMessage("Spawning batch " + m_currentBatch);
|
|
Spawner spawner = new GameSpawner(m_arena.spawnpoints()[0]);
|
|
m_currentWave.spawnBatch(spawner, m_currentBatch);
|
|
updateMobBar();
|
|
}
|
|
|
|
public void handlePlayerDeath(Player player) {
|
|
if (m_livingPlayers.contains(player)) {
|
|
m_livingPlayers.remove(player);
|
|
player.setGameMode(GameMode.SPECTATOR);
|
|
if (m_livingPlayers.size() == 0) {
|
|
broadcastMessage("Everyone is dead :(");
|
|
requestTransition(State.GameOver);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void handleEntityDeath(Entity entity) {
|
|
if (m_spawnedMobs.contains(entity)) {
|
|
broadcastMessage("Killed game entity " + entity);
|
|
m_spawnedMobs.remove(entity);
|
|
m_killedMobs += 1;
|
|
updateMobBar();
|
|
if (m_spawnedMobs.size() == 0) {
|
|
broadcastMessage("Batch complete!");
|
|
if (m_currentBatch >= m_currentWave.batchCount()) {
|
|
if (m_currentWaveNum >= m_game.getWaveCount()) {
|
|
requestTransition(State.GameOver);
|
|
} else {
|
|
requestTransition(State.Warmup);
|
|
}
|
|
} else {
|
|
m_currentBatch += 1;
|
|
spawnNextBatch();
|
|
}
|
|
} else {
|
|
broadcastMessage("Entities remaining: " + m_spawnedMobs.size());
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean syncPlayer(Player player) {
|
|
World playerWorld = player.getLocation().getWorld();
|
|
World gameWorld = m_arena.getWorld();
|
|
m_gameBar.addPlayer(player);
|
|
if (m_livingPlayers.contains(player)) {
|
|
player.setGameMode(GameMode.ADVENTURE);
|
|
player.setHealth(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
|
|
} else {
|
|
player.setGameMode(GameMode.SPECTATOR);
|
|
}
|
|
if (playerWorld != gameWorld) {
|
|
return player.teleport(gameWorld.getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private boolean attemptTransition(State state) {
|
|
if (m_state == state) {
|
|
return false;
|
|
}
|
|
switch(state) {
|
|
case Idle:
|
|
return enterIdle();
|
|
case Warmup:
|
|
return enterWarmup();
|
|
case Playing:
|
|
return enterPlaying();
|
|
case GameOver:
|
|
return enterGameOver();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private boolean validateTransition(State from, State to) {
|
|
switch(from) {
|
|
case Idle:
|
|
return to == State.Warmup;
|
|
case Warmup:
|
|
return to == State.Playing || to == State.Idle || to == State.GameOver;
|
|
case Playing:
|
|
return to == State.Warmup || to == State.GameOver || to == State.Idle;
|
|
case GameOver:
|
|
return to == State.Idle;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public boolean requestTransition(State state) {
|
|
if (!validateTransition(m_state, state)) {
|
|
return false;
|
|
}
|
|
if (attemptTransition(state)) {
|
|
m_state = state;
|
|
for(Player p : m_players) {
|
|
syncPlayer(p);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public boolean addPlayer(Player p) {
|
|
if (m_state == State.Idle || m_state == State.Warmup) {
|
|
m_players.add(p);
|
|
broadcastMessage("Added player " + p + " to game");
|
|
syncPlayer(p);
|
|
if (m_state == State.Idle) {
|
|
requestTransition(State.Warmup);
|
|
}
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public void removePlayer(Player p) {
|
|
m_gameBar.removePlayer(p);
|
|
m_players.remove(p);
|
|
m_livingPlayers.remove(p);
|
|
if (m_players.size() == 0) {
|
|
requestTransition(State.Idle);
|
|
}
|
|
}
|
|
|
|
void broadcastMessage(String string) {
|
|
World world = m_arena.getWorld();
|
|
for(Player p : world.getPlayers()) {
|
|
p.sendMessage(string);
|
|
}
|
|
}
|
|
|
|
void registerSpawnedMob(Entity entity) {
|
|
m_spawnedMobs.add(entity);
|
|
}
|
|
|
|
private class GameSpawner implements Spawner {
|
|
Spawnpoint m_spawnpoint;
|
|
|
|
public GameSpawner(Spawnpoint spawnpoint) {
|
|
m_spawnpoint = spawnpoint;
|
|
}
|
|
|
|
@Override
|
|
public Entity spawnMob(EntityType type) {
|
|
Entity newMob = m_arena.getWorld().spawnEntity(m_spawnpoint.getLocation(), type);
|
|
LivingEntity livingMob = (LivingEntity)newMob;
|
|
livingMob.setRemoveWhenFarAway(false);
|
|
registerSpawnedMob(newMob);
|
|
return newMob;
|
|
}
|
|
}
|
|
}
|