Reimplement wave AI, split out some UI code into a ui module, update TODO
This commit is contained in:
		
							
								
								
									
										24
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								TODO.md
									
									
									
									
									
								
							@@ -2,19 +2,33 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[X] Mobs spawn in waves
 | 
					[X] Mobs spawn in waves
 | 
				
			||||||
[X] Mobs move towards goal
 | 
					[X] Mobs move towards goal
 | 
				
			||||||
[ ] Mobs carry bomb to goal
 | 
					[X] Mobs carry bomb to goal
 | 
				
			||||||
[X] Mobs arm bomb
 | 
					[X] Mobs arm bomb
 | 
				
			||||||
[X] Bomb explodes
 | 
					[X] Bomb explodes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Malloc Beta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ ] Join games
 | 
				
			||||||
 | 
					[ ] Leave games
 | 
				
			||||||
 | 
					[ ] One arena config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Scaled waves
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ ] Weaker mobs, more of them
 | 
				
			||||||
 | 
					[ ] Mob categories
 | 
				
			||||||
 | 
					[ ] Spawnpoint categories
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# UX
 | 
					# UX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[X] Wave boss bar
 | 
					[X] Wave boss bar
 | 
				
			||||||
[X] Mob count boss bar
 | 
					[X] Mob count boss bar
 | 
				
			||||||
[X] Stage titles
 | 
					[X] Stage titles
 | 
				
			||||||
[ ] EXPLOSIONS
 | 
					[X] EXPLOSIONS
 | 
				
			||||||
 | 
					[ ] Target catches on fire more it is lit
 | 
				
			||||||
[ ] Colored titles
 | 
					[ ] Colored titles
 | 
				
			||||||
[ ] Clickable /ready in chat
 | 
					[ ] Clickable /ready in chat
 | 
				
			||||||
[ ] Sidebar
 | 
					[ ] Sidebar
 | 
				
			||||||
 | 
					[ ] List of mobs in next wave
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Social
 | 
					# Social
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -27,9 +41,9 @@
 | 
				
			|||||||
# Mechanics
 | 
					# Mechanics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[ ] Coin drops
 | 
					[ ] Coin drops
 | 
				
			||||||
[ ] Mob tracking should prioritize bomb
 | 
					[X] Mob tracking should prioritize bomb
 | 
				
			||||||
[ ] Mobs recover dropped bombs
 | 
					[X] Mobs recover dropped bombs
 | 
				
			||||||
[ ] Bomb carriers are slower
 | 
					[X] Bomb carriers are slower
 | 
				
			||||||
[ ] Bonus coins for complete coin pickup
 | 
					[ ] Bonus coins for complete coin pickup
 | 
				
			||||||
[ ] Infinite weapons + armor
 | 
					[ ] Infinite weapons + armor
 | 
				
			||||||
[ ] Ammo/health spawns
 | 
					[ ] Ammo/health spawns
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,14 +40,6 @@ public class GameEventHandler implements Listener {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @EventHandler
 | 
					  @EventHandler
 | 
				
			||||||
  public void onEntityDamage(EntityDamageEvent evt) {
 | 
					  public void onEntityDamage(EntityDamageEvent evt) {
 | 
				
			||||||
    if (evt.getEntity() instanceof Player) {
 | 
					 | 
				
			||||||
      Player player = (Player)evt.getEntity();
 | 
					 | 
				
			||||||
      if (player.getHealth() - evt.getFinalDamage() <= 0) {
 | 
					 | 
				
			||||||
        evt.setCancelled(true);
 | 
					 | 
				
			||||||
        m_runner.handlePlayerDeath(player);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
    m_runner.handleEntityDamage(evt);
 | 
					    m_runner.handleEntityDamage(evt);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,21 +22,24 @@ public class SetStageCommand implements CommandExecutor {
 | 
				
			|||||||
    GameRunner runner = m_plugin.getRunnerForWorld(world);
 | 
					    GameRunner runner = m_plugin.getRunnerForWorld(world);
 | 
				
			||||||
    String stateName = args[0].toLowerCase();
 | 
					    String stateName = args[0].toLowerCase();
 | 
				
			||||||
    boolean ret = false;
 | 
					    boolean ret = false;
 | 
				
			||||||
    if (stateName.equals("idle")) {
 | 
					    GameRunner.Stage decodedStage = null;
 | 
				
			||||||
      ret = runner.requestTransition(GameRunner.Stage.Idle);
 | 
					    GameRunner.Stage stages[] = GameRunner.Stage.Idle.getDeclaringClass().getEnumConstants();
 | 
				
			||||||
    } else if (stateName.equals("warmup")) {
 | 
					    for(GameRunner.Stage stage : stages) {
 | 
				
			||||||
      ret = runner.requestTransition(GameRunner.Stage.Warmup);
 | 
					      if (stage.toString().toLowerCase().equals(stateName)) {
 | 
				
			||||||
    } else if (stateName.equals("playing")) {
 | 
					        decodedStage = stage;
 | 
				
			||||||
      ret = runner.requestTransition(GameRunner.Stage.Playing);
 | 
					        break;
 | 
				
			||||||
    } else if (stateName.equals("gameover")) {
 | 
					      }
 | 
				
			||||||
      ret = runner.requestTransition(GameRunner.Stage.GameOver);
 | 
					    }
 | 
				
			||||||
 | 
					    if (decodedStage != null) {
 | 
				
			||||||
 | 
					      sender.sendMessage("Requesting transition to " + decodedStage);
 | 
				
			||||||
 | 
					      if (!runner.requestTransition(decodedStage)) {
 | 
				
			||||||
 | 
					        sender.sendMessage("Could not transition to " + decodedStage);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      sender.sendMessage("Unknown state " + stateName);
 | 
					      sender.sendMessage("Unknown state " + stateName);
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!ret) {
 | 
					 | 
				
			||||||
      sender.sendMessage("Could not set state to " + stateName);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										30
									
								
								src/main/java/gg/malloc/defense/engine/BombFuse.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/main/java/gg/malloc/defense/engine/BombFuse.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					package gg.malloc.defense.engine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class BombFuse {
 | 
				
			||||||
 | 
					  int m_bombFuseCount = 0;
 | 
				
			||||||
 | 
					  int m_bombFuseTarget = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public double getProgress() {
 | 
				
			||||||
 | 
					    return Math.max(0.0, Math.min(1.0, (double)m_bombFuseCount / (double)m_bombFuseTarget));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public boolean isLit() {
 | 
				
			||||||
 | 
					    return m_bombFuseCount > 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public boolean isExploded() {
 | 
				
			||||||
 | 
					    return m_bombFuseCount > m_bombFuseTarget;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void reset() {
 | 
				
			||||||
 | 
					    m_bombFuseCount = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void tickLit() {
 | 
				
			||||||
 | 
					    m_bombFuseCount += 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void tickDecay() {
 | 
				
			||||||
 | 
					    m_bombFuseCount -= 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,30 +1,35 @@
 | 
				
			|||||||
package gg.malloc.defense.engine;
 | 
					package gg.malloc.defense.engine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import gg.malloc.defense.model.Game;
 | 
					 | 
				
			||||||
import gg.malloc.defense.model.Arena;
 | 
					import gg.malloc.defense.model.Arena;
 | 
				
			||||||
 | 
					import gg.malloc.defense.model.Game;
 | 
				
			||||||
import gg.malloc.defense.model.Spawner;
 | 
					import gg.malloc.defense.model.Spawner;
 | 
				
			||||||
import gg.malloc.defense.model.Wave;
 | 
					
 | 
				
			||||||
 | 
					import gg.malloc.defense.ui.BombCarrier;
 | 
				
			||||||
 | 
					import gg.malloc.defense.ui.BossBars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import gg.malloc.defense.Plugin;
 | 
					import gg.malloc.defense.Plugin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.logging.Logger;
 | 
					import java.util.logging.Logger;
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.HashSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.bukkit.Bukkit;
 | 
					import org.bukkit.Bukkit;
 | 
				
			||||||
 | 
					import org.bukkit.Location;
 | 
				
			||||||
 | 
					import org.bukkit.Particle;
 | 
				
			||||||
import org.bukkit.Sound;
 | 
					import org.bukkit.Sound;
 | 
				
			||||||
 | 
					import org.bukkit.SoundCategory;
 | 
				
			||||||
import org.bukkit.World;
 | 
					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.EntityDamageEvent;
 | 
				
			||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
 | 
					import org.bukkit.event.entity.EntityDamageByEntityEvent;
 | 
				
			||||||
 | 
					import org.bukkit.event.entity.EntityTargetEvent;
 | 
				
			||||||
 | 
					import org.bukkit.event.player.PlayerTeleportEvent;
 | 
				
			||||||
import org.bukkit.entity.Entity;
 | 
					import org.bukkit.entity.Entity;
 | 
				
			||||||
import org.bukkit.entity.LivingEntity;
 | 
					 | 
				
			||||||
import org.bukkit.entity.ArmorStand;
 | 
					 | 
				
			||||||
import org.bukkit.entity.EntityType;
 | 
					import org.bukkit.entity.EntityType;
 | 
				
			||||||
 | 
					import org.bukkit.Material;
 | 
				
			||||||
 | 
					import org.bukkit.attribute.Attribute;
 | 
				
			||||||
 | 
					import org.bukkit.attribute.AttributeModifier;
 | 
				
			||||||
 | 
					import org.bukkit.entity.LivingEntity;
 | 
				
			||||||
import org.bukkit.entity.Player;
 | 
					import org.bukkit.entity.Player;
 | 
				
			||||||
import org.bukkit.scheduler.BukkitTask;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class GameRunner {
 | 
					public class GameRunner {
 | 
				
			||||||
  Arena m_arena;
 | 
					  Arena m_arena;
 | 
				
			||||||
@@ -32,18 +37,11 @@ public class GameRunner {
 | 
				
			|||||||
  Stage m_stage;
 | 
					  Stage m_stage;
 | 
				
			||||||
  Plugin m_plugin;
 | 
					  Plugin m_plugin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  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;
 | 
					  MobManager m_mobs;
 | 
				
			||||||
  WaveManager m_waves;
 | 
					  WaveManager m_waves;
 | 
				
			||||||
  PlayerManager m_players;
 | 
					  PlayerManager m_players;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  LivingEntity m_bombTarget = null;
 | 
					  BombFuse m_bombFuse;
 | 
				
			||||||
  int m_bombHP = 100;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Logger m_log;
 | 
					  Logger m_log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,126 +53,96 @@ public class GameRunner {
 | 
				
			|||||||
    GameOver
 | 
					    GameOver
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class WaveManager {
 | 
					  TickTask m_fuseTask;
 | 
				
			||||||
    int m_currentWaveNum = 0;
 | 
					  TickTask m_countdownTask;
 | 
				
			||||||
    int m_currentBatch = 0;
 | 
					  TickTask m_bombSmokeTask;
 | 
				
			||||||
    Wave m_currentWave = null;
 | 
					  TickTask m_bombCrackleTask;
 | 
				
			||||||
    Game m_game;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    WaveManager(Game game) {
 | 
					 | 
				
			||||||
      m_game = game;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void reset() {
 | 
					 | 
				
			||||||
      m_currentWaveNum = 0;
 | 
					 | 
				
			||||||
      m_currentBatch = 0;
 | 
					 | 
				
			||||||
      m_currentWave = null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Wave currentWave() {
 | 
					 | 
				
			||||||
      return m_currentWave;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int currentWaveNum() {
 | 
					 | 
				
			||||||
      return m_currentWaveNum;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int currentBatchNum() {
 | 
					 | 
				
			||||||
      return m_currentBatch;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    double progress() {
 | 
					 | 
				
			||||||
      return (double)m_currentWaveNum / (double)m_game.getWaveCount();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    boolean isLastWave() {
 | 
					 | 
				
			||||||
      return m_currentWaveNum >= m_game.getWaveCount();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    boolean isLastBatch() {
 | 
					 | 
				
			||||||
      return m_currentBatch >= m_currentWave.batchCount();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void nextBatch() {
 | 
					 | 
				
			||||||
      m_currentBatch += 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void next() {
 | 
					 | 
				
			||||||
      m_currentWaveNum += 1;
 | 
					 | 
				
			||||||
      m_currentBatch = 0;
 | 
					 | 
				
			||||||
      m_currentWave = m_game.getWave(m_currentWaveNum);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BossBars m_bars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public GameRunner(Plugin plugin, Game game, Arena arena) {
 | 
					  public GameRunner(Plugin plugin, Game game, Arena arena) {
 | 
				
			||||||
    m_plugin = plugin;
 | 
					    m_plugin = plugin;
 | 
				
			||||||
    m_game = game;
 | 
					    m_game = game;
 | 
				
			||||||
    m_arena = arena;
 | 
					    m_arena = arena;
 | 
				
			||||||
    m_stage = Stage.Idle;
 | 
					    m_stage = Stage.Idle;
 | 
				
			||||||
    m_gameBar.setVisible(true);
 | 
					    m_mobs = new MobManager();
 | 
				
			||||||
    m_waveBar.setVisible(false);
 | 
					 | 
				
			||||||
    m_bombBar.setVisible(false);
 | 
					 | 
				
			||||||
    m_mobs = new MobManager(m_game);
 | 
					 | 
				
			||||||
    m_waves = new WaveManager(m_game);
 | 
					    m_waves = new WaveManager(m_game);
 | 
				
			||||||
    m_players = new PlayerManager();
 | 
					    m_players = new PlayerManager();
 | 
				
			||||||
 | 
					    m_bombFuse = new BombFuse();
 | 
				
			||||||
 | 
					    m_bars = new BossBars(this, m_game, m_waves, m_players, m_bombFuse, m_mobs);
 | 
				
			||||||
    m_log = m_plugin.getLogger();
 | 
					    m_log = m_plugin.getLogger();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_fuseTask = new TickTask(m_plugin, () -> {
 | 
				
			||||||
 | 
					      if (m_bombFuse.isLit()) {
 | 
				
			||||||
 | 
					        m_bombFuse.tickDecay();
 | 
				
			||||||
 | 
					        m_bars.update();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }, 80);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_countdownTask = new TickTask(m_plugin, () -> {
 | 
				
			||||||
 | 
					      if (m_warmupCountdown == 0) {
 | 
				
			||||||
 | 
					        requestTransition(Stage.Playing);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        m_bars.update();
 | 
				
			||||||
 | 
					        broadcastMessage("Starting game in " + m_warmupCountdown);
 | 
				
			||||||
 | 
					        m_warmupCountdown--;
 | 
				
			||||||
 | 
					        m_bars.setCountdownProgress((double)m_warmupCountdown / 10.0);
 | 
				
			||||||
 | 
					        m_bars.update();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }, 20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_bombSmokeTask = new TickTask(m_plugin, () -> {
 | 
				
			||||||
 | 
					      Location targetLoc = m_arena.bombTarget().getLocation();
 | 
				
			||||||
 | 
					      m_arena.getWorld().spawnParticle(Particle.SMOKE_LARGE, targetLoc, 35, 4, 2, 4);
 | 
				
			||||||
 | 
					      m_arena.getWorld().spawnParticle(Particle.SMALL_FLAME, targetLoc, 30, 3, 2, 3);
 | 
				
			||||||
 | 
					    }, 5);
 | 
				
			||||||
 | 
					    m_bombCrackleTask = new TickTask(m_plugin, () -> {
 | 
				
			||||||
 | 
					      Location targetLoc = m_arena.bombTarget().getLocation();
 | 
				
			||||||
 | 
					      m_arena.getWorld().playSound(targetLoc, Sound.BLOCK_CAMPFIRE_CRACKLE, SoundCategory.NEUTRAL, 1.0f, 1.0f);
 | 
				
			||||||
 | 
					    }, 35);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int m_warmupCountdown = 0;
 | 
					  int m_warmupCountdown = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void handleEntityRetargeting(EntityTargetEvent evt) {
 | 
					  public void handleEntityRetargeting(EntityTargetEvent evt) {
 | 
				
			||||||
    if (m_mobs.contains(evt.getEntity()) && evt.getReason() == EntityTargetEvent.TargetReason.FORGOT_TARGET) {
 | 
					    m_mobs.handleEntityRetarget(evt);
 | 
				
			||||||
      evt.setTarget(m_bombTarget);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void handleEntityDamage(EntityDamageEvent evt) {
 | 
					  public void handleEntityDamage(EntityDamageEvent 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);
 | 
					    m_mobs.handleEntityDamage(evt);
 | 
				
			||||||
 | 
					    if (m_mobs.bombWasHit()) {
 | 
				
			||||||
 | 
					      EntityDamageByEntityEvent entityEvt = (EntityDamageByEntityEvent)evt;
 | 
				
			||||||
 | 
					      m_log.info("Target attacked!");
 | 
				
			||||||
 | 
					      entityEvt.getDamager().setGlowing(true);
 | 
				
			||||||
 | 
					      m_bombFuse.tickLit();
 | 
				
			||||||
 | 
					      m_arena.getWorld().playSound(m_arena.bombTarget().getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 1.5f, 0.9f);
 | 
				
			||||||
 | 
					      m_bars.update();
 | 
				
			||||||
 | 
					      if (m_bombFuse.isExploded()) {
 | 
				
			||||||
 | 
					        m_arena.getWorld().strikeLightningEffect(m_arena.bombTarget().getLocation());
 | 
				
			||||||
 | 
					        m_arena.getWorld().playSound(m_arena.bombTarget().getLocation(), Sound.ENTITY_GENERIC_EXPLODE, SoundCategory.NEUTRAL, 1.3f, 1.0f);
 | 
				
			||||||
 | 
					        m_arena.getWorld().spawnParticle(Particle.EXPLOSION_HUGE, m_arena.bombTarget().getLocation(), 8, 5, 2, 5);
 | 
				
			||||||
 | 
					        requestTransition(Stage.GameOver);
 | 
				
			||||||
 | 
					        m_bombSmokeTask.start();
 | 
				
			||||||
 | 
					        m_bombCrackleTask.start();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    } else if (evt.getEntity() instanceof Player) {
 | 
				
			||||||
 | 
					      Player player = (Player)evt.getEntity();
 | 
				
			||||||
 | 
					      if (m_players.contains(player) && player.getHealth() - evt.getFinalDamage() <= 0) {
 | 
				
			||||||
 | 
					        evt.setCancelled(true);
 | 
				
			||||||
 | 
					        handlePlayerDeath(player);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  private void countdownTick() {
 | 
					 | 
				
			||||||
    if (m_warmupCountdown == 0) {
 | 
					 | 
				
			||||||
      requestTransition(Stage.Playing);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      updateMobBars();
 | 
					 | 
				
			||||||
      broadcastMessage("Starting game in " + m_warmupCountdown);
 | 
					 | 
				
			||||||
      m_warmupCountdown--;
 | 
					 | 
				
			||||||
      m_countdownTask = m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> {
 | 
					 | 
				
			||||||
        countdownTick();
 | 
					 | 
				
			||||||
      }, 20);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private boolean enterIdle() {
 | 
					  private boolean enterIdle() {
 | 
				
			||||||
    m_bombHP = 100;
 | 
					    m_bombFuse.reset();
 | 
				
			||||||
    m_waves.reset();
 | 
					    m_waves.reset();
 | 
				
			||||||
    m_mobs.clear();
 | 
					    m_mobs.clear();
 | 
				
			||||||
 | 
					    m_bombSmokeTask.stop();
 | 
				
			||||||
 | 
					    m_bombCrackleTask.stop();
 | 
				
			||||||
    m_players.requestTransitionForAll(PlayerManager.State.Idle);
 | 
					    m_players.requestTransitionForAll(PlayerManager.State.Idle);
 | 
				
			||||||
    if (m_bombTarget != null) {
 | 
					    m_fuseTask.stop();
 | 
				
			||||||
      m_bombTarget.remove();
 | 
					    m_countdownTask.stop();
 | 
				
			||||||
      m_bombTarget = null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (m_countdownTask != null) {
 | 
					 | 
				
			||||||
      m_countdownTask.cancel();
 | 
					 | 
				
			||||||
      m_countdownTask = null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -204,25 +172,22 @@ public class GameRunner {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private boolean enterCountdown() {
 | 
					  private boolean enterCountdown() {
 | 
				
			||||||
    m_warmupCountdown = 10;
 | 
					    m_warmupCountdown = 10;
 | 
				
			||||||
    countdownTick();
 | 
					    m_bars.setCountdownProgress(1.0);
 | 
				
			||||||
 | 
					    m_countdownTask.start();
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private boolean enterPlaying() {
 | 
					  private boolean enterPlaying() {
 | 
				
			||||||
    m_log.info("Starting wave " + m_waves.currentWaveNum());
 | 
					    m_log.info("Starting wave " + m_waves.currentWaveNum());
 | 
				
			||||||
    if (m_bombTarget == null) {
 | 
					    m_mobs.spawnTarget(m_arena.bombTarget().getLocation());
 | 
				
			||||||
      m_bombTarget = (LivingEntity)m_arena.getWorld().spawnEntity(m_arena.bombTarget().getLocation(), EntityType.ARMOR_STAND);
 | 
					    // TODO: Set helmet with custom model data
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    ArmorStand bombStand = (ArmorStand)m_bombTarget;
 | 
					 | 
				
			||||||
    bombStand.setCustomName("Bomb Target");
 | 
					 | 
				
			||||||
    bombStand.setVisible(true);
 | 
					 | 
				
			||||||
    bombStand.setCustomNameVisible(true);
 | 
					 | 
				
			||||||
    bombStand.setGlowing(true);
 | 
					 | 
				
			||||||
    for(Player p : m_players.getPlayers()) {
 | 
					    for(Player p : m_players.getPlayers()) {
 | 
				
			||||||
        if (m_players.requestTransition(p, PlayerManager.State.Playing)) {
 | 
					        if (m_players.requestTransition(p, PlayerManager.State.Playing)) {
 | 
				
			||||||
          p.teleport(m_arena.getWorld().getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
 | 
					          p.teleport(m_arena.getWorld().getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    m_countdownTask.stop();
 | 
				
			||||||
 | 
					    m_fuseTask.start();
 | 
				
			||||||
    spawnNextBatch();
 | 
					    spawnNextBatch();
 | 
				
			||||||
    broadcastTitle("Wave " + m_waves.currentWaveNum());
 | 
					    broadcastTitle("Wave " + m_waves.currentWaveNum());
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
@@ -230,80 +195,28 @@ public class GameRunner {
 | 
				
			|||||||
  
 | 
					  
 | 
				
			||||||
  private boolean enterGameOver() {
 | 
					  private boolean enterGameOver() {
 | 
				
			||||||
    broadcastTitle("Game Over!");
 | 
					    broadcastTitle("Game Over!");
 | 
				
			||||||
    if (m_countdownTask != null) {
 | 
					    broadcastMessage("The bomb blew up!");
 | 
				
			||||||
      m_countdownTask.cancel();
 | 
					    m_countdownTask.stop();
 | 
				
			||||||
      m_countdownTask = null;
 | 
					    m_fuseTask.stop();
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    m_mobs.clear();
 | 
					    m_mobs.clear();
 | 
				
			||||||
    for(Player p : m_players.getPlayers()) {
 | 
					    for(Player p : new ArrayList<Player>(m_players.getPlayers())) {
 | 
				
			||||||
      removePlayer(p);
 | 
					      removePlayer(p);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void updateMobBars() {
 | 
					  public Stage getStage() {
 | 
				
			||||||
    m_gameBar.setVisible(true);
 | 
					    return m_stage;
 | 
				
			||||||
    switch(m_stage) {
 | 
					 | 
				
			||||||
      case Idle:
 | 
					 | 
				
			||||||
        m_gameBar.setProgress(1.0);
 | 
					 | 
				
			||||||
        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("Wave starting!");
 | 
					 | 
				
			||||||
        m_waveBar.setProgress((double)m_warmupCountdown / (double)10);
 | 
					 | 
				
			||||||
        m_bombBar.setVisible(false);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case Playing:
 | 
					 | 
				
			||||||
        m_gameBar.setProgress(m_waves.progress());
 | 
					 | 
				
			||||||
        m_gameBar.setTitle("Wave " + m_waves.currentWaveNum() + " / " + m_game.getWaveCount());
 | 
					 | 
				
			||||||
        m_gameBar.setColor(BarColor.PURPLE);
 | 
					 | 
				
			||||||
        if (m_mobs.createdMobs() > 0) {
 | 
					 | 
				
			||||||
          m_waveBar.setVisible(true);
 | 
					 | 
				
			||||||
          m_waveBar.setColor(BarColor.GREEN);
 | 
					 | 
				
			||||||
          m_waveBar.setTitle("Mobs remaining: " + m_mobs.remainingMobs());
 | 
					 | 
				
			||||||
          m_waveBar.setProgress(m_mobs.progress());
 | 
					 | 
				
			||||||
        } 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() {
 | 
					  private void spawnNextBatch() {
 | 
				
			||||||
    broadcastMessage("Spawning batch " + m_waves.currentBatchNum());
 | 
					    broadcastMessage("Spawning batch " + m_waves.currentBatchNum());
 | 
				
			||||||
    Spawner spawner = new GameSpawner(m_arena, m_mobs, m_players, m_bombTarget);
 | 
					    Spawner spawner = new GameSpawner(m_arena, m_mobs, m_players);
 | 
				
			||||||
    m_waves.currentWave().spawnBatch(spawner, m_waves.currentBatchNum());
 | 
					    m_waves.currentWave().spawnBatch(spawner, m_waves.currentBatchNum());
 | 
				
			||||||
    updateMobBars();
 | 
					    m_bars.update();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void handlePlayerDeath(Player player) {
 | 
					  private void handlePlayerDeath(Player player) {
 | 
				
			||||||
    if (m_players.requestTransition(player, PlayerManager.State.Dead)) {
 | 
					    if (m_players.requestTransition(player, PlayerManager.State.Dead)) {
 | 
				
			||||||
      m_arena.getWorld().strikeLightningEffect(player.getLocation());
 | 
					      m_arena.getWorld().strikeLightningEffect(player.getLocation());
 | 
				
			||||||
      if (!m_players.isAnyoneAlive()) {
 | 
					      if (!m_players.isAnyoneAlive()) {
 | 
				
			||||||
@@ -316,9 +229,9 @@ public class GameRunner {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void handleEntityDeath(Entity entity) {
 | 
					  public void handleEntityDeath(Entity entity) {
 | 
				
			||||||
 | 
					    boolean wasCarrier = m_mobs.isBombCarrier(entity);
 | 
				
			||||||
    if (m_mobs.killMob(entity)) {
 | 
					    if (m_mobs.killMob(entity)) {
 | 
				
			||||||
      broadcastMessage("Killed game entity " + entity);
 | 
					      m_bars.update();
 | 
				
			||||||
      updateMobBars();
 | 
					 | 
				
			||||||
      if (m_mobs.remainingMobs() <= 3) {
 | 
					      if (m_mobs.remainingMobs() <= 3) {
 | 
				
			||||||
        m_log.info("Starting next batch!");
 | 
					        m_log.info("Starting next batch!");
 | 
				
			||||||
        if (m_waves.isLastBatch()) {
 | 
					        if (m_waves.isLastBatch()) {
 | 
				
			||||||
@@ -381,7 +294,7 @@ public class GameRunner {
 | 
				
			|||||||
    if (attemptTransition(stage)) {
 | 
					    if (attemptTransition(stage)) {
 | 
				
			||||||
      m_log.info("Game transition: " + m_stage + " -> " + stage);
 | 
					      m_log.info("Game transition: " + m_stage + " -> " + stage);
 | 
				
			||||||
      m_stage = stage;
 | 
					      m_stage = stage;
 | 
				
			||||||
      updateMobBars();
 | 
					      m_bars.update();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    m_log.severe("Failed to complete transition: " + m_stage + " -> " + stage);
 | 
					    m_log.severe("Failed to complete transition: " + m_stage + " -> " + stage);
 | 
				
			||||||
@@ -389,10 +302,11 @@ public class GameRunner {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void addPlayer(Player p) {
 | 
					  public void addPlayer(Player p) {
 | 
				
			||||||
 | 
					    if (m_players.contains(p)) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    m_players.addPlayer(p);
 | 
					    m_players.addPlayer(p);
 | 
				
			||||||
    m_gameBar.addPlayer(p);
 | 
					    m_bars.addPlayer(p);
 | 
				
			||||||
    m_waveBar.addPlayer(p);
 | 
					 | 
				
			||||||
    m_bombBar.addPlayer(p);
 | 
					 | 
				
			||||||
    if (m_stage == Stage.Idle || m_stage == Stage.Warmup) {
 | 
					    if (m_stage == Stage.Idle || m_stage == Stage.Warmup) {
 | 
				
			||||||
      if (m_players.requestTransition(p, PlayerManager.State.Playing)) {
 | 
					      if (m_players.requestTransition(p, PlayerManager.State.Playing)) {
 | 
				
			||||||
        p.teleport(m_arena.getWorld().getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
 | 
					        p.teleport(m_arena.getWorld().getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
 | 
				
			||||||
@@ -405,8 +319,7 @@ public class GameRunner {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void removePlayer(Player p) {
 | 
					  public void removePlayer(Player p) {
 | 
				
			||||||
    m_gameBar.removePlayer(p);
 | 
					    m_bars.removePlayer(p);
 | 
				
			||||||
    m_waveBar.removePlayer(p);
 | 
					 | 
				
			||||||
    m_players.removePlayer(p);
 | 
					    m_players.removePlayer(p);
 | 
				
			||||||
    if (m_players.isEmpty()) {
 | 
					    if (m_players.isEmpty()) {
 | 
				
			||||||
      requestTransition(Stage.Idle);
 | 
					      requestTransition(Stage.Idle);
 | 
				
			||||||
@@ -429,8 +342,4 @@ public class GameRunner {
 | 
				
			|||||||
      p.sendMessage(string);
 | 
					      p.sendMessage(string);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  void registerSpawnedMob(Entity entity) {
 | 
					 | 
				
			||||||
    m_mobs.addEntity(entity);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,32 +8,44 @@ import org.bukkit.entity.Entity;
 | 
				
			|||||||
import org.bukkit.entity.LivingEntity;
 | 
					import org.bukkit.entity.LivingEntity;
 | 
				
			||||||
import org.bukkit.entity.EntityType;
 | 
					import org.bukkit.entity.EntityType;
 | 
				
			||||||
import org.bukkit.entity.Mob;
 | 
					import org.bukkit.entity.Mob;
 | 
				
			||||||
 | 
					import org.bukkit.inventory.EntityEquipment;
 | 
				
			||||||
 | 
					import org.bukkit.inventory.ItemStack;
 | 
				
			||||||
 | 
					import org.bukkit.inventory.meta.ItemMeta;
 | 
				
			||||||
 | 
					import org.bukkit.Material;
 | 
				
			||||||
 | 
					import org.bukkit.attribute.Attribute;
 | 
				
			||||||
 | 
					import org.bukkit.attribute.AttributeModifier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class GameSpawner implements Spawner {
 | 
					public class GameSpawner implements Spawner {
 | 
				
			||||||
  Arena m_arena;
 | 
					  Arena m_arena;
 | 
				
			||||||
  MobManager m_manager;
 | 
					  MobManager m_manager;
 | 
				
			||||||
  PlayerManager m_players;
 | 
					  PlayerManager m_players;
 | 
				
			||||||
  LivingEntity m_bombTarget;
 | 
					 | 
				
			||||||
  int m_spawnIdx = 0;
 | 
					  int m_spawnIdx = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public GameSpawner(Arena arena, MobManager manager, PlayerManager players, LivingEntity bombTarget) {
 | 
					  public GameSpawner(Arena arena, MobManager manager, PlayerManager players) {
 | 
				
			||||||
    m_arena = arena;
 | 
					    m_arena = arena;
 | 
				
			||||||
    m_manager = manager;
 | 
					    m_manager = manager;
 | 
				
			||||||
    m_players = players;
 | 
					    m_players = players;
 | 
				
			||||||
    m_bombTarget = bombTarget;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Entity spawnMob(EntityType type) {
 | 
					  public LivingEntity spawnBombCarrier(EntityType type) {
 | 
				
			||||||
 | 
					    if (m_manager.bombCount() == 0) {
 | 
				
			||||||
 | 
					      return m_manager.addBombCarrier(spawnMob(type));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      return spawnMob(type);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public LivingEntity spawnMob(EntityType type) {
 | 
				
			||||||
    Spawnpoint[] spawnpoints = m_arena.spawnpoints();
 | 
					    Spawnpoint[] spawnpoints = m_arena.spawnpoints();
 | 
				
			||||||
    m_spawnIdx %= spawnpoints.length;
 | 
					    m_spawnIdx %= spawnpoints.length;
 | 
				
			||||||
    //m_log.fine("Spawning " + type + " at " + spawnpoints[m_spawnIdx]);
 | 
					    //m_log.fine("Spawning " + type + " at " + spawnpoints[m_spawnIdx]);
 | 
				
			||||||
    Entity newMob = m_arena.getWorld().spawnEntity(spawnpoints[m_spawnIdx].getLocation(), type);
 | 
					    Entity newMob = m_arena.getWorld().spawnEntity(spawnpoints[m_spawnIdx].getLocation(), type);
 | 
				
			||||||
    LivingEntity livingMob = (LivingEntity)newMob;
 | 
					    LivingEntity livingMob = (LivingEntity)newMob;
 | 
				
			||||||
    livingMob.setRemoveWhenFarAway(false);
 | 
					    livingMob.setRemoveWhenFarAway(false);
 | 
				
			||||||
    m_manager.addEntity(newMob);
 | 
					    m_manager.addEntity(livingMob);
 | 
				
			||||||
    m_spawnIdx += 1;
 | 
					    m_spawnIdx += 1;
 | 
				
			||||||
    ((Mob)newMob).setTarget(m_bombTarget);
 | 
					    return livingMob;
 | 
				
			||||||
    return newMob;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,48 +2,61 @@ package gg.malloc.defense.engine;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.util.HashSet;
 | 
					import java.util.HashSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.Location;
 | 
				
			||||||
 | 
					import org.bukkit.entity.ArmorStand;
 | 
				
			||||||
import org.bukkit.entity.Entity;
 | 
					import org.bukkit.entity.Entity;
 | 
				
			||||||
 | 
					import org.bukkit.entity.EntityType;
 | 
				
			||||||
 | 
					import org.bukkit.entity.LivingEntity;
 | 
				
			||||||
 | 
					import org.bukkit.entity.Mob;
 | 
				
			||||||
import org.bukkit.event.entity.EntityDamageEvent;
 | 
					import org.bukkit.event.entity.EntityDamageEvent;
 | 
				
			||||||
 | 
					import org.bukkit.event.entity.EntityDamageByEntityEvent;
 | 
				
			||||||
 | 
					import org.bukkit.event.entity.EntityTargetEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import gg.malloc.defense.model.Game;
 | 
					import gg.malloc.defense.model.Game;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gg.malloc.defense.ui.BombCarrier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class MobManager {
 | 
					public class MobManager {
 | 
				
			||||||
  HashSet<Entity> m_livingMobs = new HashSet<>();
 | 
					  HashSet<LivingEntity> m_livingMobs = new HashSet<>();
 | 
				
			||||||
 | 
					  HashSet<LivingEntity> m_bombCarriers = new HashSet<>();
 | 
				
			||||||
 | 
					  HashSet<LivingEntity> m_droppedBombs = new HashSet<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int m_createdMobs = 0;
 | 
					  int m_createdMobs = 0;
 | 
				
			||||||
  int m_killedMobs = 0;
 | 
					  int m_killedMobs = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Game m_game;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  MobManager(Game game) {
 | 
					 | 
				
			||||||
    m_game = game;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public void handleEntityDamage(EntityDamageEvent evt) {
 | 
					 | 
				
			||||||
    Entity entity = evt.getEntity();
 | 
					 | 
				
			||||||
    //m_log.info("Damage " + entity);
 | 
					 | 
				
			||||||
    //m_log.info("Living Mobs " + m_livingMobs);
 | 
					 | 
				
			||||||
    if (m_livingMobs.contains(entity)) {
 | 
					 | 
				
			||||||
      m_game.onMobDamaged(entity);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public boolean contains(Entity entity) {
 | 
					  public boolean contains(Entity entity) {
 | 
				
			||||||
    return m_livingMobs.contains(entity);
 | 
					    return m_livingMobs.contains(entity);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public boolean isBombCarrier(Entity entity) {
 | 
				
			||||||
 | 
					    return m_bombCarriers.contains(entity);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public boolean killMob(Entity entity) {
 | 
					  public boolean killMob(Entity entity) {
 | 
				
			||||||
    if (m_livingMobs.contains(entity)) {
 | 
					    if (m_livingMobs.contains(entity)) {
 | 
				
			||||||
      m_killedMobs += 1;
 | 
					      m_killedMobs += 1;
 | 
				
			||||||
 | 
					      if (m_bombCarriers.remove(entity)) {
 | 
				
			||||||
 | 
					        dropBomb(entity.getLocation());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      return m_livingMobs.remove(entity);
 | 
					      return m_livingMobs.remove(entity);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void clear() {
 | 
					  public void clear() {
 | 
				
			||||||
    for(Entity e : m_livingMobs) {
 | 
					    for(LivingEntity e : m_livingMobs) {
 | 
				
			||||||
      e.remove();
 | 
					      e.remove();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    for(LivingEntity e : m_droppedBombs) {
 | 
				
			||||||
 | 
					      e.remove();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (m_bombTarget != null) {
 | 
				
			||||||
 | 
					      m_bombTarget.remove();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    m_bombTarget = null;
 | 
				
			||||||
 | 
					    m_droppedBombs.clear();
 | 
				
			||||||
    m_livingMobs.clear();
 | 
					    m_livingMobs.clear();
 | 
				
			||||||
 | 
					    m_bombCarriers.clear();
 | 
				
			||||||
    m_createdMobs = 0;
 | 
					    m_createdMobs = 0;
 | 
				
			||||||
    m_killedMobs = 0;
 | 
					    m_killedMobs = 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -64,13 +77,106 @@ public class MobManager {
 | 
				
			|||||||
    return (double)m_killedMobs / (double)m_createdMobs;
 | 
					    return (double)m_killedMobs / (double)m_createdMobs;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public void addEntity(Entity entity) {
 | 
					  public void addEntity(LivingEntity entity) {
 | 
				
			||||||
    //m_log.fine("Registered new mob " + entity); 
 | 
					 | 
				
			||||||
    m_livingMobs.add(entity);
 | 
					    m_livingMobs.add(entity);
 | 
				
			||||||
 | 
					    Mob asMob = (Mob)entity;
 | 
				
			||||||
 | 
					    if (m_droppedBombs.size() > 0) {
 | 
				
			||||||
 | 
					      asMob.setTarget(m_droppedBombs.iterator().next());
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      asMob.setTarget(m_bombTarget);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    m_createdMobs += 1;
 | 
					    m_createdMobs += 1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public int bombCount() {
 | 
				
			||||||
 | 
					    return m_bombCarriers.size() + m_droppedBombs.size();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public LivingEntity addBombCarrier(LivingEntity entity) {
 | 
				
			||||||
 | 
					    m_bombCarriers.add(entity);
 | 
				
			||||||
 | 
					    ((Mob)entity).setTarget(m_bombTarget);
 | 
				
			||||||
 | 
					    return new BombCarrier(entity).inHand();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void removeBombCarrier(LivingEntity entity) {
 | 
				
			||||||
 | 
					    m_bombCarriers.remove(entity);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public boolean empty() {
 | 
					  public boolean empty() {
 | 
				
			||||||
    return m_livingMobs.size() == 0;
 | 
					    return m_livingMobs.size() == 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public LivingEntity dropBomb(Location location) {
 | 
				
			||||||
 | 
					    ArmorStand droppedBomb = (ArmorStand)(new BombCarrier((LivingEntity)location.getWorld().spawnEntity(location, EntityType.ARMOR_STAND)).onHead());
 | 
				
			||||||
 | 
					    droppedBomb.setCustomName("The Bomb");
 | 
				
			||||||
 | 
					    droppedBomb.setVisible(true);
 | 
				
			||||||
 | 
					    droppedBomb.setCustomNameVisible(true);
 | 
				
			||||||
 | 
					    droppedBomb.setGlowing(true);
 | 
				
			||||||
 | 
					    m_droppedBombs.add(droppedBomb);
 | 
				
			||||||
 | 
					    for(LivingEntity ent : m_livingMobs) {
 | 
				
			||||||
 | 
					      if (!m_bombCarriers.contains(ent)) {
 | 
				
			||||||
 | 
					        ((Mob)ent).setTarget(droppedBomb);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return droppedBomb;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  boolean m_bombWasHit = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public boolean bombWasHit() {
 | 
				
			||||||
 | 
					    return m_bombWasHit;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void handleEntityDamage(EntityDamageEvent evt) {
 | 
				
			||||||
 | 
					    Entity entity = evt.getEntity();
 | 
				
			||||||
 | 
					    m_bombWasHit = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (entity == m_bombTarget && evt instanceof EntityDamageByEntityEvent) {
 | 
				
			||||||
 | 
					      EntityDamageByEntityEvent entityEvt = (EntityDamageByEntityEvent)evt;
 | 
				
			||||||
 | 
					      evt.setCancelled(true);
 | 
				
			||||||
 | 
					      if (m_bombCarriers.contains(entityEvt.getDamager())) {
 | 
				
			||||||
 | 
					        m_bombWasHit = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } if (m_droppedBombs.contains(entity)) {
 | 
				
			||||||
 | 
					      evt.setCancelled(true);
 | 
				
			||||||
 | 
					      EntityDamageByEntityEvent entityEvt = (EntityDamageByEntityEvent)evt;
 | 
				
			||||||
 | 
					      if (m_livingMobs.contains(entityEvt.getDamager())) {
 | 
				
			||||||
 | 
					        evt.getEntity().remove();
 | 
				
			||||||
 | 
					        m_droppedBombs.remove(evt.getEntity());
 | 
				
			||||||
 | 
					        addBombCarrier((LivingEntity)entityEvt.getDamager());
 | 
				
			||||||
 | 
					        for(LivingEntity ent : m_livingMobs) {
 | 
				
			||||||
 | 
					          if (!m_bombCarriers.contains(ent)) {
 | 
				
			||||||
 | 
					            ((Mob)ent).setTarget(m_bombTarget);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else if (m_livingMobs.contains(evt.getEntity())) {
 | 
				
			||||||
 | 
					      //m_game.onMobDamaged(evt.getEntity());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LivingEntity m_bombTarget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public LivingEntity spawnTarget(Location location) {
 | 
				
			||||||
 | 
					    assert(m_bombTarget == null);
 | 
				
			||||||
 | 
					    m_bombTarget = (LivingEntity)location.getWorld().spawnEntity(location, EntityType.ARMOR_STAND);
 | 
				
			||||||
 | 
					    ArmorStand bombStand = (ArmorStand)m_bombTarget;
 | 
				
			||||||
 | 
					    bombStand.setCustomName("Bomb Target");
 | 
				
			||||||
 | 
					    bombStand.setVisible(true);
 | 
				
			||||||
 | 
					    bombStand.setCustomNameVisible(true);
 | 
				
			||||||
 | 
					    bombStand.setGlowing(true);
 | 
				
			||||||
 | 
					    return m_bombTarget;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void handleEntityRetarget(EntityTargetEvent evt) {
 | 
				
			||||||
 | 
					    if (m_livingMobs.contains(evt.getEntity())) {
 | 
				
			||||||
 | 
					      if (m_bombCarriers.contains(evt.getEntity())) {
 | 
				
			||||||
 | 
					        evt.setTarget(m_bombTarget);
 | 
				
			||||||
 | 
					      } if (m_droppedBombs.size() > 0) {
 | 
				
			||||||
 | 
					        evt.setTarget(m_droppedBombs.iterator().next());
 | 
				
			||||||
 | 
					      } else if (evt.getReason() == EntityTargetEvent.TargetReason.FORGOT_TARGET) {
 | 
				
			||||||
 | 
					        evt.setTarget(m_bombTarget);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,10 @@ public class PlayerManager {
 | 
				
			|||||||
    return allSuccess;
 | 
					    return allSuccess;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public boolean contains(Player player) {
 | 
				
			||||||
 | 
					    return m_playerStates.containsKey(player);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public boolean requestTransition(Player player, State toState) {
 | 
					  public boolean requestTransition(Player player, State toState) {
 | 
				
			||||||
    State currentState = m_playerStates.get(player);
 | 
					    State currentState = m_playerStates.get(player);
 | 
				
			||||||
    if (currentState == toState) {
 | 
					    if (currentState == toState) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										40
									
								
								src/main/java/gg/malloc/defense/engine/TickTask.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/main/java/gg/malloc/defense/engine/TickTask.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					package gg.malloc.defense.engine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gg.malloc.defense.Plugin;
 | 
				
			||||||
 | 
					import org.bukkit.scheduler.BukkitTask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class TickTask {
 | 
				
			||||||
 | 
					  Runnable m_runnable;
 | 
				
			||||||
 | 
					  int m_interval;
 | 
				
			||||||
 | 
					  BukkitTask m_task = null;
 | 
				
			||||||
 | 
					  Plugin m_plugin;
 | 
				
			||||||
 | 
					  boolean m_cancelled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public TickTask(Plugin plugin, Runnable runnable, int interval) {
 | 
				
			||||||
 | 
					    m_plugin = plugin;
 | 
				
			||||||
 | 
					    m_runnable = runnable;
 | 
				
			||||||
 | 
					    m_interval = interval;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void start() {
 | 
				
			||||||
 | 
					    m_cancelled = false;
 | 
				
			||||||
 | 
					    if (m_task == null) {
 | 
				
			||||||
 | 
					      tick();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private void tick() {
 | 
				
			||||||
 | 
					    m_runnable.run();
 | 
				
			||||||
 | 
					    if (!m_cancelled) {
 | 
				
			||||||
 | 
					      m_task = m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> {tick();}, m_interval);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void stop() {
 | 
				
			||||||
 | 
					    m_cancelled = true;
 | 
				
			||||||
 | 
					    if (m_task != null) {
 | 
				
			||||||
 | 
					      m_task.cancel();
 | 
				
			||||||
 | 
					      m_task = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										55
									
								
								src/main/java/gg/malloc/defense/engine/WaveManager.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/main/java/gg/malloc/defense/engine/WaveManager.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					package gg.malloc.defense.engine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gg.malloc.defense.model.Wave;
 | 
				
			||||||
 | 
					import gg.malloc.defense.model.Game;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class WaveManager {
 | 
				
			||||||
 | 
					  int m_currentWaveNum = 0;
 | 
				
			||||||
 | 
					  int m_currentBatch = 0;
 | 
				
			||||||
 | 
					  Wave m_currentWave = null;
 | 
				
			||||||
 | 
					  Game m_game;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public WaveManager(Game game) {
 | 
				
			||||||
 | 
					    m_game = game;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void reset() {
 | 
				
			||||||
 | 
					    m_currentWaveNum = 0;
 | 
				
			||||||
 | 
					    m_currentBatch = 0;
 | 
				
			||||||
 | 
					    m_currentWave = null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public Wave currentWave() {
 | 
				
			||||||
 | 
					    return m_currentWave;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public int currentWaveNum() {
 | 
				
			||||||
 | 
					    return m_currentWaveNum;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public int currentBatchNum() {
 | 
				
			||||||
 | 
					    return m_currentBatch;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public double progress() {
 | 
				
			||||||
 | 
					    return (double)m_currentWaveNum / (double)m_game.getWaveCount();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public boolean isLastWave() {
 | 
				
			||||||
 | 
					    return m_currentWaveNum >= m_game.getWaveCount();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public boolean isLastBatch() {
 | 
				
			||||||
 | 
					    return m_currentBatch >= m_currentWave.batchCount();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void nextBatch() {
 | 
				
			||||||
 | 
					    m_currentBatch += 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void next() {
 | 
				
			||||||
 | 
					    m_currentWaveNum += 1;
 | 
				
			||||||
 | 
					    m_currentBatch = 0;
 | 
				
			||||||
 | 
					    m_currentWave = m_game.getWave(m_currentWaveNum);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,6 +6,9 @@ import gg.malloc.defense.model.Spawner;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import org.bukkit.entity.Entity;
 | 
					import org.bukkit.entity.Entity;
 | 
				
			||||||
import org.bukkit.entity.EntityType;
 | 
					import org.bukkit.entity.EntityType;
 | 
				
			||||||
 | 
					import org.bukkit.entity.Mob;
 | 
				
			||||||
 | 
					import org.bukkit.attribute.AttributeModifier;
 | 
				
			||||||
 | 
					import org.bukkit.attribute.Attribute;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,6 +58,8 @@ public class ScaledWaves implements Game {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void spawnBatch(Spawner spawner, int batch) {
 | 
					    public void spawnBatch(Spawner spawner, int batch) {
 | 
				
			||||||
 | 
					      double healthScale = -0.5;
 | 
				
			||||||
 | 
					      AttributeModifier modifier = new AttributeModifier("Scaled Health", healthScale, AttributeModifier.Operation.MULTIPLY_SCALAR_1);
 | 
				
			||||||
      assert(m_mobsPerBatch > 0);
 | 
					      assert(m_mobsPerBatch > 0);
 | 
				
			||||||
      for(int i = 0; i < m_mobsPerBatch; i++) {
 | 
					      for(int i = 0; i < m_mobsPerBatch; i++) {
 | 
				
			||||||
        EntityType selectedType = null;
 | 
					        EntityType selectedType = null;
 | 
				
			||||||
@@ -67,8 +72,9 @@ public class ScaledWaves implements Game {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        assert(selectedType != null);
 | 
					        assert(selectedType != null);
 | 
				
			||||||
        Entity newMob = spawner.spawnMob(selectedType);
 | 
					        Mob newMob = (Mob)spawner.spawnBombCarrier(selectedType);
 | 
				
			||||||
        newMob.setCustomName("Mob " + i + "/" + m_mobsPerBatch);
 | 
					        newMob.setCustomName("Mob " + i + "/" + m_mobsPerBatch);
 | 
				
			||||||
 | 
					        newMob.getAttribute(Attribute.GENERIC_MAX_HEALTH).addModifier(modifier);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (m_hasRavager) {
 | 
					      if (m_hasRavager) {
 | 
				
			||||||
        Entity newMob = spawner.spawnMob(EntityType.RAVAGER);
 | 
					        Entity newMob = spawner.spawnMob(EntityType.RAVAGER);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,9 @@
 | 
				
			|||||||
package gg.malloc.defense.model;
 | 
					package gg.malloc.defense.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.bukkit.entity.EntityType;
 | 
					import org.bukkit.entity.EntityType;
 | 
				
			||||||
import org.bukkit.entity.Entity;
 | 
					import org.bukkit.entity.LivingEntity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public interface Spawner {
 | 
					public interface Spawner {
 | 
				
			||||||
  Entity spawnMob(EntityType type);
 | 
					  LivingEntity spawnMob(EntityType type);
 | 
				
			||||||
 | 
					  LivingEntity spawnBombCarrier(EntityType type);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										37
									
								
								src/main/java/gg/malloc/defense/ui/BombCarrier.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/main/java/gg/malloc/defense/ui/BombCarrier.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					package gg.malloc.defense.ui;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.entity.LivingEntity;
 | 
				
			||||||
 | 
					import org.bukkit.inventory.EntityEquipment;
 | 
				
			||||||
 | 
					import org.bukkit.inventory.ItemStack;
 | 
				
			||||||
 | 
					import org.bukkit.inventory.meta.ItemMeta;
 | 
				
			||||||
 | 
					import org.bukkit.Material;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class BombCarrier {
 | 
				
			||||||
 | 
					  LivingEntity m_entity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public BombCarrier(LivingEntity entity) {
 | 
				
			||||||
 | 
					    m_entity = entity;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public LivingEntity inHand() {
 | 
				
			||||||
 | 
					    EntityEquipment equipment = m_entity.getEquipment();
 | 
				
			||||||
 | 
					    equipment.setItemInOffHand(makeBombHelmet());
 | 
				
			||||||
 | 
					    //equipment.setItemInOffHandDropChance(0.0f);
 | 
				
			||||||
 | 
					    return m_entity;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public LivingEntity onHead() {
 | 
				
			||||||
 | 
					    EntityEquipment equipment = m_entity.getEquipment();
 | 
				
			||||||
 | 
					    equipment.setHelmet(makeBombHelmet());
 | 
				
			||||||
 | 
					    //equipment.setHelmetDropChance(0.0f);
 | 
				
			||||||
 | 
					    return m_entity;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static ItemStack makeBombHelmet() {
 | 
				
			||||||
 | 
					      ItemStack bombItem = new ItemStack(Material.CARVED_PUMPKIN);
 | 
				
			||||||
 | 
					      ItemMeta meta = bombItem.getItemMeta();
 | 
				
			||||||
 | 
					      meta.setCustomModelData(33197);
 | 
				
			||||||
 | 
					      bombItem.setItemMeta(meta);
 | 
				
			||||||
 | 
					      return bombItem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										116
									
								
								src/main/java/gg/malloc/defense/ui/BossBars.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/main/java/gg/malloc/defense/ui/BossBars.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
				
			|||||||
 | 
					package gg.malloc.defense.ui;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gg.malloc.defense.engine.GameRunner;
 | 
				
			||||||
 | 
					import gg.malloc.defense.engine.WaveManager;
 | 
				
			||||||
 | 
					import gg.malloc.defense.engine.PlayerManager;
 | 
				
			||||||
 | 
					import gg.malloc.defense.engine.MobManager;
 | 
				
			||||||
 | 
					import gg.malloc.defense.engine.BombFuse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gg.malloc.defense.model.Game;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.boss.BossBar;
 | 
				
			||||||
 | 
					import org.bukkit.boss.BarStyle;
 | 
				
			||||||
 | 
					import org.bukkit.boss.BarColor;
 | 
				
			||||||
 | 
					import org.bukkit.Bukkit;
 | 
				
			||||||
 | 
					import org.bukkit.entity.Player;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class BossBars {
 | 
				
			||||||
 | 
					  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 Fuse", BarColor.RED, BarStyle.SOLID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GameRunner m_runner;
 | 
				
			||||||
 | 
					  MobManager m_mobs;
 | 
				
			||||||
 | 
					  WaveManager m_waves;
 | 
				
			||||||
 | 
					  PlayerManager m_players;
 | 
				
			||||||
 | 
					  BombFuse m_fuse;
 | 
				
			||||||
 | 
					  Game m_game;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  double m_countdownProgress;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void setCountdownProgress(double v) {
 | 
				
			||||||
 | 
					    m_countdownProgress = v;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public BossBars(GameRunner runner, Game game, WaveManager waves, PlayerManager players, BombFuse fuse, MobManager mobs) {
 | 
				
			||||||
 | 
					    m_runner = runner;
 | 
				
			||||||
 | 
					    m_game = game;
 | 
				
			||||||
 | 
					    m_waves = waves;
 | 
				
			||||||
 | 
					    m_players = players;
 | 
				
			||||||
 | 
					    m_fuse = fuse;
 | 
				
			||||||
 | 
					    m_mobs = mobs;
 | 
				
			||||||
 | 
					    m_gameBar.setVisible(true);
 | 
				
			||||||
 | 
					    m_waveBar.setVisible(false);
 | 
				
			||||||
 | 
					    m_bombBar.setVisible(false);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void addPlayer(Player p) {
 | 
				
			||||||
 | 
					    m_gameBar.addPlayer(p);
 | 
				
			||||||
 | 
					    m_waveBar.addPlayer(p);
 | 
				
			||||||
 | 
					    m_bombBar.addPlayer(p);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void removePlayer(Player p) {
 | 
				
			||||||
 | 
					    m_gameBar.removePlayer(p);
 | 
				
			||||||
 | 
					    m_waveBar.removePlayer(p);
 | 
				
			||||||
 | 
					    m_bombBar.removePlayer(p);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void update() {
 | 
				
			||||||
 | 
					    switch(m_runner.getStage()) {
 | 
				
			||||||
 | 
					      case Idle:
 | 
				
			||||||
 | 
					        m_gameBar.setProgress(1.0);
 | 
				
			||||||
 | 
					        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("Wave starting!");
 | 
				
			||||||
 | 
					        m_waveBar.setProgress(m_countdownProgress);
 | 
				
			||||||
 | 
					        m_bombBar.setVisible(false);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case Playing:
 | 
				
			||||||
 | 
					        m_gameBar.setProgress(m_waves.progress());
 | 
				
			||||||
 | 
					        m_gameBar.setTitle("Wave " + m_waves.currentWaveNum() + " / " + m_game.getWaveCount());
 | 
				
			||||||
 | 
					        m_gameBar.setColor(BarColor.PURPLE);
 | 
				
			||||||
 | 
					        if (m_mobs.createdMobs() > 0) {
 | 
				
			||||||
 | 
					          m_waveBar.setVisible(true);
 | 
				
			||||||
 | 
					          m_waveBar.setColor(BarColor.GREEN);
 | 
				
			||||||
 | 
					          m_waveBar.setTitle("Mobs remaining: " + m_mobs.remainingMobs());
 | 
				
			||||||
 | 
					          m_waveBar.setProgress(m_mobs.progress());
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          m_waveBar.setVisible(false);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (m_fuse.isLit()) {
 | 
				
			||||||
 | 
					          m_bombBar.setVisible(true);
 | 
				
			||||||
 | 
					          m_bombBar.setProgress(1.0 - m_fuse.getProgress());
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          m_bombBar.setVisible(false);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								src/main/java/gg/malloc/defense/ui/Items.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/main/java/gg/malloc/defense/ui/Items.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					package gg.malloc.defense.engine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.inventory.ItemStack;
 | 
				
			||||||
 | 
					import org.bukkit.inventory.meta.ItemMeta;
 | 
				
			||||||
 | 
					import org.bukkit.Material;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class Items {
 | 
				
			||||||
 | 
					  static ItemStack makeBombHelmet() {
 | 
				
			||||||
 | 
					      ItemStack bombItem = new ItemStack(Material.CARVED_PUMPKIN);
 | 
				
			||||||
 | 
					      ItemMeta meta = bombItem.getItemMeta();
 | 
				
			||||||
 | 
					      meta.setCustomModelData(0);
 | 
				
			||||||
 | 
					      bombItem.setItemMeta(meta);
 | 
				
			||||||
 | 
					      return bombItem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user