351 lines
12 KiB
Java
351 lines
12 KiB
Java
package com.garbagemule.MobArena;
|
|
|
|
import com.garbagemule.MobArena.events.ArenaCompleteEvent;
|
|
import com.garbagemule.MobArena.events.NewWaveEvent;
|
|
import com.garbagemule.MobArena.framework.Arena;
|
|
import com.garbagemule.MobArena.region.ArenaRegion;
|
|
import com.garbagemule.MobArena.waves.MABoss;
|
|
import com.garbagemule.MobArena.waves.MACreature;
|
|
import com.garbagemule.MobArena.waves.Wave;
|
|
import com.garbagemule.MobArena.waves.WaveManager;
|
|
import com.garbagemule.MobArena.waves.enums.WaveType;
|
|
import com.garbagemule.MobArena.waves.types.BossWave;
|
|
import com.garbagemule.MobArena.waves.types.SupplyWave;
|
|
import com.garbagemule.MobArena.waves.types.UpgradeWave;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.World;
|
|
import org.bukkit.entity.Entity;
|
|
import org.bukkit.entity.LivingEntity;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.inventory.ItemStack;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
public class MASpawnThread implements Runnable
|
|
{
|
|
private MobArena plugin;
|
|
private Arena arena;
|
|
private ArenaRegion region;
|
|
private RewardManager rewardManager;
|
|
private WaveManager waveManager;
|
|
private MonsterManager monsterManager;
|
|
|
|
private int playerCount, monsterLimit;
|
|
private boolean waveClear, bossClear, preBossClear, wavesAsLevel;
|
|
|
|
/**
|
|
* Create a new monster spawner for the input arena.
|
|
* Note that the arena's WaveManager is reset
|
|
* @param plugin a MobArena instance
|
|
* @param arena an arena
|
|
*/
|
|
public MASpawnThread(MobArena plugin, Arena arena) {
|
|
this.plugin = plugin;
|
|
this.arena = arena;
|
|
this.region = arena.getRegion();
|
|
this.rewardManager = arena.getRewardManager();
|
|
this.waveManager = arena.getWaveManager();
|
|
this.monsterManager = arena.getMonsterManager();
|
|
|
|
reset();
|
|
}
|
|
|
|
/**
|
|
* Reset the spawner, so all systems and settings are
|
|
* ready for a new session.
|
|
*/
|
|
public void reset() {
|
|
waveManager.reset();
|
|
playerCount = arena.getPlayersInArena().size();
|
|
monsterLimit = arena.getSettings().getInt("monster-limit", 100);
|
|
waveClear = arena.getSettings().getBoolean("clear-wave-before-next", false);
|
|
bossClear = arena.getSettings().getBoolean("clear-boss-before-next", false);
|
|
preBossClear = arena.getSettings().getBoolean("clear-wave-before-boss", false);
|
|
wavesAsLevel = arena.getSettings().getBoolean("display-waves-as-level", false);
|
|
}
|
|
|
|
public void run() {
|
|
// If the arena isn't running or if there are no players in it.
|
|
if (!arena.isRunning() || arena.getPlayersInArena().isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
// Clear out all dead monsters in the monster set.
|
|
removeDeadMonsters();
|
|
removeCheatingPlayers();
|
|
|
|
// In case some players were removed, check again.
|
|
if (!arena.isRunning()) {
|
|
return;
|
|
}
|
|
|
|
// Grab the wave number.
|
|
int nextWave = waveManager.getWaveNumber() + 1;
|
|
|
|
// Check if wave needs to be cleared first. If so, return!
|
|
if (!isWaveClear()) {
|
|
arena.scheduleTask(this, 60);
|
|
return;
|
|
}
|
|
|
|
// Fire off the event. If cancelled, try again in 3 seconds.
|
|
NewWaveEvent event = new NewWaveEvent(arena, waveManager.getNext(), nextWave);
|
|
plugin.getServer().getPluginManager().callEvent(event);
|
|
if (event.isCancelled()) {
|
|
arena.scheduleTask(this, 60);
|
|
return;
|
|
}
|
|
|
|
// Grant rewards (if any) for the wave that just ended
|
|
grantRewards(nextWave - 1);
|
|
|
|
// Check if this is the final wave, in which case, end instead of spawn
|
|
if (nextWave > 1 && (nextWave - 1) == waveManager.getFinalWave()) {
|
|
// Fire the complete event
|
|
ArenaCompleteEvent complete = new ArenaCompleteEvent(arena);
|
|
plugin.getServer().getPluginManager().callEvent(complete);
|
|
|
|
// Then force leave everyone
|
|
List<Player> players = new ArrayList<>(arena.getPlayersInArena());
|
|
for (Player p : players) {
|
|
arena.playerLeave(p);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Spawn the next wave.
|
|
spawnWave(nextWave);
|
|
|
|
// Update stats
|
|
updateStats(nextWave);
|
|
|
|
// Reschedule the spawner for the next wave.
|
|
arena.scheduleTask(this, arena.getSettings().getInt("wave-interval", 3) * 20);
|
|
}
|
|
|
|
private void spawnWave(int wave) {
|
|
Wave w = waveManager.next();
|
|
|
|
w.announce(arena, wave);
|
|
|
|
arena.getScoreboard().updateWave(wave);
|
|
|
|
// Set the players' level to the wave number
|
|
if (wavesAsLevel) {
|
|
for (Player p : arena.getPlayersInArena()) {
|
|
p.setLevel(wave);
|
|
p.setExp(0.0f);
|
|
}
|
|
}
|
|
|
|
if (w.getType() == WaveType.UPGRADE) {
|
|
handleUpgradeWave(w);
|
|
return;
|
|
}
|
|
|
|
Map<MACreature, Integer> monsters = w.getMonstersToSpawn(wave, playerCount, arena);
|
|
List<Location> spawnpoints = w.getSpawnpoints(arena);
|
|
|
|
World world = arena.getWorld();
|
|
int totalSpawnpoints = spawnpoints.size();
|
|
int index = 0;
|
|
double mul = w.getHealthMultiplier();
|
|
|
|
for (Map.Entry<MACreature, Integer> entry : monsters.entrySet()) {
|
|
for (int i = 0; i < entry.getValue(); i++, index++) {
|
|
// Check if monster limit has been reached.
|
|
if (monsterManager.getMonsters().size() >= monsterLimit) {
|
|
return;
|
|
}
|
|
|
|
// Grab a spawnpoint
|
|
Location spawnpoint = spawnpoints.get(index % totalSpawnpoints);
|
|
|
|
// Spawn the monster
|
|
LivingEntity e = entry.getKey().spawn(arena, world, spawnpoint);
|
|
|
|
// Add it to the arena.
|
|
monsterManager.addMonster(e);
|
|
|
|
// Set the health.
|
|
e.resetMaxHealth(); // Avoid conflicts/enormous multiplications from other plugins handling Mob health
|
|
int health = (int) Math.max(1D, e.getMaxHealth() * mul);
|
|
try {
|
|
e.setMaxHealth(health);
|
|
e.setHealth(health);
|
|
} catch (IllegalArgumentException ex) {
|
|
// Spigot... *facepalm*
|
|
plugin.getLogger().severe("Can't set health to " + health + ", using default health. If you are running Spigot, set 'maxHealth' higher in your Spigot settings.");
|
|
plugin.getLogger().severe(ex.getLocalizedMessage());
|
|
if (w.getType() == WaveType.BOSS) {
|
|
((BossWave) w).setBossName("SPIGOT ERROR");
|
|
} else {
|
|
e.setCustomName("SPIGOT ERROR");
|
|
}
|
|
}
|
|
|
|
// Switch on the type.
|
|
switch (w.getType()){
|
|
case BOSS:
|
|
BossWave bw = (BossWave) w;
|
|
double maxHealth = bw.getMaxHealth(playerCount);
|
|
MABoss boss = monsterManager.addBoss(e, maxHealth);
|
|
boss.setReward(bw.getReward());
|
|
boss.setDrops(bw.getDrops());
|
|
bw.addMABoss(boss);
|
|
bw.activateAbilities(arena);
|
|
e.addPotionEffects(bw.getPotions());
|
|
if (bw.getBossName() != null) {
|
|
e.setCustomName(bw.getBossName());
|
|
e.setCustomNameVisible(true);
|
|
}
|
|
break;
|
|
case SWARM:
|
|
health = (int) (mul < 1D ? e.getMaxHealth() * mul : 1);
|
|
health = Math.max(1, health);
|
|
e.setHealth(Math.min(health, e.getMaxHealth()));
|
|
break;
|
|
case SUPPLY:
|
|
SupplyWave sw = (SupplyWave) w;
|
|
monsterManager.addSupplier(e, sw.getDropList());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void handleUpgradeWave(Wave w) {
|
|
UpgradeWave uw = (UpgradeWave) w;
|
|
|
|
for (Player p : arena.getPlayersInArena()) {
|
|
String className = arena.getArenaPlayer(p).getArenaClass().getLowercaseName();
|
|
uw.grantItems(arena, p, className);
|
|
uw.grantItems(arena, p, "all");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the wave is clear for new spawns.
|
|
* If clear-boss-before-next: true, bosses must be dead.
|
|
* If clear-wave-before-next: true, all monsters must be dead.
|
|
* @return true, if the wave is "clear" for new spawns.
|
|
*/
|
|
private boolean isWaveClear() {
|
|
// Check for monster limit
|
|
if (monsterManager.getMonsters().size() >= monsterLimit) {
|
|
return false;
|
|
}
|
|
|
|
// Check for boss clear
|
|
if (bossClear && !monsterManager.getBossMonsters().isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
// Check for wave and pre boss clear
|
|
if (waveClear && !monsterManager.getMonsters().isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
// Check for pre boss clear
|
|
if (preBossClear && waveManager.getNext().getType() == WaveType.BOSS && !monsterManager.getMonsters().isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
// Check for final wave
|
|
if (!monsterManager.getMonsters().isEmpty() && waveManager.getWaveNumber() == waveManager.getFinalWave()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void removeDeadMonsters() {
|
|
List<Entity> tmp = new ArrayList<Entity>(monsterManager.getMonsters());
|
|
for (Entity e : tmp) {
|
|
if (e == null) {
|
|
continue;
|
|
}
|
|
|
|
if (e.isDead() || !region.contains(e.getLocation())) {
|
|
monsterManager.remove(e);
|
|
e.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void removeCheatingPlayers() {
|
|
List<Player> players = new ArrayList<>(arena.getPlayersInArena());
|
|
for (Player p : players) {
|
|
if (region.contains(p.getLocation())) {
|
|
continue;
|
|
}
|
|
|
|
arena.getMessenger().tell(p, "Leaving so soon?");
|
|
p.getInventory().clear();
|
|
arena.playerLeave(p);
|
|
}
|
|
}
|
|
|
|
private void grantRewards(int wave) {
|
|
for (Map.Entry<Integer, List<ItemStack>> entry : arena.getEveryWaveEntrySet()) {
|
|
if (wave > 0 && wave % entry.getKey() == 0) {
|
|
addReward(entry.getValue());
|
|
}
|
|
}
|
|
|
|
List<ItemStack> after = arena.getAfterWaveReward(wave);
|
|
if (after != null) {
|
|
addReward(after);
|
|
}
|
|
}
|
|
|
|
private void updateStats(int wave) {
|
|
for (ArenaPlayer ap : arena.getArenaPlayerSet()) {
|
|
if (arena.getPlayersInArena().contains(ap.getPlayer())) {
|
|
ap.getStats().inc("lastWave");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ////////////////////////////////////////////////////////////////////
|
|
* //
|
|
* // Getters/setters
|
|
* //
|
|
* ////////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
public int getPlayerCount() {
|
|
return playerCount;
|
|
}
|
|
|
|
/**
|
|
* Rewards all players with an item from the input String.
|
|
*/
|
|
private void addReward(List<ItemStack> rewards) {
|
|
for (Player p : arena.getPlayersInArena()) {
|
|
ItemStack reward = MAUtils.getRandomReward(rewards);
|
|
rewardManager.addReward(p, reward);
|
|
|
|
if (reward == null) {
|
|
arena.getMessenger().tell(p, "ERROR! Problem with rewards. Notify server host!");
|
|
plugin.getLogger().warning("Could not add null reward. Please check the config-file!");
|
|
}
|
|
else if (reward.getTypeId() == MobArena.ECONOMY_MONEY_ID) {
|
|
if (plugin.giveMoney(p, reward)) { // Money already awarded here, not needed at end of match as well
|
|
arena.getMessenger().tell(p, Msg.WAVE_REWARD, plugin.economyFormat(reward));
|
|
}
|
|
else {
|
|
plugin.getLogger().warning("Tried to add money, but no economy plugin detected!");
|
|
}
|
|
}
|
|
else {
|
|
arena.getMessenger().tell(p, Msg.WAVE_REWARD, MAUtils.toCamelCase(reward.getType().toString()) + ":" + reward.getAmount());
|
|
}
|
|
}
|
|
}
|
|
} |