diff --git a/src/main/java/com/simolzimol/levelcraft/item/ItemEffects.java b/src/main/java/com/simolzimol/levelcraft/item/ItemEffects.java new file mode 100644 index 0000000..7923a56 --- /dev/null +++ b/src/main/java/com/simolzimol/levelcraft/item/ItemEffects.java @@ -0,0 +1,21 @@ +package com.simolzimol.levelcraft.item; + +import java.util.List; + +public class ItemEffects { + public static final List EFFECTS = List.of( + "§bEffekt: Feuerresistenz", + "§bEffekt: Schnelligkeit", + "§bEffekt: Regeneration", + "§bEffekt: Unsichtbarkeit", + "§bEffekt: Stärke" + ); + + public static final List SKILLS = List.of( + "§dSkill: Doppelschlag", + "§dSkill: Lebensraub", + "§dSkill: Flächenschaden", + "§dSkill: Rückstoß", + "§dSkill: Kritischer Treffer" + ); +} diff --git a/src/main/java/com/simolzimol/levelcraft/item/ItemUtil.java b/src/main/java/com/simolzimol/levelcraft/item/ItemUtil.java index 83f3047..5fc32b6 100644 --- a/src/main/java/com/simolzimol/levelcraft/item/ItemUtil.java +++ b/src/main/java/com/simolzimol/levelcraft/item/ItemUtil.java @@ -1,10 +1,13 @@ package com.simolzimol.levelcraft.item; import org.bukkit.NamespacedKey; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; import java.util.List; import java.util.UUID; @@ -54,4 +57,208 @@ public class ItemUtil { public static NamespacedKey getRarityKey() { return rarityKey; } + + public static void addRandomBonuses(ItemStack item, Rarity rarity, java.util.Random random) { + ItemMeta meta = item.getItemMeta(); + java.util.List lore = meta.hasLore() ? meta.getLore() : new java.util.ArrayList<>(); + + int stats = switch (rarity) { + case COMMON -> 1; + case UNCOMMON, RARE, EPIC -> 2; + case LEGENDARY, MYTHIC -> 3; + case ANCIENT -> 4; + case DIVINE -> 5; + default -> 0; + }; + + // Stat-Typen, die für dieses Item zulässig sind + java.util.List possibleStats = new java.util.ArrayList<>(); + if (item.getType().getMaxDurability() > 0) possibleStats.add("DURABILITY"); + if (isWeapon(item)) possibleStats.add("DAMAGE"); + if (isArmor(item) || item.getType().name().equals("SHIELD")) possibleStats.add("ARMOR"); + if (isTool(item)) possibleStats.add("MINING_SPEED"); + possibleStats.add("LUCK"); // Luck kann auf alles + + java.util.Collections.shuffle(possibleStats, random); + + java.util.Set usedStats = new java.util.HashSet<>(); + for (int i = 0; i < stats && i < possibleStats.size(); i++) { + StatTier tier = StatTier.values()[Math.min(i, StatTier.values().length-1)]; + String stat = possibleStats.get(i); + usedStats.add(stat); + + switch (stat) { + case "DURABILITY" -> { + double percent = tier.getMinDurability() + (tier.getMaxDurability() - tier.getMinDurability()) * random.nextDouble(); + int bonus = (int) Math.round(item.getType().getMaxDurability() * percent); + lore.add(tier.getDisplay() + ": +" + (int)(percent*100) + "% Haltbarkeit (" + bonus + " Punkte)"); + item.setDurability((short) 0); // Item ist voll repariert + } + case "DAMAGE" -> { + double percent = tier.getMinDamage() + (tier.getMaxDamage() - tier.getMinDamage()) * random.nextDouble(); + double base = getBaseDamage(item); + double bonus = base * percent * 10; // Bonus x10 + 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)); + meta.addAttributeModifier( + org.bukkit.attribute.Attribute.GENERIC_ATTACK_DAMAGE, + new AttributeModifier(UUID.randomUUID(), "levelcraft_bonus_damage", bonus, AttributeModifier.Operation.ADD_NUMBER)); + 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) + ")"); + } + case "MINING_SPEED" -> { + double percent = tier.getMinAttackSpeed() + (tier.getMaxAttackSpeed() - tier.getMinAttackSpeed()) * random.nextDouble(); + double bonus = 4.0 * percent * 10; // Bonus x10 + meta.addAttributeModifier( + org.bukkit.attribute.Attribute.GENERIC_ATTACK_SPEED, + new AttributeModifier(UUID.randomUUID(), "levelcraft_bonus_mining_speed", bonus, AttributeModifier.Operation.ADD_NUMBER)); + lore.add(tier.getDisplay() + ": +" + String.format("%.2f", bonus) + " Abbausgeschwindigkeit"); + } + case "LUCK" -> { + double percent = tier.getMinLuck() + (tier.getMaxLuck() - tier.getMinLuck()) * random.nextDouble(); + 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)); + 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 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)); + // 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)); + 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)); + } + + meta.setLore(lore); + item.setItemMeta(meta); + } + + // Beispiel: ActionBar mit aktuellen Stats anzeigen (nur wenn Player bekannt) + public static void sendItemStatsActionBar(org.bukkit.entity.Player player, ItemStack item) { + ItemMeta meta = item.getItemMeta(); + double damage = 0, armor = 0, speed = 0, luck = 0; + if (meta != null && meta.hasAttributeModifiers()) { + for (var attr : meta.getAttributeModifiers().keySet()) { + for (AttributeModifier mod : meta.getAttributeModifiers(attr)) { + switch (attr.name()) { + case "GENERIC_ATTACK_DAMAGE" -> damage += mod.getAmount(); + case "GENERIC_ARMOR" -> armor += mod.getAmount(); + case "GENERIC_ATTACK_SPEED" -> speed += mod.getAmount(); + case "GENERIC_LUCK" -> luck += mod.getAmount(); + } + } + } + } + String stats = "§eStats: "; + if (damage > 0) stats += "§c" + String.format("%.2f", damage) + "⚔ "; + if (armor > 0) stats += "§b" + String.format("%.2f", armor) + "🛡 "; + if (speed > 0) stats += "§a" + String.format("%.2f", speed) + "⏩ "; + if (luck > 0) stats += "§d" + String.format("%.2f", luck) + "☘ "; + player.sendActionBar(stats.trim()); + } + + // Hilfsmethoden für Item-Typen: + private static boolean isWeapon(ItemStack item) { + String name = item.getType().name(); + return name.endsWith("_SWORD") || name.endsWith("_AXE") || name.equals("TRIDENT") || name.equals("BOW") || name.equals("CROSSBOW"); + } + private static boolean isArmor(ItemStack item) { + String name = item.getType().name(); + return name.endsWith("_HELMET") || name.endsWith("_CHESTPLATE") || name.endsWith("_LEGGINGS") || name.endsWith("_BOOTS"); + } + private static boolean isTool(ItemStack item) { + String name = item.getType().name(); + return name.endsWith("_PICKAXE") || name.endsWith("_SHOVEL") || name.endsWith("_HOE"); + } + + private static double getBaseDamage(ItemStack item) { + switch (item.getType()) { + case WOODEN_SWORD: return 4; + case STONE_SWORD: return 5; + case IRON_SWORD: return 6; + case DIAMOND_SWORD: return 7; + case NETHERITE_SWORD: return 8; + case WOODEN_AXE: return 7; + case STONE_AXE: return 9; + case IRON_AXE: return 9; + case DIAMOND_AXE: return 9; + case NETHERITE_AXE: return 10; + case TRIDENT: return 8; + case BOW: return 6; + case CROSSBOW: return 9; + default: return 1; + } + } + + 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; + default: return 0; + } + } } diff --git a/src/main/java/com/simolzimol/levelcraft/item/StatTier.java b/src/main/java/com/simolzimol/levelcraft/item/StatTier.java new file mode 100644 index 0000000..b55d84e --- /dev/null +++ b/src/main/java/com/simolzimol/levelcraft/item/StatTier.java @@ -0,0 +1,53 @@ +package com.simolzimol.levelcraft.item; + +public enum StatTier { + TIER_1("§7Tier 1", 0.01, 0.03, 0.01, 0.03, 0.01, 0.03, 0.01, 0.02, 0.01, 0.02, 0.01, 0.02), + TIER_2("§aTier 2", 0.04, 0.07, 0.04, 0.07, 0.04, 0.07, 0.02, 0.04, 0.02, 0.04, 0.02, 0.04), + TIER_3("§9Tier 3", 0.08, 0.12, 0.08, 0.12, 0.08, 0.12, 0.04, 0.07, 0.04, 0.07, 0.04, 0.07), + TIER_4("§5Tier 4", 0.13, 0.18, 0.13, 0.18, 0.13, 0.18, 0.07, 0.10, 0.07, 0.10, 0.07, 0.10), + TIER_5("§6Tier 5", 0.19, 0.25, 0.19, 0.25, 0.19, 0.25, 0.10, 0.15, 0.10, 0.15, 0.10, 0.15); + + private final String display; + private final double minDurability, maxDurability; + private final double minDamage, maxDamage; + private final double minArmor, maxArmor; + private final double minAttackSpeed, maxAttackSpeed; + private final double minMoveSpeed, maxMoveSpeed; + private final double minLuck, maxLuck; + + StatTier(String display, + double minDurability, double maxDurability, + double minDamage, double maxDamage, + double minArmor, double maxArmor, + double minAttackSpeed, double maxAttackSpeed, + double minMoveSpeed, double maxMoveSpeed, + double minLuck, double maxLuck) { + this.display = display; + this.minDurability = minDurability; + this.maxDurability = maxDurability; + this.minDamage = minDamage; + this.maxDamage = maxDamage; + this.minArmor = minArmor; + this.maxArmor = maxArmor; + this.minAttackSpeed = minAttackSpeed; + this.maxAttackSpeed = maxAttackSpeed; + this.minMoveSpeed = minMoveSpeed; + this.maxMoveSpeed = maxMoveSpeed; + this.minLuck = minLuck; + this.maxLuck = maxLuck; + } + + public String getDisplay() { return display; } + public double getMinDurability() { return minDurability; } + public double getMaxDurability() { return maxDurability; } + public double getMinDamage() { return minDamage; } + public double getMaxDamage() { return maxDamage; } + public double getMinArmor() { return minArmor; } + public double getMaxArmor() { return maxArmor; } + public double getMinAttackSpeed() { return minAttackSpeed; } + public double getMaxAttackSpeed() { return maxAttackSpeed; } + public double getMinMoveSpeed() { return minMoveSpeed; } + public double getMaxMoveSpeed() { return maxMoveSpeed; } + public double getMinLuck() { return minLuck; } + public double getMaxLuck() { return maxLuck; } +} diff --git a/src/main/java/com/simolzimol/levelcraft/listener/CraftListener.java b/src/main/java/com/simolzimol/levelcraft/listener/CraftListener.java index d846bd9..408c64b 100644 --- a/src/main/java/com/simolzimol/levelcraft/listener/CraftListener.java +++ b/src/main/java/com/simolzimol/levelcraft/listener/CraftListener.java @@ -18,10 +18,10 @@ public class CraftListener implements Listener { if (result == null) return; if (result.getType().getMaxDurability() <= 0) return; - // Gecraftete Items: -1 (selten) bis 3 (häufig) Rarity rarity = Rarity.getRandomRarity(random, true, 3); ItemUtil.setRarity(result, rarity); ItemUtil.assignUniqueId(result); + ItemUtil.addRandomBonuses(result, rarity, random); event.setCurrentItem(result); } } diff --git a/src/main/java/com/simolzimol/levelcraft/listener/LootListener.java b/src/main/java/com/simolzimol/levelcraft/listener/LootListener.java index 76ca68a..cb85c09 100644 --- a/src/main/java/com/simolzimol/levelcraft/listener/LootListener.java +++ b/src/main/java/com/simolzimol/levelcraft/listener/LootListener.java @@ -75,6 +75,7 @@ public class LootListener implements Listener { Rarity rarity = Rarity.fromValue(rarityValue); ItemUtil.setRarity(item, rarity); ItemUtil.assignUniqueId(item); + ItemUtil.addRandomBonuses(item, rarity, random); item.setItemMeta(item.getItemMeta()); } }, 1L); // 1 Tick Verzögerung diff --git a/src/main/java/com/simolzimol/levelcraft/listener/MobDropListener.java b/src/main/java/com/simolzimol/levelcraft/listener/MobDropListener.java index bd1eb50..27377c2 100644 --- a/src/main/java/com/simolzimol/levelcraft/listener/MobDropListener.java +++ b/src/main/java/com/simolzimol/levelcraft/listener/MobDropListener.java @@ -16,10 +16,8 @@ public class MobDropListener implements Listener { public void onMobDrop(EntityDropItemEvent event) { ItemStack item = event.getItemDrop().getItemStack(); if (item == null) return; - // Nur Items mit Haltbarkeit (Waffen, Rüstung, Werkzeuge) if (item.getType().getMaxDurability() <= 0) return; - // Rarity für Mobdrops: -1 bis 7 int rarityValue = random.nextInt(9) - 1; // -1 bis 7 if (rarityValue > 7) rarityValue = 7; if (rarityValue < -1) rarityValue = -1; @@ -27,6 +25,7 @@ public class MobDropListener implements Listener { Rarity rarity = Rarity.fromValue(rarityValue); ItemUtil.setRarity(item, rarity); ItemUtil.assignUniqueId(item); + ItemUtil.addRandomBonuses(item, rarity, random); event.getItemDrop().setItemStack(item); } } diff --git a/src/main/java/com/simolzimol/levelcraft/listener/VillagerTradeListener.java b/src/main/java/com/simolzimol/levelcraft/listener/VillagerTradeListener.java index ecc4d65..dbf85bf 100644 --- a/src/main/java/com/simolzimol/levelcraft/listener/VillagerTradeListener.java +++ b/src/main/java/com/simolzimol/levelcraft/listener/VillagerTradeListener.java @@ -30,7 +30,6 @@ public class VillagerTradeListener implements Listener { ItemStack result = recipe.getResult().clone(); ItemMeta meta = result.getItemMeta(); if (meta != null && !meta.getPersistentDataContainer().has(ItemUtil.getRarityKey(), PersistentDataType.INTEGER)) { - // Nur Items mit Haltbarkeit (Waffen, Rüstung, Werkzeuge) if (result.getType().getMaxDurability() > 0) { int rarityValue = random.nextInt(7) - 1; // -1 bis 5 if (rarityValue > 5) rarityValue = 5; @@ -38,6 +37,7 @@ public class VillagerTradeListener implements Listener { Rarity rarity = Rarity.fromValue(rarityValue); ItemUtil.setRarity(result, rarity); ItemUtil.assignUniqueId(result); + ItemUtil.addRandomBonuses(result, rarity, random); } } // Neues Rezept mit gleichem Input, aber modifiziertem Output