package dev.loki.gate; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.World; public class ExitGate { private final Location location; private GateState state; private double progress; private double savedProgress; // сохраняется при уходе игрока private boolean powered; public enum GateState { CLOSED, OPENING, OPEN } public ExitGate(Location location) { this.location = location; this.state = GateState.CLOSED; this.progress = 0.0; this.savedProgress = 0.0; this.powered = false; } public Location getLocation() { return location; } /** Place a HOPPER block at this gate's location for player interaction. */ public void spawnGateBlock() { if (location.getWorld() == null) return; location.getBlock().setType(org.bukkit.Material.HOPPER, false); } /** Remove the interaction block (e.g. when gate opens or on cleanup). */ public void removeGateBlock() { if (location.getWorld() == null) return; location.getBlock().setType(org.bukkit.Material.AIR, false); } public GateState getState() { return state; } public boolean isClosed() { return state == GateState.CLOSED; } public boolean isOpening() { return state == GateState.OPENING; } public boolean isOpen() { return state == GateState.OPEN; } public double getProgress() { return progress; } public int getProgressPercent() { return (int) (progress * 100); } public boolean isPowered() { return powered; } public void setPowered(boolean powered) { this.powered = powered; if (powered && state == GateState.CLOSED) { state = GateState.OPENING; } } public void startOpening() { if (state == GateState.CLOSED && powered) { state = GateState.OPENING; playOpenSound(); } } public void updateProgress(double delta) { if (state != GateState.OPENING) return; // Линейная установка — delta это абсолютный шаг, не additive accumulation progress = Math.min(1.0, progress + delta); if (progress >= 1.0) { progress = 1.0; state = GateState.OPEN; playOpenedSound(); } } /** Прямая установка прогресса (для линейного расчёта в GateOpening). */ public void setProgressDirect(double value) { if (state != GateState.OPENING) return; progress = Math.min(1.0, Math.max(0.0, value)); if (progress >= 1.0) { progress = 1.0; state = GateState.OPEN; removeGateBlock(); playOpenedSound(); } } public double getSavedProgress() { return savedProgress; } /** Сохранить текущий прогресс (вызывается когда игрок уходит от ворот) */ public void saveProgress() { savedProgress = progress; } /** Восстановить сохранённый прогресс (вызывается когда игрок подходит снова) */ public void restoreProgress() { progress = savedProgress; } public void reset() { removeGateBlock(); this.state = GateState.CLOSED; this.progress = 0.0; this.savedProgress = 0.0; this.powered = false; } public boolean isInRange(Location playerLoc, double radius) { return location.distance(playerLoc) <= radius; } public void playOpenSound() { World world = location.getWorld(); if (world != null) { world.playSound(location, Sound.BLOCK_IRON_DOOR_OPEN, 1.0f, 0.8f); } } public void playOpenedSound() { World world = location.getWorld(); if (world != null) { world.playSound(location, Sound.BLOCK_IRON_DOOR_CLOSE, 1.0f, 1.2f); world.playSound(location, Sound.ENTITY_PLAYER_LEVELUP, 0.5f, 1.0f); } } public void spawnOpenParticles() { World world = location.getWorld(); if (world == null) return; world.spawnParticle(org.bukkit.Particle.PORTAL, location.clone().add(0.5, 1.5, 0.5), 50, 0.5, 1.0, 0.5, 0.1); } }