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

406 lines
No EOL
16 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.chest.ChestManager;
import dev.loki.chest.ChestOpening;
import dev.loki.config.GameConfig;
import dev.loki.core.GameSession;
import dev.loki.gate.ExitGate;
import dev.loki.gate.GateManager;
import dev.loki.gate.GateOpening;
import dev.loki.hook.HookManager;
import dev.loki.hook.HookRecovery;
import dev.loki.hook.HookRescue;
import dev.loki.hook.HookSabotage;
import dev.loki.hook.HookSacrifice;
import dev.loki.hook.HookStruggle;
import dev.loki.item.ChestLoot;
import dev.loki.killer.GeneratorKick;
import dev.loki.mdbd;
import dev.loki.minigames.GeneratorMinigame;
import dev.loki.minigames.generator.GuiRouletteMinigame;
import dev.loki.objective.GeneratorManager;
import dev.loki.player.BasePlayer;
import dev.loki.player.PlayerState;
import dev.loki.player.Survivor;
import dev.loki.ui.ActionBar;
import dev.loki.ui.TitleUI;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class GameplayPhase implements Phase {
private final GeneratorManager generatorManager;
private int tickCounter;
private boolean shouldEnd;
private boolean allGensDone;
// Sub-handlers
private GameplayHookHandler hookHandler;
private GameplayWinConditions winConditions;
private GameplayDamageSystem damageSystem;
private GameplayUI ui;
private GameplayInteraction interaction;
// Managers
private HookManager hookManager;
private GateManager gateManager;
private GateOpening gateOpening;
private HookRescue hookRescue;
private HookSabotage hookSabotage;
private HookStruggle hookStruggle;
private TitleUI titleUI;
private ChestManager chestManager;
private ChestOpening chestOpening;
private GeneratorKick generatorKick;
private dev.loki.objective.GeneratorRepair generatorRepair;
private dev.loki.objective.GeneratorHologram generatorHologram;
private dev.loki.hook.HookHologram hookHologram;
private dev.loki.chest.ChestHologram chestHologram;
public GameplayPhase(GeneratorManager generatorManager) {
this.generatorManager = generatorManager;
}
// =========================================================================
// Phase lifecycle
// =========================================================================
@Override
public void enter(GameSession session) {
mdbd plugin = session.getPlugin();
GameConfig cfg = session.getConfig();
tickCounter = 0;
shouldEnd = false;
allGensDone = false;
winConditions = new GameplayWinConditions();
initManagers(session, plugin, cfg);
initSubHandlers(session, plugin, cfg);
initListeners(session, plugin);
// Устанавливаем ночь на всех мирах
for (var world : Bukkit.getWorlds()) {
world.setGameRule(org.bukkit.GameRule.DO_DAYLIGHT_CYCLE, false);
world.setTime(18000); // Полночь
world.setStorm(false);
}
Bukkit.broadcast(session.getPlugin().getConfigManager().getMessages().get("game.start"));
}
@Override
public void tick(GameSession session) {
tickCounter++;
generatorManager.tick();
if (generatorRepair != null) generatorRepair.tick();
if (interaction != null) interaction.tickSurvivors();
hookHandler.tick();
boolean timeExpired = ui.tickMatchTimer(session);
// Particle effects around generators (every 10 ticks)
if (tickCounter % 10 == 0 && generatorManager != null) {
for (var gen : generatorManager.getAllGenerators()) {
if (gen.isCompleted()) continue;
Location gloc = gen.getLocation().clone().add(0.5, 0.5, 0.5);
gloc.getWorld().spawnParticle(org.bukkit.Particle.ELECTRIC_SPARK,
gloc, 2, 0.8, 0.5, 0.8, 0.01);
gloc.getWorld().spawnParticle(org.bukkit.Particle.END_ROD,
gloc, 1, 0.6, 0.3, 0.6, 0.01);
}
}
if (tickCounter % 20 == 0) {
checkGeneratorProgress(session);
winConditions.checkWinConditions(session);
if (winConditions.isShouldEnd() || timeExpired) {
shouldEnd = true;
}
ui.updateSidebar(session, generatorManager);
}
if (timeExpired) {
showGameResults(session);
teleportAllToLobby(session);
session.stop();
return;
}
}
@Override
public void exit(GameSession session) {
clearListeners();
clearManagers(session);
ui.clear(session);
ui.resetPlayers(session);
damageSystem.clear();
damageSystem.clearManagers();
Bukkit.broadcast(session.getPlugin().getConfigManager().getMessages().get("game.end"));
}
@Override
public boolean isComplete() {
return shouldEnd;
}
/**
* Returns the reason the gameplay phase ended, or null if not yet ended.
*/
public String getWinReason() {
return winConditions != null ? winConditions.getWinReason() : null;
}
// =========================================================================
// Init helpers
// =========================================================================
private void initManagers(GameSession session, mdbd plugin, GameConfig cfg) {
hookManager = new HookManager(plugin);
hookManager.loadHooks(plugin.getConfigManager().getLocations());
hookManager.setMaxHooks(cfg.getMaxHooks());
hookManager.startTicking();
gateManager = new GateManager(plugin.getConfigManager().getLocations());
gateOpening = new GateOpening(gateManager, cfg);
ActionBar ab = new ActionBar();
HookRecovery hookRecovery = new HookRecovery(plugin, cfg);
titleUI = new TitleUI(plugin);
String genMinigameType = cfg.getGeneratorMinigame();
GeneratorMinigame genMinigame;
if ("gui".equalsIgnoreCase(genMinigameType)) {
genMinigame = new GuiRouletteMinigame(plugin);
} else if ("text".equalsIgnoreCase(genMinigameType)) {
genMinigame = new dev.loki.minigames.generator.TextSkillCheckMinigame(plugin);
} else {
plugin.getLogger().warning("Unknown generator minigame: " + genMinigameType + ", using gui");
genMinigame = new GuiRouletteMinigame(plugin);
}
hookStruggle = new HookStruggle(plugin, titleUI, cfg);
HookSacrifice hookSacrifice = new HookSacrifice(plugin, null);
hookSabotage = new HookSabotage(plugin, cfg, hookManager);
hookRescue = new HookRescue(plugin, ab, cfg);
hookHandler = new GameplayHookHandler(hookManager, hookSacrifice, hookStruggle, hookRecovery);
hookRescue.setOnRescueComplete((rescuer, victim) -> hookHandler.onRescued(victim));
chestManager = new ChestManager(plugin, plugin.getConfigManager().getLocations(), cfg);
chestManager.startLootResetTimer();
chestOpening = new ChestOpening(plugin);
chestOpening.setChestLoot(new ChestLoot(cfg));
var gameWorld = plugin.getLobbyManager().getGameWorld();
if (gameWorld != null) {
for (var h : hookManager.getAllHooks()) h.getLocation().setWorld(gameWorld);
for (var c : chestManager.getAllChests()) c.getLocation().setWorld(gameWorld);
for (var g : generatorManager.getAllGenerators()) g.getLocation().setWorld(gameWorld);
}
spawnGameBlocks(plugin, cfg);
generatorKick = new GeneratorKick(plugin, cfg, generatorManager);
generatorRepair = new dev.loki.objective.GeneratorRepair(plugin, generatorManager, genMinigame);
// Голограммы ВСЕГДА включены
generatorHologram = new dev.loki.objective.GeneratorHologram(plugin, generatorManager);
generatorHologram.start();
plugin.getLogger().info("[GameplayPhase] Generator holograms started");
hookHologram = new dev.loki.hook.HookHologram(plugin, hookManager);
hookHologram.start();
plugin.getLogger().info("[GameplayPhase] Hook holograms: " + hookManager.getAllHooks().size());
chestHologram = new dev.loki.chest.ChestHologram(plugin, chestManager);
chestHologram.start();
plugin.getLogger().info("[GameplayPhase] Chest holograms: " + chestManager.getAllChests().size());
session.setHookManager(hookManager);
session.setGateManager(gateManager);
}
private void initSubHandlers(GameSession session, mdbd plugin, GameConfig cfg) {
damageSystem = new GameplayDamageSystem();
damageSystem.init(session, plugin, cfg);
ui = new GameplayUI();
ui.init(session, plugin, cfg);
ui.setWinConditions(winConditions);
interaction = new GameplayInteraction();
interaction.setMoveListener(plugin.getMoveListener());
interaction.setInteractListener(plugin.getInteractListener());
// ВАЖНО: переустановить generatorManager, поскольку он может быть null после exit()
plugin.getInteractListener().setGeneratorManager(generatorManager);
interaction.setManagers(gateManager, hookManager, hookRescue,
hookSabotage, generatorKick, damageSystem,
chestManager, chestOpening, gateOpening, generatorRepair);
}
private void initListeners(GameSession session, mdbd plugin) {
for (BasePlayer bp : session.getPlayers().values()) {
Player p = bp.getPlayer();
if (p != null && p.isOnline()) p.getInventory().clear();
}
GeneratorMinigame gm = generatorRepair.getMinigame();
if (gm instanceof GuiRouletteMinigame gui) {
dev.loki.listener.SkillCheckListener listener =
new dev.loki.listener.SkillCheckListener(plugin, gui);
listener.register();
}
interaction.wire(session);
}
// =========================================================================
// Tick helpers
// =========================================================================
private void checkGeneratorProgress(GameSession session) {
if (allGensDone) return;
if (generatorManager.areAllRequiredCompleted()) {
allGensDone = true;
interaction.setAllGensDone(true);
gateManager.activateEndgame();
Bukkit.broadcast(session.getPlugin().getConfigManager().getMessages().get("generator.repair.all-done"));
for (BasePlayer bp : session.getPlayers().values()) {
Player p = bp.getPlayer();
if (p != null) p.playSound(p.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_BLAST, 1.0f, 1.0f);
}
}
}
private void spawnGameBlocks(mdbd plugin, GameConfig cfg) {
// Спавн блоков на местах генераторов
Material genMat = Material.matchMaterial(cfg.getGeneratorBlock());
if (genMat == null) genMat = Material.BLAST_FURNACE;
for (var gen : generatorManager.getAllGenerators()) {
Location loc = gen.getLocation();
if (loc.getWorld() == null) continue;
Block b = loc.getBlock();
if (b.getType() != genMat) b.setType(genMat, false);
}
// Спавн блоков на местах сундуков + лут (resetAllChests уже устанавливает лут)
Material chestMat = Material.matchMaterial(cfg.getChestBlock());
if (chestMat == null) chestMat = Material.CHEST;
chestManager.resetAllChests();
// Убедимся, что у каждого сундука есть лут (не null и не AIR)
for (dev.loki.chest.Chest chest : chestManager.getAllChests()) {
Location loc = chest.getLocation();
if (loc.getWorld() == null) continue;
Block block = loc.getBlock();
if (block.getType() != chestMat) block.setType(chestMat, false);
if (!chest.hasLoot()) {
ChestLoot chestLoot = new ChestLoot(cfg);
chest.setLoot(chestLoot.rollLoot());
}
}
plugin.getLogger().info("[GameplayPhase] Spawned " + chestManager.getTotalChests() + " chests with loot");
// Спавн блоков на местах крюков
Material hookMat = Material.matchMaterial(cfg.getHookBlock());
if (hookMat == null) hookMat = Material.IRON_BARS;
for (var hook : hookManager.getAllHooks()) {
Location loc = hook.getLocation();
if (loc.getWorld() == null) continue;
Block b = loc.getBlock();
if (b.getType() != hookMat) b.setType(hookMat, false);
}
plugin.getLogger().info("[GameplayPhase] Spawned blocks for " + hookManager.getAllHooks().size() + " hooks");
// Спавн блоков на местах ворот (Hopper — для открытия через ПКМ)
for (ExitGate gate : gateManager.getAllGates()) {
gate.spawnGateBlock();
}
plugin.getLogger().info("[GameplayPhase] Spawned blocks for " + gateManager.getAllGates().size() + " gates");
}
// =========================================================================
// Cleanup
// =========================================================================
private void showGameResults(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()) {
Player p = player.getPlayer();
String name = p != null ? p.getName() : "Unknown";
results.add("§c☠ " + name + " — Маньяк");
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);
}
}
private void teleportAllToLobby(GameSession session) {
for (BasePlayer bp : session.getPlayers().values()) {
Player p = bp.getPlayer();
if (p != null && p.isOnline()) {
p.setGameMode(org.bukkit.GameMode.ADVENTURE);
p.getInventory().clear();
p.setWalkSpeed(0.2f);
p.setFlySpeed(0.1f);
p.setHealth(20.0);
p.setFoodLevel(20);
session.getPlugin().getLobbyManager().teleportToLobby(p);
}
}
}
private void clearListeners() {
if (interaction != null) interaction.clear();
}
private void clearManagers(GameSession session) {
if (hookHandler != null) hookHandler.clear();
if (hookRescue != null) hookRescue.clear();
if (hookSabotage != null) hookSabotage.shutdown();
if (hookManager != null) hookManager.clear();
if (chestOpening != null) chestOpening.cancelAll();
if (chestManager != null) chestManager.resetAllChests();
if (generatorKick != null) generatorKick.shutdown();
if (generatorHologram != null) generatorHologram.stop();
if (hookHologram != null) hookHologram.stop();
if (titleUI != null) titleUI.clearSkillChecks();
if (hookStruggle != null) hookStruggle.clear();
if (chestManager != null) chestManager.stopLootResetTimer();
if (chestHologram != null) chestHologram.stop();
// Clean up gate blocks
if (gateManager != null) {
for (ExitGate gate : gateManager.getAllGates()) {
gate.removeGateBlock();
}
gateManager.resetAll();
}
session.getPlugin().getInteractListener().setGeneratorManager(null);
}
}