package dev.loki.killer; import dev.loki.config.GameConfig; import dev.loki.objective.Generator; import dev.loki.objective.GeneratorManager; import dev.loki.player.Killer; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.Sound; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitTask; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * Killer generator kick: Killer holds Shift near a generator for * kick-charge-seconds (default 3), then the generator loses * kick-regression-percent (default 20%) progress. * * A shared cooldown of kick-cooldown-seconds applies to ALL generators. */ public class GeneratorKick { private final Plugin plugin; private final GameConfig config; private final GeneratorManager generatorManager; /** UUID → ongoing charging task */ private final Map chargingTasks = new HashMap<>(); /** Shared cooldown across all generators: remaining ticks */ private int globalCooldownTicks = 0; private BukkitTask cooldownTask; public GeneratorKick(Plugin plugin, GameConfig config, GeneratorManager generatorManager) { this.plugin = plugin; this.config = config; this.generatorManager = generatorManager; } // ------------------------------------------------------------------------- // Public API — called when killer starts/stops sneaking near a generator // ------------------------------------------------------------------------- /** Call when killer starts holding Shift near a generator. */ public boolean startCharging(Killer killer) { UUID uuid = killer.getUuid(); if (chargingTasks.containsKey(uuid)) return false; // already charging if (globalCooldownTicks > 0) { Player p = killer.getPlayer(); if (p != null) { int secsLeft = (int) Math.ceil(globalCooldownTicks / 20.0); p.sendMessage(Component.text("[DBD] Кулдаун удара: " + secsLeft + " сек", NamedTextColor.RED)); } return false; } Player p = killer.getPlayer(); if (p == null) return false; Generator gen = generatorManager.getNearestGenerator(p.getLocation(), config.getGeneratorInteractionRange()); if (gen == null || !gen.canBeRepaired()) return false; int chargeTicks = config.getKickChargeSeconds() * 20; BukkitTask task = new BukkitRunnable() { int elapsed = 0; @Override public void run() { Player player = killer.getPlayer(); if (player == null || !player.isOnline() || !player.isSneaking()) { stopCharging(killer.getUuid()); cancel(); return; } // Still near the same generator? Generator g = generatorManager.getNearestGenerator(player.getLocation(), config.getGeneratorInteractionRange()); if (g == null || g != gen) { stopCharging(killer.getUuid()); cancel(); return; } elapsed++; double pct = (double) elapsed / chargeTicks * 100; player.sendActionBar(Component.text("§c⚡ Разрушение: " + (int) pct + "%")); if (elapsed >= chargeTicks) { executeKick(killer, gen); cancel(); } } }.runTaskTimer(plugin, 1L, 1L); chargingTasks.put(uuid, task); if (p.isOnline()) p.sendMessage(Component.text("[DBD] Держите Shift для разрушения генератора...", NamedTextColor.RED)); return true; } /** Call when killer releases Shift or moves away. */ public void stopCharging(UUID killerUuid) { BukkitTask task = chargingTasks.remove(killerUuid); if (task != null) { task.cancel(); Player p = Bukkit.getPlayer(killerUuid); if (p != null && p.isOnline()) { p.sendActionBar(Component.empty()); } } } public boolean isCharging(UUID killerUuid) { return chargingTasks.containsKey(killerUuid); } public void shutdown() { for (BukkitTask t : chargingTasks.values()) t.cancel(); chargingTasks.clear(); if (cooldownTask != null) { cooldownTask.cancel(); cooldownTask = null; } } // ------------------------------------------------------------------------- // Private // ------------------------------------------------------------------------- private void executeKick(Killer killer, Generator gen) { chargingTasks.remove(killer.getUuid()); // Remove progress double regPct = config.getKickRegressionPercent(); double current = gen.getProgress(); double newProg = Math.max(0, current - regPct); gen.setProgress(newProg); gen.setUnderRegression(true, config.getKickDuration() * 20); Player p = killer.getPlayer(); if (p != null && p.isOnline()) { p.sendActionBar(Component.empty()); p.sendMessage(Component.text("[DBD] Генератор поврежден! -" + (int) regPct + "% прогресса", NamedTextColor.RED)); p.getWorld().playSound(p.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 0.6f, 1.3f); } // Notify all players nearby Bukkit.broadcast(Component.text("[DBD] ⚡ Маньяк разрушил генератор!", NamedTextColor.DARK_RED)); // Start global cooldown startGlobalCooldown(); } private void startGlobalCooldown() { globalCooldownTicks = config.getKickCooldownSeconds() * 20; if (cooldownTask != null) { cooldownTask.cancel(); } cooldownTask = new BukkitRunnable() { @Override public void run() { if (globalCooldownTicks > 0) { globalCooldownTicks -= 20; } else { globalCooldownTicks = 0; cancel(); cooldownTask = null; } } }.runTaskTimer(plugin, 20L, 20L); } }