package dev.loki.phase; import dev.loki.config.GameConfig; import dev.loki.core.GameSession; import dev.loki.hook.*; import dev.loki.player.BasePlayer; import dev.loki.player.Killer; import dev.loki.player.PlayerState; import dev.loki.player.Survivor; import dev.loki.ui.TitleUI; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Sound; import org.bukkit.entity.Player; /** * Handles win condition checking during gameplay phase. */ public class GameplayWinConditions { private boolean shouldEnd; private String winReason; // "killer_win", "survivors_win", null public boolean isShouldEnd() { return shouldEnd; } public String getWinReason() { return winReason; } /** * Check all win conditions each second (20 ticks). */ public void checkWinConditions(GameSession session) { int aliveSurvivors = countAliveSurvivors(session); Killer killer = getKiller(session); // Killer disconnect: if killer player is null/offline, survivors win if (killer == null || killer.getPlayer() == null || !killer.getPlayer().isOnline()) { winReason = "survivors_win"; Bukkit.broadcast(Component.text("[DBD] Маньяк покинул игру! Выжившие победили!", NamedTextColor.GREEN)); announceSurvivorsWin(session); shouldEnd = true; return; } // Killer wins: all survivors are downed/hooked/carried/dead if (allSurvivorsIncapacitated(session)) { winReason = "killer_win"; Bukkit.broadcast(Component.text("[DBD] Все выжившие обезврежены!", NamedTextColor.DARK_RED)); announceKillerWin(session); shouldEnd = true; return; } // Survivors win: all generators done and at least one escaped if (hasEscapedSurvivor(session)) { winReason = "survivors_win"; announceSurvivorsWin(session); shouldEnd = true; } } /** True if NO survivor can act (all are DOWNED, HOOKED, CARRIED, or DEAD). */ private boolean allSurvivorsIncapacitated(GameSession session) { boolean hasSurvivors = false; for (BasePlayer bp : session.getPlayers().values()) { if (bp.isKiller()) continue; hasSurvivors = true; PlayerState st = bp.getState(); if (st != PlayerState.DOWNED && st != PlayerState.HOOKED && st != PlayerState.CARRIED && st != PlayerState.DEAD) { return false; // at least one survivor can still act } } return hasSurvivors; // true if there are survivors and all are incapacitated } private int countAliveSurvivors(GameSession session) { int count = 0; for (BasePlayer bp : session.getPlayers().values()) { if (bp.isKiller()) continue; Survivor s = (Survivor) bp; if (!s.isDeadOrEscaped()) count++; } return count; } private boolean hasEscapedSurvivor(GameSession session) { for (BasePlayer bp : session.getPlayers().values()) { if (bp.isKiller()) continue; if (bp.getState() == PlayerState.ESCAPED) return true; } return false; } private Killer getKiller(GameSession session) { for (BasePlayer bp : session.getPlayers().values()) { if (bp.isKiller()) return (Killer) bp; } return null; } public void announceKillerWin(GameSession session) { winReason = "killer_win"; Bukkit.broadcast(Component.text("[DBD] Маньяк победил! Все выжившие мертвы!", NamedTextColor.DARK_RED)); for (BasePlayer bp : session.getPlayers().values()) { Player p = bp.getPlayer(); if (p == null || !p.isOnline()) continue; if (!bp.isKiller() && bp.getState() == PlayerState.DEAD) { p.setGameMode(GameMode.SPECTATOR); } else { p.setGameMode(GameMode.SURVIVAL); } p.playSound(p.getLocation(), Sound.ENTITY_WITHER_DEATH, 1.0f, 1.0f); } // Teleport handled by EndgamePhase.exit() } public void announceSurvivorsWin(GameSession session) { winReason = "survivors_win"; Bukkit.broadcast(Component.text("[DBD] Выжившие победили!", NamedTextColor.GREEN)); for (BasePlayer bp : session.getPlayers().values()) { Player p = bp.getPlayer(); if (p == null || !p.isOnline()) continue; p.setGameMode(GameMode.SURVIVAL); p.playSound(p.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 1.2f); } // Teleport handled by EndgamePhase.exit() } // Removed scheduleTeleportToLobby — teleport now happens only in EndgamePhase.exit() }