199 lines
7.2 KiB
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);
|
|
}
|
|
}
|