mdbd/src/main/java/dev/loki/phase/EndgamePhase.java

285 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package dev.loki.phase;
import dev.loki.core.GameSession;
import dev.loki.gate.GateManager;
import dev.loki.hatch.Hatch;
import dev.loki.hatch.HatchCondition;
import dev.loki.hatch.HatchEscape;
import dev.loki.player.BasePlayer;
import dev.loki.player.PlayerState;
import dev.loki.player.Survivor;
import dev.loki.ui.Sidebar;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.title.Title;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
public class EndgamePhase implements Phase {
private final int openTicks;
private boolean complete;
private boolean gatesActivated;
private boolean killerWin; // true если маньяк убил всех — пропускаем геймплей эндгейма
private GateManager gateManager;
private Hatch hatch;
private HatchCondition hatchCondition;
private HatchEscape hatchEscape;
private Sidebar sidebar;
public EndgamePhase() {
this.openTicks = 20 * 20;
}
public EndgamePhase(GateManager gateManager,
Hatch hatch, HatchCondition hatchCondition) {
this.openTicks = 20 * 20;
this.gateManager = gateManager;
this.hatch = hatch;
this.hatchCondition = hatchCondition;
this.hatchEscape = new HatchEscape(hatch);
}
// -------------------------------------------------------------------------
// Phase lifecycle
// -------------------------------------------------------------------------
@Override
public void enter(GameSession session) {
this.complete = false;
this.gatesActivated = false;
this.killerWin = false;
// Проверяем: если все выжившие мертвы/на крюке — это killer win,
// показываем результаты сразу, без геймплея эндгейма
int aliveCount = 0;
for (BasePlayer bp : session.getPlayers().values()) {
if (!bp.isKiller() && bp.getState() != PlayerState.DEAD && bp.getState() != PlayerState.ESCAPED
&& bp.getState() != PlayerState.DOWNED && bp.getState() != PlayerState.HOOKED) {
aliveCount++;
}
}
if (aliveCount == 0) {
this.killerWin = true;
this.complete = true;
// Показываем результаты и телепортируем всех в лобби
announceEndgameEnd(session);
teleportAllToLobby(session);
return;
}
// Pick up GateManager from session if not injected via constructor
if (gateManager == null) {
gateManager = session.getGateManager();
}
// Set up sidebar
sidebar = new Sidebar();
for (BasePlayer bp : session.getPlayers().values()) {
Player p = bp.getPlayer();
if (p != null && p.isOnline()) sidebar.setupPlayer(p);
}
activateEndgame(session);
announceEndgameStart(session);
}
@Override
public void tick(GameSession session) {
// Update sidebar stats every 40 ticks
if (session.getTicksElapsed() % 40 == 0 && sidebar != null) {
for (BasePlayer bp : session.getPlayers().values()) {
Player p = bp.getPlayer();
if (p != null && p.isOnline()) {
sidebar.updateGameStats(p, session, session.getGeneratorManager());
}
}
}
updateGates(session);
updateHatch(session);
checkWinConditions(session);
}
@Override
public void exit(GameSession session) {
if (sidebar != null) {
for (BasePlayer bp : session.getPlayers().values()) {
Player p = bp.getPlayer();
if (p != null && p.isOnline()) {
sidebar.disableTimerObjective(p);
}
}
sidebar.clear();
sidebar = null;
}
if (hatch != null) {
hatch.reset();
}
// exit() НЕ вызывает session.stop() — это делает transitionToNextPhase()
// Телепорт и результаты уже обработаны в enter() или будут в teleportAllToLobby
}
/**
* Телепортирует всех игроков в лобби, сбрасывает атрибуты и останавливает сессию.
*/
private void teleportAllToLobby(GameSession session) {
List<BasePlayer> playersToTeleport = new ArrayList<>(session.getPlayers().values());
new BukkitRunnable() {
@Override
public void run() {
for (BasePlayer bp : playersToTeleport) {
Player p = bp.getPlayer();
if (p != null && p.isOnline()) {
resetPlayerAttributes(p);
session.getPlugin().getLobbyManager().teleportToLobby(p);
}
}
session.stop();
}
}.runTaskLater(session.getPlugin(), 60L);
}
/**
* Сбрасывает все атрибуты игрока на значения по умолчанию.
*/
private void resetPlayerAttributes(Player p) {
p.setGameMode(org.bukkit.GameMode.ADVENTURE);
p.getInventory().clear();
p.setWalkSpeed(0.2f);
p.setFlySpeed(0.1f);
p.setSwimming(false);
p.setSprinting(false);
p.setSneaking(false);
p.setHealth(20.0);
p.setFoodLevel(20);
p.setSaturation(5);
try {
var scale = p.getAttribute(org.bukkit.attribute.Attribute.SCALE);
if (scale != null) scale.setBaseValue(1.0);
} catch (Exception ignored) {}
try {
var maxHp = p.getAttribute(org.bukkit.attribute.Attribute.MAX_HEALTH);
if (maxHp != null) maxHp.setBaseValue(20.0);
} catch (Exception ignored) {}
try {
var moveSpeed = p.getAttribute(org.bukkit.attribute.Attribute.MOVEMENT_SPEED);
if (moveSpeed != null) moveSpeed.setBaseValue(0.1);
} catch (Exception ignored) {}
}
@Override
public boolean isComplete() {
return complete;
}
// -------------------------------------------------------------------------
// Private helpers
// -------------------------------------------------------------------------
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 (hatchCondition.isLastSurvivor(session.getPlayers().values())) {
hatchCondition.checkAndOpen(hatch, session.getPlayers().values(), repairedGens);
if (hatch.isOpen() && hatchEscape != null) {
hatchEscape.notifyNearbyPlayers();
}
}
}
private int countRepairedGenerators(GameSession session) {
if (session.getGeneratorManager() != null) {
return session.getGeneratorManager().getCompletedCount();
}
return 0;
}
private void announceEndgameStart(GameSession session) {
for (BasePlayer bp : session.getPlayers().values()) {
Player p = bp.getPlayer();
if (p == null) continue;
Title title = Title.title(
Component.text("ЭНДГЕЙМ!").color(TextColor.color(0xCC0000)),
Component.text("Ворота открыты! Бегите!").color(NamedTextColor.GREEN),
Title.Times.times(Duration.ofMillis(500), Duration.ofSeconds(3), Duration.ofMillis(500))
);
p.showTitle(title);
p.playSound(p.getLocation(), Sound.ENTITY_WITHER_SPAWN, 1.0f, 0.8f);
}
}
private void updateGates(GameSession session) {
if (gateManager == null) return;
gateManager.updateAllGates(1.0 / openTicks);
}
private void updateHatch(GameSession session) {
if (hatch == null || !hatch.isOpen() || hatchEscape == null) return;
for (BasePlayer player : session.getPlayers().values()) {
if (player.isKiller()) continue;
PlayerState st = player.getState();
if (st != PlayerState.HEALTHY && st != PlayerState.INJURED) continue;
if (hatchEscape.canEscape((Survivor) player)) {
hatchEscape.tryEscape((Survivor) player);
}
}
}
private void checkWinConditions(GameSession session) {
int survivorsAlive = 0;
for (BasePlayer player : session.getPlayers().values()) {
if (player.isKiller()) continue;
PlayerState st = player.getState();
if (st != PlayerState.DEAD && st != PlayerState.ESCAPED
&& st != PlayerState.DOWNED && st != PlayerState.HOOKED) {
survivorsAlive++;
}
}
if (survivorsAlive == 0) {
complete = true;
}
}
private void announceEndgameEnd(GameSession session) {
List<String> results = new ArrayList<>();
results.add("§6§l=== РЕЗУЛЬТАТЫ ===");
int escaped = 0, died = 0;
for (BasePlayer player : session.getPlayers().values()) {
if (player.isKiller()) continue;
Player p = player.getPlayer();
String name = p != null ? p.getName() : "Unknown";
if (player.getState() == PlayerState.ESCAPED) {
results.add("§a✔ " + name + " — Сбежал");
escaped++;
} else {
results.add("§c✘ " + name + " — Погиб");
died++;
}
}
results.add("§7Выживших: §a" + escaped + " §7/ Погибших: §c" + died);
String msg = String.join("\n", results);
for (BasePlayer player : session.getPlayers().values()) {
Player p = player.getPlayer();
if (p != null) p.sendMessage(msg);
}
}
}