1
0
mirror of https://github.com/garbagemule/MobArena.git synced 2025-03-23 12:10:34 +01:00

Add support for boss health bars.

Three different types of health bars are implemented behind a basic Strategy Pattern. A new per-arena setting, boss-health-bar, can be used to configure which one of the three types (if any) of health bar should be used for bosses in the given arena:

- `boss-bar` creates a boss bar at the top of the screen as if the players were fighting an ender dragon or a wither.
- `title` uses the Chapters/Titles API in Bukkit to display the health of the boss as a "subtitle" whenever it takes damage.
- `name` sets the entitiy's health along with an optional custom name above the entity's head.
This commit is contained in:
Andreas Troelsen 2018-06-22 00:00:05 +02:00
parent c4362474a1
commit 2aecea401d
12 changed files with 294 additions and 0 deletions

View File

@ -25,6 +25,7 @@ import com.garbagemule.MobArena.util.ClassChests;
import com.garbagemule.MobArena.util.inventory.InventoryManager;
import com.garbagemule.MobArena.util.timer.AutoStartTimer;
import com.garbagemule.MobArena.util.timer.StartDelayTimer;
import com.garbagemule.MobArena.waves.MABoss;
import com.garbagemule.MobArena.waves.SheepBouncer;
import com.garbagemule.MobArena.waves.WaveManager;
import org.bukkit.Bukkit;
@ -1118,6 +1119,14 @@ public class ArenaImpl implements Arena
private void clearPlayer(Player p)
{
// Remove from boss health bar
monsterManager.getBossMonsters().forEach(entity -> {
MABoss boss = monsterManager.getBoss(entity);
if (boss != null) {
boss.getHealthBar().removePlayer(p);
}
});
// Remove pets.
monsterManager.removePets(p);

View File

@ -635,6 +635,7 @@ public class ArenaListener
event.getDrops().addAll(drops);
}
boss.setDead(true);
boss.getHealthBar().setProgress(0);
}
List<ItemStack> loot = monsters.getLoot(damagee);
@ -685,6 +686,10 @@ public class ArenaListener
}
}
MABoss boss = (damagee instanceof LivingEntity)
? monsters.getBoss((LivingEntity) damagee)
: null;
// Pet wolf
if (damagee instanceof Wolf && arena.hasPet(damagee)) {
onPetDamage(event, (Wolf) damagee, damager);
@ -701,6 +706,10 @@ public class ArenaListener
else if (damagee instanceof Snowman && event.getCause() == DamageCause.MELTING) {
event.setCancelled(true);
}
// Boss monster
else if (boss != null) {
onBossDamage(event, boss, damager);
}
// Regular monster
else if (monsters.getMonsters().contains(damagee)) {
onMonsterDamage(event, damagee, damager);
@ -739,6 +748,16 @@ public class ArenaListener
private void onMountDamage(EntityDamageEvent event, Horse mount, Entity damager) {
event.setCancelled(true);
}
private void onBossDamage(EntityDamageEvent event, MABoss boss, Entity damager) {
onMonsterDamage(event, boss.getEntity(), damager);
if (event.isCancelled()) {
return;
}
double progress = boss.getHealth() / boss.getMaxHealth();
boss.getHealthBar().setProgress(progress);
}
private void onMonsterDamage(EntityDamageEvent event, Entity monster, Entity damager) {
if (damager instanceof Player) {

View File

@ -3,6 +3,8 @@ 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.healthbar.CreatesHealthBar;
import com.garbagemule.MobArena.healthbar.HealthBar;
import com.garbagemule.MobArena.region.ArenaRegion;
import com.garbagemule.MobArena.things.Thing;
import com.garbagemule.MobArena.waves.MABoss;
@ -31,6 +33,7 @@ public class MASpawnThread implements Runnable
private RewardManager rewardManager;
private WaveManager waveManager;
private MonsterManager monsterManager;
private CreatesHealthBar createsHealthBar;
private int playerCount, monsterLimit;
private boolean waveClear, bossClear, preBossClear, wavesAsLevel;
@ -48,6 +51,7 @@ public class MASpawnThread implements Runnable
this.rewardManager = arena.getRewardManager();
this.waveManager = arena.getWaveManager();
this.monsterManager = arena.getMonsterManager();
this.createsHealthBar = new CreatesHealthBar(arena.getSettings().getString("boss-health-bar", "none"));
reset();
}
@ -195,6 +199,10 @@ public class MASpawnThread implements Runnable
BossWave bw = (BossWave) w;
double maxHealth = bw.getMaxHealth(playerCount);
MABoss boss = monsterManager.addBoss(e, maxHealth);
HealthBar healthbar = createsHealthBar.create(e, bw.getBossName());
arena.getPlayersInArena().forEach(healthbar::addPlayer);
healthbar.setProgress(1);
boss.setHealthBar(healthbar);
boss.setReward(bw.getReward());
boss.setDrops(bw.getDrops());
bw.addMABoss(boss);

View File

@ -0,0 +1,49 @@
package com.garbagemule.MobArena.healthbar;
import org.bukkit.Bukkit;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarFlag;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.BossBar;
import org.bukkit.entity.Player;
class BossHealthBar implements HealthBar {
private static final double LOW_HEALTH = 0.25;
private final BossBar bar;
BossHealthBar(String title) {
bar = Bukkit.createBossBar(
title.isEmpty() ? "Boss" : title,
BarColor.GREEN,
BarStyle.SOLID,
BarFlag.PLAY_BOSS_MUSIC,
BarFlag.DARKEN_SKY
);
}
@Override
public void setProgress(double progress) {
if (progress <= LOW_HEALTH && bar.getColor() != BarColor.RED) {
bar.setColor(BarColor.RED);
}
bar.setProgress(progress);
}
@Override
public void addPlayer(Player player) {
bar.addPlayer(player);
}
@Override
public void removePlayer(Player player) {
bar.removePlayer(player);
}
@Override
public void removeAll() {
bar.removeAll();
}
}

View File

@ -0,0 +1,30 @@
package com.garbagemule.MobArena.healthbar;
import org.bukkit.entity.Entity;
public class CreatesHealthBar {
private final String type;
private final CreatesHealthString createsHealthString;
public CreatesHealthBar(String type) {
this.type = type;
this.createsHealthString = new CreatesHealthString();
}
public HealthBar create(Entity entity, String title) {
String name = (title != null) ? title : "";
switch (type) {
case "boss-bar":
return new BossHealthBar(name);
case "title":
return new TitleHealthBar(name, createsHealthString);
case "name":
return new NameHealthBar(entity, name, createsHealthString);
default:
return new NullHealthBar();
}
}
}

View File

@ -0,0 +1,29 @@
package com.garbagemule.MobArena.healthbar;
import org.bukkit.ChatColor;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class CreatesHealthString {
private static final int TOTAL_BARS = 20;
private static final int LOW_BARS = TOTAL_BARS / 4;
String create(double progress) {
int bars = (int) (progress * TOTAL_BARS);
String current = IntStream.range(0, bars)
.mapToObj(i -> "|")
.collect(Collectors.joining());
String lost = IntStream.range(bars, TOTAL_BARS)
.mapToObj(i -> "|")
.collect(Collectors.joining());
ChatColor color = (bars <= LOW_BARS) ? ChatColor.RED : ChatColor.GREEN;
return color + current + ChatColor.GRAY + lost;
}
}

View File

@ -0,0 +1,15 @@
package com.garbagemule.MobArena.healthbar;
import org.bukkit.entity.Player;
public interface HealthBar {
void setProgress(double progress);
void addPlayer(Player player);
void removePlayer(Player player);
void removeAll();
}

View File

@ -0,0 +1,43 @@
package com.garbagemule.MobArena.healthbar;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
class NameHealthBar implements HealthBar {
private final Entity entity;
private final String title;
private final CreatesHealthString createsHealthString;
NameHealthBar(Entity entity, String title, CreatesHealthString createsHealthString) {
this.entity = entity;
this.title = title;
this.createsHealthString = createsHealthString;
entity.setCustomNameVisible(true);
}
@Override
public void setProgress(double progress) {
String health = createsHealthString.create(progress);
String name = title.isEmpty() ? health : title + " " + health;
entity.setCustomName(name);
}
@Override
public void addPlayer(Player player) {
// OK BOSS
}
@Override
public void removePlayer(Player player) {
// OK BOSS
}
@Override
public void removeAll() {
// OK BOSS
}
}

View File

@ -0,0 +1,27 @@
package com.garbagemule.MobArena.healthbar;
import org.bukkit.entity.Player;
class NullHealthBar implements HealthBar {
@Override
public void setProgress(double progress) {
// OK BOSS
}
@Override
public void addPlayer(Player player) {
// OK BOSS
}
@Override
public void removePlayer(Player player) {
// OK BOSS
}
@Override
public void removeAll() {
// OK BOSS
}
}

View File

@ -0,0 +1,53 @@
package com.garbagemule.MobArena.healthbar;
import org.bukkit.entity.Player;
import java.util.HashSet;
import java.util.Set;
class TitleHealthBar implements HealthBar {
private static final int FADE_IN_TICKS = 5;
private static final int STAY_TICKS = 40;
private static final int FADE_OUT_TICKS = 10;
private final String title;
private final CreatesHealthString createsHealthString;
private final Set<Player> players;
TitleHealthBar(String title, CreatesHealthString createsHealthString) {
this.title = title;
this.createsHealthString = createsHealthString;
this.players = new HashSet<>();
}
@Override
public void setProgress(double progress) {
String health = createsHealthString.create(progress);
String message = title.isEmpty() ? health : title + " " + health;
players.forEach(player -> player.sendTitle(
"",
message,
FADE_IN_TICKS,
STAY_TICKS,
FADE_OUT_TICKS
));
}
@Override
public void addPlayer(Player player) {
players.add(player);
}
@Override
public void removePlayer(Player player) {
players.remove(player);
}
@Override
public void removeAll() {
players.clear();
}
}

View File

@ -1,5 +1,6 @@
package com.garbagemule.MobArena.waves;
import com.garbagemule.MobArena.healthbar.HealthBar;
import com.garbagemule.MobArena.things.Thing;
import org.bukkit.Bukkit;
import org.bukkit.entity.LivingEntity;
@ -13,6 +14,7 @@ public class MABoss
private boolean dead;
private Thing reward;
private List<ItemStack> drops;
private HealthBar healthbar;
/**
* Create an MABoss from the given entity with the given max health.
@ -73,6 +75,7 @@ public class MABoss
*/
public void setDead(boolean dead) {
this.dead = dead;
healthbar.removeAll();
}
public void setReward(Thing reward) {
@ -90,4 +93,12 @@ public class MABoss
public List<ItemStack> getDrops() {
return drops;
}
public HealthBar getHealthBar() {
return healthbar;
}
public void setHealthBar(HealthBar healthbar) {
this.healthbar = healthbar;
}
}

View File

@ -34,6 +34,7 @@ auto-start-timer: 0
start-delay-timer: 0
auto-ready: false
use-class-chests: false
boss-health-bar: boss-bar
display-waves-as-level: false
display-timer-as-level: false
use-scoreboards: true