mdbd/src/main/java/dev/loki/killer/GeneratorKick.java

199 lines
7.2 KiB
Java

package dev.loki.killer;
import dev.loki.config.GameConfig;
import dev.loki.config.MessagesConfig;
import dev.loki.mdbd;
import dev.loki.objective.Generator;
import dev.loki.objective.GeneratorManager;
import dev.loki.player.Killer;
import net.kyori.adventure.text.Component;
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.ArrayList;
import java.util.HashMap;
import java.util.List;
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;
private final MessagesConfig messages;
/** UUID → ongoing charging task */
private final Map<UUID, BukkitTask> chargingTasks = new HashMap<>();
/** Shared cooldown across all generators: remaining ticks */
private int globalCooldownTicks = 0;
private BukkitTask cooldownTask;
/** Pending unblock tasks — cancelled on shutdown to avoid ghost tasks */
private final List<BukkitTask> pendingUnblockTasks = new ArrayList<>();
public GeneratorKick(Plugin plugin, GameConfig config, GeneratorManager generatorManager) {
this.plugin = plugin;
this.config = config;
this.generatorManager = generatorManager;
this.messages = mdbd.getInstance().getConfigManager().getMessages();
}
// -------------------------------------------------------------------------
// 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(messages.get("generator.kicked.cooldown", secsLeft));
}
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;
if (gen.getProgress() <= 0) {
if (p.isOnline()) {
p.sendMessage(messages.get("generator.kicked.already-broken"));
}
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(messages.get("generator.kicked.actionbar", (int) pct));
if (elapsed >= chargeTicks) {
executeKick(killer, gen);
cancel();
}
}
}.runTaskTimer(plugin, 1L, 1L);
chargingTasks.put(uuid, task);
if (p.isOnline()) p.sendMessage(messages.get("generator.kicked.begin"));
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; }
for (BukkitTask t : pendingUnblockTasks) t.cancel();
pendingUnblockTasks.clear();
}
// -------------------------------------------------------------------------
// Private
// -------------------------------------------------------------------------
private void executeKick(Killer killer, Generator gen) {
chargingTasks.remove(killer.getUuid());
// Remove 20% progress (or configured percent) and STOP — no continuous regression
double regPct = config.getKickRegressionPercent();
double current = gen.getProgress();
double newProg = Math.max(0, current - regPct);
gen.setProgress(newProg);
// Block generator from repair for the cooldown duration
gen.setBlocked(true);
Player p = killer.getPlayer();
if (p != null && p.isOnline()) {
p.sendActionBar(Component.empty());
p.sendMessage(messages.get("generator.kicked.success", (int) regPct));
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 0.6f, 1.3f);
}
// Notify all players
Bukkit.broadcast(messages.get("generator.kicked.broadcast", (int) regPct));
// Unblock generator after kick-duration (separate from global cooldown)
int unblockTicks = config.getKickDuration() * 20;
BukkitTask unblockTask = plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
gen.setBlocked(false);
}, unblockTicks);
pendingUnblockTasks.add(unblockTask);
// Start global kick 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);
}
}