feat: DBD custom items - medkit/flashlight/toolbox/key/map with charges, ItemUseListener, starting items for survivors
This commit is contained in:
parent
371384ca8a
commit
f9847dbb73
4 changed files with 495 additions and 57 deletions
198
src/main/java/dev/loki/item/DBDItems.java
Normal file
198
src/main/java/dev/loki/item/DBDItems.java
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
package dev.loki.item;
|
||||
|
||||
import dev.loki.util.TextUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Central factory for all DBD custom items.
|
||||
* Items are identified by a PersistentDataContainer tag "mdbd:item_type".
|
||||
* Charges are stored as "mdbd:charges".
|
||||
*/
|
||||
public final class DBDItems {
|
||||
|
||||
public static final NamespacedKey KEY_TYPE = new NamespacedKey("mdbd", "item_type");
|
||||
public static final NamespacedKey KEY_CHARGES = new NamespacedKey("mdbd", "charges");
|
||||
|
||||
private DBDItems() {}
|
||||
|
||||
// ── Factories ─────────────────────────────────────────────────────────────
|
||||
|
||||
/** Медкит — лечит одно состояние здоровья. */
|
||||
public static ItemStack medkit(int charges) {
|
||||
return build(
|
||||
Material.PAPER,
|
||||
"<#00FF7F>Медкит",
|
||||
charges, ItemType.MEDKIT.getDefaultCharges(),
|
||||
List.of(
|
||||
"<gray>Лечит одно состояние здоровья.",
|
||||
"<yellow>ПКМ <gray>— начать лечение"
|
||||
),
|
||||
"MEDKIT"
|
||||
);
|
||||
}
|
||||
|
||||
public static ItemStack medkit() { return medkit(ItemType.MEDKIT.getDefaultCharges()); }
|
||||
|
||||
/** Фонарик — ослепляет киллера при попадании. */
|
||||
public static ItemStack flashlight(int charges) {
|
||||
return build(
|
||||
Material.TORCH,
|
||||
"<#FFD700>Фонарик",
|
||||
charges, ItemType.FLASHLIGHT.getDefaultCharges(),
|
||||
List.of(
|
||||
"<gray>Ослепляет киллера при попадании.",
|
||||
"<yellow>ПКМ <gray>— направить луч на киллера"
|
||||
),
|
||||
"FLASHLIGHT"
|
||||
);
|
||||
}
|
||||
|
||||
public static ItemStack flashlight() { return flashlight(ItemType.FLASHLIGHT.getDefaultCharges()); }
|
||||
|
||||
/** Ящик с инструментами — ускоряет ремонт генератора. */
|
||||
public static ItemStack toolbox(int charges) {
|
||||
return build(
|
||||
Material.CHEST,
|
||||
"<#00CED1>Ящик с инструментами",
|
||||
charges, ItemType.TOOLBOX.getDefaultCharges(),
|
||||
List.of(
|
||||
"<gray>Ускоряет ремонт генераторов.",
|
||||
"<yellow>Держите в руке <gray>во время ремонта"
|
||||
),
|
||||
"TOOLBOX"
|
||||
);
|
||||
}
|
||||
|
||||
public static ItemStack toolbox() { return toolbox(ItemType.TOOLBOX.getDefaultCharges()); }
|
||||
|
||||
/** Ключ — открывает люк (hatch). */
|
||||
public static ItemStack key(int charges) {
|
||||
return build(
|
||||
Material.TRIPWIRE_HOOK,
|
||||
"<#FFA500>Ключ",
|
||||
charges, ItemType.KEY.getDefaultCharges(),
|
||||
List.of(
|
||||
"<gray>Открывает люк немедленно.",
|
||||
"<yellow>ПКМ у люка <gray>— открыть"
|
||||
),
|
||||
"KEY"
|
||||
);
|
||||
}
|
||||
|
||||
public static ItemStack key() { return key(ItemType.KEY.getDefaultCharges()); }
|
||||
|
||||
/** Карта — показывает объекты на карте. */
|
||||
public static ItemStack map(int charges) {
|
||||
return build(
|
||||
Material.MAP,
|
||||
"<#87CEEB>Карта",
|
||||
charges, ItemType.MAP.getDefaultCharges(),
|
||||
List.of(
|
||||
"<gray>Раскрывает объекты поблизости.",
|
||||
"<yellow>ПКМ <gray>— активировать"
|
||||
),
|
||||
"MAP"
|
||||
);
|
||||
}
|
||||
|
||||
public static ItemStack map() { return map(ItemType.MAP.getDefaultCharges()); }
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
private static ItemStack build(Material mat, String name, int charges, int maxCharges,
|
||||
List<String> loreLines, String typeId) {
|
||||
var item = new ItemStack(mat);
|
||||
item.editMeta(meta -> {
|
||||
meta.displayName(TextUtil.color(name));
|
||||
|
||||
// Build lore: description lines + charges bar
|
||||
var lore = new java.util.ArrayList<Component>();
|
||||
for (String line : loreLines) {
|
||||
lore.add(TextUtil.color(line));
|
||||
}
|
||||
lore.add(Component.empty());
|
||||
lore.add(TextUtil.color(chargesBar(charges, maxCharges)));
|
||||
meta.lore(lore);
|
||||
|
||||
meta.getPersistentDataContainer().set(KEY_TYPE, PersistentDataType.STRING, typeId);
|
||||
meta.getPersistentDataContainer().set(KEY_CHARGES, PersistentDataType.INTEGER, charges);
|
||||
});
|
||||
return item;
|
||||
}
|
||||
|
||||
private static String chargesBar(int charges, int max) {
|
||||
int filled = max > 0 ? (int) (8.0 * charges / max) : 0;
|
||||
int empty = 8 - filled;
|
||||
return "<#FFD700>Заряды: <#00FF00>" + "█".repeat(filled) + "<gray>" + "░".repeat(empty)
|
||||
+ " <white>" + charges + "/" + max;
|
||||
}
|
||||
|
||||
// ── Identification ────────────────────────────────────────────────────────
|
||||
|
||||
public static String getType(ItemStack item) {
|
||||
if (item == null || !item.hasItemMeta()) return null;
|
||||
return item.getItemMeta().getPersistentDataContainer()
|
||||
.get(KEY_TYPE, PersistentDataType.STRING);
|
||||
}
|
||||
|
||||
public static int getCharges(ItemStack item) {
|
||||
if (item == null || !item.hasItemMeta()) return 0;
|
||||
Integer c = item.getItemMeta().getPersistentDataContainer()
|
||||
.get(KEY_CHARGES, PersistentDataType.INTEGER);
|
||||
return c != null ? c : 0;
|
||||
}
|
||||
|
||||
/** Обновить заряды на существующем предмете и вернуть обновлённый стак. */
|
||||
public static ItemStack setCharges(ItemStack item, int newCharges) {
|
||||
if (item == null || !item.hasItemMeta()) return item;
|
||||
String type = getType(item);
|
||||
if (type == null) return item;
|
||||
int max = getMaxCharges(type);
|
||||
return build(item.getType(),
|
||||
getDisplayNameRaw(type), newCharges, max,
|
||||
getLoreRaw(type), type);
|
||||
}
|
||||
|
||||
public static boolean isMedkit(ItemStack item) { return "MEDKIT".equals(getType(item)); }
|
||||
public static boolean isFlashlight(ItemStack item) { return "FLASHLIGHT".equals(getType(item)); }
|
||||
public static boolean isToolbox(ItemStack item) { return "TOOLBOX".equals(getType(item)); }
|
||||
public static boolean isKey(ItemStack item) { return "KEY".equals(getType(item)); }
|
||||
public static boolean isMap(ItemStack item) { return "MAP".equals(getType(item)); }
|
||||
public static boolean isDBDItem(ItemStack item) { return getType(item) != null; }
|
||||
|
||||
private static int getMaxCharges(String type) {
|
||||
return switch (type) {
|
||||
case "MEDKIT" -> ItemType.MEDKIT.getDefaultCharges();
|
||||
case "FLASHLIGHT" -> ItemType.FLASHLIGHT.getDefaultCharges();
|
||||
case "TOOLBOX" -> ItemType.TOOLBOX.getDefaultCharges();
|
||||
case "KEY" -> ItemType.KEY.getDefaultCharges();
|
||||
default -> ItemType.MAP.getDefaultCharges();
|
||||
};
|
||||
}
|
||||
|
||||
private static String getDisplayNameRaw(String type) {
|
||||
return switch (type) {
|
||||
case "MEDKIT" -> "<#00FF7F>Медкит";
|
||||
case "FLASHLIGHT" -> "<#FFD700>Фонарик";
|
||||
case "TOOLBOX" -> "<#00CED1>Ящик с инструментами";
|
||||
case "KEY" -> "<#FFA500>Ключ";
|
||||
default -> "<#87CEEB>Карта";
|
||||
};
|
||||
}
|
||||
|
||||
private static List<String> getLoreRaw(String type) {
|
||||
return switch (type) {
|
||||
case "MEDKIT" -> List.of("<gray>Лечит одно состояние здоровья.", "<yellow>ПКМ <gray>— начать лечение");
|
||||
case "FLASHLIGHT" -> List.of("<gray>Ослепляет киллера при попадании.", "<yellow>ПКМ <gray>— направить луч на киллера");
|
||||
case "TOOLBOX" -> List.of("<gray>Ускоряет ремонт генераторов.", "<yellow>Держите в руке <gray>во время ремонта");
|
||||
case "KEY" -> List.of("<gray>Открывает люк немедленно.", "<yellow>ПКМ у люка <gray>— открыть");
|
||||
default -> List.of("<gray>Раскрывает объекты поблизости.", "<yellow>ПКМ <gray>— активировать");
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue