mdbd/src/main/java/dev/loki/phase/GameplayInteraction.java
2026-06-10 23:00:12 +02:00

308 lines
13 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.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);
}
}
}