new file: src/main/java/com/simolzimol/levelcraft/item/ItemEffects.java

modified:   src/main/java/com/simolzimol/levelcraft/item/ItemUtil.java
	new file:   src/main/java/com/simolzimol/levelcraft/item/StatTier.java
	modified:   src/main/java/com/simolzimol/levelcraft/listener/CraftListener.java
	modified:   src/main/java/com/simolzimol/levelcraft/listener/LootListener.java
	modified:   src/main/java/com/simolzimol/levelcraft/listener/MobDropListener.java
	modified:   src/main/java/com/simolzimol/levelcraft/listener/VillagerTradeListener.java
This commit is contained in:
SimolZimol
2025-05-24 19:14:44 +02:00
parent 81d048f238
commit 7f8d10798f
7 changed files with 285 additions and 4 deletions

View File

@@ -0,0 +1,21 @@
package com.simolzimol.levelcraft.item;
import java.util.List;
public class ItemEffects {
public static final List<String> EFFECTS = List.of(
"§bEffekt: Feuerresistenz",
"§bEffekt: Schnelligkeit",
"§bEffekt: Regeneration",
"§bEffekt: Unsichtbarkeit",
"§bEffekt: Stärke"
);
public static final List<String> SKILLS = List.of(
"§dSkill: Doppelschlag",
"§dSkill: Lebensraub",
"§dSkill: Flächenschaden",
"§dSkill: Rückstoß",
"§dSkill: Kritischer Treffer"
);
}

View File

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

View File

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

View File

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

View File

@@ -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

View File

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

View File

@@ -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