package dev.loki.hook; import dev.loki.mdbd; import dev.loki.player.PlayerState; import dev.loki.player.Survivor; import dev.loki.ui.ActionBar; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; import java.util.HashMap; import java.util.Map; import java.util.UUID; public class HookRescue { private final mdbd plugin; private final ActionBar actionBar; private final Map activeRescues; private static final int RESCUE_DURATION_TICKS = 40; private static final double RESCUE_RANGE = 3.0; public HookRescue(mdbd plugin, ActionBar actionBar) { this.plugin = plugin; this.actionBar = actionBar; this.activeRescues = new HashMap<>(); } public boolean startRescue(Survivor rescuer, Hook hook) { UUID uuid = rescuer.getUuid(); if (activeRescues.containsKey(uuid)) return false; if (!hook.isOccupied() || hook.getHookedSurvivor() == null) return false; Location hookLoc = hook.getLocation(); Player player = rescuer.getPlayer(); if (player == null || player.getLocation().distance(hookLoc) > RESCUE_RANGE) { return false; } RescueSession session = new RescueSession(rescuer, hook, RESCUE_DURATION_TICKS); activeRescues.put(uuid, session); BukkitTask task = plugin.getServer().getScheduler().runTaskTimer( plugin, () -> tickRescue(uuid), 1L, 1L ); session.setTask(task); return true; } private void tickRescue(UUID uuid) { RescueSession session = activeRescues.get(uuid); if (session == null) return; Survivor rescuer = session.getRescuer(); Hook hook = session.getHook(); Player player = rescuer.getPlayer(); if (player == null || !player.isOnline()) { cancelRescue(uuid); return; } if (player.getLocation().distance(hook.getLocation()) > RESCUE_RANGE) { cancelRescue(uuid); actionBar.sendMessage(player, "Rescue cancelled - too far!"); return; } session.incrementProgress(); double percent = session.getProgressPercent(); actionBar.showProgress(player, "Rescuing...", percent); if (session.isComplete()) { completeRescue(session); activeRescues.remove(uuid); } } private void completeRescue(RescueSession session) { Survivor rescuer = session.getRescuer(); Hook hook = session.getHook(); Survivor victim = hook.getHookedSurvivor(); hook.unhookSurvivor(); if (victim != null) { victim.setState(PlayerState.INJURED); Player victimPlayer = victim.getPlayer(); if (victimPlayer != null) { victimPlayer.teleport(hook.getLocation().clone().add(1, 0, 0)); } } Player rescuerPlayer = rescuer.getPlayer(); if (rescuerPlayer != null) { actionBar.sendMessage(rescuerPlayer, "Rescue complete!"); } } public void cancelRescue(UUID uuid) { RescueSession session = activeRescues.remove(uuid); if (session != null) { session.cancel(); } } public boolean isRescuing(UUID uuid) { return activeRescues.containsKey(uuid); } public void clear() { for (RescueSession session : activeRescues.values()) { session.cancel(); } activeRescues.clear(); } private static class RescueSession { private final Survivor rescuer; private final Hook hook; private final int durationTicks; private int progressTicks; private BukkitTask task; RescueSession(Survivor rescuer, Hook hook, int durationTicks) { this.rescuer = rescuer; this.hook = hook; this.durationTicks = durationTicks; this.progressTicks = 0; } void incrementProgress() { progressTicks++; } boolean isComplete() { return progressTicks >= durationTicks; } double getProgressPercent() { return (double) progressTicks / durationTicks * 100; } void setTask(BukkitTask task) { this.task = task; } void cancel() { if (task != null) task.cancel(); } Survivor getRescuer() { return rescuer; } Hook getHook() { return hook; } } }