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