From 4955e943067e221439a78d10a2a2a0046af92d13 Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 17 Oct 2025 19:38:10 +0200 Subject: [PATCH 01/15] started bloodmoon appliance --- .../gameplay/bloodmoon/Bloodmoon.java | 54 +++++++++++++++++++ .../BloodmoonMonsterDeathListener.java | 19 +++++++ 2 files changed, 73 insertions(+) create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java new file mode 100644 index 0000000..c7a5394 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -0,0 +1,54 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon; + +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonMonsterDeathListener; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +public class Bloodmoon extends Appliance { + // für alle Dimensionen? einstellbar machen? + + public final Set affectedMobs = Set.of( + EntityType.ZOMBIE, + EntityType.SKELETON, + EntityType.SPIDER, + EntityType.CREEPER, + EntityType.HUSK, + EntityType.DROWNED, + EntityType.WITCH, + EntityType.ZOMBIE_VILLAGER, + EntityType.PHANTOM, + EntityType.ENDERMAN + ); + public final int expMultiplier = 4; + public final boolean summonLightning = true; + + private final int minBonusDrops = 1; + private final int maxBonusDrops = 4; + + public boolean bloodmoonIsActive() { + return true; + } + + public Set getRandomBonusDrops() { + int itemCount = ThreadLocalRandom.current().nextInt(this.minBonusDrops, this.maxBonusDrops + 1); + return Set.of( + new ItemStack(Material.DIAMOND_BLOCK, 2), + new ItemStack(Material.IRON_BARS, 3) + ); + } + + @Override + protected @NotNull List listeners() { + return List.of( + new BloodmoonMonsterDeathListener() + ); + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java new file mode 100644 index 0000000..32cec35 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java @@ -0,0 +1,19 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDeathEvent; + +public class BloodmoonMonsterDeathListener extends ApplianceListener { + @EventHandler + public void onMonsterDeath(EntityDeathEvent event) { + if(!this.getAppliance().bloodmoonIsActive()) return; + LivingEntity entity = event.getEntity(); + if(!this.getAppliance().affectedMobs.contains(entity.getType())) return; + + event.setDroppedExp(event.getDroppedExp() * this.getAppliance().expMultiplier); + event.getDrops().addAll(this.getAppliance().getRandomBonusDrops()); + } +} -- 2.30.2 From 9433495a52888fcd74e7a6bd9e1f3b5e1cddd939 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 18 Oct 2025 19:01:09 +0200 Subject: [PATCH 02/15] added random drops and boss bar for Bloodmoon --- .../gameplay/bloodmoon/Bloodmoon.java | 122 +++++++++++++++--- .../bloodmoon/LightningPotionEffect.java | 10 ++ .../bloodmoon/commands/BloodmoonCommand.java | 44 +++++++ .../BloodmoonEntityDamageListener.java | 25 ++++ .../BloodmoonMonsterDeathListener.java | 3 +- .../listener/BloodmoonPlayerJoinListener.java | 14 ++ 6 files changed, 197 insertions(+), 21 deletions(-) create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/LightningPotionEffect.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonPlayerJoinListener.java diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index c7a5394..be62263 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -1,54 +1,136 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; +import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.commands.BloodmoonCommand; import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonMonsterDeathListener; +import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonPlayerJoinListener; +import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarFlag; +import org.bukkit.boss.BarStyle; +import org.bukkit.boss.BossBar; import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.List; -import java.util.Set; +import java.util.Map; import java.util.concurrent.ThreadLocalRandom; public class Bloodmoon extends Appliance { // für alle Dimensionen? einstellbar machen? - public final Set affectedMobs = Set.of( - EntityType.ZOMBIE, - EntityType.SKELETON, - EntityType.SPIDER, - EntityType.CREEPER, - EntityType.HUSK, - EntityType.DROWNED, - EntityType.WITCH, - EntityType.ZOMBIE_VILLAGER, - EntityType.PHANTOM, - EntityType.ENDERMAN + public final Map affectedMobEffectMap = Map.of( + EntityType.ZOMBIE, new PotionEffect[]{ + new PotionEffect(PotionEffectType.WITHER, 7 * 20, 1) + }, + EntityType.SKELETON, new PotionEffect[]{ + new PotionEffect(PotionEffectType.SLOWNESS, (int) (3.5 * 20), 1) + }, + EntityType.SPIDER, new PotionEffect[]{ + new PotionEffect(PotionEffectType.POISON, 4 * 20, 1), + new PotionEffect(PotionEffectType.NAUSEA, 6 * 20, 10) + }, + EntityType.CREEPER, new PotionEffect[]{ + new LightningPotionEffect() + }, + EntityType.HUSK, new PotionEffect[]{ + new PotionEffect(PotionEffectType.WITHER, 7 * 20, 1) + }, + EntityType.DROWNED, new PotionEffect[]{ + new PotionEffect(PotionEffectType.WITHER, 7 * 20, 1) + }, + EntityType.WITCH, new PotionEffect[]{}, + EntityType.ZOMBIE_VILLAGER, new PotionEffect[]{ + new PotionEffect(PotionEffectType.WITHER, 7 * 20, 1) + }, + EntityType.PHANTOM, new PotionEffect[]{ + new PotionEffect(PotionEffectType.LEVITATION, (int) (1.5 * 20), 3) + }, + EntityType.ENDERMAN, new PotionEffect[]{ + new PotionEffect(PotionEffectType.SLOWNESS, (int) (2.5 * 20), 2) + } ); public final int expMultiplier = 4; - public final boolean summonLightning = true; + public final boolean lightningsActive = true; + private boolean isActive = false; + private final BossBar bossBar = Bukkit.createBossBar( + "Bloodmoon", + BarColor.RED, + BarStyle.SEGMENTED_12, + BarFlag.CREATE_FOG, + BarFlag.DARKEN_SKY + ); + private final int bloodMoonLegth = 12000; + private final int daysBetweenBloodmoons = 1; private final int minBonusDrops = 1; private final int maxBonusDrops = 4; + private final Map bonusDropWeightMap = Map.of( + new ItemStack(Material.IRON_INGOT, 5), 10, + new ItemStack(Material.GOLD_INGOT, 2), 5, + new ItemStack(Material.DIAMOND, 1), 1, + new ItemStack(Material.IRON_BLOCK, 1), 5, + new ItemStack(Material.GOLD_BLOCK, 1), 2 + ); public boolean bloodmoonIsActive() { - return true; + return this.isActive; } - public Set getRandomBonusDrops() { + public void startBloodmoon() { + this.isActive = true; + Bukkit.getOnlinePlayers().forEach(player -> this.bossBar.addPlayer(player)); + } + + public void stopBloodmoon() { + this.isActive = false; + this.bossBar.removeAll(); + } + + public void addPlayerToBossBar(Player p) { + this.bossBar.addPlayer(p); + } + + public List getRandomBonusDrops() { int itemCount = ThreadLocalRandom.current().nextInt(this.minBonusDrops, this.maxBonusDrops + 1); - return Set.of( - new ItemStack(Material.DIAMOND_BLOCK, 2), - new ItemStack(Material.IRON_BARS, 3) - ); + List result = new ArrayList<>(); + for(int i = 0; i < itemCount; i++) { + result.add(this.getRandomBonusDrop()); + } + return result; + } + + private ItemStack getRandomBonusDrop() { + int totalWeight = this.bonusDropWeightMap.values().stream().mapToInt(value -> value).sum(); + int randomInt = ThreadLocalRandom.current().nextInt(0, totalWeight + 1); + int cumulativeWeight = 0; + for(Map.Entry entry : this.bonusDropWeightMap.entrySet()) { + cumulativeWeight += entry.getValue(); + if(randomInt <= cumulativeWeight) return entry.getKey(); + } + return null; } @Override protected @NotNull List listeners() { return List.of( - new BloodmoonMonsterDeathListener() + new BloodmoonMonsterDeathListener(), + new BloodmoonPlayerJoinListener() + ); + } + + @Override + protected @NotNull List> commands() { + return List.of( + new BloodmoonCommand() ); } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/LightningPotionEffect.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/LightningPotionEffect.java new file mode 100644 index 0000000..297f74c --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/LightningPotionEffect.java @@ -0,0 +1,10 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon; + +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +public class LightningPotionEffect extends PotionEffect { + public LightningPotionEffect() { + super(PotionEffectType.SLOWNESS, 0, 0); + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java new file mode 100644 index 0000000..11340f4 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java @@ -0,0 +1,44 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.commands; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; +import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class BloodmoonCommand extends ApplianceCommand { + public BloodmoonCommand() { + super("bloodmoon"); + } + + @Override + protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception { + if(args.length == 0) { + sender.sendMessage("Bloodmoon is currently " + (this.getAppliance().bloodmoonIsActive() ? "active." : "inactive.")); + return; + } + + switch(args[0]) { + case "start": { + this.getAppliance().startBloodmoon(); + sender.sendMessage("Started bloodmoon."); + break; + } + case "stop": { + this.getAppliance().stopBloodmoon(); + sender.sendMessage("Stopped bloodmoon."); + break; + } + default: throw new Error("No such option: '" + args[0] + "' !"); + } + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if(args.length == 1) return List.of("start", "stop"); + return null; + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java new file mode 100644 index 0000000..ac2c619 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java @@ -0,0 +1,25 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Projectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageByEntityEvent; + +public class BloodmoonEntityDamageListener extends ApplianceListener { + @EventHandler + public void onEntityDamage(EntityDamageByEntityEvent event) { + if(!this.getAppliance().bloodmoonIsActive()) return; + Entity damagerEntity = event.getDamager(); + if(damagerEntity instanceof Projectile projectile) { + if(!(projectile.getShooter() instanceof Entity shooter)) return; + damagerEntity = shooter; + } + if(!(damagerEntity instanceof LivingEntity damager && event.getEntity() instanceof LivingEntity receiver)) return; + if(event.getFinalDamage() == 0) return; + + // TODO: damage increase / reduction and effects + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java index 32cec35..6ff70cd 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java @@ -11,9 +11,10 @@ public class BloodmoonMonsterDeathListener extends ApplianceListener public void onMonsterDeath(EntityDeathEvent event) { if(!this.getAppliance().bloodmoonIsActive()) return; LivingEntity entity = event.getEntity(); - if(!this.getAppliance().affectedMobs.contains(entity.getType())) return; + if(!this.getAppliance().affectedMobEffectMap.containsKey(entity.getType())) return; event.setDroppedExp(event.getDroppedExp() * this.getAppliance().expMultiplier); event.getDrops().addAll(this.getAppliance().getRandomBonusDrops()); + if(this.getAppliance().lightningsActive) event.getEntity().getWorld().strikeLightningEffect(event.getEntity().getLocation()); } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonPlayerJoinListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonPlayerJoinListener.java new file mode 100644 index 0000000..61da747 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonPlayerJoinListener.java @@ -0,0 +1,14 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; + +public class BloodmoonPlayerJoinListener extends ApplianceListener { + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + if(!this.getAppliance().bloodmoonIsActive()) return; + this.getAppliance().addPlayerToBossBar(event.getPlayer()); + } +} -- 2.30.2 From e14c87c2fb39d3babf4fb3bb18701a4fdd081afd Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 19 Oct 2025 01:18:27 +0200 Subject: [PATCH 03/15] added mob effects and Setting --- .../metaGameplay/settings/Settings.java | 3 +- .../gameplay/bloodmoon/Bloodmoon.java | 118 +++++++++++------- .../gameplay/bloodmoon/BloodmoonSetting.java | 46 +++++++ .../bloodmoon/LightningPotionEffect.java | 10 -- .../gameplay/bloodmoon/MobEffect.java | 29 +++++ .../BloodmoonEntityDamageListener.java | 12 +- .../BloodmoonMonsterDeathListener.java | 7 +- 7 files changed, 164 insertions(+), 61 deletions(-) create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java delete mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/LightningPotionEffect.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/MobEffect.java diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/settings/Settings.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/settings/Settings.java index aae45d2..dfec693 100644 --- a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/settings/Settings.java +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/metaGameplay/settings/Settings.java @@ -38,7 +38,8 @@ public class Settings extends Appliance { BorderWarning, LocatorBar, InfoBars, - CoordinateDisplay + CoordinateDisplay, + Bloodmoon } public static Settings instance() { diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index be62263..ea58d30 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -1,75 +1,80 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon; +import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.commands.BloodmoonCommand; +import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonEntityDamageListener; import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonMonsterDeathListener; import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonPlayerJoinListener; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarFlag; -import org.bukkit.boss.BarStyle; -import org.bukkit.boss.BossBar; +import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public class Bloodmoon extends Appliance { // für alle Dimensionen? einstellbar machen? - public final Map affectedMobEffectMap = Map.of( - EntityType.ZOMBIE, new PotionEffect[]{ - new PotionEffect(PotionEffectType.WITHER, 7 * 20, 1) - }, - EntityType.SKELETON, new PotionEffect[]{ - new PotionEffect(PotionEffectType.SLOWNESS, (int) (3.5 * 20), 1) - }, - EntityType.SPIDER, new PotionEffect[]{ - new PotionEffect(PotionEffectType.POISON, 4 * 20, 1), - new PotionEffect(PotionEffectType.NAUSEA, 6 * 20, 10) - }, - EntityType.CREEPER, new PotionEffect[]{ - new LightningPotionEffect() - }, - EntityType.HUSK, new PotionEffect[]{ - new PotionEffect(PotionEffectType.WITHER, 7 * 20, 1) - }, - EntityType.DROWNED, new PotionEffect[]{ - new PotionEffect(PotionEffectType.WITHER, 7 * 20, 1) - }, - EntityType.WITCH, new PotionEffect[]{}, - EntityType.ZOMBIE_VILLAGER, new PotionEffect[]{ - new PotionEffect(PotionEffectType.WITHER, 7 * 20, 1) - }, - EntityType.PHANTOM, new PotionEffect[]{ - new PotionEffect(PotionEffectType.LEVITATION, (int) (1.5 * 20), 3) - }, - EntityType.ENDERMAN, new PotionEffect[]{ - new PotionEffect(PotionEffectType.SLOWNESS, (int) (2.5 * 20), 2) - } + public final Map> affectedMobEffectMap = Map.of( + EntityType.ZOMBIE, Set.of( + new MobEffect.PotionMobEffect(PotionEffectType.WITHER, 7, 1) + ), + EntityType.SKELETON, Set.of( + new MobEffect.PotionMobEffect(PotionEffectType.SLOWNESS, 3.5, 1) + ), + EntityType.SPIDER, Set.of( + new MobEffect.PotionMobEffect(PotionEffectType.POISON, 4, 1), + new MobEffect.PotionMobEffect(PotionEffectType.NAUSEA, 6, 10) + ), + EntityType.CREEPER, Set.of( + new MobEffect.LightningMobEffect() + ), + EntityType.HUSK, Set.of( + new MobEffect.PotionMobEffect(PotionEffectType.WITHER, 7, 1) + ), + EntityType.DROWNED, Set.of( + new MobEffect.PotionMobEffect(PotionEffectType.WITHER, 7, 1) + ), + EntityType.WITCH, Set.of(), + EntityType.ZOMBIE_VILLAGER, Set.of( + new MobEffect.PotionMobEffect(PotionEffectType.WITHER, 7, 1) + ), + EntityType.PHANTOM, Set.of( + new MobEffect.PotionMobEffect(PotionEffectType.LEVITATION, 1.5, 3) + ), + EntityType.ENDERMAN, Set.of( + new MobEffect.PotionMobEffect(PotionEffectType.SLOWNESS, 2.5, 2) + ) ); public final int expMultiplier = 4; public final boolean lightningsActive = true; + public final double mobDamageMultipier = 2; + public final double mobHealthMultiplier = 3; private boolean isActive = false; - private final BossBar bossBar = Bukkit.createBossBar( - "Bloodmoon", - BarColor.RED, - BarStyle.SEGMENTED_12, - BarFlag.CREATE_FOG, - BarFlag.DARKEN_SKY + private final BossBar bossBar = BossBar.bossBar( + Component.text("Blutmond", NamedTextColor.DARK_RED), + 1f, + BossBar.Color.RED, + BossBar.Overlay.NOTCHED_12, + Set.of(BossBar.Flag.CREATE_WORLD_FOG, BossBar.Flag.DARKEN_SCREEN) ); - private final int bloodMoonLegth = 12000; + private final int bloodmoonLegth = 12000; + private final int bloodmoonStartTime = 12000; private final int daysBetweenBloodmoons = 1; private final int minBonusDrops = 1; private final int maxBonusDrops = 4; @@ -81,22 +86,40 @@ public class Bloodmoon extends Appliance { new ItemStack(Material.GOLD_BLOCK, 1), 2 ); + @Override + public void onEnable() { + Settings.instance().declareSetting(BloodmoonSetting.class); + } + public boolean bloodmoonIsActive() { return this.isActive; } public void startBloodmoon() { this.isActive = true; - Bukkit.getOnlinePlayers().forEach(player -> this.bossBar.addPlayer(player)); + Bukkit.getOnlinePlayers().forEach(this::addPlayerToBossBar); } public void stopBloodmoon() { this.isActive = false; - this.bossBar.removeAll(); + Bukkit.getOnlinePlayers().forEach(player -> player.hideBossBar(this.bossBar)); } - public void addPlayerToBossBar(Player p) { - this.bossBar.addPlayer(p); + public void addPlayerToBossBar(Player player) { + if(!this.getBloodmoonSetting(player)) return; + player.showBossBar(this.bossBar); + } + + public boolean isAffectedMob(Entity entity) { + return this.affectedMobEffectMap.containsKey(entity.getType()); + } + + public boolean getBloodmoonSetting(Player player) { + return Settings.instance().getSetting( + player, + Settings.Key.Bloodmoon, + Boolean.class + ); } public List getRandomBonusDrops() { @@ -123,7 +146,8 @@ public class Bloodmoon extends Appliance { protected @NotNull List listeners() { return List.of( new BloodmoonMonsterDeathListener(), - new BloodmoonPlayerJoinListener() + new BloodmoonPlayerJoinListener(), + new BloodmoonEntityDamageListener() ); } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java new file mode 100644 index 0000000..d0b43aa --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java @@ -0,0 +1,46 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon; + +import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.CategorizedSetting; +import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.SettingCategory; +import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; +import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes.BoolSetting; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; + +public class BloodmoonSetting extends BoolSetting implements CategorizedSetting { + public BloodmoonSetting() { + super(Settings.Key.Bloodmoon); + } + + @Override + public SettingCategory category() { + return SettingCategory.Misc; + } + + @Override + protected String title() { + return "Blutmond"; + } + + @Override + protected String description() { + return "Kämpfe während dem Blutmond mit stärkeren Monstern, um mit besseren Drops belohnt zu werden."; + } + + @Override + protected Material icon() { + return Material.CLOCK; + } + + @Override + protected Boolean defaultValue() { + return false; + } + + // TODO: only change when bloodmoon is not active + @Override + protected void change(Player player, ClickType clickType) { + super.change(player, clickType); + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/LightningPotionEffect.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/LightningPotionEffect.java deleted file mode 100644 index 297f74c..0000000 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/LightningPotionEffect.java +++ /dev/null @@ -1,10 +0,0 @@ -package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon; - -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; - -public class LightningPotionEffect extends PotionEffect { - public LightningPotionEffect() { - super(PotionEffectType.SLOWNESS, 0, 0); - } -} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/MobEffect.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/MobEffect.java new file mode 100644 index 0000000..c84ce63 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/MobEffect.java @@ -0,0 +1,29 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon; + +import net.kyori.adventure.util.Ticks; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +public abstract class MobEffect { + public abstract void apply(Player p); + + public static class PotionMobEffect extends MobEffect { + private final PotionEffect effect; + public PotionMobEffect(PotionEffectType type, double seconds, int amplifier) { + this.effect = new PotionEffect(type, (int) (seconds * Ticks.TICKS_PER_SECOND), amplifier); + } + + @Override + public void apply(Player p) { + p.addPotionEffect(this.effect); + } + } + + public static class LightningMobEffect extends MobEffect { + @Override + public void apply(Player p) { + p.getWorld().strikeLightning(p.getLocation()); + } + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java index ac2c619..3923340 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java @@ -4,6 +4,7 @@ import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.event.EventHandler; import org.bukkit.event.entity.EntityDamageByEntityEvent; @@ -20,6 +21,15 @@ public class BloodmoonEntityDamageListener extends ApplianceListener if(!(damagerEntity instanceof LivingEntity damager && event.getEntity() instanceof LivingEntity receiver)) return; if(event.getFinalDamage() == 0) return; - // TODO: damage increase / reduction and effects + if(this.getAppliance().isAffectedMob(damager) && receiver instanceof Player player) { + if(!this.getAppliance().getBloodmoonSetting(player)) return; + event.setDamage(event.getDamage() * this.getAppliance().mobDamageMultipier); + this.getAppliance().affectedMobEffectMap.get(damager.getType()).forEach(mobEffect -> mobEffect.apply(player)); + return; + } + if(this.getAppliance().isAffectedMob(receiver) && damager instanceof Player player) { + if(!this.getAppliance().getBloodmoonSetting(player)) return; + event.setDamage(event.getDamage() / this.getAppliance().mobHealthMultiplier); + } } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java index 6ff70cd..e6dce3e 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java @@ -3,6 +3,7 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.list import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.entity.EntityDeathEvent; @@ -10,11 +11,13 @@ public class BloodmoonMonsterDeathListener extends ApplianceListener @EventHandler public void onMonsterDeath(EntityDeathEvent event) { if(!this.getAppliance().bloodmoonIsActive()) return; + if(!(event.getDamageSource().getCausingEntity() instanceof Player player)) return; + if(!this.getAppliance().getBloodmoonSetting(player)) return; LivingEntity entity = event.getEntity(); - if(!this.getAppliance().affectedMobEffectMap.containsKey(entity.getType())) return; + if(!this.getAppliance().isAffectedMob(entity)) return; event.setDroppedExp(event.getDroppedExp() * this.getAppliance().expMultiplier); event.getDrops().addAll(this.getAppliance().getRandomBonusDrops()); - if(this.getAppliance().lightningsActive) event.getEntity().getWorld().strikeLightningEffect(event.getEntity().getLocation()); + if(this.getAppliance().lightningsActive) entity.getWorld().strikeLightningEffect(entity.getLocation()); } } -- 2.30.2 From d70b0255028e73f6d9d399ef887eeab793585c9d Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 19 Oct 2025 18:45:55 +0200 Subject: [PATCH 04/15] added hordes, disabled setting when bloodmoon is active --- .../gameplay/bloodmoon/Bloodmoon.java | 64 +++++++++++++++++-- .../gameplay/bloodmoon/BloodmoonSetting.java | 5 +- .../BloodmoonMonsterDeathListener.java | 2 +- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index ea58d30..7771266 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -1,6 +1,7 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon; import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; +import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.commands.BloodmoonCommand; @@ -11,6 +12,7 @@ import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -20,10 +22,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ThreadLocalRandom; public class Bloodmoon extends Appliance { @@ -61,7 +60,6 @@ public class Bloodmoon extends Appliance { ) ); public final int expMultiplier = 4; - public final boolean lightningsActive = true; public final double mobDamageMultipier = 2; public final double mobHealthMultiplier = 3; @@ -73,6 +71,17 @@ public class Bloodmoon extends Appliance { BossBar.Overlay.NOTCHED_12, Set.of(BossBar.Flag.CREATE_WORLD_FOG, BossBar.Flag.DARKEN_SCREEN) ); + private final boolean hordesEnabled = true; + private final int hordeSpawnRateTicks = 800; + private final int hordeSpawnRateVariationTicks = 100; + private final int hordeMinPopulation = 3; + private final int hordeMaxPopulation = 10; + private final int hordeSpawnDistance = 10; + private final List hordeMobList = List.of( + EntityType.ZOMBIE, + EntityType.SKELETON, + EntityType.SPIDER + ); private final int bloodmoonLegth = 12000; private final int bloodmoonStartTime = 12000; private final int daysBetweenBloodmoons = 1; @@ -98,6 +107,23 @@ public class Bloodmoon extends Appliance { public void startBloodmoon() { this.isActive = true; Bukkit.getOnlinePlayers().forEach(this::addPlayerToBossBar); + this.startHordeSpawning(this.getRandomHordeSpawnDelay()); + } + + private int getRandomHordeSpawnDelay() { + return this.hordeSpawnRateTicks + ThreadLocalRandom.current().nextInt(-this.hordeSpawnRateVariationTicks, this.hordeSpawnRateVariationTicks); + } + + private void startHordeSpawning(int delay) { + Bukkit.getScheduler().runTaskLater( + Main.instance(), + () -> { + if(!this.bloodmoonIsActive()) return; + this.spawnRandomHorde(); + this.startHordeSpawning(this.getRandomHordeSpawnDelay()); + }, + delay + ); } public void stopBloodmoon() { @@ -131,6 +157,20 @@ public class Bloodmoon extends Appliance { return result; } + public void spawnRandomHorde() { + if(Bukkit.getOnlinePlayers().isEmpty()) return; + if(!this.hordesEnabled) return; + List onlinePlayerList = Bukkit.getOnlinePlayers().stream() + .filter(this::getBloodmoonSetting) + .toList(); + ThreadLocalRandom random = ThreadLocalRandom.current(); + Player player = onlinePlayerList.get(random.nextInt(onlinePlayerList.size())); + EntityType hordeEntityType = this.hordeMobList.get(random.nextInt(this.hordeMobList.size())); + int hordeSize = random.nextInt(this.hordeMinPopulation, this.hordeMaxPopulation + 1); + this.spawnHorde(player, hordeSize, hordeEntityType); + Bukkit.getOnlinePlayers().forEach(p -> p.sendMessage(Component.text("Eine Horde ist bei %s gespawnt.".formatted(player.getName()), NamedTextColor.RED))); + } + private ItemStack getRandomBonusDrop() { int totalWeight = this.bonusDropWeightMap.values().stream().mapToInt(value -> value).sum(); int randomInt = ThreadLocalRandom.current().nextInt(0, totalWeight + 1); @@ -142,6 +182,20 @@ public class Bloodmoon extends Appliance { return null; } + private void spawnHorde(Player player, int size, EntityType type) { + for(int i = 0; i < size; i++) { + double spawnRadiant = ThreadLocalRandom.current().nextDouble(0, 2*Math.PI); + Location mobSpawnLocation = player.getLocation().clone().add( + Math.sin(spawnRadiant)*this.hordeSpawnDistance, + 0, + Math.cos(spawnRadiant)*this.hordeSpawnDistance + ); + mobSpawnLocation.setY(player.getWorld().getHighestBlockYAt(mobSpawnLocation) + 1); + player.getWorld().spawnEntity(mobSpawnLocation, type); + player.getWorld().strikeLightningEffect(mobSpawnLocation); + } + } + @Override protected @NotNull List listeners() { return List.of( diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java index d0b43aa..f75e145 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java @@ -4,6 +4,7 @@ import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Categor import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.SettingCategory; import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes.BoolSetting; +import eu.mhsl.craftattack.spawn.core.Main; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; @@ -25,7 +26,7 @@ public class BloodmoonSetting extends BoolSetting implements CategorizedSetting @Override protected String description() { - return "Kämpfe während dem Blutmond mit stärkeren Monstern, um mit besseren Drops belohnt zu werden."; + return "Kämpfe während dem Blutmond mit stärkeren Monstern mit besseren Drops. Kann nicht während dem Blutmond geändert werden!"; } @Override @@ -38,9 +39,9 @@ public class BloodmoonSetting extends BoolSetting implements CategorizedSetting return false; } - // TODO: only change when bloodmoon is not active @Override protected void change(Player player, ClickType clickType) { + if(Main.instance().getAppliance(Bloodmoon.class).bloodmoonIsActive()) return; super.change(player, clickType); } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java index e6dce3e..5ec9bb3 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonMonsterDeathListener.java @@ -18,6 +18,6 @@ public class BloodmoonMonsterDeathListener extends ApplianceListener event.setDroppedExp(event.getDroppedExp() * this.getAppliance().expMultiplier); event.getDrops().addAll(this.getAppliance().getRandomBonusDrops()); - if(this.getAppliance().lightningsActive) entity.getWorld().strikeLightningEffect(entity.getLocation()); + entity.getWorld().strikeLightningEffect(entity.getLocation()); } } -- 2.30.2 From 263fd85df73e4582915157c00ae51f216ae36123 Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 19 Oct 2025 18:56:12 +0200 Subject: [PATCH 05/15] fixed multiple horde tasks being started --- .../appliances/gameplay/bloodmoon/Bloodmoon.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index 7771266..41ee3da 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -20,7 +20,9 @@ import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -82,6 +84,7 @@ public class Bloodmoon extends Appliance { EntityType.SKELETON, EntityType.SPIDER ); + private @Nullable BukkitTask hordeSpawnTask = null; private final int bloodmoonLegth = 12000; private final int bloodmoonStartTime = 12000; private final int daysBetweenBloodmoons = 1; @@ -115,7 +118,8 @@ public class Bloodmoon extends Appliance { } private void startHordeSpawning(int delay) { - Bukkit.getScheduler().runTaskLater( + if(this.hordeSpawnTask != null) this.hordeSpawnTask.cancel(); + this.hordeSpawnTask = Bukkit.getScheduler().runTaskLater( Main.instance(), () -> { if(!this.bloodmoonIsActive()) return; -- 2.30.2 From 045f31d4ca772ca5ff4faef212e5f67218103513 Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 19 Oct 2025 21:26:24 +0200 Subject: [PATCH 06/15] removed horde announcement message and unnecessary copy of player location, added setting feedback when bloodmoon active --- .../gameplay/bloodmoon/Bloodmoon.java | 57 ++++++++++--------- .../gameplay/bloodmoon/BloodmoonSetting.java | 11 +++- .../bloodmoon/commands/BloodmoonCommand.java | 4 +- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index 41ee3da..b7de9a3 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -12,6 +12,7 @@ import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Entity; @@ -152,6 +153,34 @@ public class Bloodmoon extends Appliance { ); } + public void spawnRandomHorde() { + if(Bukkit.getOnlinePlayers().isEmpty()) return; + if(!this.hordesEnabled) return; + List onlinePlayerList = Bukkit.getOnlinePlayers().stream() + .filter(this::getBloodmoonSetting) + .filter(player -> player.getGameMode().equals(GameMode.SURVIVAL)) + .toList(); + ThreadLocalRandom random = ThreadLocalRandom.current(); + Player player = onlinePlayerList.get(random.nextInt(onlinePlayerList.size())); + EntityType hordeEntityType = this.hordeMobList.get(random.nextInt(this.hordeMobList.size())); + int hordeSize = random.nextInt(this.hordeMinPopulation, this.hordeMaxPopulation + 1); + this.spawnHorde(player, hordeSize, hordeEntityType); + } + + private void spawnHorde(Player player, int size, EntityType type) { + for(int i = 0; i < size; i++) { + double spawnRadiant = ThreadLocalRandom.current().nextDouble(0, 2*Math.PI); + Location mobSpawnLocation = player.getLocation().add( + Math.sin(spawnRadiant)*this.hordeSpawnDistance, + 0, + Math.cos(spawnRadiant)*this.hordeSpawnDistance + ); + mobSpawnLocation.setY(player.getWorld().getHighestBlockYAt(mobSpawnLocation) + 1); + player.getWorld().spawnEntity(mobSpawnLocation, type); + player.getWorld().strikeLightningEffect(mobSpawnLocation); + } + } + public List getRandomBonusDrops() { int itemCount = ThreadLocalRandom.current().nextInt(this.minBonusDrops, this.maxBonusDrops + 1); List result = new ArrayList<>(); @@ -161,20 +190,6 @@ public class Bloodmoon extends Appliance { return result; } - public void spawnRandomHorde() { - if(Bukkit.getOnlinePlayers().isEmpty()) return; - if(!this.hordesEnabled) return; - List onlinePlayerList = Bukkit.getOnlinePlayers().stream() - .filter(this::getBloodmoonSetting) - .toList(); - ThreadLocalRandom random = ThreadLocalRandom.current(); - Player player = onlinePlayerList.get(random.nextInt(onlinePlayerList.size())); - EntityType hordeEntityType = this.hordeMobList.get(random.nextInt(this.hordeMobList.size())); - int hordeSize = random.nextInt(this.hordeMinPopulation, this.hordeMaxPopulation + 1); - this.spawnHorde(player, hordeSize, hordeEntityType); - Bukkit.getOnlinePlayers().forEach(p -> p.sendMessage(Component.text("Eine Horde ist bei %s gespawnt.".formatted(player.getName()), NamedTextColor.RED))); - } - private ItemStack getRandomBonusDrop() { int totalWeight = this.bonusDropWeightMap.values().stream().mapToInt(value -> value).sum(); int randomInt = ThreadLocalRandom.current().nextInt(0, totalWeight + 1); @@ -186,20 +201,6 @@ public class Bloodmoon extends Appliance { return null; } - private void spawnHorde(Player player, int size, EntityType type) { - for(int i = 0; i < size; i++) { - double spawnRadiant = ThreadLocalRandom.current().nextDouble(0, 2*Math.PI); - Location mobSpawnLocation = player.getLocation().clone().add( - Math.sin(spawnRadiant)*this.hordeSpawnDistance, - 0, - Math.cos(spawnRadiant)*this.hordeSpawnDistance - ); - mobSpawnLocation.setY(player.getWorld().getHighestBlockYAt(mobSpawnLocation) + 1); - player.getWorld().spawnEntity(mobSpawnLocation, type); - player.getWorld().strikeLightningEffect(mobSpawnLocation); - } - } - @Override protected @NotNull List listeners() { return List.of( diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java index f75e145..6c49a84 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java @@ -5,6 +5,9 @@ import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Setting import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes.BoolSetting; import eu.mhsl.craftattack.spawn.core.Main; +import eu.mhsl.craftattack.spawn.core.util.world.InteractSounds; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; @@ -36,12 +39,16 @@ public class BloodmoonSetting extends BoolSetting implements CategorizedSetting @Override protected Boolean defaultValue() { - return false; + return true; } @Override protected void change(Player player, ClickType clickType) { - if(Main.instance().getAppliance(Bloodmoon.class).bloodmoonIsActive()) return; + if(Main.instance().getAppliance(Bloodmoon.class).bloodmoonIsActive()) { + InteractSounds.of(player).delete(); + player.sendMessage(Component.text("Während dem Blutmond kann diese Einstellung nicht geändert werden!", NamedTextColor.RED)); + return; + } super.change(player, clickType); } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java index 11340f4..30540ad 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java @@ -17,7 +17,7 @@ public class BloodmoonCommand extends ApplianceCommand { @Override protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception { if(args.length == 0) { - sender.sendMessage("Bloodmoon is currently " + (this.getAppliance().bloodmoonIsActive() ? "active." : "inactive.")); + sender.sendMessage("Bloodmoon is currently %s.".formatted(this.getAppliance().bloodmoonIsActive() ? "active" : "inactive")); return; } @@ -32,7 +32,7 @@ public class BloodmoonCommand extends ApplianceCommand { sender.sendMessage("Stopped bloodmoon."); break; } - default: throw new Error("No such option: '" + args[0] + "' !"); + default: throw new Error("No such option: '%s' !".formatted(args[0])); } } -- 2.30.2 From 1182cb2ed626763d0a6e6a58f856d4432acc7de8 Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 19 Oct 2025 21:35:03 +0200 Subject: [PATCH 07/15] added todos --- .../appliances/gameplay/bloodmoon/BloodmoonSetting.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java index 6c49a84..e2925d8 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java @@ -19,7 +19,7 @@ public class BloodmoonSetting extends BoolSetting implements CategorizedSetting @Override public SettingCategory category() { - return SettingCategory.Misc; + return SettingCategory.Misc; // TODO: mehr als 8 bug fixen } @Override @@ -42,6 +42,8 @@ public class BloodmoonSetting extends BoolSetting implements CategorizedSetting return true; } + // TODO: Settings deaktivierbar machen + @Override protected void change(Player player, ClickType clickType) { if(Main.instance().getAppliance(Bloodmoon.class).bloodmoonIsActive()) { -- 2.30.2 From ff81c91661ff2b22205fb1cb5a7d7ea5f54b0210 Mon Sep 17 00:00:00 2001 From: lars Date: Mon, 20 Oct 2025 16:27:10 +0200 Subject: [PATCH 08/15] changed horde spawning to delay for each player --- .../gameplay/bloodmoon/Bloodmoon.java | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index b7de9a3..ff29e5a 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -12,7 +12,6 @@ import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; -import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Entity; @@ -76,7 +75,7 @@ public class Bloodmoon extends Appliance { ); private final boolean hordesEnabled = true; private final int hordeSpawnRateTicks = 800; - private final int hordeSpawnRateVariationTicks = 100; + private final int hordeSpawnRateVariationTicks = 800; private final int hordeMinPopulation = 3; private final int hordeMaxPopulation = 10; private final int hordeSpawnDistance = 10; @@ -85,7 +84,7 @@ public class Bloodmoon extends Appliance { EntityType.SKELETON, EntityType.SPIDER ); - private @Nullable BukkitTask hordeSpawnTask = null; + private final Map hordeSpawnTasks = new HashMap<>(); private final int bloodmoonLegth = 12000; private final int bloodmoonStartTime = 12000; private final int daysBetweenBloodmoons = 1; @@ -115,20 +114,26 @@ public class Bloodmoon extends Appliance { } private int getRandomHordeSpawnDelay() { - return this.hordeSpawnRateTicks + ThreadLocalRandom.current().nextInt(-this.hordeSpawnRateVariationTicks, this.hordeSpawnRateVariationTicks); + return this.hordeSpawnRateTicks + ThreadLocalRandom.current().nextInt(this.hordeSpawnRateVariationTicks); } private void startHordeSpawning(int delay) { - if(this.hordeSpawnTask != null) this.hordeSpawnTask.cancel(); - this.hordeSpawnTask = Bukkit.getScheduler().runTaskLater( - Main.instance(), - () -> { - if(!this.bloodmoonIsActive()) return; - this.spawnRandomHorde(); - this.startHordeSpawning(this.getRandomHordeSpawnDelay()); - }, - delay + Bukkit.getOnlinePlayers().forEach(player -> this.startHordeSpawning(delay, player)); + } + + private void startHordeSpawning(int delay, Player player) { + @Nullable BukkitTask task = this.hordeSpawnTasks.get(player); + if(task != null) task.cancel(); + task = Bukkit.getScheduler().runTaskLater( + Main.instance(), + () -> { + if(!this.bloodmoonIsActive()) return; + this.spawnRandomHorde(); + this.startHordeSpawning(this.getRandomHordeSpawnDelay()); + }, + delay ); + this.hordeSpawnTasks.put(player, task); } public void stopBloodmoon() { @@ -158,7 +163,7 @@ public class Bloodmoon extends Appliance { if(!this.hordesEnabled) return; List onlinePlayerList = Bukkit.getOnlinePlayers().stream() .filter(this::getBloodmoonSetting) - .filter(player -> player.getGameMode().equals(GameMode.SURVIVAL)) +// .filter(player -> player.getGameMode().equals(GameMode.SURVIVAL)) .toList(); ThreadLocalRandom random = ThreadLocalRandom.current(); Player player = onlinePlayerList.get(random.nextInt(onlinePlayerList.size())); -- 2.30.2 From 0565f5de9e0dcbfd3bfa1bd52e60d38c9b1f2579 Mon Sep 17 00:00:00 2001 From: lars Date: Mon, 20 Oct 2025 16:28:00 +0200 Subject: [PATCH 09/15] changed bloodmoon setting description --- .../appliances/gameplay/bloodmoon/BloodmoonSetting.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java index e2925d8..c7dadeb 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java @@ -29,7 +29,7 @@ public class BloodmoonSetting extends BoolSetting implements CategorizedSetting @Override protected String description() { - return "Kämpfe während dem Blutmond mit stärkeren Monstern mit besseren Drops. Kann nicht während dem Blutmond geändert werden!"; + return "Kämpfe während dem Blutmond gegen stärkere Monster mit besseren Drops. Kann nicht während dem Blutmond geändert werden!"; } @Override -- 2.30.2 From b55035f1f021659d59faf9d7faa7daf9be80950f Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 1 Nov 2025 17:29:39 +0100 Subject: [PATCH 10/15] added timings and announcements for automatic bloodmoon start --- .../gameplay/bloodmoon/Bloodmoon.java | 65 ++++++++++++++++--- .../listener/BloodmoonPlayerJoinListener.java | 1 + .../listener/BloodmoonTimeListener.java | 28 ++++++++ 3 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index b7de9a3..dc1b1cf 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -8,9 +8,11 @@ import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.comma import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonEntityDamageListener; import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonMonsterDeathListener; import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonPlayerJoinListener; +import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonTimeListener; import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; @@ -86,9 +88,11 @@ public class Bloodmoon extends Appliance { EntityType.SPIDER ); private @Nullable BukkitTask hordeSpawnTask = null; - private final int bloodmoonLegth = 12000; + public final int bloodmoonLength = 12000; + public final int ticksPerDay = 24000; + private final int bloodmoonFreeDaysAtStart = 3; private final int bloodmoonStartTime = 12000; - private final int daysBetweenBloodmoons = 1; + private final int bloodmoonDayInterval = 2; private final int minBonusDrops = 1; private final int maxBonusDrops = 4; private final Map bonusDropWeightMap = Map.of( @@ -112,6 +116,20 @@ public class Bloodmoon extends Appliance { this.isActive = true; Bukkit.getOnlinePlayers().forEach(this::addPlayerToBossBar); this.startHordeSpawning(this.getRandomHordeSpawnDelay()); + this.sendStartMessages(); + } + + public void stopBloodmoon() { + this.isActive = false; + Bukkit.getOnlinePlayers().forEach(player -> player.hideBossBar(this.bossBar)); + this.sendStopMessages(); + } + + public boolean isStartTick(long tick) { + long day = tick / this.ticksPerDay; + if(day % this.bloodmoonDayInterval != 0 || day - this.bloodmoonFreeDaysAtStart <= 0) return false; + long time = tick - (day * this.ticksPerDay); + return time == this.bloodmoonStartTime; } private int getRandomHordeSpawnDelay() { @@ -131,11 +149,6 @@ public class Bloodmoon extends Appliance { ); } - public void stopBloodmoon() { - this.isActive = false; - Bukkit.getOnlinePlayers().forEach(player -> player.hideBossBar(this.bossBar)); - } - public void addPlayerToBossBar(Player player) { if(!this.getBloodmoonSetting(player)) return; player.showBossBar(this.bossBar); @@ -167,6 +180,18 @@ public class Bloodmoon extends Appliance { this.spawnHorde(player, hordeSize, hordeEntityType); } + public void sendWarningMessage(Player p) { + p.sendMessage(Component.text("Der Blutmond waltet in diesem Augenblick!", NamedTextColor.RED)); + } + + public void sendAnnouncementMessages() { + this.sendMessage(Component.text("Der Blutmond naht; morgen wird er den Himmel beherrschen", NamedTextColor.GOLD)); + } + + public void sendPreStartMessages() { + this.sendMessage(Component.text("Der Himmel ist heute Nacht ungewöhnlich düster", NamedTextColor.DARK_PURPLE)); + } + private void spawnHorde(Player player, int size, EntityType type) { for(int i = 0; i < size; i++) { double spawnRadiant = ThreadLocalRandom.current().nextDouble(0, 2*Math.PI); @@ -201,12 +226,36 @@ public class Bloodmoon extends Appliance { return null; } + private void sendMessage(Component message) { + if(Bukkit.getOnlinePlayers().isEmpty()) return; + List onlinePlayers = Bukkit.getOnlinePlayers().stream() + .filter(this::getBloodmoonSetting) + .toList(); + onlinePlayers.forEach(player -> player.sendMessage(message)); + } + + private void sendStartMessages() { + this.sendMessage( + Component.empty() + .append(Component.text("Der Blutmond ist über uns", NamedTextColor.DARK_RED, TextDecoration.BOLD)) + .appendNewline() + .append(Component.text("Erfahrung vervielfacht sich und Mobs lassen reichere Beute fallen", NamedTextColor.RED)) + .appendNewline() + .append(Component.text("Mobs sind erstarkt und belegen dich mit finsteren Debuffs", NamedTextColor.RED)) + ); + } + + private void sendStopMessages() { + this.sendMessage(Component.text("Der Blutmond weicht...", NamedTextColor.GREEN, TextDecoration.BOLD)); + } + @Override protected @NotNull List listeners() { return List.of( new BloodmoonMonsterDeathListener(), new BloodmoonPlayerJoinListener(), - new BloodmoonEntityDamageListener() + new BloodmoonEntityDamageListener(), + new BloodmoonTimeListener() ); } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonPlayerJoinListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonPlayerJoinListener.java index 61da747..30c575e 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonPlayerJoinListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonPlayerJoinListener.java @@ -10,5 +10,6 @@ public class BloodmoonPlayerJoinListener extends ApplianceListener { public void onPlayerJoin(PlayerJoinEvent event) { if(!this.getAppliance().bloodmoonIsActive()) return; this.getAppliance().addPlayerToBossBar(event.getPlayer()); + this.getAppliance().sendWarningMessage(event.getPlayer()); } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java new file mode 100644 index 0000000..13325e3 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java @@ -0,0 +1,28 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener; + +import com.destroystokyo.paper.event.server.ServerTickStartEvent; +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; + +public class BloodmoonTimeListener extends ApplianceListener { + @EventHandler + public void onServerTick(ServerTickStartEvent event) { + if(this.getAppliance().isStartTick(Bukkit.getWorlds().getFirst().getFullTime())) { + this.getAppliance().startBloodmoon(); + return; + } + if(this.getAppliance().isStartTick(Bukkit.getWorlds().getFirst().getFullTime() - this.getAppliance().bloodmoonLength)) { + this.getAppliance().stopBloodmoon(); + return; + } + if(this.getAppliance().isStartTick(Bukkit.getWorlds().getFirst().getFullTime() + this.getAppliance().ticksPerDay)) { + this.getAppliance().sendAnnouncementMessages(); + return; + } + if(this.getAppliance().isStartTick(Bukkit.getWorlds().getFirst().getFullTime() + 1000)) { + this.getAppliance().sendPreStartMessages(); + } + } +} -- 2.30.2 From 53dbeff82912c790b6c7c4c73ea2f058bd23d466 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 1 Nov 2025 17:43:35 +0100 Subject: [PATCH 11/15] merged automatic start with hordes per player --- .../craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index 1b69e5b..41aef89 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -88,7 +88,6 @@ public class Bloodmoon extends Appliance { EntityType.SPIDER ); private final Map hordeSpawnTasks = new HashMap<>(); - private @Nullable BukkitTask hordeSpawnTask = null; public final int bloodmoonLength = 12000; public final int ticksPerDay = 24000; private final int bloodmoonFreeDaysAtStart = 3; @@ -149,7 +148,7 @@ public class Bloodmoon extends Appliance { () -> { if(!this.bloodmoonIsActive()) return; this.spawnRandomHorde(); - this.startHordeSpawning(this.getRandomHordeSpawnDelay()); + this.startHordeSpawning(this.getRandomHordeSpawnDelay(), player); }, delay ); -- 2.30.2 From 143f4ee8ebe2d3cbd0c24c11314ebde7dda90fbd Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 21 Nov 2025 09:03:43 +0100 Subject: [PATCH 12/15] adjusted bloodmoon settings --- .../gameplay/bloodmoon/Bloodmoon.java | 18 ++++++++++-------- .../BloodmoonEntityDamageListener.java | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index 41aef89..ccace71 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -13,6 +13,7 @@ import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.util.Ticks; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; @@ -30,6 +31,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.ThreadLocalRandom; +@SuppressWarnings("FieldCanBeLocal") public class Bloodmoon extends Appliance { // für alle Dimensionen? einstellbar machen? @@ -64,9 +66,9 @@ public class Bloodmoon extends Appliance { new MobEffect.PotionMobEffect(PotionEffectType.SLOWNESS, 2.5, 2) ) ); - public final int expMultiplier = 4; - public final double mobDamageMultipier = 2; - public final double mobHealthMultiplier = 3; + public final int expMultiplier = 3; + public final double mobDamageMultiplier = 2; + public final double mobHealthMultiplier = 2; private boolean isActive = false; private final BossBar bossBar = BossBar.bossBar( @@ -77,8 +79,8 @@ public class Bloodmoon extends Appliance { Set.of(BossBar.Flag.CREATE_WORLD_FOG, BossBar.Flag.DARKEN_SCREEN) ); private final boolean hordesEnabled = true; - private final int hordeSpawnRateTicks = 800; - private final int hordeSpawnRateVariationTicks = 800; + private final int hordeSpawnRateTicks = 40 * Ticks.TICKS_PER_SECOND; + private final int hordeSpawnRateVariationTicks = 40 * Ticks.TICKS_PER_SECOND; private final int hordeMinPopulation = 3; private final int hordeMaxPopulation = 10; private final int hordeSpawnDistance = 10; @@ -88,11 +90,11 @@ public class Bloodmoon extends Appliance { EntityType.SPIDER ); private final Map hordeSpawnTasks = new HashMap<>(); - public final int bloodmoonLength = 12000; public final int ticksPerDay = 24000; + public final int bloodmoonLength = ticksPerDay/2; private final int bloodmoonFreeDaysAtStart = 3; - private final int bloodmoonStartTime = 12000; - private final int bloodmoonDayInterval = 2; + private final int bloodmoonStartTime = ticksPerDay/2; + private final int bloodmoonDayInterval = 30; private final int minBonusDrops = 1; private final int maxBonusDrops = 4; private final Map bonusDropWeightMap = Map.of( diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java index 3923340..8f2b4f5 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonEntityDamageListener.java @@ -23,7 +23,7 @@ public class BloodmoonEntityDamageListener extends ApplianceListener if(this.getAppliance().isAffectedMob(damager) && receiver instanceof Player player) { if(!this.getAppliance().getBloodmoonSetting(player)) return; - event.setDamage(event.getDamage() * this.getAppliance().mobDamageMultipier); + event.setDamage(event.getDamage() * this.getAppliance().mobDamageMultiplier); this.getAppliance().affectedMobEffectMap.get(damager.getType()).forEach(mobEffect -> mobEffect.apply(player)); return; } -- 2.30.2 From c90d767f0fe588350c6bf58b20935c5f42e90de9 Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 21 Nov 2025 09:12:17 +0100 Subject: [PATCH 13/15] added todos --- .../craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index ccace71..bdc3976 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -34,6 +34,7 @@ import java.util.concurrent.ThreadLocalRandom; @SuppressWarnings("FieldCanBeLocal") public class Bloodmoon extends Appliance { // für alle Dimensionen? einstellbar machen? + // TODO: Bossbar muss kleiner werden public final Map> affectedMobEffectMap = Map.of( EntityType.ZOMBIE, Set.of( @@ -149,6 +150,7 @@ public class Bloodmoon extends Appliance { Main.instance(), () -> { if(!this.bloodmoonIsActive()) return; + // TODO: Nur für den speziellen Spieler this.spawnRandomHorde(); this.startHordeSpawning(this.getRandomHordeSpawnDelay(), player); }, -- 2.30.2 From b8725bc0f2e9f88bf2ebb1862bc148f6193cec9a Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 23 Nov 2025 13:58:02 +0100 Subject: [PATCH 14/15] made bossbar shrink until end of bloodmoon, fixed horde spawning --- .../gameplay/bloodmoon/Bloodmoon.java | 25 +++++++++++-------- .../bloodmoon/commands/BloodmoonCommand.java | 2 +- .../listener/BloodmoonTimeListener.java | 12 +++++---- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index bdc3976..f025005 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -34,7 +34,6 @@ import java.util.concurrent.ThreadLocalRandom; @SuppressWarnings("FieldCanBeLocal") public class Bloodmoon extends Appliance { // für alle Dimensionen? einstellbar machen? - // TODO: Bossbar muss kleiner werden public final Map> affectedMobEffectMap = Map.of( EntityType.ZOMBIE, Set.of( @@ -91,6 +90,7 @@ public class Bloodmoon extends Appliance { EntityType.SPIDER ); private final Map hordeSpawnTasks = new HashMap<>(); + private long lastBloodmoonStartTick = 0; public final int ticksPerDay = 24000; public final int bloodmoonLength = ticksPerDay/2; private final int bloodmoonFreeDaysAtStart = 3; @@ -115,7 +115,8 @@ public class Bloodmoon extends Appliance { return this.isActive; } - public void startBloodmoon() { + public void startBloodmoon(long startTick) { + this.lastBloodmoonStartTick = startTick; this.isActive = true; Bukkit.getOnlinePlayers().forEach(this::addPlayerToBossBar); this.startHordeSpawning(this.getRandomHordeSpawnDelay()); @@ -128,6 +129,14 @@ public class Bloodmoon extends Appliance { this.sendStopMessages(); } + public void updateBossBar() { + long tick = Bukkit.getWorlds().getFirst().getFullTime(); + long sinceStart = tick - this.lastBloodmoonStartTick; + float progress = 1f - ((float) sinceStart / this.bloodmoonLength); + if(progress < 0) progress = 1f; + this.bossBar.progress(progress); + } + public boolean isStartTick(long tick) { long day = tick / this.ticksPerDay; if(day % this.bloodmoonDayInterval != 0 || day - this.bloodmoonFreeDaysAtStart <= 0) return false; @@ -150,8 +159,7 @@ public class Bloodmoon extends Appliance { Main.instance(), () -> { if(!this.bloodmoonIsActive()) return; - // TODO: Nur für den speziellen Spieler - this.spawnRandomHorde(); + this.spawnRandomHorde(player); this.startHordeSpawning(this.getRandomHordeSpawnDelay(), player); }, delay @@ -176,15 +184,10 @@ public class Bloodmoon extends Appliance { ); } - public void spawnRandomHorde() { - if(Bukkit.getOnlinePlayers().isEmpty()) return; + public void spawnRandomHorde(Player player) { if(!this.hordesEnabled) return; - List onlinePlayerList = Bukkit.getOnlinePlayers().stream() - .filter(this::getBloodmoonSetting) - .filter(player -> player.getGameMode().equals(GameMode.SURVIVAL)) - .toList(); + if(!player.getGameMode().equals(GameMode.SURVIVAL)) return; ThreadLocalRandom random = ThreadLocalRandom.current(); - Player player = onlinePlayerList.get(random.nextInt(onlinePlayerList.size())); EntityType hordeEntityType = this.hordeMobList.get(random.nextInt(this.hordeMobList.size())); int hordeSize = random.nextInt(this.hordeMinPopulation, this.hordeMaxPopulation + 1); this.spawnHorde(player, hordeSize, hordeEntityType); diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java index 30540ad..42a788c 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/commands/BloodmoonCommand.java @@ -23,7 +23,7 @@ public class BloodmoonCommand extends ApplianceCommand { switch(args[0]) { case "start": { - this.getAppliance().startBloodmoon(); + this.getAppliance().startBloodmoon(0L); sender.sendMessage("Started bloodmoon."); break; } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java index 13325e3..374d1e2 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java @@ -9,19 +9,21 @@ import org.bukkit.event.EventHandler; public class BloodmoonTimeListener extends ApplianceListener { @EventHandler public void onServerTick(ServerTickStartEvent event) { - if(this.getAppliance().isStartTick(Bukkit.getWorlds().getFirst().getFullTime())) { - this.getAppliance().startBloodmoon(); + long currentTime = Bukkit.getWorlds().getFirst().getFullTime(); + if(this.getAppliance().isStartTick(currentTime)) { + this.getAppliance().startBloodmoon(currentTime); return; } - if(this.getAppliance().isStartTick(Bukkit.getWorlds().getFirst().getFullTime() - this.getAppliance().bloodmoonLength)) { + if(this.getAppliance().isStartTick(currentTime - this.getAppliance().bloodmoonLength)) { this.getAppliance().stopBloodmoon(); return; } - if(this.getAppliance().isStartTick(Bukkit.getWorlds().getFirst().getFullTime() + this.getAppliance().ticksPerDay)) { + this.getAppliance().updateBossBar(); + if(this.getAppliance().isStartTick(currentTime + this.getAppliance().ticksPerDay)) { this.getAppliance().sendAnnouncementMessages(); return; } - if(this.getAppliance().isStartTick(Bukkit.getWorlds().getFirst().getFullTime() + 1000)) { + if(this.getAppliance().isStartTick(currentTime + 1000)) { this.getAppliance().sendPreStartMessages(); } } -- 2.30.2 From 4d9548aafcb0218c33fd829fc9a25fee4ccd8c8b Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 23 Nov 2025 15:00:16 +0100 Subject: [PATCH 15/15] resolved pr comments --- .../gameplay/bloodmoon/Bloodmoon.java | 67 ++++++++++--------- .../gameplay/bloodmoon/BloodmoonSetting.java | 2 +- .../listener/BloodmoonTimeListener.java | 5 +- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index f025005..b4de47f 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -33,43 +33,43 @@ import java.util.concurrent.ThreadLocalRandom; @SuppressWarnings("FieldCanBeLocal") public class Bloodmoon extends Appliance { - // für alle Dimensionen? einstellbar machen? - - public final Map> affectedMobEffectMap = Map.of( - EntityType.ZOMBIE, Set.of( + public final Map> affectedMobEffectMap = Map.ofEntries( + Map.entry(EntityType.ZOMBIE, Set.of( new MobEffect.PotionMobEffect(PotionEffectType.WITHER, 7, 1) - ), - EntityType.SKELETON, Set.of( + )), + Map.entry(EntityType.SKELETON, Set.of( new MobEffect.PotionMobEffect(PotionEffectType.SLOWNESS, 3.5, 1) - ), - EntityType.SPIDER, Set.of( + )), + Map.entry(EntityType.SPIDER, Set.of( new MobEffect.PotionMobEffect(PotionEffectType.POISON, 4, 1), new MobEffect.PotionMobEffect(PotionEffectType.NAUSEA, 6, 10) - ), - EntityType.CREEPER, Set.of( + )), + Map.entry(EntityType.CREEPER, Set.of( new MobEffect.LightningMobEffect() - ), - EntityType.HUSK, Set.of( + )), + Map.entry(EntityType.HUSK, Set.of( new MobEffect.PotionMobEffect(PotionEffectType.WITHER, 7, 1) - ), - EntityType.DROWNED, Set.of( + )), + Map.entry(EntityType.STRAY, Set.of()), + Map.entry(EntityType.DROWNED, Set.of( new MobEffect.PotionMobEffect(PotionEffectType.WITHER, 7, 1) - ), - EntityType.WITCH, Set.of(), - EntityType.ZOMBIE_VILLAGER, Set.of( + )), + Map.entry(EntityType.WITCH, Set.of()), + Map.entry(EntityType.ZOMBIE_VILLAGER, Set.of( new MobEffect.PotionMobEffect(PotionEffectType.WITHER, 7, 1) - ), - EntityType.PHANTOM, Set.of( + )), + Map.entry(EntityType.PHANTOM, Set.of( new MobEffect.PotionMobEffect(PotionEffectType.LEVITATION, 1.5, 3) - ), - EntityType.ENDERMAN, Set.of( + )), + Map.entry(EntityType.ENDERMAN, Set.of( new MobEffect.PotionMobEffect(PotionEffectType.SLOWNESS, 2.5, 2) - ) + )) ); public final int expMultiplier = 3; public final double mobDamageMultiplier = 2; public final double mobHealthMultiplier = 2; + private final ThreadLocalRandom random = ThreadLocalRandom.current(); private boolean isActive = false; private final BossBar bossBar = BossBar.bossBar( Component.text("Blutmond", NamedTextColor.DARK_RED), @@ -89,10 +89,11 @@ public class Bloodmoon extends Appliance { EntityType.SKELETON, EntityType.SPIDER ); - private final Map hordeSpawnTasks = new HashMap<>(); + private final Map hordeSpawnTasks = new WeakHashMap<>(); private long lastBloodmoonStartTick = 0; public final int ticksPerDay = 24000; public final int bloodmoonLength = ticksPerDay/2; + public final int preStartMessageTicks = Ticks.TICKS_PER_SECOND * 50; private final int bloodmoonFreeDaysAtStart = 3; private final int bloodmoonStartTime = ticksPerDay/2; private final int bloodmoonDayInterval = 30; @@ -145,7 +146,7 @@ public class Bloodmoon extends Appliance { } private int getRandomHordeSpawnDelay() { - return this.hordeSpawnRateTicks + ThreadLocalRandom.current().nextInt(this.hordeSpawnRateVariationTicks); + return this.hordeSpawnRateTicks + this.random.nextInt(this.hordeSpawnRateVariationTicks); } private void startHordeSpawning(int delay) { @@ -155,7 +156,7 @@ public class Bloodmoon extends Appliance { private void startHordeSpawning(int delay, Player player) { @Nullable BukkitTask task = this.hordeSpawnTasks.get(player); if(task != null) task.cancel(); - task = Bukkit.getScheduler().runTaskLater( + BukkitTask newTask = Bukkit.getScheduler().runTaskLater( Main.instance(), () -> { if(!this.bloodmoonIsActive()) return; @@ -164,7 +165,7 @@ public class Bloodmoon extends Appliance { }, delay ); - this.hordeSpawnTasks.put(player, task); + this.hordeSpawnTasks.put(player, newTask); } public void addPlayerToBossBar(Player player) { @@ -187,9 +188,9 @@ public class Bloodmoon extends Appliance { public void spawnRandomHorde(Player player) { if(!this.hordesEnabled) return; if(!player.getGameMode().equals(GameMode.SURVIVAL)) return; - ThreadLocalRandom random = ThreadLocalRandom.current(); - EntityType hordeEntityType = this.hordeMobList.get(random.nextInt(this.hordeMobList.size())); - int hordeSize = random.nextInt(this.hordeMinPopulation, this.hordeMaxPopulation + 1); + + EntityType hordeEntityType = this.hordeMobList.get(this.random.nextInt(this.hordeMobList.size())); + int hordeSize = this.random.nextInt(this.hordeMinPopulation, this.hordeMaxPopulation + 1); this.spawnHorde(player, hordeSize, hordeEntityType); } @@ -207,7 +208,7 @@ public class Bloodmoon extends Appliance { private void spawnHorde(Player player, int size, EntityType type) { for(int i = 0; i < size; i++) { - double spawnRadiant = ThreadLocalRandom.current().nextDouble(0, 2*Math.PI); + double spawnRadiant = this.random.nextDouble(0, 2*Math.PI); Location mobSpawnLocation = player.getLocation().add( Math.sin(spawnRadiant)*this.hordeSpawnDistance, 0, @@ -220,7 +221,7 @@ public class Bloodmoon extends Appliance { } public List getRandomBonusDrops() { - int itemCount = ThreadLocalRandom.current().nextInt(this.minBonusDrops, this.maxBonusDrops + 1); + int itemCount = this.random.nextInt(this.minBonusDrops, this.maxBonusDrops + 1); List result = new ArrayList<>(); for(int i = 0; i < itemCount; i++) { result.add(this.getRandomBonusDrop()); @@ -228,9 +229,9 @@ public class Bloodmoon extends Appliance { return result; } - private ItemStack getRandomBonusDrop() { + private @Nullable ItemStack getRandomBonusDrop() { int totalWeight = this.bonusDropWeightMap.values().stream().mapToInt(value -> value).sum(); - int randomInt = ThreadLocalRandom.current().nextInt(0, totalWeight + 1); + int randomInt = this.random.nextInt(0, totalWeight + 1); int cumulativeWeight = 0; for(Map.Entry entry : this.bonusDropWeightMap.entrySet()) { cumulativeWeight += entry.getValue(); diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java index c7dadeb..3782205 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/BloodmoonSetting.java @@ -34,7 +34,7 @@ public class BloodmoonSetting extends BoolSetting implements CategorizedSetting @Override protected Material icon() { - return Material.CLOCK; + return Material.SKELETON_SKULL; } @Override diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java index 374d1e2..6b9923e 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/listener/BloodmoonTimeListener.java @@ -3,6 +3,7 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.list import com.destroystokyo.paper.event.server.ServerTickStartEvent; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon; +import net.kyori.adventure.util.Ticks; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; @@ -18,12 +19,12 @@ public class BloodmoonTimeListener extends ApplianceListener { this.getAppliance().stopBloodmoon(); return; } - this.getAppliance().updateBossBar(); + if(currentTime % Ticks.TICKS_PER_SECOND == 0) this.getAppliance().updateBossBar(); if(this.getAppliance().isStartTick(currentTime + this.getAppliance().ticksPerDay)) { this.getAppliance().sendAnnouncementMessages(); return; } - if(this.getAppliance().isStartTick(currentTime + 1000)) { + if(this.getAppliance().isStartTick(currentTime + this.getAppliance().preStartMessageTicks)) { this.getAppliance().sendPreStartMessages(); } } -- 2.30.2