Implement /ready and basic objective mechanics

This commit is contained in:
2022-05-08 18:36:35 +02:00
parent a078f74b4b
commit 2f63695ee9
11 changed files with 263 additions and 36 deletions

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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) {