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
|
|
@ -13,65 +13,14 @@ public class ChestLoot {
|
|||
this.random = ThreadLocalRandom.current();
|
||||
}
|
||||
|
||||
/** Roll a random item with weighted probabilities. */
|
||||
public ItemStack rollLoot() {
|
||||
int roll = random.nextInt(100);
|
||||
int currentWeight = 0;
|
||||
|
||||
currentWeight += 30;
|
||||
if (roll < currentWeight) {
|
||||
return createMedkit();
|
||||
}
|
||||
|
||||
currentWeight += 25;
|
||||
if (roll < currentWeight) {
|
||||
return createFlashlight();
|
||||
}
|
||||
|
||||
currentWeight += 25;
|
||||
if (roll < currentWeight) {
|
||||
return createToolbox();
|
||||
}
|
||||
|
||||
currentWeight += 12;
|
||||
if (roll < currentWeight) {
|
||||
return createKey();
|
||||
}
|
||||
|
||||
return createMap();
|
||||
}
|
||||
|
||||
private ItemStack createMedkit() {
|
||||
int charges = 12 + random.nextInt(8);
|
||||
return new ItemMedkit(charges).createItemStack();
|
||||
}
|
||||
|
||||
private ItemStack createFlashlight() {
|
||||
int charges = 6 + random.nextInt(6);
|
||||
return new ItemFlashlight(charges).createItemStack();
|
||||
}
|
||||
|
||||
private ItemStack createToolbox() {
|
||||
int charges = 10 + random.nextInt(10);
|
||||
return new ItemToolbox(charges).createItemStack();
|
||||
}
|
||||
|
||||
private ItemStack createKey() {
|
||||
int charges = 24 + random.nextInt(16);
|
||||
return new ItemKey(charges).createItemStack();
|
||||
}
|
||||
|
||||
private ItemStack createMap() {
|
||||
int charges = 8 + random.nextInt(12);
|
||||
return new ItemMap(charges).createItemStack();
|
||||
}
|
||||
|
||||
public int getRarity(ItemType type) {
|
||||
return switch (type) {
|
||||
case MEDKIT -> 30;
|
||||
case FLASHLIGHT -> 25;
|
||||
case TOOLBOX -> 25;
|
||||
case KEY -> 12;
|
||||
case MAP -> 8;
|
||||
};
|
||||
if (roll < 30) return DBDItems.medkit(12 + random.nextInt(5)); // 30%
|
||||
if (roll < 55) return DBDItems.flashlight(6 + random.nextInt(4)); // 25%
|
||||
if (roll < 80) return DBDItems.toolbox(10 + random.nextInt(7)); // 25%
|
||||
if (roll < 92) return DBDItems.key(24 + random.nextInt(9)); // 12%
|
||||
return DBDItems.map(8 + random.nextInt(9)); // 8%
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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>— активировать");
|
||||
};
|
||||
}
|
||||
}
|
||||
264
src/main/java/dev/loki/item/ItemUseListener.java
Normal file
264
src/main/java/dev/loki/item/ItemUseListener.java
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
package dev.loki.item;
|
||||
|
||||
import dev.loki.core.GameSession;
|
||||
import dev.loki.player.BasePlayer;
|
||||
import dev.loki.player.PlayerState;
|
||||
import dev.loki.player.Survivor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Handles right-click usage of DBD custom items during gameplay.
|
||||
*/
|
||||
public class ItemUseListener implements Listener {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final GameSession session;
|
||||
|
||||
// Medkit heal: survivor UUID → task
|
||||
private final Map<UUID, BukkitTask> activeHeals = new HashMap<>();
|
||||
private static final int MEDKIT_TICKS = 160; // 8 seconds
|
||||
|
||||
public ItemUseListener(Plugin plugin, GameSession session) {
|
||||
this.plugin = plugin;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public void register() {
|
||||
org.bukkit.Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
public void unregister() {
|
||||
HandlerList.unregisterAll(this);
|
||||
activeHeals.values().forEach(BukkitTask::cancel);
|
||||
activeHeals.clear();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onInteract(PlayerInteractEvent event) {
|
||||
if (event.getHand() != EquipmentSlot.HAND) return;
|
||||
Action action = event.getAction();
|
||||
if (action != Action.RIGHT_CLICK_AIR && action != Action.RIGHT_CLICK_BLOCK) return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (!session.getPlayers().containsKey(player.getUniqueId())) return;
|
||||
|
||||
BasePlayer bp = session.getPlayer(player.getUniqueId());
|
||||
if (bp == null || bp.isKiller()) return;
|
||||
|
||||
ItemStack hand = player.getInventory().getItemInMainHand();
|
||||
if (!DBDItems.isDBDItem(hand)) return;
|
||||
|
||||
String type = DBDItems.getType(hand);
|
||||
if (type == null) return;
|
||||
|
||||
event.setCancelled(true); // prevent block interaction
|
||||
|
||||
switch (type) {
|
||||
case "MEDKIT" -> useMedkit(player, (Survivor) bp, hand);
|
||||
case "FLASHLIGHT" -> useFlashlight(player, hand);
|
||||
case "TOOLBOX" -> { /* passive — handled in repair */ }
|
||||
case "KEY" -> useKey(player, (Survivor) bp, hand);
|
||||
case "MAP" -> useMap(player, hand);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Medkit ───────────────────────────────────────────────────────────────
|
||||
|
||||
private void useMedkit(Player player, Survivor survivor, ItemStack item) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
// Toggle: if already healing, cancel
|
||||
if (activeHeals.containsKey(uuid)) {
|
||||
cancelHeal(player);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerState state = survivor.getState();
|
||||
if (state != PlayerState.INJURED) {
|
||||
player.sendMessage(Component.text("Вы не ранены!", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
int charges = DBDItems.getCharges(item);
|
||||
if (charges <= 0) {
|
||||
player.sendMessage(Component.text("Медкит пуст!", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendMessage(Component.text("Начинаете самолечение...", NamedTextColor.GREEN));
|
||||
player.sendActionBar(Component.text("⚕ Самолечение...", NamedTextColor.GREEN));
|
||||
|
||||
BukkitTask task = new BukkitRunnable() {
|
||||
int ticks = 0;
|
||||
int chargesLeft = charges;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!player.isOnline() || survivor.getState() != PlayerState.INJURED) {
|
||||
cancelHeal(player);
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
ticks++;
|
||||
chargesLeft = Math.max(0, charges - ticks);
|
||||
|
||||
// Update action bar progress
|
||||
int filled = (int)(8.0 * ticks / MEDKIT_TICKS);
|
||||
int empty = 8 - filled;
|
||||
player.sendActionBar(Component.text(
|
||||
"⚕ " + "█".repeat(filled) + "░".repeat(empty) +
|
||||
" " + (int)(100.0 * ticks / MEDKIT_TICKS) + "%",
|
||||
NamedTextColor.GREEN));
|
||||
|
||||
// Use 1 charge per 10 ticks
|
||||
if (ticks % 10 == 0) {
|
||||
updateItemCharges(player, chargesLeft);
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_HURT, 0.2f, 1.5f);
|
||||
}
|
||||
|
||||
if (ticks >= MEDKIT_TICKS) {
|
||||
// Heal done
|
||||
survivor.setState(PlayerState.HEALTHY);
|
||||
player.sendMessage(Component.text("✔ Вы вылечились!", NamedTextColor.GREEN));
|
||||
player.sendActionBar(Component.empty());
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 0.5f, 1.5f);
|
||||
updateItemCharges(player, Math.max(0, charges - MEDKIT_TICKS / 10));
|
||||
activeHeals.remove(uuid);
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(plugin, 0L, 1L);
|
||||
|
||||
activeHeals.put(uuid, task);
|
||||
}
|
||||
|
||||
private void cancelHeal(Player player) {
|
||||
BukkitTask task = activeHeals.remove(player.getUniqueId());
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
player.sendActionBar(Component.empty());
|
||||
player.sendMessage(Component.text("Лечение прервано.", NamedTextColor.YELLOW));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Flashlight ────────────────────────────────────────────────────────────
|
||||
|
||||
private void useFlashlight(Player player, ItemStack item) {
|
||||
int charges = DBDItems.getCharges(item);
|
||||
if (charges <= 0) {
|
||||
player.sendMessage(Component.text("Батарейки сели!", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ray-trace to find killer within 15 blocks
|
||||
var result = player.getWorld().rayTraceEntities(
|
||||
player.getEyeLocation(),
|
||||
player.getEyeLocation().getDirection(),
|
||||
15.0,
|
||||
e -> e instanceof Player && !e.equals(player)
|
||||
);
|
||||
|
||||
boolean hitKiller = false;
|
||||
if (result != null && result.getHitEntity() instanceof Player target) {
|
||||
BasePlayer bp = session.getPlayer(target.getUniqueId());
|
||||
if (bp != null && bp.isKiller()) {
|
||||
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 60, 1, false, false));
|
||||
target.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, 60, 3, false, false));
|
||||
target.playSound(target.getLocation(), Sound.ENTITY_BLAZE_HURT, 1.0f, 0.5f);
|
||||
player.sendMessage(Component.text("✔ Ослепили киллера!", NamedTextColor.YELLOW));
|
||||
target.sendMessage(Component.text("☀ Вас ослепили фонариком!", NamedTextColor.YELLOW));
|
||||
hitKiller = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hitKiller) {
|
||||
player.sendMessage(Component.text("Мимо...", NamedTextColor.GRAY));
|
||||
}
|
||||
|
||||
// Spend 1 charge per use
|
||||
updateItemCharges(player, charges - 1);
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_REDSTONE_TORCH_BURNOUT, 0.3f, 1.5f);
|
||||
}
|
||||
|
||||
// ── Key ───────────────────────────────────────────────────────────────────
|
||||
|
||||
private void useKey(Player player, Survivor survivor, ItemStack item) {
|
||||
int charges = DBDItems.getCharges(item);
|
||||
if (charges <= 0) {
|
||||
player.sendMessage(Component.text("Ключ сломан!", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
// Actual hatch opening logic is handled by hatch system
|
||||
// This just plays the animation and spends a charge
|
||||
player.sendMessage(Component.text("Вы используете ключ...", NamedTextColor.GOLD));
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_IRON_DOOR_OPEN, 1.0f, 0.8f);
|
||||
updateItemCharges(player, charges - 1);
|
||||
}
|
||||
|
||||
// ── Map ───────────────────────────────────────────────────────────────────
|
||||
|
||||
private void useMap(Player player, ItemStack item) {
|
||||
int charges = DBDItems.getCharges(item);
|
||||
if (charges <= 0) {
|
||||
player.sendMessage(Component.text("Карта использована!", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
// Show nearby generators / hooks in chat
|
||||
player.sendMessage(Component.text("═══ Карта (ближайшие объекты) ═══", NamedTextColor.AQUA));
|
||||
|
||||
var genManager = session.getGeneratorManager();
|
||||
if (genManager != null) {
|
||||
genManager.getIncompleteGenerators().stream()
|
||||
.filter(g -> g.getLocation().getWorld().equals(player.getWorld()))
|
||||
.sorted((a, b) -> Double.compare(
|
||||
a.getLocation().distance(player.getLocation()),
|
||||
b.getLocation().distance(player.getLocation())))
|
||||
.limit(3)
|
||||
.forEach(g -> {
|
||||
int dist = (int) g.getLocation().distance(player.getLocation());
|
||||
player.sendMessage(Component.text(
|
||||
" ⚙ Генератор [" + (int)g.getProgress() + "%] — " + dist + " блоков",
|
||||
NamedTextColor.YELLOW));
|
||||
});
|
||||
}
|
||||
|
||||
updateItemCharges(player, charges - 1);
|
||||
player.playSound(player.getLocation(), Sound.ITEM_ARMOR_EQUIP_LEATHER, 0.5f, 1.0f);
|
||||
}
|
||||
|
||||
// ── Utils ─────────────────────────────────────────────────────────────────
|
||||
|
||||
private void updateItemCharges(Player player, int newCharges) {
|
||||
ItemStack item = player.getInventory().getItemInMainHand();
|
||||
if (!DBDItems.isDBDItem(item)) return;
|
||||
|
||||
if (newCharges <= 0) {
|
||||
player.getInventory().setItemInMainHand(null);
|
||||
player.sendMessage(Component.text("Предмет израсходован.", NamedTextColor.RED));
|
||||
} else {
|
||||
player.getInventory().setItemInMainHand(DBDItems.setCharges(item, newCharges));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -66,6 +66,7 @@ public class GameplayPhase implements Phase {
|
|||
private KillerController killerController;
|
||||
private AttackListener attackListener;
|
||||
private Listener vanillaDamageBlocker;
|
||||
private dev.loki.item.ItemUseListener itemUseListener;
|
||||
|
||||
// Listener references grabbed from plugin
|
||||
private PlayerMoveListener moveListener;
|
||||
|
|
@ -155,6 +156,12 @@ public class GameplayPhase implements Phase {
|
|||
|
||||
killerController.initialize();
|
||||
|
||||
// --- Give starting items to survivors & register item use ---
|
||||
itemUseListener = new dev.loki.item.ItemUseListener(plugin, session);
|
||||
itemUseListener.register();
|
||||
|
||||
giveStartingItems(session);
|
||||
|
||||
// --- Wire listeners ---
|
||||
moveListener = plugin.getMoveListener();
|
||||
interactListener = plugin.getInteractListener();
|
||||
|
|
@ -215,6 +222,9 @@ public class GameplayPhase implements Phase {
|
|||
if (killerController != null) {
|
||||
killerController.shutdown();
|
||||
}
|
||||
if (itemUseListener != null) {
|
||||
itemUseListener.unregister();
|
||||
}
|
||||
if (playerManager != null) {
|
||||
playerManager.clear();
|
||||
}
|
||||
|
|
@ -234,6 +244,23 @@ public class GameplayPhase implements Phase {
|
|||
return shouldEnd;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Starting items
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private void giveStartingItems(GameSession session) {
|
||||
var loot = new dev.loki.item.ChestLoot();
|
||||
for (BasePlayer bp : session.getPlayers().values()) {
|
||||
if (bp.isKiller()) continue;
|
||||
Player p = bp.getPlayer();
|
||||
if (p == null || !p.isOnline()) continue;
|
||||
// Clear hotbar slots 0-3, give a random item in slot 0
|
||||
p.getInventory().clear();
|
||||
p.getInventory().setItem(0, loot.rollLoot());
|
||||
p.sendMessage(Component.text("[DBD] Вы получили стартовый предмет!", NamedTextColor.YELLOW));
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Hook ticking
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue