diff --git a/src/main/java/com/simolzimol/levelcraft/LevelCraft.java b/src/main/java/com/simolzimol/levelcraft/LevelCraft.java index 60c8b3c..918d534 100644 --- a/src/main/java/com/simolzimol/levelcraft/LevelCraft.java +++ b/src/main/java/com/simolzimol/levelcraft/LevelCraft.java @@ -10,7 +10,14 @@ public class LevelCraft extends JavaPlugin { getServer().getPluginManager().registerEvents(new com.simolzimol.levelcraft.listener.CraftListener(), this); getServer().getPluginManager().registerEvents(new com.simolzimol.levelcraft.listener.LootListener(this), this); getServer().getPluginManager().registerEvents(new com.simolzimol.levelcraft.listener.VillagerTradeListener(), this); + getServer().getPluginManager().registerEvents(new com.simolzimol.levelcraft.listener.MobDropListener(), this); + getServer().getPluginManager().registerEvents(new com.simolzimol.levelcraft.listener.MobSpawnListener(), this); + getServer().getPluginManager().registerEvents(new com.simolzimol.levelcraft.listener.CustomStatsListener(), this); getCommand("testsmithchest").setExecutor(new com.simolzimol.levelcraft.command.TestSmithChestCommand()); + + // ActionBar-Task für alle Spieler starten + com.simolzimol.levelcraft.system.PlayerStatsManager.startActionBarTask(this); + com.simolzimol.levelcraft.system.PlayerStatsManager.startRegenTask(this); // <--- hinzufügen } @Override diff --git a/src/main/java/com/simolzimol/levelcraft/item/ItemUtil.java b/src/main/java/com/simolzimol/levelcraft/item/ItemUtil.java index 5fc32b6..30c40b8 100644 --- a/src/main/java/com/simolzimol/levelcraft/item/ItemUtil.java +++ b/src/main/java/com/simolzimol/levelcraft/item/ItemUtil.java @@ -8,6 +8,7 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.inventory.EquipmentSlot; import java.util.List; import java.util.UUID; @@ -87,6 +88,9 @@ public class ItemUtil { String stat = possibleStats.get(i); usedStats.add(stat); + // CURSED: Keine Boni, Skills, Effekte, aber Basiswert wird später gesetzt! + if (rarity == Rarity.CURSED && stat.equals("ARMOR")) continue; + switch (stat) { case "DURABILITY" -> { double percent = tier.getMinDurability() + (tier.getMaxDurability() - tier.getMinDurability()) * random.nextDouble(); @@ -101,26 +105,34 @@ public class ItemUtil { double newDamage = base + bonus; meta.addAttributeModifier( org.bukkit.attribute.Attribute.GENERIC_ATTACK_DAMAGE, - new AttributeModifier(UUID.nameUUIDFromBytes("levelcraft_base_damage".getBytes()), "levelcraft_base_damage", base, AttributeModifier.Operation.ADD_NUMBER)); + new AttributeModifier(UUID.nameUUIDFromBytes("levelcraft_base_damage".getBytes()), "levelcraft_base_damage", base, AttributeModifier.Operation.ADD_NUMBER, EquipmentSlot.HAND)); meta.addAttributeModifier( org.bukkit.attribute.Attribute.GENERIC_ATTACK_DAMAGE, - new AttributeModifier(UUID.randomUUID(), "levelcraft_bonus_damage", bonus, AttributeModifier.Operation.ADD_NUMBER)); + new AttributeModifier(UUID.randomUUID(), "levelcraft_bonus_damage", bonus, AttributeModifier.Operation.ADD_NUMBER, EquipmentSlot.HAND)); lore.add(tier.getDisplay() + ": +" + String.format("%.2f", bonus) + " Angriffsschaden (gesamt: " + String.format("%.2f", newDamage) + ")"); } case "ARMOR" -> { - double percent = tier.getMinArmor() + (tier.getMaxArmor() - tier.getMinArmor()) * random.nextDouble(); double base = getBaseArmor(item); - double bonus = base * percent * 10; // Bonus x10 - double newArmor = base + bonus; - // Erst Basiswert als Modifier setzen - meta.addAttributeModifier( - org.bukkit.attribute.Attribute.GENERIC_ARMOR, - new AttributeModifier(UUID.nameUUIDFromBytes("levelcraft_base_armor".getBytes()), "levelcraft_base_armor", base, AttributeModifier.Operation.ADD_NUMBER)); - // Dann Bonus als Modifier setzen - meta.addAttributeModifier( - org.bukkit.attribute.Attribute.GENERIC_ARMOR, - new AttributeModifier(UUID.randomUUID(), "levelcraft_bonus_armor", bonus, AttributeModifier.Operation.ADD_NUMBER)); - lore.add(tier.getDisplay() + ": +" + String.format("%.2f", bonus) + " Rüstung (gesamt: " + String.format("%.2f", newArmor) + ")"); + + // Entferne ALLE Vanilla-Armor-Modifier (auch bei alten Items!) + if (meta.hasAttributeModifiers()) { + var modifiers = meta.getAttributeModifiers(); + if (modifiers != null && modifiers.containsKey(org.bukkit.attribute.Attribute.GENERIC_ARMOR)) { + meta.removeAttributeModifier(org.bukkit.attribute.Attribute.GENERIC_ARMOR); + } + } + + if (rarity != Rarity.CURSED) { + double percent = tier.getMinArmor() + (tier.getMaxArmor() - tier.getMinArmor()) * random.nextDouble(); + double bonus = base * percent * 10; + double newArmor = base + bonus; + meta.getPersistentDataContainer().set(new NamespacedKey("levelcraft", "custom_armor"), PersistentDataType.DOUBLE, newArmor); + lore.add(tier.getDisplay() + ": +" + String.format("%.2f", bonus) + " Rüstung (Basis: " + String.format("%.2f", base) + ", gesamt: " + String.format("%.2f", newArmor) + " /100)"); + } else { + // CURSED: Nur Basiswert, keine Boni, keine Effekte, keine Skills + meta.getPersistentDataContainer().set(new NamespacedKey("levelcraft", "custom_armor"), PersistentDataType.DOUBLE, base); + lore.add("§8Verflucht: Nur Basis-Rüstung (" + String.format("%.2f", base) + " /100)"); + } } case "MINING_SPEED" -> { double percent = tier.getMinAttackSpeed() + (tier.getMaxAttackSpeed() - tier.getMinAttackSpeed()) * random.nextDouble(); @@ -135,44 +147,60 @@ public class ItemUtil { double bonus = 1.0 * percent * 10; // Bonus x10 meta.addAttributeModifier( org.bukkit.attribute.Attribute.GENERIC_LUCK, - new AttributeModifier(UUID.randomUUID(), "levelcraft_bonus_luck", bonus, AttributeModifier.Operation.ADD_NUMBER)); + new AttributeModifier(UUID.randomUUID(), "levelcraft_bonus_luck", bonus, AttributeModifier.Operation.ADD_NUMBER, EquipmentSlot.HAND)); lore.add(tier.getDisplay() + ": +" + String.format("%.2f", bonus) + " Glück"); } case "ATTACK_SPEED" -> { double percent = tier.getMinAttackSpeed() + (tier.getMaxAttackSpeed() - tier.getMinAttackSpeed()) * random.nextDouble(); double base = 4.0; // Standard für Waffen - double malus = base * percent; // KEIN x2! + double malus = base * percent; double newSpeed = base - malus; if (newSpeed < 0.1) newSpeed = 0.1; // Basiswert als Modifier setzen meta.addAttributeModifier( org.bukkit.attribute.Attribute.GENERIC_ATTACK_SPEED, - new AttributeModifier(UUID.nameUUIDFromBytes("levelcraft_base_attackspeed".getBytes()), "levelcraft_base_attackspeed", base, AttributeModifier.Operation.ADD_NUMBER)); + new AttributeModifier(UUID.nameUUIDFromBytes("levelcraft_base_attackspeed".getBytes()), "levelcraft_base_attackspeed", base, AttributeModifier.Operation.ADD_NUMBER, EquipmentSlot.HAND)); // Bonus als Modifier setzen (negativ, weil niedriger besser) meta.addAttributeModifier( org.bukkit.attribute.Attribute.GENERIC_ATTACK_SPEED, - new AttributeModifier(UUID.randomUUID(), "levelcraft_bonus_attackspeed", -malus, AttributeModifier.Operation.ADD_NUMBER)); + new AttributeModifier(UUID.randomUUID(), "levelcraft_bonus_attackspeed", -malus, AttributeModifier.Operation.ADD_NUMBER, EquipmentSlot.HAND)); lore.add(tier.getDisplay() + ": -" + String.format("%.2f", malus) + " Angriffsgeschwindigkeit (neu: " + String.format("%.2f", newSpeed) + ")"); } } } - // Effekte und Skills wie gehabt (hier nicht verändert) - java.util.List effectsList = new java.util.ArrayList<>(ItemEffects.EFFECTS); - java.util.Collections.shuffle(effectsList, random); - int effects = 1; // Beispiel, passe nach deinem System an - for (int i = 0; i < effects && i < effectsList.size(); i++) { - lore.add(effectsList.get(i)); - } - java.util.List skillsList = new java.util.ArrayList<>(ItemEffects.SKILLS); - java.util.Collections.shuffle(skillsList, random); - int skills = 1; // Beispiel, passe nach deinem System an - for (int i = 0; i < skills && i < skillsList.size(); i++) { - lore.add(skillsList.get(i)); + // Effekte und Skills NUR wenn NICHT CURSED + if (rarity != Rarity.CURSED) { + java.util.List effectsList = new java.util.ArrayList<>(ItemEffects.EFFECTS); + java.util.Collections.shuffle(effectsList, random); + int effects = 1; + for (int i = 0; i < effects && i < effectsList.size(); i++) { + lore.add(effectsList.get(i)); + } + java.util.List skillsList = new java.util.ArrayList<>(ItemEffects.SKILLS); + java.util.Collections.shuffle(skillsList, random); + int skills = 1; + for (int i = 0; i < skills && i < skillsList.size(); i++) { + lore.add(skillsList.get(i)); + } } meta.setLore(lore); item.setItemMeta(meta); + + // --- Basiswert für Armor IMMER setzen, auch für CURSED --- + if (isArmor(item) || item.getType().name().equals("SHIELD")) { + Double current = meta.getPersistentDataContainer().get(new NamespacedKey("levelcraft", "custom_armor"), PersistentDataType.DOUBLE); + double base = getBaseArmor(item); + if (current == null) { + meta.getPersistentDataContainer().set(new NamespacedKey("levelcraft", "custom_armor"), PersistentDataType.DOUBLE, base); + // Basiswert auch in der Lore, falls noch nicht vorhanden + boolean found = lore.stream().anyMatch(s -> s.contains("Basis-Rüstung") || s.contains("Basis:")); + if (!found) lore.add("§7Basis-Rüstung: " + String.format("%.2f", base) + " /100"); + meta.setLore(lore); + item.setItemMeta(meta); + } + } } // Beispiel: ActionBar mit aktuellen Stats anzeigen (nur wenn Player bekannt) @@ -234,30 +262,30 @@ public class ItemUtil { private static double getBaseArmor(ItemStack item) { switch (item.getType()) { - case LEATHER_HELMET: return 1; - case LEATHER_CHESTPLATE: return 3; - case LEATHER_LEGGINGS: return 2; - case LEATHER_BOOTS: return 1; - case CHAINMAIL_HELMET: return 2; - case CHAINMAIL_CHESTPLATE: return 5; - case CHAINMAIL_LEGGINGS: return 4; - case CHAINMAIL_BOOTS: return 1; - case IRON_HELMET: return 2; - case IRON_CHESTPLATE: return 6; - case IRON_LEGGINGS: return 5; - case IRON_BOOTS: return 2; - case DIAMOND_HELMET: return 3; - case DIAMOND_CHESTPLATE: return 8; - case DIAMOND_LEGGINGS: return 6; - case DIAMOND_BOOTS: return 3; - case NETHERITE_HELMET: return 3; - case NETHERITE_CHESTPLATE: return 8; - case NETHERITE_LEGGINGS: return 6; - case NETHERITE_BOOTS: return 3; - case GOLDEN_HELMET: return 2; - case GOLDEN_CHESTPLATE: return 5; - case GOLDEN_LEGGINGS: return 3; - case GOLDEN_BOOTS: return 1; + case DIAMOND_HELMET: return 12.5; + case DIAMOND_CHESTPLATE: return 50; + case DIAMOND_LEGGINGS: return 25; + case DIAMOND_BOOTS: return 12.5; + case NETHERITE_HELMET: return 12.5; + case NETHERITE_CHESTPLATE: return 50; + case NETHERITE_LEGGINGS: return 25; + case NETHERITE_BOOTS: return 12.5; + case IRON_HELMET: return 7.5; + case IRON_CHESTPLATE: return 30; + case IRON_LEGGINGS: return 20; + case IRON_BOOTS: return 7.5; + case GOLDEN_HELMET: return 5; + case GOLDEN_CHESTPLATE: return 20; + case GOLDEN_LEGGINGS: return 15; + case GOLDEN_BOOTS: return 5; + case LEATHER_HELMET: return 2.5; + case LEATHER_CHESTPLATE: return 10; + case LEATHER_LEGGINGS: return 7.5; + case LEATHER_BOOTS: return 2.5; + case CHAINMAIL_HELMET: return 5; + case CHAINMAIL_CHESTPLATE: return 20; + case CHAINMAIL_LEGGINGS: return 15; + case CHAINMAIL_BOOTS: return 5; default: return 0; } } diff --git a/src/main/java/com/simolzimol/levelcraft/listener/CustomStatsListener.java b/src/main/java/com/simolzimol/levelcraft/listener/CustomStatsListener.java new file mode 100644 index 0000000..7cf61f4 --- /dev/null +++ b/src/main/java/com/simolzimol/levelcraft/listener/CustomStatsListener.java @@ -0,0 +1,74 @@ +package com.simolzimol.levelcraft.listener; + +import com.simolzimol.levelcraft.system.PlayerStatsManager; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.NamespacedKey; + +public class CustomStatsListener implements Listener { + @EventHandler + public void onEntityDamage(EntityDamageEvent event) { + if (!(event.getEntity() instanceof Player player)) return; + event.setCancelled(true); // Vanilla-Schaden verhindern + + double hp = PlayerStatsManager.getHP(player); + double armor = PlayerStatsManager.getArmor(player); + double damage = event.getFinalDamage() * (1 - armor / 100.0); + + hp -= damage; + PlayerStatsManager.setHP(player, hp); + + // Nach 1 Sekunde wieder die Stats anzeigen + org.bukkit.Bukkit.getScheduler().runTaskLater( + org.bukkit.Bukkit.getPluginManager().getPlugin("LevelCraft"), + () -> PlayerStatsManager.showStats(player), + 20L // 1 Sekunde + ); + + if (hp <= 0) player.setHealth(0); // Spieler töten + } + + public static void updatePlayerArmor(Player player) { + double totalArmor = 0; + for (ItemStack item : player.getInventory().getArmorContents()) { + if (item == null) continue; + ItemMeta meta = item.getItemMeta(); + if (meta == null) continue; + Double armor = meta.getPersistentDataContainer().get(new NamespacedKey("levelcraft", "custom_armor"), PersistentDataType.DOUBLE); + if (armor != null) totalArmor += armor; + } + PlayerStatsManager.setArmor(player, totalArmor); + // ActionBar sofort updaten + PlayerStatsManager.showStats(player); + } + + @EventHandler + public void onInventoryClick(org.bukkit.event.inventory.InventoryClickEvent event) { + if (!(event.getWhoClicked() instanceof Player player)) return; + // Verzögert ausführen, damit das Inventar schon aktualisiert ist + org.bukkit.Bukkit.getScheduler().runTaskLater( + org.bukkit.Bukkit.getPluginManager().getPlugin("LevelCraft"), + () -> updatePlayerArmor(player), + 1L + ); + } + + @EventHandler + public void onJoin(org.bukkit.event.player.PlayerJoinEvent event) { + updatePlayerArmor(event.getPlayer()); + } + + @EventHandler + public void onRespawn(org.bukkit.event.player.PlayerRespawnEvent event) { + org.bukkit.Bukkit.getScheduler().runTaskLater( + org.bukkit.Bukkit.getPluginManager().getPlugin("LevelCraft"), + () -> updatePlayerArmor(event.getPlayer()), + 1L + ); + } +} diff --git a/src/main/java/com/simolzimol/levelcraft/listener/MobDropListener.java b/src/main/java/com/simolzimol/levelcraft/listener/MobDropListener.java index 27377c2..781057b 100644 --- a/src/main/java/com/simolzimol/levelcraft/listener/MobDropListener.java +++ b/src/main/java/com/simolzimol/levelcraft/listener/MobDropListener.java @@ -16,7 +16,9 @@ public class MobDropListener implements Listener { public void onMobDrop(EntityDropItemEvent event) { ItemStack item = event.getItemDrop().getItemStack(); if (item == null) return; - if (item.getType().getMaxDurability() <= 0) return; + + // Optional: Nur für bestimmte Itemtypen, z.B. Waffen, Rüstung, Tools, Bögen, Schilde + // if (!ItemUtil.isWeapon(item) && !ItemUtil.isArmor(item) && !ItemUtil.isTool(item) && !item.getType().name().equals("SHIELD") && !item.getType().name().equals("BOW") && !item.getType().name().equals("CROSSBOW")) return; int rarityValue = random.nextInt(9) - 1; // -1 bis 7 if (rarityValue > 7) rarityValue = 7; diff --git a/src/main/java/com/simolzimol/levelcraft/listener/MobSpawnListener.java b/src/main/java/com/simolzimol/levelcraft/listener/MobSpawnListener.java new file mode 100644 index 0000000..e246e92 --- /dev/null +++ b/src/main/java/com/simolzimol/levelcraft/listener/MobSpawnListener.java @@ -0,0 +1,54 @@ +package com.simolzimol.levelcraft.listener; + +import com.simolzimol.levelcraft.item.ItemUtil; +import com.simolzimol.levelcraft.item.Rarity; +import org.bukkit.Bukkit; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; + +import java.util.Random; + +public class MobSpawnListener implements Listener { + private final Random random = new Random(); + + @EventHandler + public void onMobSpawn(CreatureSpawnEvent event) { + if (!(event.getEntity() instanceof LivingEntity living)) return; + Bukkit.getScheduler().runTaskLater( + Bukkit.getPluginManager().getPlugin("LevelCraft"), // Passe ggf. den Plugin-Namen an! + () -> { + EntityEquipment eq = living.getEquipment(); + if (eq == null) return; + ItemStack[] items = { + eq.getItemInMainHand(), + eq.getItemInOffHand(), + eq.getHelmet(), + eq.getChestplate(), + eq.getLeggings(), + eq.getBoots() + }; + for (int i = 0; i < items.length; i++) { + ItemStack item = items[i]; + if (item == null || item.getType().isAir()) continue; + // Optional: Filter für Waffen, Bögen, etc. + Rarity rarity = Rarity.getRandomRarity(random, true, 5); + ItemUtil.setRarity(item, rarity); + ItemUtil.assignUniqueId(item); + ItemUtil.addRandomBonuses(item, rarity, random); + switch (i) { + case 0 -> eq.setItemInMainHand(item); + case 1 -> eq.setItemInOffHand(item); + case 2 -> eq.setHelmet(item); + case 3 -> eq.setChestplate(item); + case 4 -> eq.setLeggings(item); + case 5 -> eq.setBoots(item); + } + } + }, 1L // 1 Tick Verzögerung + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/simolzimol/levelcraft/system/PlayerStatsManager.java b/src/main/java/com/simolzimol/levelcraft/system/PlayerStatsManager.java new file mode 100644 index 0000000..5e74969 --- /dev/null +++ b/src/main/java/com/simolzimol/levelcraft/system/PlayerStatsManager.java @@ -0,0 +1,68 @@ +package com.simolzimol.levelcraft.system; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.HashMap; +import java.util.UUID; + +public class PlayerStatsManager { + private static final HashMap hp = new HashMap<>(); + private static final HashMap armor = new HashMap<>(); + private static final HashMap mana = new HashMap<>(); + + public static void setHP(Player p, double value) { hp.put(p.getUniqueId(), value); } + public static double getHP(Player p) { return hp.getOrDefault(p.getUniqueId(), 20.0); } + + public static void setArmor(Player p, double value) { armor.put(p.getUniqueId(), value); } + public static double getArmor(Player p) { return armor.getOrDefault(p.getUniqueId(), 0.0); } + + public static void setMana(Player p, double value) { mana.put(p.getUniqueId(), value); } + public static double getMana(Player p) { return mana.getOrDefault(p.getUniqueId(), 100.0); } + + @EventHandler + public void onJoin(PlayerJoinEvent event) { + Player p = event.getPlayer(); + PlayerStatsManager.setHP(p, 20.0); + PlayerStatsManager.setArmor(p, 0.0); + PlayerStatsManager.setMana(p, 100.0); + } + + public static void startActionBarTask(org.bukkit.plugin.Plugin plugin) { + new BukkitRunnable() { + @Override + public void run() { + for (Player p : Bukkit.getOnlinePlayers()) { + double hpVal = getHP(p); + double armorVal = getArmor(p); + double manaVal = getMana(p); + p.sendActionBar("§cHP: " + Math.round(hpVal*10)/10.0 + " §bRüstung: " + Math.round(armorVal*10)/10.0 + " §9Mana: " + Math.round(manaVal*10)/10.0); + } + } + }.runTaskTimer(plugin, 0L, 20L); // alle 20 Ticks = 1 Sekunde + } + + public static void startRegenTask(org.bukkit.plugin.Plugin plugin) { + new BukkitRunnable() { + @Override + public void run() { + for (Player p : Bukkit.getOnlinePlayers()) { + double hp = getHP(p); + if (hp < 20.0) { + setHP(p, Math.min(20.0, hp + 0.2)); // 0.2 HP pro Sekunde + } + } + } + }.runTaskTimer(plugin, 0L, 20L); // alle 20 Ticks = 1 Sekunde + } + + public static void showStats(Player p) { + double hpVal = getHP(p); + double armorVal = getArmor(p); + double manaVal = getMana(p); + p.sendActionBar("§cHP: " + Math.round(hpVal*10)/10.0 + " §bRüstung: " + Math.round(armorVal*10)/10.0 + " §9Mana: " + Math.round(manaVal*10)/10.0); + } +}