This commit is contained in:
loki5512344 2026-06-10 23:00:12 +02:00
parent 89dc9eb00d
commit 957ab4a5a2
149 changed files with 5379 additions and 3263 deletions

View file

@ -0,0 +1,308 @@
package dev.loki.phase;
import dev.loki.core.GameSession;
import dev.loki.gate.ExitGate;
import dev.loki.gate.GateManager;
import dev.loki.gate.GateOpening;
import dev.loki.hook.Hook;
import dev.loki.hook.HookManager;
import dev.loki.hook.HookRescue;
import dev.loki.hook.HookSabotage;
import dev.loki.killer.GeneratorKick;
import dev.loki.listener.PlayerInteractListener;
import dev.loki.listener.PlayerMoveListener;
import dev.loki.player.BasePlayer;
import dev.loki.player.Killer;
import dev.loki.player.PlayerState;
import dev.loki.player.Survivor;
import dev.loki.survivor.SurvivorController;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Handles listener wiring for player interactions.
*/
public class GameplayInteraction {
private PlayerMoveListener moveListener;
private PlayerInteractListener interactListener;
private GateManager gateManager;
private HookManager hookManager;
private HookRescue hookRescue;
private HookSabotage hookSabotage;
private GeneratorKick generatorKick;
private GameplayDamageSystem damageSystem;
private dev.loki.chest.ChestManager chestManager;
private dev.loki.chest.ChestOpening chestOpening;
private GateOpening gateOpening;
private dev.loki.objective.GeneratorRepair generatorRepair;
private boolean allGensDone;
private final Map<UUID, Long> killerLastSneakMs = new HashMap<>();
private final Map<UUID, SurvivorController> survivorControllers = new HashMap<>();
/**
* Wire all listeners.
*/
public void wire(GameSession session) {
wireMoveListener(session);
wireInteractListener(session);
wireSurvivorHealing(session);
}
/**
* Initialize SurvivorControllers with a survivorLookup so healing
* can find ANY player's Survivor instance (for healing other survivors).
*/
private void wireSurvivorHealing(GameSession session) {
survivorControllers.clear();
for (BasePlayer bp : session.getPlayers().values()) {
if (bp.isKiller()) continue;
Survivor survivor = (Survivor) bp;
SurvivorController controller = new SurvivorController(survivor, session.getConfig());
controller.getHealing().setSurvivorLookup(player -> {
BasePlayer found = session.getPlayer(player.getUniqueId());
if (found == null || found.isKiller()) return null;
return (Survivor) found;
});
survivorControllers.put(survivor.getUuid(), controller);
}
}
public void setMoveListener(PlayerMoveListener moveListener) {
this.moveListener = moveListener;
}
public void setInteractListener(PlayerInteractListener interactListener) {
this.interactListener = interactListener;
}
public void setManagers(GateManager gateManager,
HookManager hookManager, HookRescue hookRescue,
HookSabotage hookSabotage, GeneratorKick generatorKick,
GameplayDamageSystem damageSystem,
dev.loki.chest.ChestManager chestManager,
dev.loki.chest.ChestOpening chestOpening,
GateOpening gateOpening,
dev.loki.objective.GeneratorRepair generatorRepair) {
this.gateManager = gateManager;
this.hookManager = hookManager;
this.hookRescue = hookRescue;
this.hookSabotage = hookSabotage;
this.generatorKick = generatorKick;
this.damageSystem = damageSystem;
this.chestManager = chestManager;
this.chestOpening = chestOpening;
this.gateOpening = gateOpening;
this.generatorRepair = generatorRepair;
}
public void setAllGensDone(boolean allGensDone) {
this.allGensDone = allGensDone;
}
private void wireMoveListener(GameSession session) {
if (moveListener == null) return;
moveListener.setOnSurvivorMove((survivor, loc) -> {
if (!allGensDone) return;
if (survivor.getState() == PlayerState.ESCAPED) return;
ExitGate gate = gateManager.getGateAt(loc, 3.0);
if (gate != null && gate.isOpen()) {
survivor.setState(PlayerState.ESCAPED);
Player p = survivor.getPlayer();
if (p != null) {
p.playSound(loc, Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 1.2f);
Bukkit.broadcast(Component.text(
"[DBD] " + p.getName() + " сбежал через ворота!", NamedTextColor.GOLD));
}
}
});
}
private void wireInteractListener(GameSession session) {
if (interactListener == null) return;
// Rescue
interactListener.setOnRescueAttempt((player, ignored) -> {
BasePlayer bp = session.getPlayer(player.getUniqueId());
if (bp == null || bp.isKiller()) return;
Survivor rescuer = (Survivor) bp;
// Cannot rescue if you're hooked, downed, or carried
if (rescuer.getState() == PlayerState.HOOKED ||
rescuer.getState() == PlayerState.DOWNED ||
rescuer.getState() == PlayerState.CARRIED) return;
Hook hook = hookManager.findNearestOccupiedHook(player.getLocation(), 3.0);
if (hook != null) hookRescue.startRescue(rescuer, hook);
});
// Right-click attack (hook carrying / pickup downed)
interactListener.setOnAttack((player, isRightClick) -> {
if (!isRightClick) return;
BasePlayer bp = session.getPlayer(player.getUniqueId());
if (bp == null || !bp.isKiller()) return;
Killer killer = (Killer) bp;
if (killer.isCarrying()) {
for (BasePlayer other : session.getPlayers().values()) {
if (!other.isKiller() && other.getState() == PlayerState.CARRIED) {
Survivor carried = (Survivor) other;
if (hookManager.tryHookSurvivor(carried, player.getLocation())) {
killer.setCarrying(false);
Hook nearest = hookManager.findNearestOccupiedHook(player.getLocation(), 5.0);
if (nearest != null) {
Player vp = carried.getPlayer();
if (vp != null) vp.teleport(nearest.getLocation());
}
}
break;
}
}
} else {
Survivor target = damageSystem.getPlayerManager().getNearestSurvivorInState(
player, PlayerState.DOWNED, 3.0);
if (target != null) {
boolean picked = damageSystem.getKillerController().tryPickup(killer, target);
if (!picked) player.sendMessage(Component.text(
"[DBD] Не удалось подобрать выжившего.", NamedTextColor.RED));
}
}
});
// Sneak: killer → Hook / GeneratorKick / carry pickup, survivor → Sabotage
interactListener.setOnKillerSneak((player, isSneaking) -> {
BasePlayer bp = session.getPlayer(player.getUniqueId());
if (bp == null) return;
if (bp.isKiller()) {
Killer killer = (Killer) bp;
if (isSneaking) {
// #1: Hook carried survivor if near a hook
if (killer.isCarrying()) {
for (BasePlayer other : session.getPlayers().values()) {
if (!other.isKiller() && other.getState() == PlayerState.CARRIED) {
Survivor carried = (Survivor) other;
if (hookManager.tryHookSurvivor(carried, player.getLocation())) {
killer.setCarrying(false);
Hook nearest = hookManager.findNearestOccupiedHook(player.getLocation(), 5.0);
if (nearest != null) {
Player vp = carried.getPlayer();
if (vp != null) vp.teleport(nearest.getLocation());
}
return;
}
break;
}
}
return;
}
// #2: Double-sneak to pickup downed survivor
long now = System.currentTimeMillis();
Long last = killerLastSneakMs.get(player.getUniqueId());
if (last != null && now - last < 450 && !killer.isCarrying()) {
Survivor target = damageSystem.getPlayerManager().getNearestSurvivorInState(
player, PlayerState.DOWNED, 3.0);
if (target != null) {
damageSystem.getKillerController().tryPickup(killer, target);
}
}
killerLastSneakMs.put(player.getUniqueId(), now);
generatorKick.startCharging(killer);
} else {
generatorKick.stopCharging(killer.getUuid());
}
} else {
Survivor surv = (Survivor) bp;
if (surv.getState() == PlayerState.HOOKED) {
// Hook recovery is handled elsewhere
} else {
if (isSneaking) hookSabotage.startSabotage(surv);
else hookSabotage.stopSabotage(surv.getUuid());
}
}
});
// Generator repair
interactListener.setOnGeneratorInteract((player, action) -> {
BasePlayer bp = session.getPlayer(player.getUniqueId());
if (bp == null || bp.isKiller()) return;
if (generatorRepair == null) return;
var genManager = session.getGeneratorManager();
if (genManager == null) return;
double range = session.getConfig().getGeneratorInteractionRange();
var generator = genManager.getNearestGenerator(player.getLocation(), range);
if (generator != null) {
generatorRepair.startRepair(player, generator);
}
});
// Chest
interactListener.setOnChestInteract((player, ignored) -> {
BasePlayer bp = session.getPlayer(player.getUniqueId());
if (bp == null || bp.isKiller()) return;
var chest = chestManager.getNearestChest(player.getLocation(), 3.0);
if (chest != null) chestOpening.startOpening(player, chest);
});
// Healing: survivor sneaks near injured/downed survivor
interactListener.setOnHealSneak((healer, target) -> {
SurvivorController controller = survivorControllers.get(healer.getUniqueId());
if (controller != null) {
controller.onHealAttempt(target);
}
});
// #11: Carried survivor shift-spam to escape from killer
interactListener.setOnCarriedShift((player, isSneaking) -> {
if (!isSneaking) return;
BasePlayer bp = session.getPlayer(player.getUniqueId());
if (bp == null || bp.isKiller()) return;
Survivor survivor = (Survivor) bp;
if (survivor.getState() != PlayerState.CARRIED) return;
damageSystem.getKillerController().getCarry().onSurvivorShift(survivor.getUuid());
});
// Gate (uses hatch callback - triggered on PORTAL/HOPPER interaction)
interactListener.setOnHatchInteract((player, ignored) -> {
BasePlayer bp = session.getPlayer(player.getUniqueId());
if (bp == null || bp.isKiller()) return;
Survivor survivor = (Survivor) bp;
ExitGate gate = gateManager.getGateAt(player.getLocation(), 3.0);
if (gate != null && !gate.isOpen() && gateOpening != null) {
gateOpening.tryStartOpening(survivor, session.getPlugin());
}
});
}
/**
* Tick all survivor controllers (healing, movement, etc.)
*/
public void tickSurvivors() {
for (SurvivorController controller : survivorControllers.values()) {
controller.tick();
}
}
/**
* Clear all listener callbacks.
*/
public void clear() {
survivorControllers.clear();
if (moveListener != null) moveListener.setOnSurvivorMove(null);
if (interactListener != null) {
interactListener.setOnRescueAttempt(null);
interactListener.setOnChestInteract(null);
interactListener.setOnAttack(null);
interactListener.setOnKillerSneak(null);
interactListener.setOnHealSneak(null);
interactListener.setOnCarriedShift(null);
interactListener.setOnGeneratorInteract(null);
interactListener.setOnHatchInteract(null);
}
}
}