package dev.loki.phase; import dev.loki.core.GameSession; import dev.loki.gate.GateManager; import dev.loki.gate.GateOpening; import dev.loki.hatch.Hatch; import dev.loki.hatch.HatchCondition; import dev.loki.hatch.HatchEscape; import dev.loki.player.BasePlayer; import dev.loki.player.Killer; import dev.loki.player.PlayerState; import dev.loki.player.Survivor; import org.bukkit.Sound; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import java.util.ArrayList; import java.util.List; public class EndgamePhase implements Phase { private final int collapseSeconds; private final int openTicks; private int remainingTicks; private boolean complete; private boolean gatesActivated; private GateManager gateManager; private GateOpening gateOpening; private Hatch hatch; private HatchCondition hatchCondition; private HatchEscape hatchEscape; public EndgamePhase() { this.collapseSeconds = 120; this.openTicks = 20 * 20; } public EndgamePhase(int collapseSeconds, GateManager gateManager, Hatch hatch, HatchCondition hatchCondition) { this.collapseSeconds = collapseSeconds; this.openTicks = 20 * 20; this.gateManager = gateManager; this.hatch = hatch; this.hatchCondition = hatchCondition; this.hatchEscape = new HatchEscape(hatch); } @Override public void enter(GameSession session) { this.remainingTicks = collapseSeconds * 20; this.complete = false; this.gatesActivated = false; activateEndgame(session); announceEndgameStart(session); } private void activateEndgame(GameSession session) { if (gateManager != null && !gatesActivated) { gateManager.activateEndgame(); gatesActivated = true; } checkHatchConditions(session); session.getPlugin().getLogger().info("Endgame started!"); } private void checkHatchConditions(GameSession session) { if (hatch == null || hatchCondition == null) return; int repairedGens = countRepairedGenerators(session); hatchCondition.checkAndReveal(hatch, session.getPlayers().values(), repairedGens); if (isLastSurvivor(session)) { hatchCondition.checkAndOpen(hatch, session.getPlayers().values(), repairedGens); if (hatch.isOpen()) { hatchEscape.notifyNearbyPlayers(); } } } private boolean isLastSurvivor(GameSession session) { if (hatchCondition == null) return false; return hatchCondition.isLastSurvivor(session.getPlayers().values()); } private int countRepairedGenerators(GameSession session) { return 5; } private void announceEndgameStart(GameSession session) { for (BasePlayer player : session.getPlayers().values()) { Player bukkitPlayer = player.getPlayer(); if (bukkitPlayer != null) { bukkitPlayer.sendTitle("§4§lЭНДГЕЙМ!", "§cКоллапс через 2 минуты!", 10, 70, 20); bukkitPlayer.playSound(bukkitPlayer.getLocation(), Sound.ENTITY_WITHER_SPAWN, 1.0f, 0.8f); } } } @Override public void tick(GameSession session) { remainingTicks--; int secondsLeft = remainingTicks / 20; updateGates(session); updateHatch(session); checkWinConditions(session); sendCountdown(session, secondsLeft); if (remainingTicks <= 0) { triggerCollapse(session); complete = true; } } private void updateGates(GameSession session) { if (gateManager == null) return; gateManager.updateAllGates(1.0 / openTicks); } private void updateHatch(GameSession session) { if (hatch == null || !hatch.isOpen()) return; for (BasePlayer player : session.getPlayers().values()) { if (player.isKiller()) continue; if (player.getState() != PlayerState.HEALTHY && player.getState() != PlayerState.INJURED) continue; if (hatchEscape.canEscape((Survivor) player)) { hatchEscape.tryEscape((Survivor) player); } } } private void checkWinConditions(GameSession session) { boolean allEscapedOrDead = true; int survivorsAlive = 0; for (BasePlayer player : session.getPlayers().values()) { if (player.isKiller()) continue; PlayerState state = player.getState(); if (state != PlayerState.DEAD && state != PlayerState.ESCAPED) { allEscapedOrDead = false; survivorsAlive++; } } if (allEscapedOrDead || survivorsAlive == 0) { complete = true; } } private void sendCountdown(GameSession session, int secondsLeft) { if (secondsLeft > 0 && secondsLeft <= 10) { for (BasePlayer player : session.getPlayers().values()) { Player bukkitPlayer = player.getPlayer(); if (bukkitPlayer != null) { bukkitPlayer.sendTitle("§4" + secondsLeft, "", 0, 25, 0); bukkitPlayer.playSound(bukkitPlayer.getLocation(), Sound.BLOCK_NOTE_BLOCK_HAT, 0.5f, 1.0f); } } } } private void triggerCollapse(GameSession session) { for (BasePlayer player : session.getPlayers().values()) { if (player.getState() == PlayerState.DEAD || player.getState() == PlayerState.ESCAPED) continue; Player bukkitPlayer = player.getPlayer(); if (bukkitPlayer == null) continue; if (!player.isKiller()) { bukkitPlayer.setHealth(0); player.setState(PlayerState.DEAD); } else { ((Killer) player).setCarrying(false); } bukkitPlayer.sendTitle("§4§lКОЛЛАПС!", "§cКарта разрушена!", 10, 70, 20); } } @Override public void exit(GameSession session) { announceEndgameEnd(session); if (hatch != null) { hatch.reset(); } new BukkitRunnable() { @Override public void run() { session.stop(); } }.runTaskLater(session.getPlugin(), 100L); } private void announceEndgameEnd(GameSession session) { List results = new ArrayList<>(); results.add("§6§l=== РЕЗУЛЬТАТЫ ==="); int escaped = 0; int died = 0; for (BasePlayer player : session.getPlayers().values()) { if (player.isKiller()) continue; PlayerState state = player.getState(); Player bukkitPlayer = player.getPlayer(); String name = bukkitPlayer != null ? bukkitPlayer.getName() : "Unknown"; if (state == PlayerState.ESCAPED) { results.add("§a✔ " + name + " — Сбежал"); escaped++; } else { results.add("§c✘ " + name + " — Погиб"); died++; } } results.add("§7Выживших: §a" + escaped + " §7/ Погибших: §c" + died); String resultMessage = String.join("\n", results); for (BasePlayer player : session.getPlayers().values()) { Player bukkitPlayer = player.getPlayer(); if (bukkitPlayer != null) { bukkitPlayer.sendMessage(resultMessage); } } } @Override public boolean isComplete() { return complete; } public int getRemainingSeconds() { return remainingTicks / 20; } }