2 Commits

Author SHA1 Message Date
9433495a52 added random drops and boss bar for Bloodmoon 2025-10-18 19:01:09 +02:00
4955e94306 started bloodmoon appliance 2025-10-17 19:38:10 +02:00
6 changed files with 249 additions and 0 deletions

View File

@@ -0,0 +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.Map;
import java.util.concurrent.ThreadLocalRandom;
public class Bloodmoon extends Appliance {
// für alle Dimensionen? einstellbar machen?
public final Map<EntityType, PotionEffect[]> 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 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<ItemStack, Integer> 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 this.isActive;
}
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<ItemStack> getRandomBonusDrops() {
int itemCount = ThreadLocalRandom.current().nextInt(this.minBonusDrops, this.maxBonusDrops + 1);
List<ItemStack> 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<ItemStack, Integer> entry : this.bonusDropWeightMap.entrySet()) {
cumulativeWeight += entry.getValue();
if(randomInt <= cumulativeWeight) return entry.getKey();
}
return null;
}
@Override
protected @NotNull List<Listener> listeners() {
return List.of(
new BloodmoonMonsterDeathListener(),
new BloodmoonPlayerJoinListener()
);
}
@Override
protected @NotNull List<ApplianceCommand<?>> commands() {
return List.of(
new BloodmoonCommand()
);
}
}

View File

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

View File

@@ -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<Bloodmoon> {
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<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if(args.length == 1) return List.of("start", "stop");
return null;
}
}

View File

@@ -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<Bloodmoon> {
@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
}
}

View File

@@ -0,0 +1,20 @@
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<Bloodmoon> {
@EventHandler
public void onMonsterDeath(EntityDeathEvent event) {
if(!this.getAppliance().bloodmoonIsActive()) return;
LivingEntity entity = event.getEntity();
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());
}
}

View File

@@ -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<Bloodmoon> {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
if(!this.getAppliance().bloodmoonIsActive()) return;
this.getAppliance().addPlayerToBossBar(event.getPlayer());
}
}